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>2022-10-18 15:09:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-18 15:09:21 +0300
commita300f4d5c7fdd5d557288ee526986e0adb683b35 (patch)
tree8fb18970393c8b4e3b9681262b0318db00f7ba51
parent7bbc9509dc0567d2a2d8314e99179aaad33ba361 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/cop/static_translation_definition.yml14
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum12
-rw-r--r--Gemfile.lock31
-rw-r--r--app/assets/javascripts/diffs/components/app.vue2
-rw-r--r--app/assets/javascripts/groups/components/overview_tabs.vue63
-rw-r--r--app/assets/javascripts/vue_shared/components/gitlab_version_check.vue25
-rw-r--r--app/graphql/mutations/ci/job/artifacts_destroy.rb21
-rw-r--r--app/models/application_setting.rb32
-rw-r--r--app/models/ci/job_token/scope.rb2
-rw-r--r--app/models/group_group_link.rb2
-rw-r--r--app/models/incident_management/timeline_event.rb5
-rw-r--r--app/models/incident_management/timeline_event_tag.rb20
-rw-r--r--app/models/incident_management/timeline_event_tag_link.rb11
-rw-r--r--app/models/jira_import_state.rb2
-rw-r--r--app/models/member.rb2
-rw-r--r--app/models/project.rb11
-rw-r--r--app/models/project_group_link.rb2
-rw-r--r--app/models/user.rb4
-rw-r--r--app/models/users/banned_user.rb2
-rw-r--r--app/services/ci/job_artifacts/delete_service.rb18
-rw-r--r--app/views/admin/application_settings/appearances/preview_sign_in.html.haml4
-rw-r--r--app/views/shared/issuable/_label_page_create.html.haml4
-rw-r--r--app/workers/ci/cancel_pipeline_worker.rb1
-rw-r--r--config/metrics/counts_28d/20210216184850_deploy_token_packages_total_unique_counts_monthly.yml7
-rw-r--r--config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml8
-rw-r--r--db/docs/incident_management_timeline_event_tag_links.yml9
-rw-r--r--db/docs/incident_management_timeline_event_tags.yml9
-rw-r--r--db/migrate/20221005072353_create_incident_management_timeline_event_tags.rb19
-rw-r--r--db/migrate/20221005094926_create_incident_management_timeline_event_tag_links.rb33
-rw-r--r--db/migrate/20221018081416_members_remove_member_namespace_id_not_null_constraint.rb15
-rw-r--r--db/schema_migrations/202210050723531
-rw-r--r--db/schema_migrations/202210050949261
-rw-r--r--db/schema_migrations/202210180814161
-rw-r--r--db/structure.sql62
-rw-r--r--lib/api/entities/ci/job_basic.rb2
-rw-r--r--lib/api/entities/project.rb2
-rw-r--r--lib/api/events.rb2
-rw-r--r--lib/api/helpers/events_helpers.rb2
-rw-r--r--lib/gitlab/database/gitlab_schemas.yml2
-rw-r--r--lib/gitlab/json.rb3
-rw-r--r--qa/Gemfile2
-rw-r--r--qa/Gemfile.lock4
-rw-r--r--qa/Rakefile4
-rw-r--r--qa/qa.rb17
-rw-r--r--qa/qa/scenario/test/instance.rb36
-rw-r--r--qa/qa/scenario/test/integration/github.rb20
-rw-r--r--qa/qa/specs/qa_deprecation_toolkit_env.rb30
-rw-r--r--qa/qa/specs/spec_helper.rb3
-rw-r--r--qa/qa/tools/ci/non_empty_suites.rb81
-rw-r--r--qa/qa/tools/delete_test_ssh_keys.rb2
-rw-r--r--qa/qa/tools/initialize_gitlab_auth.rb2
-rw-r--r--qa/spec/scenario/test/integration/github_spec.rb21
-rw-r--r--qa/spec/tools/ci/non_empty_suites_spec.rb4
-rw-r--r--spec/factories/incident_management/timeline_event_tag_links.rb8
-rw-r--r--spec/factories/incident_management/timeline_event_tags.rb8
-rw-r--r--spec/factories/projects.rb4
-rw-r--r--spec/frontend/diffs/components/app_spec.js24
-rw-r--r--spec/frontend/groups/components/overview_tabs_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/gitlab_version_check_spec.js18
-rw-r--r--spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb2
-rw-r--r--spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb6
-rw-r--r--spec/graphql/types/ci/job_token_scope_type_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml3
-rw-r--r--spec/lib/gitlab/json_spec.rb10
-rw-r--r--spec/models/ci/job_token/scope_spec.rb4
-rw-r--r--spec/models/incident_management/timeline_event_spec.rb6
-rw-r--r--spec/models/incident_management/timeline_event_tag_link_spec.rb10
-rw-r--r--spec/models/incident_management/timeline_event_tag_spec.rb28
-rw-r--r--spec/models/project_spec.rb25
-rw-r--r--spec/policies/project_policy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job/artifacts_destroy_spec.rb85
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb6
-rw-r--r--spec/services/ci/job_artifacts/delete_service_spec.rb27
-rw-r--r--spec/services/ci/job_token_scope/add_project_service_spec.rb2
-rw-r--r--spec/services/ci/job_token_scope/remove_project_service_spec.rb2
-rw-r--r--spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb10
80 files changed, 683 insertions, 319 deletions
diff --git a/.rubocop_todo/cop/static_translation_definition.yml b/.rubocop_todo/cop/static_translation_definition.yml
index 22f5070d07c..ecbee866a6c 100644
--- a/.rubocop_todo/cop/static_translation_definition.yml
+++ b/.rubocop_todo/cop/static_translation_definition.yml
@@ -1,20 +1,6 @@
---
Cop/StaticTranslationDefinition:
Exclude:
- - 'app/models/application_setting.rb'
- 'app/models/diff_viewer/image.rb'
- 'app/models/diff_viewer/rich.rb'
- 'app/models/diff_viewer/simple.rb'
- - 'app/models/group_group_link.rb'
- - 'app/models/jira_import_state.rb'
- - 'app/models/member.rb'
- - 'app/models/project.rb'
- - 'app/models/project_group_link.rb'
- - 'app/models/user.rb'
- - 'app/models/users/banned_user.rb'
- - 'ee/app/models/allowed_email_domain.rb'
- - 'ee/app/models/dast/site_profile_secret_variable.rb'
- - 'ee/app/models/group_merge_request_approval_setting.rb'
- - 'ee/app/models/incident_management/escalation_policy.rb'
- - 'ee/app/models/incident_management/escalation_rule.rb'
- - 'ee/app/models/vulnerabilities/read.rb'
diff --git a/Gemfile b/Gemfile
index a671cfebe8b..65ed6078dc5 100644
--- a/Gemfile
+++ b/Gemfile
@@ -424,7 +424,7 @@ group :development, :test do
gem 'sigdump', '~> 0.2.4', require: 'sigdump/setup'
- gem 'pact', '~> 1.12'
+ gem 'pact', '~> 1.63'
end
group :development, :test, :danger do
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 11f50976235..509fb46286c 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -141,6 +141,7 @@
{"name":"ethon","version":"0.15.0","platform":"ruby","checksum":"0809805a035bc10f54162ca99f15ded49e428e0488bcfe1c08c821e18261a74d"},
{"name":"excon","version":"0.90.0","platform":"ruby","checksum":"01beac0f20652b12de95aef931f72bcb82ffb009e1c34c42a5cf5df93f4070ae"},
{"name":"execjs","version":"2.8.1","platform":"ruby","checksum":"6d939919cfd81bcc4d6556f322c3995a70cfe4289ea0bd3b1f999b489c323088"},
+{"name":"expgen","version":"0.1.1","platform":"ruby","checksum":"4e6a0f65b210a201d6045debb3e62a24e33251a49f81a11b067d303a60d3a239"},
{"name":"expression_parser","version":"0.9.0","platform":"ruby","checksum":"2b56db3cffc48c3337f4f29f5bc2374c86e7ba29acb40269c74bb55af9f868a4"},
{"name":"extended-markdown-filter","version":"0.6.0","platform":"ruby","checksum":"46844b5740b1703a0e0674e31a17c83d1244a3198abb3aae51cad1eb152eb19e"},
{"name":"factory_bot","version":"6.2.0","platform":"ruby","checksum":"d181902cdda531cf6cef036001b3a700a7b5e04bac63976864530120b2ac7d13"},
@@ -398,9 +399,9 @@
{"name":"org-ruby","version":"0.9.12","platform":"ruby","checksum":"93cbec3a4470cb9dca6a4a98dc276a6434ea9d9e7bc2d42ea33c3aedd5d1c974"},
{"name":"orm_adapter","version":"0.5.0","platform":"ruby","checksum":"aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9"},
{"name":"os","version":"1.1.1","platform":"ruby","checksum":"3db1fbc14ab8ea99b69ed8e353c894613e1b35e665fffb90414996cf8989d489"},
-{"name":"pact","version":"1.59.0","platform":"ruby","checksum":"6272cea35e4ee809493fadcba9800d4a24c262ef0778a0d1ba5d9a9b3f61fc59"},
-{"name":"pact-mock_service","version":"3.6.2","platform":"ruby","checksum":"cc91229484ae428b6eb3a6673c178046cbf6610ee6536ca6cbac060b6071f547"},
-{"name":"pact-support","version":"1.15.1","platform":"ruby","checksum":"c364596fe9fe78c4f93028013262d5d97867a680fa6acc35dda946447cdf1d1f"},
+{"name":"pact","version":"1.63.0","platform":"ruby","checksum":"cc2991ed242bf182c6a4abadfd492b2923d09a9b3ed24578126cc056921cb151"},
+{"name":"pact-mock_service","version":"3.10.0","platform":"ruby","checksum":"898ec3b8d96f1934d15941c701ca7d5fef5ccff32022d9a196fb82073cd95e27"},
+{"name":"pact-support","version":"1.18.1","platform":"ruby","checksum":"4a25961c8b1c4132e433a8eaa838b1e6914c6d3aae48eee705b9860a5e8b0476"},
{"name":"parallel","version":"1.22.1","platform":"ruby","checksum":"ebdf1f0c51f182df38522f70ba770214940bef998cdb6e00f36492b29699761f"},
{"name":"parser","version":"3.1.2.1","platform":"ruby","checksum":"57e49821b52d5fe7baffaca44ed77e9754688c9bbc68443b5293a722fdb161e0"},
{"name":"parslet","version":"1.8.2","platform":"ruby","checksum":"08d1ab3721cd3f175bfbee8788b2ddff71f92038f2d69bd65454c22bb9fbd98a"},
@@ -438,7 +439,7 @@
{"name":"rack-oauth2","version":"1.21.3","platform":"ruby","checksum":"4e72a79dd6a866692e84422a552b27c38a5a1918ded06661e04910f2bbe676ba"},
{"name":"rack-protection","version":"2.2.2","platform":"ruby","checksum":"fd41414dbabbec274af0bdb1f72a48504449de4d979782c9af38cbb5dfff3299"},
{"name":"rack-proxy","version":"0.7.4","platform":"ruby","checksum":"a8bb373583d8a3165d8caf5af5fd7c32c9e8a91b983fbc531efa0e3d6617d2d4"},
-{"name":"rack-test","version":"1.1.0","platform":"ruby","checksum":"154161f40f162b1c009a655b7b0c5de3a3102cc6d7d2e94b64e1f46ace800866"},
+{"name":"rack-test","version":"2.0.2","platform":"ruby","checksum":"adadd0e957f63a34199a9fdf905a920a0b0a50795735095b4ac4bd3c13385466"},
{"name":"rack-timeout","version":"0.6.3","platform":"ruby","checksum":"1754892eacc124d405e7f1145731ec9b7421ebd1bee5d51ddc18b72c204d0ab3"},
{"name":"rails","version":"6.1.6.1","platform":"ruby","checksum":"17024921a3913fb341f584542b06adf6bb12977a8b92d5fce093c3996c963686"},
{"name":"rails-controller-testing","version":"1.0.5","platform":"ruby","checksum":"741448db59366073e86fc965ba403f881c636b79a2c39a48d0486f2607182e94"},
@@ -448,7 +449,6 @@
{"name":"railties","version":"6.1.6.1","platform":"ruby","checksum":"bafecdf2dcbe4ea44e1ab7081fd797aa87ae9bbcd0f3a4372b662a1b93949733"},
{"name":"rainbow","version":"3.1.1","platform":"ruby","checksum":"039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a"},
{"name":"rake","version":"13.0.6","platform":"ruby","checksum":"5ce4bf5037b4196c24ac62834d8db1ce175470391026bd9e557d669beeb19097"},
-{"name":"randexp","version":"0.1.7","platform":"ruby","checksum":"3026510ecf6a8e8642b9b96fa44bb41af6d24058023b7df77cf280f08e14e4c8"},
{"name":"rb-fsevent","version":"0.11.2","platform":"ruby","checksum":"43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe"},
{"name":"rb-inotify","version":"0.10.1","platform":"ruby","checksum":"050062d4f31d307cca52c3f6a7f4b946df8de25fc4bd373e1a5142e41034a7ca"},
{"name":"rbtrace","version":"0.4.14","platform":"ruby","checksum":"162bbf89cecabfc4f09c869b655f6f3a679c4870ebb7cbdcadf7393a81cc1769"},
@@ -586,7 +586,7 @@
{"name":"timecop","version":"0.9.1","platform":"ruby","checksum":"374b543f0961dbd487e96d09ac812d4fdfeb603ec705bbff241ba060d0a9f534"},
{"name":"timeliness","version":"0.3.10","platform":"ruby","checksum":"c357233ce19dc53148e8b29dfddde134689f18f52b32928e9dfe12ebcf4a773f"},
{"name":"timfel-krb5-auth","version":"0.8.3","platform":"ruby","checksum":"ab388c9d747fa3cd95baf2cc1c03253e372d8c680adcc543670f4f099854bb80"},
-{"name":"tins","version":"1.31.0","platform":"ruby","checksum":"20b5ea997dc046358fd05f15d39636bd7946798591b9c5741cc41f69853c7894"},
+{"name":"tins","version":"1.31.1","platform":"ruby","checksum":"51c4a347c25c630d310cbc2c040ffb84e266c8227f2ade881f1130ee4f9fbecf"},
{"name":"toml-rb","version":"2.0.1","platform":"ruby","checksum":"5016c6c77ac72bca5fe67c372722bdfdd4479a6fe1a1c4ff2a486e247849b274"},
{"name":"tomlrb","version":"1.3.0","platform":"ruby","checksum":"68666bf53fa70ba686a48a7435ce7e086f5227c58c4c993bd9792f4760f2a503"},
{"name":"tpm-key_attestation","version":"0.9.0","platform":"ruby","checksum":"e469ad9111a68dab4d04596e1c0621d7c877c2e3e247f765af3c04f1adf2b8cd"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 9d0d013037d..24e4c532f08 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -420,6 +420,8 @@ GEM
ffi (>= 1.15.0)
excon (0.90.0)
execjs (2.8.1)
+ expgen (0.1.1)
+ parslet
expression_parser (0.9.0)
extended-markdown-filter (0.6.0)
html-pipeline (~> 2.0)
@@ -999,29 +1001,29 @@ GEM
rubypants (~> 0.2)
orm_adapter (0.5.0)
os (1.1.1)
- pact (1.59.0)
+ pact (1.63.0)
pact-mock_service (~> 3.0, >= 3.3.1)
- pact-support (~> 1.15)
- rack-test (>= 0.6.3, < 2.0.0)
+ pact-support (~> 1.16, >= 1.16.9)
+ rack-test (>= 0.6.3, < 3.0.0)
rspec (~> 3.0)
term-ansicolor (~> 1.0)
thor (>= 0.20, < 2.0)
webrick (~> 1.3)
- pact-mock_service (3.6.2)
+ pact-mock_service (3.10.0)
filelock (~> 1.1)
find_a_port (~> 1.0.1)
json
- pact-support (~> 1.12, >= 1.12.0)
+ pact-support (~> 1.16, >= 1.16.4)
rack (~> 2.0)
rspec (>= 2.14)
term-ansicolor (~> 1.0)
thor (>= 0.19, < 2.0)
webrick (~> 1.3)
- pact-support (1.15.1)
- awesome_print (~> 1.1)
- randexp (~> 0.1.7)
- rspec (>= 2.14)
- term-ansicolor (~> 1.0)
+ pact-support (1.18.1)
+ awesome_print (~> 1.9)
+ diff-lcs (~> 1.4)
+ expgen (~> 0.1)
+ rainbow (~> 3.1.1)
parallel (1.22.1)
parser (3.1.2.1)
ast (~> 2.4.1)
@@ -1087,8 +1089,8 @@ GEM
rack
rack-proxy (0.7.4)
rack
- rack-test (1.1.0)
- rack (>= 1.0, < 3)
+ rack-test (2.0.2)
+ rack (>= 1.3)
rack-timeout (0.6.3)
rails (6.1.6.1)
actioncable (= 6.1.6.1)
@@ -1125,7 +1127,6 @@ GEM
thor (~> 1.0)
rainbow (3.1.1)
rake (13.0.6)
- randexp (0.1.7)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
@@ -1415,7 +1416,7 @@ GEM
timecop (0.9.1)
timeliness (0.3.10)
timfel-krb5-auth (0.8.3)
- tins (1.31.0)
+ tins (1.31.1)
sync
toml-rb (2.0.1)
citrus (~> 3.0, > 3.0)
@@ -1725,7 +1726,7 @@ DEPENDENCIES
omniauth_crowd (~> 2.4.0)!
openssl (= 2.2.1)
org-ruby (~> 0.9.12)
- pact (~> 1.12)
+ pact (~> 1.63)
parallel (~> 1.19)
parslet (~> 1.8)
peek (~> 1.1)
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 2c330d8c851..bc49464a560 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -472,7 +472,7 @@ export default {
fetchData(toggleTree = true) {
this.fetchDiffFilesMeta()
.then(({ real_size = 0 }) => {
- this.diffFilesLength = parseInt(real_size, 10);
+ this.diffFilesLength = parseInt(real_size, 10) || 0;
if (toggleTree) {
this.setTreeDisplay();
}
diff --git a/app/assets/javascripts/groups/components/overview_tabs.vue b/app/assets/javascripts/groups/components/overview_tabs.vue
index 84e992b6365..15a0c686548 100644
--- a/app/assets/javascripts/groups/components/overview_tabs.vue
+++ b/app/assets/javascripts/groups/components/overview_tabs.vue
@@ -19,34 +19,35 @@ export default {
components: { GlTabs, GlTab, GroupsApp, GlSearchBoxByType, GlSorting, GlSortingItem },
inject: ['endpoints', 'initialSort'],
data() {
+ const tabs = [
+ {
+ title: this.$options.i18n[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS],
+ key: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
+ renderEmptyState: true,
+ lazy: this.$route.name !== ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
+ service: new GroupsService(this.endpoints[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS]),
+ store: new GroupsStore({ showSchemaMarkup: true }),
+ },
+ {
+ title: this.$options.i18n[ACTIVE_TAB_SHARED],
+ key: ACTIVE_TAB_SHARED,
+ renderEmptyState: false,
+ lazy: this.$route.name !== ACTIVE_TAB_SHARED,
+ service: new GroupsService(this.endpoints[ACTIVE_TAB_SHARED]),
+ store: new GroupsStore(),
+ },
+ {
+ title: this.$options.i18n[ACTIVE_TAB_ARCHIVED],
+ key: ACTIVE_TAB_ARCHIVED,
+ renderEmptyState: false,
+ lazy: this.$route.name !== ACTIVE_TAB_ARCHIVED,
+ service: new GroupsService(this.endpoints[ACTIVE_TAB_ARCHIVED]),
+ store: new GroupsStore(),
+ },
+ ];
return {
- tabs: [
- {
- title: this.$options.i18n[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS],
- key: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
- renderEmptyState: true,
- lazy: false,
- service: new GroupsService(this.endpoints[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS]),
- store: new GroupsStore({ showSchemaMarkup: true }),
- },
- {
- title: this.$options.i18n[ACTIVE_TAB_SHARED],
- key: ACTIVE_TAB_SHARED,
- renderEmptyState: false,
- lazy: true,
- service: new GroupsService(this.endpoints[ACTIVE_TAB_SHARED]),
- store: new GroupsStore(),
- },
- {
- title: this.$options.i18n[ACTIVE_TAB_ARCHIVED],
- key: ACTIVE_TAB_ARCHIVED,
- renderEmptyState: false,
- lazy: true,
- service: new GroupsService(this.endpoints[ACTIVE_TAB_ARCHIVED]),
- store: new GroupsStore(),
- },
- ],
- activeTabIndex: 0,
+ tabs,
+ activeTabIndex: tabs.findIndex((tab) => tab.key === this.$route.name),
sort: SORTING_ITEM_NAME,
isAscending: true,
search: '',
@@ -75,14 +76,6 @@ export default {
) || SORTING_ITEM_NAME;
this.sort = sort;
this.isAscending = sort.asc === sortQueryStringValue;
-
- const activeTabIndex = this.tabs.findIndex((tab) => tab.key === this.$route.name);
-
- if (activeTabIndex === -1) {
- return;
- }
-
- this.activeTabIndex = activeTabIndex;
},
methods: {
handleTabInput(tabIndex) {
diff --git a/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue b/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue
index 25c4b01af44..c2be5e4f7a1 100644
--- a/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue
+++ b/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue
@@ -57,7 +57,7 @@ export default {
this.status = res.data.severity;
this.track('rendered_version_badge', {
- label: this.status,
+ label: this.title,
});
}
})
@@ -66,19 +66,24 @@ export default {
this.status = null;
});
},
+ onClick() {
+ this.track('click_version_badge', { label: this.title });
+ },
},
UPGRADE_DOCS_URL,
};
</script>
<template>
- <gl-badge
- v-if="status"
- :href="$options.UPGRADE_DOCS_URL"
- class="version-check-badge"
- :variant="status"
- :size="size"
- @click="track('click_version_badge', { label: status })"
- >{{ title }}</gl-badge
- >
+ <!-- TODO: remove the span element once bootstrap-vue is updated to version 2.21.1 -->
+ <!-- TODO: https://github.com/bootstrap-vue/bootstrap-vue/issues/6219 -->
+ <span v-if="status" data-testid="badge-click-wrapper" @click="onClick">
+ <gl-badge
+ :href="$options.UPGRADE_DOCS_URL"
+ class="version-check-badge"
+ :variant="status"
+ :size="size"
+ >{{ title }}</gl-badge
+ >
+ </span>
</template>
diff --git a/app/graphql/mutations/ci/job/artifacts_destroy.rb b/app/graphql/mutations/ci/job/artifacts_destroy.rb
index c27ab9c4d89..34c58fc1240 100644
--- a/app/graphql/mutations/ci/job/artifacts_destroy.rb
+++ b/app/graphql/mutations/ci/job/artifacts_destroy.rb
@@ -25,12 +25,21 @@ module Mutations
def resolve(id:)
job = authorized_find!(id: id)
- result = ::Ci::JobArtifacts::DestroyBatchService.new(job.job_artifacts, pick_up_at: Time.current).execute
- {
- job: job,
- destroyed_artifacts_count: result[:destroyed_artifacts_count],
- errors: Array(result[:errors])
- }
+ result = ::Ci::JobArtifacts::DeleteService.new(job).execute
+
+ if result.success?
+ {
+ job: job,
+ destroyed_artifacts_count: result.payload[:destroyed_artifacts_count],
+ errors: Array(result.payload[:errors])
+ }
+ else
+ {
+ job: job,
+ destroyed_artifacts_count: 0,
+ errors: Array(result.message)
+ }
+ end
end
end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index fa8951bf642..f83aa79b461 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -120,7 +120,7 @@ class ApplicationSetting < ApplicationRecord
if: :help_page_support_url_column_exists?
validates :help_page_documentation_base_url,
- length: { maximum: 255, message: _("is too long (maximum is %{count} characters)") },
+ length: { maximum: 255, message: N_("is too long (maximum is %{count} characters)") },
allow_blank: true,
addressable_url: true
@@ -148,7 +148,7 @@ class ApplicationSetting < ApplicationRecord
if: :akismet_enabled
validates :spam_check_api_key,
- length: { maximum: 2000, message: _('is too long (maximum is %{count} characters)') },
+ length: { maximum: 2000, message: N_('is too long (maximum is %{count} characters)') },
allow_blank: true
validates :unique_ips_limit_per_user,
@@ -228,7 +228,7 @@ class ApplicationSetting < ApplicationRecord
validates :default_artifacts_expire_in, presence: true, duration: true
validates :container_expiration_policies_enable_historic_entries,
- inclusion: { in: [true, false], message: _('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :container_registry_token_expire_delay,
presence: true,
@@ -320,8 +320,8 @@ class ApplicationSetting < ApplicationRecord
validates :personal_access_token_prefix,
format: { with: %r{\A[a-zA-Z0-9_+=/@:.-]+\z},
- message: _("can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'") },
- length: { maximum: 20, message: _('is too long (maximum is %{count} characters)') },
+ message: N_("can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'") },
+ length: { maximum: 20, message: N_('is too long (maximum is %{count} characters)') },
allow_blank: true
validates :commit_email_hostname, format: { with: /\A[^@]+\z/ }
@@ -369,7 +369,7 @@ class ApplicationSetting < ApplicationRecord
validates :email_restrictions, untrusted_regexp: true
- validates :hashed_storage_enabled, inclusion: { in: [true], message: _("Hashed storage can't be disabled anymore for new projects") }
+ validates :hashed_storage_enabled, inclusion: { in: [true], message: N_("Hashed storage can't be disabled anymore for new projects") }
validates :container_registry_delete_tags_service_timeout,
:container_registry_cleanup_tags_service_max_list_size,
@@ -377,7 +377,7 @@ class ApplicationSetting < ApplicationRecord
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :container_registry_expiration_policies_caching,
- inclusion: { in: [true, false], message: _('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :container_registry_import_max_tags_count,
:container_registry_import_max_retries,
@@ -404,11 +404,11 @@ class ApplicationSetting < ApplicationRecord
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :invisible_captcha_enabled,
- inclusion: { in: [true, false], message: _('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :invitation_flow_enforcement, :can_create_group,
allow_nil: false,
- inclusion: { in: [true, false], message: _('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
Gitlab::SSHPublicKey.supported_types.each do |type|
validates :"#{type}_key_restriction", presence: true, key_restriction: { type: type }
@@ -513,11 +513,11 @@ class ApplicationSetting < ApplicationRecord
rsa_key: true, allow_nil: true
validates :rate_limiting_response_text,
- length: { maximum: 255, message: _('is too long (maximum is %{count} characters)') },
+ length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
allow_blank: true
validates :jira_connect_application_key,
- length: { maximum: 255, message: _('is too long (maximum is %{count} characters)') },
+ length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
allow_blank: true
with_options(presence: true, numericality: { only_integer: true, greater_than: 0 }) do
@@ -561,7 +561,7 @@ class ApplicationSetting < ApplicationRecord
allow_nil: false
validates :admin_mode,
- inclusion: { in: [true, false], message: _('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :external_pipeline_validation_service_url,
addressable_url: true, allow_blank: true
@@ -574,7 +574,7 @@ class ApplicationSetting < ApplicationRecord
inclusion: { in: ApplicationSetting.whats_new_variants.keys }
validates :floc_enabled,
- inclusion: { in: [true, false], message: _('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
enum sidekiq_job_limiter_mode: {
Gitlab::SidekiqMiddleware::SizeLimiter::Validator::TRACK_MODE => 0,
@@ -589,7 +589,7 @@ class ApplicationSetting < ApplicationRecord
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :sentry_enabled,
- inclusion: { in: [true, false], message: _('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :sentry_dsn,
addressable_url: true, presence: true, length: { maximum: 255 },
if: :sentry_enabled?
@@ -601,7 +601,7 @@ class ApplicationSetting < ApplicationRecord
if: :sentry_enabled?
validates :error_tracking_enabled,
- inclusion: { in: [true, false], message: _('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
validates :error_tracking_api_url,
presence: true,
addressable_url: true,
@@ -670,7 +670,7 @@ class ApplicationSetting < ApplicationRecord
attr_encrypted :jitsu_administrator_password, encryption_options_base_32_aes_256_gcm
validates :disable_feed_token,
- inclusion: { in: [true, false], message: _('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }
before_validation :ensure_uuid!
before_validation :coerce_repository_storages_weighted, if: :repository_storages_weighted_changed?
diff --git a/app/models/ci/job_token/scope.rb b/app/models/ci/job_token/scope.rb
index 26a49d6a730..1aa49b95201 100644
--- a/app/models/ci/job_token/scope.rb
+++ b/app/models/ci/job_token/scope.rb
@@ -23,7 +23,7 @@ module Ci
def includes?(target_project)
# if the setting is disabled any project is considered to be in scope.
- return true unless source_project.ci_job_token_scope_enabled?
+ return true unless source_project.ci_outbound_job_token_scope_enabled?
target_project.id == source_project.id ||
Ci::JobToken::ProjectScopeLink.from_project(source_project).to_project(target_project).exists?
diff --git a/app/models/group_group_link.rb b/app/models/group_group_link.rb
index 7005c8593bd..15949570f9c 100644
--- a/app/models/group_group_link.rb
+++ b/app/models/group_group_link.rb
@@ -8,7 +8,7 @@ class GroupGroupLink < ApplicationRecord
validates :shared_group, presence: true
validates :shared_group_id, uniqueness: { scope: [:shared_with_group_id],
- message: _('The group has already been shared with this group') }
+ message: N_('The group has already been shared with this group') }
validates :shared_with_group, presence: true
validates :group_access, inclusion: { in: Gitlab::Access.all_values },
presence: true
diff --git a/app/models/incident_management/timeline_event.rb b/app/models/incident_management/timeline_event.rb
index de193308558..735d4e4298c 100644
--- a/app/models/incident_management/timeline_event.rb
+++ b/app/models/incident_management/timeline_event.rb
@@ -21,6 +21,11 @@ module IncidentManagement
validates :note, presence: true, length: { maximum: 10_000 }
validates :note_html, length: { maximum: 10_000 }
+ has_many :timeline_event_tag_links, class_name: 'IncidentManagement::TimelineEventTagLink'
+ has_many :timeline_event_tags,
+ class_name: 'IncidentManagement::TimelineEventTag',
+ through: :timeline_event_tag_links
+
scope :order_occurred_at_asc_id_asc, -> { reorder(occurred_at: :asc, id: :asc) }
end
end
diff --git a/app/models/incident_management/timeline_event_tag.rb b/app/models/incident_management/timeline_event_tag.rb
new file mode 100644
index 00000000000..cde3afcaa16
--- /dev/null
+++ b/app/models/incident_management/timeline_event_tag.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ class TimelineEventTag < ApplicationRecord
+ self.table_name = 'incident_management_timeline_event_tags'
+
+ belongs_to :project, inverse_of: :incident_management_timeline_event_tags
+
+ has_many :timeline_event_tag_links,
+ class_name: 'IncidentManagement::TimelineEventTagLink'
+
+ has_many :timeline_events,
+ class_name: 'IncidentManagement::TimelineEvent',
+ through: :timeline_event_tag_links
+
+ validates :name, presence: true, format: { with: /\A[^,]+\z/ }
+ validates :name, uniqueness: { scope: :project_id }
+ validates :name, length: { maximum: 255 }
+ end
+end
diff --git a/app/models/incident_management/timeline_event_tag_link.rb b/app/models/incident_management/timeline_event_tag_link.rb
new file mode 100644
index 00000000000..912339717a8
--- /dev/null
+++ b/app/models/incident_management/timeline_event_tag_link.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ class TimelineEventTagLink < ApplicationRecord
+ self.table_name = 'incident_management_timeline_event_tag_links'
+
+ belongs_to :timeline_event_tag, class_name: 'IncidentManagement::TimelineEventTag'
+
+ belongs_to :timeline_event, class_name: 'IncidentManagement::TimelineEvent'
+ end
+end
diff --git a/app/models/jira_import_state.rb b/app/models/jira_import_state.rb
index 76b5f1def6a..97d6cd00fb8 100644
--- a/app/models/jira_import_state.rb
+++ b/app/models/jira_import_state.rb
@@ -24,7 +24,7 @@ class JiraImportState < ApplicationRecord
validates :project, uniqueness: {
conditions: -> { where.not(status: STATUSES.values_at(:failed, :finished)) },
- message: _('Cannot have multiple Jira imports running at the same time')
+ message: N_('Cannot have multiple Jira imports running at the same time')
}
before_save :ensure_error_message_size
diff --git a/app/models/member.rb b/app/models/member.rb
index f23705816b6..ff1d8f18c25 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -55,7 +55,7 @@ class Member < ApplicationRecord
validate :signup_email_valid?, on: :create, if: ->(member) { member.invite_email.present? }
validates :user_id,
uniqueness: {
- message: _('project bots cannot be added to other groups / projects')
+ message: N_('project bots cannot be added to other groups / projects')
},
if: :project_bot?
validate :access_level_inclusion
diff --git a/app/models/project.rb b/app/models/project.rb
index a5589c71f73..7b61010ab01 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -262,6 +262,7 @@ class Project < ApplicationRecord
has_many :source_of_merge_requests, foreign_key: 'source_project_id', class_name: 'MergeRequest'
has_many :issues
has_many :incident_management_issuable_escalation_statuses, through: :issues, inverse_of: :project, class_name: 'IncidentManagement::IssuableEscalationStatus'
+ has_many :incident_management_timeline_event_tags, inverse_of: :project, class_name: 'IncidentManagement::TimelineEventTag'
has_many :labels, class_name: 'ProjectLabel'
has_many :integrations
has_many :events
@@ -476,7 +477,7 @@ class Project < ApplicationRecord
delegate :dashboard_timezone, to: :metrics_setting, allow_nil: true, prefix: true
delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
delegate :forward_deployment_enabled, :forward_deployment_enabled=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
- delegate :job_token_scope_enabled, :job_token_scope_enabled=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
+ delegate :job_token_scope_enabled, :job_token_scope_enabled=, to: :ci_cd_settings, prefix: :ci_outbound, allow_nil: true
delegate :inbound_job_token_scope_enabled, :inbound_job_token_scope_enabled=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
delegate :keep_latest_artifact, :keep_latest_artifact=, to: :ci_cd_settings, allow_nil: true
delegate :opt_in_jwt, :opt_in_jwt=, to: :ci_cd_settings, prefix: :ci, allow_nil: true
@@ -503,7 +504,7 @@ class Project < ApplicationRecord
validates :description, length: { maximum: 2000 }, allow_blank: true
validates :ci_config_path,
format: { without: %r{(\.{2}|\A/)},
- message: _('cannot include leading slash or directory traversal.') },
+ message: N_('cannot include leading slash or directory traversal.') },
length: { maximum: 255 },
allow_blank: true
validates :name,
@@ -699,13 +700,13 @@ class Project < ApplicationRecord
enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 }
chronic_duration_attr :build_timeout_human_readable, :build_timeout,
- default: 3600, error_message: _('Maximum job timeout has a value which could not be accepted')
+ default: 3600, error_message: N_('Maximum job timeout has a value which could not be accepted')
validates :build_timeout, allow_nil: true,
numericality: { greater_than_or_equal_to: 10.minutes,
less_than: MAX_BUILD_TIMEOUT,
only_integer: true,
- message: _('needs to be between 10 minutes and 1 month') }
+ message: N_('needs to be between 10 minutes and 1 month') }
# Used by Projects::CleanupService to hold a map of rewritten object IDs
mount_uploader :bfg_object_map, AttachmentUploader
@@ -2896,7 +2897,7 @@ class Project < ApplicationRecord
ci_cd_settings.allow_fork_pipelines_to_run_in_parent_project?
end
- def ci_job_token_scope_enabled?
+ def ci_outbound_job_token_scope_enabled?
return false unless ci_cd_settings
ci_cd_settings.job_token_scope_enabled?
diff --git a/app/models/project_group_link.rb b/app/models/project_group_link.rb
index 2ba3c74df5b..9f9447c1de2 100644
--- a/app/models/project_group_link.rb
+++ b/app/models/project_group_link.rb
@@ -9,7 +9,7 @@ class ProjectGroupLink < ApplicationRecord
validates :project_id, presence: true
validates :group, presence: true
- validates :group_id, uniqueness: { scope: [:project_id], message: _("already shared with this group") }
+ validates :group_id, uniqueness: { scope: [:project_id], message: N_("already shared with this group") }
validates :group_access, presence: true
validates :group_access, inclusion: { in: Gitlab::Access.values }, presence: true
validate :different_group
diff --git a/app/models/user.rb b/app/models/user.rb
index 74035414970..b36b00fcbaf 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -286,10 +286,10 @@ class User < ApplicationRecord
validate :check_username_format, if: :username_changed?
validates :theme_id, allow_nil: true, inclusion: { in: Gitlab::Themes.valid_ids,
- message: _("%{placeholder} is not a valid theme") % { placeholder: '%{value}' } }
+ message: ->(*) { _("%{placeholder} is not a valid theme") % { placeholder: '%{value}' } } }
validates :color_scheme_id, allow_nil: true, inclusion: { in: Gitlab::ColorSchemes.valid_ids,
- message: _("%{placeholder} is not a valid color scheme") % { placeholder: '%{value}' } }
+ message: ->(*) { _("%{placeholder} is not a valid color scheme") % { placeholder: '%{value}' } } }
validates :website_url, allow_blank: true, url: true, if: :website_url_changed?
diff --git a/app/models/users/banned_user.rb b/app/models/users/banned_user.rb
index c52b6d4b728..615668e2b55 100644
--- a/app/models/users/banned_user.rb
+++ b/app/models/users/banned_user.rb
@@ -7,6 +7,6 @@ module Users
belongs_to :user
validates :user, presence: true
- validates :user_id, uniqueness: { message: _("banned user already exists") }
+ validates :user_id, uniqueness: { message: N_("banned user already exists") }
end
end
diff --git a/app/services/ci/job_artifacts/delete_service.rb b/app/services/ci/job_artifacts/delete_service.rb
index 65cae03312e..c9d590eccc4 100644
--- a/app/services/ci/job_artifacts/delete_service.rb
+++ b/app/services/ci/job_artifacts/delete_service.rb
@@ -15,13 +15,23 @@ module Ci
method: 'Ci::JobArtifacts::DeleteService#execute',
project_id: build.project_id
)
+ return ServiceResponse.error(
+ message: 'Action temporarily disabled. The project this job belongs to is undergoing stats refresh.',
+ reason: :project_stats_refresh
+ )
end
- # fix_expire_at is false because in this case we want to explicitly delete the job artifacts
- # this flag is a workaround that will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/355833
- Ci::JobArtifacts::DestroyBatchService.new(build.job_artifacts.erasable, fix_expire_at: false).execute
+ result = Ci::JobArtifacts::DestroyBatchService.new(build.job_artifacts.erasable).execute
- ServiceResponse.success
+ if result.fetch(:status) == :success
+ ServiceResponse.success(payload:
+ {
+ destroyed_artifacts_count: result.fetch(:destroyed_artifacts_count),
+ statistics_updates: result.fetch(:statistics_updates)
+ })
+ else
+ ServiceResponse.error(message: result.fetch(:message))
+ end
end
private
diff --git a/app/views/admin/application_settings/appearances/preview_sign_in.html.haml b/app/views/admin/application_settings/appearances/preview_sign_in.html.haml
index 2e4ab714048..1c2350e2835 100644
--- a/app/views/admin/application_settings/appearances/preview_sign_in.html.haml
+++ b/app/views/admin/application_settings/appearances/preview_sign_in.html.haml
@@ -9,5 +9,5 @@
= label_tag :password
= password_field_tag :password, nil, disabled: true, class: "form-control gl-form-input bottom", title: title
.form-group
- = button_tag _("Sign in"), disabled: true, class: "btn gl-button btn-confirm", type: "button", title: title
-
+ = render Pajamas::ButtonComponent.new(variant: :confirm, disabled: true, button_options: { title: title }) do
+ = _("Sign in")
diff --git a/app/views/shared/issuable/_label_page_create.html.haml b/app/views/shared/issuable/_label_page_create.html.haml
index ec78b3f7ce3..eb3acd8e055 100644
--- a/app/views/shared/issuable/_label_page_create.html.haml
+++ b/app/views/shared/issuable/_label_page_create.html.haml
@@ -19,7 +19,7 @@
%input.js-add-list{ type: "checkbox", name: "add_list", checked: add_list }
%span= _('Add list')
.clearfix
- %button.gl-button.btn.btn-confirm.float-left.js-new-label-btn{ type: "button" }
+ = render Pajamas::ButtonComponent.new(variant: :confirm, button_options: { class: 'float-left js-new-label-btn' }) do
= _('Create')
- %button.gl-button.btn.btn-default.float-right.js-cancel-label-btn{ type: "button" }
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'float-right js-cancel-label-btn' }) do
= _('Cancel')
diff --git a/app/workers/ci/cancel_pipeline_worker.rb b/app/workers/ci/cancel_pipeline_worker.rb
index 147839a0625..2735498b6bb 100644
--- a/app/workers/ci/cancel_pipeline_worker.rb
+++ b/app/workers/ci/cancel_pipeline_worker.rb
@@ -10,6 +10,7 @@ module Ci
idempotent!
deduplicate :until_executed
urgency :high
+ loggable_arguments 1
def perform(pipeline_id, auto_canceled_by_pipeline_id)
::Ci::Pipeline.find_by_id(pipeline_id).try do |pipeline|
diff --git a/config/metrics/counts_28d/20210216184850_deploy_token_packages_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184850_deploy_token_packages_total_unique_counts_monthly.yml
index 6b6c40495a6..59427c74b0f 100644
--- a/config/metrics/counts_28d/20210216184850_deploy_token_packages_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216184850_deploy_token_packages_total_unique_counts_monthly.yml
@@ -1,7 +1,7 @@
---
data_category: optional
key_path: redis_hll_counters.deploy_token_packages.deploy_token_packages_total_unique_counts_monthly
-description: A monthly count of packages published to the registry using a deploy
+description: A monthly count of unique users who published packages to the registry using a deploy
token
product_section: ops
product_stage: package
@@ -11,8 +11,11 @@ value_type: number
status: active
time_frame: 28d
data_source: redis_hll
-instrumentation_class: RedisHLLMetric
+instrumentation_class: AggregatedMetric
options:
+ aggregate:
+ operator: OR
+ attribute: user_id
events:
- i_package_composer_deploy_token
- i_package_conan_deploy_token
diff --git a/config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml
index 28adf6d6d01..19bb7f0ba3c 100644
--- a/config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml
@@ -1,7 +1,8 @@
---
data_category: optional
key_path: redis_hll_counters.deploy_token_packages.deploy_token_packages_total_unique_counts_weekly
-description: A weekly count of packages published to the registry using a deploy token
+description: A weekly count of unique users who published packages to the registry using a deploy
+ token
product_section: ops
product_stage: package
product_group: package
@@ -10,8 +11,11 @@ value_type: number
status: active
time_frame: 7d
data_source: redis_hll
-instrumentation_class: RedisHLLMetric
+instrumentation_class: AggregatedMetric
options:
+ aggregate:
+ operator: OR
+ attribute: user_id
events:
- i_package_composer_deploy_token
- i_package_conan_deploy_token
diff --git a/db/docs/incident_management_timeline_event_tag_links.yml b/db/docs/incident_management_timeline_event_tag_links.yml
new file mode 100644
index 00000000000..429371aefb7
--- /dev/null
+++ b/db/docs/incident_management_timeline_event_tag_links.yml
@@ -0,0 +1,9 @@
+---
+table_name: incident_management_timeline_event_tag_links
+classes:
+- IncidentManagement::TimelineEventTagLink
+feature_categories:
+- incident_management
+description: Persists links between timeline event tags and timeline events.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100271
+milestone: '15.6'
diff --git a/db/docs/incident_management_timeline_event_tags.yml b/db/docs/incident_management_timeline_event_tags.yml
new file mode 100644
index 00000000000..47dedaf3de2
--- /dev/null
+++ b/db/docs/incident_management_timeline_event_tags.yml
@@ -0,0 +1,9 @@
+---
+table_name: incident_management_timeline_event_tags
+classes:
+- IncidentManagement::TimelineEventTag
+feature_categories:
+- incident_management
+description: Persists tags for timeline events in a project.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100271
+milestone: '15.6'
diff --git a/db/migrate/20221005072353_create_incident_management_timeline_event_tags.rb b/db/migrate/20221005072353_create_incident_management_timeline_event_tags.rb
new file mode 100644
index 00000000000..c046548af01
--- /dev/null
+++ b/db/migrate/20221005072353_create_incident_management_timeline_event_tags.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class CreateIncidentManagementTimelineEventTags < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ def up
+ create_table :incident_management_timeline_event_tags do |t|
+ t.timestamps_with_timezone null: false
+ t.references :project, null: false, index: false, foreign_key: { on_delete: :cascade }
+ t.text :name, limit: 255, null: false
+
+ t.index [:project_id, :name], unique: true, name: 'index_im_timeline_event_tags_name_project_id'
+ end
+ end
+
+ def down
+ drop_table :incident_management_timeline_event_tags
+ end
+end
diff --git a/db/migrate/20221005094926_create_incident_management_timeline_event_tag_links.rb b/db/migrate/20221005094926_create_incident_management_timeline_event_tag_links.rb
new file mode 100644
index 00000000000..b3ec8f97738
--- /dev/null
+++ b/db/migrate/20221005094926_create_incident_management_timeline_event_tag_links.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class CreateIncidentManagementTimelineEventTagLinks < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ def up
+ create_table :incident_management_timeline_event_tag_links do |t|
+ t.references :timeline_event,
+ null: false,
+ index: { name: 'index_im_timeline_event_id' },
+ foreign_key: { to_table: :incident_management_timeline_events, column: :timeline_event_id, on_delete: :cascade }
+
+ t.references :timeline_event_tag,
+ null: false,
+ index: false,
+ foreign_key: {
+ to_table: :incident_management_timeline_event_tags,
+ column: :timeline_event_tag_id,
+ on_delete: :cascade
+ }
+
+ t.index [:timeline_event_tag_id, :timeline_event_id],
+ unique: true,
+ name: 'index_im_timeline_event_tags_on_tag_id_and_event_id'
+
+ t.datetime_with_timezone :created_at, null: false
+ end
+ end
+
+ def down
+ drop_table :incident_management_timeline_event_tag_links
+ end
+end
diff --git a/db/migrate/20221018081416_members_remove_member_namespace_id_not_null_constraint.rb b/db/migrate/20221018081416_members_remove_member_namespace_id_not_null_constraint.rb
new file mode 100644
index 00000000000..e4cbcd24bc4
--- /dev/null
+++ b/db/migrate/20221018081416_members_remove_member_namespace_id_not_null_constraint.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class MembersRemoveMemberNamespaceIdNotNullConstraint < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ CONSTRAINT_NAME = 'check_508774aac0'
+
+ def up
+ remove_not_null_constraint :members, :member_namespace_id, constraint_name: CONSTRAINT_NAME
+ end
+
+ def down
+ add_not_null_constraint :members, :member_namespace_id, validate: false, constraint_name: CONSTRAINT_NAME
+ end
+end
diff --git a/db/schema_migrations/20221005072353 b/db/schema_migrations/20221005072353
new file mode 100644
index 00000000000..3249a062aa7
--- /dev/null
+++ b/db/schema_migrations/20221005072353
@@ -0,0 +1 @@
+6b90dfb738c597a45ecaae792e97e1ae0decb93779ecc35fbc2fbaedafb5b9d1 \ No newline at end of file
diff --git a/db/schema_migrations/20221005094926 b/db/schema_migrations/20221005094926
new file mode 100644
index 00000000000..7606c06170f
--- /dev/null
+++ b/db/schema_migrations/20221005094926
@@ -0,0 +1 @@
+ab93968543b6aec0bc304a2c0dc051f63a29b4765df11432fba45325e5e75e55 \ No newline at end of file
diff --git a/db/schema_migrations/20221018081416 b/db/schema_migrations/20221018081416
new file mode 100644
index 00000000000..4b92b46709a
--- /dev/null
+++ b/db/schema_migrations/20221018081416
@@ -0,0 +1 @@
+25030e3ba7c6632fa86100c2db320d1e0c431f992e2b3e333a98e7e03bd31a49 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 960c736090d..10b2d26b1e0 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -16411,6 +16411,40 @@ CREATE SEQUENCE incident_management_pending_issue_escalations_id_seq
ALTER SEQUENCE incident_management_pending_issue_escalations_id_seq OWNED BY incident_management_pending_issue_escalations.id;
+CREATE TABLE incident_management_timeline_event_tag_links (
+ id bigint NOT NULL,
+ timeline_event_id bigint NOT NULL,
+ timeline_event_tag_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL
+);
+
+CREATE SEQUENCE incident_management_timeline_event_tag_links_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE incident_management_timeline_event_tag_links_id_seq OWNED BY incident_management_timeline_event_tag_links.id;
+
+CREATE TABLE incident_management_timeline_event_tags (
+ id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ project_id bigint NOT NULL,
+ name text NOT NULL,
+ CONSTRAINT check_8717184e2c CHECK ((char_length(name) <= 255))
+);
+
+CREATE SEQUENCE incident_management_timeline_event_tags_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE incident_management_timeline_event_tags_id_seq OWNED BY incident_management_timeline_event_tags.id;
+
CREATE TABLE incident_management_timeline_events (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -23743,6 +23777,10 @@ ALTER TABLE ONLY incident_management_pending_alert_escalations ALTER COLUMN id S
ALTER TABLE ONLY incident_management_pending_issue_escalations ALTER COLUMN id SET DEFAULT nextval('incident_management_pending_issue_escalations_id_seq'::regclass);
+ALTER TABLE ONLY incident_management_timeline_event_tag_links ALTER COLUMN id SET DEFAULT nextval('incident_management_timeline_event_tag_links_id_seq'::regclass);
+
+ALTER TABLE ONLY incident_management_timeline_event_tags ALTER COLUMN id SET DEFAULT nextval('incident_management_timeline_event_tags_id_seq'::regclass);
+
ALTER TABLE ONLY incident_management_timeline_events ALTER COLUMN id SET DEFAULT nextval('incident_management_timeline_events_id_seq'::regclass);
ALTER TABLE ONLY index_statuses ALTER COLUMN id SET DEFAULT nextval('index_statuses_id_seq'::regclass);
@@ -25102,9 +25140,6 @@ ALTER TABLE ONLY chat_teams
ALTER TABLE vulnerability_scanners
ADD CONSTRAINT check_37608c9db5 CHECK ((char_length(vendor) <= 255)) NOT VALID;
-ALTER TABLE members
- ADD CONSTRAINT check_508774aac0 CHECK ((member_namespace_id IS NOT NULL)) NOT VALID;
-
ALTER TABLE sprints
ADD CONSTRAINT check_ccd8a1eae0 CHECK ((start_date IS NOT NULL)) NOT VALID;
@@ -25702,6 +25737,12 @@ ALTER TABLE ONLY incident_management_pending_alert_escalations
ALTER TABLE ONLY incident_management_pending_issue_escalations
ADD CONSTRAINT incident_management_pending_issue_escalations_pkey PRIMARY KEY (id, process_at);
+ALTER TABLE ONLY incident_management_timeline_event_tag_links
+ ADD CONSTRAINT incident_management_timeline_event_tag_links_pkey PRIMARY KEY (id);
+
+ALTER TABLE ONLY incident_management_timeline_event_tags
+ ADD CONSTRAINT incident_management_timeline_event_tags_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY incident_management_timeline_events
ADD CONSTRAINT incident_management_timeline_events_pkey PRIMARY KEY (id);
@@ -29054,6 +29095,12 @@ CREATE INDEX index_im_issuable_escalation_statuses_on_policy_id ON incident_mana
CREATE UNIQUE INDEX index_im_oncall_schedules_on_project_id_and_iid ON incident_management_oncall_schedules USING btree (project_id, iid);
+CREATE INDEX index_im_timeline_event_id ON incident_management_timeline_event_tag_links USING btree (timeline_event_id);
+
+CREATE UNIQUE INDEX index_im_timeline_event_tags_name_project_id ON incident_management_timeline_event_tags USING btree (project_id, name);
+
+CREATE UNIQUE INDEX index_im_timeline_event_tags_on_tag_id_and_event_id ON incident_management_timeline_event_tag_links USING btree (timeline_event_tag_id, timeline_event_id);
+
CREATE INDEX index_im_timeline_events_author_id ON incident_management_timeline_events USING btree (author_id);
CREATE INDEX index_im_timeline_events_issue_id ON incident_management_timeline_events USING btree (issue_id);
@@ -33925,6 +33972,9 @@ ALTER TABLE ONLY issue_user_mentions
ALTER TABLE ONLY merge_request_assignees
ADD CONSTRAINT fk_rails_579d375628 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY incident_management_timeline_event_tag_links
+ ADD CONSTRAINT fk_rails_57baccd7f9 FOREIGN KEY (timeline_event_id) REFERENCES incident_management_timeline_events(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY packages_debian_project_architectures
ADD CONSTRAINT fk_rails_5808663adf FOREIGN KEY (distribution_id) REFERENCES packages_debian_project_distributions(id) ON DELETE CASCADE;
@@ -34129,6 +34179,9 @@ ALTER TABLE ONLY group_crm_settings
ALTER TABLE ONLY clusters_applications_ingress
ADD CONSTRAINT fk_rails_753a7b41c1 FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE;
+ALTER TABLE ONLY incident_management_timeline_event_tag_links
+ ADD CONSTRAINT fk_rails_753b8b6ee3 FOREIGN KEY (timeline_event_tag_id) REFERENCES incident_management_timeline_event_tags(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY release_links
ADD CONSTRAINT fk_rails_753be7ae29 FOREIGN KEY (release_id) REFERENCES releases(id) ON DELETE CASCADE;
@@ -34756,6 +34809,9 @@ ALTER TABLE ONLY deployment_merge_requests
ALTER TABLE ONLY packages_debian_group_component_files
ADD CONSTRAINT fk_rails_dd262386e9 FOREIGN KEY (component_id) REFERENCES packages_debian_group_components(id) ON DELETE RESTRICT;
+ALTER TABLE ONLY incident_management_timeline_event_tags
+ ADD CONSTRAINT fk_rails_dd5c91484e FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY user_callouts
ADD CONSTRAINT fk_rails_ddfdd80f3d FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
diff --git a/lib/api/entities/ci/job_basic.rb b/lib/api/entities/ci/job_basic.rb
index 3d9318ec428..fb975475cf5 100644
--- a/lib/api/entities/ci/job_basic.rb
+++ b/lib/api/entities/ci/job_basic.rb
@@ -21,7 +21,7 @@ module API
expose :project do
expose :ci_job_token_scope_enabled do |job|
- job.project.ci_job_token_scope_enabled?
+ job.project.ci_outbound_job_token_scope_enabled?
end
end
end
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index b3907397fbb..f158695f605 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -104,7 +104,7 @@ module API
expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] }
expose :ci_default_git_depth
expose :ci_forward_deployment_enabled
- expose :ci_job_token_scope_enabled
+ expose(:ci_job_token_scope_enabled) { |p, _| p.ci_outbound_job_token_scope_enabled? }
expose :ci_separated_caches
expose :ci_opt_in_jwt
expose :ci_allow_fork_pipelines_to_run_in_parent_project
diff --git a/lib/api/events.rb b/lib/api/events.rb
index 521a9e6d351..0a0141484ef 100644
--- a/lib/api/events.rb
+++ b/lib/api/events.rb
@@ -20,8 +20,6 @@ module API
use :pagination
use :event_filter_params
use :sort_params
- optional :scope, type: String, desc: 'Include all events across a user\'s projects',
- documentation: { example: 'all' }
end
get do
diff --git a/lib/api/helpers/events_helpers.rb b/lib/api/helpers/events_helpers.rb
index cef34ca8d05..bf3b76bb92d 100644
--- a/lib/api/helpers/events_helpers.rb
+++ b/lib/api/helpers/events_helpers.rb
@@ -6,7 +6,7 @@ module API
extend Grape::API::Helpers
params :event_filter_params do
- optional :action, type: String, values: Event.actions.keys, desc: 'Event action to filter on'
+ optional :action, type: String, values: Event.actions, desc: 'Event action to filter on'
optional :target_type, type: String, values: Event.target_types, desc: 'Event target type to filter on'
optional :before, type: Date, desc: 'Include only events created before this date'
optional :after, type: Date, desc: 'Include only events created after this date'
diff --git a/lib/gitlab/database/gitlab_schemas.yml b/lib/gitlab/database/gitlab_schemas.yml
index 0f93f6df54d..c4a9cf8b80f 100644
--- a/lib/gitlab/database/gitlab_schemas.yml
+++ b/lib/gitlab/database/gitlab_schemas.yml
@@ -264,6 +264,8 @@ incident_management_oncall_shifts: :gitlab_main
incident_management_pending_alert_escalations: :gitlab_main
incident_management_pending_issue_escalations: :gitlab_main
incident_management_timeline_events: :gitlab_main
+incident_management_timeline_event_tags: :gitlab_main
+incident_management_timeline_event_tag_links: :gitlab_main
index_statuses: :gitlab_main
in_product_marketing_emails: :gitlab_main
insights: :gitlab_main
diff --git a/lib/gitlab/json.rb b/lib/gitlab/json.rb
index ce07752f88c..823d6202b1e 100644
--- a/lib/gitlab/json.rb
+++ b/lib/gitlab/json.rb
@@ -34,6 +34,7 @@ module Gitlab
alias_method :parse!, :parse
alias_method :load, :parse
+ alias_method :decode, :parse
# Restricted method for converting a Ruby object to JSON. If you
# need to pass options to this, you should use `.generate` instead,
@@ -56,6 +57,8 @@ module Gitlab
adapter_generate(object, opts)
end
+ alias_method :encode, :generate
+
# Generates JSON for an object and makes it look purdy
#
# The Oj variant in this looks seriously weird but these are the settings
diff --git a/qa/Gemfile b/qa/Gemfile
index 8a4ec1f2f76..0f16739b477 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -16,7 +16,7 @@ gem 'rspec-retry', '~> 0.6.1', require: 'rspec/retry'
gem 'rspec_junit_formatter', '~> 0.6.0'
gem 'faker', '~> 2.23'
gem 'knapsack', '~> 4.0'
-gem 'parallel_tests', '~> 2.32'
+gem 'parallel_tests', '~> 3.13'
gem 'rotp', '~> 6.2.0'
gem 'timecop', '~> 0.9.5'
gem 'parallel', '~> 1.19'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 2f3bfef01a4..1f94b534ef1 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -185,7 +185,7 @@ GEM
oj (3.13.21)
os (1.1.4)
parallel (1.19.2)
- parallel_tests (2.32.0)
+ parallel_tests (3.13.0)
parallel
parser (3.1.2.1)
ast (~> 2.4.1)
@@ -316,7 +316,7 @@ DEPENDENCIES
nokogiri (~> 1.13, >= 1.13.8)
octokit (~> 5.6.1)
parallel (~> 1.19)
- parallel_tests (~> 2.32)
+ parallel_tests (~> 3.13)
pry-byebug (~> 3.5.1)
rainbow (~> 3.0.0)
rake (~> 13)
diff --git a/qa/Rakefile b/qa/Rakefile
index ada27596ae4..6f94c63b4de 100644
--- a/qa/Rakefile
+++ b/qa/Rakefile
@@ -11,7 +11,7 @@ end
desc "Initialize GitLab with an access token"
task :initialize_gitlab_auth, [:address] do |_, args|
- QA::Tools::InitializeGitLabAuth.new(args).run
+ QA::Tools::InitializeGitlabAuth.new(args).run
end
desc "Generate Performance Testdata"
@@ -46,7 +46,7 @@ task generate_data_and_run_load_test: [:generate_perf_testdata, :run_artillery_l
desc "Deletes test ssh keys a user"
task :delete_test_ssh_keys, [:title_portion, :delete_before, :dry_run] do |_, args|
- QA::Tools::DeleteTestSSHKeys.new(args).run
+ QA::Tools::DeleteTestSshKeys.new(args).run
end
desc "Deletes projects directly under the provided group"
diff --git a/qa/qa.rb b/qa/qa.rb
index 99a8a34d6d8..bf6b75a1278 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -30,6 +30,22 @@ module QA
loader.ignore("#{root}/specs/features")
loader.ignore("#{root}/specs/spec_helper.rb")
+ # we need to eager load scenario classes
+ # zeitwerk does not have option to configure what to eager load, so all exceptions have to be defined
+ loader.do_not_eager_load("#{root}/ce")
+ loader.do_not_eager_load("#{root}/ee")
+ loader.do_not_eager_load("#{root}/flow")
+ loader.do_not_eager_load("#{root}/git")
+ loader.do_not_eager_load("#{root}/mobile")
+ loader.do_not_eager_load("#{root}/page")
+ loader.do_not_eager_load("#{root}/resource")
+ loader.do_not_eager_load("#{root}/runtime")
+ loader.do_not_eager_load("#{root}/service")
+ loader.do_not_eager_load("#{root}/specs")
+ loader.do_not_eager_load("#{root}/support")
+ loader.do_not_eager_load("#{root}/tools")
+ loader.do_not_eager_load("#{root}/vendor")
+
loader.inflector.inflect(
"ce" => "CE",
"ee" => "EE",
@@ -74,6 +90,7 @@ module QA
end
loader.setup
+ loader.eager_load
end
# Custom warning processing
diff --git a/qa/qa/scenario/test/instance.rb b/qa/qa/scenario/test/instance.rb
deleted file mode 100644
index b4098619e4e..00000000000
--- a/qa/qa/scenario/test/instance.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Scenario
- module Test
- # This class exists for back-compatibility so that gitlab-qa can continue
- # to call Test::Instance instead of Test::Instance::All until at least
- # the current latest GitLab version has the Test::Instance::All class.
- # As of Aug, 22nd 2018. Only GitLab >= 11.3 has this class.
- module Instance
- include Bootable
-
- def self.perform(*args)
- self.tap do |scenario|
- yield scenario if block_given?
- break scenario.do_perform(*args)
- end
- end
-
- def self.do_perform(address, *rspec_options)
- Runtime::Scenario.define(:gitlab_address, address)
-
- ##
- # Perform before hooks, which are different for CE and EE
- #
- Runtime::Release.perform_before_hooks
-
- Specs::Runner.perform do |specs|
- specs.tty = true
- specs.options = rspec_options if rspec_options.any?
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/scenario/test/integration/github.rb b/qa/qa/scenario/test/integration/github.rb
deleted file mode 100644
index 857a1f00bd5..00000000000
--- a/qa/qa/scenario/test/integration/github.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Scenario
- module Test
- module Integration
- class Github < Test::Instance::All
- tags :github
-
- def perform(address, *rspec_options)
- # This test suite requires a GitHub personal access token
- Runtime::Env.require_github_access_token!
-
- super
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/qa_deprecation_toolkit_env.rb b/qa/qa/specs/qa_deprecation_toolkit_env.rb
index 21ef5a6f229..5224a2e9ae0 100644
--- a/qa/qa/specs/qa_deprecation_toolkit_env.rb
+++ b/qa/qa/specs/qa_deprecation_toolkit_env.rb
@@ -5,20 +5,24 @@ require 'deprecation_toolkit/rspec'
require 'concurrent/utility/monotonic_time'
require 'active_support/gem_version'
-module QaDeprecationToolkitEnv
- # Taken from https://github.com/jeremyevans/ruby-warning/blob/1.1.0/lib/warning.rb#L18
- # rubocop:disable Layout/LineLength
- def self.kwargs_warning
- %r{warning: (?:Using the last argument (?:for `.+' )?as keyword parameters is deprecated; maybe \*\* should be added to the call|Passing the keyword argument (?:for `.+' )?as the last hash parameter is deprecated|Splitting the last argument (?:for `.+' )?into positional and keyword parameters is deprecated|The called method (?:`.+' )?is defined here)\n\z}
- end
- # rubocop:enable Layout/LineLength
+module QA
+ module Specs
+ class QaDeprecationToolkitEnv
+ # Taken from https://github.com/jeremyevans/ruby-warning/blob/1.1.0/lib/warning.rb#L18
+ # rubocop:disable Layout/LineLength
+ def self.kwargs_warning
+ %r{warning: (?:Using the last argument (?:for `.+' )?as keyword parameters is deprecated; maybe \*\* should be added to the call|Passing the keyword argument (?:for `.+' )?as the last hash parameter is deprecated|Splitting the last argument (?:for `.+' )?into positional and keyword parameters is deprecated|The called method (?:`.+' )?is defined here)\n\z}
+ end
+ # rubocop:enable Layout/LineLength
- def self.configure!
- # Enable ruby deprecations for keywords, it's suppressed by default in Ruby 2.7
- Warning[:deprecated] = true
+ def self.configure!
+ # Enable ruby deprecations for keywords, it's suppressed by default in Ruby 2.7
+ Warning[:deprecated] = true
- DeprecationToolkit::Configuration.test_runner = :rspec
- DeprecationToolkit::Configuration.deprecation_path = 'deprecations'
- DeprecationToolkit::Configuration.warnings_treated_as_deprecation = [kwargs_warning]
+ DeprecationToolkit::Configuration.test_runner = :rspec
+ DeprecationToolkit::Configuration.deprecation_path = 'deprecations'
+ DeprecationToolkit::Configuration.warnings_treated_as_deprecation = [kwargs_warning]
+ end
+ end
end
end
diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb
index b9e67c2fa72..97901042883 100644
--- a/qa/qa/specs/spec_helper.rb
+++ b/qa/qa/specs/spec_helper.rb
@@ -2,8 +2,7 @@
require_relative '../../qa'
-require_relative 'qa_deprecation_toolkit_env'
-QaDeprecationToolkitEnv.configure!
+QA::Specs::QaDeprecationToolkitEnv.configure!
Knapsack::Adapters::RSpecAdapter.bind if QA::Runtime::Env.knapsack?
diff --git a/qa/qa/tools/ci/non_empty_suites.rb b/qa/qa/tools/ci/non_empty_suites.rb
index 687c11a3e62..2319237fa25 100644
--- a/qa/qa/tools/ci/non_empty_suites.rb
+++ b/qa/qa/tools/ci/non_empty_suites.rb
@@ -10,42 +10,11 @@ module QA
class NonEmptySuites
include Helpers
- # rubocop:disable Layout/LineLength
- SCENARIOS = [
- { klass: "Test::Instance::All" },
- { klass: "Test::Instance::Smoke" },
- { klass: "Test::Instance::Reliable" },
- { klass: "Test::Instance::ReviewBlocking" },
- { klass: "Test::Instance::ReviewNonBlocking" },
- { klass: "Test::Instance::CloudActivation" },
- { klass: "Test::Instance::Integrations" },
- { klass: "Test::Instance::Jira" },
- { klass: "Test::Instance::LargeSetup" },
- { klass: "Test::Instance::Metrics" },
- { klass: "Test::Instance::ObjectStorage" },
- { klass: "Test::Instance::Packages" },
- { klass: "Test::Instance::RepositoryStorage" },
- { klass: "Test::Integration::ServicePingDisabled" },
- { klass: "Test::Integration::LDAPNoTLS" },
- { klass: "Test::Integration::LDAPTLS" },
- { klass: "Test::Integration::LDAPNoServer" },
- { klass: "Test::Integration::InstanceSAML" },
- { klass: "Test::Integration::RegistryWithCDN" },
- { klass: "Test::Integration::RegistryTLS" },
- { klass: "Test::Integration::Registry" },
- { klass: "Test::Integration::SMTP" },
- { klass: "QA::EE::Scenario::Test::Integration::Elasticsearch" },
- { klass: "QA::EE::Scenario::Test::Integration::GroupSAML" },
- {
- klass: "QA::EE::Scenario::Test::Geo",
- args: "--primary-address http://dummy1.test --primary-name gitlab-primary --secondary-address http://dummy2.test --secondary-name gitlab-secondary --without-setup"
- },
- {
- klass: "Test::Integration::Mattermost",
- args: "--mattermost-address http://mattermost.test"
- }
+ # @return [Array] scenarios that never run in package-and-test pipeline
+ IGNORED_SCENARIOS = [
+ "QA::EE::Scenario::Test::Geo",
+ "QA::Scenario::Test::Instance::Airgapped"
].freeze
- # rubocop:enable Layout/LineLength
def initialize(qa_tests)
@qa_tests = qa_tests
@@ -56,38 +25,58 @@ module QA
# @return [String]
def fetch
logger.info("Checking for runnable suites")
- scenarios = SCENARIOS.each_with_object([]) do |scenario, runnable_scenarios|
- logger.info(" fetching runnable specs for '#{scenario[:klass]}'")
+ scenarios.each_with_object([]) do |scenario, runnable_scenarios|
+ logger.info(" fetching runnable specs for '#{scenario}'")
+ next logger.info(" scenario is in ignore list, skipping") if IGNORED_SCENARIOS.include?(scenario)
- out, err, status = run_command(**scenario)
+ out, err, status = run_command(scenario)
unless status.success?
- logger.error(" example count failed!\n#{err}")
+ logger.error(" example count failed!\n#{err}")
next
end
count = out.split("\n").last.to_i
logger.info(" found #{count} examples to run")
- runnable_scenarios << scenario[:klass] if count > 0
- end
-
- scenarios.join(",")
+ runnable_scenarios << scenario if count > 0
+ end.join(",")
end
private
attr_reader :qa_tests
+ # Get all defined scenarios
+ #
+ # @return [Array<String>]
+ def scenarios
+ foss_scenarios = scenario_classes(QA::Scenario::Test)
+ return foss_scenarios unless QA.const_defined?("QA::EE")
+
+ foss_scenarios + scenario_classes(QA::EE::Scenario::Test)
+ end
+
+ # Fetch scenario classes recursively
+ #
+ # @param [Module] mod
+ # @return [Array<String>]
+ def scenario_classes(mod)
+ mod.constants.map do |const|
+ c = mod.const_get(const, false)
+ next c.to_s if c.is_a?(Class)
+
+ scenario_classes(c)
+ end.flatten
+ end
+
# Run scenario count command
#
# @param [String] klass
- # @param [String] args
# @return [String]
- def run_command(klass:, args: nil)
+ def run_command(klass)
cmd = ["bundle exec bin/qa"]
cmd << klass
cmd << "--count-examples-only --address http://dummy1.test"
- cmd << args if args
cmd << "-- #{qa_tests}" unless qa_tests.blank?
Open3.capture3(cmd.join(" "))
diff --git a/qa/qa/tools/delete_test_ssh_keys.rb b/qa/qa/tools/delete_test_ssh_keys.rb
index 9e5728a5509..c10188eae6d 100644
--- a/qa/qa/tools/delete_test_ssh_keys.rb
+++ b/qa/qa/tools/delete_test_ssh_keys.rb
@@ -12,7 +12,7 @@
module QA
module Tools
- class DeleteTestSSHKeys
+ class DeleteTestSshKeys
include Support::API
ITEMS_PER_PAGE = '100'
diff --git a/qa/qa/tools/initialize_gitlab_auth.rb b/qa/qa/tools/initialize_gitlab_auth.rb
index 18e90f0d739..6d586f95ecf 100644
--- a/qa/qa/tools/initialize_gitlab_auth.rb
+++ b/qa/qa/tools/initialize_gitlab_auth.rb
@@ -6,7 +6,7 @@ module QA
# Also creates a personal access token
# @example
# $ bundle exec rake 'initialize_gitlab_auth[http://gitlab.test]'
- class InitializeGitLabAuth
+ class InitializeGitlabAuth
attr_reader :address
def initialize(address:)
diff --git a/qa/spec/scenario/test/integration/github_spec.rb b/qa/spec/scenario/test/integration/github_spec.rb
deleted file mode 100644
index 4ad42b4f5cc..00000000000
--- a/qa/spec/scenario/test/integration/github_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe QA::Scenario::Test::Integration::Github do
- describe '#perform' do
- let(:env) { spy('Runtime::Env', knapsack?: false, dry_run: false) }
-
- before do
- stub_const('QA::Runtime::Env', env)
- end
-
- it_behaves_like 'a QA scenario class' do
- let(:tags) { [:github] }
-
- it 'requires a GitHub access token' do
- subject.perform(args)
-
- expect(env).to have_received(:require_github_access_token!)
- end
- end
- end
-end
diff --git a/qa/spec/tools/ci/non_empty_suites_spec.rb b/qa/spec/tools/ci/non_empty_suites_spec.rb
index d9bfe1eebe7..f71e07aa4b4 100644
--- a/qa/spec/tools/ci/non_empty_suites_spec.rb
+++ b/qa/spec/tools/ci/non_empty_suites_spec.rb
@@ -9,11 +9,11 @@ RSpec.describe QA::Tools::Ci::NonEmptySuites do
allow(Gitlab::QA::TestLogger).to receive(:logger).and_return(Logger.new(StringIO.new))
allow(Open3).to receive(:capture3).and_return(["output\n0", "", status])
allow(Open3).to receive(:capture3)
- .with("bundle exec bin/qa Test::Instance::All --count-examples-only --address http://dummy1.test")
+ .with("bundle exec bin/qa QA::Scenario::Test::Instance::All --count-examples-only --address http://dummy1.test")
.and_return(["output\n1", "", status])
end
it "returns runnable test suites" do
- expect(non_empty_suites.fetch).to eq("Test::Instance::All")
+ expect(non_empty_suites.fetch).to eq("QA::Scenario::Test::Instance::All")
end
end
diff --git a/spec/factories/incident_management/timeline_event_tag_links.rb b/spec/factories/incident_management/timeline_event_tag_links.rb
new file mode 100644
index 00000000000..883aca29f99
--- /dev/null
+++ b/spec/factories/incident_management/timeline_event_tag_links.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :incident_management_timeline_event_tag_link, class: 'IncidentManagement::TimelineEventTagLink' do
+ association :timeline_event_tag, factory: :incident_management_timeline_event_tag
+ association :timeline_event, factory: :incident_management_timeline_event
+ end
+end
diff --git a/spec/factories/incident_management/timeline_event_tags.rb b/spec/factories/incident_management/timeline_event_tags.rb
new file mode 100644
index 00000000000..6333872ee4f
--- /dev/null
+++ b/spec/factories/incident_management/timeline_event_tags.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :incident_management_timeline_event_tag, class: 'IncidentManagement::TimelineEventTag' do
+ project
+ name { 'Start time' }
+ end
+end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 1e14b3088db..b62995dce42 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -54,7 +54,7 @@ FactoryBot.define do
import_last_error { nil }
forward_deployment_enabled { nil }
restrict_user_defined_variables { nil }
- ci_job_token_scope_enabled { nil }
+ ci_outbound_job_token_scope_enabled { nil }
ci_inbound_job_token_scope_enabled { nil }
runner_token_expiration_interval { nil }
runner_token_expiration_interval_human_readable { nil }
@@ -113,7 +113,7 @@ FactoryBot.define do
project.merge_trains_enabled = evaluator.merge_trains_enabled unless evaluator.merge_trains_enabled.nil?
project.keep_latest_artifact = evaluator.keep_latest_artifact unless evaluator.keep_latest_artifact.nil?
project.restrict_user_defined_variables = evaluator.restrict_user_defined_variables unless evaluator.restrict_user_defined_variables.nil?
- project.ci_job_token_scope_enabled = evaluator.ci_job_token_scope_enabled unless evaluator.ci_job_token_scope_enabled.nil?
+ project.ci_outbound_job_token_scope_enabled = evaluator.ci_outbound_job_token_scope_enabled unless evaluator.ci_outbound_job_token_scope_enabled.nil?
project.ci_inbound_job_token_scope_enabled = evaluator.ci_inbound_job_token_scope_enabled unless evaluator.ci_inbound_job_token_scope_enabled.nil?
project.runner_token_expiration_interval = evaluator.runner_token_expiration_interval unless evaluator.runner_token_expiration_interval.nil?
project.runner_token_expiration_interval_human_readable = evaluator.runner_token_expiration_interval_human_readable unless evaluator.runner_token_expiration_interval_human_readable.nil?
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js
index b88206c3b9a..936f4744e94 100644
--- a/spec/frontend/diffs/components/app_spec.js
+++ b/spec/frontend/diffs/components/app_spec.js
@@ -152,6 +152,30 @@ describe('diffs/components/app', () => {
});
});
+ describe('fetch diff with no changes', () => {
+ beforeEach(() => {
+ const fetchResolver = () => {
+ store.state.diffs.retrievingBatches = false;
+ return Promise.resolve({ real_size: null });
+ };
+
+ createComponent();
+ jest.spyOn(wrapper.vm, 'fetchDiffFilesMeta').mockImplementation(fetchResolver);
+
+ return nextTick();
+ });
+
+ it('diff counter to be 0 after fetch', async () => {
+ expect(wrapper.vm.diffFilesLength).toEqual(0);
+ wrapper.vm.fetchData(false);
+
+ await nextTick();
+
+ expect(wrapper.vm.fetchDiffFilesMeta).toHaveBeenCalled();
+ expect(wrapper.vm.diffFilesLength).toEqual(0);
+ });
+ });
+
describe('codequality diff', () => {
it('does not fetch code quality data on FOSS', async () => {
createComponent();
diff --git a/spec/frontend/groups/components/overview_tabs_spec.js b/spec/frontend/groups/components/overview_tabs_spec.js
index be352301f43..93e087e10f2 100644
--- a/spec/frontend/groups/components/overview_tabs_spec.js
+++ b/spec/frontend/groups/components/overview_tabs_spec.js
@@ -141,6 +141,14 @@ describe('OverviewTabs', () => {
expect(tabPanel.vm.$attrs.lazy).toBe(false);
});
+ it('sets `lazy` prop to `false` for initially active tab and `true` for all other tabs', async () => {
+ await createComponent({ route: { name: ACTIVE_TAB_SHARED, params: { group: 'foo/bar' } } });
+
+ expect(findTabPanels().at(0).vm.$attrs.lazy).toBe(true);
+ expect(findTabPanels().at(1).vm.$attrs.lazy).toBe(false);
+ expect(findTabPanels().at(2).vm.$attrs.lazy).toBe(true);
+ });
+
describe.each([
[
{ name: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, params: { group: 'foo/bar/baz' } },
diff --git a/spec/frontend/vue_shared/components/gitlab_version_check_spec.js b/spec/frontend/vue_shared/components/gitlab_version_check_spec.js
index 5f63d38c532..38f28837cc1 100644
--- a/spec/frontend/vue_shared/components/gitlab_version_check_spec.js
+++ b/spec/frontend/vue_shared/components/gitlab_version_check_spec.js
@@ -1,6 +1,6 @@
import { GlBadge } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { mockTracking } from 'helpers/tracking_helper';
import { helpPagePath } from '~/helpers/help_page_helper';
@@ -27,7 +27,7 @@ describe('GitlabVersionCheck', () => {
mock = new MockAdapter(axios);
mock.onGet().replyOnce(response.code, response.res);
- wrapper = shallowMount(GitlabVersionCheck);
+ wrapper = shallowMountExtended(GitlabVersionCheck);
};
const dummyGon = {
@@ -42,6 +42,7 @@ describe('GitlabVersionCheck', () => {
window.gon = originalGon;
});
+ const findGlBadgeClickWrapper = () => wrapper.findByTestId('badge-click-wrapper');
const findGlBadge = () => wrapper.findComponent(GlBadge);
describe.each`
@@ -81,7 +82,8 @@ describe('GitlabVersionCheck', () => {
await waitForPromises(); // Ensure we wrap up the axios call
});
- it(`does${renders ? '' : ' not'} render GlBadge`, () => {
+ it(`does${renders ? '' : ' not'} render Badge Click Wrapper and GlBadge`, () => {
+ expect(findGlBadgeClickWrapper().exists()).toBe(renders);
expect(findGlBadge().exists()).toBe(renders);
});
});
@@ -110,9 +112,9 @@ describe('GitlabVersionCheck', () => {
expect(findGlBadge().attributes('variant')).toBe(expectedUI.variant);
});
- it(`tracks rendered_version_badge with status ${expectedUI.variant}`, () => {
+ it(`tracks rendered_version_badge with label ${expectedUI.title}`, () => {
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'rendered_version_badge', {
- label: expectedUI.variant,
+ label: expectedUI.title,
});
});
@@ -120,11 +122,11 @@ describe('GitlabVersionCheck', () => {
expect(findGlBadge().attributes('href')).toBe(UPGRADE_DOCS_URL);
});
- it(`tracks click_version_badge with status ${expectedUI.variant} when badge is clicked`, async () => {
- await findGlBadge().vm.$emit('click');
+ it(`tracks click_version_badge with label ${expectedUI.title} when badge is clicked`, async () => {
+ await findGlBadgeClickWrapper().trigger('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_version_badge', {
- label: expectedUI.variant,
+ label: expectedUI.title,
});
});
});
diff --git a/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb b/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb
index 412be5f16a4..727db7e2361 100644
--- a/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb
+++ b/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddProject do
describe '#resolve' do
let_it_be(:project) do
- create(:project, ci_job_token_scope_enabled: true).tap(&:save!)
+ create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!)
end
let_it_be(:target_project) { create(:project) }
diff --git a/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb b/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
index 0e706ea6e0c..d399e73f394 100644
--- a/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
+++ b/spec/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Mutations::Ci::JobTokenScope::RemoveProject do
end
describe '#resolve' do
- let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
let_it_be(:target_project) { create(:project) }
let_it_be(:link) do
diff --git a/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb b/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb
index 1bfd6fbf6b9..59ece15b745 100644
--- a/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/job_token_scope_resolver_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Resolvers::Ci::JobTokenScopeResolver do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
- let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
specify do
expect(described_class).to have_nullable_graphql_type(::Types::Ci::JobTokenScopeType)
@@ -21,7 +21,7 @@ RSpec.describe Resolvers::Ci::JobTokenScopeResolver do
end
it 'returns the same project in the allow list of projects for the Ci Job Token when scope is not enabled' do
- allow(project).to receive(:ci_job_token_scope_enabled?).and_return(false)
+ allow(project).to receive(:ci_outbound_job_token_scope_enabled?).and_return(false)
expect(resolve_scope.all_projects).to contain_exactly(project)
end
@@ -40,7 +40,7 @@ RSpec.describe Resolvers::Ci::JobTokenScopeResolver do
context 'when job token scope is disabled' do
before do
- project.update!(ci_job_token_scope_enabled: false)
+ project.update!(ci_outbound_job_token_scope_enabled: false)
end
it 'resolves projects' do
diff --git a/spec/graphql/types/ci/job_token_scope_type_spec.rb b/spec/graphql/types/ci/job_token_scope_type_spec.rb
index 18f4d762d1e..569b59d6c70 100644
--- a/spec/graphql/types/ci/job_token_scope_type_spec.rb
+++ b/spec/graphql/types/ci/job_token_scope_type_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
end
describe 'query' do
- let(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
let_it_be(:current_user) { create(:user) }
let(:query) do
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index f2cdbc35f26..ccc4f1f7149 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -61,6 +61,8 @@ issues:
- requirement
- incident_management_issuable_escalation_status
- incident_management_timeline_events
+- incident_management_timeline_event_tags
+- incident_management_timeline_event_links
- pending_escalations
- customer_relations_contacts
- issue_customer_relations_contacts
@@ -622,6 +624,7 @@ project:
- incident_management_oncall_rotations
- incident_management_escalation_policies
- incident_management_issuable_escalation_statuses
+- incident_management_timeline_event_tags
- debian_distributions
- merge_request_metrics
- security_orchestration_policy_configuration
diff --git a/spec/lib/gitlab/json_spec.rb b/spec/lib/gitlab/json_spec.rb
index 7c093049e18..73276288765 100644
--- a/spec/lib/gitlab/json_spec.rb
+++ b/spec/lib/gitlab/json_spec.rb
@@ -8,6 +8,12 @@ RSpec.describe Gitlab::Json do
end
describe ".parse" do
+ it "is aliased" do
+ [:parse!, :load, :decode].each do |method|
+ expect(described_class.method(method)).to eq(described_class.method(:parse))
+ end
+ end
+
context "legacy_mode is disabled by default" do
it "parses an object" do
expect(subject.parse('{ "foo": "bar" }')).to eq({ "foo" => "bar" })
@@ -178,6 +184,10 @@ RSpec.describe Gitlab::Json do
{ test: true, "foo.bar" => "baz", is_json: 1, some: [1, 2, 3] }
end
+ it "is aliased" do
+ expect(described_class.method(:encode)).to eq(described_class.method(:generate))
+ end
+
it "generates JSON" do
expected_string = <<~STR.chomp
{"test":true,"foo.bar":"baz","is_json":1,"some":[1,2,3]}
diff --git a/spec/models/ci/job_token/scope_spec.rb b/spec/models/ci/job_token/scope_spec.rb
index 4b95adf8476..1e3f6d044d2 100644
--- a/spec/models/ci/job_token/scope_spec.rb
+++ b/spec/models/ci/job_token/scope_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::JobToken::Scope do
- let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
let(:scope) { described_class.new(project) }
@@ -53,7 +53,7 @@ RSpec.describe Ci::JobToken::Scope do
context 'when project scope setting is disabled' do
before do
- project.ci_job_token_scope_enabled = false
+ project.ci_outbound_job_token_scope_enabled = false
end
it 'considers any project to be part of the scope' do
diff --git a/spec/models/incident_management/timeline_event_spec.rb b/spec/models/incident_management/timeline_event_spec.rb
index c68bcd4a9ed..d288cc1a75d 100644
--- a/spec/models/incident_management/timeline_event_spec.rb
+++ b/spec/models/incident_management/timeline_event_spec.rb
@@ -13,6 +13,12 @@ RSpec.describe IncidentManagement::TimelineEvent do
it { is_expected.to belong_to(:incident) }
it { is_expected.to belong_to(:updated_by_user) }
it { is_expected.to belong_to(:promoted_from_note) }
+ it { is_expected.to have_many(:timeline_event_tag_links).class_name('IncidentManagement::TimelineEventTagLink') }
+
+ it do
+ is_expected.to have_many(:timeline_event_tags)
+ .class_name('IncidentManagement::TimelineEventTag').through(:timeline_event_tag_links)
+ end
end
describe 'validations' do
diff --git a/spec/models/incident_management/timeline_event_tag_link_spec.rb b/spec/models/incident_management/timeline_event_tag_link_spec.rb
new file mode 100644
index 00000000000..fe31a6604c1
--- /dev/null
+++ b/spec/models/incident_management/timeline_event_tag_link_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IncidentManagement::TimelineEventTagLink do
+ describe 'associations' do
+ it { is_expected.to belong_to(:timeline_event) }
+ it { is_expected.to belong_to(:timeline_event_tag) }
+ end
+end
diff --git a/spec/models/incident_management/timeline_event_tag_spec.rb b/spec/models/incident_management/timeline_event_tag_spec.rb
new file mode 100644
index 00000000000..cff8ad8469f
--- /dev/null
+++ b/spec/models/incident_management/timeline_event_tag_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IncidentManagement::TimelineEventTag do
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to have_many(:timeline_event_tag_links).class_name('IncidentManagement::TimelineEventTagLink') }
+
+ it {
+ is_expected.to have_many(:timeline_events)
+ .class_name('IncidentManagement::TimelineEvent').through(:timeline_event_tag_links)
+ }
+ end
+
+ describe 'validations' do
+ subject { build(:incident_management_timeline_event_tag) }
+
+ it { is_expected.to validate_presence_of(:name) }
+ it { is_expected.to validate_length_of(:name).is_at_most(255) }
+ it { is_expected.to validate_uniqueness_of(:name).scoped_to([:project_id]) }
+
+ it { is_expected.to allow_value('Test tag 1').for(:name) }
+ it { is_expected.not_to allow_value('Test tag, 1').for(:name) }
+ it { is_expected.not_to allow_value('').for(:name) }
+ it { is_expected.not_to allow_value('s' * 256).for(:name) }
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 767cda952b0..75887e49dc9 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -149,6 +149,7 @@ RSpec.describe Project, factory_default: :keep do
it { is_expected.to have_one(:build_artifacts_size_refresh).class_name('Projects::BuildArtifactsSizeRefresh') }
it { is_expected.to have_many(:project_callouts).class_name('Users::ProjectCallout').with_foreign_key(:project_id) }
it { is_expected.to have_many(:pipeline_metadata).class_name('Ci::PipelineMetadata') }
+ it { is_expected.to have_many(:incident_management_timeline_event_tags).class_name('IncidentManagement::TimelineEventTag') }
# GitLab Pages
it { is_expected.to have_many(:pages_domains) }
@@ -845,6 +846,8 @@ RSpec.describe Project, factory_default: :keep do
end
describe 'delegation' do
+ let_it_be(:project) { create(:project) }
+
[:add_guest, :add_reporter, :add_developer, :add_maintainer, :add_member, :add_members].each do |method|
it { is_expected.to delegate_method(method).to(:team) }
end
@@ -887,8 +890,24 @@ RSpec.describe Project, factory_default: :keep do
end
include_examples 'ci_cd_settings delegation' do
- # Skip attributes defined in EE code
+ let(:attributes_with_prefix) do
+ {
+ 'group_runners_enabled' => '',
+ 'default_git_depth' => 'ci_',
+ 'forward_deployment_enabled' => 'ci_',
+ 'keep_latest_artifact' => '',
+ 'restrict_user_defined_variables' => '',
+ 'runner_token_expiration_interval' => '',
+ 'separated_caches' => 'ci_',
+ 'opt_in_jwt' => 'ci_',
+ 'allow_fork_pipelines_to_run_in_parent_project' => 'ci_',
+ 'inbound_job_token_scope_enabled' => 'ci_',
+ 'job_token_scope_enabled' => 'ci_outbound_'
+ }
+ end
+
let(:exclude_attributes) do
+ # Skip attributes defined in EE code
%w(
merge_pipelines_enabled
merge_trains_enabled
@@ -909,8 +928,8 @@ RSpec.describe Project, factory_default: :keep do
end
end
- describe '#ci_job_token_scope_enabled?' do
- it_behaves_like 'a ci_cd_settings predicate method', prefix: 'ci_' do
+ describe '#ci_outbound_job_token_scope_enabled?' do
+ it_behaves_like 'a ci_cd_settings predicate method', prefix: 'ci_outbound_' do
let(:delegated_method) { :job_token_scope_enabled? }
end
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index a7662634793..40ee2e662b2 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -2437,7 +2437,7 @@ RSpec.describe ProjectPolicy do
before do
current_user.set_ci_job_token_scope!(job)
current_user.external = external_user
- scope_project.update!(ci_job_token_scope_enabled: token_scope_enabled)
+ scope_project.update!(ci_outbound_job_token_scope_enabled: token_scope_enabled)
end
it "enforces the expected permissions" do
diff --git a/spec/requests/api/graphql/mutations/ci/job/artifacts_destroy_spec.rb b/spec/requests/api/graphql/mutations/ci/job/artifacts_destroy_spec.rb
new file mode 100644
index 00000000000..bdad80995ea
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/job/artifacts_destroy_spec.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'JobArtifactsDestroy' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:job) { create(:ci_build) }
+
+ let(:mutation) do
+ variables = {
+ id: job.to_global_id.to_s
+ }
+ graphql_mutation(:job_artifacts_destroy, variables, <<~FIELDS)
+ job {
+ name
+ }
+ destroyedArtifactsCount
+ errors
+ FIELDS
+ end
+
+ before do
+ create(:ci_job_artifact, :archive, job: job)
+ create(:ci_job_artifact, :junit, job: job)
+ end
+
+ context 'when the user is not allowed to destroy the job artifacts' do
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(graphql_errors).not_to be_empty
+ expect(job.reload.job_artifacts.count).to be(2)
+ end
+ end
+
+ context 'when the user is allowed to destroy the job artifacts' do
+ before do
+ job.project.add_maintainer(user)
+ end
+
+ it 'destroys the job artifacts and returns the expected data' do
+ expected_data = {
+ 'jobArtifactsDestroy' => {
+ 'errors' => [],
+ 'destroyedArtifactsCount' => 2,
+ 'job' => {
+ 'name' => job.name
+ }
+ }
+ }
+
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_data).to eq(expected_data)
+ expect(job.reload.job_artifacts.count).to be(0)
+ end
+
+ context 'when the the project this job belongs to is undergoing stats refresh' do
+ it 'destroys no artifacts and returns the correct error' do
+ allow_next_found_instance_of(Project) do |project|
+ allow(project).to receive(:refreshing_build_artifacts_size?).and_return(true)
+ end
+
+ expected_data = {
+ 'jobArtifactsDestroy' => {
+ 'errors' => ['Action temporarily disabled. The project this job belongs to is undergoing stats refresh.'],
+ 'destroyedArtifactsCount' => 0,
+ 'job' => {
+ 'name' => job.name
+ }
+ }
+ }
+
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_data).to eq(expected_data)
+ expect(job.reload.job_artifacts.count).to be(2)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
index 5269c60b50a..b2f84ab2869 100644
--- a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'CiJobTokenScopeAddProject' do
include GraphqlHelpers
- let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
let_it_be(:target_project) { create(:project) }
let(:variables) do
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
index b62291d1ebd..2b0adf89f40 100644
--- a/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'CiJobTokenScopeRemoveProject' do
include GraphqlHelpers
- let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
let_it_be(:target_project) { create(:project) }
let_it_be(:link) do
diff --git a/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
index 6cca618726b..c808cf5ede9 100644
--- a/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'ProjectCiCdSettingsUpdate' do
let_it_be(:project) do
create(:project,
keep_latest_artifact: true,
- ci_job_token_scope_enabled: true,
+ ci_outbound_job_token_scope_enabled: true,
ci_inbound_job_token_scope_enabled: true
).tap(&:save!)
end
@@ -66,7 +66,7 @@ RSpec.describe 'ProjectCiCdSettingsUpdate' do
project.reload
expect(response).to have_gitlab_http_status(:success)
- expect(project.ci_job_token_scope_enabled).to eq(false)
+ expect(project.ci_outbound_job_token_scope_enabled).to eq(false)
end
it 'does not update job_token_scope_enabled if not specified' do
@@ -77,7 +77,7 @@ RSpec.describe 'ProjectCiCdSettingsUpdate' do
project.reload
expect(response).to have_gitlab_http_status(:success)
- expect(project.ci_job_token_scope_enabled).to eq(true)
+ expect(project.ci_outbound_job_token_scope_enabled).to eq(true)
end
describe 'inbound_job_token_scope_enabled' do
diff --git a/spec/services/ci/job_artifacts/delete_service_spec.rb b/spec/services/ci/job_artifacts/delete_service_spec.rb
index 62a755eb44a..78e8be48255 100644
--- a/spec/services/ci/job_artifacts/delete_service_spec.rb
+++ b/spec/services/ci/job_artifacts/delete_service_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe Ci::JobArtifacts::DeleteService do
result = service.execute
expect(result).to be_success
+ expect(result[:destroyed_artifacts_count]).to be(2)
end
it 'deletes erasable artifacts' do
@@ -24,7 +25,7 @@ RSpec.describe Ci::JobArtifacts::DeleteService do
expect { service.execute }.not_to change { build.has_trace? }.from(true)
end
- context 'when project is undergoing statistics refresh' do
+ context 'when project is undergoing stats refresh' do
before do
allow(build.project).to receive(:refreshing_build_artifacts_size?).and_return(true)
end
@@ -36,6 +37,30 @@ RSpec.describe Ci::JobArtifacts::DeleteService do
service.execute
end
+
+ it 'returns an error response with the correct message and reason' do
+ result = service.execute
+
+ expect(result).to be_error
+ expect(result[:message]).to be('Action temporarily disabled. ' \
+ 'The project this job belongs to is undergoing stats refresh.')
+ expect(result[:reason]).to be(:project_stats_refresh)
+ end
+ end
+
+ context 'when an error response is received from DestroyBatchService' do
+ before do
+ allow_next_instance_of(Ci::JobArtifacts::DestroyBatchService) do |service|
+ allow(service).to receive(:execute).and_return({ status: :error, message: 'something went wrong' })
+ end
+ end
+
+ it 'returns an error response with the correct message' do
+ result = service.execute
+
+ expect(result).to be_error
+ expect(result[:message]).to be('something went wrong')
+ end
end
end
end
diff --git a/spec/services/ci/job_token_scope/add_project_service_spec.rb b/spec/services/ci/job_token_scope/add_project_service_spec.rb
index bb6df4268dd..bf7df3a5595 100644
--- a/spec/services/ci/job_token_scope/add_project_service_spec.rb
+++ b/spec/services/ci/job_token_scope/add_project_service_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Ci::JobTokenScope::AddProjectService do
let(:service) { described_class.new(project, current_user) }
- let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
let_it_be(:target_project) { create(:project) }
let_it_be(:current_user) { create(:user) }
diff --git a/spec/services/ci/job_token_scope/remove_project_service_spec.rb b/spec/services/ci/job_token_scope/remove_project_service_spec.rb
index 155e60ac48e..c3f9081cbd8 100644
--- a/spec/services/ci/job_token_scope/remove_project_service_spec.rb
+++ b/spec/services/ci/job_token_scope/remove_project_service_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Ci::JobTokenScope::RemoveProjectService do
let(:service) { described_class.new(project, current_user) }
- let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
let_it_be(:target_project) { create(:project) }
let_it_be(:current_user) { create(:user) }
diff --git a/spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb b/spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb
index c92e819db19..3caf58da4d2 100644
--- a/spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb
+++ b/spec/support/shared_examples/models/project_ci_cd_settings_shared_examples.rb
@@ -5,12 +5,14 @@ RSpec.shared_examples 'ci_cd_settings delegation' do
context 'when ci_cd_settings is destroyed but project is not' do
it 'allows methods delegated to ci_cd_settings to be nil', :aggregate_failures do
- project = create(:project)
attributes = project.ci_cd_settings.attributes.keys - %w(id project_id) - exclude_attributes
+
+ expect(attributes).to match_array(attributes_with_prefix.keys)
+
project.ci_cd_settings.destroy!
project.reload
- attributes.each do |attr|
- method = project.respond_to?("ci_#{attr}") ? "ci_#{attr}" : attr
+ attributes_with_prefix.each do |attr, prefix|
+ method = "#{prefix}#{attr}"
expect(project.send(method)).to be_nil, "#{attr} was not nil"
end
end
@@ -20,8 +22,6 @@ end
RSpec.shared_examples 'a ci_cd_settings predicate method' do |prefix: ''|
using RSpec::Parameterized::TableSyntax
- let_it_be(:project) { create(:project) }
-
context 'when ci_cd_settings is nil' do
before do
allow(project).to receive(:ci_cd_settings).and_return(nil)