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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml11
-rw-r--r--.rubocop.yml2
-rw-r--r--.rubocop_todo/rspec/missing_feature_category.yml1
-rw-r--r--app/assets/javascripts/environments/components/stop_environment_modal.vue5
-rw-r--r--app/assets/javascripts/google_cloud/aiml/service_table.vue115
-rw-r--r--app/assets/javascripts/super_sidebar/components/nav_item.vue2
-rw-r--r--app/assets/javascripts/token_access/components/opt_in_jwt.vue125
-rw-r--r--app/assets/javascripts/token_access/components/token_access_app.vue3
-rw-r--r--app/assets/javascripts/token_access/constants.js14
-rw-r--r--app/assets/javascripts/token_access/graphql/mutations/update_opt_in_jwt.mutation.graphql8
-rw-r--r--app/assets/javascripts/token_access/graphql/queries/get_opt_in_jwt_setting.query.graphql8
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_add_note.vue18
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_discussion.vue9
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_note.vue15
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue1
-rw-r--r--app/assets/javascripts/work_items/components/work_item_notes.vue32
-rw-r--r--app/assets/javascripts/work_items/graphql/cache_utils.js34
-rw-r--r--app/assets/javascripts/work_items/graphql/notes/work_item_notes.query.graphql27
-rw-r--r--app/assets/javascripts/work_items/utils.js6
-rw-r--r--app/mailers/emails/service_desk.rb5
-rw-r--r--app/models/ci/pipeline_variable.rb3
-rw-r--r--app/views/projects/edit.html.haml1
-rw-r--r--app/views/projects/hooks/index.html.haml1
-rw-r--r--app/views/projects/settings/access_tokens/index.html.haml1
-rw-r--r--app/views/projects/settings/ci_cd/show.html.haml1
-rw-r--r--app/views/projects/settings/integrations/index.html.haml1
-rw-r--r--app/views/projects/settings/merge_requests/show.html.haml1
-rw-r--r--app/views/projects/settings/operations/show.html.haml1
-rw-r--r--app/views/projects/settings/packages_and_registries/show.html.haml1
-rw-r--r--app/views/projects/settings/repository/show.html.haml1
-rw-r--r--app/views/projects/usage_quotas/index.html.haml1
-rw-r--r--config/feature_flags/development/jira_dvcs_end_of_life_amnesty.yml2
-rw-r--r--config/feature_flags/development/use_replica_for_mailers.yml8
-rw-r--r--config/initializers/mailer_retries.rb2
-rw-r--r--config/sidekiq_queues.yml2
-rw-r--r--db/docs/deleted_tables/analytics_cycle_analytics_project_stages.yml (renamed from db/docs/analytics_cycle_analytics_project_stages.yml)2
-rw-r--r--db/docs/deleted_tables/analytics_cycle_analytics_project_value_streams.yml (renamed from db/docs/analytics_cycle_analytics_project_value_streams.yml)2
-rw-r--r--db/migrate/20230427065641_initialize_conversion_of_ci_pipeline_variables.rb16
-rw-r--r--db/post_migrate/20230427065942_backfill_ci_pipeline_variables_for_bigint_conversion.rb16
-rw-r--r--db/post_migrate/20230427190005_drop_foreign_keys_from_cycle_analytics_unused_tables.rb67
-rw-r--r--db/post_migrate/20230427194552_drop_cycle_analytics_unused_tables.rb83
-rw-r--r--db/schema_migrations/202304270656411
-rw-r--r--db/schema_migrations/202304270659421
-rw-r--r--db/schema_migrations/202304271900051
-rw-r--r--db/schema_migrations/202304271945521
-rw-r--r--db/structure.sql103
-rw-r--r--doc/ci/secrets/id_token_authentication.md10
-rw-r--r--doc/ci/yaml/index.md7
-rw-r--r--doc/development/documentation/topic_types/tutorial.md6
-rw-r--r--doc/integration/jira/development_panel.md5
-rw-r--r--doc/integration/jira/dvcs/index.md5
-rw-r--r--doc/user/application_security/dependency_scanning/index.md28
-rw-r--r--doc/user/profile/index.md14
-rw-r--r--locale/gitlab.pot51
-rwxr-xr-xscripts/verify-tff-mapping6
-rw-r--r--spec/features/projects/environments/environments_spec.rb20
-rw-r--r--spec/frontend/google_cloud/aiml/service_table_spec.js34
-rw-r--r--spec/frontend/search/sidebar/components/scope_new_navigation_spec.js2
-rw-r--r--spec/frontend/token_access/mock_data.js26
-rw-r--r--spec/frontend/token_access/opt_in_jwt_spec.js144
-rw-r--r--spec/frontend/token_access/token_access_app_spec.js6
-rw-r--r--spec/frontend/work_items/components/notes/work_item_add_note_spec.js59
-rw-r--r--spec/frontend/work_items/components/notes/work_item_discussion_spec.js6
-rw-r--r--spec/frontend/work_items/components/notes/work_item_note_spec.js11
-rw-r--r--spec/frontend/work_items/components/work_item_notes_spec.js62
-rw-r--r--spec/frontend/work_items/mock_data.js665
-rw-r--r--spec/mailers/emails/service_desk_spec.rb9
-rw-r--r--spec/rubocop/cop/rspec/httparty_basic_auth_spec.rb (renamed from spec/rubocop/cop/rspec/htt_party_basic_auth_spec.rb)2
-rw-r--r--tests.yml4
69 files changed, 888 insertions, 1055 deletions
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 2d1e2d5918f..87641327d97 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -1420,6 +1420,10 @@
- <<: *if-force-ci
when: manual
allow_failure: true
+ - <<: *if-merge-request
+ changes: *code-patterns
+ when: manual
+ allow_failure: true
.qa:rules:package-and-test-schedule:
rules:
@@ -1437,10 +1441,6 @@
rules:
- !reference [".qa:rules:package-and-test-common", rules]
- !reference [".qa:rules:package-and-test-schedule", rules]
- - <<: *if-merge-request
- changes: *code-patterns
- when: manual
- allow_failure: true
.qa:rules:package-and-test-ce:
rules:
@@ -1465,9 +1465,6 @@
when: never
- !reference [".qa:rules:package-and-test-common", rules]
- !reference [".qa:rules:package-and-test-schedule", rules]
- - <<: *if-merge-request
- changes: *code-patterns
- allow_failure: true
.qa:rules:package-and-test-sidebar:
rules:
diff --git a/.rubocop.yml b/.rubocop.yml
index c9c64a39288..6108b2981e9 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -151,6 +151,8 @@ RSpec/FilePath:
- 'ee/spec/frontend/fixtures/*'
- 'spec/requests/api/v3/*'
- 'spec/fixtures/**/*'
+ CustomTransform:
+ HTTPartyBasicAuth: httparty_basic_auth
# Configuration parameters: AllowSubject.
RSpec/MultipleMemoizedHelpers:
diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml
index 205f633e9cb..966e80de174 100644
--- a/.rubocop_todo/rspec/missing_feature_category.yml
+++ b/.rubocop_todo/rspec/missing_feature_category.yml
@@ -5453,7 +5453,6 @@ RSpec/MissingFeatureCategory:
- 'spec/rubocop/cop/rspec/factory_bot/inline_association_spec.rb'
- 'spec/rubocop/cop/rspec/factory_bot/strategy_in_callback_spec.rb'
- 'spec/rubocop/cop/rspec/have_gitlab_http_status_spec.rb'
- - 'spec/rubocop/cop/rspec/htt_party_basic_auth_spec.rb'
- 'spec/rubocop/cop/rspec/modify_sidekiq_middleware_spec.rb'
- 'spec/rubocop/cop/rspec/top_level_describe_path_spec.rb'
- 'spec/rubocop/cop/rspec/web_mock_enable_spec.rb'
diff --git a/app/assets/javascripts/environments/components/stop_environment_modal.vue b/app/assets/javascripts/environments/components/stop_environment_modal.vue
index dc0c5dc0f46..95ece2b653e 100644
--- a/app/assets/javascripts/environments/components/stop_environment_modal.vue
+++ b/app/assets/javascripts/environments/components/stop_environment_modal.vue
@@ -41,6 +41,9 @@ export default {
text: __('Cancel'),
};
},
+ hasStopAction() {
+ return this.graphql ? this.environment.hasStopAction : this.environment.has_stop_action;
+ },
},
methods: {
@@ -81,7 +84,7 @@ export default {
<p>{{ s__('Environments|Are you sure you want to stop this environment?') }}</p>
- <div v-if="!environment.has_stop_action" class="warning_message">
+ <div v-if="!hasStopAction" class="warning_message">
<p>
<gl-sprintf
:message="
diff --git a/app/assets/javascripts/google_cloud/aiml/service_table.vue b/app/assets/javascripts/google_cloud/aiml/service_table.vue
new file mode 100644
index 00000000000..b53baaa5c6f
--- /dev/null
+++ b/app/assets/javascripts/google_cloud/aiml/service_table.vue
@@ -0,0 +1,115 @@
+<script>
+import { GlButton, GlTable } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
+const KEY_VISION_AI = 'key-vision-ai';
+const KEY_NATURAL_LANGUAGE_AI = 'key-natural-language-ai';
+const KEY_TRANSLATION_AI = 'key-translation-ai';
+
+const i18n = {
+ visionAi: s__('CloudSeed|Vision AI'),
+ visionAiDescription: s__(
+ 'CloudSeed|Derive insights from your images in the cloud or at the edge',
+ ),
+ naturalLanguageAi: s__('CloudSeed|Language AI'),
+ naturalLanguageAiDescription: s__(
+ 'CloudSeed|Derive insights from unstructured text using Google machine learning',
+ ),
+ translationAi: s__('CloudSeed|Translation AI'),
+ translationAiDescription: s__(
+ 'CloudSeed|Make your content and apps multilingual with fast, dynamic machine translation',
+ ),
+ aiml: s__('CloudSeed|AI / ML'),
+ aimlDescription: s__(
+ "CloudSeed|Google Cloud's AI tools are armed with the best of Google's research and technology to help developers focus exclusively on solving problems that matter",
+ ),
+ configureViaMergeRequest: s__('CloudSeed|Configure via Merge Request'),
+ service: s__('CloudSeed|Service'),
+ description: s__('CloudSeed|Description'),
+};
+
+export default {
+ components: { GlButton, GlTable },
+ props: {
+ visionAiUrl: {
+ type: String,
+ required: true,
+ },
+ languageAiUrl: {
+ type: String,
+ required: true,
+ },
+ translationAiUrl: {
+ type: String,
+ required: true,
+ },
+ },
+ methods: {
+ actionUrl(key) {
+ switch (key) {
+ case KEY_VISION_AI:
+ return this.visionAiUrl;
+ case KEY_NATURAL_LANGUAGE_AI:
+ return this.languageAiUrl;
+ case KEY_TRANSLATION_AI:
+ return this.translationAiUrl;
+ default:
+ return '#';
+ }
+ },
+ },
+ fields: [
+ { key: 'title', label: i18n.service },
+ { key: 'description', label: i18n.description },
+ { key: 'action', label: '' },
+ ],
+ items: [
+ {
+ title: i18n.naturalLanguageAi,
+ description: i18n.naturalLanguageAiDescription,
+ action: {
+ key: KEY_NATURAL_LANGUAGE_AI,
+ testId: 'button-natural-language-ai',
+ title: i18n.configureViaMergeRequest,
+ },
+ },
+ {
+ title: i18n.translationAi,
+ description: i18n.translationAiDescription,
+ action: {
+ key: KEY_TRANSLATION_AI,
+ testId: 'button-translation-ai',
+ title: i18n.configureViaMergeRequest,
+ disabled: true,
+ },
+ },
+ {
+ title: i18n.visionAi,
+ description: i18n.visionAiDescription,
+ action: {
+ key: KEY_VISION_AI,
+ testId: 'button-vision-ai',
+ title: i18n.configureViaMergeRequest,
+ },
+ },
+ ],
+ i18n,
+};
+</script>
+<template>
+ <div class="gl-mx-3">
+ <h2 class="gl-font-size-h2">{{ $options.i18n.aiml }}</h2>
+ <p>{{ $options.i18n.aimlDescription }}</p>
+ <gl-table :fields="$options.fields" :items="$options.items">
+ <template #cell(action)="{ value }">
+ <gl-button
+ :disabled="value.disabled"
+ :href="actionUrl(value.key)"
+ :data-testid="value.testId"
+ >
+ {{ value.title }}
+ </gl-button>
+ </template>
+ </gl-table>
+ </div>
+</template>
diff --git a/app/assets/javascripts/super_sidebar/components/nav_item.vue b/app/assets/javascripts/super_sidebar/components/nav_item.vue
index 55146610d5f..a4bbd87b34a 100644
--- a/app/assets/javascripts/super_sidebar/components/nav_item.vue
+++ b/app/assets/javascripts/super_sidebar/components/nav_item.vue
@@ -129,7 +129,7 @@ export default {
/>
</slot>
</div>
- <div class="gl-pr-3 gl-text-gray-900 gl-truncate-end">
+ <div class="gl-pr-8 gl-text-gray-900 gl-truncate-end">
{{ item.title }}
<div v-if="item.subtitle" class="gl-font-sm gl-text-gray-500 gl-truncate-end">
{{ item.subtitle }}
diff --git a/app/assets/javascripts/token_access/components/opt_in_jwt.vue b/app/assets/javascripts/token_access/components/opt_in_jwt.vue
deleted file mode 100644
index 18636a26f46..00000000000
--- a/app/assets/javascripts/token_access/components/opt_in_jwt.vue
+++ /dev/null
@@ -1,125 +0,0 @@
-<script>
-import { GlLink, GlLoadingIcon, GlSprintf, GlToggle } from '@gitlab/ui';
-import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
-import { createAlert } from '~/alert';
-import { __, s__ } from '~/locale';
-import updateOptInJwtMutation from '../graphql/mutations/update_opt_in_jwt.mutation.graphql';
-import getOptInJwtSettingQuery from '../graphql/queries/get_opt_in_jwt_setting.query.graphql';
-import { LIMIT_JWT_ACCESS_SNIPPET, OPT_IN_JWT_HELP_LINK } from '../constants';
-
-export default {
- i18n: {
- labelText: s__('CICD|Limit JSON Web Token (JWT) access'),
- helpText: s__(
- `CICD|The JWT must be manually declared in each job that needs it. When disabled, the token is always available in all jobs in the pipeline. %{linkStart}Learn more.%{linkEnd}`,
- ),
- expandedText: s__(
- 'CICD|Use the %{codeStart}secrets%{codeEnd} keyword to configure a job with a JWT.',
- ),
- copyToClipboard: __('Copy to clipboard'),
- fetchError: s__('CICD|There was a problem fetching the token access settings.'),
- updateError: s__('CICD|An error occurred while update the setting. Please try again.'),
- },
- components: {
- CodeInstruction,
- GlLink,
- GlLoadingIcon,
- GlSprintf,
- GlToggle,
- },
- inject: ['fullPath'],
- apollo: {
- optInJwt: {
- query: getOptInJwtSettingQuery,
- variables() {
- return {
- fullPath: this.fullPath,
- };
- },
- update({
- project: {
- ciCdSettings: { optInJwt },
- },
- }) {
- return optInJwt;
- },
- error() {
- createAlert({ message: this.$options.i18n.fetchError });
- },
- },
- },
- data() {
- return {
- optInJwt: null,
- };
- },
- computed: {
- isLoading() {
- return this.$apollo.queries.optInJwt.loading;
- },
- },
- methods: {
- async updateOptInJwt() {
- try {
- const {
- data: {
- projectCiCdSettingsUpdate: { errors },
- },
- } = await this.$apollo.mutate({
- mutation: updateOptInJwtMutation,
- variables: {
- input: {
- fullPath: this.fullPath,
- optInJwt: this.optInJwt,
- },
- },
- });
-
- if (errors.length) {
- throw new Error(errors[0]);
- }
- } catch (error) {
- createAlert({ message: this.$options.i18n.updateError });
- }
- },
- },
- OPT_IN_JWT_HELP_LINK,
- LIMIT_JWT_ACCESS_SNIPPET,
-};
-</script>
-<template>
- <div>
- <gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-5" />
- <template v-else>
- <gl-toggle
- v-model="optInJwt"
- class="gl-mt-5"
- :label="$options.i18n.labelText"
- @change="updateOptInJwt"
- >
- <template #help>
- <gl-sprintf :message="$options.i18n.helpText">
- <template #link="{ content }">
- <gl-link :href="$options.OPT_IN_JWT_HELP_LINK" class="inline-link" target="_blank">
- {{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- </template>
- </gl-toggle>
- <div v-if="optInJwt" class="gl-mt-5" data-testid="opt-in-jwt-expanded-section">
- <gl-sprintf :message="$options.i18n.expandedText">
- <template #code="{ content }">
- <code>{{ content }}</code>
- </template>
- </gl-sprintf>
- <code-instruction
- class="gl-mt-3"
- :instruction="$options.LIMIT_JWT_ACCESS_SNIPPET"
- :copy-text="$options.i18n.copyToClipboard"
- multiline
- />
- </div>
- </template>
- </div>
-</template>
diff --git a/app/assets/javascripts/token_access/components/token_access_app.vue b/app/assets/javascripts/token_access/components/token_access_app.vue
index beaa564db51..167eebc8d9b 100644
--- a/app/assets/javascripts/token_access/components/token_access_app.vue
+++ b/app/assets/javascripts/token_access/components/token_access_app.vue
@@ -1,14 +1,12 @@
<script>
import OutboundTokenAccess from './outbound_token_access.vue';
import InboundTokenAccess from './inbound_token_access.vue';
-import OptInJwt from './opt_in_jwt.vue';
export default {
name: 'TokenAccessApp',
components: {
OutboundTokenAccess,
InboundTokenAccess,
- OptInJwt,
},
};
</script>
@@ -16,6 +14,5 @@ export default {
<div>
<inbound-token-access class="gl-pb-5" />
<outbound-token-access class="gl-py-5" />
- <opt-in-jwt />
</div>
</template>
diff --git a/app/assets/javascripts/token_access/constants.js b/app/assets/javascripts/token_access/constants.js
deleted file mode 100644
index fb2128462f0..00000000000
--- a/app/assets/javascripts/token_access/constants.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { helpPagePath } from '~/helpers/help_page_helper';
-
-export const LIMIT_JWT_ACCESS_SNIPPET = `job_name:
- id_tokens:
- ID_TOKEN_1: # or any other name
- aud: "..." # sub-keyword to configure the token's audience
- secrets:
- TEST_SECRET:
- vault: db/prod
-`;
-
-export const OPT_IN_JWT_HELP_LINK = helpPagePath('ci/secrets/id_token_authentication', {
- anchor: 'automatic-id-token-authentication-with-hashicorp-vault',
-});
diff --git a/app/assets/javascripts/token_access/graphql/mutations/update_opt_in_jwt.mutation.graphql b/app/assets/javascripts/token_access/graphql/mutations/update_opt_in_jwt.mutation.graphql
deleted file mode 100644
index 7f0a6bc7d6d..00000000000
--- a/app/assets/javascripts/token_access/graphql/mutations/update_opt_in_jwt.mutation.graphql
+++ /dev/null
@@ -1,8 +0,0 @@
-mutation updateOptInJwt($input: ProjectCiCdSettingsUpdateInput!) {
- projectCiCdSettingsUpdate(input: $input) {
- ciCdSettings {
- optInJwt
- }
- errors
- }
-}
diff --git a/app/assets/javascripts/token_access/graphql/queries/get_opt_in_jwt_setting.query.graphql b/app/assets/javascripts/token_access/graphql/queries/get_opt_in_jwt_setting.query.graphql
deleted file mode 100644
index a1a216b7dc3..00000000000
--- a/app/assets/javascripts/token_access/graphql/queries/get_opt_in_jwt_setting.query.graphql
+++ /dev/null
@@ -1,8 +0,0 @@
-query getOptInJwtSetting($fullPath: ID!) {
- project(fullPath: $fullPath) {
- id
- ciCdSettings {
- optInJwt
- }
- }
-}
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue b/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue
index 6c27d5a87f0..cb682e8b944 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue
@@ -4,9 +4,8 @@ import Tracking from '~/tracking';
import { ASC } from '~/notes/constants';
import { __ } from '~/locale';
import { clearDraft } from '~/lib/utils/autosave';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { getWorkItemQuery } from '../../utils';
import createNoteMutation from '../../graphql/notes/create_work_item_note.mutation.graphql';
+import workItemByIidQuery from '../../graphql/work_item_by_iid.query.graphql';
import { TRACKING_CATEGORY_SHOW, i18n } from '../../constants';
import WorkItemNoteSignedOut from './work_item_note_signed_out.vue';
import WorkItemCommentLocked from './work_item_comment_locked.vue';
@@ -21,7 +20,7 @@ export default {
WorkItemCommentLocked,
WorkItemCommentForm,
},
- mixins: [glFeatureFlagMixin(), Tracking.mixin()],
+ mixins: [Tracking.mixin()],
props: {
workItemId: {
type: String,
@@ -31,11 +30,6 @@ export default {
type: String,
required: true,
},
- fetchByIid: {
- type: Boolean,
- required: false,
- default: false,
- },
queryVariables: {
type: Object,
required: true,
@@ -89,17 +83,15 @@ export default {
},
apollo: {
workItem: {
- query() {
- return getWorkItemQuery(this.fetchByIid);
- },
+ query: workItemByIidQuery,
variables() {
return this.queryVariables;
},
update(data) {
- return this.fetchByIid ? data.workspace.workItems.nodes[0] : data.workItem;
+ return data.workspace.workItems.nodes[0];
},
skip() {
- return !this.queryVariables.id && !this.queryVariables.iid;
+ return !this.queryVariables.iid;
},
error() {
this.$emit('error', i18n.fetchError);
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue b/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue
index b1ed5cb6b3a..e40c6296229 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue
@@ -35,11 +35,6 @@ export default {
type: String,
required: true,
},
- fetchByIid: {
- type: Boolean,
- required: false,
- default: false,
- },
discussion: {
type: Array,
required: true,
@@ -168,7 +163,6 @@ export default {
:work-item-id="workItemId"
:query-variables="queryVariables"
:full-path="fullPath"
- :fetch-by-iid="fetchByIid"
@startReplying="showReplyForm"
@deleteNote="$emit('deleteNote', note)"
@reportAbuse="$emit('reportAbuse', note)"
@@ -201,7 +195,6 @@ export default {
:can-set-work-item-metadata="canSetWorkItemMetadata"
:query-variables="queryVariables"
:full-path="fullPath"
- :fetch-by-iid="fetchByIid"
@startReplying="showReplyForm"
@deleteNote="$emit('deleteNote', note)"
@reportAbuse="$emit('reportAbuse', note)"
@@ -229,7 +222,6 @@ export default {
:can-set-work-item-metadata="canSetWorkItemMetadata"
:query-variables="queryVariables"
:full-path="fullPath"
- :fetch-by-iid="fetchByIid"
@startReplying="showReplyForm"
@deleteNote="$emit('deleteNote', reply)"
@reportAbuse="$emit('reportAbuse', reply)"
@@ -244,7 +236,6 @@ export default {
:query-variables="queryVariables"
:full-path="fullPath"
:work-item-id="workItemId"
- :fetch-by-iid="fetchByIid"
:discussion-id="discussionId"
:work-item-type="workItemType"
:sort-order="sortOrder"
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_note.vue b/app/assets/javascripts/work_items/components/notes/work_item_note.vue
index 949dca72318..a6ab8a371de 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_note.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_note.vue
@@ -9,7 +9,6 @@ import { updateDraft, clearDraft } from '~/lib/utils/autosave';
import { renderMarkdown } from '~/notes/utils';
import { getLocationHash } from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { getWorkItemQuery } from '~/work_items/utils';
import EditedAt from '~/issues/show/components/edited.vue';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import NoteBody from '~/work_items/components/notes/work_item_note_body.vue';
@@ -17,6 +16,7 @@ import NoteHeader from '~/notes/components/note_header.vue';
import NoteActions from '~/work_items/components/notes/work_item_note_actions.vue';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
import updateWorkItemNoteMutation from '../../graphql/notes/update_work_item_note.mutation.graphql';
+import workItemByIidQuery from '../../graphql/work_item_by_iid.query.graphql';
import WorkItemCommentForm from './work_item_comment_form.vue';
export default {
@@ -37,11 +37,6 @@ export default {
type: String,
required: true,
},
- fetchByIid: {
- type: Boolean,
- required: false,
- default: false,
- },
queryVariables: {
type: Object,
required: true,
@@ -161,17 +156,15 @@ export default {
},
apollo: {
workItem: {
- query() {
- return getWorkItemQuery(this.fetchByIid);
- },
+ query: workItemByIidQuery,
variables() {
return this.queryVariables;
},
update(data) {
- return this.fetchByIid ? data.workspace.workItems.nodes[0] : data.workItem;
+ return data.workspace?.workItems?.nodes[0];
},
skip() {
- return !this.queryVariables.id && !this.queryVariables.iid;
+ return !this.queryVariables.iid;
},
error() {
this.$emit('error', i18n.fetchError);
diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue
index 5abc4da38ee..ddf7c789c09 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -733,7 +733,6 @@ export default {
:work-item-iid="workItem.iid"
:query-variables="queryVariables"
:full-path="fullPath"
- :fetch-by-iid="fetchByIid"
:work-item-type="workItemType"
:is-modal="isModal"
:assignees="workItemAssignees && workItemAssignees.assignees.nodes"
diff --git a/app/assets/javascripts/work_items/components/work_item_notes.vue b/app/assets/javascripts/work_items/components/work_item_notes.vue
index e34578e1f46..42afde76a00 100644
--- a/app/assets/javascripts/work_items/components/work_item_notes.vue
+++ b/app/assets/javascripts/work_items/components/work_item_notes.vue
@@ -15,11 +15,7 @@ import {
WORK_ITEM_NOTES_FILTER_ONLY_HISTORY,
} from '~/work_items/constants';
import { ASC, DESC } from '~/notes/constants';
-import {
- getWorkItemNotesQuery,
- autocompleteDataSources,
- markdownPreviewPath,
-} from '~/work_items/utils';
+import { autocompleteDataSources, markdownPreviewPath } from '~/work_items/utils';
import {
updateCacheAfterCreatingNote,
updateCacheAfterDeletingNote,
@@ -31,6 +27,7 @@ import workItemNoteCreatedSubscription from '~/work_items/graphql/notes/work_ite
import workItemNoteUpdatedSubscription from '~/work_items/graphql/notes/work_item_note_updated.subscription.graphql';
import workItemNoteDeletedSubscription from '~/work_items/graphql/notes/work_item_note_deleted.subscription.graphql';
import deleteNoteMutation from '../graphql/notes/delete_work_item_notes.mutation.graphql';
+import workItemNotesByIidQuery from '../graphql/notes/work_item_notes_by_iid.query.graphql';
import WorkItemAddNote from './notes/work_item_add_note.vue';
export default {
@@ -69,11 +66,6 @@ export default {
type: String,
required: true,
},
- fetchByIid: {
- type: Boolean,
- required: false,
- default: false,
- },
isModal: {
type: Boolean,
required: false,
@@ -133,7 +125,6 @@ export default {
queryVariables: this.queryVariables,
fullPath: this.fullPath,
workItemId: this.workItemId,
- fetchByIid: this.fetchByIid,
workItemType: this.workItemType,
sortOrder: this.sortOrder,
isNewDiscussion: true,
@@ -172,9 +163,7 @@ export default {
},
apollo: {
workItemNotes: {
- query() {
- return getWorkItemNotesQuery(this.fetchByIid);
- },
+ query: workItemNotesByIidQuery,
context: {
isSingleRequest: true,
},
@@ -186,15 +175,11 @@ export default {
};
},
update(data) {
- const workItemWidgets = this.fetchByIid
- ? data.workspace?.workItems?.nodes[0]?.widgets
- : data.workItem?.widgets;
- const discussionNodes =
- workItemWidgets.find((widget) => widget.type === 'NOTES')?.discussions || [];
- return discussionNodes;
+ const widgets = data.workspace?.workItems?.nodes[0]?.widgets;
+ return widgets?.find((widget) => widget.type === 'NOTES')?.discussions || [];
},
skip() {
- return !this.queryVariables.id && !this.queryVariables.iid;
+ return !this.queryVariables.iid;
},
error() {
this.$emit('error', i18n.fetchError);
@@ -214,7 +199,7 @@ export default {
{
document: workItemNoteCreatedSubscription,
updateQuery(previousResult, { subscriptionData }) {
- return updateCacheAfterCreatingNote(previousResult, subscriptionData, this.fetchByIid);
+ return updateCacheAfterCreatingNote(previousResult, subscriptionData);
},
variables() {
return {
@@ -228,7 +213,7 @@ export default {
{
document: workItemNoteDeletedSubscription,
updateQuery(previousResult, { subscriptionData }) {
- return updateCacheAfterDeletingNote(previousResult, subscriptionData, this.fetchByIid);
+ return updateCacheAfterDeletingNote(previousResult, subscriptionData);
},
variables() {
return {
@@ -377,7 +362,6 @@ export default {
:query-variables="queryVariables"
:full-path="fullPath"
:work-item-id="workItemId"
- :fetch-by-iid="fetchByIid"
:work-item-type="workItemType"
:is-modal="isModal"
:autocomplete-data-sources="autocompleteDataSources"
diff --git a/app/assets/javascripts/work_items/graphql/cache_utils.js b/app/assets/javascripts/work_items/graphql/cache_utils.js
index 95d68b69745..455d8b8ae7b 100644
--- a/app/assets/javascripts/work_items/graphql/cache_utils.js
+++ b/app/assets/javascripts/work_items/graphql/cache_utils.js
@@ -3,22 +3,12 @@ import { WIDGET_TYPE_NOTES } from '~/work_items/constants';
const isNotesWidget = (widget) => widget.type === WIDGET_TYPE_NOTES;
-const getNotesWidgetFromSourceData = (draftData, fetchByIid) => {
- return fetchByIid
- ? draftData.workspace.workItems.nodes[0].widgets.find(isNotesWidget)
- : draftData.workItem.widgets.find(isNotesWidget);
-};
-
-const updateNotesWidgetDataInDraftData = (draftData, notesWidget, fetchByIid) => {
- const noteWidgetIndex = fetchByIid
- ? draftData.workspace.workItems.nodes[0].widgets.findIndex(isNotesWidget)
- : draftData.workItem.widgets.findIndex(isNotesWidget);
+const getNotesWidgetFromSourceData = (draftData) =>
+ draftData?.workspace?.workItems?.nodes[0]?.widgets.find(isNotesWidget);
- if (fetchByIid) {
- draftData.workspace.workItems.nodes[0].widgets[noteWidgetIndex] = notesWidget;
- } else {
- draftData.workItem.widgets[noteWidgetIndex] = notesWidget;
- }
+const updateNotesWidgetDataInDraftData = (draftData, notesWidget) => {
+ const noteWidgetIndex = draftData.workspace.workItems.nodes[0].widgets.findIndex(isNotesWidget);
+ draftData.workspace.workItems.nodes[0].widgets[noteWidgetIndex] = notesWidget;
};
/**
@@ -26,17 +16,16 @@ const updateNotesWidgetDataInDraftData = (draftData, notesWidget, fetchByIid) =>
*
* @param currentNotes
* @param subscriptionData
- * @param fetchByIid
*/
-export const updateCacheAfterCreatingNote = (currentNotes, subscriptionData, fetchByIid) => {
+export const updateCacheAfterCreatingNote = (currentNotes, subscriptionData) => {
if (!subscriptionData.data?.workItemNoteCreated) {
return currentNotes;
}
const newNote = subscriptionData.data.workItemNoteCreated;
return produce(currentNotes, (draftData) => {
- const notesWidget = getNotesWidgetFromSourceData(draftData, fetchByIid);
+ const notesWidget = getNotesWidgetFromSourceData(draftData);
if (!notesWidget.discussions) {
return;
@@ -50,7 +39,7 @@ export const updateCacheAfterCreatingNote = (currentNotes, subscriptionData, fet
}
notesWidget.discussions.nodes.push(newNote.discussion);
- updateNotesWidgetDataInDraftData(draftData, notesWidget, fetchByIid);
+ updateNotesWidgetDataInDraftData(draftData, notesWidget);
});
};
@@ -59,10 +48,9 @@ export const updateCacheAfterCreatingNote = (currentNotes, subscriptionData, fet
*
* @param currentNotes
* @param subscriptionData
- * @param fetchByIid
*/
-export const updateCacheAfterDeletingNote = (currentNotes, subscriptionData, fetchByIid) => {
+export const updateCacheAfterDeletingNote = (currentNotes, subscriptionData) => {
if (!subscriptionData.data?.workItemNoteDeleted) {
return currentNotes;
}
@@ -70,7 +58,7 @@ export const updateCacheAfterDeletingNote = (currentNotes, subscriptionData, fet
const { id, discussionId, lastDiscussionNote } = deletedNote;
return produce(currentNotes, (draftData) => {
- const notesWidget = getNotesWidgetFromSourceData(draftData, fetchByIid);
+ const notesWidget = getNotesWidgetFromSourceData(draftData);
if (!notesWidget.discussions) {
return;
@@ -95,6 +83,6 @@ export const updateCacheAfterDeletingNote = (currentNotes, subscriptionData, fet
notesWidget.discussions.nodes[discussionIndex] = deletedThreadDiscussion;
}
- updateNotesWidgetDataInDraftData(draftData, notesWidget, fetchByIid);
+ updateNotesWidgetDataInDraftData(draftData, notesWidget);
});
};
diff --git a/app/assets/javascripts/work_items/graphql/notes/work_item_notes.query.graphql b/app/assets/javascripts/work_items/graphql/notes/work_item_notes.query.graphql
deleted file mode 100644
index 56dc175109f..00000000000
--- a/app/assets/javascripts/work_items/graphql/notes/work_item_notes.query.graphql
+++ /dev/null
@@ -1,27 +0,0 @@
-#import "~/graphql_shared/fragments/page_info.fragment.graphql"
-#import "./work_item_note.fragment.graphql"
-
-query workItemNotes($id: WorkItemID!, $after: String, $pageSize: Int) {
- workItem(id: $id) {
- id
- iid
- widgets {
- ... on WorkItemWidgetNotes {
- type
- discussions(first: $pageSize, after: $after, filter: ALL_NOTES) {
- pageInfo {
- ...PageInfo
- }
- nodes {
- id
- notes {
- nodes {
- ...WorkItemNote
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/work_items/utils.js b/app/assets/javascripts/work_items/utils.js
index 110e0f98c10..c5b937ef132 100644
--- a/app/assets/javascripts/work_items/utils.js
+++ b/app/assets/javascripts/work_items/utils.js
@@ -1,17 +1,11 @@
import { WIDGET_TYPE_HIERARCHY } from '~/work_items/constants';
import workItemQuery from './graphql/work_item.query.graphql';
import workItemByIidQuery from './graphql/work_item_by_iid.query.graphql';
-import workItemNotesIdQuery from './graphql/notes/work_item_notes.query.graphql';
-import workItemNotesByIidQuery from './graphql/notes/work_item_notes_by_iid.query.graphql';
export function getWorkItemQuery(isFetchedByIid) {
return isFetchedByIid ? workItemByIidQuery : workItemQuery;
}
-export function getWorkItemNotesQuery(isFetchedByIid) {
- return isFetchedByIid ? workItemNotesByIidQuery : workItemNotesIdQuery;
-}
-
export const findHierarchyWidgets = (widgets) =>
widgets?.find((widget) => widget.type === WIDGET_TYPE_HIERARCHY);
diff --git a/app/mailers/emails/service_desk.rb b/app/mailers/emails/service_desk.rb
index e75882073f2..b9d8735494a 100644
--- a/app/mailers/emails/service_desk.rb
+++ b/app/mailers/emails/service_desk.rb
@@ -157,6 +157,7 @@ module Emails
.gsub(/%\{\s*ISSUE_ID\s*\}/, issue_id)
.gsub(/%\{\s*ISSUE_PATH\s*\}/, issue_path)
.gsub(/%\{\s*NOTE_TEXT\s*\}/, note_text)
+ .gsub(/%\{\s*ISSUE_DESCRIPTION\s*\}/, issue_description)
.gsub(/%\{\s*SYSTEM_HEADER\s*\}/, text_header_message.to_s)
.gsub(/%\{\s*SYSTEM_FOOTER\s*\}/, text_footer_message.to_s)
.gsub(/%\{\s*UNSUBSCRIBE_URL\s*\}/, unsubscribe_sent_notification_url(@sent_notification))
@@ -175,6 +176,10 @@ module Emails
@note&.note.to_s
end
+ def issue_description
+ @issue.description_html.to_s
+ end
+
def subject_base
"#{@issue.title} (##{@issue.iid})"
end
diff --git a/app/models/ci/pipeline_variable.rb b/app/models/ci/pipeline_variable.rb
index 8e83b41cd0b..f2457af0074 100644
--- a/app/models/ci/pipeline_variable.rb
+++ b/app/models/ci/pipeline_variable.rb
@@ -6,6 +6,9 @@ module Ci
include Ci::HasVariable
include Ci::RawVariable
+ include IgnorableColumns
+ ignore_column :id_convert_to_bigint, remove_with: '16.3', remove_after: '2023-08-22'
+
belongs_to :pipeline
partitionable scope: :pipeline
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index a81afa5f450..13d628ec9a4 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -3,6 +3,7 @@
- add_page_specific_style 'page_bundles/projects_edit'
- expanded = expanded_by_default?
- reduce_visibility_form_id = 'reduce-visibility-form'
+- @force_desktop_expanded_sidebar = true
= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index 35214ad38dc..4d71161c96e 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -1,5 +1,6 @@
- breadcrumb_title _('Webhook Settings')
- page_title _('Webhooks')
+- @force_desktop_expanded_sidebar = true
.row.gl-mt-3.js-search-settings-section
.col-lg-4
diff --git a/app/views/projects/settings/access_tokens/index.html.haml b/app/views/projects/settings/access_tokens/index.html.haml
index b581ccaceec..26c08fcdfe4 100644
--- a/app/views/projects/settings/access_tokens/index.html.haml
+++ b/app/views/projects/settings/access_tokens/index.html.haml
@@ -2,6 +2,7 @@
- page_title _('Project Access Tokens')
- type = _('project access token')
- type_plural = _('project access tokens')
+- @force_desktop_expanded_sidebar = true
.row.gl-mt-3.js-search-settings-section
.col-lg-4
diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml
index d8e26c7ad72..c7bb6a7f5da 100644
--- a/app/views/projects/settings/ci_cd/show.html.haml
+++ b/app/views/projects/settings/ci_cd/show.html.haml
@@ -1,5 +1,6 @@
- page_title _("CI/CD Settings")
- page_title _("CI/CD")
+- @force_desktop_expanded_sidebar = true
- expanded = expanded_by_default?
- general_expanded = @project.errors.empty? ? expanded : true
diff --git a/app/views/projects/settings/integrations/index.html.haml b/app/views/projects/settings/integrations/index.html.haml
index ed65cce5acb..59cdda5bb92 100644
--- a/app/views/projects/settings/integrations/index.html.haml
+++ b/app/views/projects/settings/integrations/index.html.haml
@@ -1,5 +1,6 @@
- breadcrumb_title _('Integration Settings')
- page_title _('Integrations')
+- @force_desktop_expanded_sidebar = true
= render 'shared/integrations/slack_notifications_deprecation_alert'
diff --git a/app/views/projects/settings/merge_requests/show.html.haml b/app/views/projects/settings/merge_requests/show.html.haml
index 6cc5dfd8c90..ef528d17fc9 100644
--- a/app/views/projects/settings/merge_requests/show.html.haml
+++ b/app/views/projects/settings/merge_requests/show.html.haml
@@ -1,5 +1,6 @@
- breadcrumb_title _('Merge requests')
- page_title _('Merge requests')
+- @force_desktop_expanded_sidebar = true
%section.rspec-merge-request-settings.settings.merge-requests-feature.no-animate#js-merge-request-settings.expanded{ class: [('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)], data: { qa_selector: 'merge_request_settings_content' } }
.settings-header
diff --git a/app/views/projects/settings/operations/show.html.haml b/app/views/projects/settings/operations/show.html.haml
index bfa637ee35e..d44ebf1eb83 100644
--- a/app/views/projects/settings/operations/show.html.haml
+++ b/app/views/projects/settings/operations/show.html.haml
@@ -1,5 +1,6 @@
- page_title _('Monitor Settings')
- breadcrumb_title _('Monitor Settings')
+- @force_desktop_expanded_sidebar = true
- if Feature.disabled?(:remove_monitor_metrics)
= render 'projects/settings/operations/metrics_dashboard'
diff --git a/app/views/projects/settings/packages_and_registries/show.html.haml b/app/views/projects/settings/packages_and_registries/show.html.haml
index 22385677192..6f38a3ace92 100644
--- a/app/views/projects/settings/packages_and_registries/show.html.haml
+++ b/app/views/projects/settings/packages_and_registries/show.html.haml
@@ -1,4 +1,5 @@
- breadcrumb_title _('Packages and registries settings')
- page_title _('Packages and registries settings')
+- @force_desktop_expanded_sidebar = true
#js-registry-settings{ data: settings_data }
diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml
index c532c19e0d1..12404180362 100644
--- a/app/views/projects/settings/repository/show.html.haml
+++ b/app/views/projects/settings/repository/show.html.haml
@@ -1,6 +1,7 @@
- breadcrumb_title _("Repository Settings")
- page_title _("Repository")
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to packages, your repository, and registry images.')
+- @force_desktop_expanded_sidebar = true
= render "projects/branch_defaults/show"
- if Feature.enabled?(:branch_rules, @project)
diff --git a/app/views/projects/usage_quotas/index.html.haml b/app/views/projects/usage_quotas/index.html.haml
index 5bfe6b650d1..1dd179f7b38 100644
--- a/app/views/projects/usage_quotas/index.html.haml
+++ b/app/views/projects/usage_quotas/index.html.haml
@@ -1,5 +1,6 @@
- page_title s_("UsageQuota|Usage")
- add_page_specific_style 'page_bundles/projects_usage_quotas'
+- @force_desktop_expanded_sidebar = true
= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
diff --git a/config/feature_flags/development/jira_dvcs_end_of_life_amnesty.yml b/config/feature_flags/development/jira_dvcs_end_of_life_amnesty.yml
index 1d0f364580a..dd72f9e13dd 100644
--- a/config/feature_flags/development/jira_dvcs_end_of_life_amnesty.yml
+++ b/config/feature_flags/development/jira_dvcs_end_of_life_amnesty.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/408148
milestone: '16.0'
type: development
group: group::import and integrate
-default_enabled: true
+default_enabled: false
diff --git a/config/feature_flags/development/use_replica_for_mailers.yml b/config/feature_flags/development/use_replica_for_mailers.yml
deleted file mode 100644
index 06dd2d699c7..00000000000
--- a/config/feature_flags/development/use_replica_for_mailers.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: use_replica_for_mailers
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116357
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/408785
-milestone: '16.0'
-type: development
-group: group::scalability
-default_enabled: false
diff --git a/config/initializers/mailer_retries.rb b/config/initializers/mailer_retries.rb
index cf41ecf1952..6812d3e5742 100644
--- a/config/initializers/mailer_retries.rb
+++ b/config/initializers/mailer_retries.rb
@@ -3,5 +3,5 @@
Rails.application.config.after_initialize do
ActionMailer::MailDeliveryJob.sidekiq_options retry: 3
ActionMailer::MailDeliveryJob.include(WorkerAttributes)
- ActionMailer::MailDeliveryJob.data_consistency :delayed, feature_flag: :use_replica_for_mailers
+ ActionMailer::MailDeliveryJob.data_consistency :delayed
end
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index ea3260d8260..f0917c9265b 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -113,6 +113,8 @@
- 1
- - compliance_management_chain_of_custody_report
- 1
+- - compliance_management_framework_export_mailer
+ - 1
- - compliance_management_merge_requests_compliance_violations
- 1
- - compliance_management_update_default_framework
diff --git a/db/docs/analytics_cycle_analytics_project_stages.yml b/db/docs/deleted_tables/analytics_cycle_analytics_project_stages.yml
index 4d6baab5a00..75e1d307d59 100644
--- a/db/docs/analytics_cycle_analytics_project_stages.yml
+++ b/db/docs/deleted_tables/analytics_cycle_analytics_project_stages.yml
@@ -7,3 +7,5 @@ description: Persists project level value stream analytics stages. Scheduled for
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/15061
milestone: '12.2'
gitlab_schema: gitlab_main
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118980
+removed_in_milestone: '16.0'
diff --git a/db/docs/analytics_cycle_analytics_project_value_streams.yml b/db/docs/deleted_tables/analytics_cycle_analytics_project_value_streams.yml
index 839b49f1bed..8fbaf68ec7f 100644
--- a/db/docs/analytics_cycle_analytics_project_value_streams.yml
+++ b/db/docs/deleted_tables/analytics_cycle_analytics_project_value_streams.yml
@@ -7,3 +7,5 @@ description: Used to store the value stream configurations for projects. Schedul
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60925
milestone: '13.12'
gitlab_schema: gitlab_main
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118980
+removed_in_milestone: '16.0'
diff --git a/db/migrate/20230427065641_initialize_conversion_of_ci_pipeline_variables.rb b/db/migrate/20230427065641_initialize_conversion_of_ci_pipeline_variables.rb
new file mode 100644
index 00000000000..1c986dee3d2
--- /dev/null
+++ b/db/migrate/20230427065641_initialize_conversion_of_ci_pipeline_variables.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class InitializeConversionOfCiPipelineVariables < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ TABLE = :ci_pipeline_variables
+ COLUMNS = %i[id]
+
+ def up
+ initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
+ end
+
+ def down
+ revert_initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
+ end
+end
diff --git a/db/post_migrate/20230427065942_backfill_ci_pipeline_variables_for_bigint_conversion.rb b/db/post_migrate/20230427065942_backfill_ci_pipeline_variables_for_bigint_conversion.rb
new file mode 100644
index 00000000000..c73c29bbbad
--- /dev/null
+++ b/db/post_migrate/20230427065942_backfill_ci_pipeline_variables_for_bigint_conversion.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class BackfillCiPipelineVariablesForBigintConversion < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+
+ TABLE = :ci_pipeline_variables
+ COLUMNS = %i[id]
+
+ def up
+ backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS, sub_batch_size: 500)
+ end
+
+ def down
+ revert_backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS)
+ end
+end
diff --git a/db/post_migrate/20230427190005_drop_foreign_keys_from_cycle_analytics_unused_tables.rb b/db/post_migrate/20230427190005_drop_foreign_keys_from_cycle_analytics_unused_tables.rb
new file mode 100644
index 00000000000..a0a6679f136
--- /dev/null
+++ b/db/post_migrate/20230427190005_drop_foreign_keys_from_cycle_analytics_unused_tables.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+class DropForeignKeysFromCycleAnalyticsUnusedTables < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ remove_foreign_key :analytics_cycle_analytics_project_stages, column: :stage_event_hash_id
+ remove_foreign_key :analytics_cycle_analytics_project_stages, column: :project_id
+ remove_foreign_key :analytics_cycle_analytics_project_stages, column: :start_event_label_id
+ remove_foreign_key :analytics_cycle_analytics_project_stages, column: :end_event_label_id
+ remove_foreign_key :analytics_cycle_analytics_project_stages, column: :project_value_stream_id
+
+ remove_foreign_key :analytics_cycle_analytics_project_value_streams, column: :project_id
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(:analytics_cycle_analytics_project_stages,
+ :analytics_cycle_analytics_stage_event_hashes,
+ name: "fk_c3339bdfc9",
+ column: :stage_event_hash_id,
+ target_column: :id,
+ on_delete: :cascade
+ )
+
+ add_concurrent_foreign_key(:analytics_cycle_analytics_project_stages,
+ :labels,
+ name: "fk_rails_1722574860",
+ column: :start_event_label_id,
+ target_column: :id,
+ on_delete: :cascade
+ )
+
+ add_concurrent_foreign_key(:analytics_cycle_analytics_project_stages,
+ :projects,
+ name: "fk_rails_3829e49b66",
+ column: :project_id,
+ target_column: :id,
+ on_delete: :cascade
+ )
+
+ add_concurrent_foreign_key(:analytics_cycle_analytics_project_stages,
+ :labels,
+ name: "fk_rails_3ec9fd7912",
+ column: :end_event_label_id,
+ target_column: :id,
+ on_delete: :cascade
+ )
+
+ add_concurrent_foreign_key(:analytics_cycle_analytics_project_stages,
+ :analytics_cycle_analytics_project_value_streams,
+ name: "fk_rails_796a7dbc9c",
+ column: :project_value_stream_id,
+ target_column: :id,
+ on_delete: :cascade
+ )
+
+ add_concurrent_foreign_key(:analytics_cycle_analytics_project_value_streams,
+ :projects,
+ name: "fk_rails_669f4ba293",
+ column: :project_id,
+ target_column: :id,
+ on_delete: :cascade
+ )
+ end
+end
diff --git a/db/post_migrate/20230427194552_drop_cycle_analytics_unused_tables.rb b/db/post_migrate/20230427194552_drop_cycle_analytics_unused_tables.rb
new file mode 100644
index 00000000000..7c10238a1bc
--- /dev/null
+++ b/db/post_migrate/20230427194552_drop_cycle_analytics_unused_tables.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+# See https://docs.gitlab.com/ee/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class DropCycleAnalyticsUnusedTables < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ drop_table :analytics_cycle_analytics_project_stages
+ drop_table :analytics_cycle_analytics_project_value_streams
+ end
+
+ def down
+ create_analytics_cycle_analytics_project_value_streams_table
+ create_analytics_cycle_analytics_project_stages_table
+ end
+
+ def create_analytics_cycle_analytics_project_value_streams_table
+ index_name = 'index_analytics_ca_project_value_streams_on_project_id_and_name'
+
+ # rubocop:disable Migration/SchemaAdditionMethodsNoPost
+ # rubocop:disable Migration/AddLimitToTextColumns
+ create_table :analytics_cycle_analytics_project_value_streams do |t|
+ t.timestamps_with_timezone
+ t.references(:project,
+ null: false,
+ index: false,
+ foreign_key: { to_table: :projects, on_delete: :cascade }
+ )
+ t.text :name, null: false
+ t.index [:project_id, :name], unique: true, name: index_name
+ end
+ # rubocop:enable Migration/SchemaAdditionMethodsNoPost
+ # rubocop:enable Migration/AddLimitToTextColumns
+
+ add_text_limit :analytics_cycle_analytics_project_value_streams, :name, 100
+ end
+
+ def create_analytics_cycle_analytics_project_stages_table
+ index_prefix = 'index_analytics_ca_project_stages_'
+
+ # rubocop:disable Migration/SchemaAdditionMethodsNoPost
+ create_table :analytics_cycle_analytics_project_stages do |t|
+ t.timestamps_with_timezone
+ t.integer :relative_position
+ t.integer :start_event_identifier, null: false
+ t.integer :end_event_identifier, null: false
+ t.references(:project, null: false,
+ foreign_key: { to_table: :projects, on_delete: :cascade },
+ index: { name: "#{index_prefix}on_project_id" }
+ )
+ t.references(:start_event_label,
+ foreign_key: { to_table: :labels, on_delete: :cascade },
+ index: { name: "#{index_prefix}on_start_event_label_id" }
+ )
+ t.references(:end_event_label,
+ foreign_key: { to_table: :labels, on_delete: :cascade },
+ index: { name: "#{index_prefix}on_end_event_label_id" }
+ )
+ t.boolean :hidden, default: false, null: false
+ t.boolean :custom, default: true, null: false
+ t.string :name, null: false, limit: 255 # rubocop: disable Migration/PreventStrings
+ t.references(:project_value_stream, null: false,
+ foreign_key: { to_table: :analytics_cycle_analytics_project_value_streams, on_delete: :cascade },
+ index: { name: "#{index_prefix}on_value_stream_id" }
+ )
+ t.references(:stage_event_hash,
+ foreign_key: { to_table: :analytics_cycle_analytics_stage_event_hashes, on_delete: :cascade },
+ index: { name: 'index_project_stages_on_stage_event_hash_id' }
+ )
+ end
+ # rubocop:enable Migration/SchemaAdditionMethodsNoPost
+
+ add_check_constraint :analytics_cycle_analytics_project_stages, 'stage_event_hash_id IS NOT NULL',
+ 'check_8f6019de1e'
+
+ add_index :analytics_cycle_analytics_project_stages, [:project_id, :name], unique: true,
+ name: "#{index_prefix}on_project_id_and_name"
+ add_index :analytics_cycle_analytics_project_stages, [:relative_position],
+ name: "#{index_prefix}on_relative_position"
+ end
+end
diff --git a/db/schema_migrations/20230427065641 b/db/schema_migrations/20230427065641
new file mode 100644
index 00000000000..4a202ea0bc7
--- /dev/null
+++ b/db/schema_migrations/20230427065641
@@ -0,0 +1 @@
+69f768f9b0eed0f81e206b819f403b3d3b9b2f16d415fcfbb4d9eafc920b55d6 \ No newline at end of file
diff --git a/db/schema_migrations/20230427065942 b/db/schema_migrations/20230427065942
new file mode 100644
index 00000000000..6bb8571c4f4
--- /dev/null
+++ b/db/schema_migrations/20230427065942
@@ -0,0 +1 @@
+88617cc027cd260d56db9d2c44724e4ffba0b01604cb1c444ee9af2e36919cc8 \ No newline at end of file
diff --git a/db/schema_migrations/20230427190005 b/db/schema_migrations/20230427190005
new file mode 100644
index 00000000000..514c2c9071d
--- /dev/null
+++ b/db/schema_migrations/20230427190005
@@ -0,0 +1 @@
+b704051dd0fd69f22a1f33739fd8d969acd0c56e4b56c8711daf10a735bc2027 \ No newline at end of file
diff --git a/db/schema_migrations/20230427194552 b/db/schema_migrations/20230427194552
new file mode 100644
index 00000000000..10d4b9e687e
--- /dev/null
+++ b/db/schema_migrations/20230427194552
@@ -0,0 +1 @@
+e0b4dc1848c0d4c5880366861b9806f98747d5bcddc270c14c7757c4d5398819 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index a5bf3bd3829..d2cabbf6636 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -237,6 +237,15 @@ RETURN NULL;
END
$$;
+CREATE FUNCTION trigger_023e82d8e257() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ NEW."id_convert_to_bigint" := NEW."id";
+ RETURN NEW;
+END;
+$$;
+
CREATE FUNCTION trigger_080e73845bfd() RETURNS trigger
LANGUAGE plpgsql
AS $$
@@ -11142,51 +11151,6 @@ CREATE SEQUENCE analytics_cycle_analytics_group_value_streams_id_seq
ALTER SEQUENCE analytics_cycle_analytics_group_value_streams_id_seq OWNED BY analytics_cycle_analytics_group_value_streams.id;
-CREATE TABLE analytics_cycle_analytics_project_stages (
- id bigint NOT NULL,
- created_at timestamp with time zone NOT NULL,
- updated_at timestamp with time zone NOT NULL,
- relative_position integer,
- start_event_identifier integer NOT NULL,
- end_event_identifier integer NOT NULL,
- project_id bigint NOT NULL,
- start_event_label_id bigint,
- end_event_label_id bigint,
- hidden boolean DEFAULT false NOT NULL,
- custom boolean DEFAULT true NOT NULL,
- name character varying(255) NOT NULL,
- project_value_stream_id bigint NOT NULL,
- stage_event_hash_id bigint,
- CONSTRAINT check_8f6019de1e CHECK ((stage_event_hash_id IS NOT NULL))
-);
-
-CREATE SEQUENCE analytics_cycle_analytics_project_stages_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-ALTER SEQUENCE analytics_cycle_analytics_project_stages_id_seq OWNED BY analytics_cycle_analytics_project_stages.id;
-
-CREATE TABLE analytics_cycle_analytics_project_value_streams (
- 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_9b1970a898 CHECK ((char_length(name) <= 100))
-);
-
-CREATE SEQUENCE analytics_cycle_analytics_project_value_streams_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-ALTER SEQUENCE analytics_cycle_analytics_project_value_streams_id_seq OWNED BY analytics_cycle_analytics_project_value_streams.id;
-
CREATE TABLE analytics_cycle_analytics_stage_event_hashes (
id bigint NOT NULL,
hash_sha256 bytea
@@ -13654,7 +13618,8 @@ CREATE TABLE ci_pipeline_variables (
pipeline_id integer NOT NULL,
variable_type smallint DEFAULT 1 NOT NULL,
partition_id bigint DEFAULT 100 NOT NULL,
- raw boolean DEFAULT false NOT NULL
+ raw boolean DEFAULT false NOT NULL,
+ id_convert_to_bigint bigint DEFAULT 0 NOT NULL
);
CREATE SEQUENCE ci_pipeline_variables_id_seq
@@ -24820,10 +24785,6 @@ ALTER TABLE ONLY analytics_cycle_analytics_group_stages ALTER COLUMN id SET DEFA
ALTER TABLE ONLY analytics_cycle_analytics_group_value_streams ALTER COLUMN id SET DEFAULT nextval('analytics_cycle_analytics_group_value_streams_id_seq'::regclass);
-ALTER TABLE ONLY analytics_cycle_analytics_project_stages ALTER COLUMN id SET DEFAULT nextval('analytics_cycle_analytics_project_stages_id_seq'::regclass);
-
-ALTER TABLE ONLY analytics_cycle_analytics_project_value_streams ALTER COLUMN id SET DEFAULT nextval('analytics_cycle_analytics_project_value_streams_id_seq'::regclass);
-
ALTER TABLE ONLY analytics_cycle_analytics_stage_event_hashes ALTER COLUMN id SET DEFAULT nextval('analytics_cycle_analytics_stage_event_hashes_id_seq'::regclass);
ALTER TABLE ONLY analytics_dashboards_pointers ALTER COLUMN id SET DEFAULT nextval('analytics_dashboards_pointers_id_seq'::regclass);
@@ -26554,12 +26515,6 @@ ALTER TABLE ONLY analytics_cycle_analytics_group_stages
ALTER TABLE ONLY analytics_cycle_analytics_group_value_streams
ADD CONSTRAINT analytics_cycle_analytics_group_value_streams_pkey PRIMARY KEY (id);
-ALTER TABLE ONLY analytics_cycle_analytics_project_stages
- ADD CONSTRAINT analytics_cycle_analytics_project_stages_pkey PRIMARY KEY (id);
-
-ALTER TABLE ONLY analytics_cycle_analytics_project_value_streams
- ADD CONSTRAINT analytics_cycle_analytics_project_value_streams_pkey PRIMARY KEY (id);
-
ALTER TABLE ONLY analytics_cycle_analytics_stage_event_hashes
ADD CONSTRAINT analytics_cycle_analytics_stage_event_hashes_pkey PRIMARY KEY (id);
@@ -29776,20 +29731,6 @@ CREATE INDEX index_analytics_ca_group_stages_on_value_stream_id ON analytics_cyc
CREATE UNIQUE INDEX index_analytics_ca_group_value_streams_on_group_id_and_name ON analytics_cycle_analytics_group_value_streams USING btree (group_id, name);
-CREATE INDEX index_analytics_ca_project_stages_on_end_event_label_id ON analytics_cycle_analytics_project_stages USING btree (end_event_label_id);
-
-CREATE INDEX index_analytics_ca_project_stages_on_project_id ON analytics_cycle_analytics_project_stages USING btree (project_id);
-
-CREATE UNIQUE INDEX index_analytics_ca_project_stages_on_project_id_and_name ON analytics_cycle_analytics_project_stages USING btree (project_id, name);
-
-CREATE INDEX index_analytics_ca_project_stages_on_relative_position ON analytics_cycle_analytics_project_stages USING btree (relative_position);
-
-CREATE INDEX index_analytics_ca_project_stages_on_start_event_label_id ON analytics_cycle_analytics_project_stages USING btree (start_event_label_id);
-
-CREATE INDEX index_analytics_ca_project_stages_on_value_stream_id ON analytics_cycle_analytics_project_stages USING btree (project_value_stream_id);
-
-CREATE UNIQUE INDEX index_analytics_ca_project_value_streams_on_project_id_and_name ON analytics_cycle_analytics_project_value_streams USING btree (project_id, name);
-
CREATE INDEX index_analytics_cycle_analytics_group_stages_custom_only ON analytics_cycle_analytics_group_stages USING btree (id) WHERE (custom = true);
CREATE UNIQUE INDEX index_analytics_dashboards_pointers_on_namespace_id ON analytics_dashboards_pointers USING btree (namespace_id);
@@ -32054,8 +31995,6 @@ CREATE INDEX index_project_settings_on_project_id_partially ON project_settings
CREATE UNIQUE INDEX index_project_settings_on_push_rule_id ON project_settings USING btree (push_rule_id);
-CREATE INDEX index_project_stages_on_stage_event_hash_id ON analytics_cycle_analytics_project_stages USING btree (stage_event_hash_id);
-
CREATE INDEX index_project_states_failed_verification ON project_states USING btree (verification_retry_at NULLS FIRST) WHERE (verification_state = 3);
CREATE INDEX index_project_states_needs_verification ON project_states USING btree (verification_state) WHERE ((verification_state = 0) OR (verification_state = 3));
@@ -34596,6 +34535,8 @@ CREATE TRIGGER push_rules_loose_fk_trigger AFTER DELETE ON push_rules REFERENCIN
CREATE TRIGGER tags_loose_fk_trigger AFTER DELETE ON tags REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
+CREATE TRIGGER trigger_023e82d8e257 BEFORE INSERT OR UPDATE ON ci_pipeline_variables FOR EACH ROW EXECUTE FUNCTION trigger_023e82d8e257();
+
CREATE TRIGGER trigger_080e73845bfd BEFORE INSERT OR UPDATE ON notes FOR EACH ROW EXECUTE FUNCTION trigger_080e73845bfd();
CREATE TRIGGER trigger_0e214b8a14f2 BEFORE INSERT OR UPDATE ON vulnerability_user_mentions FOR EACH ROW EXECUTE FUNCTION trigger_0e214b8a14f2();
@@ -35424,9 +35365,6 @@ ALTER TABLE ONLY packages_packages
ALTER TABLE ONLY sbom_occurrences
ADD CONSTRAINT fk_c2a5562923 FOREIGN KEY (source_id) REFERENCES sbom_sources(id) ON DELETE CASCADE;
-ALTER TABLE ONLY analytics_cycle_analytics_project_stages
- ADD CONSTRAINT fk_c3339bdfc9 FOREIGN KEY (stage_event_hash_id) REFERENCES analytics_cycle_analytics_stage_event_hashes(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY user_group_callouts
ADD CONSTRAINT fk_c366e12ec3 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
@@ -35853,9 +35791,6 @@ ALTER TABLE ONLY catalog_resources
ALTER TABLE ONLY project_deploy_tokens
ADD CONSTRAINT fk_rails_170e03cbaf FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-ALTER TABLE ONLY analytics_cycle_analytics_project_stages
- ADD CONSTRAINT fk_rails_1722574860 FOREIGN KEY (start_event_label_id) REFERENCES labels(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY security_orchestration_policy_rule_schedules
ADD CONSTRAINT fk_rails_17ade83f17 FOREIGN KEY (security_orchestration_policy_configuration_id) REFERENCES security_orchestration_policy_configurations(id) ON DELETE CASCADE;
@@ -36081,9 +36016,6 @@ ALTER TABLE ONLY merge_request_reviewers
ALTER TABLE ONLY group_merge_request_approval_settings
ADD CONSTRAINT fk_rails_37b6b4cdba FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
-ALTER TABLE ONLY analytics_cycle_analytics_project_stages
- ADD CONSTRAINT fk_rails_3829e49b66 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY packages_debian_project_distribution_keys
ADD CONSTRAINT fk_rails_3834a11264 FOREIGN KEY (distribution_id) REFERENCES packages_debian_project_distributions(id) ON DELETE CASCADE;
@@ -36123,9 +36055,6 @@ ALTER TABLE ONLY snippet_user_mentions
ALTER TABLE ONLY epic_user_mentions
ADD CONSTRAINT fk_rails_3eaf4d88cc FOREIGN KEY (epic_id) REFERENCES epics(id) ON DELETE CASCADE;
-ALTER TABLE ONLY analytics_cycle_analytics_project_stages
- ADD CONSTRAINT fk_rails_3ec9fd7912 FOREIGN KEY (end_event_label_id) REFERENCES labels(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY issuable_resource_links
ADD CONSTRAINT fk_rails_3f0ec6b1cf FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
@@ -36417,9 +36346,6 @@ ALTER TABLE ONLY namespace_admin_notes
ALTER TABLE ONLY ci_runner_machines
ADD CONSTRAINT fk_rails_666b61f04f FOREIGN KEY (runner_id) REFERENCES ci_runners(id) ON DELETE CASCADE;
-ALTER TABLE ONLY analytics_cycle_analytics_project_value_streams
- ADD CONSTRAINT fk_rails_669f4ba293 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY jira_imports
ADD CONSTRAINT fk_rails_675d38c03b FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE SET NULL;
@@ -36537,9 +36463,6 @@ ALTER TABLE ONLY packages_debian_group_distribution_keys
ALTER TABLE ONLY terraform_states
ADD CONSTRAINT fk_rails_78f54ca485 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-ALTER TABLE ONLY analytics_cycle_analytics_project_stages
- ADD CONSTRAINT fk_rails_796a7dbc9c FOREIGN KEY (project_value_stream_id) REFERENCES analytics_cycle_analytics_project_value_streams(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY software_license_policies
ADD CONSTRAINT fk_rails_7a7a2a92de FOREIGN KEY (software_license_id) REFERENCES software_licenses(id) ON DELETE CASCADE;
diff --git a/doc/ci/secrets/id_token_authentication.md b/doc/ci/secrets/id_token_authentication.md
index c5b19797a05..c1a6282447b 100644
--- a/doc/ci/secrets/id_token_authentication.md
+++ b/doc/ci/secrets/id_token_authentication.md
@@ -130,7 +130,13 @@ manual_authentication:
You can use ID tokens to automatically fetch secrets from HashiCorp Vault with the
[`secrets`](../yaml/index.md#secrets) keyword.
-### Enable automatic ID token authentication
+<!--- start_remove The following content will be removed on remove_date: '2023-05-11' -->
+
+### Enable automatic ID token authentication (deprecated)
+
+WARNING:
+This setting was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/391886) in GitLab 16.0.
+ID token authentication is now always available, and JSON Web Token access is always limited.
To enable automatic ID token authentication:
@@ -139,6 +145,8 @@ To enable automatic ID token authentication:
1. Expand **Token Access**.
1. Toggle **Limit JSON Web Token (JWT) access** to enabled.
+<!--- end_remove -->
+
### Configure automatic ID Token authentication
If one ID token is defined, the `secrets` keyword automatically uses it to authenticate with Vault. For example:
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index 39f979d98d5..9cf718573ec 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -3831,9 +3831,6 @@ job:
Use `secrets:token` to explicitly select a token to use when authenticating with Vault by referencing the token's CI/CD variable.
-This keyword has no effect if [**Limit JSON Web Token (JWT) access**](../secrets/id_token_authentication.md#enable-automatic-id-token-authentication)
-is disabled.
-
**Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**:
@@ -3857,8 +3854,8 @@ job:
**Additional details**:
-- When the `token` keyword is not set and **Limit JSON Web Token (JWT) access** enabled, the first ID token
- is used to authenticate.
+- When the `token` keyword is not set, the first ID token is used to authenticate.
+- In GitLab 15.8 to 15.11, you must enable [**Limit JSON Web Token (JWT) access**](../secrets/id_token_authentication.md#enable-automatic-id-token-authentication-deprecated) for this keyword to be available.
- When **Limit JSON Web Token (JWT) access** is disabled, the `token` keyword is ignored and the `CI_JOB_JWT`
CI/CD variable is used to authenticate.
diff --git a/doc/development/documentation/topic_types/tutorial.md b/doc/development/documentation/topic_types/tutorial.md
index 52f715cfcf3..91f426147b5 100644
--- a/doc/development/documentation/topic_types/tutorial.md
+++ b/doc/development/documentation/topic_types/tutorial.md
@@ -27,8 +27,10 @@ In general, you might consider using a tutorial when:
## Tutorial file name and location
-For tutorial Markdown files, create a subfolder under `doc/tutorials`.
-The tutorial file should be `index.md`.
+For tutorial Markdown files, you can either:
+
+- Save the file in a directory with the product documentation.
+- Create a subfolder under `doc/tutorials` and name the file `index.md`.
## Tutorial format
diff --git a/doc/integration/jira/development_panel.md b/doc/integration/jira/development_panel.md
index e4fe94476bd..009e620f121 100644
--- a/doc/integration/jira/development_panel.md
+++ b/doc/integration/jira/development_panel.md
@@ -92,3 +92,8 @@ For more information about how Smart Commits work and what commands are availabl
- [Process issues with Smart Commits](https://support.atlassian.com/jira-software-cloud/docs/process-issues-with-smart-commits/)
- [Using Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html)
+
+## Troubleshooting
+
+To troubleshoot the Jira development panel on your own server, see the
+[Atlassian documentation](https://confluence.atlassian.com/jirakb/troubleshoot-the-development-panel-in-jira-server-574685212.html).
diff --git a/doc/integration/jira/dvcs/index.md b/doc/integration/jira/dvcs/index.md
index dc2b488e043..580086e15ff 100644
--- a/doc/integration/jira/dvcs/index.md
+++ b/doc/integration/jira/dvcs/index.md
@@ -78,8 +78,3 @@ can refresh the data manually from the Jira interface:
1. Select **DVCS accounts**.
1. In the table, for the repository you want to refresh, in the **Last Activity**
column, select the icon.
-
-## Troubleshooting
-
-To troubleshoot the Jira development panel on your own server, see the
-[Atlassian documentation](https://confluence.atlassian.com/jirakb/troubleshoot-the-development-panel-in-jira-server-574685212.html).
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 766fc4504cb..0ef87adfb89 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -773,34 +773,6 @@ As a result, it only supports Java 8, 11, and 17.
Dependency scanning for Gradle projects and auto-remediation for Yarn projects are not supported in FIPS mode.
-## Interacting with the vulnerabilities
-
-Once a vulnerability is found, you can interact with it. Read more on how to
-[address the vulnerabilities](../vulnerabilities/index.md).
-
-## Solutions for vulnerabilities
-
-Some vulnerabilities can be fixed by applying the solution that GitLab
-automatically generates. Read more about the
-[solutions for vulnerabilities](../vulnerabilities/index.md#resolve-a-vulnerability).
-
-## Security Dashboard
-
-The Security Dashboard is a good place to get an overview of all the security
-vulnerabilities in your groups, projects and pipelines. Read more about the
-[Security Dashboard](../security_dashboard/index.md).
-
-## Vulnerabilities database update
-
-For more information about the vulnerabilities database update, see the
-[maintenance table](../index.md#vulnerability-scanner-maintenance).
-
-## Dependency List
-
-An additional benefit of dependency scanning is the ability to view your
-project's dependencies and their known vulnerabilities. Read more about
-the [Dependency List](../dependency_list/index.md).
-
## Reports JSON format
The dependency scanning tool emits a JSON report file. For more information, see the
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index 191695bc7ab..4e71a5fdca8 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -342,17 +342,21 @@ the server continues to reset the TTL, regardless of whether 2FA is installed.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20340) in GitLab 13.1.
-When you sign in, two cookies are set:
+When you sign in, three cookies are set:
- A session cookie called `_gitlab_session`.
This cookie has no set expiration date. However, it expires based on its `session_expire_delay`.
+- A session cookied called `about_gitlab_active_user`.
+ This cookie is used by the [marketing site](https://about.gitlab.com/) to determine if a user has an active GitLab session. No user information is passed to the cookie and it expires with the session.
- A persistent cookie called `remember_user_token`, which is set only if you selected **Remember me** on the sign-in page.
-When you close your browser, the `_gitlab_session` cookie is usually cleared client-side.
-When it expires or isn't available, GitLab uses the `remember_user_token`cookie to get you
-a new `_gitlab_session` cookie and keep you signed in, even if you close your browser.
+When you close your browser, the `_gitlab_session` and `about_gitlab_active_user` cookies are usually cleared client-side.
+When it expires or isn't available, GitLab:
-When both cookies are gone or expired, you must sign in again.
+- Uses the `remember_user_token`cookie to get you a new `_gitlab_session` cookie and keep you signed in, even if you close your browser.
+- Sets the `about_gitlab_active_user` to `true`.
+
+When both the `remember_user_token` and `_gitlab_session` cookies are gone or expired, you must sign in again.
NOTE:
When any session is signed out, or when a session is revoked
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 77ad8d29440..64579d44aa3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8421,9 +8421,6 @@ msgstr ""
msgid "CICD|Allow access to this project with a CI_JOB_TOKEN"
msgstr ""
-msgid "CICD|An error occurred while update the setting. Please try again."
-msgstr ""
-
msgid "CICD|Auto DevOps"
msgstr ""
@@ -8463,9 +8460,6 @@ msgstr ""
msgid "CICD|Limit CI_JOB_TOKEN access"
msgstr ""
-msgid "CICD|Limit JSON Web Token (JWT) access"
-msgstr ""
-
msgid "CICD|Manage which projects can use their CI_JOB_TOKEN to access this project. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -8481,24 +8475,15 @@ msgstr ""
msgid "CICD|The Auto DevOps pipeline runs if no alternative CI configuration file is found."
msgstr ""
-msgid "CICD|The JWT must be manually declared in each job that needs it. When disabled, the token is always available in all jobs in the pipeline. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
-
msgid "CICD|There are several CI/CD limits in place."
msgstr ""
-msgid "CICD|There was a problem fetching the token access settings."
-msgstr ""
-
msgid "CICD|Unprotected branches will not have access to the cache from protected branches."
msgstr ""
msgid "CICD|Use separate caches for protected branches"
msgstr ""
-msgid "CICD|Use the %{codeStart}secrets%{codeEnd} keyword to configure a job with a JWT."
-msgstr ""
-
msgid "CICD|group enabled"
msgstr ""
@@ -9816,6 +9801,9 @@ msgstr ""
msgid "Cloud Storage"
msgstr ""
+msgid "CloudSeed|AI / ML"
+msgstr ""
+
msgid "CloudSeed|All"
msgstr ""
@@ -9852,6 +9840,9 @@ msgstr ""
msgid "CloudSeed|Configuration"
msgstr ""
+msgid "CloudSeed|Configure via Merge Request"
+msgstr ""
+
msgid "CloudSeed|Create MySQL Instance"
msgstr ""
@@ -9882,6 +9873,12 @@ msgstr ""
msgid "CloudSeed|Deployments"
msgstr ""
+msgid "CloudSeed|Derive insights from unstructured text using Google machine learning"
+msgstr ""
+
+msgid "CloudSeed|Derive insights from your images in the cloud or at the edge"
+msgstr ""
+
msgid "CloudSeed|Description"
msgstr ""
@@ -9921,18 +9918,27 @@ msgstr ""
msgid "CloudSeed|Google Cloud project"
msgstr ""
+msgid "CloudSeed|Google Cloud's AI tools are armed with the best of Google's research and technology to help developers focus exclusively on solving problems that matter"
+msgstr ""
+
msgid "CloudSeed|I accept Google Cloud pricing and responsibilities involved with managing database instances"
msgstr ""
msgid "CloudSeed|Instances"
msgstr ""
+msgid "CloudSeed|Language AI"
+msgstr ""
+
msgid "CloudSeed|Learn more about pricing for %{cloudsqlPricingStart}Cloud SQL%{cloudsqlPricingEnd}, %{alloydbPricingStart}Alloy DB%{alloydbPricingEnd}, %{memorystorePricingStart}Memorystore%{memorystorePricingEnd} and %{firestorePricingStart}Firestore%{firestorePricingEnd}."
msgstr ""
msgid "CloudSeed|Machine type"
msgstr ""
+msgid "CloudSeed|Make your content and apps multilingual with fast, dynamic machine translation"
+msgstr ""
+
msgid "CloudSeed|Memorystore for Redis"
msgstr ""
@@ -9960,9 +9966,15 @@ msgstr ""
msgid "CloudSeed|There are no instances to display."
msgstr ""
+msgid "CloudSeed|Translation AI"
+msgstr ""
+
msgid "CloudSeed|Version"
msgstr ""
+msgid "CloudSeed|Vision AI"
+msgstr ""
+
msgid "Cluster"
msgstr ""
@@ -11146,6 +11158,9 @@ msgstr ""
msgid "ComplianceFrameworks|Cancel"
msgstr ""
+msgid "ComplianceFrameworks|Compliance Frameworks Export"
+msgstr ""
+
msgid "ComplianceFrameworks|Compliance framework created"
msgstr ""
@@ -11230,6 +11245,12 @@ msgstr ""
msgid "ComplianceFrameworks|You are about to permanently delete the compliance framework %{framework} from all projects which currently have it applied, which may remove other functionality. This cannot be undone."
msgstr ""
+msgid "ComplianceFrameworks|Your Compliance Frameworks CSV export for the group \"%{group_name}\" has been attached to this email."
+msgstr ""
+
+msgid "ComplianceFrameworks|Your Compliance Frameworks CSV export for the group %{group_link} has been attached to this email."
+msgstr ""
+
msgid "ComplianceFrameworks|default"
msgstr ""
diff --git a/scripts/verify-tff-mapping b/scripts/verify-tff-mapping
index bab3afd4e4e..c37ccafa02c 100755
--- a/scripts/verify-tff-mapping
+++ b/scripts/verify-tff-mapping
@@ -66,6 +66,12 @@ tests = [
},
{
+ explanation: 'Map RuboCop related files to respective specs',
+ source: 'rubocop/cop/gettext/static_identifier.rb',
+ expected: ['spec/rubocop/cop/gettext/static_identifier_spec.rb']
+ },
+
+ {
explanation: 'Initializers should map to respective spec',
source: 'config/initializers/action_mailer_hooks.rb',
expected: ['spec/initializers/action_mailer_hooks_spec.rb']
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 788bf6477b1..3bb4e93dc64 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -175,7 +175,7 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
context 'when builds and manual actions are present' do
let!(:pipeline) { create(:ci_pipeline, project: project) }
- let!(:build) { create(:ci_build, pipeline: pipeline) }
+ let!(:build) { create(:ci_build, :success, pipeline: pipeline) }
let!(:action) do
create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production')
@@ -207,8 +207,14 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
.not_to change { Ci::Pipeline.count }
end
- it 'shows a stop button' do
+ it 'shows a stop button and dialog' do
expect(page).to have_selector(stop_button_selector)
+
+ click_button(_('Stop'))
+
+ within('.modal-body') do
+ expect(page).to have_css('.warning_message')
+ end
end
it 'does not show external link button' do
@@ -216,7 +222,6 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
end
it 'does not show terminal button' do
- expect(page).not_to have_button(_('More actions'))
expect(page).not_to have_terminal_button
end
@@ -242,8 +247,14 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
on_stop: 'close_app')
end
- it 'shows a stop button' do
+ it 'shows a stop button and dialog' do
expect(page).to have_selector(stop_button_selector)
+
+ click_button(_('Stop'))
+
+ within('.modal-body') do
+ expect(page).not_to have_css('.warning_message')
+ end
end
context 'when user is a reporter' do
@@ -273,7 +284,6 @@ RSpec.describe 'Environments page', :js, feature_category: :projects do
let(:role) { :developer }
it 'does not show terminal button' do
- expect(page).not_to have_button(_('More actions'))
expect(page).not_to have_terminal_button
end
end
diff --git a/spec/frontend/google_cloud/aiml/service_table_spec.js b/spec/frontend/google_cloud/aiml/service_table_spec.js
new file mode 100644
index 00000000000..b14db064a7f
--- /dev/null
+++ b/spec/frontend/google_cloud/aiml/service_table_spec.js
@@ -0,0 +1,34 @@
+import { GlTable } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import ServiceTable from '~/google_cloud/aiml/service_table.vue';
+
+describe('google_cloud/aiml/service_table', () => {
+ let wrapper;
+
+ const findTable = () => wrapper.findComponent(GlTable);
+
+ beforeEach(() => {
+ const propsData = {
+ visionAiUrl: '#url-vision-ai',
+ languageAiUrl: '#url-language-ai',
+ translationAiUrl: '#url-translate-ai',
+ };
+ wrapper = mountExtended(ServiceTable, { propsData });
+ });
+
+ it('should contain a table', () => {
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it.each`
+ name | testId | url
+ ${'key-vision-ai'} | ${'button-vision-ai'} | ${'#url-vision-ai'}
+ ${'key-natural-language-ai'} | ${'button-natural-language-ai'} | ${'#url-language-ai'}
+ ${'key-translation-ai'} | ${'button-translation-ai'} | ${'#url-translate-ai'}
+ `('renders $name button with correct url', ({ testId, url }) => {
+ const button = wrapper.findByTestId(testId);
+
+ expect(button.exists()).toBe(true);
+ expect(button.attributes('href')).toBe(url);
+ });
+});
diff --git a/spec/frontend/search/sidebar/components/scope_new_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_new_navigation_spec.js
index 105beae8638..c7dd6e931b1 100644
--- a/spec/frontend/search/sidebar/components/scope_new_navigation_spec.js
+++ b/spec/frontend/search/sidebar/components/scope_new_navigation_spec.js
@@ -42,7 +42,7 @@ describe('ScopeNewNavigation', () => {
const findNavItems = () => wrapper.findAllComponents(NavItem);
const findNavItemActive = () => wrapper.find('[aria-current=page]');
const findNavItemActiveLabel = () =>
- findNavItemActive().find('[class="gl-pr-3 gl-text-gray-900 gl-truncate-end"]');
+ findNavItemActive().find('[class="gl-pr-8 gl-text-gray-900 gl-truncate-end"]');
describe('scope navigation', () => {
beforeEach(() => {
diff --git a/spec/frontend/token_access/mock_data.js b/spec/frontend/token_access/mock_data.js
index 67ee197b831..a4b5532108a 100644
--- a/spec/frontend/token_access/mock_data.js
+++ b/spec/frontend/token_access/mock_data.js
@@ -121,32 +121,6 @@ export const mockFields = [
},
];
-export const optInJwtQueryResponse = (optInJwt) => ({
- data: {
- project: {
- id: '1',
- ciCdSettings: {
- optInJwt,
- __typename: 'ProjectCiCdSetting',
- },
- __typename: 'Project',
- },
- },
-});
-
-export const optInJwtMutationResponse = (optInJwt) => ({
- data: {
- projectCiCdSettingsUpdate: {
- ciCdSettings: {
- optInJwt,
- __typename: 'ProjectCiCdSetting',
- },
- errors: [],
- __typename: 'ProjectCiCdSettingsUpdatePayload',
- },
- },
-});
-
export const inboundJobTokenScopeEnabledResponse = {
data: {
project: {
diff --git a/spec/frontend/token_access/opt_in_jwt_spec.js b/spec/frontend/token_access/opt_in_jwt_spec.js
deleted file mode 100644
index cdb385aa743..00000000000
--- a/spec/frontend/token_access/opt_in_jwt_spec.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { GlLink, GlLoadingIcon, GlToggle, GlSprintf } from '@gitlab/ui';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import { OPT_IN_JWT_HELP_LINK } from '~/token_access/constants';
-import OptInJwt from '~/token_access/components/opt_in_jwt.vue';
-import getOptInJwtSettingQuery from '~/token_access/graphql/queries/get_opt_in_jwt_setting.query.graphql';
-import updateOptInJwtMutation from '~/token_access/graphql/mutations/update_opt_in_jwt.mutation.graphql';
-import { optInJwtMutationResponse, optInJwtQueryResponse } from './mock_data';
-
-const errorMessage = 'An error occurred';
-const error = new Error(errorMessage);
-
-Vue.use(VueApollo);
-
-jest.mock('~/alert');
-
-describe('OptInJwt component', () => {
- let wrapper;
-
- const failureHandler = jest.fn().mockRejectedValue(error);
- const enabledOptInJwtHandler = jest.fn().mockResolvedValue(optInJwtQueryResponse(true));
- const disabledOptInJwtHandler = jest.fn().mockResolvedValue(optInJwtQueryResponse(false));
- const updateOptInJwtHandler = jest.fn().mockResolvedValue(optInJwtMutationResponse(true));
-
- const findHelpLink = () => wrapper.findComponent(GlLink);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findToggle = () => wrapper.findComponent(GlToggle);
- const findOptInJwtExpandedSection = () => wrapper.findByTestId('opt-in-jwt-expanded-section');
-
- const createMockApolloProvider = (requestHandlers) => {
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = (requestHandlers, mountFn = shallowMountExtended, options = {}) => {
- wrapper = mountFn(OptInJwt, {
- provide: {
- fullPath: 'root/my-repo',
- },
- apolloProvider: createMockApolloProvider(requestHandlers),
- data() {
- return {
- targetProjectPath: 'root/test',
- };
- },
- ...options,
- });
- };
-
- const createShallowComponent = (requestHandlers, options = {}) =>
- createComponent(requestHandlers, shallowMountExtended, options);
- const createFullComponent = (requestHandlers, options = {}) =>
- createComponent(requestHandlers, mountExtended, options);
-
- describe('loading state', () => {
- it('shows loading state and hides toggle while waiting on query to resolve', async () => {
- createShallowComponent([[getOptInJwtSettingQuery, enabledOptInJwtHandler]]);
-
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findToggle().exists()).toBe(false);
-
- await waitForPromises();
-
- expect(findLoadingIcon().exists()).toBe(false);
- expect(findToggle().exists()).toBe(true);
- });
- });
-
- describe('template', () => {
- it('renders help link', async () => {
- createShallowComponent([[getOptInJwtSettingQuery, enabledOptInJwtHandler]], {
- stubs: {
- GlToggle,
- GlSprintf,
- GlLink,
- },
- });
- await waitForPromises();
-
- expect(findHelpLink().exists()).toBe(true);
- expect(findHelpLink().attributes('href')).toBe(OPT_IN_JWT_HELP_LINK);
- });
- });
-
- describe('toggle JWT token access', () => {
- it('code instruction is visible when toggle is enabled', async () => {
- createShallowComponent([[getOptInJwtSettingQuery, enabledOptInJwtHandler]]);
-
- await waitForPromises();
-
- expect(findToggle().props('value')).toBe(true);
- expect(findOptInJwtExpandedSection().exists()).toBe(true);
- });
-
- it('code instruction is hidden when toggle is disabled', async () => {
- createShallowComponent([[getOptInJwtSettingQuery, disabledOptInJwtHandler]]);
-
- await waitForPromises();
-
- expect(findToggle().props('value')).toBe(false);
- expect(findOptInJwtExpandedSection().exists()).toBe(false);
- });
-
- describe('update JWT token access', () => {
- it('calls updateOptInJwtMutation with correct arguments', async () => {
- createFullComponent([
- [getOptInJwtSettingQuery, disabledOptInJwtHandler],
- [updateOptInJwtMutation, updateOptInJwtHandler],
- ]);
-
- await waitForPromises();
-
- findToggle().vm.$emit('change', true);
-
- expect(updateOptInJwtHandler).toHaveBeenCalledWith({
- input: {
- fullPath: 'root/my-repo',
- optInJwt: true,
- },
- });
- });
-
- it('handles update error', async () => {
- createFullComponent([
- [getOptInJwtSettingQuery, enabledOptInJwtHandler],
- [updateOptInJwtMutation, failureHandler],
- ]);
-
- await waitForPromises();
-
- findToggle().vm.$emit('change', false);
-
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: 'An error occurred while update the setting. Please try again.',
- });
- });
- });
- });
-});
diff --git a/spec/frontend/token_access/token_access_app_spec.js b/spec/frontend/token_access/token_access_app_spec.js
index cff16fd125c..77356f1b839 100644
--- a/spec/frontend/token_access/token_access_app_spec.js
+++ b/spec/frontend/token_access/token_access_app_spec.js
@@ -1,7 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import OutboundTokenAccess from '~/token_access/components/outbound_token_access.vue';
import InboundTokenAccess from '~/token_access/components/inbound_token_access.vue';
-import OptInJwt from '~/token_access/components/opt_in_jwt.vue';
import TokenAccessApp from '~/token_access/components/token_access_app.vue';
describe('TokenAccessApp component', () => {
@@ -9,7 +8,6 @@ describe('TokenAccessApp component', () => {
const findOutboundTokenAccess = () => wrapper.findComponent(OutboundTokenAccess);
const findInboundTokenAccess = () => wrapper.findComponent(InboundTokenAccess);
- const findOptInJwt = () => wrapper.findComponent(OptInJwt);
const createComponent = () => {
wrapper = shallowMount(TokenAccessApp);
@@ -20,10 +18,6 @@ describe('TokenAccessApp component', () => {
createComponent();
});
- it('renders the opt in jwt component', () => {
- expect(findOptInJwt().exists()).toBe(true);
- });
-
it('renders the outbound token access component', () => {
expect(findOutboundTokenAccess().exists()).toBe(true);
});
diff --git a/spec/frontend/work_items/components/notes/work_item_add_note_spec.js b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
index a97164f9dce..fbcf759d50f 100644
--- a/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
@@ -5,21 +5,16 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking } from 'helpers/tracking_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { clearDraft } from '~/lib/utils/autosave';
-import { config } from '~/graphql_shared/issuable_client';
import WorkItemAddNote from '~/work_items/components/notes/work_item_add_note.vue';
import WorkItemCommentLocked from '~/work_items/components/notes/work_item_comment_locked.vue';
import WorkItemCommentForm from '~/work_items/components/notes/work_item_comment_form.vue';
import createNoteMutation from '~/work_items/graphql/notes/create_work_item_note.mutation.graphql';
import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
-import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
-import workItemNotesQuery from '~/work_items/graphql/notes/work_item_notes.query.graphql';
import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
import {
- workItemResponseFactory,
- workItemQueryResponse,
- projectWorkItemResponse,
createWorkItemNoteResponse,
- mockWorkItemNotesResponse,
+ workItemByIidResponseFactory,
+ workItemQueryResponse,
} from '../../mock_data';
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
@@ -33,7 +28,6 @@ describe('Work item add note', () => {
Vue.use(VueApollo);
const mutationSuccessHandler = jest.fn().mockResolvedValue(createWorkItemNoteResponse);
- const workItemByIidResponseHandler = jest.fn().mockResolvedValue(projectWorkItemResponse);
let workItemResponseHandler;
const findCommentForm = () => wrapper.findComponent(WorkItemCommentForm);
@@ -42,9 +36,8 @@ describe('Work item add note', () => {
const createComponent = async ({
mutationHandler = mutationSuccessHandler,
canUpdate = true,
- workItemResponse = workItemResponseFactory({ canUpdate }),
- queryVariables = { id: workItemId },
- fetchByIid = false,
+ workItemResponse = workItemByIidResponseFactory({ canUpdate }),
+ queryVariables = { iid: '1' },
signedIn = true,
isEditing = true,
workItemType = 'Task',
@@ -55,24 +48,10 @@ describe('Work item add note', () => {
window.gon.current_user_avatar_url = 'avatar.png';
}
- const apolloProvider = createMockApollo(
- [
- [workItemQuery, workItemResponseHandler],
- [createNoteMutation, mutationHandler],
- [workItemByIidQuery, workItemByIidResponseHandler],
- ],
- {},
- { ...config.cacheConfig },
- );
-
- apolloProvider.clients.defaultClient.writeQuery({
- query: workItemNotesQuery,
- variables: {
- id: workItemId,
- pageSize: 100,
- },
- data: mockWorkItemNotesResponse.data,
- });
+ const apolloProvider = createMockApollo([
+ [workItemByIidQuery, workItemResponseHandler],
+ [createNoteMutation, mutationHandler],
+ ]);
const { id } = workItemQueryResponse.data.workItem;
wrapper = shallowMountExtended(WorkItemAddNote, {
@@ -81,7 +60,6 @@ describe('Work item add note', () => {
workItemId: id,
fullPath: 'test-project-path',
queryVariables,
- fetchByIid,
workItemType,
markdownPreviewPath: '/group/project/preview_markdown?target_type=WorkItem',
autocompleteDataSources: {},
@@ -139,9 +117,7 @@ describe('Work item add note', () => {
await createComponent({
isEditing: true,
signedIn: true,
- queryVariables: {
- id: mockWorkItemNotesResponse.data.workItem.id,
- },
+ queryVariables: { iid: '1' },
});
findCommentForm().vm.$emit('submitForm', 'some text');
@@ -244,23 +220,14 @@ describe('Work item add note', () => {
});
});
- it('calls the global ID work item query when `fetchByIid` prop is false', async () => {
- createComponent({ fetchByIid: false });
- await waitForPromises();
+ it('calls the work item query', async () => {
+ await createComponent();
expect(workItemResponseHandler).toHaveBeenCalled();
- expect(workItemByIidResponseHandler).not.toHaveBeenCalled();
- });
-
- it('calls the IID work item query when when `fetchByIid` prop is true', async () => {
- await createComponent({ fetchByIid: true, isEditing: false });
-
- expect(workItemResponseHandler).not.toHaveBeenCalled();
- expect(workItemByIidResponseHandler).toHaveBeenCalled();
});
- it('skips calling the handlers when missing the needed queryVariables', async () => {
- await createComponent({ queryVariables: {}, fetchByIid: false, isEditing: false });
+ it('skips calling the work item query when missing queryVariables', async () => {
+ await createComponent({ queryVariables: {}, isEditing: false });
expect(workItemResponseHandler).not.toHaveBeenCalled();
});
diff --git a/spec/frontend/work_items/components/notes/work_item_discussion_spec.js b/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
index 568b76150c4..28c8ea13a23 100644
--- a/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
@@ -11,7 +11,7 @@ import {
} from 'jest/work_items/mock_data';
import { WIDGET_TYPE_NOTES } from '~/work_items/constants';
-const mockWorkItemNotesWidgetResponseWithComments = mockWorkItemNotesResponseWithComments.data.workItem.widgets.find(
+const mockWorkItemNotesWidgetResponseWithComments = mockWorkItemNotesResponseWithComments.data.workspace.workItems.nodes[0].widgets.find(
(widget) => widget.type === WIDGET_TYPE_NOTES,
);
@@ -28,8 +28,7 @@ describe('Work Item Discussion', () => {
const createComponent = ({
discussion = [mockWorkItemCommentNote],
workItemId = mockWorkItemId,
- queryVariables = { id: workItemId },
- fetchByIid = false,
+ queryVariables = { iid: '1' },
fullPath = 'gitlab-org',
workItemType = 'Task',
} = {}) => {
@@ -38,7 +37,6 @@ describe('Work Item Discussion', () => {
discussion,
workItemId,
queryVariables,
- fetchByIid,
fullPath,
workItemType,
markdownPreviewPath: '/group/project/preview_markdown?target_type=WorkItem',
diff --git a/spec/frontend/work_items/components/notes/work_item_note_spec.js b/spec/frontend/work_items/components/notes/work_item_note_spec.js
index f8be2f5667b..956b52bb74c 100644
--- a/spec/frontend/work_items/components/notes/work_item_note_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_note_spec.js
@@ -11,13 +11,14 @@ import NoteBody from '~/work_items/components/notes/work_item_note_body.vue';
import NoteHeader from '~/notes/components/note_header.vue';
import NoteActions from '~/work_items/components/notes/work_item_note_actions.vue';
import WorkItemCommentForm from '~/work_items/components/notes/work_item_comment_form.vue';
-import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
import updateWorkItemNoteMutation from '~/work_items/graphql/notes/update_work_item_note.mutation.graphql';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
+import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
import {
mockAssignees,
mockWorkItemCommentNote,
updateWorkItemMutationResponse,
+ workItemByIidResponseFactory,
workItemQueryResponse,
} from 'jest/work_items/mock_data';
import { i18n, TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
@@ -45,7 +46,7 @@ describe('Work Item Note', () => {
},
});
- const workItemResponseHandler = jest.fn().mockResolvedValue(workItemQueryResponse);
+ const workItemResponseHandler = jest.fn().mockResolvedValue(workItemByIidResponseFactory());
const updateWorkItemMutationSuccessHandler = jest
.fn()
@@ -68,8 +69,7 @@ describe('Work Item Note', () => {
workItemId = mockWorkItemId,
updateWorkItemMutationHandler = updateWorkItemMutationSuccessHandler,
assignees = mockAssignees,
- queryVariables = { id: mockWorkItemId },
- fetchByIid = false,
+ queryVariables = { iid: '1' },
} = {}) => {
wrapper = shallowMount(WorkItemNote, {
propsData: {
@@ -81,11 +81,10 @@ describe('Work Item Note', () => {
autocompleteDataSources: {},
assignees,
queryVariables,
- fetchByIid,
fullPath: 'test-project-path',
},
apolloProvider: mockApollo([
- [workItemQuery, workItemResponseHandler],
+ [workItemByIidQuery, workItemResponseHandler],
[updateWorkItemNoteMutation, updateNoteMutationHandler],
[updateWorkItemMutation, updateWorkItemMutationHandler],
]),
diff --git a/spec/frontend/work_items/components/work_item_notes_spec.js b/spec/frontend/work_items/components/work_item_notes_spec.js
index 9cbe8283468..be5861ba1e2 100644
--- a/spec/frontend/work_items/components/work_item_notes_spec.js
+++ b/spec/frontend/work_items/components/work_item_notes_spec.js
@@ -10,7 +10,6 @@ import WorkItemNotes from '~/work_items/components/work_item_notes.vue';
import WorkItemDiscussion from '~/work_items/components/notes/work_item_discussion.vue';
import WorkItemAddNote from '~/work_items/components/notes/work_item_add_note.vue';
import WorkItemNotesActivityHeader from '~/work_items/components/notes/work_item_notes_activity_header.vue';
-import workItemNotesQuery from '~/work_items/graphql/notes/work_item_notes.query.graphql';
import workItemNotesByIidQuery from '~/work_items/graphql/notes/work_item_notes_by_iid.query.graphql';
import deleteWorkItemNoteMutation from '~/work_items/graphql/notes/delete_work_item_notes.mutation.graphql';
import workItemNoteCreatedSubscription from '~/work_items/graphql/notes/work_item_note_created.subscription.graphql';
@@ -36,15 +35,11 @@ const mockNotesWidgetResponse = mockWorkItemNotesResponse.data.workItem.widgets.
(widget) => widget.type === WIDGET_TYPE_NOTES,
);
-const mockNotesByIidWidgetResponse = mockWorkItemNotesByIidResponse.data.workspace.workItems.nodes[0].widgets.find(
+const mockMoreNotesWidgetResponse = mockMoreWorkItemNotesResponse.data.workspace.workItems.nodes[0].widgets.find(
(widget) => widget.type === WIDGET_TYPE_NOTES,
);
-const mockMoreNotesWidgetResponse = mockMoreWorkItemNotesResponse.data.workItem.widgets.find(
- (widget) => widget.type === WIDGET_TYPE_NOTES,
-);
-
-const mockWorkItemNotesWidgetResponseWithComments = mockWorkItemNotesResponseWithComments.data.workItem.widgets.find(
+const mockWorkItemNotesWidgetResponseWithComments = mockWorkItemNotesResponseWithComments.data.workspace.workItems.nodes[0].widgets.find(
(widget) => widget.type === WIDGET_TYPE_NOTES,
);
@@ -61,7 +56,6 @@ describe('WorkItemNotes component', () => {
const findAllSystemNotes = () => wrapper.findAllComponents(SystemNote);
const findAllListItems = () => wrapper.findAll('ul.timeline > *');
- const findWorkItemAddNote = () => wrapper.findComponent(WorkItemAddNote);
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findActivityHeader = () => wrapper.findComponent(WorkItemNotesActivityHeader);
const findSystemNoteAtIndex = (index) => findAllSystemNotes().at(index);
@@ -69,10 +63,7 @@ describe('WorkItemNotes component', () => {
const findWorkItemCommentNoteAtIndex = (index) => findAllWorkItemCommentNotes().at(index);
const findDeleteNoteModal = () => wrapper.findComponent(GlModal);
- const workItemNotesQueryHandler = jest.fn().mockResolvedValue(mockWorkItemNotesResponse);
- const workItemNotesByIidQueryHandler = jest
- .fn()
- .mockResolvedValue(mockWorkItemNotesByIidResponse);
+ const workItemNotesQueryHandler = jest.fn().mockResolvedValue(mockWorkItemNotesByIidResponse);
const workItemMoreNotesQueryHandler = jest.fn().mockResolvedValue(mockMoreWorkItemNotesResponse);
const workItemNotesWithCommentsQueryHandler = jest
.fn()
@@ -93,7 +84,6 @@ describe('WorkItemNotes component', () => {
const createComponent = ({
workItemId = mockWorkItemId,
- fetchByIid = false,
workItemIid = mockWorkItemIid,
defaultWorkItemNotesQueryHandler = workItemNotesQueryHandler,
deleteWINoteMutationHandler = deleteWorkItemNoteMutationSuccessHandler,
@@ -101,8 +91,7 @@ describe('WorkItemNotes component', () => {
} = {}) => {
wrapper = shallowMount(WorkItemNotes, {
apolloProvider: createMockApollo([
- [workItemNotesQuery, defaultWorkItemNotesQueryHandler],
- [workItemNotesByIidQuery, workItemNotesByIidQueryHandler],
+ [workItemNotesByIidQuery, defaultWorkItemNotesQueryHandler],
[deleteWorkItemNoteMutation, deleteWINoteMutationHandler],
[workItemNoteCreatedSubscription, notesCreateSubscriptionHandler],
[workItemNoteUpdatedSubscription, notesUpdateSubscriptionHandler],
@@ -111,11 +100,8 @@ describe('WorkItemNotes component', () => {
propsData: {
workItemId,
workItemIid,
- queryVariables: {
- id: workItemId,
- },
+ queryVariables: { iid: '1' },
fullPath: 'test-path',
- fetchByIid,
workItemType: 'task',
reportAbusePath: '/report/abuse/path',
isModal,
@@ -134,17 +120,6 @@ describe('WorkItemNotes component', () => {
expect(findActivityHeader().exists()).toBe(true);
});
- it('passes correct props to comment form component', async () => {
- createComponent({
- workItemId: mockWorkItemId,
- fetchByIid: false,
- defaultWorkItemNotesQueryHandler: workItemNotesByIidQueryHandler,
- });
- await waitForPromises();
-
- expect(findWorkItemAddNote().props('fetchByIid')).toEqual(false);
- });
-
describe('when notes are loading', () => {
it('renders skeleton loader', () => {
expect(findSkeletonLoader().exists()).toBe(true);
@@ -162,28 +137,15 @@ describe('WorkItemNotes component', () => {
it('renders system notes to the length of the response', async () => {
await waitForPromises();
+ expect(workItemNotesQueryHandler).toHaveBeenCalledWith({
+ after: undefined,
+ iid: '1',
+ pageSize: 30,
+ });
expect(findAllSystemNotes()).toHaveLength(mockNotesWidgetResponse.discussions.nodes.length);
});
});
- describe('when the notes are fetched by `iid`', () => {
- beforeEach(async () => {
- createComponent({ workItemId: mockWorkItemId, fetchByIid: true });
- await waitForPromises();
- });
-
- it('renders the notes list to the length of the response', () => {
- expect(workItemNotesByIidQueryHandler).toHaveBeenCalled();
- expect(findAllSystemNotes()).toHaveLength(
- mockNotesByIidWidgetResponse.discussions.nodes.length,
- );
- });
-
- it('passes correct props to comment form component', () => {
- expect(findWorkItemAddNote().props('fetchByIid')).toEqual(true);
- });
- });
-
describe('Pagination', () => {
describe('When there is no next page', () => {
it('fetch more notes is not called', async () => {
@@ -202,14 +164,14 @@ describe('WorkItemNotes component', () => {
it('fetch more notes should be called', async () => {
expect(workItemMoreNotesQueryHandler).toHaveBeenCalledWith({
pageSize: DEFAULT_PAGE_SIZE_NOTES,
- id: 'gid://gitlab/WorkItem/1',
+ iid: '1',
});
await nextTick();
expect(workItemMoreNotesQueryHandler).toHaveBeenCalledWith({
pageSize: DEFAULT_PAGE_SIZE_NOTES,
- id: 'gid://gitlab/WorkItem/1',
+ iid: '1',
after: mockMoreNotesWidgetResponse.discussions.pageInfo.endCursor,
});
});
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index 36e8d713789..2ab31908577 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -2235,186 +2235,197 @@ export const mockWorkItemNotesByIidResponse = {
};
export const mockMoreWorkItemNotesResponse = {
data: {
- workItem: {
- id: 'gid://gitlab/WorkItem/600',
- iid: '60',
- widgets: [
- {
- __typename: 'WorkItemWidgetIteration',
- },
- {
- __typename: 'WorkItemWidgetWeight',
- },
- {
- __typename: 'WorkItemWidgetAssignees',
- },
- {
- __typename: 'WorkItemWidgetLabels',
- },
- {
- __typename: 'WorkItemWidgetDescription',
- },
- {
- __typename: 'WorkItemWidgetHierarchy',
- },
- {
- __typename: 'WorkItemWidgetStartAndDueDate',
- },
- {
- __typename: 'WorkItemWidgetMilestone',
- },
- {
- type: 'NOTES',
- discussions: {
- pageInfo: {
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: null,
- endCursor: 'endCursor',
- __typename: 'PageInfo',
- },
- nodes: [
+ workspace: {
+ id: 'gid://gitlab/Project/6',
+ workItems: {
+ nodes: [
+ {
+ id: 'gid://gitlab/WorkItem/600',
+ iid: '60',
+ widgets: [
{
- id: 'gid://gitlab/Discussion/8bbc4890b6ff0f2cde93a5a0947cd2b8a13d3b6e',
- notes: {
- nodes: [
- {
- id: 'gid://gitlab/Note/2428',
- body: 'added #31 as parent issue',
- bodyHtml:
- '<p data-sourcepos="1:1-1:25" dir="auto">added <a href="/flightjs/Flight/-/issues/31" data-reference-type="issue" data-original="#31" data-link="false" data-link-reference="false" data-project="6" data-issue="224" data-project-path="flightjs/Flight" data-iid="31" data-issue-type="issue" data-container=body data-placement="top" title="Perferendis est quae totam quia laborum tempore ut voluptatem." class="gfm gfm-issue">#31</a> as parent issue</p>',
- systemNoteIconName: 'link',
- createdAt: '2022-11-14T04:18:59Z',
- lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
- lastEditedBy: null,
- system: true,
- internal: false,
- discussion: {
- id: 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da1112356a59e',
- },
- userPermissions: {
- adminNote: false,
- awardEmoji: true,
- readNote: true,
- createNote: true,
- resolveNote: true,
- repositionNote: true,
- __typename: 'NotePermissions',
- },
- author: {
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- id: 'gid://gitlab/User/1',
- name: 'Administrator',
- username: 'root',
- webUrl: 'http://127.0.0.1:3000/root',
- __typename: 'UserCore',
- },
- __typename: 'Note',
- },
- ],
- __typename: 'NoteConnection',
- },
- __typename: 'Discussion',
+ __typename: 'WorkItemWidgetIteration',
},
{
- id: 'gid://gitlab/Discussion/7b08b89a728a5ceb7de8334246837ba1d07270dc',
- notes: {
- nodes: [
- {
- id: 'gid://gitlab/MilestoneNote/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83823',
- body: 'changed milestone to %v4.0',
- bodyHtml:
- '<p data-sourcepos="1:1-1:23" dir="auto">changed milestone to <a href="/flightjs/Flight/-/milestones/5" data-reference-type="milestone" data-original="%5" data-link="false" data-link-reference="false" data-project="6" data-milestone="30" data-container=body data-placement="top" title="" class="gfm gfm-milestone has-tooltip">%v4.0</a></p>',
- systemNoteIconName: 'clock',
- createdAt: '2022-11-14T04:18:59Z',
- lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
- lastEditedBy: null,
- system: true,
- internal: false,
- discussion: {
- id: 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da1272356a59e',
- },
- userPermissions: {
- adminNote: false,
- awardEmoji: true,
- readNote: true,
- createNote: true,
- resolveNote: true,
- repositionNote: true,
- __typename: 'NotePermissions',
- },
- author: {
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- id: 'gid://gitlab/User/1',
- name: 'Administrator',
- username: 'root',
- webUrl: 'http://127.0.0.1:3000/root',
- __typename: 'UserCore',
- },
- __typename: 'Note',
- },
- ],
- __typename: 'NoteConnection',
- },
- __typename: 'Discussion',
+ __typename: 'WorkItemWidgetWeight',
},
{
- id: 'gid://gitlab/Discussion/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83864',
- notes: {
+ __typename: 'WorkItemWidgetAssignees',
+ },
+ {
+ __typename: 'WorkItemWidgetLabels',
+ },
+ {
+ __typename: 'WorkItemWidgetDescription',
+ },
+ {
+ __typename: 'WorkItemWidgetHierarchy',
+ },
+ {
+ __typename: 'WorkItemWidgetStartAndDueDate',
+ },
+ {
+ __typename: 'WorkItemWidgetMilestone',
+ },
+ {
+ type: 'NOTES',
+ discussions: {
+ pageInfo: {
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: null,
+ endCursor: 'endCursor',
+ __typename: 'PageInfo',
+ },
nodes: [
{
- id: 'gid://gitlab/WeightNote/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83864',
- body: 'changed weight to **89**',
- bodyHtml: '<p dir="auto">changed weight to <strong>89</strong></p>',
- systemNoteIconName: 'weight',
- createdAt: '2022-11-25T07:16:20Z',
- lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
- lastEditedBy: null,
- system: true,
- internal: false,
- discussion: {
- id: 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da12723569876',
+ id: 'gid://gitlab/Discussion/8bbc4890b6ff0f2cde93a5a0947cd2b8a13d3b6e',
+ notes: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Note/2428',
+ body: 'added #31 as parent issue',
+ bodyHtml:
+ '<p data-sourcepos="1:1-1:25" dir="auto">added <a href="/flightjs/Flight/-/issues/31" data-reference-type="issue" data-original="#31" data-link="false" data-link-reference="false" data-project="6" data-issue="224" data-project-path="flightjs/Flight" data-iid="31" data-issue-type="issue" data-container=body data-placement="top" title="Perferendis est quae totam quia laborum tempore ut voluptatem." class="gfm gfm-issue">#31</a> as parent issue</p>',
+ systemNoteIconName: 'link',
+ createdAt: '2022-11-14T04:18:59Z',
+ lastEditedAt: null,
+ url:
+ 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ lastEditedBy: null,
+ system: true,
+ internal: false,
+ discussion: {
+ id:
+ 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da1112356a59e',
+ },
+ userPermissions: {
+ adminNote: false,
+ awardEmoji: true,
+ readNote: true,
+ createNote: true,
+ resolveNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ author: {
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: 'gid://gitlab/User/1',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ __typename: 'Note',
+ },
+ ],
+ __typename: 'NoteConnection',
},
- userPermissions: {
- adminNote: false,
- awardEmoji: true,
- readNote: true,
- createNote: true,
- resolveNote: true,
- repositionNote: true,
- __typename: 'NotePermissions',
+ __typename: 'Discussion',
+ },
+ {
+ id: 'gid://gitlab/Discussion/7b08b89a728a5ceb7de8334246837ba1d07270dc',
+ notes: {
+ nodes: [
+ {
+ id:
+ 'gid://gitlab/MilestoneNote/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83823',
+ body: 'changed milestone to %v4.0',
+ bodyHtml:
+ '<p data-sourcepos="1:1-1:23" dir="auto">changed milestone to <a href="/flightjs/Flight/-/milestones/5" data-reference-type="milestone" data-original="%5" data-link="false" data-link-reference="false" data-project="6" data-milestone="30" data-container=body data-placement="top" title="" class="gfm gfm-milestone has-tooltip">%v4.0</a></p>',
+ systemNoteIconName: 'clock',
+ createdAt: '2022-11-14T04:18:59Z',
+ lastEditedAt: null,
+ url:
+ 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ lastEditedBy: null,
+ system: true,
+ internal: false,
+ discussion: {
+ id:
+ 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da1272356a59e',
+ },
+ userPermissions: {
+ adminNote: false,
+ awardEmoji: true,
+ readNote: true,
+ createNote: true,
+ resolveNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ author: {
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: 'gid://gitlab/User/1',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ __typename: 'Note',
+ },
+ ],
+ __typename: 'NoteConnection',
},
- author: {
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- id: 'gid://gitlab/User/1',
- name: 'Administrator',
- username: 'root',
- webUrl: 'http://127.0.0.1:3000/root',
- __typename: 'UserCore',
+ __typename: 'Discussion',
+ },
+ {
+ id: 'gid://gitlab/Discussion/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83864',
+ notes: {
+ nodes: [
+ {
+ id: 'gid://gitlab/WeightNote/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83864',
+ body: 'changed weight to **89**',
+ bodyHtml: '<p dir="auto">changed weight to <strong>89</strong></p>',
+ systemNoteIconName: 'weight',
+ createdAt: '2022-11-25T07:16:20Z',
+ lastEditedAt: null,
+ url:
+ 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ lastEditedBy: null,
+ system: true,
+ internal: false,
+ discussion: {
+ id:
+ 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da12723569876',
+ },
+ userPermissions: {
+ adminNote: false,
+ awardEmoji: true,
+ readNote: true,
+ createNote: true,
+ resolveNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ author: {
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: 'gid://gitlab/User/1',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ __typename: 'Note',
+ },
+ ],
+ __typename: 'NoteConnection',
},
- __typename: 'Note',
+ __typename: 'Discussion',
},
],
- __typename: 'NoteConnection',
+ __typename: 'DiscussionConnection',
},
- __typename: 'Discussion',
+ __typename: 'WorkItemWidgetNotes',
},
],
- __typename: 'DiscussionConnection',
+ __typename: 'WorkItem',
},
- __typename: 'WorkItemWidgetNotes',
- },
- ],
- __typename: 'WorkItem',
+ ],
+ },
},
},
};
@@ -2514,177 +2525,187 @@ export const mockWorkItemCommentNote = {
export const mockWorkItemNotesResponseWithComments = {
data: {
- workItem: {
- id: 'gid://gitlab/WorkItem/600',
- iid: '60',
- widgets: [
- {
- __typename: 'WorkItemWidgetIteration',
- },
- {
- __typename: 'WorkItemWidgetWeight',
- },
- {
- __typename: 'WorkItemWidgetAssignees',
- },
- {
- __typename: 'WorkItemWidgetLabels',
- },
- {
- __typename: 'WorkItemWidgetDescription',
- },
- {
- __typename: 'WorkItemWidgetHierarchy',
- },
- {
- __typename: 'WorkItemWidgetStartAndDueDate',
- },
- {
- __typename: 'WorkItemWidgetMilestone',
- },
- {
- type: 'NOTES',
- discussions: {
- pageInfo: {
- hasNextPage: false,
- hasPreviousPage: false,
- startCursor: null,
- endCursor: null,
- __typename: 'PageInfo',
- },
- nodes: [
+ workspace: {
+ id: 'gid://gitlab/Project/6',
+ workItems: {
+ nodes: [
+ {
+ id: 'gid://gitlab/WorkItem/600',
+ iid: '60',
+ widgets: [
{
- id: 'gid://gitlab/Discussion/8bbc4890b6ff0f2cde93a5a0947cd2b8a13d3b6e',
- notes: {
- nodes: [
- {
- id: 'gid://gitlab/DiscussionNote/174',
- body: 'Separate thread',
- bodyHtml: '<p data-sourcepos="1:1-1:15" dir="auto">Separate thread</p>',
- system: false,
- internal: false,
- systemNoteIconName: null,
- createdAt: '2023-01-12T07:47:40Z',
- lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
- lastEditedBy: null,
- discussion: {
- id: 'gid://gitlab/Discussion/2bb1162fd0d39297d1a68fdd7d4083d3780af0f3',
- __typename: 'Discussion',
- },
- author: {
- id: 'gid://gitlab/User/1',
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- name: 'Administrator',
- username: 'root',
- webUrl: 'http://127.0.0.1:3000/root',
- __typename: 'UserCore',
- },
- userPermissions: {
- adminNote: true,
- awardEmoji: true,
- readNote: true,
- createNote: true,
- resolveNote: true,
- repositionNote: true,
- __typename: 'NotePermissions',
- },
- __typename: 'Note',
- },
- {
- id: 'gid://gitlab/DiscussionNote/235',
- body: 'Thread comment',
- bodyHtml: '<p data-sourcepos="1:1-1:15" dir="auto">Thread comment</p>',
- system: false,
- internal: false,
- systemNoteIconName: null,
- createdAt: '2023-01-18T09:09:54Z',
- lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
- lastEditedBy: null,
- discussion: {
- id: 'gid://gitlab/Discussion/2bb1162fd0d39297d1a68fdd7d4083d3780af0f3',
- __typename: 'Discussion',
- },
- author: {
- id: 'gid://gitlab/User/1',
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- name: 'Administrator',
- username: 'root',
- webUrl: 'http://127.0.0.1:3000/root',
- __typename: 'UserCore',
- },
- userPermissions: {
- adminNote: true,
- awardEmoji: true,
- readNote: true,
- createNote: true,
- resolveNote: true,
- repositionNote: true,
- __typename: 'NotePermissions',
- },
- __typename: 'Note',
- },
- ],
- __typename: 'NoteConnection',
- },
- __typename: 'Discussion',
+ __typename: 'WorkItemWidgetIteration',
},
{
- id: 'gid://gitlab/Discussion/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83864',
- notes: {
+ __typename: 'WorkItemWidgetWeight',
+ },
+ {
+ __typename: 'WorkItemWidgetAssignees',
+ },
+ {
+ __typename: 'WorkItemWidgetLabels',
+ },
+ {
+ __typename: 'WorkItemWidgetDescription',
+ },
+ {
+ __typename: 'WorkItemWidgetHierarchy',
+ },
+ {
+ __typename: 'WorkItemWidgetStartAndDueDate',
+ },
+ {
+ __typename: 'WorkItemWidgetMilestone',
+ },
+ {
+ type: 'NOTES',
+ discussions: {
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: null,
+ endCursor: null,
+ __typename: 'PageInfo',
+ },
nodes: [
{
- id: 'gid://gitlab/WeightNote/0f2f195ec0d1ef95ee9d5b10446b8e96a9883864',
- body: 'Main thread 2',
- bodyHtml: '<p data-sourcepos="1:1-1:15" dir="auto">Main thread 2</p>',
- systemNoteIconName: 'weight',
- createdAt: '2022-11-25T07:16:20Z',
- lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
- lastEditedBy: null,
- system: false,
- internal: false,
- discussion: {
- id: 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da12723560987',
- },
- userPermissions: {
- adminNote: false,
- awardEmoji: true,
- readNote: true,
- createNote: true,
- resolveNote: true,
- repositionNote: true,
- __typename: 'NotePermissions',
+ id: 'gid://gitlab/Discussion/8bbc4890b6ff0f2cde93a5a0947cd2b8a13d3b6e',
+ notes: {
+ nodes: [
+ {
+ id: 'gid://gitlab/DiscussionNote/174',
+ body: 'Separate thread',
+ bodyHtml: '<p data-sourcepos="1:1-1:15" dir="auto">Separate thread</p>',
+ system: false,
+ internal: false,
+ systemNoteIconName: null,
+ createdAt: '2023-01-12T07:47:40Z',
+ lastEditedAt: null,
+ url:
+ 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ lastEditedBy: null,
+ discussion: {
+ id:
+ 'gid://gitlab/Discussion/2bb1162fd0d39297d1a68fdd7d4083d3780af0f3',
+ __typename: 'Discussion',
+ },
+ author: {
+ id: 'gid://gitlab/User/1',
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ userPermissions: {
+ adminNote: true,
+ awardEmoji: true,
+ readNote: true,
+ createNote: true,
+ resolveNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ __typename: 'Note',
+ },
+ {
+ id: 'gid://gitlab/DiscussionNote/235',
+ body: 'Thread comment',
+ bodyHtml: '<p data-sourcepos="1:1-1:15" dir="auto">Thread comment</p>',
+ system: false,
+ internal: false,
+ systemNoteIconName: null,
+ createdAt: '2023-01-18T09:09:54Z',
+ lastEditedAt: null,
+ url:
+ 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ lastEditedBy: null,
+ discussion: {
+ id:
+ 'gid://gitlab/Discussion/2bb1162fd0d39297d1a68fdd7d4083d3780af0f3',
+ __typename: 'Discussion',
+ },
+ author: {
+ id: 'gid://gitlab/User/1',
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ userPermissions: {
+ adminNote: true,
+ awardEmoji: true,
+ readNote: true,
+ createNote: true,
+ resolveNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ __typename: 'Note',
+ },
+ ],
+ __typename: 'NoteConnection',
},
- author: {
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- id: 'gid://gitlab/User/1',
- name: 'Administrator',
- username: 'root',
- webUrl: 'http://127.0.0.1:3000/root',
- __typename: 'UserCore',
+ __typename: 'Discussion',
+ },
+ {
+ id: 'gid://gitlab/Discussion/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83864',
+ notes: {
+ nodes: [
+ {
+ id: 'gid://gitlab/WeightNote/0f2f195ec0d1ef95ee9d5b10446b8e96a9883864',
+ body: 'Main thread 2',
+ bodyHtml: '<p data-sourcepos="1:1-1:15" dir="auto">Main thread 2</p>',
+ systemNoteIconName: 'weight',
+ createdAt: '2022-11-25T07:16:20Z',
+ lastEditedAt: null,
+ url:
+ 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ lastEditedBy: null,
+ system: false,
+ internal: false,
+ discussion: {
+ id:
+ 'gid://gitlab/Discussion/9c17769ca29798eddaed539d010da12723560987',
+ },
+ userPermissions: {
+ adminNote: false,
+ awardEmoji: true,
+ readNote: true,
+ createNote: true,
+ resolveNote: true,
+ repositionNote: true,
+ __typename: 'NotePermissions',
+ },
+ author: {
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: 'gid://gitlab/User/1',
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'http://127.0.0.1:3000/root',
+ __typename: 'UserCore',
+ },
+ __typename: 'Note',
+ },
+ ],
+ __typename: 'NoteConnection',
},
- __typename: 'Note',
+ __typename: 'Discussion',
},
],
- __typename: 'NoteConnection',
+ __typename: 'DiscussionConnection',
},
- __typename: 'Discussion',
+ __typename: 'WorkItemWidgetNotes',
},
],
- __typename: 'DiscussionConnection',
+ __typename: 'WorkItem',
},
- __typename: 'WorkItemWidgetNotes',
- },
- ],
- __typename: 'WorkItem',
+ ],
+ },
},
},
};
diff --git a/spec/mailers/emails/service_desk_spec.rb b/spec/mailers/emails/service_desk_spec.rb
index 76036fcd0b3..521cbe469d9 100644
--- a/spec/mailers/emails/service_desk_spec.rb
+++ b/spec/mailers/emails/service_desk_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
- let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:issue) { create(:issue, project: project, description: 'Some **issue** description') }
let_it_be(:email) { 'someone@gitlab.com' }
let_it_be(:expected_unsubscribe_url) { unsubscribe_sent_notification_url('b7721fc7e8419911a8bea145236a0519') }
let_it_be(:credential) { create(:service_desk_custom_email_credential, project: project) }
@@ -171,6 +171,13 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
it_behaves_like 'handle template content', 'thank_you'
end
+
+ context 'when issue description placeholder is used' do
+ let(:template_content) { 'thank you, your new issue has been created. %{ISSUE_DESCRIPTION}' }
+ let(:expected_body) { "<p dir=\"auto\">thank you, your new issue has been created. </p>#{issue.description_html}" }
+
+ it_behaves_like 'handle template content', 'thank_you'
+ end
end
end
diff --git a/spec/rubocop/cop/rspec/htt_party_basic_auth_spec.rb b/spec/rubocop/cop/rspec/httparty_basic_auth_spec.rb
index 537a7a9a7e9..c7f4c61b501 100644
--- a/spec/rubocop/cop/rspec/htt_party_basic_auth_spec.rb
+++ b/spec/rubocop/cop/rspec/httparty_basic_auth_spec.rb
@@ -4,7 +4,7 @@ require 'rubocop_spec_helper'
require_relative '../../../../rubocop/cop/rspec/httparty_basic_auth'
-RSpec.describe RuboCop::Cop::RSpec::HTTPartyBasicAuth do
+RSpec.describe RuboCop::Cop::RSpec::HTTPartyBasicAuth, feature_category: :shared do
context 'when passing `basic_auth: { user: ... }`' do
it 'registers an offense and corrects', :aggregate_failures do
expect_offense(<<~SOURCE, 'spec/foo.rb')
diff --git a/tests.yml b/tests.yml
index 26433e5c4fa..e4c84789459 100644
--- a/tests.yml
+++ b/tests.yml
@@ -40,6 +40,10 @@ mapping:
- source: tooling/(.+)\.rb
test: spec/tooling/%s_spec.rb
+ # RuboCop related specs
+ - source: rubocop/(.+)\.rb
+ test: spec/rubocop/%s_spec.rb
+
# Initializers should map to respective spec
- source: config/initializers/(.+)\.rb
test: spec/initializers/%s_spec.rb