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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-09 00:07:12 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-09 00:07:12 +0300
commit58cad9b83fc4b319542586e2cab64e2fe7d12050 (patch)
treea5f94021664861ff5fdcbcfabc045c0a120d6133
parentbb0d99269b1bee11939e6a3ddfcefed8c6fd4874 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/rspec/feature_category.yml1
-rw-r--r--app/assets/javascripts/ci/job_details/components/log/log.vue7
-rw-r--r--app/assets/javascripts/ci/job_details/index.js10
-rw-r--r--app/assets/javascripts/ci/job_details/store/actions.js13
-rw-r--r--app/assets/javascripts/ci/job_details/store/mutations.js4
-rw-r--r--app/assets/javascripts/ci/job_details/store/state.js2
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue12
-rw-r--r--app/assets/javascripts/issues/list/constants.js6
-rw-r--r--app/assets/javascripts/issues/list/index.js2
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js9
-rw-r--r--app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue3
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue5
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/general/components/signup_checkbox.vue8
-rw-r--r--app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue1
-rw-r--r--app/assets/javascripts/pages/import/history/components/import_history_app.vue2
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue5
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue3
-rw-r--r--app/helpers/ci/jobs_helper.rb5
-rw-r--r--app/models/ci/build.rb5
-rw-r--r--app/models/ci/catalog/resources/sync_event.rb2
-rw-r--r--app/models/ci/job_token/scope.rb5
-rw-r--r--app/models/ci/processable.rb6
-rw-r--r--app/policies/project_policy.rb15
-rw-r--r--app/views/groups/settings/_general.html.haml2
-rw-r--r--config/feature_flags/development/restrict_ci_job_token_for_public_and_internal_projects.yml8
-rw-r--r--db/post_migrate/20231207194620_backfill_catalog_resources_visibility_level.rb25
-rw-r--r--db/schema_migrations/202312071946201
-rw-r--r--doc/api/graphql/reference/index.md2
-rw-r--r--doc/api/merge_requests.md4
-rw-r--r--doc/ci/pipelines/index.md15
-rw-r--r--doc/development/merge_request_concepts/diffs/index.md4
-rw-r--r--doc/development/merge_request_concepts/index.md2
-rw-r--r--doc/tutorials/protected_workflow/index.md2
-rw-r--r--doc/user/project/code_intelligence.md2
-rw-r--r--doc/user/project/merge_requests/ai_in_merge_requests.md2
-rw-r--r--doc/user/project/merge_requests/authorization_for_merge_requests.md2
-rw-r--r--doc/user/project/merge_requests/changes.md2
-rw-r--r--doc/user/project/merge_requests/commit_templates.md2
-rw-r--r--doc/user/project/merge_requests/confidential.md4
-rw-r--r--doc/user/project/merge_requests/conflicts.md2
-rw-r--r--doc/user/project/merge_requests/creating_merge_requests.md2
-rw-r--r--doc/user/project/merge_requests/drafts.md2
-rw-r--r--doc/user/project/merge_requests/index.md4
-rw-r--r--doc/user/project/merge_requests/revert_changes.md2
-rw-r--r--doc/user/project/merge_requests/versions.md2
-rw-r--r--doc/user/search/advanced_search.md1
-rw-r--r--lib/gitlab/ci/config/entry/job.rb9
-rw-r--r--lib/gitlab/ci/config/entry/processable.rb10
-rw-r--r--package.json2
-rw-r--r--qa/qa/page/group/settings/package_registries.rb18
-rw-r--r--qa/qa/page/project/fork/new.rb14
-rw-r--r--spec/factories/ci/builds.rb6
-rw-r--r--spec/factories/ci/processable.rb10
-rw-r--r--spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js4
-rw-r--r--spec/frontend/ci/job_details/components/log/log_spec.js27
-rw-r--r--spec/frontend/ci/job_details/job_app_spec.js10
-rw-r--r--spec/frontend/ci/job_details/store/actions_spec.js40
-rw-r--r--spec/frontend/ci/job_details/store/mutations_spec.js8
-rw-r--r--spec/frontend/diffs/components/diff_file_spec.js3
-rw-r--r--spec/helpers/ci/jobs_helper_spec.rb5
-rw-r--r--spec/lib/gitlab/ci/config/entry/bridge_spec.rb9
-rw-r--r--spec/lib/gitlab/ci/config/entry/processable_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/yaml_processor/test_cases/interruptible_spec.rb96
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb49
-rw-r--r--spec/migrations/20231207194620_backfill_catalog_resources_visibility_level_spec.rb27
-rw-r--r--spec/models/ci/bridge_spec.rb5
-rw-r--r--spec/models/ci/job_token/scope_spec.rb12
-rw-r--r--spec/policies/project_policy_spec.rb82
-rw-r--r--spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb28
-rw-r--r--yarn.lock8
71 files changed, 420 insertions, 320 deletions
diff --git a/.rubocop_todo/rspec/feature_category.yml b/.rubocop_todo/rspec/feature_category.yml
index de0a2029d9b..fb8e7eecc64 100644
--- a/.rubocop_todo/rspec/feature_category.yml
+++ b/.rubocop_todo/rspec/feature_category.yml
@@ -2905,7 +2905,6 @@ RSpec/FeatureCategory:
- 'spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/allow_failure_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/artifacts_spec.rb'
- - 'spec/lib/gitlab/ci/config/entry/bridge_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/cache_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/caches_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/commands_spec.rb'
diff --git a/app/assets/javascripts/ci/job_details/components/log/log.vue b/app/assets/javascripts/ci/job_details/components/log/log.vue
index b8ad4801510..8b43739d7ef 100644
--- a/app/assets/javascripts/ci/job_details/components/log/log.vue
+++ b/app/assets/javascripts/ci/job_details/components/log/log.vue
@@ -12,6 +12,7 @@ export default {
LogLineHeader,
LogLine,
},
+ inject: ['pagePath'],
props: {
searchResults: {
type: Array,
@@ -20,7 +21,7 @@ export default {
},
},
computed: {
- ...mapState(['jobLogEndpoint', 'jobLog', 'jobLogSections', 'isJobLogComplete']),
+ ...mapState(['jobLog', 'jobLogSections', 'isJobLogComplete']),
highlightedLines() {
return this.searchResults.map((result) => result.lineNumber);
},
@@ -73,7 +74,7 @@ export default {
v-if="line.isHeader"
:key="line.offset"
:line="line"
- :path="jobLogEndpoint"
+ :path="pagePath"
:is-closed="jobLogSections[line.section].isClosed"
:duration="jobLogSections[line.section].duration"
:hide-duration="jobLogSections[line.section].hideDuration"
@@ -84,7 +85,7 @@ export default {
v-else
:key="line.offset"
:line="line"
- :path="jobLogEndpoint"
+ :path="pagePath"
:is-highlighted="isHighlighted(line)"
/>
</template>
diff --git a/app/assets/javascripts/ci/job_details/index.js b/app/assets/javascripts/ci/job_details/index.js
index 424ae698861..7748b6e83ef 100644
--- a/app/assets/javascripts/ci/job_details/index.js
+++ b/app/assets/javascripts/ci/job_details/index.js
@@ -20,13 +20,14 @@ export const initJobDetails = () => {
}
const {
+ jobEndpoint,
+ logEndpoint,
+ pagePath,
+ projectPath,
artifactHelpUrl,
deploymentHelpUrl,
runnerSettingsUrl,
subscriptionsMoreMinutesUrl,
- endpoint,
- pagePath,
- projectPath,
retryOutdatedJobDocsUrl,
aiRootCauseAnalysisAvailable,
testReportSummaryUrl,
@@ -35,13 +36,14 @@ export const initJobDetails = () => {
// init store to start fetching log
const store = createStore();
- store.dispatch('init', { endpoint, pagePath, testReportSummaryUrl });
+ store.dispatch('init', { jobEndpoint, logEndpoint, testReportSummaryUrl });
return new Vue({
el,
apolloProvider,
store,
provide: {
+ pagePath,
projectPath,
retryOutdatedJobDocsUrl,
aiRootCauseAnalysisAvailable: parseBoolean(aiRootCauseAnalysisAvailable),
diff --git a/app/assets/javascripts/ci/job_details/store/actions.js b/app/assets/javascripts/ci/job_details/store/actions.js
index 1a018c577ac..03323e51583 100644
--- a/app/assets/javascripts/ci/job_details/store/actions.js
+++ b/app/assets/javascripts/ci/job_details/store/actions.js
@@ -15,18 +15,12 @@ import { __ } from '~/locale';
import { reportToSentry } from '~/ci/utils';
import * as types from './mutation_types';
-export const init = ({ dispatch }, { endpoint, pagePath, testReportSummaryUrl }) => {
- dispatch('setJobLogOptions', {
- endpoint,
- pagePath,
- testReportSummaryUrl,
- });
+export const init = ({ commit, dispatch }, { jobEndpoint, logEndpoint, testReportSummaryUrl }) => {
+ commit(types.SET_JOB_LOG_OPTIONS, { jobEndpoint, logEndpoint, testReportSummaryUrl });
return dispatch('fetchJob');
};
-export const setJobLogOptions = ({ commit }, options) => commit(types.SET_JOB_LOG_OPTIONS, options);
-
export const hideSidebar = ({ commit }) => commit(types.HIDE_SIDEBAR);
export const showSidebar = ({ commit }) => commit(types.SHOW_SIDEBAR);
@@ -155,10 +149,9 @@ export const requestJobLog = ({ commit }) => commit(types.REQUEST_JOB_LOG);
export const fetchJobLog = ({ commit, dispatch, state }) => {
let isScrolledToBottomBeforeReceivingJobLog;
- // update trace endpoint once BE completes trace re-naming in #340626
return (
axios
- .get(`${state.jobLogEndpoint}/trace.json`, {
+ .get(state.logEndpoint, {
params: { state: state.jobLogState },
})
.then(({ data }) => {
diff --git a/app/assets/javascripts/ci/job_details/store/mutations.js b/app/assets/javascripts/ci/job_details/store/mutations.js
index bc679699012..e8e65d690d8 100644
--- a/app/assets/javascripts/ci/job_details/store/mutations.js
+++ b/app/assets/javascripts/ci/job_details/store/mutations.js
@@ -3,8 +3,8 @@ import { logLinesParser } from './utils';
export default {
[types.SET_JOB_LOG_OPTIONS](state, options = {}) {
- state.jobLogEndpoint = options.pagePath;
- state.jobEndpoint = options.endpoint;
+ state.jobEndpoint = options.jobEndpoint;
+ state.logEndpoint = options.logEndpoint;
state.testReportSummaryUrl = options.testReportSummaryUrl;
},
diff --git a/app/assets/javascripts/ci/job_details/store/state.js b/app/assets/javascripts/ci/job_details/store/state.js
index 3efbcc51d65..24736bedf56 100644
--- a/app/assets/javascripts/ci/job_details/store/state.js
+++ b/app/assets/javascripts/ci/job_details/store/state.js
@@ -1,6 +1,6 @@
export default () => ({
jobEndpoint: null,
- jobLogEndpoint: null,
+ logEndpoint: null,
testReportSummaryUrl: null,
// sidebar
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index c9fd25171aa..b2841172fe1 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -9,7 +9,7 @@ import DiffContent from 'jh_else_ce/diffs/components/diff_content.vue';
import { createAlert } from '~/alert';
import { hasDiff } from '~/helpers/diffs_helper';
import { diffViewerErrors } from '~/ide/constants';
-import { scrollToElement } from '~/lib/utils/common_utils';
+import { scrollToElement, isElementStuck } from '~/lib/utils/common_utils';
import { sprintf } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import notesEventHub from '~/notes/event_hub';
@@ -295,8 +295,13 @@ export default {
collapsed: collapsingNow,
});
- if (collapsingNow && viaUserInteraction && contentElement) {
- scrollToElement(contentElement, { duration: 1 });
+ if (
+ collapsingNow &&
+ viaUserInteraction &&
+ contentElement &&
+ isElementStuck(this.$refs.header.$el)
+ ) {
+ scrollToElement(contentElement, { duration: 0 });
}
if (!this.hasDiff && !collapsingNow) {
@@ -381,6 +386,7 @@ export default {
class="diff-file file-holder gl-border-none gl-mb-0! gl-pb-5"
>
<diff-file-header
+ ref="header"
:can-current-user-fork="canCurrentUserFork"
:diff-file="file"
:collapsible="true"
diff --git a/app/assets/javascripts/issues/list/constants.js b/app/assets/javascripts/issues/list/constants.js
index 682c7629962..d6ff5c952c2 100644
--- a/app/assets/javascripts/issues/list/constants.js
+++ b/app/assets/javascripts/issues/list/constants.js
@@ -164,6 +164,12 @@ export const specialFilterValues = [
FILTER_STARTED,
];
+export const TYPE_TOKEN_EPIC_OPTION = {
+ icon: 'epic',
+ title: __('Epic'),
+ value: 'epic',
+};
+
export const TYPE_TOKEN_OBJECTIVE_OPTION = {
icon: 'issue-type-objective',
title: s__('WorkItem|Objective'),
diff --git a/app/assets/javascripts/issues/list/index.js b/app/assets/javascripts/issues/list/index.js
index 8c60ad6dc4e..5a836e3e40a 100644
--- a/app/assets/javascripts/issues/list/index.js
+++ b/app/assets/javascripts/issues/list/index.js
@@ -70,6 +70,7 @@ export async function mountIssuesListApp() {
hasAnyIssues,
hasAnyProjects,
hasBlockedIssuesFeature,
+ hasEpicsFeature,
hasIssuableHealthStatusFeature,
hasIssueDateFilterFeature,
hasIssueWeightsFeature,
@@ -127,6 +128,7 @@ export async function mountIssuesListApp() {
hasAnyIssues: parseBoolean(hasAnyIssues),
hasAnyProjects: parseBoolean(hasAnyProjects),
hasBlockedIssuesFeature: parseBoolean(hasBlockedIssuesFeature),
+ hasEpicsFeature: parseBoolean(hasEpicsFeature),
hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature),
hasIssueDateFilterFeature: parseBoolean(hasIssueDateFilterFeature),
hasIssueWeightsFeature: parseBoolean(hasIssueWeightsFeature),
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index b29c234338d..2c31e4c210c 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -740,3 +740,12 @@ export const isDefaultCiConfig = (path) => {
export const hasCiConfigExtension = (path) => {
return CI_CONFIG_PATH_EXTENSION.test(path);
};
+
+/**
+ * Checks if an element with position:sticky is stuck
+ *
+ * @param el
+ * @returns {boolean}
+ */
+export const isElementStuck = (el) =>
+ el.getBoundingClientRect().top <= parseInt(getComputedStyle(el).top, 10);
diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue
index a821a2483cd..b1729f07861 100644
--- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue
+++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue
@@ -126,7 +126,6 @@ export default {
attributes: {
variant: 'danger',
category: 'primary',
- 'data-qa-selector': 'delete_modal_button',
},
},
fileDeletePrimaryAction: {
@@ -158,7 +157,6 @@ export default {
class="js-delete-button"
variant="danger"
category="primary"
- data-qa-selector="delete_button"
>
{{ __('Delete') }}
</gl-button>
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue
index 59d4f5e24d0..9e6d55d71d3 100644
--- a/app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue
+++ b/app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue
@@ -129,7 +129,7 @@ export default {
</script>
<template>
- <settings-block data-qa-selector="dependency_proxy_settings_content">
+ <settings-block data-testid="dependency-proxy-settings-content">
<template #title> {{ $options.i18n.DEPENDENCY_PROXY_HEADER }} </template>
<template #description> {{ $options.i18n.DEPENDENCY_PROXY_DESCRIPTION }} </template>
<template #default>
@@ -138,7 +138,6 @@ export default {
v-model="enabled"
:disabled="isLoading"
:label="$options.i18n.enabledProxyLabel"
- data-qa-selector="dependency_proxy_setting_toggle"
data-testid="dependency-proxy-setting-toggle"
>
<template v-if="enabled" #help>
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue
index e15f204dc6e..a773a64c4fc 100644
--- a/app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue
+++ b/app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue
@@ -78,7 +78,6 @@ export default {
exception: 'mavenDuplicateExceptionRegex',
},
testid: 'maven-settings',
- dataQaSelector: 'allow_duplicates_toggle',
},
{
id: 'generic-duplicated-settings-regex-input',
@@ -154,7 +153,7 @@ export default {
</script>
<template>
- <settings-block data-qa-selector="package_registry_settings_content">
+ <settings-block data-testid="package-registry-settings-content">
<template #title> {{ $options.i18n.PACKAGE_SETTINGS_HEADER }}</template>
<template #description>
<span data-testid="description">
@@ -174,7 +173,7 @@ export default {
</template>
<template #cell(allowDuplicates)="{ item }">
<gl-toggle
- :data-qa-selector="item.dataQaSelector"
+ :data-testid="item.dataTestid"
:label="$options.i18n.DUPLICATES_TOGGLE_LABEL"
:value="item.duplicatesAllowed"
:disabled="isLoading"
diff --git a/app/assets/javascripts/pages/admin/application_settings/general/components/signup_checkbox.vue b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_checkbox.vue
index 2217792d7f3..9dfad16ae82 100644
--- a/app/assets/javascripts/pages/admin/application_settings/general/components/signup_checkbox.vue
+++ b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_checkbox.vue
@@ -23,7 +23,7 @@ export default {
type: Boolean,
required: true,
},
- dataQaSelector: {
+ dataTestId: {
type: String,
required: false,
default: '',
@@ -36,11 +36,7 @@ export default {
<div>
<input :name="name" type="hidden" :value="value ? '1' : '0'" data-testid="input" />
- <gl-form-checkbox
- :checked="value"
- :data-qa-selector="dataQaSelector"
- @input="$emit('input', $event)"
- >
+ <gl-form-checkbox :checked="value" :data-testid="dataTestId" @input="$emit('input', $event)">
<span data-testid="label">{{ label }}</span>
<template v-if="helpText" #help>
<span data-testid="helpText">{{ helpText }}</span>
diff --git a/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue b/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue
index e99aceb2196..1d54dad43a9 100644
--- a/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue
+++ b/app/assets/javascripts/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue
@@ -93,7 +93,6 @@ export default {
tableCell({
key: 'status',
label: __('Status'),
- tdAttr: { 'data-qa-selector': 'import_status_indicator' },
}),
],
diff --git a/app/assets/javascripts/pages/import/history/components/import_history_app.vue b/app/assets/javascripts/pages/import/history/components/import_history_app.vue
index 94fa40cc700..a0ff3ded3f5 100644
--- a/app/assets/javascripts/pages/import/history/components/import_history_app.vue
+++ b/app/assets/javascripts/pages/import/history/components/import_history_app.vue
@@ -65,10 +65,10 @@ export default {
key: 'created_at',
label: __('Date'),
}),
+
tableCell({
key: 'status',
label: __('Status'),
- tdAttr: { 'data-qa-selector': 'import_status_indicator' },
}),
],
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
index e3d50e900ca..bfa2f2cc14f 100644
--- a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
+++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
@@ -423,7 +423,7 @@ export default {
>
<div>
<gl-icon
- data-qa-selector="fork_privacy_button"
+ data-testid="fork-privacy-button"
:name="icon"
:data-qa-privacy-level="`${value}`"
/>
@@ -440,8 +440,7 @@ export default {
category="primary"
variant="confirm"
class="js-no-auto-disable"
- data-testid="submit-button"
- data-qa-selector="fork_project_button"
+ data-testid="fork-project-button"
:loading="isSaving"
>
{{ s__('ForkProject|Fork project') }}
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
index 84796954cf1..b4bb2176e26 100644
--- a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
+++ b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
@@ -90,8 +90,7 @@ export default {
}}</gl-button>
<gl-collapsible-listbox
class="gl-flex-grow-1"
- data-qa-selector="select_namespace_dropdown"
- data-testid="select_namespace_dropdown"
+ data-testid="select-namespace-dropdown"
:items="namespaceItems"
:header-text="__('Namespaces')"
:no-results-text="__('No matches found')"
diff --git a/app/helpers/ci/jobs_helper.rb b/app/helpers/ci/jobs_helper.rb
index c3af2de16e1..37b008611e6 100644
--- a/app/helpers/ci/jobs_helper.rb
+++ b/app/helpers/ci/jobs_helper.rb
@@ -4,14 +4,15 @@ module Ci
module JobsHelper
def jobs_data(project, build)
{
- "endpoint" => project_job_path(project, build, format: :json),
+ "job_endpoint" => project_job_path(project, build, format: :json),
+ "log_endpoint" => trace_project_job_path(project, build, format: :json),
+ "test_report_summary_url" => test_report_summary_project_job_path(project, build, format: :json),
"page_path" => project_job_path(project, build),
"project_path" => project.full_path,
"artifact_help_url" => help_page_path('user/gitlab_com/index.md', anchor: 'gitlab-cicd'),
"deployment_help_url" => help_page_path('user/project/clusters/deploy_to_cluster.md', anchor: 'troubleshooting'),
"runner_settings_url" => project_runners_path(build.project, anchor: 'js-runners-settings'),
"retry_outdated_job_docs_url" => help_page_path('ci/pipelines/settings', anchor: 'retry-outdated-jobs'),
- "test_report_summary_url" => test_report_summary_project_job_path(project, build, format: :json),
"pipeline_test_report_url" => test_report_project_pipeline_path(project, build.pipeline)
}
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index dbc56079a06..69584f2dd38 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -111,11 +111,6 @@ module Ci
validates :coverage, numericality: true, allow_blank: true
validates :ref, presence: true
- scope :not_interruptible, -> do
- joins(:metadata)
- .where.not(Ci::BuildMetadata.table_name => { id: Ci::BuildMetadata.scoped_build.with_interruptible.select(:id) })
- end
-
scope :unstarted, -> { where(runner_id: nil) }
scope :with_any_artifacts, -> do
diff --git a/app/models/ci/catalog/resources/sync_event.rb b/app/models/ci/catalog/resources/sync_event.rb
index a2819102875..2a452e6cc65 100644
--- a/app/models/ci/catalog/resources/sync_event.rb
+++ b/app/models/ci/catalog/resources/sync_event.rb
@@ -17,7 +17,7 @@ module Ci
self.primary_key = :id
self.sequence_name = :p_catalog_resource_sync_events_id_seq
- ignore_column :partition_id, remove_with: '3000.0', remove_after: '3000-01-01'
+ ignore_column :partition_id, remove_never: true
belongs_to :catalog_resource, class_name: 'Ci::Catalog::Resource', inverse_of: :sync_events
belongs_to :project, inverse_of: :catalog_resource_sync_events
diff --git a/app/models/ci/job_token/scope.rb b/app/models/ci/job_token/scope.rb
index 17809ba20d3..a29d4fee299 100644
--- a/app/models/ci/job_token/scope.rb
+++ b/app/models/ci/job_token/scope.rb
@@ -54,10 +54,7 @@ module Ci
# if the setting is disabled any project is considered to be in scope.
return true unless current_project.ci_outbound_job_token_scope_enabled?
- if !accessed_project.private? &&
- Feature.enabled?(:restrict_ci_job_token_for_public_and_internal_projects, accessed_project)
- return true
- end
+ return true unless accessed_project.private?
outbound_allowlist.includes?(accessed_project)
end
diff --git a/app/models/ci/processable.rb b/app/models/ci/processable.rb
index 132f706d265..414d36da7c3 100644
--- a/app/models/ci/processable.rb
+++ b/app/models/ci/processable.rb
@@ -33,6 +33,12 @@ module Ci
where('NOT EXISTS (?)', needs)
end
+ scope :not_interruptible, -> do
+ joins(:metadata).where.not(
+ Ci::BuildMetadata.table_name => { id: Ci::BuildMetadata.scoped_build.with_interruptible.select(:id) }
+ )
+ end
+
state_machine :status do
event :enqueue do
transition [:created, :skipped, :manual, :scheduled] => :waiting_for_resource, if: :with_resource_group?
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index bbb0e3df500..15bab8ab007 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -154,9 +154,6 @@ class ProjectPolicy < BasePolicy
end
with_scope :subject
- condition(:restrict_job_token_enabled) { Feature.enabled?(:restrict_ci_job_token_for_public_and_internal_projects, @subject) }
-
- with_scope :subject
condition(:forking_allowed) do
@subject.feature_available?(:forking, @user)
end
@@ -709,7 +706,7 @@ class ProjectPolicy < BasePolicy
rule { ~public_project & ~internal_access & ~project_allowed_for_job_token }.prevent_all
# If this project is public or internal we want to prevent all aside from a few public policies
- rule { public_or_internal & ~project_allowed_for_job_token & restrict_job_token_enabled }.policy do
+ rule { public_or_internal & ~project_allowed_for_job_token }.policy do
prevent :guest_access
prevent :public_access
prevent :public_user_access
@@ -719,25 +716,25 @@ class ProjectPolicy < BasePolicy
prevent :owner_access
end
- rule { public_or_internal & job_token_container_registry & restrict_job_token_enabled }.policy do
+ rule { public_or_internal & job_token_container_registry }.policy do
enable :build_read_container_image
enable :read_container_image
end
- rule { public_or_internal & job_token_package_registry & restrict_job_token_enabled }.policy do
+ rule { public_or_internal & job_token_package_registry }.policy do
enable :read_package
enable :read_project
end
- rule { public_or_internal & job_token_builds & restrict_job_token_enabled }.policy do
+ rule { public_or_internal & job_token_builds }.policy do
enable :read_commit_status # this is additionally needed to download artifacts
end
- rule { public_or_internal & job_token_releases & restrict_job_token_enabled }.policy do
+ rule { public_or_internal & job_token_releases }.policy do
enable :read_release
end
- rule { public_or_internal & job_token_environments & restrict_job_token_enabled }.policy do
+ rule { public_or_internal & job_token_environments }.policy do
enable :read_environment
end
diff --git a/app/views/groups/settings/_general.html.haml b/app/views/groups/settings/_general.html.haml
index 115ed0f0fa4..e02a61243f7 100644
--- a/app/views/groups/settings/_general.html.haml
+++ b/app/views/groups/settings/_general.html.haml
@@ -17,7 +17,7 @@
.row.gl-mt-3
.form-group.col-md-9
= f.label :description, s_('Groups|Group description (optional)'), class: 'label-bold'
- = f.text_area :description, class: 'form-control', rows: 3
+ = f.text_area :description, class: 'form-control', rows: 3, maxlength: 500
.row.gl-mt-3
.form-group.col-md-5
diff --git a/config/feature_flags/development/restrict_ci_job_token_for_public_and_internal_projects.yml b/config/feature_flags/development/restrict_ci_job_token_for_public_and_internal_projects.yml
deleted file mode 100644
index 31216be0a5c..00000000000
--- a/config/feature_flags/development/restrict_ci_job_token_for_public_and_internal_projects.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: restrict_ci_job_token_for_public_and_internal_projects
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135263
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/417172
-milestone: '16.6'
-type: development
-group: group::pipeline security
-default_enabled: true
diff --git a/db/post_migrate/20231207194620_backfill_catalog_resources_visibility_level.rb b/db/post_migrate/20231207194620_backfill_catalog_resources_visibility_level.rb
new file mode 100644
index 00000000000..808b0d983a8
--- /dev/null
+++ b/db/post_migrate/20231207194620_backfill_catalog_resources_visibility_level.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class BackfillCatalogResourcesVisibilityLevel < Gitlab::Database::Migration[2.2]
+ milestone '16.7'
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ sql = <<-SQL
+ UPDATE catalog_resources
+ SET visibility_level = projects.visibility_level
+ FROM projects
+ WHERE catalog_resources.project_id = projects.id
+ SQL
+
+ execute(sql)
+ end
+
+ def down
+ # no-op
+
+ # The `visibility_level` column in `catalog_resources` is denormalized;
+ # it should always stay in sync with the corresponding data in `projects`.
+ end
+end
diff --git a/db/schema_migrations/20231207194620 b/db/schema_migrations/20231207194620
new file mode 100644
index 00000000000..48bdcfd9069
--- /dev/null
+++ b/db/schema_migrations/20231207194620
@@ -0,0 +1 @@
+fe43053b1d4a2bdebb2dc6bf3acbf7471feaa33b60f718f980b4ea8810dcca28 \ No newline at end of file
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 9884e6e8f34..3f998bdef31 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -5380,7 +5380,7 @@ Input type: `MemberRoleCreateInput`
| <a id="mutationmemberrolecreategrouppath"></a>`groupPath` | [`ID!`](#id) | Group the member role to mutate is in. |
| <a id="mutationmemberrolecreatemanageprojectaccesstokens"></a>`manageProjectAccessTokens` | [`Boolean`](#boolean) | Permission to admin project access tokens. |
| <a id="mutationmemberrolecreatename"></a>`name` | [`String`](#string) | Name of the member role. |
-| <a id="mutationmemberrolecreatepermissions"></a>`permissions` **{warning-solid}** | [`[String!]`](#string) | **Deprecated:** This feature is an Experiment. It can be changed or removed at any time. Introduced in 16.7. |
+| <a id="mutationmemberrolecreatepermissions"></a>`permissions` **{warning-solid}** | [`[MemberRolePermission!]`](#memberrolepermission) | **Deprecated:** This feature is an Experiment. It can be changed or removed at any time. Introduced in 16.7. |
| <a id="mutationmemberrolecreatereadcode"></a>`readCode` | [`Boolean`](#boolean) | Permission to read code. |
| <a id="mutationmemberrolecreatereaddependency"></a>`readDependency` | [`Boolean`](#boolean) | Permission to read dependency. |
| <a id="mutationmemberrolecreatereadvulnerability"></a>`readVulnerability` | [`Boolean`](#boolean) | Permission to read vulnerability. |
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index cc7dccc9342..8e8ee1a8477 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -206,7 +206,7 @@ Supported attributes:
### Merge requests list response notes
-- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31890) in GitLab 13.0, listing merge requests may
+- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31890) in GitLab 13.0, listing merge requests might
not proactively update `merge_status` (which also affects the `has_conflicts`), as this can be an expensive operation.
If you need the value of these fields from this endpoint, set the `with_merge_status_recheck` parameter to
`true` in the query.
@@ -1279,7 +1279,7 @@ POST /projects/:id/merge_requests
| `milestone_id` | integer | No | The global ID of a milestone. |
| `remove_source_branch` | boolean | No | Flag indicating if a merge request should remove the source branch when merging. |
| `reviewer_ids` | integer array | No | The ID of the users added as a reviewer to the merge request. If set to `0` or left empty, no reviewers are added. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49341) in GitLab 13.8. |
-| `squash` | boolean | No | Indicates if the merge request is set to be squashed when merged. [Project settings](../user/project/merge_requests/squash_and_merge.md#configure-squash-options-for-a-project) may override this value. |
+| `squash` | boolean | No | Indicates if the merge request is set to be squashed when merged. [Project settings](../user/project/merge_requests/squash_and_merge.md#configure-squash-options-for-a-project) might override this value. |
| `target_project_id` | integer | No | Numeric ID of the target project. |
```json
diff --git a/doc/ci/pipelines/index.md b/doc/ci/pipelines/index.md
index adeb1168644..957e0e0de27 100644
--- a/doc/ci/pipelines/index.md
+++ b/doc/ci/pipelines/index.md
@@ -262,18 +262,11 @@ In the example below, the `production` stage has a job with a manual action:
![Pipelines example](img/manual_pipeline_v14_2.png)
-#### Start multiple manual actions in a stage
+#### Start all manual jobs in a stage
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/27188) in GitLab 11.11.
-
-Multiple manual actions in a single stage can be started at the same time using the "Play all manual"
-After you select this action, each individual manual action is triggered and refreshed
-to an updated status.
-
-This functionality is only available:
-
-- For users with at least the Developer role.
-- If the stage contains [manual actions](#add-manual-interaction-to-your-pipeline).
+If a stage contains only manual jobs, you can start all the jobs at the same time
+by selecting **Play all manual** (**{play}**) above the stage. If the stage contains
+non-manual jobs, the option is not displayed.
### Skip a pipeline
diff --git a/doc/development/merge_request_concepts/diffs/index.md b/doc/development/merge_request_concepts/diffs/index.md
index ed29b830dc5..ad0e8603983 100644
--- a/doc/development/merge_request_concepts/diffs/index.md
+++ b/doc/development/merge_request_concepts/diffs/index.md
@@ -21,7 +21,7 @@ We rely on different sources to present diffs. These include:
In January 2019, Oswaldo Ferreira hosted a Deep Dive (GitLab team members only:
`https://gitlab.com/gitlab-org/create-stage/-/issues/1`) on GitLab Diffs and Commenting on Diffs
-functionality to share domain-specific knowledge with anyone who may work in this part of the
+functionality to share domain-specific knowledge with anyone who works in this part of the
codebase in the future:
<!-- vale gitlab.Spelling = YES -->
@@ -31,7 +31,7 @@ codebase in the future:
- Slides on [Google Slides](https://docs.google.com/presentation/d/1bGutFH2AT3bxOPZuLMGl1ANWHqFnrxwQwjiwAZkF-TU/edit)
- [PDF slides](https://gitlab.com/gitlab-org/create-stage/uploads/b5ad2f336e0afcfe0f99db0af0ccc71a/)
-Everything covered in this deep dive was accurate as of GitLab 11.7, and while specific details may
+Everything covered in this deep dive was accurate as of GitLab 11.7, and while specific details might
have changed since then, it should still serve as a good introduction.
## Architecture overview
diff --git a/doc/development/merge_request_concepts/index.md b/doc/development/merge_request_concepts/index.md
index 40eb9231342..d04dff9f1be 100644
--- a/doc/development/merge_request_concepts/index.md
+++ b/doc/development/merge_request_concepts/index.md
@@ -27,7 +27,7 @@ The merge widget is the component of the merge request where the `merge` button
![merge widget](../img/merge_widget_v14_7.png)
-This area of the merge request is where all of the options and commit messages are defined prior to merging. It also contains information about what is in the merge request, what issues may be closed, and other important information to the merging process.
+This area of the merge request is where all of the options and commit messages are defined prior to merging. It also contains information about what is in the merge request, what issues are closed, and other information important to the merging process.
## Report widgets
diff --git a/doc/tutorials/protected_workflow/index.md b/doc/tutorials/protected_workflow/index.md
index 324aa5dc885..8e9ed3e952a 100644
--- a/doc/tutorials/protected_workflow/index.md
+++ b/doc/tutorials/protected_workflow/index.md
@@ -258,7 +258,7 @@ to protect multiple branches:
to files they work on, toggle **Require approval from code owners**.
1. Select **Protect**.
1. In the table of branches, find the rule marked as `Default`. (Depending on
- your version of GitLab, this branch may be named `main` or `master`.) Set the
+ your version of GitLab, this branch might be named `main` or `master`.) Set the
values for this branch to match the settings you used for the `1.*` rule.
Your rules are now in place, even though no `1.*` branches exist yet:
diff --git a/doc/user/project/code_intelligence.md b/doc/user/project/code_intelligence.md
index 7a4e4090cd6..a7f1aff9b02 100644
--- a/doc/user/project/code_intelligence.md
+++ b/doc/user/project/code_intelligence.md
@@ -40,7 +40,7 @@ code_navigation:
lsif: dump.lsif
```
-The generated LSIF file size may be limited by
+The generated LSIF file size might be limited by
the [artifact application limits (`ci_max_artifact_size_lsif`)](../../administration/instance_limits.md#maximum-file-size-per-type-of-artifact),
default to 100 MB (configurable by an instance administrator).
diff --git a/doc/user/project/merge_requests/ai_in_merge_requests.md b/doc/user/project/merge_requests/ai_in_merge_requests.md
index 2380df0b9fc..77072392692 100644
--- a/doc/user/project/merge_requests/ai_in_merge_requests.md
+++ b/doc/user/project/merge_requests/ai_in_merge_requests.md
@@ -80,7 +80,7 @@ Provide feedback on this experimental feature in [issue 408991](https://gitlab.c
This feature is an [Experiment](../../../policy/experiment-beta-support.md) on GitLab.com.
-When preparing to merge your merge request you may wish to edit the proposed squash or merge commit message.
+When preparing to merge your merge request you might wish to edit the proposed squash or merge commit message.
To generate a commit message with GitLab Duo:
diff --git a/doc/user/project/merge_requests/authorization_for_merge_requests.md b/doc/user/project/merge_requests/authorization_for_merge_requests.md
index 657a0582967..f0f2d3777f1 100644
--- a/doc/user/project/merge_requests/authorization_for_merge_requests.md
+++ b/doc/user/project/merge_requests/authorization_for_merge_requests.md
@@ -63,7 +63,7 @@ forks.
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
+important to describe those, too. Think of things that might go wrong and include them here.
This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask.
diff --git a/doc/user/project/merge_requests/changes.md b/doc/user/project/merge_requests/changes.md
index a091649482e..513010b01e2 100644
--- a/doc/user/project/merge_requests/changes.md
+++ b/doc/user/project/merge_requests/changes.md
@@ -84,7 +84,7 @@ The changes are displayed after the original text.
## Compare changes side-by-side
-Depending on the length of the changes in your merge request, you may find it
+Depending on the length of the changes in your merge request, you might find it
easier to view the changes inline, or side-by-side:
1. On the left sidebar, select **Search or go to** and find your project.
diff --git a/doc/user/project/merge_requests/commit_templates.md b/doc/user/project/merge_requests/commit_templates.md
index 2659230fb57..2f4dae5178a 100644
--- a/doc/user/project/merge_requests/commit_templates.md
+++ b/doc/user/project/merge_requests/commit_templates.md
@@ -36,7 +36,7 @@ To do this:
1. For your desired commit type, enter your default message. You can use both static
text and [variables](#supported-variables-in-commit-templates). Each template
is limited to a maximum of 500 characters, though after replacing the templates
- with data, the final message may be longer.
+ with data, the final message might be longer.
1. Select **Save changes**.
## Default template for merge commits
diff --git a/doc/user/project/merge_requests/confidential.md b/doc/user/project/merge_requests/confidential.md
index 4554fbec5ff..72fa836e60c 100644
--- a/doc/user/project/merge_requests/confidential.md
+++ b/doc/user/project/merge_requests/confidential.md
@@ -33,8 +33,8 @@ permissions in your downstream private fork without action by you. These users c
immediately push code to branches in your private fork to help fix the confidential issue.
WARNING:
-Your private fork may expose confidential information, if you create it in a different
-namespace than the upstream repository. The two namespaces may not contain the same users.
+Your private fork might expose confidential information, if you create it in a different
+namespace than the upstream repository. The two namespaces might not contain the same users.
Prerequisites:
diff --git a/doc/user/project/merge_requests/conflicts.md b/doc/user/project/merge_requests/conflicts.md
index 93b1ca16732..d61753c3b40 100644
--- a/doc/user/project/merge_requests/conflicts.md
+++ b/doc/user/project/merge_requests/conflicts.md
@@ -168,7 +168,7 @@ merge commit. Verify it contains no unintended changes and doesn't break your bu
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
+important to describe those, too. Think of things that might go wrong and include them here.
This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask.
diff --git a/doc/user/project/merge_requests/creating_merge_requests.md b/doc/user/project/merge_requests/creating_merge_requests.md
index 723bda0e02c..26cbc4c5d8b 100644
--- a/doc/user/project/merge_requests/creating_merge_requests.md
+++ b/doc/user/project/merge_requests/creating_merge_requests.md
@@ -26,7 +26,7 @@ You can create a merge request from the list of merge requests.
1. Fill out the fields and select **Create merge request**.
NOTE:
-Merge requests are designed around a one-to-one (1:1) branch relationship. Only one open merge request may
+Merge requests are designed around a one-to-one (1:1) branch relationship. Only one open merge request can
be associated with a given target branch at a time.
## From an issue
diff --git a/doc/user/project/merge_requests/drafts.md b/doc/user/project/merge_requests/drafts.md
index ec9e5bb3f4f..67d24e72fed 100644
--- a/doc/user/project/merge_requests/drafts.md
+++ b/doc/user/project/merge_requests/drafts.md
@@ -78,7 +78,7 @@ if you want to run [merged results pipelines](../../../ci/pipelines/merged_resul
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
+important to describe those, too. Think of things that might go wrong and include them here.
This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask.
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index 063b3a9ad95..3555d9ffa01 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -462,7 +462,7 @@ merge request to display an incorrect message: `merged into <branch-name>`.
### Close a merge request from the Rails console **(FREE SELF)**
-If closing a merge request doesn't work through the UI or API, you may want to attempt to close it in a [Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
+If closing a merge request doesn't work through the UI or API, you might want to attempt to close it in a [Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
WARNING:
Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
@@ -476,7 +476,7 @@ MergeRequests::CloseService.new(project: p, current_user: u).execute(m)
### Delete a merge request from the Rails console **(FREE SELF)**
-If deleting a merge request doesn't work through the UI or API, you may want to attempt to delete it in a [Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
+If deleting a merge request doesn't work through the UI or API, you might want to attempt to delete it in a [Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
WARNING:
Any command that changes data directly could be damaging if not run correctly,
diff --git a/doc/user/project/merge_requests/revert_changes.md b/doc/user/project/merge_requests/revert_changes.md
index 22a6874156c..07523b9f34c 100644
--- a/doc/user/project/merge_requests/revert_changes.md
+++ b/doc/user/project/merge_requests/revert_changes.md
@@ -92,7 +92,7 @@ you must revert the commit from the command line:
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
+important to describe those, too. Think of things that might go wrong and include them here.
This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask.
diff --git a/doc/user/project/merge_requests/versions.md b/doc/user/project/merge_requests/versions.md
index 877f7bb77a8..62cee897b49 100644
--- a/doc/user/project/merge_requests/versions.md
+++ b/doc/user/project/merge_requests/versions.md
@@ -63,7 +63,7 @@ For more information, see how to [show or filter system notes on a merge request
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
+important to describe those, too. Think of things that might go wrong and include them here.
This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask.
diff --git a/doc/user/search/advanced_search.md b/doc/user/search/advanced_search.md
index bbc8838b640..3b715fb13da 100644
--- a/doc/user/search/advanced_search.md
+++ b/doc/user/search/advanced_search.md
@@ -33,6 +33,7 @@ You can use advanced search in:
- On GitLab.com, advanced search is enabled for groups with paid subscriptions.
- For self-managed GitLab instances, an administrator must
[enable advanced search](../../integration/advanced_search/elasticsearch.md#enable-advanced-search).
+- For GitLab Dedicated, advanced search is enabled.
## Syntax
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index 5fcafcba829..7ea4b460640 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -13,7 +13,7 @@ module Gitlab
ALLOWED_WHEN = %w[on_success on_failure always manual delayed].freeze
ALLOWED_KEYS = %i[tags script image services start_in artifacts
cache dependencies before_script after_script hooks
- coverage retry parallel interruptible timeout
+ coverage retry parallel timeout
release id_tokens publish pages].freeze
validations do
@@ -83,10 +83,6 @@ module Gitlab
description: 'Services that will be used to execute this job.',
inherit: true
- entry :interruptible, ::Gitlab::Config::Entry::Boolean,
- description: 'Set jobs interruptible value.',
- inherit: true
-
entry :timeout, Entry::Timeout,
description: 'Timeout duration of this job.',
inherit: true
@@ -139,7 +135,7 @@ module Gitlab
attributes :script, :tags, :when, :dependencies,
:needs, :retry, :parallel, :start_in,
- :interruptible, :timeout, :release,
+ :timeout, :release,
:allow_failure, :publish, :pages
def self.matching?(name, config)
@@ -169,7 +165,6 @@ module Gitlab
coverage: coverage_defined? ? coverage_value : nil,
retry: retry_defined? ? retry_value : nil,
parallel: has_parallel? ? parallel_value : nil,
- interruptible: interruptible_defined? ? interruptible_value : nil,
timeout: parsed_timeout,
artifacts: artifacts_value,
release: release_value,
diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb
index d0e9a9afc51..0b322fd433c 100644
--- a/lib/gitlab/ci/config/entry/processable.rb
+++ b/lib/gitlab/ci/config/entry/processable.rb
@@ -15,7 +15,8 @@ module Gitlab
include ::Gitlab::Config::Entry::Inheritable
PROCESSABLE_ALLOWED_KEYS = %i[extends stage only except rules variables
- inherit allow_failure when needs resource_group environment].freeze
+ inherit allow_failure when needs resource_group environment
+ interruptible].freeze
MAX_NESTING_LEVEL = 10
included do
@@ -74,6 +75,10 @@ module Gitlab
description: 'Environment configuration for this job.',
inherit: false
+ entry :interruptible, ::Gitlab::Config::Entry::Boolean,
+ description: 'Set jobs interruptible value.',
+ inherit: true
+
attributes :extends, :rules, :resource_group
end
@@ -133,7 +138,8 @@ module Gitlab
except: except_value,
environment: environment_defined? ? environment_value : nil,
environment_name: environment_defined? ? environment_value[:name] : nil,
- resource_group: resource_group }.compact
+ resource_group: resource_group,
+ interruptible: interruptible_defined? ? interruptible_value : nil }.compact
end
def root_variables_inheritance
diff --git a/package.json b/package.json
index 87b1039c909..d881bfaf808 100644
--- a/package.json
+++ b/package.json
@@ -124,7 +124,7 @@
"clipboard": "^2.0.8",
"compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1",
- "core-js": "^3.33.3",
+ "core-js": "^3.34.0",
"cron-validator": "^1.1.1",
"cronstrue": "^1.122.0",
"cropperjs": "^1.6.1",
diff --git a/qa/qa/page/group/settings/package_registries.rb b/qa/qa/page/group/settings/package_registries.rb
index bcf51f0f223..76f50809d83 100644
--- a/qa/qa/page/group/settings/package_registries.rb
+++ b/qa/qa/page/group/settings/package_registries.rb
@@ -7,23 +7,23 @@ module QA
include ::QA::Page::Settings::Common
view 'app/assets/javascripts/packages_and_registries/settings/group/components/packages_settings.vue' do
- element :package_registry_settings_content
- element :allow_duplicates_toggle
+ element 'package-registry-settings-content'
+ element 'maven-settings'
end
view 'app/assets/javascripts/packages_and_registries/settings/group/components/dependency_proxy_settings.vue' do
- element :dependency_proxy_settings_content
- element :dependency_proxy_setting_toggle
+ element 'dependency-proxy-settings-content'
+ element 'dependency-proxy-setting-toggle'
end
def set_allow_duplicates_disabled
- within_element :package_registry_settings_content do
+ within_element 'package-registry-settings-content' do
click_on_allow_duplicates_button if duplicates_enabled?
end
end
def set_allow_duplicates_enabled
- within_element :package_registry_settings_content do
+ within_element 'package-registry-settings-content' do
click_on_allow_duplicates_button unless duplicates_enabled?
end
end
@@ -41,15 +41,15 @@ module QA
end
def with_allow_duplicates_button
- within_element :allow_duplicates_toggle do
+ within_element 'maven-settings' do
toggle = find('button.gl-toggle:not(.is-disabled)')
yield(toggle)
end
end
def has_dependency_proxy_enabled?
- within_element :dependency_proxy_settings_content do
- within_element :dependency_proxy_setting_toggle do
+ within_element 'dependency-proxy-settings-content' do
+ within_element 'dependency-proxy-setting-toggle' do
toggle = find('button.gl-toggle')
toggle[:class].include?('is-checked')
end
diff --git a/qa/qa/page/project/fork/new.rb b/qa/qa/page/project/fork/new.rb
index 2b36766d996..9118aefc36c 100644
--- a/qa/qa/page/project/fork/new.rb
+++ b/qa/qa/page/project/fork/new.rb
@@ -8,28 +8,28 @@ module QA
include ::QA::Page::Component::Dropdown
view 'app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue' do
- element :fork_project_button
- element :fork_privacy_button
+ element 'fork-project-button'
+ element 'fork-privacy-button'
end
view 'app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue' do
- element :select_namespace_dropdown
+ element 'select-namespace-dropdown'
end
def fork_project(namespace = Runtime::Namespace.path)
choose_namespace(namespace)
- click_element(:fork_privacy_button, privacy_level: 'public')
- click_element(:fork_project_button)
+ click_element('fork-privacy-button', privacy_level: 'public')
+ click_element('fork-project-button')
end
def get_list_of_namespaces
- click_element(:select_namespace_dropdown)
+ click_element('select-namespace-dropdown')
all_items
end
def choose_namespace(namespace)
retry_on_exception do
- click_element(:select_namespace_dropdown)
+ click_element('select-namespace-dropdown')
search_and_select(namespace)
end
end
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 18415a6079f..6662e83b564 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -637,11 +637,5 @@ FactoryBot.define do
build.build_runner_session(url: 'https://gitlab.example.com')
end
end
-
- trait :interruptible do
- after(:build) do |build|
- build.metadata.interruptible = true
- end
- end
end
end
diff --git a/spec/factories/ci/processable.rb b/spec/factories/ci/processable.rb
index 49756433713..c84a2d5d93d 100644
--- a/spec/factories/ci/processable.rb
+++ b/spec/factories/ci/processable.rb
@@ -11,6 +11,10 @@ FactoryBot.define do
scheduling_type { 'stage' }
partition_id { pipeline.partition_id }
+ options do
+ {}
+ end
+
# This factory was updated to help with the efforts of the removal of `ci_builds.stage`:
# https://gitlab.com/gitlab-org/gitlab/-/issues/364377
# These additions can be removed once the specs that use the stage attribute have been updated
@@ -52,5 +56,11 @@ FactoryBot.define do
processable.resource_group = create(:ci_resource_group, project: processable.project)
end
end
+
+ trait :interruptible do
+ after(:build) do |processable|
+ processable.metadata.interruptible = true
+ end
+ end
end
end
diff --git a/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js b/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js
index 9e55716cc30..463455573ee 100644
--- a/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js
+++ b/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js
@@ -10,7 +10,7 @@ describe('Signup Form', () => {
helpText: 'some help text',
label: 'a label',
value: true,
- dataQaSelector: 'qa_selector',
+ dataTestId: 'test-id',
};
const mountComponent = () => {
@@ -55,7 +55,7 @@ describe('Signup Form', () => {
});
it('gets passed data qa selector', () => {
- expect(findCheckbox().attributes('data-qa-selector')).toBe(props.dataQaSelector);
+ expect(findCheckbox().attributes('data-testid')).toBe(props.dataTestId);
});
});
});
diff --git a/spec/frontend/ci/job_details/components/log/log_spec.js b/spec/frontend/ci/job_details/components/log/log_spec.js
index 8cc28fe4045..f3877d70457 100644
--- a/spec/frontend/ci/job_details/components/log/log_spec.js
+++ b/spec/frontend/ci/job_details/components/log/log_spec.js
@@ -10,6 +10,8 @@ import LineNumber from '~/ci/job_details/components/log/line_number.vue';
import { logLinesParser } from '~/ci/job_details/store/utils';
import { mockJobLog, mockJobLogLineCount } from './mock_data';
+const mockPagePath = 'project/-/jobs/99';
+
jest.mock('~/lib/utils/common_utils', () => ({
...jest.requireActual('~/lib/utils/common_utils'),
scrollToElement: jest.fn(),
@@ -28,6 +30,9 @@ describe('Job Log', () => {
store = new Vuex.Store({ actions, state });
wrapper = mount(Log, {
+ provide: {
+ pagePath: mockPagePath,
+ },
propsData: {
...props,
},
@@ -46,25 +51,25 @@ describe('Job Log', () => {
state = {
jobLog: lines,
jobLogSections: sections,
- jobLogEndpoint: 'jobs/id',
};
});
- const findLineNumbers = () => wrapper.findAllComponents(LineNumber).wrappers.map((w) => w.text());
+ const findLineNumbers = () => wrapper.findAllComponents(LineNumber);
const findLineHeader = () => wrapper.findComponent(LogLineHeader);
- const findAllLineHeaders = () => wrapper.findAllComponents(LogLineHeader);
+ const findLineHeaders = () => wrapper.findAllComponents(LogLineHeader);
describe('line numbers', () => {
beforeEach(() => {
createComponent();
});
- it('renders a line number for each line %d', () => {
- const expectLineNumbers = Array(mockJobLogLineCount)
- .fill()
- .map((_, i) => `${i + 1}`);
+ it('renders a line number for each line %d with an href', () => {
+ for (let i = 0; i < mockJobLogLineCount; i += 1) {
+ const w = findLineNumbers().at(i);
- expect(findLineNumbers()).toEqual(expectLineNumbers);
+ expect(w.text()).toBe(`${i + 1}`);
+ expect(w.attributes('href')).toBe(`${mockPagePath}#L${i + 1}`);
+ }
});
});
@@ -112,7 +117,7 @@ describe('Job Log', () => {
});
it('hides lines in section', () => {
- expect(findLineNumbers()).toEqual([
+ expect(findLineNumbers().wrappers.map((w) => w.text())).toEqual([
'1',
'2',
'3',
@@ -185,8 +190,8 @@ describe('Job Log', () => {
createComponent({ searchResults: mockSearchResults });
- expect(findAllLineHeaders().at(0).props('isHighlighted')).toBe(true);
- expect(findAllLineHeaders().at(1).props('isHighlighted')).toBe(false);
+ expect(findLineHeaders().at(0).props('isHighlighted')).toBe(true);
+ expect(findLineHeaders().at(1).props('isHighlighted')).toBe(false);
});
});
});
diff --git a/spec/frontend/ci/job_details/job_app_spec.js b/spec/frontend/ci/job_details/job_app_spec.js
index 2bd0429ef56..8601850a403 100644
--- a/spec/frontend/ci/job_details/job_app_spec.js
+++ b/spec/frontend/ci/job_details/job_app_spec.js
@@ -4,7 +4,6 @@ import Vuex from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { TEST_HOST } from 'helpers/test_constants';
import EmptyState from '~/ci/job_details/components/empty_state.vue';
import EnvironmentsBlock from '~/ci/job_details/components/environments_block.vue';
import ErasedBlock from '~/ci/job_details/components/erased_block.vue';
@@ -29,8 +28,9 @@ describe('Job App', () => {
let mock;
const initSettings = {
- endpoint: `${TEST_HOST}jobs/123.json`,
- pagePath: `${TEST_HOST}jobs/123`,
+ jobEndpoint: '/group1/project1/-/jobs/99.json',
+ logEndpoint: '/group1/project1/-/jobs/99/trace',
+ testReportSummaryUrl: '/group1/project1/-/jobs/99/test_report_summary.json',
};
const props = {
@@ -50,8 +50,8 @@ describe('Job App', () => {
};
const setupAndMount = async ({ jobData = {}, jobLogData = {} } = {}) => {
- mock.onGet(initSettings.endpoint).replyOnce(HTTP_STATUS_OK, { ...job, ...jobData });
- mock.onGet(`${initSettings.pagePath}/trace.json`).reply(HTTP_STATUS_OK, jobLogData);
+ mock.onGet(initSettings.jobEndpoint).replyOnce(HTTP_STATUS_OK, { ...job, ...jobData });
+ mock.onGet(initSettings.logEndpoint).reply(HTTP_STATUS_OK, jobLogData);
const asyncInit = store.dispatch('init', initSettings);
diff --git a/spec/frontend/ci/job_details/store/actions_spec.js b/spec/frontend/ci/job_details/store/actions_spec.js
index 43db1885b1f..15e4b80a3ff 100644
--- a/spec/frontend/ci/job_details/store/actions_spec.js
+++ b/spec/frontend/ci/job_details/store/actions_spec.js
@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper';
import {
- setJobLogOptions,
+ init,
clearEtagPoll,
stopPolling,
requestJob,
@@ -37,6 +37,9 @@ import { testSummaryData } from 'jest/ci/jobs_mock_data';
jest.mock('~/lib/utils/scroll_utils');
+const mockJobEndpoint = '/group1/project1/-/jobs/99.json';
+const mockLogEndpoint = '/group1/project1/-/jobs/99/trace';
+
describe('Job State actions', () => {
let mockedState;
@@ -44,22 +47,27 @@ describe('Job State actions', () => {
mockedState = state();
});
- describe('setJobLogOptions', () => {
+ describe('init', () => {
it('should commit SET_JOB_LOG_OPTIONS mutation', () => {
return testAction(
- setJobLogOptions,
- { endpoint: '/group1/project1/-/jobs/99.json', pagePath: '/group1/project1/-/jobs/99' },
+ init,
+ {
+ jobEndpoint: mockJobEndpoint,
+ logEndpoint: mockLogEndpoint,
+ testReportSummaryUrl: '/group1/project1/-/jobs/99/test_report_summary.json',
+ },
mockedState,
[
{
type: types.SET_JOB_LOG_OPTIONS,
payload: {
- endpoint: '/group1/project1/-/jobs/99.json',
- pagePath: '/group1/project1/-/jobs/99',
+ jobEndpoint: mockJobEndpoint,
+ logEndpoint: mockLogEndpoint,
+ testReportSummaryUrl: '/group1/project1/-/jobs/99/test_report_summary.json',
},
},
],
- [],
+ [{ type: 'fetchJob' }],
);
});
});
@@ -102,7 +110,7 @@ describe('Job State actions', () => {
let mock;
beforeEach(() => {
- mockedState.jobEndpoint = `${TEST_HOST}/endpoint.json`;
+ mockedState.jobEndpoint = mockJobEndpoint;
mock = new MockAdapter(axios);
});
@@ -114,9 +122,7 @@ describe('Job State actions', () => {
describe('success', () => {
it('dispatches requestJob and receiveJobSuccess', () => {
- mock
- .onGet(`${TEST_HOST}/endpoint.json`)
- .replyOnce(HTTP_STATUS_OK, { id: 121212, name: 'karma' });
+ mock.onGet(mockJobEndpoint).replyOnce(HTTP_STATUS_OK, { id: 121212, name: 'karma' });
return testAction(
fetchJob,
@@ -206,7 +212,7 @@ describe('Job State actions', () => {
let mock;
beforeEach(() => {
- mockedState.jobLogEndpoint = `${TEST_HOST}/endpoint`;
+ mockedState.logEndpoint = mockLogEndpoint;
mock = new MockAdapter(axios);
});
@@ -230,7 +236,7 @@ describe('Job State actions', () => {
complete: true,
};
- mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, jobLogPayload);
+ mock.onGet(mockLogEndpoint).replyOnce(HTTP_STATUS_OK, jobLogPayload);
});
it('commits RECEIVE_JOB_LOG_SUCCESS, dispatches stopPollingJobLog and requestTestSummary', () => {
@@ -256,7 +262,7 @@ describe('Job State actions', () => {
complete: false,
};
- mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, jobLogPayload);
+ mock.onGet(mockLogEndpoint).replyOnce(HTTP_STATUS_OK, jobLogPayload);
});
it('dispatches startPollingJobLog', () => {
@@ -301,7 +307,7 @@ describe('Job State actions', () => {
complete: true,
};
- mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, jobLogPayload);
+ mock.onGet(mockLogEndpoint).replyOnce(HTTP_STATUS_OK, jobLogPayload);
});
it('should auto scroll to bottom by dispatching scrollBottom', () => {
@@ -327,7 +333,7 @@ describe('Job State actions', () => {
describe('server error', () => {
beforeEach(() => {
- mock.onGet(`${TEST_HOST}/endpoint/trace.json`).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ mock.onGet(mockLogEndpoint).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
});
it('dispatches requestJobLog and receiveJobLogError', () => {
@@ -347,7 +353,7 @@ describe('Job State actions', () => {
describe('unexpected error', () => {
beforeEach(() => {
- mock.onGet(`${TEST_HOST}/endpoint/trace.json`).reply(() => {
+ mock.onGet(mockLogEndpoint).reply(() => {
throw new Error('an error');
});
});
diff --git a/spec/frontend/ci/job_details/store/mutations_spec.js b/spec/frontend/ci/job_details/store/mutations_spec.js
index 87387fe9272..8ebf36bc0a0 100644
--- a/spec/frontend/ci/job_details/store/mutations_spec.js
+++ b/spec/frontend/ci/job_details/store/mutations_spec.js
@@ -16,13 +16,15 @@ describe('Jobs Store Mutations', () => {
describe('SET_JOB_LOG_OPTIONS', () => {
it('should set jobEndpoint', () => {
mutations[types.SET_JOB_LOG_OPTIONS](stateCopy, {
- endpoint: '/group1/project1/-/jobs/99.json',
- pagePath: '/group1/project1/-/jobs/99',
+ jobEndpoint: '/group1/project1/-/jobs/99.json',
+ logEndpoint: '/group1/project1/-/jobs/99/trace',
+ testReportSummaryUrl: '/group1/project1/-/jobs/99/test_report_summary.json',
});
expect(stateCopy).toMatchObject({
- jobLogEndpoint: '/group1/project1/-/jobs/99',
jobEndpoint: '/group1/project1/-/jobs/99.json',
+ logEndpoint: '/group1/project1/-/jobs/99/trace',
+ testReportSummaryUrl: '/group1/project1/-/jobs/99/test_report_summary.json',
});
});
});
diff --git a/spec/frontend/diffs/components/diff_file_spec.js b/spec/frontend/diffs/components/diff_file_spec.js
index 34af3d72b04..90c42e6e5db 100644
--- a/spec/frontend/diffs/components/diff_file_spec.js
+++ b/spec/frontend/diffs/components/diff_file_spec.js
@@ -23,7 +23,7 @@ import eventHub from '~/diffs/event_hub';
import { diffViewerModes, diffViewerErrors } from '~/ide/constants';
import axios from '~/lib/utils/axios_utils';
-import { scrollToElement } from '~/lib/utils/common_utils';
+import { scrollToElement, isElementStuck } from '~/lib/utils/common_utils';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import createNotesStore from '~/notes/stores/modules';
import diffsModule from '~/diffs/store/modules';
@@ -429,6 +429,7 @@ describe('DiffFile', () => {
describe('scoll-to-top of file after collapse', () => {
beforeEach(() => {
jest.spyOn(wrapper.vm.$store, 'dispatch').mockImplementation(() => {});
+ isElementStuck.mockReturnValueOnce(true);
});
it("scrolls to the top when the file is open, the users initiates the collapse, and there's a content block to scroll to", async () => {
diff --git a/spec/helpers/ci/jobs_helper_spec.rb b/spec/helpers/ci/jobs_helper_spec.rb
index 315bda9b2c1..1394f536c72 100644
--- a/spec/helpers/ci/jobs_helper_spec.rb
+++ b/spec/helpers/ci/jobs_helper_spec.rb
@@ -19,14 +19,15 @@ RSpec.describe Ci::JobsHelper, feature_category: :continuous_integration do
it 'returns jobs data' do
expect(helper.jobs_data(project, job)).to include({
- "endpoint" => "/#{project.full_path}/-/jobs/#{job.id}.json",
+ "job_endpoint" => "/#{project.full_path}/-/jobs/#{job.id}.json",
+ "log_endpoint" => "/#{project.full_path}/-/jobs/#{job.id}/trace",
+ "test_report_summary_url" => "/#{project.full_path}/-/jobs/#{job.id}/test_report_summary.json",
"page_path" => "/#{project.full_path}/-/jobs/#{job.id}",
"project_path" => project.full_path,
"artifact_help_url" => "/help/user/gitlab_com/index.md#gitlab-cicd",
"deployment_help_url" => "/help/user/project/clusters/deploy_to_cluster.md#troubleshooting",
"runner_settings_url" => "/#{project.full_path}/-/runners#js-runners-settings",
"retry_outdated_job_docs_url" => "/help/ci/pipelines/settings#retry-outdated-jobs",
- "test_report_summary_url" => "/#{project.full_path}/-/jobs/#{job.id}/test_report_summary.json",
"pipeline_test_report_url" => "/#{project.full_path}/-/pipelines/#{job.pipeline.id}/test_report"
})
end
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
index 6e6b9d949c5..35f2a99ee87 100644
--- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
@@ -2,10 +2,11 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
+RSpec.describe Gitlab::Ci::Config::Entry::Bridge, feature_category: :continuous_integration do
subject(:entry) { described_class.new(config, name: :my_bridge) }
it_behaves_like 'with inheritable CI config' do
+ let(:config) { { trigger: 'some/project' } }
let(:inheritable_key) { 'default' }
let(:inheritable_class) { Gitlab::Ci::Config::Entry::Default }
@@ -13,9 +14,13 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
# that we know that we don't want to inherit
# as they do not have sense in context of Bridge
let(:ignored_inheritable_columns) do
- %i[before_script after_script hooks image services cache interruptible timeout
+ %i[before_script after_script hooks image services cache timeout
retry tags artifacts id_tokens]
end
+
+ before do
+ allow(entry).to receive_message_chain(:inherit_entry, :default_entry, :inherit?).and_return(true)
+ end
end
describe '.matching?' do
diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
index 44e2fdbac37..84a8fd827cb 100644
--- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
@@ -217,6 +217,15 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable, feature_category: :pipeli
end
end
end
+
+ context 'when interruptible is not a boolean' do
+ let(:config) { { interruptible: 123 } }
+
+ it 'returns error about wrong value type' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include "interruptible config should be a boolean value"
+ end
+ end
end
describe '#relevant?' do
@@ -462,6 +471,28 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable, feature_category: :pipeli
end
end
end
+
+ context 'with interruptible' do
+ context 'when interruptible is not defined' do
+ let(:config) { { script: 'ls' } }
+
+ it 'sets interruptible to nil' do
+ entry.compose!(deps)
+
+ expect(entry.value[:interruptible]).to be_nil
+ end
+ end
+
+ context 'when interruptible is defined' do
+ let(:config) { { script: 'ls', interruptible: true } }
+
+ it 'sets interruptible to the value' do
+ entry.compose!(deps)
+
+ expect(entry.value[:interruptible]).to eq(true)
+ end
+ end
+ end
end
context 'when composed' do
diff --git a/spec/lib/gitlab/ci/yaml_processor/test_cases/interruptible_spec.rb b/spec/lib/gitlab/ci/yaml_processor/test_cases/interruptible_spec.rb
new file mode 100644
index 00000000000..03ff7077969
--- /dev/null
+++ b/spec/lib/gitlab/ci/yaml_processor/test_cases/interruptible_spec.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+module Gitlab
+ module Ci
+ RSpec.describe YamlProcessor, feature_category: :pipeline_composition do
+ subject(:processor) { described_class.new(config, user: nil).execute }
+
+ let(:builds) { processor.builds }
+
+ context 'with interruptible' do
+ let(:default_config) { nil }
+
+ let(:config) do
+ <<~YAML
+ #{default_config}
+
+ build1:
+ script: rspec
+ interruptible: true
+
+ build2:
+ script: rspec
+ interruptible: false
+
+ build3:
+ script: rspec
+
+ bridge1:
+ trigger: some/project
+ interruptible: true
+
+ bridge2:
+ trigger: some/project
+ interruptible: false
+
+ bridge3:
+ trigger: some/project
+ YAML
+ end
+
+ it 'returns jobs with their interruptible value' do
+ expect(builds).to contain_exactly(
+ a_hash_including(name: 'build1', interruptible: true),
+ a_hash_including(name: 'build2', interruptible: false),
+ a_hash_including(name: 'build3').and(exclude(:interruptible)),
+ a_hash_including(name: 'bridge1', interruptible: true),
+ a_hash_including(name: 'bridge2', interruptible: false),
+ a_hash_including(name: 'bridge3').and(exclude(:interruptible))
+ )
+ end
+
+ context 'when default:interruptible is true' do
+ let(:default_config) do
+ <<~YAML
+ default:
+ interruptible: true
+ YAML
+ end
+
+ it 'returns jobs with their interruptible value' do
+ expect(builds).to contain_exactly(
+ a_hash_including(name: 'build1', interruptible: true),
+ a_hash_including(name: 'build2', interruptible: false),
+ a_hash_including(name: 'build3', interruptible: true),
+ a_hash_including(name: 'bridge1', interruptible: true),
+ a_hash_including(name: 'bridge2', interruptible: false),
+ a_hash_including(name: 'bridge3', interruptible: true)
+ )
+ end
+ end
+
+ context 'when default:interruptible is false' do
+ let(:default_config) do
+ <<~YAML
+ default:
+ interruptible: false
+ YAML
+ end
+
+ it 'returns jobs with their interruptible value' do
+ expect(builds).to contain_exactly(
+ a_hash_including(name: 'build1', interruptible: true),
+ a_hash_including(name: 'build2', interruptible: false),
+ a_hash_including(name: 'build3', interruptible: false),
+ a_hash_including(name: 'bridge1', interruptible: true),
+ a_hash_including(name: 'bridge2', interruptible: false),
+ a_hash_including(name: 'bridge3', interruptible: false)
+ )
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 511fd4b14f8..3ba62888b7c 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -123,55 +123,6 @@ module Gitlab
end
end
- describe 'interruptible entry' do
- describe 'interruptible job' do
- let(:config) do
- YAML.dump(rspec: { script: 'rspec', interruptible: true })
- end
-
- it { expect(rspec_build[:interruptible]).to be_truthy }
- end
-
- describe 'interruptible job with default value' do
- let(:config) do
- YAML.dump(rspec: { script: 'rspec' })
- end
-
- it { expect(rspec_build).not_to have_key(:interruptible) }
- end
-
- describe 'uninterruptible job' do
- let(:config) do
- YAML.dump(rspec: { script: 'rspec', interruptible: false })
- end
-
- it { expect(rspec_build[:interruptible]).to be_falsy }
- end
-
- it "returns interruptible when overridden for job" do
- config = YAML.dump({ default: { interruptible: true },
- rspec: { script: "rspec" } })
-
- config_processor = described_class.new(config).execute
- builds = config_processor.builds.select { |b| b[:stage] == "test" }
-
- expect(builds.size).to eq(1)
- expect(builds.first).to eq({
- stage: "test",
- stage_idx: 2,
- name: "rspec",
- only: { refs: %w[branches tags] },
- options: { script: ["rspec"] },
- interruptible: true,
- allow_failure: false,
- when: "on_success",
- job_variables: [],
- root_variables_inheritance: true,
- scheduling_type: :stage
- })
- end
- end
-
describe 'retry entry' do
context 'when retry count is specified' do
let(:config) do
diff --git a/spec/migrations/20231207194620_backfill_catalog_resources_visibility_level_spec.rb b/spec/migrations/20231207194620_backfill_catalog_resources_visibility_level_spec.rb
new file mode 100644
index 00000000000..9023aa705a1
--- /dev/null
+++ b/spec/migrations/20231207194620_backfill_catalog_resources_visibility_level_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe BackfillCatalogResourcesVisibilityLevel, feature_category: :pipeline_composition do
+ let(:namespace) { table(:namespaces).create!(name: 'name', path: 'path') }
+
+ let(:project) do
+ table(:projects).create!(
+ visibility_level: Gitlab::VisibilityLevel::INTERNAL,
+ namespace_id: namespace.id, project_namespace_id: namespace.id
+ )
+ end
+
+ let(:resource) { table(:catalog_resources).create!(project_id: project.id) }
+
+ describe '#up' do
+ it 'updates the visibility_level to match the project' do
+ expect(resource.visibility_level).to eq(0)
+
+ migrate!
+
+ expect(resource.reload.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
+ end
+ end
+end
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index 53ad3a3a698..ae8c5aea858 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -1039,8 +1039,9 @@ RSpec.describe Ci::Bridge, feature_category: :continuous_integration do
end
it 'creates the metadata record and assigns its partition' do
- # the factory doesn't use any metadatable setters by default
- # so the record will be initialized by the before_validation callback
+ # The record is initialized by the factory calling metadatable setters
+ bridge.metadata = nil
+
expect(bridge.metadata).to be_nil
expect(bridge.save!).to be_truthy
diff --git a/spec/models/ci/job_token/scope_spec.rb b/spec/models/ci/job_token/scope_spec.rb
index d41286f5a45..adb9f461f63 100644
--- a/spec/models/ci/job_token/scope_spec.rb
+++ b/spec/models/ci/job_token/scope_spec.rb
@@ -160,18 +160,6 @@ RSpec.describe Ci::JobToken::Scope, feature_category: :continuous_integration, f
with_them do
it { is_expected.to eq(result) }
end
-
- context "with FF restrict_ci_job_token_for_public_and_internal_projects disabled" do
- before do
- stub_feature_flags(restrict_ci_job_token_for_public_and_internal_projects: false)
- end
-
- let(:accessed_project) { unscoped_public_project }
-
- it "restricts public and internal outbound projects not in allowlist" do
- is_expected.to eq(false)
- end
- end
end
end
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index fda889ff422..c81cffeb871 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -2573,7 +2573,7 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do
RSpec.shared_examples 'CI_JOB_TOKEN enforces the expected permissions' do
with_them do
let(:current_user) { public_send(user_role) }
- let(:project) { public_send("#{project_visibility}_project") }
+ let(:project) { public_project }
let(:job) { build_stubbed(:ci_build, project: scope_project, user: current_user) }
let(:scope_project) do
@@ -2607,20 +2607,19 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do
end
end
- # Remove project_visibility on FF restrict_ci_job_token_for_public_and_internal_projects cleanup
- where(:project_visibility, :user_role, :external_user, :scope_project_type, :token_scope_enabled, :result) do
- :public | :reporter | false | :same | true | true
- :public | :reporter | true | :same | true | true
- :public | :reporter | false | :same | false | true
- :public | :reporter | false | :different | true | false
- :public | :reporter | true | :different | true | false
- :public | :reporter | false | :different | false | true
- :public | :guest | false | :same | true | true
- :public | :guest | true | :same | true | true
- :public | :guest | false | :same | false | true
- :public | :guest | false | :different | true | false
- :public | :guest | true | :different | true | false
- :public | :guest | false | :different | false | true
+ where(:user_role, :external_user, :scope_project_type, :token_scope_enabled, :result) do
+ :reporter | false | :same | true | true
+ :reporter | true | :same | true | true
+ :reporter | false | :same | false | true
+ :reporter | false | :different | true | false
+ :reporter | true | :different | true | false
+ :reporter | false | :different | false | true
+ :guest | false | :same | true | true
+ :guest | true | :same | true | true
+ :guest | false | :same | false | true
+ :guest | false | :different | true | false
+ :guest | true | :different | true | false
+ :guest | false | :different | false | true
end
include_examples "CI_JOB_TOKEN enforces the expected permissions"
@@ -2663,61 +2662,8 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do
permissions.each { |p| expect_disallowed(p) }
end
-
- context "with restrict_ci_job_token_for_public_and_internal_projects disabled" do
- before do
- stub_feature_flags(restrict_ci_job_token_for_public_and_internal_projects: false)
- end
-
- it 'allows all permissions for private' do
- project.project_feature.update!("#{feature}_access_level": ProjectFeature::PRIVATE)
-
- permissions.each { |p| expect_allowed(p) }
- end
- end
end
end
-
- context "with FF restrict_ci_job_token_for_public_and_internal_projects disabled" do
- before do
- stub_feature_flags(restrict_ci_job_token_for_public_and_internal_projects: false)
- end
-
- where(:project_visibility, :user_role, :external_user, :scope_project_type, :token_scope_enabled, :result) do
- :private | :reporter | false | :same | true | true
- :private | :reporter | false | :same | false | true
- :private | :reporter | false | :different | true | false
- :private | :reporter | false | :different | false | true
- :private | :guest | false | :same | true | true
- :private | :guest | false | :same | false | true
- :private | :guest | false | :different | true | false
- :private | :guest | false | :different | false | true
-
- :internal | :reporter | false | :same | true | true
- :internal | :reporter | true | :same | true | true
- :internal | :reporter | false | :same | false | true
- :internal | :reporter | false | :different | true | true
- :internal | :reporter | true | :different | true | false
- :internal | :reporter | false | :different | false | true
- :internal | :guest | false | :same | true | true
- :internal | :guest | true | :same | true | true
- :internal | :guest | false | :same | false | true
- :internal | :guest | false | :different | true | true
- :internal | :guest | true | :different | true | false
- :internal | :guest | false | :different | false | true
-
- :public | :reporter | false | :same | true | true
- :public | :reporter | false | :same | false | true
- :public | :reporter | false | :different | true | true
- :public | :reporter | false | :different | false | true
- :public | :guest | false | :same | true | true
- :public | :guest | false | :same | false | true
- :public | :guest | false | :different | true | true
- :public | :guest | false | :different | false | true
- end
-
- include_examples "CI_JOB_TOKEN enforces the expected permissions"
- end
end
describe 'container_image policies' do
diff --git a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
index a5dda1d13aa..0d83187f9e4 100644
--- a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
+++ b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
@@ -207,12 +207,12 @@ RSpec.describe Ci::PipelineCreation::CancelRedundantPipelinesService, feature_ca
it 'does not cancel any builds' do
expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
- expect(build_statuses(parent_pipeline)).to contain_exactly('running', 'running')
+ expect(build_statuses(parent_pipeline)).to contain_exactly('created', 'running', 'running')
execute
expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
- expect(build_statuses(parent_pipeline)).to contain_exactly('running', 'running')
+ expect(build_statuses(parent_pipeline)).to contain_exactly('created', 'running', 'running')
end
end
@@ -227,6 +227,25 @@ RSpec.describe Ci::PipelineCreation::CancelRedundantPipelinesService, feature_ca
end
end
+ context 'when there are trigger jobs' do
+ before do
+ create(:ci_bridge, :created, pipeline: prev_pipeline)
+ create(:ci_bridge, :running, pipeline: prev_pipeline)
+ create(:ci_bridge, :success, pipeline: prev_pipeline)
+ create(:ci_bridge, :interruptible, :created, pipeline: prev_pipeline)
+ create(:ci_bridge, :interruptible, :running, pipeline: prev_pipeline)
+ create(:ci_bridge, :interruptible, :success, pipeline: prev_pipeline)
+ end
+
+ it 'still cancels the pipeline because auto-cancel is not affected by non-interruptible started triggers' do
+ execute
+
+ expect(job_statuses(prev_pipeline)).to contain_exactly(
+ 'canceled', 'success', 'canceled', 'canceled', 'canceled', 'success', 'canceled', 'canceled', 'success')
+ expect(job_statuses(pipeline)).to contain_exactly('pending')
+ end
+ end
+
it 'does not cancel future pipelines' do
expect(prev_pipeline.id).to be < pipeline.id
expect(build_statuses(pipeline)).to contain_exactly('pending')
@@ -269,7 +288,8 @@ RSpec.describe Ci::PipelineCreation::CancelRedundantPipelinesService, feature_ca
private
- def build_statuses(pipeline)
- pipeline.builds.pluck(:status)
+ def job_statuses(pipeline)
+ pipeline.statuses.pluck(:status)
end
+ alias_method :build_statuses, :job_statuses
end
diff --git a/yarn.lock b/yarn.lock
index 61e2eafe0a0..9a95e529213 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4573,10 +4573,10 @@ core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
-core-js@^3.29.1, core-js@^3.33.3, core-js@^3.6.5:
- version "3.33.3"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.3.tgz#3c644a323f0f533a0d360e9191e37f7fc059088d"
- integrity sha512-lo0kOocUlLKmm6kv/FswQL8zbkH7mVsLJ/FULClOhv8WRVmKLVcs6XPNQAzstfeJTCHMyButEwG+z1kHxHoDZw==
+core-js@^3.29.1, core-js@^3.34.0, core-js@^3.6.5:
+ version "3.34.0"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.34.0.tgz#5705e6ad5982678612e96987d05b27c6c7c274a5"
+ integrity sha512-aDdvlDder8QmY91H88GzNi9EtQi2TjvQhpCX6B1v/dAZHU1AuLgHvRh54RiOerpEhEW46Tkf+vgAViB/CWC0ag==
core-util-is@~1.0.0:
version "1.0.3"