Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-31 15:10:02 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-31 15:10:02 +0300
commit2f2c8f84bf1dd181f28f71505c6216f34d67532e (patch)
tree350d9edd3f9e9bc6c003851ec55b15c499fdedf4
parent9c15dfa1ef3b13fd9c1596e0c6be971405f376ab (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/alert_management/components/alert_management_table.vue21
-rw-r--r--app/assets/javascripts/incidents/components/incidents_list.vue43
-rw-r--r--app/assets/javascripts/incidents/constants.js18
-rw-r--r--app/assets/stylesheets/fontawesome_custom.scss29
-rw-r--r--app/assets/stylesheets/pages/incident_management_list.scss4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/graphql/mutations/concerns/mutations/resolves_subscription.rb25
-rw-r--r--app/graphql/mutations/issues/set_subscription.rb11
-rw-r--r--app/graphql/mutations/merge_requests/set_subscription.rb17
-rw-r--r--app/graphql/types/issuable_state_enum.rb1
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/helpers/issuables_helper.rb9
-rw-r--r--app/models/project.rb1
-rw-r--r--app/services/metrics/dashboard/grafana_metric_embed_service.rb4
-rw-r--r--app/views/projects/notes/_actions.html.haml2
-rw-r--r--app/workers/all_queues.yml768
-rw-r--r--app/workers/git_garbage_collect_worker.rb5
-rw-r--r--app/workers/propagate_service_template_worker.rb2
-rw-r--r--changelogs/unreleased/217014-grafanametricembedservice-undefined-method-id-for-nil-nilclass.yml5
-rw-r--r--changelogs/unreleased/225921-replace-fa-certificate-icons-with-gitlab-svg-first-contribution-ic.yml5
-rw-r--r--changelogs/unreleased/226927-immediately-update-repository-statistics-when-running-housekeeping.yml6
-rw-r--r--changelogs/unreleased/229400-incident-state.yml5
-rw-r--r--changelogs/unreleased/graphql-issue-subscribe.yml5
-rw-r--r--changelogs/unreleased/mo-add-index-to-ci-pipeline.yml5
-rw-r--r--changelogs/unreleased/ph-enableAutoExpandByDefault.yml5
-rw-r--r--config/initializers/sidekiq_cluster.rb8
-rw-r--r--db/migrate/20200728080250_replace_unique_index_on_cycle_analytics_stages.rb43
-rw-r--r--db/migrate/20200729202222_add_index_to_ci_pipeline_project_id_created_at.rb17
-rw-r--r--db/schema_migrations/202007280802501
-rw-r--r--db/schema_migrations/202007292022221
-rw-r--r--db/structure.sql6
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql49
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json175
-rw-r--r--doc/api/graphql/reference/index.md10
-rw-r--r--doc/development/code_review.md2
-rw-r--r--doc/development/documentation/index.md78
-rw-r--r--doc/development/fe_guide/graphql.md10
-rw-r--r--doc/development/sql.md6
-rw-r--r--doc/user/project/web_ide/index.md41
-rw-r--r--locale/gitlab.pot18
-rw-r--r--spec/features/markdown/markdown_spec.rb4
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb169
-rw-r--r--spec/features/projects/snippets/show_spec.rb156
-rw-r--r--spec/features/snippets/show_spec.rb167
-rw-r--r--spec/frontend/alert_management/components/alert_management_table_spec.js88
-rw-r--r--spec/frontend/incidents/components/incidents_list_spec.js24
-rw-r--r--spec/graphql/mutations/issues/set_subscription_spec.rb10
-rw-r--r--spec/graphql/mutations/merge_requests/set_subscription_spec.rb42
-rw-r--r--spec/migrations/20200728080250_replace_unique_index_on_cycle_analytics_stages_spec.rb47
-rw-r--r--spec/models/project_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb12
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb57
-rw-r--r--spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb41
-rw-r--r--spec/support/shared_examples/features/snippets_shared_examples.rb142
-rw-r--r--spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb45
-rw-r--r--spec/support/shared_examples/requests/api/graphql/mutations/subscription_shared_examples.rb69
-rw-r--r--spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb6
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb84
58 files changed, 1554 insertions, 1074 deletions
diff --git a/app/assets/javascripts/alert_management/components/alert_management_table.vue b/app/assets/javascripts/alert_management/components/alert_management_table.vue
index c805ec6883f..bd3d0c11022 100644
--- a/app/assets/javascripts/alert_management/components/alert_management_table.vue
+++ b/app/assets/javascripts/alert_management/components/alert_management_table.vue
@@ -168,7 +168,7 @@ export default {
};
},
error() {
- this.errored = true;
+ this.hasError = true;
},
},
alertsCount: {
@@ -187,10 +187,9 @@ export default {
data() {
return {
searchTerm: '',
- errored: false,
+ hasError: false,
errorMessage: '',
isAlertDismissed: false,
- isErrorAlertDismissed: false,
sort: 'STARTED_AT_DESC',
statusFilter: [],
filteredByStatus: '',
@@ -203,16 +202,13 @@ export default {
computed: {
showNoAlertsMsg() {
return (
- !this.errored &&
+ !this.hasError &&
!this.loading &&
this.alertsCount?.all === 0 &&
!this.searchTerm &&
!this.isAlertDismissed
);
},
- showErrorMsg() {
- return this.errored && !this.isErrorAlertDismissed;
- },
loading() {
return this.$apollo.queries.alerts.loading;
},
@@ -306,11 +302,11 @@ export default {
};
},
handleAlertError(errorMessage) {
- this.errored = true;
+ this.hasError = true;
this.errorMessage = errorMessage;
},
dismissError() {
- this.isErrorAlertDismissed = true;
+ this.hasError = false;
this.errorMessage = '';
},
},
@@ -332,12 +328,7 @@ export default {
</template>
</gl-sprintf>
</gl-alert>
- <gl-alert
- v-if="showErrorMsg"
- variant="danger"
- data-testid="alert-error"
- @dismiss="dismissError"
- >
+ <gl-alert v-if="hasError" variant="danger" data-testid="alert-error" @dismiss="dismissError">
<p v-html="errorMessage || $options.i18n.errorMsg"></p>
</gl-alert>
diff --git a/app/assets/javascripts/incidents/components/incidents_list.vue b/app/assets/javascripts/incidents/components/incidents_list.vue
index 2731b49c4cc..66443a36b5c 100644
--- a/app/assets/javascripts/incidents/components/incidents_list.vue
+++ b/app/assets/javascripts/incidents/components/incidents_list.vue
@@ -11,13 +11,15 @@ import {
GlSearchBoxByType,
GlIcon,
GlPagination,
+ GlTabs,
+ GlTab,
} from '@gitlab/ui';
-import { debounce } from 'lodash';
+import { debounce, trim } from 'lodash';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { s__ } from '~/locale';
import { mergeUrlParams, joinPaths, visitUrl } from '~/lib/utils/url_utility';
import getIncidents from '../graphql/queries/get_incidents.query.graphql';
-import { I18N, DEFAULT_PAGE_SIZE, INCIDENT_SEARCH_DELAY } from '../constants';
+import { I18N, DEFAULT_PAGE_SIZE, INCIDENT_SEARCH_DELAY, INCIDENT_STATE_TABS } from '../constants';
const tdClass =
'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
@@ -35,6 +37,7 @@ const initialPaginationState = {
export default {
i18n: I18N,
+ stateTabs: INCIDENT_STATE_TABS,
fields: [
{
key: 'title',
@@ -67,6 +70,8 @@ export default {
GlSearchBoxByType,
GlIcon,
GlPagination,
+ GlTabs,
+ GlTab,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -78,6 +83,7 @@ export default {
variables() {
return {
searchTerm: this.searchTerm,
+ state: this.stateFilter,
projectPath: this.projectPath,
labelNames: ['incident'],
firstPageSize: this.pagination.firstPageSize,
@@ -105,6 +111,7 @@ export default {
searchTerm: '',
pagination: initialPaginationState,
incidents: {},
+ stateFilter: '',
};
},
computed: {
@@ -138,14 +145,17 @@ export default {
return mergeUrlParams({ issuable_template: this.incidentTemplateName }, this.newIssuePath);
},
},
- watch: {
- searchTerm: debounce(function debounceSearch(input) {
- if (input !== this.searchTerm) {
- this.searchTerm = input;
+ methods: {
+ onInputChange: debounce(function debounceSearch(input) {
+ const trimmedInput = trim(input);
+ if (trimmedInput !== this.searchTerm) {
+ this.searchTerm = trimmedInput;
}
}, INCIDENT_SEARCH_DELAY),
- },
- methods: {
+ filterIncidentsByState(tabIndex) {
+ const { filters } = this.$options.stateTabs[tabIndex];
+ this.stateFilter = filters;
+ },
hasAssignees(assignees) {
return Boolean(assignees.nodes?.length);
},
@@ -183,9 +193,17 @@ export default {
{{ $options.i18n.errorMsg }}
</gl-alert>
- <div class="gl-display-flex gl-justify-content-end">
+ <div class="incident-management-list-header gl-display-flex gl-justify-content-space-between">
+ <gl-tabs content-class="gl-p-0" @input="filterIncidentsByState">
+ <gl-tab v-for="tab in $options.stateTabs" :key="tab.state" :data-testid="tab.state">
+ <template #title>
+ <span>{{ tab.title }}</span>
+ </template>
+ </gl-tab>
+ </gl-tabs>
+
<gl-button
- class="gl-mt-3 gl-mb-3 create-incident-button"
+ class="gl-my-3 create-incident-button"
data-testid="createIncidentBtn"
:loading="redirecting"
:disabled="redirecting"
@@ -200,9 +218,10 @@ export default {
<div class="gl-bg-gray-10 gl-p-5 gl-border-b-solid gl-border-b-1 gl-border-gray-100">
<gl-search-box-by-type
- v-model.trim="searchTerm"
+ :value="searchTerm"
class="gl-bg-white"
:placeholder="$options.i18n.searchPlaceholder"
+ @input="onInputChange"
/>
</div>
@@ -221,7 +240,7 @@ export default {
@row-clicked="navigateToIncidentDetails"
>
<template #cell(title)="{ item }">
- <div class="gl-display-flex gl-justify-content-center">
+ <div class="gl-display-sm-flex gl-align-items-center">
<div class="gl-max-w-full text-truncate" :title="item.title">{{ item.title }}</div>
<gl-icon
v-if="item.state === 'closed'"
diff --git a/app/assets/javascripts/incidents/constants.js b/app/assets/javascripts/incidents/constants.js
index 4246c3e914f..3a3efa98f25 100644
--- a/app/assets/javascripts/incidents/constants.js
+++ b/app/assets/javascripts/incidents/constants.js
@@ -8,5 +8,23 @@ export const I18N = {
searchPlaceholder: __('Search or filter results...'),
};
+export const INCIDENT_STATE_TABS = [
+ {
+ title: s__('IncidentManagement|Open'),
+ state: 'OPENED',
+ filters: 'opened',
+ },
+ {
+ title: s__('IncidentManagement|Closed'),
+ state: 'CLOSED',
+ filters: 'closed',
+ },
+ {
+ title: s__('IncidentManagement|All incidents'),
+ state: 'ALL',
+ filters: 'all',
+ },
+];
+
export const INCIDENT_SEARCH_DELAY = 300;
export const DEFAULT_PAGE_SIZE = 10;
diff --git a/app/assets/stylesheets/fontawesome_custom.scss b/app/assets/stylesheets/fontawesome_custom.scss
index 6070ab92974..c2ce2368705 100644
--- a/app/assets/stylesheets/fontawesome_custom.scss
+++ b/app/assets/stylesheets/fontawesome_custom.scss
@@ -80,31 +80,6 @@
}
}
-.fa-stack {
- position: relative;
- display: inline-block;
- width: 2em;
- height: 2em;
- line-height: 2em;
- vertical-align: middle;
-}
-
-.fa-stack-1x,
-.fa-stack-2x {
- position: absolute;
- left: 0;
- width: 100%;
- text-align: center;
-}
-
-.fa-stack-1x {
- line-height: inherit;
-}
-
-.fa-stack-2x {
- font-size: 2em;
-}
-
.fa-inverse {
color: $white;
}
@@ -256,10 +231,6 @@
content: '\f111';
}
-.fa-certificate::before {
- content: '\f0a3';
-}
-
.fa-bitbucket::before {
content: '\f171';
}
diff --git a/app/assets/stylesheets/pages/incident_management_list.scss b/app/assets/stylesheets/pages/incident_management_list.scss
index 47a8238d3dd..e6305a5d233 100644
--- a/app/assets/stylesheets/pages/incident_management_list.scss
+++ b/app/assets/stylesheets/pages/incident_management_list.scss
@@ -90,6 +90,10 @@
}
@include media-breakpoint-down(xs) {
+ .incident-management-list-header {
+ flex-direction: column-reverse;
+ };
+
.create-incident-button {
@include gl-w-full;
}
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index e79a0135d2f..24010b20db1 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -36,7 +36,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:multiline_comments, @project)
push_frontend_feature_flag(:file_identifier_hash)
push_frontend_feature_flag(:batch_suggestions, @project, default_enabled: true)
- push_frontend_feature_flag(:auto_expand_collapsed_diffs, @project)
+ push_frontend_feature_flag(:auto_expand_collapsed_diffs, @project, default_enabled: true)
push_frontend_feature_flag(:hide_jump_to_next_unresolved_in_threads, @project)
end
diff --git a/app/graphql/mutations/concerns/mutations/resolves_subscription.rb b/app/graphql/mutations/concerns/mutations/resolves_subscription.rb
new file mode 100644
index 00000000000..e8c5d0d404d
--- /dev/null
+++ b/app/graphql/mutations/concerns/mutations/resolves_subscription.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Mutations
+ module ResolvesSubscription
+ extend ActiveSupport::Concern
+ included do
+ argument :subscribed_state,
+ GraphQL::BOOLEAN_TYPE,
+ required: true,
+ description: 'The desired state of the subscription'
+ end
+
+ def resolve(project_path:, iid:, subscribed_state:)
+ resource = authorized_find!(project_path: project_path, iid: iid)
+ project = resource.project
+
+ resource.set_subscription(current_user, subscribed_state, project)
+
+ {
+ resource.class.name.underscore.to_sym => resource,
+ errors: errors_on_object(resource)
+ }
+ end
+ end
+end
diff --git a/app/graphql/mutations/issues/set_subscription.rb b/app/graphql/mutations/issues/set_subscription.rb
new file mode 100644
index 00000000000..a04c8f5ba2d
--- /dev/null
+++ b/app/graphql/mutations/issues/set_subscription.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Issues
+ class SetSubscription < Base
+ graphql_name 'IssueSetSubscription'
+
+ include ResolvesSubscription
+ end
+ end
+end
diff --git a/app/graphql/mutations/merge_requests/set_subscription.rb b/app/graphql/mutations/merge_requests/set_subscription.rb
index 1535481ab37..7d3c40185c9 100644
--- a/app/graphql/mutations/merge_requests/set_subscription.rb
+++ b/app/graphql/mutations/merge_requests/set_subscription.rb
@@ -5,22 +5,7 @@ module Mutations
class SetSubscription < Base
graphql_name 'MergeRequestSetSubscription'
- argument :subscribed_state,
- GraphQL::BOOLEAN_TYPE,
- required: true,
- description: 'The desired state of the subscription'
-
- def resolve(project_path:, iid:, subscribed_state:)
- merge_request = authorized_find!(project_path: project_path, iid: iid)
- project = merge_request.project
-
- merge_request.set_subscription(current_user, subscribed_state, project)
-
- {
- merge_request: merge_request,
- errors: errors_on_object(merge_request)
- }
- end
+ include ResolvesSubscription
end
end
end
diff --git a/app/graphql/types/issuable_state_enum.rb b/app/graphql/types/issuable_state_enum.rb
index f2f6d6c6cab..543b7f8e5b2 100644
--- a/app/graphql/types/issuable_state_enum.rb
+++ b/app/graphql/types/issuable_state_enum.rb
@@ -8,5 +8,6 @@ module Types
value 'opened'
value 'closed'
value 'locked'
+ value 'all'
end
end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 49d51b626b2..8b4ea5d21d4 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -20,6 +20,7 @@ module Types
mount_mutation Mutations::Issues::SetConfidential
mount_mutation Mutations::Issues::SetLocked
mount_mutation Mutations::Issues::SetDueDate
+ mount_mutation Mutations::Issues::SetSubscription
mount_mutation Mutations::Issues::Update
mount_mutation Mutations::MergeRequests::Create
mount_mutation Mutations::MergeRequests::Update
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index dccb89eec79..62bdae39a37 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -205,7 +205,7 @@ module IssuablesHelper
author_output
end
- output << content_tag(:span, (issuable_first_contribution_icon if issuable.first_contribution?), class: 'has-tooltip gl-ml-2', title: _('1st contribution!'))
+ output << content_tag(:span, (sprite_icon('first-contribution', size: 16, css_class: 'gl-icon gl-vertical-align-middle') if issuable.first_contribution?), class: 'has-tooltip gl-ml-2', title: _('1st contribution!'))
output << content_tag(:span, (issuable.task_status if issuable.tasks?), id: "task_status", class: "d-none d-sm-none d-md-inline-block gl-ml-3")
output << content_tag(:span, (issuable.task_status_short if issuable.tasks?), id: "task_status_short", class: "d-md-none")
@@ -247,13 +247,6 @@ module IssuablesHelper
html.html_safe
end
- def issuable_first_contribution_icon
- content_tag(:span, class: 'fa-stack') do
- concat(icon('certificate', class: "fa-stack-2x"))
- concat(content_tag(:strong, '1', class: 'fa-inverse fa-stack-1x'))
- end
- end
-
def assigned_issuables_count(issuable_type)
case issuable_type
when :issues
diff --git a/app/models/project.rb b/app/models/project.rb
index a16669572df..b37dc3ed397 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1801,7 +1801,6 @@ class Project < ApplicationRecord
return unless namespace
mark_pages_as_not_deployed unless destroyed?
- ::Projects::UpdatePagesConfigurationService.new(self).execute
# 1. We rename pages to temporary directory
# 2. We wait 5 minutes, due to NFS caching
diff --git a/app/services/metrics/dashboard/grafana_metric_embed_service.rb b/app/services/metrics/dashboard/grafana_metric_embed_service.rb
index 8e72a185406..b8c5c17c738 100644
--- a/app/services/metrics/dashboard/grafana_metric_embed_service.rb
+++ b/app/services/metrics/dashboard/grafana_metric_embed_service.rb
@@ -33,7 +33,7 @@ module Metrics
def from_cache(project_id, user_id, grafana_url)
project = Project.find(project_id)
- user = User.find(user_id)
+ user = User.find(user_id) if user_id.present?
new(project, user, grafana_url: grafana_url)
end
@@ -56,7 +56,7 @@ module Metrics
end
def cache_key(*args)
- [project.id, current_user.id, grafana_url]
+ [project.id, current_user&.id, grafana_url]
end
# Required for ReactiveCaching; Usage overridden by
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index d725098752d..6cc4c8c1de7 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -1,7 +1,7 @@
- access = note_max_access_for_user(note)
- if note.has_special_role?(Note::SpecialRole::FIRST_TIME_CONTRIBUTOR)
%span.note-role.note-role-special.has-tooltip{ title: _("This is the author's first Merge Request to this project.") }
- = issuable_first_contribution_icon
+ = sprite_icon('first-contribution', size: 16, css_class: 'gl-icon gl-vertical-align-top')
- if access.nonzero?
%span.note-role.user-access-role= Gitlab::Access.human_access(access)
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 14488aa7f59..d20519ff774 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -5,7 +5,7 @@
---
- :name: authorized_project_update:authorized_project_update_project_create
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -13,7 +13,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_project_group_link_create
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -21,7 +21,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_user_refresh_over_user_range
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -29,7 +29,7 @@
:tags: []
- :name: authorized_project_update:authorized_project_update_user_refresh_with_low_urgency
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -37,87 +37,87 @@
:tags: []
- :name: auto_devops:auto_devops_disable
:feature_category: :auto_devops
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: auto_merge:auto_merge_process
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_cpu_spin
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_db_spin
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_kill
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_leak_mem
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: chaos:chaos_sleep
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: container_repository:cleanup_container_repository
:feature_category: :container_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: container_repository:delete_container_repository
:feature_category: :container_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:admin_email
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:authorized_project_update_periodic_recalculate
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -125,79 +125,79 @@
:tags: []
- :name: cronjob:ci_archive_traces_cron
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:container_expiration_policy
:feature_category: :container_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:environments_auto_stop_cron
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:expire_build_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:gitlab_usage_ping
:feature_category: :collection
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:import_export_project_cleanup
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:import_stuck_project_import_jobs
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:issue_due_scheduler
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:jira_import_stuck_jira_import_jobs
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:metrics_dashboard_schedule_annotations_prune
:feature_category: :metrics
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -205,39 +205,39 @@
:tags: []
- :name: cronjob:namespaces_prune_aggregation_schedules
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:pages_domain_removal_cron
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:pages_domain_ssl_renewal_cron
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:pages_domain_verification_cron
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:partition_creation
:feature_category: :database
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -245,127 +245,127 @@
:tags: []
- :name: cronjob:personal_access_tokens_expiring
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:pipeline_schedule
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:prune_old_events
:feature_category: :users
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:prune_web_hook_logs
:feature_category: :integrations
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:remove_expired_group_links
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:remove_expired_members
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:remove_unreferenced_lfs_objects
:feature_category: :git_lfs
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:repository_archive_cache
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:repository_check_dispatch
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:requests_profiles
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:schedule_migrate_external_diffs
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:stuck_ci_jobs
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:stuck_export_jobs
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:stuck_merge_jobs
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:trending_projects
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:update_container_registry_info
:feature_category: :container_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -373,11 +373,11 @@
:tags: []
- :name: cronjob:users_create_statistics
:feature_category: :users
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: cronjob:x509_issuer_crl_check
:feature_category: :source_code_management
@@ -389,27 +389,27 @@
:tags: []
- :name: deployment:deployments_finished
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: deployment:deployments_forward_deployment
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: deployment:deployments_success
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_configure_istio
:feature_category: :kubernetes_management
@@ -417,7 +417,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_install_app
:feature_category: :kubernetes_management
@@ -425,7 +425,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_patch_app
:feature_category: :kubernetes_management
@@ -433,7 +433,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_provision
:feature_category: :kubernetes_management
@@ -441,15 +441,15 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_update_app
:feature_category: :kubernetes_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_upgrade_app
:feature_category: :kubernetes_management
@@ -457,7 +457,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_wait_for_app_installation
:feature_category: :kubernetes_management
@@ -465,15 +465,15 @@
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_wait_for_app_update
:feature_category: :kubernetes_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:cluster_wait_for_ingress_ip_address
:feature_category: :kubernetes_management
@@ -481,23 +481,23 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_applications_activate_service
:feature_category: :kubernetes_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_applications_deactivate_service
:feature_category: :kubernetes_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_applications_uninstall
:feature_category: :kubernetes_management
@@ -505,7 +505,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_applications_wait_for_uninstall_app
:feature_category: :kubernetes_management
@@ -513,7 +513,7 @@
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_cleanup_app
:feature_category: :kubernetes_management
@@ -521,7 +521,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_cleanup_project_namespace
:feature_category: :kubernetes_management
@@ -529,7 +529,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:clusters_cleanup_service_account
:feature_category: :kubernetes_management
@@ -537,7 +537,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gcp_cluster:wait_for_cluster_creation
:feature_category: :kubernetes_management
@@ -545,7 +545,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_diff_note
:feature_category: :importers
@@ -553,7 +553,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_issue
:feature_category: :importers
@@ -561,7 +561,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_lfs_object
:feature_category: :importers
@@ -569,7 +569,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_note
:feature_category: :importers
@@ -577,7 +577,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_import_pull_request
:feature_category: :importers
@@ -585,103 +585,103 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_refresh_import_jid
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_finish_import
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_base_data
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_issues_and_diff_notes
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_lfs_objects
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_notes
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_pull_requests
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_importer:github_import_stage_import_repository
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: hashed_storage:hashed_storage_migrator
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: hashed_storage:hashed_storage_project_migrate
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: hashed_storage:hashed_storage_project_rollback
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: hashed_storage:hashed_storage_rollbacker
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: incident_management:clusters_applications_check_prometheus_health
:feature_category: :incident_management
@@ -693,175 +693,175 @@
:tags: []
- :name: incident_management:incident_management_pager_duty_process_incident
:feature_category: :incident_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: incident_management:incident_management_process_alert
:feature_category: :incident_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: incident_management:incident_management_process_prometheus_alert
:feature_category: :incident_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_advance_stage
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_import_issue
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_finish_import
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_import_attachments
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_import_issues
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_import_labels
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_import_notes
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: jira_importer:jira_import_stage_start_import
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: mail_scheduler:mail_scheduler_issue_due
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: mail_scheduler:mail_scheduler_notification_service
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_pool:object_pool_create
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_pool:object_pool_destroy
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_pool:object_pool_join
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_pool:object_pool_schedule_join
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_storage:object_storage_background_move
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: object_storage:object_storage_migrate_uploads
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: package_repositories:packages_nuget_extraction
:feature_category: :package_registry
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_background:archive_trace
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_background:ci_build_report_result
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -869,15 +869,15 @@
:tags: []
- :name: pipeline_background:ci_build_trace_chunk_flush
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_background:ci_daily_build_group_report_results
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -885,7 +885,7 @@
:tags: []
- :name: pipeline_background:ci_pipeline_success_unlock_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -893,7 +893,7 @@
:tags: []
- :name: pipeline_background:ci_ref_delete_unlock_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -901,7 +901,7 @@
:tags: []
- :name: pipeline_cache:expire_job_cache
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 3
@@ -909,7 +909,7 @@
:tags: []
- :name: pipeline_cache:expire_pipeline_cache
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
@@ -917,152 +917,152 @@
:tags: []
- :name: pipeline_creation:create_pipeline
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 4
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_creation:run_pipeline_schedule
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 4
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:build_coverage
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:build_trace_sections
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:ci_create_cross_project_pipeline
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:ci_pipeline_bridge_status
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:pipeline_metrics
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:pipeline_notification
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_default:pipeline_update_ci_ref_status
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_hooks:build_hooks
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_hooks:pipeline_hooks
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:build_finished
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 5
- :idempotent:
+ :idempotent:
:tags:
- :requires_disk_io
- :name: pipeline_processing:build_queue
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:build_success
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:ci_build_prepare
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:ci_build_schedule
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:ci_resource_groups_assign_resource_from_resource_group
:feature_category: :continuous_delivery
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:pipeline_process
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: pipeline_processing:pipeline_update
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
@@ -1070,7 +1070,7 @@
:tags: []
- :name: pipeline_processing:stage_update
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
@@ -1078,7 +1078,7 @@
:tags: []
- :name: pipeline_processing:update_head_pipeline_for_merge_request
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 5
@@ -1086,71 +1086,71 @@
:tags: []
- :name: repository_check:repository_check_batch
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_check:repository_check_clear
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_check:repository_check_single_repository
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_confidential_issue
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_entity_leave
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_group_private
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_private_features
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: todos_destroyer:todos_destroyer_project_private
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: unassign_issuables:members_destroyer_unassign_issuables
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1158,7 +1158,7 @@
:tags: []
- :name: update_namespace_statistics:namespaces_root_statistics
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1166,7 +1166,7 @@
:tags: []
- :name: update_namespace_statistics:namespaces_schedule_aggregation
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1174,7 +1174,7 @@
:tags: []
- :name: authorized_keys
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
@@ -1182,7 +1182,7 @@
:tags: []
- :name: authorized_projects
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
@@ -1190,11 +1190,11 @@
:tags: []
- :name: background_migration
:feature_category: :database
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :throttled
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: chat_notification
:feature_category: :chatops
@@ -1202,11 +1202,11 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: create_commit_signature
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
@@ -1214,91 +1214,91 @@
:tags: []
- :name: create_evidence
:feature_category: :release_evidence
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: create_note_diff_file
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: default
- :feature_category:
- :has_external_dependencies:
- :urgency:
- :resource_boundary:
+ :feature_category:
+ :has_external_dependencies:
+ :urgency:
+ :resource_boundary:
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: delete_diff_files
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: delete_merged_branches
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: delete_stored_files
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: delete_user
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: design_management_new_version
:feature_category: :design_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :memory
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: detect_repository_languages
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: email_receiver
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: emails_on_push
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: error_tracking_issue_link
:feature_category: :error_tracking
@@ -1306,23 +1306,23 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: expire_build_instance_artifacts
:feature_category: :continuous_integration
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: export_csv
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: external_service_reactive_caching
:feature_category: :not_owned
@@ -1330,15 +1330,15 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: file_hook
:feature_category: :integrations
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: flush_counter_increments
:feature_category: :not_owned
@@ -1350,87 +1350,87 @@
:tags: []
- :name: git_garbage_collect
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: github_import_advance_stage
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: gitlab_shell
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: group_destroy
:feature_category: :subgroups
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: group_export
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: group_import
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: import_issues_csv
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: invalid_gpg_signature_update
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: irker
:feature_category: :integrations
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: mailers
- :feature_category:
- :has_external_dependencies:
- :urgency:
- :resource_boundary:
+ :feature_category:
+ :has_external_dependencies:
+ :urgency:
+ :resource_boundary:
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: merge
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
@@ -1438,7 +1438,7 @@
:tags: []
- :name: merge_request_mergeability_check
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1446,7 +1446,7 @@
:tags: []
- :name: metrics_dashboard_prune_old_annotations
:feature_category: :metrics
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
@@ -1454,87 +1454,87 @@
:tags: []
- :name: migrate_external_diffs
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: namespaceless_project_destroy
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: new_issue
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: new_merge_request
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: new_note
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: pages
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pages_domain_ssl_renewal
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: pages_domain_verification
:feature_category: :pages
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: phabricator_import_import_tasks
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: post_receive
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 5
- :idempotent:
+ :idempotent:
:tags: []
- :name: process_commit
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 3
@@ -1542,35 +1542,35 @@
:tags: []
- :name: project_cache
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_daily_statistics
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_destroy
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_export
:feature_category: :importers
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :throttled
:resource_boundary: :memory
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_service
:feature_category: :integrations
@@ -1578,11 +1578,11 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: project_update_repository_storage
:feature_category: :gitaly
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :throttled
:resource_boundary: :unknown
:weight: 1
@@ -1590,7 +1590,7 @@
:tags: []
- :name: prometheus_create_default_alerts
:feature_category: :incident_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 1
@@ -1598,59 +1598,59 @@
:tags: []
- :name: propagate_integration
:feature_category: :integrations
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent: true
:tags: []
- :name: propagate_service_template
- :feature_category: :source_code_management
- :has_external_dependencies:
+ :feature_category: :integrations
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: reactive_caching
:feature_category: :not_owned
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: rebase
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: remote_mirror_notification
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_cleanup
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_fork
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_import
:feature_category: :importers
@@ -1658,15 +1658,15 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_remove_remote
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: repository_update_remote_mirror
:feature_category: :source_code_management
@@ -1674,51 +1674,51 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: self_monitoring_project_create
:feature_category: :metrics
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: self_monitoring_project_delete
:feature_category: :metrics
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 2
- :idempotent:
+ :idempotent:
:tags: []
- :name: service_desk_email_receiver
:feature_category: :issue_tracking
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: system_hook_push
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: update_external_pull_requests
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: update_highest_role
:feature_category: :authentication_and_authorization
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 2
@@ -1726,27 +1726,27 @@
:tags: []
- :name: update_merge_requests
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 3
- :idempotent:
+ :idempotent:
:tags: []
- :name: update_project_statistics
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: upload_checksum
:feature_category: :geo_replication
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: web_hook
:feature_category: :integrations
@@ -1754,11 +1754,11 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent:
:tags: []
- :name: x509_certificate_revoke
:feature_category: :source_code_management
- :has_external_dependencies:
+ :has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb
index f2222c7be5e..459fc5992d8 100644
--- a/app/workers/git_garbage_collect_worker.rb
+++ b/app/workers/git_garbage_collect_worker.rb
@@ -33,7 +33,10 @@ class GitGarbageCollectWorker # rubocop:disable Scalability/IdempotentWorker
# Refresh the branch cache in case garbage collection caused a ref lookup to fail
flush_ref_caches(project) if task == :gc
- project.repository.expire_statistics_caches if task != :pack_refs
+ if task != :pack_refs
+ project.repository.expire_statistics_caches
+ Projects::UpdateStatisticsService.new(project, nil, statistics: [:repository_size, :lfs_objects_size]).execute
+ end
# In case pack files are deleted, release libgit2 cache and open file
# descriptors ASAP instead of waiting for Ruby garbage collection
diff --git a/app/workers/propagate_service_template_worker.rb b/app/workers/propagate_service_template_worker.rb
index f3a6bda1821..37d5ccb656d 100644
--- a/app/workers/propagate_service_template_worker.rb
+++ b/app/workers/propagate_service_template_worker.rb
@@ -4,7 +4,7 @@
class PropagateServiceTemplateWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
- feature_category :source_code_management
+ feature_category :integrations
LEASE_TIMEOUT = 4.hours.to_i
diff --git a/changelogs/unreleased/217014-grafanametricembedservice-undefined-method-id-for-nil-nilclass.yml b/changelogs/unreleased/217014-grafanametricembedservice-undefined-method-id-for-nil-nilclass.yml
new file mode 100644
index 00000000000..577e98c1a4c
--- /dev/null
+++ b/changelogs/unreleased/217014-grafanametricembedservice-undefined-method-id-for-nil-nilclass.yml
@@ -0,0 +1,5 @@
+---
+title: Allow anonymous users to view embedded Grafana metrics in public project
+merge_request: 37844
+author:
+type: fixed
diff --git a/changelogs/unreleased/225921-replace-fa-certificate-icons-with-gitlab-svg-first-contribution-ic.yml b/changelogs/unreleased/225921-replace-fa-certificate-icons-with-gitlab-svg-first-contribution-ic.yml
new file mode 100644
index 00000000000..2fa362a43c9
--- /dev/null
+++ b/changelogs/unreleased/225921-replace-fa-certificate-icons-with-gitlab-svg-first-contribution-ic.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-certificate icon with first-contribution svg
+merge_request: 38154
+author:
+type: changed
diff --git a/changelogs/unreleased/226927-immediately-update-repository-statistics-when-running-housekeeping.yml b/changelogs/unreleased/226927-immediately-update-repository-statistics-when-running-housekeeping.yml
new file mode 100644
index 00000000000..fb5cf05e12b
--- /dev/null
+++ b/changelogs/unreleased/226927-immediately-update-repository-statistics-when-running-housekeeping.yml
@@ -0,0 +1,6 @@
+---
+title: Immediately update project statistics when running housekeeping or repository
+ cleanup
+merge_request: 37579
+author:
+type: other
diff --git a/changelogs/unreleased/229400-incident-state.yml b/changelogs/unreleased/229400-incident-state.yml
new file mode 100644
index 00000000000..3b3ba3f0a60
--- /dev/null
+++ b/changelogs/unreleased/229400-incident-state.yml
@@ -0,0 +1,5 @@
+---
+title: Add incident state columns
+merge_request: 37889
+author:
+type: other
diff --git a/changelogs/unreleased/graphql-issue-subscribe.yml b/changelogs/unreleased/graphql-issue-subscribe.yml
new file mode 100644
index 00000000000..032cdbed38b
--- /dev/null
+++ b/changelogs/unreleased/graphql-issue-subscribe.yml
@@ -0,0 +1,5 @@
+---
+title: Allows setting of issue subscribe status in GraphQL API.
+merge_request: 38051
+author:
+type: added
diff --git a/changelogs/unreleased/mo-add-index-to-ci-pipeline.yml b/changelogs/unreleased/mo-add-index-to-ci-pipeline.yml
new file mode 100644
index 00000000000..12107e1a4b9
--- /dev/null
+++ b/changelogs/unreleased/mo-add-index-to-ci-pipeline.yml
@@ -0,0 +1,5 @@
+---
+title: Fix 500 for pipeline charts page
+merge_request: 38226
+author:
+type: fixed
diff --git a/changelogs/unreleased/ph-enableAutoExpandByDefault.yml b/changelogs/unreleased/ph-enableAutoExpandByDefault.yml
new file mode 100644
index 00000000000..c1706a088fb
--- /dev/null
+++ b/changelogs/unreleased/ph-enableAutoExpandByDefault.yml
@@ -0,0 +1,5 @@
+---
+title: Auto expand collapsed diffs when viewing diffs file-by-file
+merge_request: 38296
+author:
+type: added
diff --git a/config/initializers/sidekiq_cluster.rb b/config/initializers/sidekiq_cluster.rb
index 4ff8dd9b936..2f9c1de47eb 100644
--- a/config/initializers/sidekiq_cluster.rb
+++ b/config/initializers/sidekiq_cluster.rb
@@ -14,10 +14,10 @@ if ENV['ENABLE_SIDEKIQ_CLUSTER']
if Process.ppid != parent
Process.kill(:TERM, Process.pid)
- # Wait for just a few extra seconds for a final attempt to
- # gracefully terminate. Considering the parent (cluster) process
- # have changed (SIGKILL'd), it shouldn't take long to shutdown.
- sleep(5)
+ # Allow sidekiq to cleanly terminate and push any running jobs back
+ # into the queue. We use the configured timeout and add a small
+ # grace period
+ sleep(Sidekiq.options[:timeout] + 5)
# Signaling the Sidekiq Pgroup as KILL is not forwarded to
# a possible child process. In Sidekiq Cluster, all child Sidekiq
diff --git a/db/migrate/20200728080250_replace_unique_index_on_cycle_analytics_stages.rb b/db/migrate/20200728080250_replace_unique_index_on_cycle_analytics_stages.rb
new file mode 100644
index 00000000000..0e562ae27e2
--- /dev/null
+++ b/db/migrate/20200728080250_replace_unique_index_on_cycle_analytics_stages.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+class ReplaceUniqueIndexOnCycleAnalyticsStages < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ OLD_INDEX_NAME = 'index_analytics_ca_group_stages_on_group_id_and_name'
+ NEW_INDEX_NAME = 'index_group_stages_on_group_id_group_value_stream_id_and_name'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index(:analytics_cycle_analytics_group_stages,
+ [:group_id, :group_value_stream_id, :name],
+ unique: true,
+ name: NEW_INDEX_NAME)
+
+ remove_concurrent_index_by_name :analytics_cycle_analytics_group_stages, OLD_INDEX_NAME
+ end
+
+ def down
+ # Removing duplicated records (group_id, name) that would prevent re-creating the old index.
+ execute <<-SQL
+ DELETE FROM analytics_cycle_analytics_group_stages
+ USING (
+ SELECT group_id, name, MIN(id) as min_id
+ FROM analytics_cycle_analytics_group_stages
+ GROUP BY group_id, name
+ HAVING COUNT(id) > 1
+ ) as analytics_cycle_analytics_group_stages_name_duplicates
+ WHERE analytics_cycle_analytics_group_stages_name_duplicates.group_id = analytics_cycle_analytics_group_stages.group_id
+ AND analytics_cycle_analytics_group_stages_name_duplicates.name = analytics_cycle_analytics_group_stages.name
+ AND analytics_cycle_analytics_group_stages_name_duplicates.min_id <> analytics_cycle_analytics_group_stages.id
+ SQL
+
+ add_concurrent_index(:analytics_cycle_analytics_group_stages,
+ [:group_id, :name],
+ unique: true,
+ name: OLD_INDEX_NAME)
+
+ remove_concurrent_index_by_name :analytics_cycle_analytics_group_stages, NEW_INDEX_NAME
+ end
+end
diff --git a/db/migrate/20200729202222_add_index_to_ci_pipeline_project_id_created_at.rb b/db/migrate/20200729202222_add_index_to_ci_pipeline_project_id_created_at.rb
new file mode 100644
index 00000000000..d1ee9c49d30
--- /dev/null
+++ b/db/migrate/20200729202222_add_index_to_ci_pipeline_project_id_created_at.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexToCiPipelineProjectIdCreatedAt < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_pipelines, [:project_id, :created_at]
+ end
+
+ def down
+ remove_concurrent_index :ci_pipelines, [:project_id, :created_at]
+ end
+end
diff --git a/db/schema_migrations/20200728080250 b/db/schema_migrations/20200728080250
new file mode 100644
index 00000000000..137290c0e86
--- /dev/null
+++ b/db/schema_migrations/20200728080250
@@ -0,0 +1 @@
+546555a009e8923ea8b976ce38d882d387407fb03e7bbcb9c760df53bafd1f91 \ No newline at end of file
diff --git a/db/schema_migrations/20200729202222 b/db/schema_migrations/20200729202222
new file mode 100644
index 00000000000..2ab73a764f3
--- /dev/null
+++ b/db/schema_migrations/20200729202222
@@ -0,0 +1 @@
+2976f459ac9cd0780e90077ebe4ce5ca8dc41e62b4dab1f96e39738624ad9d04 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 4b1f18073c1..770fac47ffc 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -18880,8 +18880,6 @@ CREATE INDEX index_analytics_ca_group_stages_on_end_event_label_id ON public.ana
CREATE INDEX index_analytics_ca_group_stages_on_group_id ON public.analytics_cycle_analytics_group_stages USING btree (group_id);
-CREATE UNIQUE INDEX index_analytics_ca_group_stages_on_group_id_and_name ON public.analytics_cycle_analytics_group_stages USING btree (group_id, name);
-
CREATE INDEX index_analytics_ca_group_stages_on_relative_position ON public.analytics_cycle_analytics_group_stages USING btree (relative_position);
CREATE INDEX index_analytics_ca_group_stages_on_start_event_label_id ON public.analytics_cycle_analytics_group_stages USING btree (start_event_label_id);
@@ -19150,6 +19148,8 @@ CREATE INDEX index_ci_pipelines_on_merge_request_id ON public.ci_pipelines USING
CREATE INDEX index_ci_pipelines_on_pipeline_schedule_id ON public.ci_pipelines USING btree (pipeline_schedule_id);
+CREATE INDEX index_ci_pipelines_on_project_id_and_created_at ON public.ci_pipelines USING btree (project_id, created_at);
+
CREATE INDEX index_ci_pipelines_on_project_id_and_id_desc ON public.ci_pipelines USING btree (project_id, id DESC);
CREATE UNIQUE INDEX index_ci_pipelines_on_project_id_and_iid ON public.ci_pipelines USING btree (project_id, iid) WHERE (iid IS NOT NULL);
@@ -19654,6 +19654,8 @@ CREATE INDEX index_group_group_links_on_shared_with_group_id ON public.group_gro
CREATE INDEX index_group_import_states_on_group_id ON public.group_import_states USING btree (group_id);
+CREATE UNIQUE INDEX index_group_stages_on_group_id_group_value_stream_id_and_name ON public.analytics_cycle_analytics_group_stages USING btree (group_id, group_value_stream_id, name);
+
CREATE UNIQUE INDEX index_group_wiki_repositories_on_disk_path ON public.group_wiki_repositories USING btree (disk_path);
CREATE INDEX index_group_wiki_repositories_on_shard_id ON public.group_wiki_repositories USING btree (shard_id);
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 4343aa10d96..39b6c44811b 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -5861,6 +5861,7 @@ type InstanceSecurityDashboard {
State of a GitLab issue or merge request
"""
enum IssuableState {
+ all
closed
locked
opened
@@ -6434,6 +6435,51 @@ type IssueSetLockedPayload {
}
"""
+Autogenerated input type of IssueSetSubscription
+"""
+input IssueSetSubscriptionInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The IID of the issue to mutate
+ """
+ iid: String!
+
+ """
+ The project the issue to mutate is in
+ """
+ projectPath: ID!
+
+ """
+ The desired state of the subscription
+ """
+ subscribedState: Boolean!
+}
+
+"""
+Autogenerated return type of IssueSetSubscription
+"""
+type IssueSetSubscriptionPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ The issue after mutation
+ """
+ issue: Issue
+}
+
+"""
Autogenerated input type of IssueSetWeight
"""
input IssueSetWeightInput {
@@ -6562,6 +6608,7 @@ enum IssueSort {
State of a GitLab issue
"""
enum IssueState {
+ all
closed
locked
opened
@@ -7987,6 +8034,7 @@ type MergeRequestSetWipPayload {
State of a GitLab merge request
"""
enum MergeRequestState {
+ all
closed
locked
merged
@@ -8351,6 +8399,7 @@ type Mutation {
issueSetDueDate(input: IssueSetDueDateInput!): IssueSetDueDatePayload
issueSetIteration(input: IssueSetIterationInput!): IssueSetIterationPayload
issueSetLocked(input: IssueSetLockedInput!): IssueSetLockedPayload
+ issueSetSubscription(input: IssueSetSubscriptionInput!): IssueSetSubscriptionPayload
issueSetWeight(input: IssueSetWeightInput!): IssueSetWeightPayload
jiraImportStart(input: JiraImportStartInput!): JiraImportStartPayload
jiraImportUsers(input: JiraImportUsersInput!): JiraImportUsersPayload
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index fcc73efd770..f0d66d48e72 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -16186,6 +16186,12 @@
"description": null,
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "all",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -17854,6 +17860,136 @@
},
{
"kind": "INPUT_OBJECT",
+ "name": "IssueSetSubscriptionInput",
+ "description": "Autogenerated input type of IssueSetSubscription",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project the issue to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The IID of the issue to mutate",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "subscribedState",
+ "description": "The desired state of the subscription",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "IssueSetSubscriptionPayload",
+ "description": "Autogenerated return type of IssueSetSubscription",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issue",
+ "description": "The issue after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
"name": "IssueSetWeightInput",
"description": "Autogenerated input type of IssueSetWeight",
"fields": null,
@@ -18108,6 +18244,12 @@
"description": null,
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "all",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -22395,6 +22537,12 @@
"deprecationReason": null
},
{
+ "name": "all",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "merged",
"description": null,
"isDeprecated": false,
@@ -24358,6 +24506,33 @@
"deprecationReason": null
},
{
+ "name": "issueSetSubscription",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "IssueSetSubscriptionInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "IssueSetSubscriptionPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "issueSetWeight",
"description": null,
"args": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 5eaff5350eb..07bee288217 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -985,6 +985,16 @@ Autogenerated return type of IssueSetLocked
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `issue` | Issue | The issue after mutation |
+## IssueSetSubscriptionPayload
+
+Autogenerated return type of IssueSetSubscription
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `issue` | Issue | The issue after mutation |
+
## IssueSetWeightPayload
Autogenerated return type of IssueSetWeight
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index fd53ce79534..5753b96c774 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -230,7 +230,7 @@ Instead these should be sent to the [Release Manager](https://about.gitlab.com/c
- Ask for clarification. ("I didn't understand. Can you clarify?")
- Avoid selective ownership of code. ("mine", "not mine", "yours")
- Avoid using terms that could be seen as referring to personal traits. ("dumb",
- "stupid"). Assume everyone is attractive, intelligent, and well-meaning.
+ "stupid"). Assume everyone is intelligent and well-meaning.
- Be explicit. Remember people don't always understand your intentions online.
- Be humble. ("I'm not sure - let's look it up.")
- Don't use hyperbole. ("always", "never", "endlessly", "nothing")
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index 71d8a8fc7f9..cc492cc2d1a 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -481,7 +481,7 @@ We treat documentation as code, and so use tests in our CI pipeline to maintain
standards and quality of the docs. The current tests, which run in CI jobs when a
merge request with new or changed docs is submitted, are:
-- [`docs lint`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/docs.gitlab-ci.yml#L48):
+- [`docs lint`](https://gitlab.com/gitlab-org/gitlab/-/blob/0b562014f7b71f98540e682c8d662275f0011f2f/.gitlab/ci/docs.gitlab-ci.yml#L41):
Runs several tests on the content of the docs themselves:
- [`lint-doc.sh` script](https://gitlab.com/gitlab-org/gitlab/blob/master/scripts/lint-doc.sh)
runs the following checks and linters:
@@ -492,33 +492,20 @@ merge request with new or changed docs is submitted, are:
- [markdownlint](#markdownlint).
- [Vale](#vale).
- Nanoc tests:
- - [`internal_links`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/docs.gitlab-ci.yml#L67)
+ - [`internal_links`](https://gitlab.com/gitlab-org/gitlab/-/blob/0b562014f7b71f98540e682c8d662275f0011f2f/.gitlab/ci/docs.gitlab-ci.yml#L58)
checks that all internal links (ex: `[link](../index.md)`) are valid.
- - [`internal_anchors`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/docs.gitlab-ci.yml#L69)
+ - [`internal_anchors`](https://gitlab.com/gitlab-org/gitlab/-/blob/0b562014f7b71f98540e682c8d662275f0011f2f/.gitlab/ci/docs.gitlab-ci.yml#L60)
checks that all internal anchors (ex: `[link](../index.md#internal_anchor)`)
are valid.
+ - [`ui-docs-links lint`](https://gitlab.com/gitlab-org/gitlab/-/blob/0b562014f7b71f98540e682c8d662275f0011f2f/.gitlab/ci/docs.gitlab-ci.yml#L62)
+ checks that all links to docs from UI elements (`app/views` files, for example)
+ are linking to valid docs and anchors.
-### Running tests
+### Run tests locally
Apart from [previewing your changes locally](#previewing-the-changes-live), you can also run all lint checks
and Nanoc tests locally.
-#### Nanoc tests
-
-To execute Nanoc tests locally:
-
-1. Navigate to the [`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs) directory.
-1. Run:
-
- ```shell
- # Check for broken internal links
- bundle exec nanoc check internal_links
-
- # Check for broken external links (might take a lot of time to complete).
- # This test is set to be allowed to fail and is run only in the gitlab-docs project CI
- bundle exec nanoc check internal_anchors
- ```
-
#### Lint checks
Lint checks are performed by the [`lint-doc.sh`](https://gitlab.com/gitlab-org/gitlab/blob/master/scripts/lint-doc.sh)
@@ -550,6 +537,57 @@ The output should be similar to:
Note that this requires you to either have the required lint tools installed on your machine,
or a working Docker installation, in which case an image with these tools pre-installed will be used.
+#### Nanoc tests
+
+To execute Nanoc tests locally:
+
+1. Navigate to the [`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs) directory.
+1. Run:
+
+ ```shell
+ # Check for broken internal links
+ bundle exec nanoc check internal_links
+
+ # Check for broken external links (might take a lot of time to complete).
+ # This test is set to be allowed to fail and is run only in the gitlab-docs project CI
+ bundle exec nanoc check internal_anchors
+ ```
+
+#### `ui-docs-links` test
+
+The `ui-docs-links lint` job uses `haml-lint` to test that all links to docs from
+UI elements (`app/views` files, for example) are linking to valid docs and anchors.
+
+To run the `ui-docs-links` test locally:
+
+1. Open the `gitlab` directory in a terminal window.
+1. Run:
+
+ ```shell
+ bundle exec haml-lint -i DocumentationLinks
+ ```
+
+If you receive an error the first time you run this test, run `bundle install`, which
+installs GitLab's dependencies, and try again.
+
+If you don't want to install all of GitLab's dependencies to test the links, you can:
+
+1. Open the `gitlab` directory in a terminal window.
+1. Install `haml-lint`:
+
+ ```shell
+ gem install haml_lint
+ ```
+
+1. Run:
+
+ ```shell
+ haml-lint -i DocumentationLinks
+ ```
+
+If you manually install `haml-lint` with this process, it will not update automatically
+and you should make sure your version matches the version used by GitLab.
+
### Local linters
To help adhere to the [documentation style guidelines](styleguide.md), and improve the content
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index 3f6ae556c23..3a0b3b0a128 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -85,6 +85,7 @@ Default client accepts two parameters: `resolvers` and `config`.
- `cacheConfig` field accepts an optional object of settings to [customize Apollo cache](https://www.apollographql.com/docs/react/caching/cache-configuration/#configuring-the-cache)
- `baseUrl` allows us to pass a URL for GraphQL endpoint different from our main endpoint (i.e.`${gon.relative_url_root}/api/graphql`)
- `assumeImmutableResults` (set to `false` by default) - this setting, when set to `true`, will assume that every single operation on updating Apollo Cache is immutable. It also sets `freezeResults` to `true`, so any attempt on mutating Apollo Cache will throw a console warning in development environment. Please ensure you're following the immutability pattern on cache update operations before setting this option to `true`.
+ - `fetchPolicy` determines how you want your component to interact with the Apollo cache. Defaults to "cache-first".
## GraphQL Queries
@@ -167,9 +168,7 @@ import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
Vue.use(VueApollo);
-const defaultClient = createDefaultClient({
- resolvers: {}
-});
+const defaultClient = createDefaultClient();
defaultClient.cache.writeData({
data: {
@@ -257,10 +256,7 @@ We need to pass resolvers object to our existing Apollo Client:
import createDefaultClient from '~/lib/graphql';
import resolvers from './graphql/resolvers';
-const defaultClient = createDefaultClient(
- {},
- resolvers,
-);
+const defaultClient = createDefaultClient(resolvers);
```
Now every single time on attempt to fetch a version, our client will fetch `id` and `sha` from the remote API endpoint and will assign our hardcoded values to `author` and `createdAt` version properties. With this data, frontend developers are able to work on UI part without being blocked by backend. When actual response is added to the API, a custom local resolver can be removed fast and the only change to query/fragment is `@client` directive removal.
diff --git a/doc/development/sql.md b/doc/development/sql.md
index d584a26e455..3b969c7d27a 100644
--- a/doc/development/sql.md
+++ b/doc/development/sql.md
@@ -218,9 +218,9 @@ Project.select(:id, :user_id).joins(:merge_requests)
## Plucking IDs
-This can't be stressed enough: **never** use ActiveRecord's `pluck` to pluck a
-set of values into memory only to use them as an argument for another query. For
-example, this will make the database **very** sad:
+Never use ActiveRecord's `pluck` to pluck a set of values into memory only to
+use them as an argument for another query. For example, this will execute an
+extra unecessary database query and load a lot of unecessary data into memory:
```ruby
projects = Project.all.pluck(:id)
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index ec2806cb439..12ba55cafdc 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -31,8 +31,6 @@ file path fragments to start seeing results.
## Syntax highlighting
-> Support for `.gitlab-ci.yml` validation [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218472) in GitLab 13.2.
-
As expected from an IDE, syntax highlighting for many languages within
the Web IDE will make your direct editing even easier.
@@ -44,14 +42,6 @@ The Web IDE currently provides:
- IntelliSense and validation support (displaying errors and warnings, providing
smart completions, formatting, and outlining) for some languages. For example:
TypeScript, JavaScript, CSS, LESS, SCSS, JSON, and HTML.
-- Validation support for certain JSON and YAML files using schemas based on the
- [JSON Schema Store](https://www.schemastore.org/json/). This feature
- is only supported for the `.gitlab-ci.yml` file.
-
- NOTE: **Note:**
- Validation support based on schemas is hidden behind
- the feature flag `:schema_linting` on self-managed installations. To enable the
- feature, you can [turn on the feature flag in Rails console](../../../administration/feature_flags.md#how-to-enable-and-disable-features-behind-flags).
Because the Web IDE is based on the [Monaco Editor](https://microsoft.github.io/monaco-editor/),
you can find a more complete list of supported languages in the
@@ -63,6 +53,37 @@ If you are missing Syntax Highlighting support for any language, we prepared a s
NOTE: **Note:**
Single file editing is based on the [Ace Editor](https://ace.c9.io).
+### Schema based validation
+
+> - Support for `.gitlab-ci.yml` validation [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218472) in GitLab 13.2.
+> - It was deployed behind a feature flag, disabled by default.
+> - It's enabled on GitLab.com.
+> - It cannot be enabled or disabled per-project.
+> - For GitLab self-managed instances, GitLab administrators can opt to [enable it](#enable-or-disable-schema-based-validation-core-only).
+
+The Web IDE provides validation support for certain JSON and YAML files using schemas
+based on the [JSON Schema Store](https://www.schemastore.org/json/). This feature is
+only supported for the `.gitlab-ci.yml` file.
+
+#### Enable or disable Schema based validation **(CORE ONLY)**
+
+Schema based validation is under development and not ready for production use. It is
+deployed behind a feature flag that is **disabled by default** for self-managed instances,
+[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
+can enable it for your instance.
+
+To enable it:
+
+```ruby
+Feature.enable(:schema_linting)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:schema_linting)
+```
+
### Themes
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2389) in GitLab in 13.0.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 689e96a765b..5787c6f46e6 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8653,6 +8653,9 @@ msgstr ""
msgid "Edit Release"
msgstr ""
+msgid "Edit Requirement"
+msgstr ""
+
msgid "Edit Slack integration"
msgstr ""
@@ -12713,9 +12716,15 @@ msgstr ""
msgid "Incident Management Limits"
msgstr ""
+msgid "IncidentManagement|All incidents"
+msgstr ""
+
msgid "IncidentManagement|Assignees"
msgstr ""
+msgid "IncidentManagement|Closed"
+msgstr ""
+
msgid "IncidentManagement|Create incident"
msgstr ""
@@ -12731,6 +12740,9 @@ msgstr ""
msgid "IncidentManagement|No incidents to display."
msgstr ""
+msgid "IncidentManagement|Open"
+msgstr ""
+
msgid "IncidentManagement|There was an error displaying the incidents."
msgstr ""
@@ -15803,6 +15815,9 @@ msgstr ""
msgid "New Project"
msgstr ""
+msgid "New Requirement"
+msgstr ""
+
msgid "New Snippet"
msgstr ""
@@ -20335,9 +20350,6 @@ msgstr ""
msgid "Required in this project."
msgstr ""
-msgid "Requirement"
-msgstr ""
-
msgid "Requirement %{reference} has been added"
msgstr ""
diff --git a/spec/features/markdown/markdown_spec.rb b/spec/features/markdown/markdown_spec.rb
index d9d3f566bce..52f6c87b6aa 100644
--- a/spec/features/markdown/markdown_spec.rb
+++ b/spec/features/markdown/markdown_spec.rb
@@ -217,7 +217,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures do
it_behaves_like 'all pipelines'
- it 'includes custom filters' do
+ it 'includes custom filters', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/233077' do
aggregate_failures 'UploadLinkFilter' do
expect(doc).to parse_upload_links
end
@@ -282,7 +282,7 @@ RSpec.describe 'GitLab Markdown', :aggregate_failures do
it_behaves_like 'all pipelines'
- it 'includes custom filters' do
+ it 'includes custom filters', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/233077' do
aggregate_failures 'UploadLinkFilter' do
expect(doc).to parse_upload_links
end
diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb
index 73d033cbdb8..3db870f229a 100644
--- a/spec/features/projects/snippets/create_snippet_spec.rb
+++ b/spec/features/projects/snippets/create_snippet_spec.rb
@@ -2,9 +2,28 @@
require 'spec_helper'
-RSpec.shared_examples_for 'snippet editor' do
+RSpec.describe 'Projects > Snippets > Create Snippet', :js do
+ include DropzoneHelper
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) do
+ create(:project, :public, creator: user).tap do |p|
+ p.add_maintainer(user)
+ end
+ end
+
+ let(:title) { 'My Snippet Title' }
+ let(:file_content) { 'Hello World!' }
+ let(:md_description) { 'My Snippet **Description**' }
+ let(:description) { 'My Snippet Description' }
+
before do
+ stub_feature_flags(snippets_vue: false)
stub_feature_flags(snippets_edit_vue: false)
+
+ sign_in(user)
+
+ visit new_project_snippet_path(project)
end
def description_field
@@ -12,137 +31,81 @@ RSpec.shared_examples_for 'snippet editor' do
end
def fill_form
- fill_in 'project_snippet_title', with: 'My Snippet Title'
+ fill_in 'project_snippet_title', with: title
# Click placeholder first to expand full description field
description_field.click
- fill_in 'project_snippet_description', with: 'My Snippet **Description**'
+ fill_in 'project_snippet_description', with: md_description
page.within('.file-editor') do
el = find('.inputarea')
- el.send_keys 'Hello World!'
+ el.send_keys file_content
end
end
- context 'when a user is authenticated' do
- before do
- stub_feature_flags(snippets_vue: false)
- project.add_maintainer(user)
- sign_in(user)
+ it 'shows collapsible description input' do
+ collapsed = description_field
- visit project_snippets_path(project)
-
- # Wait for the SVG to ensure the button location doesn't shift
- within('.empty-state') { find('img.js-lazy-loaded') }
- click_on('New snippet')
- wait_for_requests
- end
+ expect(page).not_to have_field('project_snippet_description')
+ expect(collapsed).to be_visible
- it 'shows collapsible description input' do
- collapsed = description_field
+ collapsed.click
- expect(page).not_to have_field('project_snippet_description')
- expect(collapsed).to be_visible
+ expect(page).to have_field('project_snippet_description')
+ expect(collapsed).not_to be_visible
+ end
- collapsed.click
+ it 'creates a new snippet' do
+ fill_form
+ click_button('Create snippet')
+ wait_for_requests
- expect(page).to have_field('project_snippet_description')
- expect(collapsed).not_to be_visible
+ expect(page).to have_content(title)
+ expect(page).to have_content(file_content)
+ page.within('.snippet-header .description') do
+ expect(page).to have_content(description)
+ expect(page).to have_selector('strong')
end
+ end
- it 'creates a new snippet' do
- fill_form
- click_button('Create snippet')
- wait_for_requests
+ it 'uploads a file when dragging into textarea' do
+ fill_form
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
- expect(page).to have_content('My Snippet Title')
- expect(page).to have_content('Hello World!')
- page.within('.snippet-header .description') do
- expect(page).to have_content('My Snippet Description')
- expect(page).to have_selector('strong')
- end
- end
+ expect(page.find_field('project_snippet_description').value).to have_content('banana_sample')
- it 'uploads a file when dragging into textarea' do
- fill_form
- dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+ click_button('Create snippet')
+ wait_for_requests
- expect(page.find_field("project_snippet_description").value).to have_content('banana_sample')
+ link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
+ expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z})
+ end
- click_button('Create snippet')
- wait_for_requests
+ it 'displays validation errors' do
+ fill_in 'project_snippet_title', with: title
+ click_button('Create snippet')
+ wait_for_requests
- link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
- expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z})
- end
+ expect(page).to have_selector('#error_explanation')
+ end
- it 'creates a snippet when all required fields are filled in after validation failing' do
- fill_in 'project_snippet_title', with: 'My Snippet Title'
- click_button('Create snippet')
+ context 'when the git operation fails' do
+ let(:error) { 'Error creating the snippet' }
- expect(page).to have_selector('#error_explanation')
+ before do
+ allow_next_instance_of(Snippets::CreateService) do |instance|
+ allow(instance).to receive(:create_commit).and_raise(StandardError, error)
+ end
fill_form
- dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
- find("input[value='Create snippet']").send_keys(:return)
+ click_button('Create snippet')
wait_for_requests
-
- expect(page).to have_content('My Snippet Title')
- expect(page).to have_content('Hello World!')
- page.within('.snippet-header .description') do
- expect(page).to have_content('My Snippet Description')
- expect(page).to have_selector('strong')
- end
- link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
- expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z})
- end
-
- context 'when the git operation fails' do
- let(:error) { 'Error creating the snippet' }
-
- before do
- allow_next_instance_of(Snippets::CreateService) do |instance|
- allow(instance).to receive(:create_commit).and_raise(StandardError, error)
- end
-
- fill_form
-
- click_button('Create snippet')
- wait_for_requests
- end
-
- it 'displays the error' do
- expect(page).to have_content(error)
- end
-
- it 'renders new page' do
- expect(page).to have_content('New Snippet')
- end
end
- end
-
- context 'when a user is not authenticated' do
- before do
- stub_feature_flags(snippets_vue: false)
- end
-
- it 'shows a public snippet on the index page but not the New snippet button' do
- snippet = create(:project_snippet, :public, :repository, project: project)
-
- visit project_snippets_path(project)
- expect(page).to have_content(snippet.title)
- expect(page).not_to have_content('New snippet')
+ it 'renders the new page and displays the error' do
+ expect(page).to have_content(error)
+ expect(page).to have_content('New Snippet')
end
end
end
-
-RSpec.describe 'Projects > Snippets > Create Snippet', :js do
- include DropzoneHelper
-
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project, :public) }
-
- it_behaves_like "snippet editor"
-end
diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb
index 0f6429d49f6..8fded3cde80 100644
--- a/spec/features/projects/snippets/show_spec.rb
+++ b/spec/features/projects/snippets/show_spec.rb
@@ -3,157 +3,41 @@
require 'spec_helper'
RSpec.describe 'Projects > Snippets > Project snippet', :js do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
- let(:snippet) { create(:project_snippet, project: project, file_name: file_name, content: content) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) do
+ create(:project, creator: user).tap do |p|
+ p.add_maintainer(user)
+ end
+ end
+
+ let_it_be(:snippet) { create(:project_snippet, :repository, project: project, author: user) }
before do
stub_feature_flags(snippets_vue: false)
- project.add_maintainer(user)
+
sign_in(user)
end
- context 'Ruby file' do
- let(:file_name) { 'popen.rb' }
- let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data }
+ it_behaves_like 'show and render proper snippet blob' do
+ let(:anchor) { nil }
- before do
- visit project_snippet_path(project, snippet)
+ subject do
+ visit project_snippet_path(project, snippet, anchor: anchor)
wait_for_requests
end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows highlighted Ruby code
- expect(page).to have_content("require 'fileutils'")
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
-
- # shows a raw button
- expect(page).to have_link('Open raw')
-
- # shows a download button
- expect(page).to have_link('Download')
- end
- end
end
- context 'Markdown file' do
- let(:file_name) { 'ruby-style-guide.md' }
- let(:content) { project.repository.blob_at('master', 'files/markdown/ruby-style-guide.md').data }
-
- context 'visiting directly' do
- before do
- visit project_snippet_path(project, snippet)
-
- wait_for_requests
- end
-
- it 'displays the blob using the rich viewer' do
- aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
-
- # shows rendered Markdown
- expect(page).to have_link("PEP-8")
-
- # shows a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
-
- # shows a disabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
-
- # shows a raw button
- expect(page).to have_link('Open raw')
-
- # shows a download button
- expect(page).to have_link('Download')
- end
- end
-
- context 'switching to the simple viewer' do
- before do
- find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
-
- wait_for_requests
- end
-
- it 'displays the blob using the simple viewer' do
- aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
-
- # shows highlighted Markdown code
- expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
- end
- end
-
- context 'switching to the rich viewer again' do
- before do
- find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
-
- wait_for_requests
- end
-
- it 'displays the blob using the rich viewer' do
- aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
- end
- end
- end
- end
- end
-
- context 'visiting with a line number anchor' do
- before do
- visit project_snippet_path(project, snippet, anchor: 'L1')
-
- wait_for_requests
- end
-
- it 'displays the blob using the simple viewer' do
- aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
-
- # highlights the line in question
- expect(page).to have_selector('#LC1.hll')
-
- # shows highlighted Markdown code
- expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+ it_behaves_like 'showing user status' do
+ let(:file_path) { 'files/ruby/popen.rb' }
+ let(:user_with_status) { snippet.author }
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
- end
- end
- end
+ subject { visit project_snippet_path(project, snippet) }
end
- it_behaves_like 'showing user status' do
- let(:file_name) { 'ruby-style-guide.md' }
- let(:content) { project.repository.blob_at('master', 'files/markdown/ruby-style-guide.md').data }
-
- let(:user_with_status) { snippet.author }
+ it_behaves_like 'does not show New Snippet button' do
+ let(:file_path) { 'files/ruby/popen.rb' }
- subject do
- visit project_snippet_path(project, snippet)
- wait_for_requests
- end
+ subject { visit project_snippet_path(project, snippet) }
end
end
diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb
index 9125ed74273..981ed12d540 100644
--- a/spec/features/snippets/show_spec.rb
+++ b/spec/features/snippets/show_spec.rb
@@ -3,180 +3,33 @@
require 'spec_helper'
RSpec.describe 'Snippet', :js do
- let(:project) { create(:project, :repository) }
- let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:snippet) { create(:personal_snippet, :public, :repository, author: user) }
before do
stub_feature_flags(snippets_vue: false)
end
- context 'Ruby file' do
- let(:file_name) { 'popen.rb' }
- let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data }
+ it_behaves_like 'show and render proper snippet blob' do
+ let(:anchor) { nil }
- before do
- visit snippet_path(snippet)
+ subject do
+ visit snippet_path(snippet, anchor: anchor)
wait_for_requests
end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows highlighted Ruby code
- expect(page).to have_content("require 'fileutils'")
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
-
- # shows a raw button
- expect(page).to have_link('Open raw')
-
- # shows a download button
- expect(page).to have_link('Download')
- end
- end
- end
-
- context 'Markdown file' do
- let(:file_name) { 'ruby-style-guide.md' }
- let(:content) { project.repository.blob_at('master', 'files/markdown/ruby-style-guide.md').data }
-
- context 'visiting directly' do
- before do
- visit snippet_path(snippet)
-
- wait_for_requests
- end
-
- it 'displays the blob using the rich viewer' do
- aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
-
- # shows rendered Markdown
- expect(page).to have_link("PEP-8")
-
- # shows a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
-
- # shows a disabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
-
- # shows a raw button
- expect(page).to have_link('Open raw')
-
- # shows a download button
- expect(page).to have_link('Download')
- end
- end
-
- context 'Markdown rendering' do
- let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content) }
- let(:file_name) { 'test.md' }
- let(:content) { "1. one\n - sublist\n" }
-
- context 'when rendering default markdown' do
- it 'renders using CommonMark' do
- expect(page).to have_content("sublist")
- expect(page).not_to have_xpath("//ol//li//ul")
- end
- end
- end
-
- context 'switching to the simple viewer' do
- before do
- find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
-
- wait_for_requests
- end
-
- it 'displays the blob using the simple viewer' do
- aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
-
- # shows highlighted Markdown code
- expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
- end
- end
-
- context 'switching to the rich viewer again' do
- before do
- find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
-
- wait_for_requests
- end
-
- it 'displays the blob using the rich viewer' do
- aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
- end
- end
- end
- end
- end
-
- context 'visiting with a line number anchor' do
- before do
- visit snippet_path(snippet, anchor: 'L1')
-
- wait_for_requests
- end
-
- it 'displays the blob using the simple viewer' do
- aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
-
- # highlights the line in question
- expect(page).to have_selector('#LC1.hll')
-
- # shows highlighted Markdown code
- expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
- end
- end
- end
end
it_behaves_like 'showing user status' do
- let(:file_name) { 'popen.rb' }
- let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data }
+ let(:file_path) { 'files/ruby/popen.rb' }
let(:user_with_status) { snippet.author }
subject { visit snippet_path(snippet) }
end
- context 'when user cannot create snippets' do
- let(:user) { create(:user, :external) }
- let(:snippet) { create(:personal_snippet, :public) }
-
- before do
- sign_in(user)
-
- visit snippet_path(snippet)
+ it_behaves_like 'does not show New Snippet button' do
+ let(:file_path) { 'files/ruby/popen.rb' }
- wait_for_requests
- end
-
- it 'does not show the "New Snippet" button' do
- expect(page).not_to have_link('New snippet')
- end
+ subject { visit snippet_path(snippet) }
end
end
diff --git a/spec/frontend/alert_management/components/alert_management_table_spec.js b/spec/frontend/alert_management/components/alert_management_table_spec.js
index d51fbe5fda5..235f86ae533 100644
--- a/spec/frontend/alert_management/components/alert_management_table_spec.js
+++ b/spec/frontend/alert_management/components/alert_management_table_spec.js
@@ -13,6 +13,7 @@ import {
GlSearchBoxByType,
} from '@gitlab/ui';
import { visitUrl } from '~/lib/utils/url_utility';
+import waitForPromises from 'helpers/wait_for_promises';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import AlertManagementTable from '~/alert_management/components/alert_management_table.vue';
import { ALERTS_STATUS_TABS, trackAlertStatusUpdateOptions } from '~/alert_management/constants';
@@ -44,6 +45,7 @@ describe('AlertManagementTable', () => {
const findPagination = () => wrapper.find(GlPagination);
const findSearch = () => wrapper.find(GlSearchBoxByType);
const findIssueFields = () => wrapper.findAll('[data-testid="issueField"]');
+ const findAlertError = () => wrapper.find('[data-testid="alert-error"]');
const alertsCount = {
open: 14,
triggered: 10,
@@ -51,6 +53,11 @@ describe('AlertManagementTable', () => {
resolved: 1,
all: 16,
};
+ const selectFirstStatusOption = () => {
+ findFirstStatusOption().vm.$emit('click');
+
+ return waitForPromises();
+ };
function mountComponent({
props = {
@@ -138,7 +145,7 @@ describe('AlertManagementTable', () => {
it('error state', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { errors: ['error'] }, alertsCount: null, errored: true },
+ data: { alerts: { errors: ['error'] }, alertsCount: null, hasError: true },
loading: false,
});
expect(findAlertsTable().exists()).toBe(true);
@@ -155,7 +162,7 @@ describe('AlertManagementTable', () => {
it('empty state', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: [], pageInfo: {} }, alertsCount: { all: 0 }, errored: false },
+ data: { alerts: { list: [], pageInfo: {} }, alertsCount: { all: 0 }, hasError: false },
loading: false,
});
expect(findAlertsTable().exists()).toBe(true);
@@ -172,7 +179,7 @@ describe('AlertManagementTable', () => {
it('has data state', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
expect(findLoader().exists()).toBe(false);
@@ -188,7 +195,7 @@ describe('AlertManagementTable', () => {
it('displays status dropdown', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
expect(findStatusDropdown().exists()).toBe(true);
@@ -197,7 +204,7 @@ describe('AlertManagementTable', () => {
it('does not display a dropdown status header', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
expect(findStatusDropdown().contains('.dropdown-title')).toBe(false);
@@ -206,7 +213,7 @@ describe('AlertManagementTable', () => {
it('shows correct severity icons', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
@@ -223,7 +230,7 @@ describe('AlertManagementTable', () => {
it('renders severity text', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
@@ -237,7 +244,7 @@ describe('AlertManagementTable', () => {
it('renders Unassigned when no assignee(s) present', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
@@ -251,7 +258,7 @@ describe('AlertManagementTable', () => {
it('renders username(s) when assignee(s) present', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
@@ -265,7 +272,7 @@ describe('AlertManagementTable', () => {
it('navigates to the detail page when alert row is clicked', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
@@ -279,7 +286,7 @@ describe('AlertManagementTable', () => {
beforeEach(() => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
});
@@ -323,7 +330,7 @@ describe('AlertManagementTable', () => {
],
},
alertsCount,
- errored: false,
+ hasError: false,
},
loading: false,
});
@@ -343,7 +350,7 @@ describe('AlertManagementTable', () => {
},
],
alertsCount,
- errored: false,
+ hasError: false,
},
loading: false,
});
@@ -358,7 +365,7 @@ describe('AlertManagementTable', () => {
it('should highlight the row when alert is new', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: [newAlert] }, alertsCount, errored: false },
+ data: { alerts: { list: [newAlert] }, alertsCount, hasError: false },
loading: false,
});
@@ -372,7 +379,7 @@ describe('AlertManagementTable', () => {
it('should not highlight the row when alert is not new', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: [oldAlert] }, alertsCount, errored: false },
+ data: { alerts: { list: [oldAlert] }, alertsCount, hasError: false },
loading: false,
});
@@ -392,7 +399,7 @@ describe('AlertManagementTable', () => {
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
data: {
alerts: { list: mockAlerts },
- errored: false,
+ hasError: false,
sort: 'STARTED_AT_DESC',
alertsCount,
},
@@ -429,7 +436,7 @@ describe('AlertManagementTable', () => {
beforeEach(() => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
});
@@ -448,19 +455,36 @@ describe('AlertManagementTable', () => {
});
});
- it('shows an error when request fails', () => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
- findFirstStatusOption().vm.$emit('click');
- wrapper.setData({
- errored: true,
+ describe('when a request fails', () => {
+ beforeEach(() => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
});
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.find('[data-testid="alert-error"]').exists()).toBe(true);
+ it('shows an error', async () => {
+ await selectFirstStatusOption();
+
+ expect(findAlertError().text()).toContain(
+ 'There was an error while updating the status of the alert.',
+ );
+ });
+
+ it('shows an error when triggered a second time', async () => {
+ await selectFirstStatusOption();
+
+ wrapper.find(GlAlert).vm.$emit('dismiss');
+
+ await wrapper.vm.$nextTick();
+
+ // Assert that the error has been dismissed in the setup
+ expect(findAlertError().exists()).toBe(false);
+
+ await selectFirstStatusOption();
+
+ expect(findAlertError().exists()).toBe(true);
});
});
- it('shows an error when response includes HTML errors', () => {
+ it('shows an error when response includes HTML errors', async () => {
const mockUpdatedMutationErrorResult = {
data: {
updateAlertStatus: {
@@ -474,13 +498,11 @@ describe('AlertManagementTable', () => {
};
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationErrorResult);
- findFirstStatusOption().vm.$emit('click');
- wrapper.setData({ errored: true });
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.contains('[data-testid="alert-error"]')).toBe(true);
- expect(wrapper.contains('[data-testid="htmlError"]')).toBe(true);
- });
+ await selectFirstStatusOption();
+
+ expect(findAlertError().exists()).toBe(true);
+ expect(findAlertError().contains('[data-testid="htmlError"]')).toBe(true);
});
});
@@ -510,7 +532,7 @@ describe('AlertManagementTable', () => {
beforeEach(() => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts, pageInfo: {} }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts, pageInfo: {} }, alertsCount, hasError: false },
loading: false,
});
});
@@ -570,7 +592,7 @@ describe('AlertManagementTable', () => {
beforeEach(() => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
loading: false,
});
});
diff --git a/spec/frontend/incidents/components/incidents_list_spec.js b/spec/frontend/incidents/components/incidents_list_spec.js
index e067ef744fd..4a17fb7393a 100644
--- a/spec/frontend/incidents/components/incidents_list_spec.js
+++ b/spec/frontend/incidents/components/incidents_list_spec.js
@@ -6,11 +6,12 @@ import {
GlAvatar,
GlPagination,
GlSearchBoxByType,
+ GlTab,
} from '@gitlab/ui';
import { visitUrl, joinPaths } from '~/lib/utils/url_utility';
import IncidentsList from '~/incidents/components/incidents_list.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import { I18N } from '~/incidents/constants';
+import { I18N, INCIDENT_STATE_TABS } from '~/incidents/constants';
import mockIncidents from '../mocks/incidents.json';
jest.mock('~/lib/utils/url_utility', () => ({
@@ -34,6 +35,7 @@ describe('Incidents List', () => {
const findSearch = () => wrapper.find(GlSearchBoxByType);
const findClosedIcon = () => wrapper.findAll("[data-testid='incident-closed']");
const findPagination = () => wrapper.find(GlPagination);
+ const findStatusFilterTabs = () => wrapper.findAll(GlTab);
function mountComponent({ data = { incidents: [] }, loading = false }) {
wrapper = mount(IncidentsList, {
@@ -280,5 +282,25 @@ describe('Incidents List', () => {
expect(wrapper.vm.$data.searchTerm).toBe(SEARCH_TERM);
});
});
+
+ describe('State Filter Tabs', () => {
+ beforeEach(() => {
+ mountComponent({
+ data: { incidents: mockIncidents },
+ loading: false,
+ stubs: {
+ GlTab: true,
+ },
+ });
+ });
+
+ it('should display filter tabs', () => {
+ const tabs = findStatusFilterTabs().wrappers;
+
+ tabs.forEach((tab, i) => {
+ expect(tab.attributes('data-testid')).toContain(INCIDENT_STATE_TABS[i].state);
+ });
+ });
+ });
});
});
diff --git a/spec/graphql/mutations/issues/set_subscription_spec.rb b/spec/graphql/mutations/issues/set_subscription_spec.rb
new file mode 100644
index 00000000000..9e05a136c0b
--- /dev/null
+++ b/spec/graphql/mutations/issues/set_subscription_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Issues::SetSubscription do
+ it_behaves_like 'a subscribeable graphql resource' do
+ let_it_be(:resource) { create(:issue) }
+ let(:permission_name) { :update_issue }
+ end
+end
diff --git a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
index 20cfed9dd3d..600053637c9 100644
--- a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
@@ -3,44 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::MergeRequests::SetSubscription do
- let(:merge_request) { create(:merge_request) }
- let(:project) { merge_request.project }
- let(:user) { create(:user) }
-
- subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
-
- specify { expect(described_class).to require_graphql_authorizations(:update_merge_request) }
-
- describe '#resolve' do
- let(:subscribe) { true }
- let(:mutated_merge_request) { subject[:merge_request] }
-
- subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, subscribed_state: subscribe) }
-
- it 'raises an error if the resource is not accessible to the user' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
- end
-
- context 'when the user can update the merge request' do
- before do
- merge_request.project.add_developer(user)
- end
-
- it 'returns the merge request as discussion locked' do
- expect(mutated_merge_request).to eq(merge_request)
- expect(mutated_merge_request.subscribed?(user, project)).to eq(true)
- expect(subject[:errors]).to be_empty
- end
-
- context 'when passing subscribe as false' do
- let(:subscribe) { false }
-
- it 'unsubscribes from the discussion' do
- merge_request.subscribe(user, project)
-
- expect(mutated_merge_request.subscribed?(user, project)).to eq(false)
- end
- end
- end
+ it_behaves_like 'a subscribeable graphql resource' do
+ let_it_be(:resource) { create(:merge_request) }
+ let(:permission_name) { :update_merge_request }
end
end
diff --git a/spec/migrations/20200728080250_replace_unique_index_on_cycle_analytics_stages_spec.rb b/spec/migrations/20200728080250_replace_unique_index_on_cycle_analytics_stages_spec.rb
new file mode 100644
index 00000000000..f9a56bf649d
--- /dev/null
+++ b/spec/migrations/20200728080250_replace_unique_index_on_cycle_analytics_stages_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20200728080250_replace_unique_index_on_cycle_analytics_stages.rb')
+
+RSpec.describe ReplaceUniqueIndexOnCycleAnalyticsStages, :migration, schema: 20200728080250 do
+ let(:namespaces) { table(:namespaces) }
+ let(:group_value_streams) { table(:analytics_cycle_analytics_group_value_streams) }
+ let(:group_stages) { table(:analytics_cycle_analytics_group_stages) }
+
+ let(:group) { namespaces.create!(type: 'Group', name: 'test', path: 'test') }
+
+ let(:value_stream_1) { group_value_streams.create!(group_id: group.id, name: 'vs1') }
+ let(:value_stream_2) { group_value_streams.create!(group_id: group.id, name: 'vs2') }
+
+ let(:duplicated_stage_1) { group_stages.create!(group_id: group.id, group_value_stream_id: value_stream_1.id, name: 'stage', start_event_identifier: 1, end_event_identifier: 1) }
+ let(:duplicated_stage_2) { group_stages.create!(group_id: group.id, group_value_stream_id: value_stream_2.id, name: 'stage', start_event_identifier: 1, end_event_identifier: 1) }
+
+ let(:stage_record) { group_stages.create!(group_id: group.id, group_value_stream_id: value_stream_2.id, name: 'other stage', start_event_identifier: 1, end_event_identifier: 1) }
+
+ describe '#down' do
+ subject { described_class.new.down }
+
+ before do
+ described_class.new.up
+
+ duplicated_stage_1
+ duplicated_stage_2
+ stage_record
+ end
+
+ it 'removes duplicated stage records' do
+ subject
+
+ stage = group_stages.find_by_id(duplicated_stage_2.id)
+ expect(stage).to be_nil
+ end
+
+ it 'does not change the first duplicated stage record' do
+ expect { subject }.not_to change { duplicated_stage_1.reload.attributes }
+ end
+
+ it 'does not change not duplicated stage record' do
+ expect { subject }.not_to change { stage_record.reload.attributes }
+ end
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index d2aa9340a8d..4609ac7fe56 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -4125,7 +4125,6 @@ RSpec.describe Project do
end
it 'removes the pages directory and marks the project as not having pages deployed' do
- expect_any_instance_of(Projects::UpdatePagesConfigurationService).to receive(:execute)
expect_any_instance_of(Gitlab::PagesTransfer).to receive(:rename_project).and_return(true)
expect(PagesWorker).to receive(:perform_in).with(5.minutes, :remove, namespace.full_path, anything)
diff --git a/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb b/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb
new file mode 100644
index 00000000000..1edc1e0553b
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Setting subscribed status of an issue' do
+ include GraphqlHelpers
+
+ it_behaves_like 'a subscribable resource api' do
+ let_it_be(:resource) { create(:issue) }
+ let(:mutation_name) { :issue_set_subscription }
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb
index 6b3035fbf48..d90faa605c0 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb
@@ -5,59 +5,8 @@ require 'spec_helper'
RSpec.describe 'Setting subscribed status of a merge request' do
include GraphqlHelpers
- let(:current_user) { create(:user) }
- let(:merge_request) { create(:merge_request) }
- let(:project) { merge_request.project }
- let(:input) { { subscribed_state: true } }
-
- let(:mutation) do
- variables = {
- project_path: project.full_path,
- iid: merge_request.iid.to_s
- }
- graphql_mutation(:merge_request_set_subscription, variables.merge(input),
- <<-QL.strip_heredoc
- clientMutationId
- errors
- mergeRequest {
- id
- subscribed
- }
- QL
- )
- end
-
- def mutation_response
- graphql_mutation_response(:merge_request_set_subscription)['mergeRequest']['subscribed']
- end
-
- before do
- project.add_developer(current_user)
- end
-
- it 'returns an error if the user is not allowed to update the merge request' do
- post_graphql_mutation(mutation, current_user: create(:user))
-
- expect(graphql_errors).not_to be_empty
- end
-
- it 'marks the merge request as WIP' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response).to eq(true)
- end
-
- context 'when passing subscribe false as input' do
- let(:input) { { subscribed_state: false } }
-
- it 'unmarks the merge request as subscribed' do
- merge_request.subscribe(current_user, project)
-
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response).to eq(false)
- end
+ it_behaves_like 'a subscribable resource api' do
+ let_it_be(:resource) { create(:merge_request) }
+ let(:mutation_name) { :merge_request_set_subscription }
end
end
diff --git a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
index ee3c55cb642..5263fd40a40 100644
--- a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
+++ b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Metrics::Dashboard::GrafanaMetricEmbedService do
include ReactiveCachingHelpers
include GrafanaApiHelpers
- let_it_be(:project) { build(:project) }
+ let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:grafana_integration) { create(:grafana_integration, project: project) }
@@ -15,7 +15,7 @@ RSpec.describe Metrics::Dashboard::GrafanaMetricEmbedService do
valid_grafana_dashboard_link(grafana_integration.grafana_url)
end
- before do
+ before_all do
project.add_maintainer(user)
end
@@ -58,6 +58,31 @@ RSpec.describe Metrics::Dashboard::GrafanaMetricEmbedService do
expect(subject.current_user).to eq(user)
expect(subject.params[:grafana_url]).to eq(grafana_url)
end
+
+ context 'with unknown users' do
+ let(:params) { [project.id, current_user_id, grafana_url] }
+
+ context 'when anonymous' do
+ where(:current_user_id) do
+ [nil, '']
+ end
+
+ with_them do
+ it 'sets current_user as nil' do
+ expect(subject.current_user).to be_nil
+ end
+ end
+ end
+
+ context 'when invalid' do
+ let(:current_user_id) { non_existing_record_id }
+
+ it 'raise record not found error' do
+ expect { subject }
+ .to raise_error(ActiveRecord::RecordNotFound, /Couldn't find User/)
+ end
+ end
+ end
end
describe '#get_dashboard', :use_clean_rails_memory_store_caching do
@@ -145,7 +170,17 @@ RSpec.describe Metrics::Dashboard::GrafanaMetricEmbedService do
stub_datasource_request(grafana_integration.grafana_url)
end
- it_behaves_like 'valid embedded dashboard service response'
+ context 'when project is private and user is member' do
+ it_behaves_like 'valid embedded dashboard service response'
+ end
+
+ context 'when project is public and user is anonymous' do
+ let(:project) { create(:project, :public) }
+ let(:user) { nil }
+ let(:grafana_integration) { create(:grafana_integration, project: project) }
+
+ it_behaves_like 'valid embedded dashboard service response'
+ end
end
end
diff --git a/spec/support/shared_examples/features/snippets_shared_examples.rb b/spec/support/shared_examples/features/snippets_shared_examples.rb
index 1c8a9714bdf..0ac0dc72017 100644
--- a/spec/support/shared_examples/features/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/features/snippets_shared_examples.rb
@@ -50,3 +50,145 @@ RSpec.shared_examples 'tabs with counts' do
expect(tab.find('.badge').text).to eq(counts[:public])
end
end
+
+RSpec.shared_examples 'does not show New Snippet button' do
+ let(:user) { create(:user, :external) }
+
+ specify do
+ sign_in(user)
+
+ subject
+
+ wait_for_requests
+
+ expect(page).not_to have_link('New snippet')
+ end
+end
+
+RSpec.shared_examples 'show and render proper snippet blob' do
+ before do
+ allow_any_instance_of(Snippet).to receive(:blobs).and_return([snippet.repository.blob_at('master', file_path)])
+ end
+
+ context 'Ruby file' do
+ let(:file_path) { 'files/ruby/popen.rb' }
+
+ it 'displays the blob' do
+ subject
+
+ aggregate_failures do
+ # shows highlighted Ruby code
+ expect(page).to have_content("require 'fileutils'")
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+ end
+
+ context 'Markdown file' do
+ let(:file_path) { 'files/markdown/ruby-style-guide.md' }
+
+ context 'visiting directly' do
+ before do
+ subject
+ end
+
+ it 'displays the blob using the rich viewer' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows rendered Markdown
+ expect(page).to have_link("PEP-8")
+
+ # shows a viewer switcher
+ expect(page).to have_selector('.js-blob-viewer-switcher')
+
+ # shows a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+
+ context 'switching to the simple viewer' do
+ before do
+ find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
+
+ wait_for_requests
+ end
+
+ it 'displays the blob using the simple viewer' do
+ aggregate_failures do
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+
+ # shows highlighted Markdown code
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ end
+ end
+
+ context 'switching to the rich viewer again' do
+ before do
+ find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
+
+ wait_for_requests
+ end
+
+ it 'displays the blob using the rich viewer' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ end
+ end
+ end
+ end
+ end
+
+ context 'visiting with a line number anchor' do
+ let(:anchor) { 'L1' }
+
+ it 'displays the blob using the simple viewer' do
+ subject
+
+ aggregate_failures do
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+
+ # highlights the line in question
+ expect(page).to have_selector('#LC1.hll')
+
+ # shows highlighted Markdown code
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb
new file mode 100644
index 00000000000..ebba312e895
--- /dev/null
+++ b/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples 'a subscribeable graphql resource' do
+ let(:project) { resource.project }
+ let_it_be(:user) { create(:user) }
+
+ subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
+
+ specify { expect(described_class).to require_graphql_authorizations(permission_name) }
+
+ describe '#resolve' do
+ let(:subscribe) { true }
+ let(:mutated_resource) { subject[resource.class.name.underscore.to_sym] }
+
+ subject { mutation.resolve(project_path: resource.project.full_path, iid: resource.iid, subscribed_state: subscribe) }
+
+ it 'raises an error if the resource is not accessible to the user' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+
+ context 'when the user can update the resource' do
+ before do
+ resource.project.add_developer(user)
+ end
+
+ it 'subscribes to the resource' do
+ expect(mutated_resource).to eq(resource)
+ expect(mutated_resource.subscribed?(user, project)).to eq(true)
+ expect(subject[:errors]).to be_empty
+ end
+
+ context 'when passing subscribe as false' do
+ let(:subscribe) { false }
+
+ it 'unsubscribes from the discussion' do
+ resource.subscribe(user, project)
+
+ expect(mutated_resource.subscribed?(user, project)).to eq(false)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/graphql/mutations/subscription_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/mutations/subscription_shared_examples.rb
new file mode 100644
index 00000000000..40b88ef370f
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/mutations/subscription_shared_examples.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples 'a subscribable resource api' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let(:project) { resource.project }
+ let(:input) { { subscribed_state: true } }
+ let(:resource_ref) { resource.class.name.camelize(:lower) }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: resource.iid.to_s
+ }
+
+ graphql_mutation(
+ mutation_name,
+ variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ #{resource_ref} {
+ id
+ subscribed
+ }
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(mutation_name)[resource_ref]['subscribed']
+ end
+
+ context 'when the user is not authorized' do
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ["The resource that you are attempting to access "\
+ "does not exist or you don't have permission to "\
+ "perform this action"]
+ end
+
+ context 'when user is authorized' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'marks the resource as subscribed' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response).to eq(true)
+ end
+
+ context 'when passing subscribe false as input' do
+ let(:input) { { subscribed_state: false } }
+
+ it 'unmarks the resource as subscribed' do
+ resource.subscribe(current_user, project)
+
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response).to eq(false)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
index c8fabfe30b9..6f131a75e3d 100644
--- a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
+++ b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
@@ -78,6 +78,12 @@ RSpec.shared_examples 'raises error for users with insufficient permissions' do
it_behaves_like 'misconfigured dashboard service response', :unauthorized
end
+
+ context 'when the user is anonymous' do
+ let(:user) { nil }
+
+ it_behaves_like 'misconfigured dashboard service response', :unauthorized
+ end
end
RSpec.shared_examples 'valid dashboard cloning process' do |dashboard_template, sequence|
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index cb6396e2859..df7acd2040f 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -11,31 +11,57 @@ RSpec.describe GitGarbageCollectWorker do
let(:shell) { Gitlab::Shell.new }
let!(:lease_uuid) { SecureRandom.uuid }
let!(:lease_key) { "project_housekeeping:#{project.id}" }
+ let(:params) { [project.id, task, lease_key, lease_uuid] }
subject { described_class.new }
+ shared_examples 'it calls Gitaly' do
+ specify do
+ expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(gitaly_task)
+ .and_return(nil)
+
+ subject.perform(*params)
+ end
+ end
+
+ shared_examples 'it updates the project statistics' do
+ specify do
+ expect_any_instance_of(Projects::UpdateStatisticsService).to receive(:execute).and_call_original
+ expect(Projects::UpdateStatisticsService)
+ .to receive(:new)
+ .with(project, nil, statistics: [:repository_size, :lfs_objects_size])
+ .and_call_original
+
+ subject.perform(*params)
+ end
+ end
+
describe "#perform" do
+ let(:gitaly_task) { :garbage_collect }
+ let(:task) { :gc }
+
context 'with active lease_uuid' do
before do
allow(subject).to receive(:get_lease_uuid).and_return(lease_uuid)
end
+ it_behaves_like 'it calls Gitaly'
+ it_behaves_like 'it updates the project statistics'
+
it "flushes ref caches when the task if 'gc'" do
expect(subject).to receive(:renew_lease).with(lease_key, lease_uuid).and_call_original
- expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect)
- .and_return(nil)
expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
expect_any_instance_of(Gitlab::Git::Repository).to receive(:has_visible_content?).and_call_original
- subject.perform(project.id, :gc, lease_key, lease_uuid)
+ subject.perform(*params)
end
it 'handles gRPC errors' do
expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect).and_raise(GRPC::NotFound)
- expect { subject.perform(project.id, :gc, lease_key, lease_uuid) }.to raise_exception(Gitlab::Git::Repository::NoRepository)
+ expect { subject.perform(*params) }.to raise_exception(Gitlab::Git::Repository::NoRepository)
end
end
@@ -49,11 +75,13 @@ RSpec.describe GitGarbageCollectWorker do
expect_any_instance_of(Repository).not_to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).not_to receive(:has_visible_content?).and_call_original
- subject.perform(project.id, :gc, lease_key, lease_uuid)
+ subject.perform(*params)
end
end
context 'with no active lease' do
+ let(:params) { [project.id] }
+
before do
allow(subject).to receive(:get_lease_uuid).and_return(false)
end
@@ -63,15 +91,16 @@ RSpec.describe GitGarbageCollectWorker do
allow(subject).to receive(:try_obtain_lease).and_return(SecureRandom.uuid)
end
+ it_behaves_like 'it calls Gitaly'
+ it_behaves_like 'it updates the project statistics'
+
it "flushes ref caches when the task if 'gc'" do
- expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect)
- .and_return(nil)
expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
expect_any_instance_of(Gitlab::Git::Repository).to receive(:has_visible_content?).and_call_original
- subject.perform(project.id)
+ subject.perform(*params)
end
context 'when the repository has joined a pool' do
@@ -81,7 +110,7 @@ RSpec.describe GitGarbageCollectWorker do
it 'ensures the repositories are linked' do
expect_any_instance_of(PoolRepository).to receive(:link_repository).once
- subject.perform(project.id)
+ subject.perform(*params)
end
end
end
@@ -97,48 +126,55 @@ RSpec.describe GitGarbageCollectWorker do
expect_any_instance_of(Repository).not_to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).not_to receive(:has_visible_content?).and_call_original
- subject.perform(project.id)
+ subject.perform(*params)
end
end
end
context "repack_full" do
+ let(:task) { :full_repack }
+ let(:gitaly_task) { :repack_full }
+
before do
expect(subject).to receive(:get_lease_uuid).and_return(lease_uuid)
end
- it "calls Gitaly" do
- expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_full)
- .and_return(nil)
-
- subject.perform(project.id, :full_repack, lease_key, lease_uuid)
- end
+ it_behaves_like 'it calls Gitaly'
+ it_behaves_like 'it updates the project statistics'
end
context "pack_refs" do
+ let(:task) { :pack_refs }
+ let(:gitaly_task) { :pack_refs }
+
before do
expect(subject).to receive(:get_lease_uuid).and_return(lease_uuid)
end
it "calls Gitaly" do
- expect_any_instance_of(Gitlab::GitalyClient::RefService).to receive(:pack_refs)
+ expect_any_instance_of(Gitlab::GitalyClient::RefService).to receive(task)
.and_return(nil)
- subject.perform(project.id, :pack_refs, lease_key, lease_uuid)
+ subject.perform(*params)
+ end
+
+ it 'does not update the project statistics' do
+ expect(Projects::UpdateStatisticsService).not_to receive(:new)
+
+ subject.perform(*params)
end
end
context "repack_incremental" do
+ let(:task) { :incremental_repack }
+ let(:gitaly_task) { :repack_incremental }
+
before do
expect(subject).to receive(:get_lease_uuid).and_return(lease_uuid)
end
- it "calls Gitaly" do
- expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_incremental)
- .and_return(nil)
-
- subject.perform(project.id, :incremental_repack, lease_key, lease_uuid)
- end
+ it_behaves_like 'it calls Gitaly'
+ it_behaves_like 'it updates the project statistics'
end
shared_examples 'gc tasks' do