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:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_page.vue2
-rw-r--r--app/assets/javascripts/lib/utils/datetime/date_format_utility.js2
-rw-r--r--app/assets/javascripts/projects/commit/components/form_modal.vue6
-rw-r--r--app/assets/javascripts/projects/commit/components/projects_dropdown.vue57
-rw-r--r--app/assets/javascripts/releases/components/evidence_block.vue5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue2
-rw-r--r--app/assets/javascripts/work_items/components/item_state.vue1
-rw-r--r--app/assets/javascripts/work_items/components/work_item_assignees.vue1
-rw-r--r--app/assets/javascripts/work_items/components/work_item_comment_form.vue1
-rw-r--r--app/assets/javascripts/work_items/components/work_item_due_date.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_labels.vue1
-rw-r--r--app/controllers/concerns/ci/auth_build_trace.rb22
-rw-r--r--app/controllers/projects/application_controller.rb15
-rw-r--r--app/controllers/projects/artifacts_controller.rb1
-rw-r--r--app/controllers/projects/jobs_controller.rb11
-rw-r--r--app/graphql/types/query_type.rb6
-rw-r--r--app/models/ci/bridge.rb10
-rw-r--r--app/models/clusters/applications/cilium.rb21
-rw-r--r--app/models/clusters/cluster.rb4
-rw-r--r--app/models/project.rb7
-rw-r--r--app/services/projects/create_service.rb2
-rw-r--r--app/services/projects/destroy_service.rb2
-rw-r--r--app/services/projects/transfer_service.rb17
-rw-r--r--config/feature_flags/development/ci_recreate_downstream_pipeline.yml8
-rw-r--r--data/deprecations/15-9-deprecate-runner-setup-instructions-api.yml13
-rw-r--r--db/docs/clusters_applications_cilium.yml2
-rw-r--r--doc/administration/geo/replication/security_review.md6
-rw-r--r--doc/administration/housekeeping.md8
-rw-r--r--doc/administration/package_information/omnibus_packages.md4
-rw-r--r--doc/administration/troubleshooting/test_environments.md2
-rw-r--r--doc/api/graphql/reference/index.md8
-rw-r--r--doc/development/database/avoiding_downtime_in_migrations.md103
-rw-r--r--doc/development/project_templates.md4
-rw-r--r--doc/development/testing_guide/review_apps.md31
-rw-r--r--doc/integration/advanced_search/elasticsearch.md4
-rw-r--r--doc/integration/advanced_search/elasticsearch_troubleshooting.md17
-rw-r--r--doc/update/deprecations.md16
-rw-r--r--doc/user/application_security/sast/customize_rulesets.md15
-rw-r--r--doc/user/application_security/secret_detection/index.md6
-rw-r--r--doc/user/application_security/security_dashboard/index.md4
-rw-r--r--doc/user/application_security/terminology/index.md2
-rw-r--r--doc/user/clusters/agent/troubleshooting.md4
-rw-r--r--doc/user/product_analytics/index.md4
-rw-r--r--doc/user/project/code_owners.md15
-rw-r--r--lib/gitlab/ci/status/bridge/factory.rb6
-rw-r--r--lib/gitlab/ci/status/bridge/retried.rb12
-rw-r--r--lib/gitlab/ci/status/bridge/retryable.rb12
-rw-r--r--lib/tasks/gitlab/db.rake4
-rw-r--r--locale/gitlab.pot78
-rw-r--r--package.json2
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb56
-rw-r--r--spec/factories/ci/bridge.rb8
-rw-r--r--spec/factories/clusters/applications/helm.rb4
-rw-r--r--spec/factories/clusters/clusters.rb1
-rw-r--r--spec/features/work_items/work_item_spec.rb45
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js45
-rw-r--r--spec/frontend/lib/utils/datetime/date_format_utility_spec.js4
-rw-r--r--spec/frontend/projects/commit/components/projects_dropdown_spec.js64
-rw-r--r--spec/frontend/releases/components/evidence_block_spec.js8
-rw-r--r--spec/frontend/vue_merge_request_widget/components/report_widget_container_spec.js27
-rw-r--r--spec/lib/gitlab/ci/status/bridge/factory_spec.rb29
-rw-r--r--spec/models/ci/bridge_spec.rb20
-rw-r--r--spec/models/ci/processable_spec.rb6
-rw-r--r--spec/models/clusters/applications/cilium_spec.rb17
-rw-r--r--spec/models/project_spec.rb23
-rw-r--r--spec/services/ci/retry_job_service_spec.rb66
-rw-r--r--spec/services/projects/create_service_spec.rb2
-rw-r--r--spec/services/projects/destroy_service_spec.rb18
-rw-r--r--spec/services/projects/transfer_service_spec.rb17
-rw-r--r--spec/support/shared_examples/features/work_items_shared_examples.rb109
-rw-r--r--yarn.lock8
74 files changed, 739 insertions, 434 deletions
diff --git a/Gemfile b/Gemfile
index e96d696f306..c50ba869258 100644
--- a/Gemfile
+++ b/Gemfile
@@ -338,7 +338,7 @@ gem 'sentry-sidekiq', '~> 5.1.1'
# PostgreSQL query parsing
#
-gem 'pg_query', '~> 2.2'
+gem 'pg_query', '~> 2.2', '>= 2.2.1'
gem 'premailer-rails', '~> 1.10.3'
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 31eab51b243..93f1a2f2ceb 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -422,7 +422,7 @@
{"name":"pg","version":"1.4.5","platform":"x64-mingw-ucrt","checksum":"614814a4597fed5c4a85e107a96ef6c8ee01b3e7dbc6529912249b7d778e5651"},
{"name":"pg","version":"1.4.5","platform":"x64-mingw32","checksum":"d9a15cb4ee478bf719fee6ecd6c8b41d5569515ee0d968e561fe120aed862cb1"},
{"name":"pg","version":"1.4.5","platform":"x86-mingw32","checksum":"255764ff8ac89203cc9dcc7188a4205e760fa7b884d75c94007b79897ee8613d"},
-{"name":"pg_query","version":"2.2.0","platform":"ruby","checksum":"84a37548412f540061bcc52ee2915352297832816bca60e4524c716e03f1e950"},
+{"name":"pg_query","version":"2.2.1","platform":"ruby","checksum":"6086972bbf4eab86d8425b35f14ca8b6fe41e4341423582801c1ec86ff5f8cea"},
{"name":"plist","version":"3.6.0","platform":"ruby","checksum":"f468bcf6b72ec6d1585ed6744eb4817c1932a5bf91895ed056e69b7f12ca10f2"},
{"name":"png_quantizator","version":"0.2.1","platform":"ruby","checksum":"6023d4d064125c3a7e02929c95b7320ed6ac0d7341f9e8de0c9ea6576ef3106b"},
{"name":"po_to_json","version":"1.0.1","platform":"ruby","checksum":"6a7188aa6c42a22c9718f9b39062862ef7f3d8f6a7b4177cae058c3308b56af7"},
diff --git a/Gemfile.lock b/Gemfile.lock
index c585f2b4e9d..f7e021aae7e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1076,7 +1076,7 @@ GEM
peek (1.1.0)
railties (>= 4.0.0)
pg (1.4.5)
- pg_query (2.2.0)
+ pg_query (2.2.1)
google-protobuf (>= 3.19.2)
plist (3.6.0)
png_quantizator (0.2.1)
@@ -1777,7 +1777,7 @@ DEPENDENCIES
parslet (~> 1.8)
peek (~> 1.1)
pg (~> 1.4.5)
- pg_query (~> 2.2)
+ pg_query (~> 2.2, >= 2.2.1)
png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3)
prometheus-client-mmap (~> 0.17)
diff --git a/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_page.vue b/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_page.vue
index f4c59b2184e..37d40071dd0 100644
--- a/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_page.vue
+++ b/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_page.vue
@@ -15,7 +15,7 @@ export default {
},
computed: {
isOauthSelfManagedEnabled() {
- return this.glFeatures.jiraConnectOauth && this.glFeatures.jiraConnectOauthSelfManaged;
+ return this.glFeatures.jiraConnectOauth;
},
},
};
diff --git a/app/assets/javascripts/lib/utils/datetime/date_format_utility.js b/app/assets/javascripts/lib/utils/datetime/date_format_utility.js
index 04a82836f69..5d6e0dff33f 100644
--- a/app/assets/javascripts/lib/utils/datetime/date_format_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime/date_format_utility.js
@@ -334,7 +334,7 @@ export const timeToHoursMinutes = (time = '') => {
* @param {String} offset An optional Date-compatible offset.
* @returns {String} The combined Date's ISO string representation.
*/
-export const dateAndTimeToISOString = (date, time, offset = '') => {
+export const dateAndTimeToISOString = (date, time = '00:00', offset = '') => {
const { year, month, day } = dateToYearMonthDate(date);
const { hours, minutes } = timeToHoursMinutes(time);
const dateString = `${year}-${month}-${day}T${hours}:${minutes}:00.000${offset || 'Z'}`;
diff --git a/app/assets/javascripts/projects/commit/components/form_modal.vue b/app/assets/javascripts/projects/commit/components/form_modal.vue
index 1febe8ceaab..921c66587c9 100644
--- a/app/assets/javascripts/projects/commit/components/form_modal.vue
+++ b/app/assets/javascripts/projects/commit/components/form_modal.vue
@@ -141,11 +141,7 @@ export default {
:value="targetProjectId"
/>
- <projects-dropdown
- class="gl-w-half"
- :value="targetProjectName"
- @selectProject="setSelectedProject"
- />
+ <projects-dropdown :value="targetProjectName" @selectProject="setSelectedProject" />
</gl-form-group>
<gl-form-group
diff --git a/app/assets/javascripts/projects/commit/components/projects_dropdown.vue b/app/assets/javascripts/projects/commit/components/projects_dropdown.vue
index 6288bcdaad0..d43f5b99e2c 100644
--- a/app/assets/javascripts/projects/commit/components/projects_dropdown.vue
+++ b/app/assets/javascripts/projects/commit/components/projects_dropdown.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdown, GlSearchBoxByType, GlDropdownItem, GlDropdownText } from '@gitlab/ui';
+import { GlCollapsibleListbox } from '@gitlab/ui';
import { mapGetters, mapState } from 'vuex';
import {
I18N_NO_RESULTS_MESSAGE,
@@ -10,10 +10,7 @@ import {
export default {
name: 'ProjectsDropdown',
components: {
- GlDropdown,
- GlSearchBoxByType,
- GlDropdownItem,
- GlDropdownText,
+ GlCollapsibleListbox,
},
props: {
value: {
@@ -41,17 +38,20 @@ export default {
project.name.toLowerCase().includes(lowerCasedFilterTerm),
);
},
+ listboxItems() {
+ return this.filteredResults.map(({ id, name }) => ({ value: id, text: name }));
+ },
selectedProject() {
return this.sortedProjects.find((project) => project.id === this.targetProjectId) || {};
},
},
methods: {
- selectProject(project) {
- this.$emit('selectProject', project.id);
- this.filterTerm = project.name; // when we select a project, we want the dropdown to filter to the selected project
- },
- isSelected(selectedProject) {
- return selectedProject === this.selectedProject;
+ selectProject(value) {
+ this.$emit('selectProject', value);
+
+ // when we select a project, we want the dropdown to filter to the selected project
+ const project = this.listboxItems.find((x) => x.value === value);
+ this.filterTerm = project?.text || '';
},
filterTermChanged(value) {
this.filterTerm = value;
@@ -60,28 +60,15 @@ export default {
};
</script>
<template>
- <gl-dropdown :text="selectedProject.name" :header-text="$options.i18n.projectHeaderTitle">
- <gl-search-box-by-type
- :value="filterTerm"
- trim
- autocomplete="off"
- :placeholder="$options.i18n.projectSearchPlaceholder"
- data-testid="dropdown-search-box"
- @input="filterTermChanged"
- />
- <gl-dropdown-item
- v-for="project in filteredResults"
- :key="project.name"
- :name="project.name"
- :is-checked="isSelected(project)"
- is-check-item
- data-testid="dropdown-item"
- @click="selectProject(project)"
- >
- {{ project.name }}
- </gl-dropdown-item>
- <gl-dropdown-text v-if="!filteredResults.length" data-testid="empty-result-message">
- <span class="gl-text-gray-500">{{ $options.i18n.noResultsMessage }}</span>
- </gl-dropdown-text>
- </gl-dropdown>
+ <gl-collapsible-listbox
+ :header-text="$options.i18n.projectHeaderTitle"
+ :items="listboxItems"
+ searchable
+ :search-placeholder="$options.i18n.projectSearchPlaceholder"
+ :selected="selectedProject.id"
+ :toggle-text="selectedProject.name"
+ :no-results-text="$options.i18n.noResultsMessage"
+ @search="filterTermChanged"
+ @select="selectProject"
+ />
</template>
diff --git a/app/assets/javascripts/releases/components/evidence_block.vue b/app/assets/javascripts/releases/components/evidence_block.vue
index 6d415471b14..2118c26fd81 100644
--- a/app/assets/javascripts/releases/components/evidence_block.vue
+++ b/app/assets/javascripts/releases/components/evidence_block.vue
@@ -67,12 +67,13 @@ export default {
<gl-link
v-gl-tooltip
class="d-flex align-items-center monospace"
- :title="__('Download evidence JSON')"
- :download="evidenceTitle(index)"
+ target="_blank"
+ :title="__('Open evidence JSON in new tab')"
:href="evidenceUrl(index)"
>
<gl-icon name="review-list" class="align-middle gl-mr-3" />
<span>{{ evidenceTitle(index) }}</span>
+ <gl-icon name="external-link" class="gl-ml-2 gl-flex-shrink-0 gl-flex-grow-0" />
</gl-link>
<expand-button>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue
index ecf08f78f57..0f20fb6d176 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue
@@ -13,7 +13,7 @@ export default {
},
methods: {
checkSlots() {
- return this.$scopedSlots.default?.()?.some((c) => c.tag);
+ return this.$scopedSlots.default?.()?.some((c) => c.elm?.innerText);
},
},
};
diff --git a/app/assets/javascripts/work_items/components/item_state.vue b/app/assets/javascripts/work_items/components/item_state.vue
index 2a0913e380a..8ec8482657d 100644
--- a/app/assets/javascripts/work_items/components/item_state.vue
+++ b/app/assets/javascripts/work_items/components/item_state.vue
@@ -62,6 +62,7 @@ export default {
:value="state"
:options="$options.states"
:disabled="disabled"
+ data-testid="work-item-state-select"
class="gl-w-auto hide-select-decoration gl-pl-3"
:class="{ 'gl-bg-transparent! gl-cursor-text!': disabled }"
@change="setState"
diff --git a/app/assets/javascripts/work_items/components/work_item_assignees.vue b/app/assets/javascripts/work_items/components/work_item_assignees.vue
index c2980405a19..0dd8a119fec 100644
--- a/app/assets/javascripts/work_items/components/work_item_assignees.vue
+++ b/app/assets/javascripts/work_items/components/work_item_assignees.vue
@@ -313,6 +313,7 @@ export default {
:view-only="!canUpdate"
:allow-clear-all="isEditing"
class="assignees-selector gl-flex-grow-1 gl-border gl-border-white gl-rounded-base col-9 gl-align-self-start gl-px-0! gl-mx-2"
+ data-testid="work-item-asssignees-input"
@input="handleAssigneesInput"
@text-input="debouncedSearchKeyUpdate"
@focus="handleFocus"
diff --git a/app/assets/javascripts/work_items/components/work_item_comment_form.vue b/app/assets/javascripts/work_items/components/work_item_comment_form.vue
index 65042f1431d..2c9b2c967dd 100644
--- a/app/assets/javascripts/work_items/components/work_item_comment_form.vue
+++ b/app/assets/javascripts/work_items/components/work_item_comment_form.vue
@@ -198,6 +198,7 @@ export default {
:form-field-placeholder="__('Write a comment or drag your files here…')"
form-field-id="work-item-add-comment"
form-field-name="work-item-add-comment"
+ data-testid="work-item-add-comment"
enable-autocomplete
autofocus
use-bottom-toolbar
diff --git a/app/assets/javascripts/work_items/components/work_item_due_date.vue b/app/assets/javascripts/work_items/components/work_item_due_date.vue
index 9ee302855c7..03c5b7096b2 100644
--- a/app/assets/javascripts/work_items/components/work_item_due_date.vue
+++ b/app/assets/javascripts/work_items/components/work_item_due_date.vue
@@ -215,6 +215,7 @@ export default {
ref="startDatePicker"
v-model="dirtyStartDate"
container="body"
+ data-testid="work-item-start-date-picker"
:disabled="isDatepickerDisabled"
:input-id="$options.startDateInputId"
show-clear-button
@@ -240,6 +241,7 @@ export default {
ref="dueDatePicker"
v-model="dirtyDueDate"
container="body"
+ data-testid="work-item-due-date-picker"
:disabled="isDatepickerDisabled"
:input-id="$options.dueDateInputId"
:min-date="dirtyStartDate"
diff --git a/app/assets/javascripts/work_items/components/work_item_labels.vue b/app/assets/javascripts/work_items/components/work_item_labels.vue
index 45fb0f7f21a..9c06a5cd724 100644
--- a/app/assets/javascripts/work_items/components/work_item_labels.vue
+++ b/app/assets/javascripts/work_items/components/work_item_labels.vue
@@ -266,6 +266,7 @@ export default {
:loading="isLoading"
:view-only="!canUpdate"
class="gl-flex-grow-1 gl-border gl-border-white gl-rounded-base col-9 gl-align-self-start gl-px-0! gl-mx-2!"
+ data-testid="work-item-labels-input"
:class="{ 'gl-hover-border-gray-200': canUpdate }"
@input="focusTokenSelector"
@text-input="debouncedSearchKeyUpdate"
diff --git a/app/controllers/concerns/ci/auth_build_trace.rb b/app/controllers/concerns/ci/auth_build_trace.rb
new file mode 100644
index 00000000000..0370a382eb8
--- /dev/null
+++ b/app/controllers/concerns/ci/auth_build_trace.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Ci
+ module AuthBuildTrace
+ extend ActiveSupport::Concern
+
+ def authorize_read_build_trace!
+ return if can?(current_user, :read_build_trace, build)
+
+ if build.debug_mode?
+ access_denied!(
+ _('You must have developer or higher permissions in the associated project to view job logs when debug ' \
+ "trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to " \
+ "'false' in your pipeline configuration or CI/CD settings. If you must view this job log, " \
+ 'a project maintainer or owner must add you to the project with developer permissions or higher.')
+ )
+ else
+ access_denied!(_('The current user is not authorized to access the job log.'))
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 25b83aed78a..62233c8c3c9 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -32,21 +32,6 @@ class Projects::ApplicationController < ApplicationController
->(project) { !project.pending_delete? }
end
- def authorize_read_build_trace!
- return if can?(current_user, :read_build_trace, build)
-
- if build.debug_mode?
- access_denied!(
- _('You must have developer or higher permissions in the associated project to view job logs when debug trace ' \
- "is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' " \
- 'in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer ' \
- 'or owner must add you to the project with developer permissions or higher.')
- )
- else
- access_denied!(_('The current user is not authorized to access the job log.'))
- end
- end
-
def build_canonical_path(project)
params[:namespace_id] = project.namespace.to_param
params[:project_id] = project.to_param
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index 3201538a393..bb068a301c4 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class Projects::ArtifactsController < Projects::ApplicationController
+ include Ci::AuthBuildTrace
include ExtractsPath
include RendersBlob
include SendFileUpload
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index c6d442a6f27..3fea5c694f7 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -1,14 +1,15 @@
# frozen_string_literal: true
class Projects::JobsController < Projects::ApplicationController
+ include Ci::AuthBuildTrace
include SendFileUpload
include ContinueParams
include ProjectStatsRefreshConflictsGuard
urgency :low, [:index, :show, :trace, :retry, :play, :cancel, :unschedule, :erase, :raw]
- before_action :find_job_as_build, except: [:index, :play, :show]
- before_action :find_job_as_processable, only: [:play, :show]
+ before_action :find_job_as_build, except: [:index, :play, :show, :retry]
+ before_action :find_job_as_processable, only: [:play, :show, :retry]
before_action :authorize_read_build_trace!, only: [:trace, :raw]
before_action :authorize_read_build!
before_action :authorize_update_build!,
@@ -76,7 +77,11 @@ class Projects::JobsController < Projects::ApplicationController
response = Ci::RetryJobService.new(project, current_user).execute(@build)
if response.success?
- redirect_to build_path(response[:job])
+ if @build.is_a?(::Ci::Build)
+ redirect_to build_path(response[:job])
+ else
+ head :ok
+ end
else
respond_422
end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index abfa2e63bbb..f0430a47a7f 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -94,8 +94,10 @@ module Types
resolver: Resolvers::Ci::RunnerResolver,
extras: [:lookahead],
description: "Find a runner."
- field :runner_platforms, resolver: Resolvers::Ci::RunnerPlatformsResolver
- field :runner_setup, resolver: Resolvers::Ci::RunnerSetupResolver
+ field :runner_platforms, resolver: Resolvers::Ci::RunnerPlatformsResolver,
+ deprecated: { reason: 'No longer used, use gitlab-runner documentation to learn about supported platforms', milestone: '15.9' }
+ field :runner_setup, resolver: Resolvers::Ci::RunnerSetupResolver,
+ deprecated: { reason: 'No longer used, use gitlab-runner documentation to learn about runner registration commands', milestone: '15.9' }
field :runners, Types::Ci::RunnerType.connection_type,
null: true,
resolver: Resolvers::Ci::RunnersResolver,
diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb
index 4af31fd37f2..54daff7dbda 100644
--- a/app/models/ci/bridge.rb
+++ b/app/models/ci/bridge.rb
@@ -55,7 +55,11 @@ module Ci
end
def retryable?
- false
+ return false unless Feature.enabled?(:ci_recreate_downstream_pipeline, project)
+
+ return false if failed? && (pipeline_loop_detected? || reached_max_descendant_pipelines_depth?)
+
+ super
end
def self.with_preloads
@@ -186,6 +190,10 @@ module Ci
def persisted_environment
end
+ def deployment_job?
+ false
+ end
+
def execute_hooks
raise NotImplementedError
end
diff --git a/app/models/clusters/applications/cilium.rb b/app/models/clusters/applications/cilium.rb
deleted file mode 100644
index 7936b0b18de..00000000000
--- a/app/models/clusters/applications/cilium.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class Cilium < ApplicationRecord
- self.table_name = 'clusters_applications_cilium'
-
- include ::Clusters::Concerns::ApplicationCore
- include ::Clusters::Concerns::ApplicationStatus
-
- # Cilium can only be installed and uninstalled through the
- # cluster-applications project by triggering CI pipeline for a
- # management project. UI operations are not available for such
- # applications. More information:
- # https://docs.gitlab.com/ee/user/clusters/management_project.html
- def allowed_to_uninstall?
- false
- end
- end
- end
-end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index af6cafc4a62..84e9b6a8df7 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -19,8 +19,7 @@ module Clusters
Clusters::Applications::Prometheus.application_name => Clusters::Applications::Prometheus,
Clusters::Applications::Runner.application_name => Clusters::Applications::Runner,
Clusters::Applications::Jupyter.application_name => Clusters::Applications::Jupyter,
- Clusters::Applications::Knative.application_name => Clusters::Applications::Knative,
- Clusters::Applications::Cilium.application_name => Clusters::Applications::Cilium
+ Clusters::Applications::Knative.application_name => Clusters::Applications::Knative
}.freeze
DEFAULT_ENVIRONMENT = '*'
KUBE_INGRESS_BASE_DOMAIN = 'KUBE_INGRESS_BASE_DOMAIN'
@@ -64,7 +63,6 @@ module Clusters
has_one_cluster_application :runner
has_one_cluster_application :jupyter
has_one_cluster_application :knative
- has_one_cluster_application :cilium
has_many :kubernetes_namespaces
has_many :metrics_dashboard_annotations, class_name: 'Metrics::Dashboard::Annotation', inverse_of: :cluster
diff --git a/app/models/project.rb b/app/models/project.rb
index 561a842f23a..31b1d597055 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -991,6 +991,13 @@ class Project < ApplicationRecord
namespace.owner == user
end
+ def invalidate_personal_projects_count_of_owner
+ return unless personal?
+ return unless namespace.owner
+
+ namespace.owner.invalidate_personal_projects_count
+ end
+
def project_setting
super.presence || build_project_setting
end
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index d3313526eaf..e1959ec09b5 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -125,7 +125,7 @@ module Projects
setup_authorizations
- current_user.invalidate_personal_projects_count
+ project.invalidate_personal_projects_count_of_owner
Projects::PostCreationWorker.perform_async(@project.id)
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index 4e883f682fb..2e346ff6f12 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -34,7 +34,7 @@ module Projects
publish_project_deleted_event_for(project)
- current_user.invalidate_personal_projects_count
+ project.invalidate_personal_projects_count_of_owner
true
rescue StandardError => error
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 3cb5a564ba5..6fca49aa3d0 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -32,9 +32,9 @@ module Projects
raise TransferError, s_("TransferProject|You don't have permission to transfer projects into that namespace.")
end
- transfer(project)
+ @owner_of_personal_project_before_transfer = project.namespace.owner if project.personal?
- current_user.invalidate_personal_projects_count
+ transfer(project)
true
rescue Projects::TransferService::TransferError => ex
@@ -121,6 +121,7 @@ module Projects
# Overridden in EE
def post_update_hooks(project)
ensure_personal_project_owner_membership(project)
+ invalidate_personal_projects_counts
publish_event
end
@@ -129,6 +130,18 @@ module Projects
def remove_paid_features
end
+ def invalidate_personal_projects_counts
+ # If the project was moved out of a personal namespace,
+ # the cache of the namespace owner, before the transfer, should be cleared.
+ if @owner_of_personal_project_before_transfer.present?
+ @owner_of_personal_project_before_transfer.invalidate_personal_projects_count
+ end
+
+ # If the project has now moved into a personal namespace,
+ # the cache of the target namespace owner should be cleared.
+ project.invalidate_personal_projects_count_of_owner
+ end
+
def transfer_missing_group_resources(group)
Labels::TransferService.new(current_user, group, project).execute
diff --git a/config/feature_flags/development/ci_recreate_downstream_pipeline.yml b/config/feature_flags/development/ci_recreate_downstream_pipeline.yml
new file mode 100644
index 00000000000..e97ee2d572d
--- /dev/null
+++ b/config/feature_flags/development/ci_recreate_downstream_pipeline.yml
@@ -0,0 +1,8 @@
+name: ci_recreate_downstream_pipeline
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108698
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387972
+milestone: '15.9'
+type: development
+group: group::pipeline authoring
+default_enabled: false
+
diff --git a/data/deprecations/15-9-deprecate-runner-setup-instructions-api.yml b/data/deprecations/15-9-deprecate-runner-setup-instructions-api.yml
new file mode 100644
index 00000000000..4f5c301b7c2
--- /dev/null
+++ b/data/deprecations/15-9-deprecate-runner-setup-instructions-api.yml
@@ -0,0 +1,13 @@
+- title: 'GitLab Runner platforms and setup instructions in GraphQL API'
+ announcement_milestone: '15.9'
+ announcement_date: '2023-02-22'
+ removal_milestone: '17.0'
+ removal_date: '2024-05-22'
+ breaking_change: true
+ reporter: mrincon
+ body: |
+ The `runnerPlatforms` and `runnerSetup` queries to get GitLab Runner platforms and installation instructions
+ are deprecated and will be removed from the GraphQL API. For installation instructions, you should use the
+ [GitLab Runner documentation](https://docs.gitlab.com/runner/)
+ stage: verify
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387937
diff --git a/db/docs/clusters_applications_cilium.yml b/db/docs/clusters_applications_cilium.yml
index b28d674cef0..12e5753f12e 100644
--- a/db/docs/clusters_applications_cilium.yml
+++ b/db/docs/clusters_applications_cilium.yml
@@ -1,7 +1,5 @@
---
table_name: clusters_applications_cilium
-classes:
-- Clusters::Applications::Cilium
feature_categories:
- security_policy_management
description: Information about installed instance of Cilium in the cluster
diff --git a/doc/administration/geo/replication/security_review.md b/doc/administration/geo/replication/security_review.md
index afe831dcb9c..92eff2faf60 100644
--- a/doc/administration/geo/replication/security_review.md
+++ b/doc/administration/geo/replication/security_review.md
@@ -114,7 +114,7 @@ from [owasp.org](https://owasp.org/).
### What private and public network links support the application?
- Customers choose their own networks. As sites are intended to be
- geographically separated, it is envisioned that replication traffic will pass
+ geographically separated, it is envisioned that replication traffic passes
over the public Internet in a typical deployment, but this is not a requirement.
## Systems
@@ -168,7 +168,7 @@ from [owasp.org](https://owasp.org/).
- GitLab is "cloud native" and this applies to Geo as much as to the rest of the
product. Deployment in clouds is a common and supported scenario.
-## If applicable, what approach(es) to cloud computing will be taken (Managed Hosting versus "Pure" Cloud, a "full machine" approach such as AWS-EC2 versus a "hosted database" approach such as AWS-RDS and Azure, etc)?
+## If applicable, what approach(es) to cloud computing is taken (Managed Hosting versus "Pure" Cloud, a "full machine" approach such as AWS-EC2 versus a "hosted database" approach such as AWS-RDS and Azure, etc)?
- To be decided by our customers, according to their operational needs.
@@ -186,7 +186,7 @@ from [owasp.org](https://owasp.org/).
- PostgreSQL >= 12, Redis, Sidekiq, Puma.
-### How will database connection strings, encryption keys, and other sensitive components be stored, accessed, and protected from unauthorized detection?
+### How can database connection strings, encryption keys, and other sensitive components be stored, accessed, and protected from unauthorized detection?
- There are some Geo-specific values. Some are shared secrets which must be
securely transmitted from the **primary** site to the **secondary** site at setup time. Our
diff --git a/doc/administration/housekeeping.md b/doc/administration/housekeeping.md
index e1b26595bc4..1883594e32c 100644
--- a/doc/administration/housekeeping.md
+++ b/doc/administration/housekeeping.md
@@ -130,7 +130,7 @@ strategy.
Administrators can enable a background job that performs housekeeping in all
repositories at a customizable interval to remedy this situation. This
background job processes all repositories hosted by a Gitaly node in a random
-order and eagerly performs housekeeping tasks on them. The Gitaly node will stop
+order and eagerly performs housekeeping tasks on them. The Gitaly node stops
processing repositories if it takes longer than the configured interval.
#### Configure scheduled housekeeping
@@ -166,7 +166,7 @@ of a repository. When creating the first fork, we:
1. Create an object pool repository that contains all objects of the repository
that is about to be forked.
-1. Link the repository to this new object pool via Git's alternates mechanism.
+1. Link the repository to this new object pool via the alternates mechanism of Git.
1. Repack the repository so that it uses objects from the object pool. It thus
can drop its own copy of the objects.
@@ -181,12 +181,12 @@ GitLab needs to perform special housekeeping operations in object pools:
thus maintain references to unreachable "dangling" objects so that they don't
ever get deleted.
- GitLab must update object pools regularly to pull in new objects that have
- been added in the primary repository. Otherwise, an object pool will become
+ been added in the primary repository. Otherwise, an object pool becomes
increasingly inefficient at deduplicating objects.
These housekeeping operations are performed by the specialized
`FetchIntoObjectPool` RPC that handles all of these special tasks while also
-executing the regular housekeeping tasks we execute for normal Git
+executing the regular housekeeping tasks we execute for standard Git
repositories.
Object pools are getting optimized automatically whenever the primary member is
diff --git a/doc/administration/package_information/omnibus_packages.md b/doc/administration/package_information/omnibus_packages.md
index 7b3892ace70..222341c7308 100644
--- a/doc/administration/package_information/omnibus_packages.md
+++ b/doc/administration/package_information/omnibus_packages.md
@@ -23,7 +23,7 @@ We have a few core goals with these packages:
GitLab in its core is a Ruby on Rails project. However, GitLab as a whole
application is more complex and has multiple components. If these components are
-not present or are incorrectly configured, GitLab will not work or it will work
+not present or are incorrectly configured, GitLab does not work or it works
unpredictably.
The [GitLab Architecture Overview](../../development/architecture.md#gitlab-architecture-overview) shows some of these components and how they
@@ -112,4 +112,4 @@ what was noted above:
1. Running separate services in multiple containers and keeping them running
can be more complex and might not be required for a given install.
-This method is useful for organizations just getting started with containers and schedulers, and may not be ready for a more complex installation. This method is a great introduction, and will work well for smaller organizations.
+This method is useful for organizations just getting started with containers and schedulers, and may not be ready for a more complex installation. This method is a great introduction, and works well for smaller organizations.
diff --git a/doc/administration/troubleshooting/test_environments.md b/doc/administration/troubleshooting/test_environments.md
index c4d191f8c0f..63ccbce9480 100644
--- a/doc/administration/troubleshooting/test_environments.md
+++ b/doc/administration/troubleshooting/test_environments.md
@@ -87,7 +87,7 @@ docker.elastic.co/elasticsearch/elasticsearch:5.5.1
```
Then confirm it works in the browser at `curl "http://<IP_ADDRESS>:9200/_cat/health"`.
-Elasticsearch's default username is `elastic` and password is `changeme`.
+In Elasticsearch, the default username is `elastic`, and the default password is `changeme`.
### Kroki
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 8a03c152acb..e57ca9230bd 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -414,6 +414,10 @@ Returns [`CiRunner`](#cirunner).
Supported runner platforms.
+WARNING:
+**Deprecated** in 15.9.
+No longer used, use gitlab-runner documentation to learn about supported platforms.
+
Returns [`RunnerPlatformConnection`](#runnerplatformconnection).
This field returns a [connection](#connections). It accepts the
@@ -424,6 +428,10 @@ four standard [pagination arguments](#connection-pagination-arguments):
Runner setup instructions.
+WARNING:
+**Deprecated** in 15.9.
+No longer used, use gitlab-runner documentation to learn about runner registration commands.
+
Returns [`RunnerSetup`](#runnersetup).
#### Arguments
diff --git a/doc/development/database/avoiding_downtime_in_migrations.md b/doc/development/database/avoiding_downtime_in_migrations.md
index bb6e13eff53..833f9dbebf6 100644
--- a/doc/development/database/avoiding_downtime_in_migrations.md
+++ b/doc/development/database/avoiding_downtime_in_migrations.md
@@ -6,20 +6,20 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Avoiding downtime in migrations
-When working with a database certain operations may require downtime. Since we
+When working with a database certain operations may require downtime. As we
cannot have downtime in migrations we need to use a set of steps to get the
same end result without downtime. This guide describes various operations that
may appear to need downtime, their impact, and how to perform them without
requiring downtime.
-## Dropping Columns
+## Dropping columns
Removing columns is tricky because running GitLab processes may still be using
the columns. To work around this safely, you need three steps in three releases:
-1. Ignoring the column (release M)
-1. Dropping the column (release M+1)
-1. Removing the ignore rule (release M+2)
+1. [Ignoring the column](#ignoring-the-column-release-m) (release M)
+1. [Dropping the column](#dropping-the-column-release-m1) (release M+1)
+1. [Removing the ignore rule](#removing-the-ignore-rule-release-m2) (release M+2)
The reason we spread this out across three releases is that dropping a column is
a destructive operation that can't be rolled back easily.
@@ -27,9 +27,9 @@ a destructive operation that can't be rolled back easily.
Following this procedure helps us to make sure there are no deployments to GitLab.com
and upgrade processes for self-managed installations that lump together any of these steps.
-### Step 1: Ignoring the column (release M)
+### Ignoring the column (release M)
-The first step is to ignore the column in the application code. This is
+The first step is to ignore the column in the application code. This step is
necessary because Rails caches the columns and re-uses this cache in various
places. This can be done by defining the columns to ignore. For example, to ignore
`updated_at` in the User model you'd use the following:
@@ -50,7 +50,7 @@ ignore_columns %i[updated_at created_at], remove_with: '12.7', remove_after: '20
If the model exists in CE and EE, the column has to be ignored in the CE model. If the
model only exists in EE, then it has to be added there.
-We require indication of when it is safe to remove the column ignore with:
+We require indication of when it is safe to remove the column ignore rule with:
- `remove_with`: set to a GitLab release typically two releases (M+2) after adding the
column ignore.
@@ -64,7 +64,7 @@ to ignore the column and subsequently remove the column ignore (which would resu
In this example, the change to ignore the column went into release 12.5.
-### Step 2: Dropping the column (release M+1)
+### Dropping the column (release M+1)
Continuing our example, dropping the column goes into a _post-deployment_ migration in release 12.6:
@@ -74,12 +74,14 @@ Start by creating the **post-deployment migration**:
bundle exec rails g post_deployment_migration remove_users_updated_at_column
```
-There are two scenarios that you need to consider
-to write a migration that removes a column:
+You must consider these scenarios when you write a migration that removes a column:
-#### A. The removed column has no indexes or constraints that belong to it
+- [The removed column has no indexes or constraints that belong to it](#the-removed-column-has-no-indexes-or-constraints-that-belong-to-it)
+- [The removed column has an index or constraint that belongs to it](#the-removed-column-has-an-index-or-constraint-that-belongs-to-it)
-In this case, a **transactional migration** can be used. Something as simple as:
+#### The removed column has no indexes or constraints that belong to it
+
+In this case, a **transactional migration** can be used:
```ruby
class RemoveUsersUpdatedAtColumn < Gitlab::Database::Migration[2.1]
@@ -97,10 +99,10 @@ You can consider [enabling lock retries](../migration_style_guide.md#usage-with-
when you run a migration on big tables, because it might take some time to
acquire a lock on this table.
-#### B. The removed column has an index or constraint that belongs to it
+#### The removed column has an index or constraint that belongs to it
If the `down` method requires adding back any dropped indexes or constraints, that cannot
-be done within a transactional migration, then the migration would look like this:
+be done in a transactional migration. The migration would look like this:
```ruby
class RemoveUsersUpdatedAtColumn < Gitlab::Database::Migration[2.1]
@@ -131,7 +133,7 @@ is used to disable the transaction that wraps the whole migration.
You can refer to the page [Migration Style Guide](../migration_style_guide.md)
for more information about database migrations.
-### Step 3: Removing the ignore rule (release M+2)
+### Removing the ignore rule (release M+2)
With the next release, in this example 12.7, we set up another merge request to remove the ignore rule.
This removes the `ignore_column` line and - if not needed anymore - also the inclusion of `IgnoreableColumns`.
@@ -139,18 +141,24 @@ This removes the `ignore_column` line and - if not needed anymore - also the inc
This should only get merged with the release indicated with `remove_with` and once
the `remove_after` date has passed.
-## Renaming Columns
+## Renaming columns
-Renaming columns the normal way requires downtime as an application may continue
+Renaming columns the standard way requires downtime as an application may continue
to use the old column names during or after a database migration. To rename a column
without requiring downtime, we need two migrations: a regular migration and a
post-deployment migration. Both these migrations can go in the same release.
+The steps:
+
+1. [Add the regular migration](#add-the-regular-migration-release-m) (release M)
+1. [Ignore the column](#ignore-the-column-release-m) (release M)
+1. [Add a post-deployment migration](#add-a-post-deployment-migration-release-m) (release M)
+1. [Remove the ignore rule](#remove-the-ignore-rule-release-m1) (release M+1)
NOTE:
It's not possible to rename columns with default values. For more details, see
[this merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52032#default-values).
-### Step 1: Add The Regular Migration
+### Add the regular migration (release M)
First we need to create the regular migration. This migration should use
`Gitlab::Database::MigrationHelpers#rename_column_concurrently` to perform the
@@ -178,7 +186,20 @@ If a column contains one or more indexes that don't contain the name of the
original column, the previously described procedure fails. In that case,
you need to rename these indexes.
-### Step 2: Add A Post-Deployment Migration
+### Ignore the column (release M)
+
+The next step is to ignore the column in the application code, and make sure it is not used. This step is
+necessary because Rails caches the columns and re-uses this cache in various places.
+This step is similar to [the first step when column is dropped](#ignoring-the-column-release-m), and the same requirements apply.
+
+```ruby
+class User < ApplicationRecord
+ include IgnorableColumns
+ ignore_column :updated_at, remove_with: '12.7', remove_after: '2020-01-22'
+end
+```
+
+### Add a post-deployment migration (release M)
The renaming procedure requires some cleaning up in a post-deployment migration.
We can perform this cleanup using
@@ -202,7 +223,11 @@ end
If you're renaming a [large table](https://gitlab.com/gitlab-org/gitlab/-/blob/master/rubocop/rubocop-migrations.yml#L3), carefully consider the state when the first migration has run but the second cleanup migration hasn't been run yet.
With [Canary](https://gitlab.com/gitlab-com/gl-infra/readiness/-/tree/master/library/canary/) it is possible that the system runs in this state for a significant amount of time.
-## Changing Column Constraints
+### Remove the ignore rule (release M+1)
+
+Same as when column is dropped, after the rename is completed, we need to [remove the ignore rule](#removing-the-ignore-rule-release-m2) in a subsequent release.
+
+## Changing column constraints
Adding or removing a `NOT NULL` clause (or another constraint) can typically be
done without requiring downtime. However, this does require that any application
@@ -218,14 +243,18 @@ You can check the following guides for each specific use case:
- [Adding `NOT NULL` constraints](not_null_constraints.md)
- [Adding limits to text columns](strings_and_the_text_data_type.md)
-## Changing Column Types
+## Changing column types
Changing the type of a column can be done using
`Gitlab::Database::MigrationHelpers#change_column_type_concurrently`. This
method works similarly to `rename_column_concurrently`. For example, let's say
-we want to change the type of `users.username` from `string` to `text`.
+we want to change the type of `users.username` from `string` to `text`:
+
+1. [Create a regular migration](#create-a-regular-migration)
+1. [Create a post-deployment migration](#create-a-post-deployment-migration)
+1. [Casting data to a new type](#casting-data-to-a-new-type)
-### Step 1: Create A Regular Migration
+### Create a regular migration
A regular migration is used to create a new column with a temporary name along
with setting up some triggers to keep data in sync. Such a migration would look
@@ -246,7 +275,7 @@ class ChangeUsersUsernameStringToText < Gitlab::Database::Migration[2.1]
end
```
-### Step 2: Create A Post Deployment Migration
+### Create a post-deployment migration
Next we need to clean up our changes using a post-deployment migration:
@@ -293,13 +322,13 @@ specify the old default.
Doing this requires steps in two minor releases:
-1. Add the `SafelyChangeColumnDefault` concern to the model and change the default in a post-migration.
-1. Clean up the `SafelyChangeColumnDefault` concern in the next minor release.
+1. [Add the `SafelyChangeColumnDefault` concern to the model](#add-the-safelychangecolumndefault-concern-to-the-model-and-change-the-default-in-a-post-migration) and change the default in a post-migration.
+1. [Clean up the `SafelyChangeColumnDefault` concern](#clean-up-the-safelychangecolumndefault-concern-in-the-next-minor-release) in the next minor release.
We must wait a minor release before cleaning up the `SafelyChangeColumnDefault` because self-managed
releases bundle an entire minor release into a single zero-downtime deployment.
-### Step 1: Add the `SafelyChangeColumnDefault` concern to the model and change the default in a post-migration
+### Add the `SafelyChangeColumnDefault` concern to the model and change the default in a post-migration
The first step is to mark the column as safe to change in application code.
@@ -333,12 +362,12 @@ You can consider [enabling lock retries](../migration_style_guide.md#usage-with-
when you run a migration on big tables, because it might take some time to
acquire a lock on this table.
-### Step 2: Clean up the `SafelyChangeColumnDefault` concern in the next minor release
+### Clean up the `SafelyChangeColumnDefault` concern in the next minor release
In the next minor release, create a new merge request to remove the `columns_changing_default` call. Also remove the `SafelyChangeColumnDefault` include
if it is not needed for a different column.
-## Changing The Schema For Large Tables
+## Changing the schema for large tables
While `change_column_type_concurrently` and `rename_column_concurrently` can be
used for changing the schema of a table without downtime, it doesn't work very
@@ -354,7 +383,7 @@ down deployments.
For more information, see [the documentation on cleaning up batched background migrations](batched_background_migrations.md#cleaning-up).
-## Adding Indexes
+## Adding indexes
Adding indexes does not require downtime when `add_concurrent_index`
is used.
@@ -362,15 +391,15 @@ is used.
See also [Migration Style Guide](../migration_style_guide.md#adding-indexes)
for more information.
-## Dropping Indexes
+## Dropping indexes
Dropping an index does not require downtime.
-## Adding Tables
+## Adding tables
This operation is safe as there's no code using the table just yet.
-## Dropping Tables
+## Dropping tables
Dropping tables can be done safely using a post-deployment migration, but only
if the application no longer uses the table.
@@ -378,7 +407,7 @@ if the application no longer uses the table.
Add the table to [`db/docs/deleted_tables`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/db/docs/deleted_tables) using the process described in [database dictionary](database_dictionary.md#dropping-tables).
Even though the table is deleted, it is still referenced in database migrations.
-## Renaming Tables
+## Renaming tables
Renaming tables requires downtime as an application may continue
using the old table name during/after a database migration.
@@ -389,7 +418,7 @@ table and creating a new one is the preferred way to "rename" the table.
Renaming a table is possible without downtime by following our multi-release
[rename table process](rename_database_tables.md#rename-table-without-downtime).
-## Adding Foreign Keys
+## Adding foreign keys
Adding foreign keys usually works in 3 steps:
@@ -404,7 +433,7 @@ GitLab allows you to work around this by using
`Gitlab::Database::MigrationHelpers#add_concurrent_foreign_key`. This method
ensures that no downtime is needed.
-## Removing Foreign Keys
+## Removing foreign keys
This operation does not require downtime.
diff --git a/doc/development/project_templates.md b/doc/development/project_templates.md
index 55a63d41425..3320f3134fb 100644
--- a/doc/development/project_templates.md
+++ b/doc/development/project_templates.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: Organization
+stage: Create
+group: Source Code
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
---
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
index 332f9f8fbe5..b074a9e34f3 100644
--- a/doc/development/testing_guide/review_apps.md
+++ b/doc/development/testing_guide/review_apps.md
@@ -134,31 +134,28 @@ resource.labels.pod_name:"review-qa-raise-e-12chm0-migrations"
```mermaid
graph TD
A["build-qa-image, compile-production-assets<br/>(canonical default refs only)"];
+ B1[start-review-app-pipeline];
B[review-build-cng];
- C[review-deploy];
+ C["review-deploy<br><br>Helm deploys the review app using the Cloud<br/>Native images built by the CNG-mirror pipeline.<br><br>Cloud Native images are deployed to the `review-apps`<br>Kubernetes (GKE) cluster, in the GCP `gitlab-review-apps` project."];
D[CNG-mirror];
- E[review-qa-smoke, review-qa-reliable];
+ E[review-qa-smoke, review-qa-blocking, review-qa-non-blocking<br><br>gitlab-qa runs the e2e tests against the review app.];
- A -->|once the `prepare` stage is done| B
- B -.->|triggers a CNG-mirror pipeline and wait for it to be done| D
- D -.->|polls until completed| B
- B -->|once the `review-build-cng` job is done| C
- C -->|once the `review-deploy` job is done| E
+ A --> B1
+ B1 --> B
+ B -.->|triggers a CNG-mirror pipeline| D
+ D -.->|depends on the multi-project pipeline| B
+ B --> C
+ C --> E
-subgraph "1. gitlab `prepare` stage"
+subgraph "1. gitlab-org/gitlab parent pipeline"
A
+ B1
end
-subgraph "2. gitlab `review-prepare` stage"
+subgraph "2. gitlab-org/gitlab child pipeline"
B
- end
-
-subgraph "3. gitlab `review` stage"
- C["review-deploy<br><br>Helm deploys the review app using the Cloud<br/>Native images built by the CNG-mirror pipeline.<br><br>Cloud Native images are deployed to the `review-apps`<br>Kubernetes (GKE) cluster, in the GCP `gitlab-review-apps` project."]
- end
-
-subgraph "4. gitlab `qa` stage"
- E[review-qa-smoke, review-qa-reliable<br><br>gitlab-qa runs the smoke and reliable suites against the review app.]
+ C
+ E
end
subgraph "CNG-mirror pipeline"
diff --git a/doc/integration/advanced_search/elasticsearch.md b/doc/integration/advanced_search/elasticsearch.md
index a55a56b30d6..ac73e6e794c 100644
--- a/doc/integration/advanced_search/elasticsearch.md
+++ b/doc/integration/advanced_search/elasticsearch.md
@@ -25,7 +25,7 @@ Advanced Search works with the following versions of Elasticsearch.
| GitLab 13.3 - 13.8 | Elasticsearch 6.4 - 7.x |
| GitLab 12.7 - 13.2 | Elasticsearch 6.x - 7.x |
-Advanced Search follows Elasticsearch's [End of Life Policy](https://www.elastic.co/support/eol).
+Advanced Search follows the [Elasticsearch end-of-life policy](https://www.elastic.co/support/eol).
When we change Elasticsearch supported versions in GitLab, we announce them in [deprecation notes](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations) in monthly release posts
before we remove them.
@@ -224,7 +224,7 @@ The following Elasticsearch settings are available:
| `Maximum file size indexed` | See [the explanation in instance limits.](../../administration/instance_limits.md#maximum-file-size-indexed). |
| `Maximum field length` | See [the explanation in instance limits.](../../administration/instance_limits.md#maximum-field-length). |
| `Maximum bulk request size (MiB)` | The Maximum Bulk Request size is used by the GitLab Golang-based indexer processes and indicates how much data it ought to collect (and store in memory) in a given indexing process before submitting the payload to Elasticsearch's Bulk API. This setting should be used with the Bulk request concurrency setting (see below) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. |
-| `Bulk request concurrency` | The Bulk request concurrency indicates how many of the GitLab Golang-based indexer processes (or threads) can run in parallel to collect data to subsequently submit to Elasticsearch's Bulk API. This increases indexing performance, but fills the Elasticsearch bulk requests queue faster. This setting should be used together with the Maximum bulk request size setting (see above) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. |
+| `Bulk request concurrency` | The Bulk request concurrency indicates how many of the GitLab Golang-based indexer processes (or threads) can run in parallel to collect data to subsequently submit to the Elasticsearch Bulk API. This increases indexing performance, but fills the Elasticsearch bulk requests queue faster. This setting should be used together with the Maximum bulk request size setting (see above) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. |
| `Client request timeout` | Elasticsearch HTTP client request timeout value in seconds. `0` means using the system default timeout value, which depends on the libraries that GitLab application is built upon. |
WARNING:
diff --git a/doc/integration/advanced_search/elasticsearch_troubleshooting.md b/doc/integration/advanced_search/elasticsearch_troubleshooting.md
index 7e2edf10c90..e2dc143e4db 100644
--- a/doc/integration/advanced_search/elasticsearch_troubleshooting.md
+++ b/doc/integration/advanced_search/elasticsearch_troubleshooting.md
@@ -309,26 +309,23 @@ When it comes to Elasticsearch, RAM is the key resource. Elasticsearch themselve
- Ideally, 64 GB of RAM.
For CPU, Elasticsearch recommends at least 2 CPU cores, but Elasticsearch states common
-setups use up to 8 cores. For more details on server specs, check out
-[Elasticsearch's hardware guide](https://www.elastic.co/guide/en/elasticsearch/guide/current/hardware.html).
+setups use up to 8 cores. For more details on server specs, check out the
+[Elasticsearch hardware guide](https://www.elastic.co/guide/en/elasticsearch/guide/current/hardware.html).
Beyond the obvious, sharding comes into play. Sharding is a core part of Elasticsearch.
It allows for horizontal scaling of indices, which is helpful when you are dealing with
a large amount of data.
With the way GitLab does indexing, there is a **huge** amount of documents being
-indexed. By utilizing sharding, you can speed up Elasticsearch's ability to locate
-data, since each shard is a Lucene index.
+indexed. By using sharding, you can speed up the ability of Elasticsearch to locate
+data because each shard is a Lucene index.
If you are not using sharding, you are likely to hit issues when you start using
Elasticsearch in a production environment.
-Keep in mind that an index with only one shard has **no scale factor** and will
-likely encounter issues when called upon with some frequency.
-
-If you need to know how many shards, read
-[Elasticsearch's documentation on capacity planning](https://www.elastic.co/guide/en/elasticsearch/guide/2.x/capacity-planning.html),
-as the answer is not straight forward.
+An index with only one shard has **no scale factor** and is likely
+to encounter issues when called upon with some frequency. See the
+[Elasticsearch documentation on capacity planning](https://www.elastic.co/guide/en/elasticsearch/guide/2.x/capacity-planning.html).
The easiest way to determine if sharding is in use is to check the output of the
[Elasticsearch Health API](https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html):
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 6840aa6108e..763b82f9010 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -66,6 +66,22 @@ Due to limited customer usage, Browser Performance Testing is deprecated and wil
<div class="deprecation removal-170 breaking-change">
+### GitLab Runner platforms and setup instructions in GraphQL API
+
+Planned removal: GitLab <span class="removal-milestone">17.0</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The `runnerPlatforms` and `runnerSetup` queries to get GitLab Runner platforms and installation instructions
+are deprecated and will be removed from the GraphQL API. For installation instructions, you should use the
+[GitLab Runner documentation](https://docs.gitlab.com/runner/)
+
+</div>
+
+<div class="deprecation removal-170 breaking-change">
+
### Load Performance Testing is deprecated
Planned removal: GitLab <span class="removal-milestone">17.0</span> <span class="removal-date"></span>
diff --git a/doc/user/application_security/sast/customize_rulesets.md b/doc/user/application_security/sast/customize_rulesets.md
index aec7158d2e4..d070883df9a 100644
--- a/doc/user/application_security/sast/customize_rulesets.md
+++ b/doc/user/application_security/sast/customize_rulesets.md
@@ -23,7 +23,7 @@ repository being scanned. There are two kinds of customization:
## Disable predefined rules
-You can disable predefined rules for any SAST analyzer. Disabled rules won't appear
+You can disable predefined rules for any SAST analyzer. Disabled rules don't appear
on the [Pipeline Security](../index.md#view-security-scan-information-in-the-pipeline-security-tab)
tab or the [Vulnerability Report](../index.md#view-security-scan-information-in-the-vulnerability-report).
@@ -103,7 +103,7 @@ differ based on the kind of configuration you're making.
| `[[$analyzer.ruleset]]` | Predefined rules | Defines modifications to an existing rule. |
| `interpolate` | All | If set to `true`, you can use `$VAR` in the configuration to evaluate environment variables. Use this feature with caution, so you don't leak secrets or tokens. (Default: `false`) |
| `description` | Passthroughs | Description of the custom ruleset. |
-| `targetdir` | Passthroughs | The directory where the final configuration should be persisted. If empty, a directory with a random name is created. The directory can contain up to 100MB of files. |
+| `targetdir` | Passthroughs | The directory where the final configuration should be persisted. If empty, a directory with a random name is created. The directory can contain up to 100 MB of files. |
| `validate` | Passthroughs | If set to `true`, the content of each passthrough is validated. The validation works for `yaml`, `xml`, `json` and `toml` content. The proper validator is identified based on the extension used in the `target` parameter of the `[[$analyzer.passthrough]]` section. (Default: `false`) |
| `timeout` | Passthroughs | The maximum time to spend to evaluate the passthrough chain, before timing out. The timeout cannot exceed 300 seconds. (Default: 60) |
@@ -249,13 +249,13 @@ a higher precedence and can overwrite or append to data yielded by previous
passthroughs (depending on the `mode`). This is useful for cases where you need
to use or modify an existing configuration.
-The amount of data generated by a single passthrough is limited to 1MB.
+The amount of data generated by a single passthrough is limited to 1 MB.
| Setting | Applies to | Description |
| ------- | ---------- | ----------- |
| `type` | All | One of `file`, `raw`, `git` or `url`. |
| `target` | All | The target file to contain the data written by the passthrough evaluation. If empty, a random filename is used. |
-| `mode` | All | If `overwrite`, the `target` file is overwritten. If `append`, new content is appended to the `target` file. Note that the `git` type only supports `overwrite`. (Default: `overwrite`) |
+| `mode` | All | If `overwrite`, the `target` file is overwritten. If `append`, new content is appended to the `target` file. The `git` type only supports `overwrite`. (Default: `overwrite`) |
| `ref` | `type = "git"` | Contains the name of the branch or the SHA to pull. When using a branch name, specify it in the form `refs/heads/<branch>`, not `refs/remotes/<remote_name>/<branch>`. |
| `subdir` | `type = "git"` | Used to select a subdirectory of the Git repository as the configuration source. |
| `value` | All | For the `file`, `url`, and `git` types, defines the location of the file or Git repository. For the `raw` type, contains the inline configuration. |
@@ -273,7 +273,7 @@ The amount of data generated by a single passthrough is limited to 1MB.
WARNING:
When using the `raw` passthrough with a YAML snippet, it's recommended to format all indentation
in the `sast-ruleset.toml` file as spaces. The YAML specification mandates spaces over tabs, and the
-analyzer will fail to parse your custom ruleset unless the indentation is represented accordingly.
+analyzer fails to parse your custom ruleset unless the indentation is represented accordingly.
## Examples
@@ -317,8 +317,7 @@ With the following custom ruleset configuration, the following rules are omitted
### Override predefined rules of SAST analyzers
With the following custom ruleset configuration, vulnerabilities found with
-`semgrep` with a type `CWE` and a value `322` will have their severity
-overridden to `Critical`.
+`semgrep` with a type `CWE` and a value `322` have their severity overridden to `Critical`.
```toml
[semgrep]
@@ -416,7 +415,7 @@ Different passthrough types are demonstrated in this example:
- The `sast-rules` entry has a higher precedence because it appears later in
the configuration.
- If there's a filename collision between the two checkouts, files
- from the `sast-rules` repository will overwrite files from the
+ from the `sast-rules` repository overwrite files from the
`myrules` repository.
- A `raw` passthrough, which writes its `value` to `/sgrules/insecure.yml`.
- A `url` passthrough, which fetches a configuration hosted at a URL and
diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md
index d955170ece2..c2fbc6ce996 100644
--- a/doc/user/application_security/secret_detection/index.md
+++ b/doc/user/application_security/secret_detection/index.md
@@ -150,9 +150,9 @@ in your CI/CD configuration file after you include the [`Secret-Detection.gitlab
You can set the tag to:
-- A major version, like `4`. Your pipelines will use any minor or patch updates that are released within this major version.
-- A minor version, like `4.5`. Your pipelines will use any patch updates that are released within this minor version.
-- A patch version, like `4.5.0`. Your pipelines won't receive any updates.
+- A major version, like `4`. Your pipelines use any minor or patch updates that are released within this major version.
+- A minor version, like `4.5`. Your pipelines use any patch updates that are released within this minor version.
+- A patch version, like `4.5.0`. Your pipelines don't receive any updates.
This example uses a specific minor version of the analyzer:
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index e7ff10820c3..7388ef80e68 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -57,7 +57,7 @@ To reduce false negatives in [dependency scans](../../../user/application_securi
The project Security Dashboard shows the total number of vulnerabilities
over time, with up to 365 days of historical data. Data refresh begins daily at 01:15 UTC via a scheduled job.
Each refresh captures a snapshot of open vulnerabilities. Data is not backported to prior days
-so vulnerabilities opened after the job has already run for the day will not be reflected in the
+so vulnerabilities opened after the job has already run for the day cannot be reflected in the
counts until the following day's refresh job.
Project Security Dashboards show statistics for all vulnerabilities with a current status of `Needs triage` or `Confirmed` .
@@ -105,7 +105,7 @@ To view project security status for a group:
1. Select **Security > Security Dashboard**.
Each project is assigned a letter [grade](#project-vulnerability-grades) according to the highest-severity open vulnerability.
-Dismissed or resolved vulnerabilities are excluded. Each project can receive only one letter grade and will appear only once
+Dismissed or resolved vulnerabilities are excluded. Each project can receive only one letter grade and appears only once
in the Project security status report.
To view vulnerabilities, go to the group's [vulnerability report](../vulnerability_report/index.md).
diff --git a/doc/user/application_security/terminology/index.md b/doc/user/application_security/terminology/index.md
index cdc70a73f87..1ce5d58c73b 100644
--- a/doc/user/application_security/terminology/index.md
+++ b/doc/user/application_security/terminology/index.md
@@ -243,7 +243,7 @@ of the finding's [first identifier](https://gitlab.com/gitlab-org/security-produ
combine to create the value.
Examples of primary identifiers include `PluginID` for OWASP Zed Attack Proxy (ZAP), or `CVE` for
-Trivy. Note that the identifier must be stable. Subsequent scans must return the same value for the
+Trivy. The identifier must be stable. Subsequent scans must return the same value for the
same finding, even if the location has slightly changed.
### Report finding
diff --git a/doc/user/clusters/agent/troubleshooting.md b/doc/user/clusters/agent/troubleshooting.md
index a44d1e9685b..f5f235d2758 100644
--- a/doc/user/clusters/agent/troubleshooting.md
+++ b/doc/user/clusters/agent/troubleshooting.md
@@ -108,7 +108,7 @@ certificate authority that is unknown to the agent.
To fix this issue, you can present the CA certificate file to the agent
by using a Kubernetes `configmap` and mount the file in the agent `/etc/ssl/certs` directory from where it
-will be picked up automatically.
+is picked up automatically.
For example, if your internal CA certificate is `myCA.pem`:
@@ -200,7 +200,7 @@ are stored in the repository where the agent is configured.
```
The GitLab agent performs vulnerability scans by creating a job to scan each workload. If a scan
-is interrupted, these jobs may be left behind and will need to be cleaned up before more jobs can
+is interrupted, these jobs may be left behind and need to be cleaned up before more jobs can
be run. You can clean up these jobs by running:
```shell
diff --git a/doc/user/product_analytics/index.md b/doc/user/product_analytics/index.md
index 28f536972ea..d9144ee2665 100644
--- a/doc/user/product_analytics/index.md
+++ b/doc/user/product_analytics/index.md
@@ -52,7 +52,7 @@ Product Analytics uses several tools:
> - Moved to be behind the [feature flag](../../administration/feature_flags.md) named `product_analytics_admin_settings` in GitLab 15.7. Disabled by default.
FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `cube_api_proxy`.
+On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `product_analytics_admin_settings`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
@@ -86,7 +86,7 @@ Prerequisite:
> Introduced in GitLab 15.5 behind the [feature flag](../../administration/feature_flags.md) named `product_analytics_internal_preview`. Disabled by default.
FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `cube_api_proxy`.
+On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `product_analytics_internal_preview`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
diff --git a/doc/user/project/code_owners.md b/doc/user/project/code_owners.md
index 7675260b3d4..8ae3715f3bf 100644
--- a/doc/user/project/code_owners.md
+++ b/doc/user/project/code_owners.md
@@ -161,7 +161,20 @@ README.md @user1
The Code Owner for `README.md` would be `@user2`.
-If you use sections, the last user _for each section_ is used.
+If you use sections, the last pattern matching the file for each section is used.
+For example, in a `CODEOWNERS` file using sections:
+
+```plaintext
+[README Owners]
+README.md @user1 @user2
+internal/README.md @user4
+
+[README other owners]
+README.md @user3
+```
+
+The Code Owners for the `README.md` in the root directory are `@user1`, `@user2`,
+and `@user3`. The Code Owners for `internal/README.md` are `@user4` and `@user3`.
Only one CODEOWNERS pattern can match per file path.
diff --git a/lib/gitlab/ci/status/bridge/factory.rb b/lib/gitlab/ci/status/bridge/factory.rb
index 4d5a94a3beb..fbe2e2282a0 100644
--- a/lib/gitlab/ci/status/bridge/factory.rb
+++ b/lib/gitlab/ci/status/bridge/factory.rb
@@ -6,11 +6,13 @@ module Gitlab
module Bridge
class Factory < Status::Factory
def self.extended_statuses
- [[Status::Bridge::Failed],
+ [[Status::Bridge::Retryable],
+ [Status::Bridge::Failed],
[Status::Bridge::Manual],
[Status::Bridge::WaitingForResource],
[Status::Bridge::Play],
- [Status::Bridge::Action]]
+ [Status::Bridge::Action],
+ [Status::Bridge::Retried]]
end
def self.common_helpers
diff --git a/lib/gitlab/ci/status/bridge/retried.rb b/lib/gitlab/ci/status/bridge/retried.rb
new file mode 100644
index 00000000000..101974f10f2
--- /dev/null
+++ b/lib/gitlab/ci/status/bridge/retried.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Status
+ module Bridge
+ class Retried < Status::Build::Retried
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/bridge/retryable.rb b/lib/gitlab/ci/status/bridge/retryable.rb
new file mode 100644
index 00000000000..203a0b8d5ca
--- /dev/null
+++ b/lib/gitlab/ci/status/bridge/retryable.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Status
+ module Bridge
+ class Retryable < Status::Build::Retryable
+ end
+ end
+ end
+ end
+end
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index 6ea05a3af9d..b979d3c0357 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -403,8 +403,8 @@ namespace :gitlab do
desc 'Generate database docs yaml'
task generate: :environment do
- FileUtils.mkdir_p(DB_DOCS_PATH) unless Dir.exist?(DB_DOCS_PATH)
- FileUtils.mkdir_p(EE_DICTIONARY_PATH) unless Dir.exist?(EE_DICTIONARY_PATH)
+ FileUtils.mkdir_p(DB_DOCS_PATH)
+ FileUtils.mkdir_p(EE_DICTIONARY_PATH) if Gitlab.ee?
Rails.application.eager_load!
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 5289990995f..b010969b306 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -5152,9 +5152,6 @@ msgstr ""
msgid "Approved"
msgstr ""
-msgid "Approved MRs"
-msgstr ""
-
msgid "Approved the current merge request."
msgstr ""
@@ -5448,9 +5445,6 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
-msgid "Ascending"
-msgstr ""
-
msgid "Ask again later"
msgstr ""
@@ -8971,9 +8965,6 @@ msgstr ""
msgid "Closed %{epicTimeagoDate}"
msgstr ""
-msgid "Closed MRs"
-msgstr ""
-
msgid "Closed date"
msgstr ""
@@ -11075,12 +11066,27 @@ msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
+msgid "ContributionAnalytics|%{pushes} by %{contributors}."
+msgstr ""
+
+msgid "ContributionAnalytics|Approved MRs"
+msgstr ""
+
+msgid "ContributionAnalytics|Closed MRs"
+msgstr ""
+
+msgid "ContributionAnalytics|Closed issues"
msgstr ""
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr ""
+msgid "ContributionAnalytics|Contributions per group member"
+msgstr ""
+
+msgid "ContributionAnalytics|Failed to load the contribution stats"
+msgstr ""
+
msgid "ContributionAnalytics|Issues"
msgstr ""
@@ -11093,9 +11099,18 @@ msgstr ""
msgid "ContributionAnalytics|Last week"
msgstr ""
+msgid "ContributionAnalytics|Loading contribution stats for group members"
+msgstr ""
+
msgid "ContributionAnalytics|Merge requests"
msgstr ""
+msgid "ContributionAnalytics|Merged MRs"
+msgstr ""
+
+msgid "ContributionAnalytics|Name"
+msgstr ""
+
msgid "ContributionAnalytics|No issues for the selected time period."
msgstr ""
@@ -11105,6 +11120,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|Opened MRs"
+msgstr ""
+
+msgid "ContributionAnalytics|Opened issues"
+msgstr ""
+
+msgid "ContributionAnalytics|Pushed"
+msgstr ""
+
msgid "ContributionAnalytics|The given date range is larger than 31 days"
msgstr ""
@@ -11114,10 +11138,10 @@ msgstr ""
msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
msgstr ""
-msgid "Contributions for %{calendar_date}"
+msgid "ContributionAnalytics|Total Contributions"
msgstr ""
-msgid "Contributions per group member"
+msgid "Contributions for %{calendar_date}"
msgstr ""
msgid "Contributor"
@@ -14095,9 +14119,6 @@ msgstr ""
msgid "Deprioritize label"
msgstr ""
-msgid "Descending"
-msgstr ""
-
msgid "Describe the goal of the changes and what reviewers should be aware of."
msgstr ""
@@ -14840,9 +14861,6 @@ msgstr ""
msgid "Download codes"
msgstr ""
-msgid "Download evidence JSON"
-msgstr ""
-
msgid "Download export"
msgstr ""
@@ -25258,9 +25276,6 @@ msgstr ""
msgid "Loading %{name}"
msgstr ""
-msgid "Loading contribution stats for group members"
-msgstr ""
-
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr ""
@@ -26516,9 +26531,6 @@ msgstr ""
msgid "Merged"
msgstr ""
-msgid "Merged MRs"
-msgstr ""
-
msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes."
msgstr ""
@@ -29379,6 +29391,9 @@ msgstr ""
msgid "Open errors"
msgstr ""
+msgid "Open evidence JSON in new tab"
+msgstr ""
+
msgid "Open in Gitpod"
msgstr ""
@@ -29418,12 +29433,6 @@ msgstr ""
msgid "Opened"
msgstr ""
-msgid "Opened MRs"
-msgstr ""
-
-msgid "Opened issues"
-msgstr ""
-
msgid "OpenedNDaysAgo|Created"
msgstr ""
@@ -34619,9 +34628,6 @@ msgstr ""
msgid "PushRule|Reject unverified users"
msgstr ""
-msgid "Pushed"
-msgstr ""
-
msgid "Pushes"
msgstr ""
@@ -39906,9 +39912,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching group member contributions"
-msgstr ""
-
msgid "Something went wrong while fetching latest comments."
msgstr ""
@@ -44443,9 +44446,6 @@ msgstr ""
msgid "Total"
msgstr ""
-msgid "Total Contributions"
-msgstr ""
-
msgid "Total Score"
msgstr ""
diff --git a/package.json b/package.json
index b3e16fc79c0..47efe37020a 100644
--- a/package.json
+++ b/package.json
@@ -228,7 +228,7 @@
"cheerio": "^1.0.0-rc.9",
"commander": "^2.20.3",
"custom-jquery-matchers": "^2.1.0",
- "eslint": "8.28.0",
+ "eslint": "8.29.0",
"eslint-import-resolver-jest": "3.0.2",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-import": "^2.26.0",
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 3dc89365530..8fb9623c21a 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
+RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, feature_category: :continuous_integration do
include ApiHelpers
include HttpIOHelpers
@@ -809,14 +809,48 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
sign_in(user)
end
+ context 'when job is not retryable' do
+ context 'and the job is a bridge' do
+ let(:job) { create(:ci_bridge, :failed, :reached_max_descendant_pipelines_depth, pipeline: pipeline) }
+
+ it 'renders unprocessable_entity' do
+ post_retry
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+ end
+
+ context 'and the job is a build' do
+ let(:job) { create(:ci_build, :deployment_rejected, pipeline: pipeline) }
+
+ it 'renders unprocessable_entity' do
+ post_retry
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+ end
+ end
+
context 'when job is retryable' do
- let(:job) { create(:ci_build, :retryable, pipeline: pipeline) }
+ context 'and the job is a bridge' do
+ let(:job) { create(:ci_bridge, :retryable, pipeline: pipeline) }
- it 'redirects to the retried job page' do
- post_retry
+ it 'responds :ok' do
+ post_retry
- expect(response).to have_gitlab_http_status(:found)
- expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id))
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'and the job is a build' do
+ let(:job) { create(:ci_build, :retryable, pipeline: pipeline) }
+
+ it 'redirects to the retried job page' do
+ post_retry
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id))
+ end
end
shared_examples_for 'retried job has the same attributes' do
@@ -847,16 +881,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
end
end
- context 'when job is not retryable' do
- let(:job) { create(:ci_build, pipeline: pipeline) }
-
- it 'renders unprocessable_entity' do
- post_retry
-
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
- end
- end
-
def post_retry
post :retry, params: {
namespace_id: project.namespace,
diff --git a/spec/factories/ci/bridge.rb b/spec/factories/ci/bridge.rb
index 6cbcabca7ab..49ac74f6f86 100644
--- a/spec/factories/ci/bridge.rb
+++ b/spec/factories/ci/bridge.rb
@@ -33,6 +33,14 @@ FactoryBot.define do
end
end
+ trait :retried do
+ retried { true }
+ end
+
+ trait :retryable do
+ success
+ end
+
trait :created do
status { 'created' }
end
diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb
index 6a21df943f5..078450ef1e8 100644
--- a/spec/factories/clusters/applications/helm.rb
+++ b/spec/factories/clusters/applications/helm.rb
@@ -125,9 +125,5 @@ FactoryBot.define do
oauth_application factory: :oauth_application
cluster factory: %i(cluster with_installed_helm provided_by_gcp project)
end
-
- factory :clusters_applications_cilium, class: 'Clusters::Applications::Cilium' do
- cluster factory: %i(cluster with_installed_helm provided_by_gcp)
- end
end
end
diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb
index 72424a3c321..f6af9d04ea5 100644
--- a/spec/factories/clusters/clusters.rb
+++ b/spec/factories/clusters/clusters.rb
@@ -100,7 +100,6 @@ FactoryBot.define do
application_runner factory: %i(clusters_applications_runner installed)
application_jupyter factory: %i(clusters_applications_jupyter installed)
application_knative factory: %i(clusters_applications_knative installed)
- application_cilium factory: %i(clusters_applications_cilium installed)
end
trait :with_domain do
diff --git a/spec/features/work_items/work_item_spec.rb b/spec/features/work_items/work_item_spec.rb
index 577ec060020..1fdf54d801a 100644
--- a/spec/features/work_items/work_item_spec.rb
+++ b/spec/features/work_items/work_item_spec.rb
@@ -5,56 +5,21 @@ require 'spec_helper'
RSpec.describe 'Work item', :js, feature_category: :team_planning do
let_it_be(:project) { create(:project, :public) }
let_it_be(:user) { create(:user) }
- let_it_be(:other_user) { create(:user) }
let_it_be(:work_item) { create(:work_item, project: project) }
context 'for signed in user' do
before do
project.add_developer(user)
- project.add_developer(other_user)
sign_in(user)
visit project_work_items_path(project, work_items_path: work_item.id)
end
- context 'in work item description' do
- it 'shows GFM autocomplete', :aggregate_failures do
- click_button "Edit description"
-
- find('[aria-label="Description"]').send_keys("@#{user.username}")
-
- wait_for_requests
-
- page.within('.atwho-container') do
- expect(page).to have_text(user.name)
- end
- end
-
- it 'shows conflict message when description changes', :aggregate_failures do
- click_button "Edit description"
- scroll_to(find('[aria-label="Description"]'))
-
- # without this for some reason the test fails when running locally
- sleep 1
-
- ::WorkItems::UpdateService.new(
- project: work_item.project,
- current_user: other_user,
- params: { description: "oh no!" }
- ).execute(work_item)
-
- work_item.reload
-
- find('[aria-label="Description"]').send_keys("oh yeah!")
-
- warning = 'Someone edited the description at the same time you did.'
- expect(page.find('[data-testid="work-item-description-conflicts"]')).to have_text(warning)
-
- click_button "Save and overwrite"
-
- expect(page.find('[data-testid="work-item-description"]')).to have_text("oh yeah!")
- end
- end
+ it_behaves_like 'work items status'
+ it_behaves_like 'work items assignees'
+ it_behaves_like 'work items labels'
+ it_behaves_like 'work items comments'
+ it_behaves_like 'work items description'
end
end
diff --git a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js
index c12a45b2f41..658b2cc4be3 100644
--- a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js
@@ -36,47 +36,18 @@ describe('SignInPage', () => {
});
it.each`
- jiraConnectOauthEnabled | jiraConnectOauthSelfManagedEnabled | shouldRenderDotCom | shouldRenderMultiversion
- ${false} | ${false} | ${true} | ${false}
- ${false} | ${true} | ${true} | ${false}
- ${true} | ${false} | ${true} | ${false}
- ${true} | ${true} | ${false} | ${true}
+ jiraConnectOauthEnabled | shouldRenderDotCom | shouldRenderMultiversion
+ ${false} | ${true} | ${false}
+ ${false} | ${true} | ${false}
+ ${true} | ${false} | ${true}
+ ${true} | ${false} | ${true}
`(
- 'renders correct component when jiraConnectOauth is $jiraConnectOauthEnabled and jiraConnectOauthSelfManaged is $jiraConnectOauthSelfManagedEnabled',
- ({
- jiraConnectOauthEnabled,
- jiraConnectOauthSelfManagedEnabled,
- shouldRenderDotCom,
- shouldRenderMultiversion,
- }) => {
- createComponent({ jiraConnectOauthEnabled, jiraConnectOauthSelfManagedEnabled });
+ 'renders correct component when jiraConnectOauth is $jiraConnectOauthEnabled',
+ ({ jiraConnectOauthEnabled, shouldRenderDotCom, shouldRenderMultiversion }) => {
+ createComponent({ jiraConnectOauthEnabled });
expect(findSignInGitlabCom().exists()).toBe(shouldRenderDotCom);
expect(findSignInGitabMultiversion().exists()).toBe(shouldRenderMultiversion);
},
);
-
- describe('when jiraConnectOauthSelfManaged is false', () => {
- beforeEach(() => {
- createComponent({ jiraConnectOauthSelfManaged: false, props: { hasSubscriptions: true } });
- });
-
- it('renders SignInGitlabCom with correct props', () => {
- expect(findSignInGitlabCom().props()).toEqual({ hasSubscriptions: true });
- });
-
- describe('when error event is emitted', () => {
- it('emits another error event', () => {
- findSignInGitlabCom().vm.$emit('error');
- expect(wrapper.emitted('error')).toHaveLength(1);
- });
- });
-
- describe('when sign-in-oauth event is emitted', () => {
- it('emits another sign-in-oauth event', () => {
- findSignInGitlabCom().vm.$emit('sign-in-oauth');
- expect(wrapper.emitted('sign-in-oauth')[0]).toEqual([]);
- });
- });
- });
});
diff --git a/spec/frontend/lib/utils/datetime/date_format_utility_spec.js b/spec/frontend/lib/utils/datetime/date_format_utility_spec.js
index a83b0ed9fbe..2c3fa612740 100644
--- a/spec/frontend/lib/utils/datetime/date_format_utility_spec.js
+++ b/spec/frontend/lib/utils/datetime/date_format_utility_spec.js
@@ -82,6 +82,10 @@ describe('date_format_utility.js', () => {
);
});
+ it('defaults to 00:00 if no time is provided', () => {
+ expect(utils.dateAndTimeToISOString(new Date('2021-08-21'))).toBe('2021-08-21T00:00:00.000Z');
+ });
+
it('throws if date in invalid', () => {
expect(() => utils.dateAndTimeToISOString('Invalid date', '10:00')).toThrow(
'Argument should be a Date instance',
diff --git a/spec/frontend/projects/commit/components/projects_dropdown_spec.js b/spec/frontend/projects/commit/components/projects_dropdown_spec.js
index bb20918e0cd..0e213ff388a 100644
--- a/spec/frontend/projects/commit/components/projects_dropdown_spec.js
+++ b/spec/frontend/projects/commit/components/projects_dropdown_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
+import { GlCollapsibleListbox } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
@@ -35,78 +35,23 @@ describe('ProjectsDropdown', () => {
);
};
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType);
- const findDropdownItemByIndex = (index) => wrapper.findAllComponents(GlDropdownItem).at(index);
- const findNoResults = () => wrapper.findByTestId('empty-result-message');
+ const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
afterEach(() => {
wrapper.destroy();
spyFetchProjects.mockReset();
});
- describe('No projects found', () => {
- beforeEach(() => {
- createComponent('_non_existent_project_');
- });
-
- it('renders empty results message', () => {
- expect(findNoResults().text()).toBe('No matching results');
- });
-
- it('shows GlSearchBoxByType with default attributes', () => {
- expect(findSearchBoxByType().exists()).toBe(true);
- expect(findSearchBoxByType().vm.$attrs).toMatchObject({
- placeholder: 'Search projects',
- });
- });
- });
-
- describe('Search term is empty', () => {
- beforeEach(() => {
- createComponent('');
- });
-
- it('renders all projects when search term is empty', () => {
- expect(findAllDropdownItems()).toHaveLength(3);
- expect(findDropdownItemByIndex(0).text()).toBe('_project_1_');
- expect(findDropdownItemByIndex(1).text()).toBe('_project_2_');
- expect(findDropdownItemByIndex(2).text()).toBe('_project_3_');
- });
-
- it('should not be selected on the inactive project', () => {
- expect(wrapper.vm.isSelected('_project_1_')).toBe(false);
- });
- });
-
describe('Projects found', () => {
beforeEach(() => {
createComponent('_project_1_', { targetProjectId: '1' });
});
- it('renders only the project searched for', () => {
- expect(findAllDropdownItems()).toHaveLength(1);
- expect(findDropdownItemByIndex(0).text()).toBe('_project_1_');
- });
-
- it('should not display empty results message', () => {
- expect(findNoResults().exists()).toBe(false);
- });
-
- it('should signify this project is selected', () => {
- expect(findDropdownItemByIndex(0).props('isChecked')).toBe(true);
- });
-
- it('should signify the project is not selected', () => {
- expect(wrapper.vm.isSelected('_not_selected_project_')).toBe(false);
- });
-
describe('Custom events', () => {
it('should emit selectProject if a project is clicked', () => {
- findDropdownItemByIndex(0).vm.$emit('click');
+ findDropdown().vm.$emit('select', '1');
expect(wrapper.emitted('selectProject')).toEqual([['1']]);
- expect(wrapper.vm.filterTerm).toBe('_project_1_');
});
});
});
@@ -117,8 +62,7 @@ describe('ProjectsDropdown', () => {
});
it('renders only the project searched for', () => {
- expect(findAllDropdownItems()).toHaveLength(1);
- expect(findDropdownItemByIndex(0).text()).toBe('_project_1_');
+ expect(findDropdown().props('items')).toEqual([{ text: '_project_1_', value: '1' }]);
});
});
});
diff --git a/spec/frontend/releases/components/evidence_block_spec.js b/spec/frontend/releases/components/evidence_block_spec.js
index 6f935215dd7..69443cb7a11 100644
--- a/spec/frontend/releases/components/evidence_block_spec.js
+++ b/spec/frontend/releases/components/evidence_block_spec.js
@@ -40,13 +40,11 @@ describe('Evidence Block', () => {
});
it('renders the correct hover text for the download', () => {
- expect(wrapper.findComponent(GlLink).attributes('title')).toBe('Download evidence JSON');
+ expect(wrapper.findComponent(GlLink).attributes('title')).toBe('Open evidence JSON in new tab');
});
- it('renders the correct file link for download', () => {
- expect(wrapper.findComponent(GlLink).attributes().download).toMatch(
- /v1\.1-evidences-[0-9]+\.json/,
- );
+ it('renders a link that opens in a new tab', () => {
+ expect(wrapper.findComponent(GlLink).attributes().target).toBe('_blank');
});
describe('sha text', () => {
diff --git a/spec/frontend/vue_merge_request_widget/components/report_widget_container_spec.js b/spec/frontend/vue_merge_request_widget/components/report_widget_container_spec.js
new file mode 100644
index 00000000000..2f6002f36e0
--- /dev/null
+++ b/spec/frontend/vue_merge_request_widget/components/report_widget_container_spec.js
@@ -0,0 +1,27 @@
+import { nextTick } from 'vue';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import ReportWidgetContainer from '~/vue_merge_request_widget/components/report_widget_container.vue';
+
+describe('app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue', () => {
+ let wrapper;
+
+ const createComponent = ({ slot } = {}) => {
+ wrapper = mountExtended(ReportWidgetContainer, {
+ slots: {
+ default: slot,
+ },
+ });
+ };
+
+ it('hides the container when children has no content', async () => {
+ createComponent({ slot: `<span><b></b></span>` });
+ await nextTick();
+ expect(wrapper.isVisible()).toBe(false);
+ });
+
+ it('shows the container when children have no content', async () => {
+ createComponent({ slot: `<span><b>test</b></span>` });
+ await nextTick();
+ expect(wrapper.isVisible()).toBe(true);
+ });
+});
diff --git a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
index c13901a4776..eac17cf08fb 100644
--- a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
@@ -40,7 +40,8 @@ RSpec.describe Gitlab::Ci::Status::Bridge::Factory, feature_category: :continuou
it 'matches correct extended statuses' do
expect(factory.extended_statuses)
- .to eq [Gitlab::Ci::Status::Bridge::Failed]
+ .to eq [Gitlab::Ci::Status::Bridge::Retryable,
+ Gitlab::Ci::Status::Bridge::Failed]
end
it 'fabricates a failed bridge status' do
@@ -54,7 +55,7 @@ RSpec.describe Gitlab::Ci::Status::Bridge::Factory, feature_category: :continuou
expect(status.label).to be_nil
expect(status.status_tooltip).to eq "#{s_('CiStatusText|failed')} - (unknown failure)"
expect(status).not_to have_details
- expect(status).not_to have_action
+ expect(status).to have_action
end
context 'failed with downstream_pipeline_creation_failed' do
@@ -136,6 +137,30 @@ RSpec.describe Gitlab::Ci::Status::Bridge::Factory, feature_category: :continuou
end
end
+ context 'when the bridge is successful and therefore retryable' do
+ let(:bridge) { create(:ci_bridge, :success) }
+
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Success
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Bridge::Retryable]
+ end
+
+ it 'fabricates a retryable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Bridge::Retryable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq s_('CiStatusText|passed')
+ expect(status.icon).to eq 'status_success'
+ expect(status.favicon).to eq 'favicon_status_success'
+ expect(status).to have_action
+ end
+ end
+
private
def create_bridge(*traits)
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index 964b57e709e..7b307de87c7 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -37,8 +37,18 @@ RSpec.describe Ci::Bridge, feature_category: :continuous_integration do
describe '#retryable?' do
let(:bridge) { create(:ci_bridge, :success) }
- it 'returns false' do
- expect(bridge.retryable?).to eq(false)
+ it 'returns true' do
+ expect(bridge.retryable?).to eq(true)
+ end
+
+ context 'without ci_recreate_downstream_pipeline ff' do
+ before do
+ stub_feature_flags(ci_recreate_downstream_pipeline: false)
+ end
+
+ it 'returns false' do
+ expect(bridge.retryable?).to eq(false)
+ end
end
end
@@ -590,4 +600,10 @@ RSpec.describe Ci::Bridge, feature_category: :continuous_integration do
expect(bridge.metadata.partition_id).to eq(ci_testing_partition_id)
end
end
+
+ describe '#deployment_job?' do
+ subject { bridge.deployment_job? }
+
+ it { is_expected.to eq(false) }
+ end
end
diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb
index 07fac4ee2f7..89ed8ab3fa7 100644
--- a/spec/models/ci/processable_spec.rb
+++ b/spec/models/ci/processable_spec.rb
@@ -287,6 +287,12 @@ RSpec.describe Ci::Processable do
end
end
+ context 'when the processable is a bridge' do
+ subject(:processable) { create(:ci_bridge, pipeline: pipeline) }
+
+ it_behaves_like 'retryable processable'
+ end
+
context 'when the processable is a build' do
subject(:processable) { create(:ci_build, pipeline: pipeline) }
diff --git a/spec/models/clusters/applications/cilium_spec.rb b/spec/models/clusters/applications/cilium_spec.rb
deleted file mode 100644
index 8b01502d5c0..00000000000
--- a/spec/models/clusters/applications/cilium_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::Cilium do
- let(:cilium) { create(:clusters_applications_cilium) }
-
- include_examples 'cluster application core specs', :clusters_applications_cilium
- include_examples 'cluster application status specs', :clusters_applications_cilium
- include_examples 'cluster application initial status specs'
-
- describe '#allowed_to_uninstall?' do
- subject { cilium.allowed_to_uninstall? }
-
- it { is_expected.to be false }
- end
-end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 63931f136f8..2ea6c396117 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -920,6 +920,29 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
end
end
+ describe '#invalidate_personal_projects_count_of_owner' do
+ context 'for personal projects' do
+ let_it_be(:namespace_user) { create(:user) }
+ let_it_be(:project) { create(:project, namespace: namespace_user.namespace) }
+
+ it 'invalidates personal_project_count cache of the the owner of the personal namespace' do
+ expect(Rails.cache).to receive(:delete).with(['users', namespace_user.id, 'personal_projects_count'])
+
+ project.invalidate_personal_projects_count_of_owner
+ end
+ end
+
+ context 'for projects in groups' do
+ let_it_be(:project) { create(:project, namespace: create(:group)) }
+
+ it 'does not invalidates any cache' do
+ expect(Rails.cache).not_to receive(:delete)
+
+ project.invalidate_personal_projects_count_of_owner
+ end
+ end
+ end
+
describe '#default_pipeline_lock' do
let(:project) { build_stubbed(:project) }
diff --git a/spec/services/ci/retry_job_service_spec.rb b/spec/services/ci/retry_job_service_spec.rb
index c3d80f2cb56..10acf032b1a 100644
--- a/spec/services/ci/retry_job_service_spec.rb
+++ b/spec/services/ci/retry_job_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::RetryJobService do
+RSpec.describe Ci::RetryJobService, feature_category: :continuous_integration do
using RSpec::Parameterized::TableSyntax
let_it_be(:reporter) { create(:user) }
let_it_be(:developer) { create(:user) }
@@ -27,6 +27,22 @@ RSpec.describe Ci::RetryJobService do
project.add_reporter(reporter)
end
+ shared_context 'retryable bridge' do
+ let_it_be(:downstream_project) { create(:project, :repository) }
+
+ let_it_be_with_refind(:job) do
+ create(:ci_bridge, :success,
+ pipeline: pipeline, downstream: downstream_project, description: 'a trigger job', ci_stage: stage
+ )
+ end
+
+ let_it_be(:job_to_clone) { job }
+
+ before do
+ job.update!(retried: false)
+ end
+ end
+
shared_context 'retryable build' do
let_it_be_with_reload(:job) do
create(:ci_build, :success, pipeline: pipeline, ci_stage: stage)
@@ -102,6 +118,14 @@ RSpec.describe Ci::RetryJobService do
end
end
+ shared_examples_for 'does not retry the job' do
+ it 'returns :not_retryable and :unprocessable_entity' do
+ expect(subject.message).to be('Job cannot be retried')
+ expect(subject.payload[:reason]).to eq(:not_retryable)
+ expect(subject.payload[:job]).to eq(job)
+ end
+ end
+
shared_examples_for 'retries the job' do
it_behaves_like 'clones the job'
@@ -189,6 +213,20 @@ RSpec.describe Ci::RetryJobService do
expect { service.clone!(create(:ci_build).present) }.to raise_error(TypeError)
end
+ context 'when the job to be cloned is a bridge' do
+ include_context 'retryable bridge'
+
+ it_behaves_like 'clones the job'
+
+ context 'when given variables' do
+ let(:new_job) { service.clone!(job, variables: job_variables_attributes) }
+
+ it 'does not give variables to the new bridge' do
+ expect { new_job }.not_to raise_error
+ end
+ end
+ end
+
context 'when the job to be cloned is a build' do
include_context 'retryable build'
@@ -287,7 +325,33 @@ RSpec.describe Ci::RetryJobService do
subject { service.execute(job) }
+ context 'when the job to be retried is a bridge' do
+ context 'and it is not retryable' do
+ let_it_be(:job) { create(:ci_bridge, :failed, :reached_max_descendant_pipelines_depth) }
+
+ it_behaves_like 'does not retry the job'
+ end
+
+ include_context 'retryable bridge'
+
+ it_behaves_like 'retries the job'
+
+ context 'when given variables' do
+ let(:new_job) { service.clone!(job, variables: job_variables_attributes) }
+
+ it 'does not give variables to the new bridge' do
+ expect { new_job }.not_to raise_error
+ end
+ end
+ end
+
context 'when the job to be retried is a build' do
+ context 'and it is not retryable' do
+ let_it_be(:job) { create(:ci_build, :deployment_rejected, pipeline: pipeline) }
+
+ it_behaves_like 'does not retry the job'
+ end
+
include_context 'retryable build'
it_behaves_like 'retries the job'
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index f85a8eda7ee..47a31b9c09d 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -163,7 +163,7 @@ RSpec.describe Projects::CreateService, '#execute', feature_category: :projects
describe 'after create actions' do
it 'invalidate personal_projects_count caches' do
- expect(user).to receive(:invalidate_personal_projects_count)
+ expect(Rails.cache).to receive(:delete).with(['users', user.id, 'personal_projects_count'])
create_project(user, opts)
end
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index ff2de45661f..0ef0ecc1099 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -151,10 +151,22 @@ RSpec.describe Projects::DestroyService, :aggregate_failures, :event_store_publi
it_behaves_like 'deleting the project'
- it 'invalidates personal_project_count cache' do
- expect(user).to receive(:invalidate_personal_projects_count)
+ context 'personal projects count cache' do
+ context 'when the executor is the creator of the project itself' do
+ it 'invalidates personal_project_count cache of the the owner of the personal namespace' do
+ expect(user).to receive(:invalidate_personal_projects_count)
- destroy_project(project, user, {})
+ destroy_project(project, user, {})
+ end
+ end
+
+ context 'when the executor is the instance administrator', :enable_admin_mode do
+ it 'invalidates personal_project_count cache of the the owner of the personal namespace' do
+ expect(user).to receive(:invalidate_personal_projects_count)
+
+ destroy_project(project, create(:admin), {})
+ end
+ end
end
context 'with running pipelines' do
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 5171836f917..d62a736fe6a 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -126,6 +126,12 @@ RSpec.describe Projects::TransferService do
expect(project.namespace).to eq(user.namespace)
end
+ it 'invalidates personal_project_count cache of the the owner of the personal namespace' do
+ expect(user).to receive(:invalidate_personal_projects_count)
+
+ execute_transfer
+ end
+
context 'the owner of the namespace does not have a direct membership in the project residing in the group' do
it 'creates a project membership record for the owner of the namespace, with OWNER access level, after the transfer' do
execute_transfer
@@ -161,6 +167,17 @@ RSpec.describe Projects::TransferService do
end
end
+ context 'personal namespace -> group', :enable_admin_mode do
+ let(:executor) { create(:admin) }
+
+ it 'invalidates personal_project_count cache of the the owner of the personal namespace' \
+ 'that previously held the project' do
+ expect(user).to receive(:invalidate_personal_projects_count)
+
+ execute_transfer
+ end
+ end
+
context 'when transfer succeeds' do
before do
group.add_owner(user)
diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb
new file mode 100644
index 00000000000..fe36b1006b0
--- /dev/null
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'work items status' do
+ let(:state_selector) { '[data-testid="work-item-state-select"]' }
+
+ it 'sucessfully shows and changes the status of the work item' do
+ expect(find(state_selector)).to have_content 'Open'
+
+ find(state_selector).select("Closed")
+
+ wait_for_requests
+
+ expect(find(state_selector)).to have_content 'Closed'
+ expect(work_item.reload.state).to eq('closed')
+ end
+end
+
+RSpec.shared_examples 'work items comments' do
+ let(:form_selector) { '[data-testid="work-item-add-comment"]' }
+
+ it 'sucessfully creates and shows comments' do
+ click_button 'Add a comment'
+
+ find(form_selector).fill_in(with: "Test comment")
+ click_button "Comment"
+
+ wait_for_requests
+
+ expect(page).to have_content "Test comment"
+ end
+end
+
+RSpec.shared_examples 'work items assignees' do
+ it 'sucessfully assigns the current user by searching' do
+ # The button is only when the mouse is over the input
+ find('[data-testid="work-item-asssignees-input"]').fill_in(with: user.username)
+ wait_for_requests
+
+ # submit and simulate blur to save
+ send_keys(:enter)
+ find("body").click
+
+ wait_for_requests
+
+ expect(work_item.assignees).to include(user)
+ end
+end
+
+RSpec.shared_examples 'work items labels' do
+ it 'sucessfully assigns a label' do
+ label = create(:label, project: work_item.project, title: "testing-label")
+
+ find('[data-testid="work-item-labels-input"]').fill_in(with: label.title)
+ wait_for_requests
+
+ # submit and simulate blur to save
+ send_keys(:enter)
+ find("body").click
+
+ wait_for_requests
+
+ expect(work_item.labels).to include(label)
+ end
+end
+
+RSpec.shared_examples 'work items description' do
+ it 'shows GFM autocomplete', :aggregate_failures do
+ click_button "Edit description"
+
+ find('[aria-label="Description"]').send_keys("@#{user.username}")
+
+ wait_for_requests
+
+ page.within('.atwho-container') do
+ expect(page).to have_text(user.name)
+ end
+ end
+
+ context 'on conflict' do
+ let_it_be(:other_user) { create(:user) }
+ let(:expected_warning) { 'Someone edited the description at the same time you did.' }
+
+ before do
+ project.add_developer(other_user)
+ end
+
+ it 'shows conflict message when description changes', :aggregate_failures do
+ click_button "Edit description"
+
+ wait_for_requests
+
+ ::WorkItems::UpdateService.new(
+ project: work_item.project,
+ current_user: other_user,
+ params: { description: "oh no!" }
+ ).execute(work_item)
+
+ wait_for_requests
+
+ find('[aria-label="Description"]').send_keys("oh yeah!")
+
+ expect(page.find('[data-testid="work-item-description-conflicts"]')).to have_text(expected_warning)
+
+ click_button "Save and overwrite"
+
+ expect(page.find('[data-testid="work-item-description"]')).to have_text("oh yeah!")
+ end
+ end
+end
diff --git a/yarn.lock b/yarn.lock
index b1ebc904861..ff6bfe361d5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5683,10 +5683,10 @@ eslint-visitor-keys@^3.3.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
-eslint@8.28.0:
- version "8.28.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.28.0.tgz#81a680732634677cc890134bcdd9fdfea8e63d6e"
- integrity sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==
+eslint@8.29.0:
+ version "8.29.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.29.0.tgz#d74a88a20fb44d59c51851625bc4ee8d0ec43f87"
+ integrity sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==
dependencies:
"@eslint/eslintrc" "^1.3.3"
"@humanwhocodes/config-array" "^0.11.6"