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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-04-14 12:09:02 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-14 12:09:02 +0300
commit6d8f30ab0ae82678f10450d2158f24772f0c765c (patch)
treef308a3feb16199440421980e68501d5efa0a9b10
parentc192f26df39e9a2ab122c2d097b86e461599bde8 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/CODEOWNERS2
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js4
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js2
-rw-r--r--app/assets/javascripts/repository/components/fork_info.vue16
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue27
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue17
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_name_group.vue16
-rw-r--r--app/assets/javascripts/users_select/index.js9
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue8
-rw-r--r--app/controllers/projects/blob_controller.rb1
-rw-r--r--app/views/layouts/header/_current_user_dropdown_item.html.haml2
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--db/docs/approval_project_rules_users.yml3
-rw-r--r--db/post_migrate/20230403085958_add_sync_tmp_partial_index_on_vulnerability_report_types2.rb16
-rw-r--r--db/post_migrate/20230412214119_finalize_encrypt_ci_trigger_token.rb23
-rw-r--r--db/schema_migrations/202304030859581
-rw-r--r--db/schema_migrations/202304122141191
-rw-r--r--db/structure.sql2
-rw-r--r--doc/administration/static_objects_external_storage.md2
-rw-r--r--doc/api/group_repository_storage_moves.md2
-rw-r--r--doc/api/usage_data.md2
-rw-r--r--doc/development/gemfile.md11
-rw-r--r--doc/development/gitlab_flavored_markdown/index.md2
-rw-r--r--doc/development/gitlab_flavored_markdown/specification_guide/index.md2
-rw-r--r--doc/development/service_ping/implement.md2
-rw-r--r--doc/development/service_ping/index.md2
-rw-r--r--doc/development/service_ping/metrics_dictionary.md2
-rw-r--r--doc/development/service_ping/metrics_instrumentation.md2
-rw-r--r--doc/development/service_ping/metrics_lifecycle.md2
-rw-r--r--doc/development/service_ping/performance_indicator_metrics.md2
-rw-r--r--doc/development/service_ping/review_guidelines.md2
-rw-r--r--doc/development/service_ping/troubleshooting.md2
-rw-r--r--doc/development/service_ping/usage_data.md2
-rw-r--r--doc/development/snowplow/event_dictionary_guide.md2
-rw-r--r--doc/development/snowplow/implementation.md2
-rw-r--r--doc/development/snowplow/index.md2
-rw-r--r--doc/development/snowplow/infrastructure.md2
-rw-r--r--doc/development/snowplow/review_guidelines.md2
-rw-r--r--doc/development/snowplow/schemas.md2
-rw-r--r--doc/development/snowplow/troubleshooting.md2
-rw-r--r--doc/integration/gitpod.md2
-rw-r--r--doc/raketasks/migrate_snippets.md2
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md2
-rw-r--r--doc/user/application_security/dependency_scanning/index.md27
-rw-r--r--doc/user/compliance/license_scanning_of_cyclonedx_files/index.md5
-rw-r--r--doc/user/profile/img/busy_indicator_note_header_v13_9.pngbin24006 -> 0 bytes
-rw-r--r--doc/user/profile/img/busy_indicator_notes_v13_9.pngbin41947 -> 0 bytes
-rw-r--r--doc/user/profile/img/busy_indicator_profile_page_v13_6.pngbin25119 -> 0 bytes
-rw-r--r--doc/user/profile/img/busy_indicator_settings_menu_v13_6.pngbin26843 -> 0 bytes
-rw-r--r--doc/user/profile/img/busy_indicator_sidebar_collapsed_v13_9.pngbin6190 -> 0 bytes
-rw-r--r--doc/user/profile/img/busy_indicator_sidebar_v13_9.pngbin21914 -> 0 bytes
-rw-r--r--doc/user/profile/img/busy_indicator_user_popovers_v13_6.pngbin32158 -> 0 bytes
-rw-r--r--doc/user/profile/index.md20
-rw-r--r--doc/user/project/remote_development/connect_machine.md2
-rw-r--r--doc/user/project/remote_development/index.md2
-rw-r--r--doc/user/project/repository/file_finder.md2
-rw-r--r--doc/user/project/repository/vscode.md2
-rw-r--r--doc/user/project/repository/web_editor.md2
-rw-r--r--doc/user/project/web_ide/index.md2
-rw-r--r--doc/user/project/web_ide_beta/index.md2
-rw-r--r--doc/user/shortcuts.md2
-rw-r--r--doc/user/workspace/quick_start/index.md2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml1
-rw-r--r--lib/gitlab/database/schema_validation/adapters/column_database_adapter.rb43
-rw-r--r--lib/gitlab/database/schema_validation/adapters/column_structure_sql_adapter.rb114
-rw-r--r--lib/gitlab/database/schema_validation/database.rb6
-rw-r--r--lib/gitlab/database/schema_validation/pg_types.rb73
-rw-r--r--lib/gitlab/database/schema_validation/schema_objects/column.rb23
-rw-r--r--lib/gitlab/database/schema_validation/schema_objects/table.rb21
-rw-r--r--lib/gitlab/database/schema_validation/structure_sql.rb10
-rw-r--r--lib/gitlab/database/schema_validation/validators/base_validator.rb3
-rw-r--r--lib/gitlab/database/schema_validation/validators/different_definition_tables.rb50
-rw-r--r--lib/gitlab/database/schema_validation/validators/extra_table_columns.rb32
-rw-r--r--lib/gitlab/database/schema_validation/validators/missing_table_columns.rb32
-rw-r--r--lib/gitlab/slug/environment.rb2
-rw-r--r--locale/gitlab.pot20
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb48
-rw-r--r--spec/features/profiles/user_edit_profile_spec.rb4
-rw-r--r--spec/fixtures/structure.sql4
-rw-r--r--spec/frontend/gfm_auto_complete_spec.js5
-rw-r--r--spec/frontend/repository/components/fork_info_spec.js13
-rw-r--r--spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js3
-rw-r--r--spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/user_popover/user_popover_spec.js4
-rw-r--r--spec/lib/gitlab/database/schema_validation/adapters/column_database_adapter_spec.rb66
-rw-r--r--spec/lib/gitlab/database/schema_validation/adapters/column_structure_sql_adapter_spec.rb69
-rw-r--r--spec/lib/gitlab/database/schema_validation/schema_objects/column_spec.rb25
-rw-r--r--spec/lib/gitlab/database/schema_validation/schema_objects/table_spec.rb25
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb3
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/different_definition_tables_spec.rb7
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/extra_table_columns_spec.rb7
-rw-r--r--spec/lib/gitlab/database/schema_validation/validators/missing_table_columns_spec.rb7
-rw-r--r--spec/migrations/20230202131928_encrypt_ci_trigger_token_spec.rb27
-rw-r--r--spec/migrations/20230412214119_finalize_encrypt_ci_trigger_token_spec.rb96
95 files changed, 943 insertions, 186 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index d0566e4eedb..8d10babc0ab 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -1206,7 +1206,7 @@ lib/gitlab/checks/** @proglottis @toon
/lib/tasks/gitlab/password.rake @gitlab-org/manage/authentication-and-authorization/approvers
/lib/tasks/tokens.rake @gitlab-org/manage/authentication-and-authorization/approvers
-[Verify] @gitlab-org/maintainers/cicd-verify
+[Verify] @gitlab-org/maintainers/cicd-verify @shinya.maeda @stanhu @ayufan
# Verify Backend
/**/app/**/ci/
/**/lib/**/ci/
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 81da8409873..b778e05c7b1 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -343,7 +343,9 @@ class GfmAutoComplete {
icon,
availabilityStatus:
availability && isUserBusy(availability)
- ? `<span class="gl-text-gray-500"> ${s__('UserAvailability|(Busy)')}</span>`
+ ? `<span class="badge badge-warning badge-pill gl-badge sm gl-ml-2"> ${s__(
+ 'UserProfile|Busy',
+ )}</span>`
: '',
});
}
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index dee13f60008..7ec56b29c88 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -114,6 +114,7 @@ const initForkInfo = () => {
aheadComparePath,
behindComparePath,
canUserCreateMrInFork,
+ createMrPath,
} = forkEl.dataset;
return new Vue({
el: forkEl,
@@ -130,6 +131,7 @@ const initForkInfo = () => {
aheadComparePath,
behindComparePath,
canUserCreateMrInFork,
+ createMrPath,
},
});
},
diff --git a/app/assets/javascripts/repository/components/fork_info.vue b/app/assets/javascripts/repository/components/fork_info.vue
index 07a29bd3b96..99cbe555a2d 100644
--- a/app/assets/javascripts/repository/components/fork_info.vue
+++ b/app/assets/javascripts/repository/components/fork_info.vue
@@ -1,7 +1,7 @@
<script>
import { GlIcon, GlLink, GlSkeletonLoader, GlLoadingIcon, GlSprintf, GlButton } from '@gitlab/ui';
import { s__, sprintf, n__ } from '~/locale';
-import { createAlert } from '~/alert';
+import { createAlert, VARIANT_INFO } from '~/alert';
import syncForkMutation from '~/repository/mutations/sync_fork.mutation.graphql';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../event_hub';
@@ -26,6 +26,9 @@ export const i18n = {
error: s__('ForksDivergence|Failed to fetch fork details. Try again later.'),
updateFork: s__('ForksDivergence|Update fork'),
createMergeRequest: s__('ForksDivergence|Create merge request'),
+ successMessage: s__(
+ 'ForksDivergence|Successfully fetched and merged from the upstream repository.',
+ ),
};
export default {
@@ -62,6 +65,10 @@ export default {
this.increasePollInterval();
}
if (this.isForkUpdated) {
+ createAlert({
+ message: this.$options.i18n.successMessage,
+ variant: VARIANT_INFO,
+ });
eventHub.$emit(FORK_UPDATED_EVENT);
}
},
@@ -124,7 +131,6 @@ export default {
return {
project: {},
currentPollInterval: null,
- isSyncTriggered: false,
};
},
computed: {
@@ -150,7 +156,7 @@ export default {
return this.forkDetails?.isSyncing;
},
isForkUpdated() {
- return !this.hasConflicts && !this.isSyncing && this.currentPollInterval;
+ return this.isUpToDate && this.currentPollInterval;
},
ahead() {
return this.project?.forkDetails?.ahead;
@@ -216,9 +222,8 @@ export default {
},
watch: {
hasConflicts(newVal) {
- if (newVal && this.isSyncTriggered) {
+ if (newVal && this.currentPollInterval) {
this.showConflictsModal();
- this.isSyncTriggered = false;
}
},
},
@@ -257,7 +262,6 @@ export default {
this.$refs.modal.show();
},
startSyncing() {
- this.isSyncTriggered = true;
this.syncForkWithPolling();
},
checkIfSyncIsPossible() {
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue
index 8b40b48b54a..c61c02c8b3a 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_participant.vue
@@ -1,7 +1,7 @@
<script>
-import { GlAvatarLabeled, GlIcon } from '@gitlab/ui';
+import { GlAvatarLabeled, GlBadge, GlIcon } from '@gitlab/ui';
import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
-import { s__, sprintf } from '~/locale';
+import { __ } from '~/locale';
const AVAILABILITY_STATUS = {
NOT_SET: 'NOT_SET',
@@ -11,6 +11,7 @@ const AVAILABILITY_STATUS = {
export default {
components: {
GlAvatarLabeled,
+ GlBadge,
GlIcon,
},
props: {
@@ -25,30 +26,23 @@ export default {
},
},
computed: {
- userLabel() {
- const { name, status } = this.user;
- if (!status || status?.availability !== AVAILABILITY_STATUS.BUSY) {
- return name;
- }
- return sprintf(
- s__('UserAvailability|%{author} (Busy)'),
- {
- author: name,
- },
- false,
- );
+ isBusy() {
+ return this.user?.status?.availability === AVAILABILITY_STATUS.BUSY;
},
hasCannotMergeIcon() {
return this.issuableType === TYPE_MERGE_REQUEST && !this.user.canMerge;
},
},
+ i18n: {
+ busy: __('Busy'),
+ },
};
</script>
<template>
<gl-avatar-labeled
:size="32"
- :label="userLabel"
+ :label="user.name"
:sub-label="`@${user.username}`"
:src="user.avatarUrl || user.avatar || user.avatar_url"
class="gl-align-items-center gl-relative sidebar-participant"
@@ -61,6 +55,9 @@ export default {
class="merge-icon"
:size="12"
/>
+ <gl-badge v-if="isBusy" size="sm" variant="warning" class="gl-ml-2">
+ {{ $options.i18n.busy }}
+ </gl-badge>
</template>
</gl-avatar-labeled>
</template>
diff --git a/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue b/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue
index bed84dc5706..72084fdafb1 100644
--- a/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue
@@ -1,10 +1,11 @@
<script>
-import { GlSprintf } from '@gitlab/ui';
+import { GlBadge, GlSprintf } from '@gitlab/ui';
import { isUserBusy } from '~/set_status_modal/utils';
export default {
name: 'UserNameWithStatus',
components: {
+ GlBadge,
GlSprintf,
},
props: {
@@ -40,17 +41,17 @@ export default {
</script>
<template>
<span :class="containerClasses">
- <gl-sprintf :message="s__('UserAvailability|%{author} %{spanStart}(Busy)%{spanEnd}')">
+ <gl-sprintf :message="s__('UserAvailability|%{author}%{badgeStart}Busy%{badgeEnd}')">
<template #author
- >{{ name }}
- <span v-if="hasPronouns" class="gl-text-gray-500 gl-font-sm gl-font-weight-normal"
+ ><span>{{ name }}</span
+ ><span v-if="hasPronouns" class="gl-text-gray-500 gl-font-sm gl-font-weight-normal gl-ml-1"
>({{ pronouns }})</span
></template
>
- <template #span="{ content }"
- ><span v-if="isBusy" class="gl-text-gray-500 gl-font-sm gl-font-weight-normal">{{
- content
- }}</span>
+ <template #badge="{ content }">
+ <gl-badge v-if="isBusy" size="sm" variant="warning" class="gl-ml-2">
+ {{ content }}
+ </gl-badge>
</template>
</gl-sprintf>
</span>
diff --git a/app/assets/javascripts/super_sidebar/components/user_name_group.vue b/app/assets/javascripts/super_sidebar/components/user_name_group.vue
index a24299d449b..57958a03edd 100644
--- a/app/assets/javascripts/super_sidebar/components/user_name_group.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_name_group.vue
@@ -1,5 +1,10 @@
<script>
-import { GlDisclosureDropdownGroup, GlDisclosureDropdownItem, GlTooltip } from '@gitlab/ui';
+import {
+ GlBadge,
+ GlDisclosureDropdownGroup,
+ GlDisclosureDropdownItem,
+ GlTooltip,
+} from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { s__ } from '~/locale';
import { USER_MENU_TRACKING_DEFAULTS } from '../constants';
@@ -7,10 +12,11 @@ import { USER_MENU_TRACKING_DEFAULTS } from '../constants';
export default {
i18n: {
user: {
- busy: s__('UserProfile|(Busy)'),
+ busy: s__('UserProfile|Busy'),
},
},
components: {
+ GlBadge,
GlDisclosureDropdownGroup,
GlDisclosureDropdownItem,
GlTooltip,
@@ -53,9 +59,9 @@ export default {
<span class="gl-font-weight-bold">
{{ user.name }}
</span>
- <span v-if="user.status.busy" class="gl-text-gray-500">{{
- $options.i18n.user.busy
- }}</span>
+ <gl-badge v-if="user.status.busy" size="sm" variant="warning">
+ {{ $options.i18n.user.busy }}
+ </gl-badge>
</span>
<span class="gl-text-gray-400">@{{ user.username }}</span>
diff --git a/app/assets/javascripts/users_select/index.js b/app/assets/javascripts/users_select/index.js
index 694f5a7fe16..66e54b59187 100644
--- a/app/assets/javascripts/users_select/index.js
+++ b/app/assets/javascripts/users_select/index.js
@@ -696,17 +696,18 @@ UsersSelect.prototype.renderRow = function (
: '';
const dataUserSuggested = user.suggested ? `data-user-suggested=${user.suggested}` : '';
- const name =
+ const busyBadge =
user?.availability && isUserBusy(user.availability)
- ? sprintf(__('%{name} (Busy)'), { name: user.name })
- : user.name;
+ ? `<span class="badge badge-warning badge-pill gl-badge sm">${__('Busy')}</span>`
+ : '';
return `
<li data-user-id=${user.id} ${dataUserSuggested}>
<a href="#" class="dropdown-menu-user-link gl-display-flex! gl-align-items-center ${linkClasses}" ${tooltipAttributes}>
${this.renderRowAvatar(issuableType, user, img)}
<span class="gl-display-flex gl-flex-direction-column gl-overflow-hidden">
<strong class="dropdown-menu-user-full-name gl-font-weight-bold">
- ${escape(name)}
+ ${escape(user.name)}
+ ${busyBadge}
</strong>
${
username
diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
index 4c8e4eb5aa1..e09f193310b 100644
--- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
@@ -1,5 +1,6 @@
<script>
import {
+ GlBadge,
GlPopover,
GlLink,
GlSkeletonLoader,
@@ -35,6 +36,7 @@ export default {
I18N_USER_LEARN,
USER_POPOVER_DELAY,
components: {
+ GlBadge,
GlIcon,
GlLink,
GlPopover,
@@ -226,9 +228,9 @@ export default {
data-testid="user-popover-pronouns"
>({{ user.pronouns }})</span
>
- <span v-if="isBusy" class="gl-text-gray-500 gl-font-sm gl-font-weight-normal gl-p-1"
- >({{ $options.I18N_USER_BUSY }})</span
- >
+ <gl-badge v-if="isBusy" size="sm" variant="warning" class="gl-ml-1">
+ {{ $options.I18N_USER_BUSY }}
+ </gl-badge>
</template>
</gl-avatar-labeled>
</div>
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 6d82e96f1c5..5173abfbfd5 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -51,6 +51,7 @@ class Projects::BlobController < Projects::ApplicationController
push_frontend_feature_flag(:highlight_js, @project)
push_frontend_feature_flag(:explain_code_snippet, current_user)
push_licensed_feature(:explain_code, @project) if @project.licensed_feature_available?(:explain_code)
+ push_frontend_feature_flag(:synchronize_fork, @project&.fork_source)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
end
diff --git a/app/views/layouts/header/_current_user_dropdown_item.html.haml b/app/views/layouts/header/_current_user_dropdown_item.html.haml
index 3fded43ee4f..fa0a6364a15 100644
--- a/app/views/layouts/header/_current_user_dropdown_item.html.haml
+++ b/app/views/layouts/header/_current_user_dropdown_item.html.haml
@@ -1,7 +1,7 @@
.gl-font-weight-bold
= current_user.name
- if current_user.status&.busy?
- %span.gl-font-weight-normal.gl-text-gray-500= s_("UserProfile|(Busy)")
+ = render Pajamas::BadgeComponent.new(s_('UserProfile|Busy'), size: 'sm', variant: 'warning')
= current_user.to_reference
- if current_user.status
.user-status.d-flex.align-items-center.gl-mt-2.gl-mr-0.gl-font-sm.has-tooltip{ title: current_user.status.message_html, data: { html: 'true', placement: 'bottom' } }
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 28f9a6a6336..70dccc4821b 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -67,7 +67,7 @@
%span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle
= "(#{@user.pronouns})"
- if @user.status&.busy?
- %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle= s_("UserProfile|(Busy)")
+ = render Pajamas::BadgeComponent.new(s_('UserProfile|Busy'), size: 'sm', variant: 'warning', class: 'gl-vertical-align-middle')
- if @user.pronunciation.present?
.gl-align-items-center
diff --git a/db/docs/approval_project_rules_users.yml b/db/docs/approval_project_rules_users.yml
index ce35033356a..1066f31a396 100644
--- a/db/docs/approval_project_rules_users.yml
+++ b/db/docs/approval_project_rules_users.yml
@@ -1,6 +1,7 @@
---
table_name: approval_project_rules_users
-classes: []
+classes:
+- ApprovalProjectRulesUser
feature_categories:
- source_code_management
description: Keeps connection between user and a project approval rule
diff --git a/db/post_migrate/20230403085958_add_sync_tmp_partial_index_on_vulnerability_report_types2.rb b/db/post_migrate/20230403085958_add_sync_tmp_partial_index_on_vulnerability_report_types2.rb
new file mode 100644
index 00000000000..a2905fa2635
--- /dev/null
+++ b/db/post_migrate/20230403085958_add_sync_tmp_partial_index_on_vulnerability_report_types2.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddSyncTmpPartialIndexOnVulnerabilityReportTypes2 < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'tmp_idx_vulnerability_occurrences_on_id_where_report_type_7_99'
+
+ disable_ddl_transaction!
+
+ def up
+ # Temporary index to be removed in 16.1 https://gitlab.com/gitlab-org/gitlab/-/issues/404408
+ add_concurrent_index :vulnerability_occurrences, :id, where: 'report_type IN (7, 99)', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :vulnerability_occurrences, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230412214119_finalize_encrypt_ci_trigger_token.rb b/db/post_migrate/20230412214119_finalize_encrypt_ci_trigger_token.rb
new file mode 100644
index 00000000000..e3e6dc43e0d
--- /dev/null
+++ b/db/post_migrate/20230412214119_finalize_encrypt_ci_trigger_token.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class FinalizeEncryptCiTriggerToken < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'EncryptCiTriggerToken'
+
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: MIGRATION,
+ table_name: :ci_triggers,
+ column_name: :id,
+ job_arguments: [],
+ finalize: true
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20230403085958 b/db/schema_migrations/20230403085958
new file mode 100644
index 00000000000..882be7fa1cd
--- /dev/null
+++ b/db/schema_migrations/20230403085958
@@ -0,0 +1 @@
+54e1499b13e6bbfb7c08e491caacae93ee21c1e939e41ffcf7ab83c6f50463ce \ No newline at end of file
diff --git a/db/schema_migrations/20230412214119 b/db/schema_migrations/20230412214119
new file mode 100644
index 00000000000..80a8f21a960
--- /dev/null
+++ b/db/schema_migrations/20230412214119
@@ -0,0 +1 @@
+aac6aa036a97fa8331983085d8afad2dd870c80a687f6c0ed09476e438e15e76 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index f74e15b2b9f..26d2a9c5787 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -32847,6 +32847,8 @@ CREATE INDEX tmp_idx_for_vulnerability_feedback_migration ON vulnerability_feedb
CREATE INDEX tmp_idx_package_files_on_non_zero_size ON packages_package_files USING btree (package_id, size) WHERE (size IS NOT NULL);
+CREATE INDEX tmp_idx_vulnerability_occurrences_on_id_where_report_type_7_99 ON vulnerability_occurrences USING btree (id) WHERE (report_type = ANY (ARRAY[7, 99]));
+
CREATE INDEX tmp_index_ci_job_artifacts_on_expire_at_where_locked_unknown ON ci_job_artifacts USING btree (expire_at, job_id) WHERE ((locked = 2) AND (expire_at IS NOT NULL));
CREATE INDEX tmp_index_ci_job_artifacts_on_id_expire_at_file_type_trace ON ci_job_artifacts USING btree (id) WHERE (((date_part('day'::text, timezone('UTC'::text, expire_at)) = ANY (ARRAY[(21)::double precision, (22)::double precision, (23)::double precision])) AND (date_part('minute'::text, timezone('UTC'::text, expire_at)) = ANY (ARRAY[(0)::double precision, (30)::double precision, (45)::double precision])) AND (date_part('second'::text, timezone('UTC'::text, expire_at)) = (0)::double precision)) OR (file_type = 3));
diff --git a/doc/administration/static_objects_external_storage.md b/doc/administration/static_objects_external_storage.md
index ef89e38be6f..73f44ed3889 100644
--- a/doc/administration/static_objects_external_storage.md
+++ b/doc/administration/static_objects_external_storage.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
type: reference
---
diff --git a/doc/api/group_repository_storage_moves.md b/doc/api/group_repository_storage_moves.md
index 8d685c75f60..95d261e79a9 100644
--- a/doc/api/group_repository_storage_moves.md
+++ b/doc/api/group_repository_storage_moves.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
---
diff --git a/doc/api/usage_data.md b/doc/api/usage_data.md
index 3918b1d3ee3..bf8924c1578 100644
--- a/doc/api/usage_data.md
+++ b/doc/api/usage_data.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference, api
---
diff --git a/doc/development/gemfile.md b/doc/development/gemfile.md
index 38c0d77bcae..d4dc66bae8f 100644
--- a/doc/development/gemfile.md
+++ b/doc/development/gemfile.md
@@ -65,6 +65,17 @@ This means that new dependencies should, at a minimum, meet the following criter
- If the project uses a C extension, consider requesting an additional review from a C or MRI
domain expert. C extensions can greatly impact GitLab stability and performance.
+## Gems that require a domain expert approval
+
+Changes to the following gems require a domain expert review and approval by a backend team member of the group.
+
+For gems not listed in this table, it's still recommended but not required that you find a domain expert to review changes.
+
+| Gem | Requires approval by |
+| ------ | ------ |
+| `doorkeeper` | [Manage:Authentication and Authorization](https://about.gitlab.com/handbook/product/categories/#authentication-and-authorization-group) |
+| `doorkeeper-openid_connect` | [Manage:Authentication and Authorization](https://about.gitlab.com/handbook/product/categories/#authentication-and-authorization-group) |
+
## Request an Appsec review
When adding a new gem to our `Gemfile` or even changing versions in
diff --git a/doc/development/gitlab_flavored_markdown/index.md b/doc/development/gitlab_flavored_markdown/index.md
index 064a7ecbfa9..cde83bff32e 100644
--- a/doc/development/gitlab_flavored_markdown/index.md
+++ b/doc/development/gitlab_flavored_markdown/index.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/gitlab_flavored_markdown/specification_guide/index.md b/doc/development/gitlab_flavored_markdown/specification_guide/index.md
index ba54ad943cc..ae78daa3687 100644
--- a/doc/development/gitlab_flavored_markdown/specification_guide/index.md
+++ b/doc/development/gitlab_flavored_markdown/specification_guide/index.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/service_ping/implement.md b/doc/development/service_ping/implement.md
index 5bfb81c1d00..54352a43010 100644
--- a/doc/development/service_ping/implement.md
+++ b/doc/development/service_ping/implement.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md
index e938de9e253..9d3f3d37dca 100644
--- a/doc/development/service_ping/index.md
+++ b/doc/development/service_ping/index.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/service_ping/metrics_dictionary.md b/doc/development/service_ping/metrics_dictionary.md
index a6d4986b819..f36a97bcf6b 100644
--- a/doc/development/service_ping/metrics_dictionary.md
+++ b/doc/development/service_ping/metrics_dictionary.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/service_ping/metrics_instrumentation.md b/doc/development/service_ping/metrics_instrumentation.md
index 14ec4b8c9a6..7441a2d1bd4 100644
--- a/doc/development/service_ping/metrics_instrumentation.md
+++ b/doc/development/service_ping/metrics_instrumentation.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/service_ping/metrics_lifecycle.md b/doc/development/service_ping/metrics_lifecycle.md
index 7fcbafe50f7..3c51eefc4b4 100644
--- a/doc/development/service_ping/metrics_lifecycle.md
+++ b/doc/development/service_ping/metrics_lifecycle.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/service_ping/performance_indicator_metrics.md b/doc/development/service_ping/performance_indicator_metrics.md
index 4c1c61aa05b..0ca663ce09a 100644
--- a/doc/development/service_ping/performance_indicator_metrics.md
+++ b/doc/development/service_ping/performance_indicator_metrics.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/service_ping/review_guidelines.md b/doc/development/service_ping/review_guidelines.md
index d94f094584f..f260d9700a3 100644
--- a/doc/development/service_ping/review_guidelines.md
+++ b/doc/development/service_ping/review_guidelines.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/service_ping/troubleshooting.md b/doc/development/service_ping/troubleshooting.md
index 3b7cd092d97..1b896efb726 100644
--- a/doc/development/service_ping/troubleshooting.md
+++ b/doc/development/service_ping/troubleshooting.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/service_ping/usage_data.md b/doc/development/service_ping/usage_data.md
index 1c7a212ed64..b3bdaedd60a 100644
--- a/doc/development/service_ping/usage_data.md
+++ b/doc/development/service_ping/usage_data.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/snowplow/event_dictionary_guide.md b/doc/development/snowplow/event_dictionary_guide.md
index dc2214a40ed..8825a38627a 100644
--- a/doc/development/snowplow/event_dictionary_guide.md
+++ b/doc/development/snowplow/event_dictionary_guide.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/snowplow/implementation.md b/doc/development/snowplow/implementation.md
index ae90b45b1f0..05137a4410f 100644
--- a/doc/development/snowplow/implementation.md
+++ b/doc/development/snowplow/implementation.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/snowplow/index.md b/doc/development/snowplow/index.md
index 276b5913890..4ccb90c22a6 100644
--- a/doc/development/snowplow/index.md
+++ b/doc/development/snowplow/index.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/snowplow/infrastructure.md b/doc/development/snowplow/infrastructure.md
index ae416f40c98..ac146542630 100644
--- a/doc/development/snowplow/infrastructure.md
+++ b/doc/development/snowplow/infrastructure.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/snowplow/review_guidelines.md b/doc/development/snowplow/review_guidelines.md
index da7f2bc2781..2cf13385179 100644
--- a/doc/development/snowplow/review_guidelines.md
+++ b/doc/development/snowplow/review_guidelines.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/snowplow/schemas.md b/doc/development/snowplow/schemas.md
index da58cd5f2e5..0ef6ed04aa3 100644
--- a/doc/development/snowplow/schemas.md
+++ b/doc/development/snowplow/schemas.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/snowplow/troubleshooting.md b/doc/development/snowplow/troubleshooting.md
index 47df3e43d57..92267dfcb0c 100644
--- a/doc/development/snowplow/troubleshooting.md
+++ b/doc/development/snowplow/troubleshooting.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/gitpod.md b/doc/integration/gitpod.md
index 6df36cff638..0ba227c2a85 100644
--- a/doc/integration/gitpod.md
+++ b/doc/integration/gitpod.md
@@ -1,7 +1,7 @@
---
type: reference, how-to
stage: Create
-group: Editor
+group: IDE
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
---
diff --git a/doc/raketasks/migrate_snippets.md b/doc/raketasks/migrate_snippets.md
index e51edc5c133..16f78d7fc71 100644
--- a/doc/raketasks/migrate_snippets.md
+++ b/doc/raketasks/migrate_snippets.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
index c216b2b2fb3..1db62bce056 100644
--- a/doc/user/admin_area/settings/usage_statistics.md
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -1,6 +1,6 @@
---
stage: Analytics
-group: Product Intelligence
+group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 6b2824e675e..86e6264fab4 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -215,8 +215,8 @@ table.supported-languages ul {
<td>N</td>
</tr>
<tr>
- <td rowspan="2">JavaScript and TypeScript</td>
- <td>All versions</td>
+ <td rowspan="3">JavaScript and TypeScript</td>
+ <td rowspan="3">All versions</td>
<td><a href="https://www.npmjs.com/">npm</a></td>
<td>
<ul>
@@ -227,12 +227,16 @@ table.supported-languages ul {
<td>Y</td>
</tr>
<tr>
- <td>All versions</td>
<td><a href="https://classic.yarnpkg.com/en/">yarn</a></td>
<td><code>yarn.lock</code></td>
<td>Y</td>
</tr>
<tr>
+ <td><a href="https://pnpm.io/">pnpm</a><sup><b><a href="#notes-regarding-supported-languages-and-package-managers-4">4</a></b></sup></td>
+ <td><code>pnpm-lock.yaml</code></td>
+ <td>Y</td>
+ </tr>
+ <tr>
<td>PHP</td>
<td>All versions</td>
<td><a href="https://getcomposer.org/">Composer</a></td>
@@ -262,13 +266,13 @@ table.supported-languages ul {
<td>
<ul>
<li><a href="https://pipenv.pypa.io/en/latest/pipfile/#example-pipfile"><code>Pipfile</code></a></li>
- <li><a href="https://pipenv.pypa.io/en/latest/pipfile/#example-pipfile-lock"><code>Pipfile.lock</code></a><sup><b><a href="#notes-regarding-supported-languages-and-package-managers-4">4</a></b></sup></li>
+ <li><a href="https://pipenv.pypa.io/en/latest/pipfile/#example-pipfile-lock"><code>Pipfile.lock</code></a><sup><b><a href="#notes-regarding-supported-languages-and-package-managers-5">5</a></b></sup></li>
</ul>
</td>
<td>N</td>
</tr>
<tr>
- <td><a href="https://python-poetry.org/">Poetry</a><sup><b><a href="#notes-regarding-supported-languages-and-package-managers-5">5</a></b></sup></td>
+ <td><a href="https://python-poetry.org/">Poetry</a><sup><b><a href="#notes-regarding-supported-languages-and-package-managers-6">6</a></b></sup></td>
<td><code>poetry.lock</code></td>
<td>N</td>
</tr>
@@ -287,7 +291,7 @@ table.supported-languages ul {
<tr>
<td>Scala</td>
<td>All versions</td>
- <td><a href="https://www.scala-sbt.org/">sbt</a><sup><b><a href="#notes-regarding-supported-languages-and-package-managers-6">6</a></b></sup></td>
+ <td><a href="https://www.scala-sbt.org/">sbt</a><sup><b><a href="#notes-regarding-supported-languages-and-package-managers-7">7</a></b></sup></td>
<td><code>build.sbt</code></td>
<td>N</td>
</tr>
@@ -316,6 +320,12 @@ table.supported-languages ul {
<li>
<a id="notes-regarding-supported-languages-and-package-managers-4"></a>
<p>
+ Support for <code>pnpm</code> lockfiles was <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/336809">introduced in GitLab 15.11</a>. <code>pnpm</code> lockfiles do not store bundled dependencies, so the reported dependencies may differ from <code>npm</code> or <code>yarn</code>.
+ </p>
+ </li>
+ <li>
+ <a id="notes-regarding-supported-languages-and-package-managers-5"></a>
+ <p>
The presence of a <code>Pipfile.lock</code> file alone will <i>not</i> trigger the analyzer; the presence of a <code>Pipfile</code> is
still required in order for the analyzer to be executed. However, if a <code>Pipfile.lock</code> file is found, it is used by
<code>Gemnasium</code> to scan the exact package versions listed in this file.
@@ -327,7 +337,7 @@ table.supported-languages ul {
</p>
</li>
<li>
- <a id="notes-regarding-supported-languages-and-package-managers-5"></a>
+ <a id="notes-regarding-supported-languages-and-package-managers-6"></a>
<p>
Support for <a href="https://python-poetry.org/">Poetry</a> projects with a <code>poetry.lock</code> file was <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/7006">added in GitLab 15.0</a>.
Support for projects without a <code>poetry.lock</code> file is tracked in issue:
@@ -335,7 +345,7 @@ table.supported-languages ul {
</p>
</li>
<li>
- <a id="notes-regarding-supported-languages-and-package-managers-6"></a>
+ <a id="notes-regarding-supported-languages-and-package-managers-7"></a>
<p>
Support for <a href="https://www.scala-sbt.org/">sbt</a> 1.3 and above was added in GitLab 13.9.
</p>
@@ -362,6 +372,7 @@ The following package managers use lockfiles that GitLab analyzers are capable o
| Go | Not applicable | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/go-modules/gosum/default/go.sum) <sup><strong><a href="#notes-regarding-parsing-lockfiles-1">1</a></strong></sup> |
| NuGet | v1 | [4.9](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/csharp-nuget-dotnetcore/default/src/web.api/packages.lock.json#L2) |
| npm | v1, v2, v3<sup><b><a href="#notes-regarding-parsing-lockfiles-2">2</a></b></sup> | [6.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-npm/default/package-lock.json#L4), [7.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-npm/lockfileVersion2/package-lock.json#L4), [9.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/scanner/parser/npm/fixtures/lockfile-v3/simple/package-lock.json#L4) |
+| pnpm | v5.3, v5.4, v6 | [7.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-pnpm/default/pnpm-lock.yaml#L1), [8.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/scanner/parser/pnpm/fixtures/v6/simple/pnpm-lock.yaml#L1) |
| yarn | v1, v2<sup><b><a href="#notes-regarding-parsing-lockfiles-3">3</a></b></sup>, v3<sup><b><a href="#notes-regarding-parsing-lockfiles-3">3</a></b></sup> | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/classic/default/yarn.lock#L2), [2.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/berry/v2/default/yarn.lock), [3.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/berry/v3/default/yarn.lock) |
| Poetry | v1 | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/python-poetry/default/poetry.lock) |
diff --git a/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md b/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md
index 1ca10ed61db..e2b2fc16707 100644
--- a/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md
+++ b/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md
@@ -67,10 +67,13 @@ License scanning is supported for the following languages and package managers:
<td><a href="https://maven.apache.org/">Maven</a></td>
</tr>
<tr>
- <td rowspan="2">JavaScript and TypeScript</td>
+ <td rowspan="3">JavaScript and TypeScript</td>
<td><a href="https://www.npmjs.com/">npm</a></td>
</tr>
<tr>
+ <td><a href="https://pnpm.io/">pnpm</a></td>
+ </tr>
+ <tr>
<td><a href="https://classic.yarnpkg.com/en/">yarn</a></td>
</tr>
<tr>
diff --git a/doc/user/profile/img/busy_indicator_note_header_v13_9.png b/doc/user/profile/img/busy_indicator_note_header_v13_9.png
deleted file mode 100644
index 63301ebdc14..00000000000
--- a/doc/user/profile/img/busy_indicator_note_header_v13_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/img/busy_indicator_notes_v13_9.png b/doc/user/profile/img/busy_indicator_notes_v13_9.png
deleted file mode 100644
index 2efe075c72b..00000000000
--- a/doc/user/profile/img/busy_indicator_notes_v13_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/img/busy_indicator_profile_page_v13_6.png b/doc/user/profile/img/busy_indicator_profile_page_v13_6.png
deleted file mode 100644
index c8e969f38db..00000000000
--- a/doc/user/profile/img/busy_indicator_profile_page_v13_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/img/busy_indicator_settings_menu_v13_6.png b/doc/user/profile/img/busy_indicator_settings_menu_v13_6.png
deleted file mode 100644
index 711638541dd..00000000000
--- a/doc/user/profile/img/busy_indicator_settings_menu_v13_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/img/busy_indicator_sidebar_collapsed_v13_9.png b/doc/user/profile/img/busy_indicator_sidebar_collapsed_v13_9.png
deleted file mode 100644
index 3dca88ec8cc..00000000000
--- a/doc/user/profile/img/busy_indicator_sidebar_collapsed_v13_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/img/busy_indicator_sidebar_v13_9.png b/doc/user/profile/img/busy_indicator_sidebar_v13_9.png
deleted file mode 100644
index 83024b319bf..00000000000
--- a/doc/user/profile/img/busy_indicator_sidebar_v13_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/img/busy_indicator_user_popovers_v13_6.png b/doc/user/profile/img/busy_indicator_user_popovers_v13_6.png
deleted file mode 100644
index 16fb0e6556b..00000000000
--- a/doc/user/profile/img/busy_indicator_user_popovers_v13_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index c54cf583247..191695bc7ab 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -226,25 +226,7 @@ To set the busy status indicator, either:
1. Select **Edit profile**.
1. In the **Current status** section, select the **Set yourself as busy** checkbox.
- The busy status is displayed in the user interface.
-
- Username:
-
- | Profile page | Settings menu | User popovers |
- | --- | --- | --- |
- | ![Busy status - profile page](img/busy_indicator_profile_page_v13_6.png) | ![Busy status - settings menu](img/busy_indicator_settings_menu_v13_6.png) | ![Busy status - user popovers](img/busy_indicator_user_popovers_v13_6.png) |
-
- Issue and merge request sidebar:
-
- | Sidebar| Collapsed sidebar |
- | --- | --- |
- | ![Busy status - sidebar](img/busy_indicator_sidebar_v13_9.png) | ![Busy status - sidebar collapsed](img/busy_indicator_sidebar_collapsed_v13_9.png) |
-
- Notes:
-
- | Notes | Note headers |
- | --- | --- |
- | ![Busy status - notes](img/busy_indicator_notes_v13_9.png) | ![Busy status - note header](img/busy_indicator_note_header_v13_9.png) |
+ The busy status is displayed next to your name, every time your name is shown in the user interface.
## Set your time zone
diff --git a/doc/user/project/remote_development/connect_machine.md b/doc/user/project/remote_development/connect_machine.md
index 9f4c7fc45c7..f8fdd626852 100644
--- a/doc/user/project/remote_development/connect_machine.md
+++ b/doc/user/project/remote_development/connect_machine.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/project/remote_development/index.md b/doc/user/project/remote_development/index.md
index 857be8361d4..e3c2b6ccfb2 100644
--- a/doc/user/project/remote_development/index.md
+++ b/doc/user/project/remote_development/index.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/project/repository/file_finder.md b/doc/user/project/repository/file_finder.md
index 69390bb359a..e22dc549a4a 100644
--- a/doc/user/project/repository/file_finder.md
+++ b/doc/user/project/repository/file_finder.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/project/repository/vscode.md b/doc/user/project/repository/vscode.md
index 94824f3c492..2a33476b545 100644
--- a/doc/user/project/repository/vscode.md
+++ b/doc/user/project/repository/vscode.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/project/repository/web_editor.md b/doc/user/project/repository/web_editor.md
index ace7e119469..dc988846676 100644
--- a/doc/user/project/repository/web_editor.md
+++ b/doc/user/project/repository/web_editor.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index 678c329e16e..889ab1442b6 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/project/web_ide_beta/index.md b/doc/user/project/web_ide_beta/index.md
index 3051ee3bbfd..933634f0c29 100644
--- a/doc/user/project/web_ide_beta/index.md
+++ b/doc/user/project/web_ide_beta/index.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/shortcuts.md b/doc/user/shortcuts.md
index aca6f4cc532..c0d2b74fd84 100644
--- a/doc/user/shortcuts.md
+++ b/doc/user/shortcuts.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
---
diff --git a/doc/user/workspace/quick_start/index.md b/doc/user/workspace/quick_start/index.md
index d2c58299b64..933dbf1766b 100644
--- a/doc/user/workspace/quick_start/index.md
+++ b/doc/user/workspace/quick_start/index.md
@@ -1,6 +1,6 @@
---
stage: Create
-group: Editor
+group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
---
diff --git a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
index 31d19779434..2196630296b 100644
--- a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
@@ -63,6 +63,7 @@ dependency_scanning:
- '**/npm-shrinkwrap.json'
- '**/package-lock.json'
- '**/yarn.lock'
+ - '**/pnpm-lock.yaml'
- '**/packages.lock.json'
- '**/conan.lock'
diff --git a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml
index 46f554360d8..46161dce74c 100644
--- a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml
@@ -63,6 +63,7 @@ dependency_scanning:
- '**/npm-shrinkwrap.json'
- '**/package-lock.json'
- '**/yarn.lock'
+ - '**/pnpm-lock.yaml'
- '**/packages.lock.json'
- '**/conan.lock'
diff --git a/lib/gitlab/database/schema_validation/adapters/column_database_adapter.rb b/lib/gitlab/database/schema_validation/adapters/column_database_adapter.rb
new file mode 100644
index 00000000000..10603b3dbad
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/adapters/column_database_adapter.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Adapters
+ class ColumnDatabaseAdapter
+ def initialize(query_result)
+ @query_result = query_result
+ end
+
+ def name
+ @name ||= query_result['column_name']
+ end
+
+ def table_name
+ query_result['table_name']
+ end
+
+ def data_type
+ query_result['data_type']
+ end
+
+ def default
+ return unless query_result['column_default']
+
+ return if name == 'id' || query_result['column_default'].include?('nextval')
+
+ "DEFAULT #{query_result['column_default']}"
+ end
+
+ def nullable
+ 'NOT NULL' if query_result['not_null']
+ end
+
+ private
+
+ attr_reader :query_result
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/adapters/column_structure_sql_adapter.rb b/lib/gitlab/database/schema_validation/adapters/column_structure_sql_adapter.rb
new file mode 100644
index 00000000000..30a13b5dff1
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/adapters/column_structure_sql_adapter.rb
@@ -0,0 +1,114 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Adapters
+ UndefinedPGType = Class.new(StandardError)
+
+ class ColumnStructureSqlAdapter
+ NOT_NULL_CONSTR = :CONSTR_NOTNULL
+ DEFAULT_CONSTR = :CONSTR_DEFAULT
+
+ MAPPINGS = {
+ 't' => 'true',
+ 'f' => 'false'
+ }.freeze
+
+ attr_reader :table_name
+
+ def initialize(table_name, pg_query_stmt)
+ @table_name = table_name
+ @pg_query_stmt = pg_query_stmt
+ end
+
+ def name
+ @name ||= pg_query_stmt.colname
+ end
+
+ def data_type
+ type(pg_query_stmt.type_name)
+ end
+
+ def default
+ return if name == 'id'
+
+ value = parse_node(constraints.find { |node| node.constraint.contype == DEFAULT_CONSTR })
+
+ return unless value
+
+ "DEFAULT #{value}"
+ end
+
+ def nullable
+ 'NOT NULL' if constraints.any? { |node| node.constraint.contype == NOT_NULL_CONSTR }
+ end
+
+ private
+
+ attr_reader :pg_query_stmt
+
+ def constraints
+ @constraints ||= pg_query_stmt.constraints
+ end
+
+ # Returns the node type
+ #
+ # pg_type:: type alias, used internally by postgres, +int4+, +int8+, +bool+, +varchar+
+ # type:: type name, like +integer+, +bigint+, +boolean+, +character varying+.
+ # array_ext:: adds the +[]+ extension for array types.
+ # precision_ext:: adds the precision, if have any, like +(255)+, +(6)+.
+ #
+ # @info +timestamp+ and +timestamptz+ have a particular case when precision is defined.
+ # In this case, the order of the statement needs to be re-arranged from
+ # timestamp without time zone(6) to timestamp(6) without a time zone.
+ def type(node)
+ pg_type = parse_node(node.names.last)
+ type = PgTypes::TYPES.fetch(pg_type).dup
+ array_ext = '[]' if node.array_bounds.any?
+ precision_ext = "(#{node.typmods.map { |typmod| parse_node(typmod) }.join(',')})" if node.typmods.any?
+
+ if %w[timestamp timestamptz].include?(pg_type)
+ type.gsub!('timestamp', ['timestamp', precision_ext].compact.join(''))
+ precision_ext = nil
+ end
+
+ [type, precision_ext, array_ext].compact.join('')
+ rescue KeyError => exception
+ raise UndefinedPGType, exception.message
+ end
+
+ # Parses PGQuery nodes recursively
+ #
+ # :constraint:: nodes that groups column default info
+ # :func_cal:: nodes that stores functions, like +now()+
+ # :a_const:: nodes that stores constant values, like +t+, +f+, +0.0.0.0+, +255+, +1.0+
+ # :type_cast:: nodes that stores casting values, like +'name'::text+, +'0.0.0.0'::inet+
+ # else:: extract node values in the last iteration of the recursion, like +int4+, +1.0+, +now+, +255+
+ #
+ # @note boolean types types are mapped from +t+, +f+ to +true+, +false+
+ def parse_node(node)
+ return unless node
+
+ case node.node
+ when :constraint
+ parse_node(node.constraint.raw_expr)
+ when :func_call
+ "#{parse_node(node.func_call.funcname.first)}()"
+ when :a_const
+ parse_node(node.a_const.val)
+ when :type_cast
+ value = parse_node(node.type_cast.arg)
+ type = type(node.type_cast.type_name)
+ separator = MAPPINGS.key?(value) ? '' : "::#{type}"
+
+ [MAPPINGS.fetch(value, "'#{value}'"), separator].compact.join('')
+ else
+ node.to_h[node.node].values.last
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/database.rb b/lib/gitlab/database/schema_validation/database.rb
index 83224629e5f..9ff4a843e6d 100644
--- a/lib/gitlab/database/schema_validation/database.rb
+++ b/lib/gitlab/database/schema_validation/database.rb
@@ -69,7 +69,11 @@ module Gitlab
end
def table_map
- @table_map ||= fetch_tables.transform_values! { |stmt| SchemaObjects::Table.new(stmt.first['table_name']) }
+ @table_map ||= fetch_tables.transform_values! do |stmt|
+ columns = stmt.map { |column| SchemaObjects::Column.new(Adapters::ColumnDatabaseAdapter.new(column)) }
+
+ SchemaObjects::Table.new(stmt.first['table_name'], columns)
+ end
end
def fetch_indexes
diff --git a/lib/gitlab/database/schema_validation/pg_types.rb b/lib/gitlab/database/schema_validation/pg_types.rb
new file mode 100644
index 00000000000..0a1999d056e
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/pg_types.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ class PgTypes
+ TYPES = {
+ 'bool' => 'boolean',
+ 'bytea' => 'bytea',
+ 'char' => '"char"',
+ 'int8' => 'bigint',
+ 'int2' => 'smallint',
+ 'int4' => 'integer',
+ 'regproc' => 'regproc',
+ 'text' => 'text',
+ 'oid' => 'oid',
+ 'tid' => 'tid',
+ 'xid' => 'xid',
+ 'cid' => 'cid',
+ 'json' => 'json',
+ 'xml' => 'xml',
+ 'pg_node_tree' => 'pg_node_tree',
+ 'pg_ndistinct' => 'pg_ndistinct',
+ 'pg_dependencies' => 'pg_dependencies',
+ 'pg_mcv_list' => 'pg_mcv_list',
+ 'xid8' => 'xid8',
+ 'path' => 'path',
+ 'polygon' => 'polygon',
+ 'float4' => 'real',
+ 'float8' => 'double precision',
+ 'circle' => 'circle',
+ 'money' => 'money',
+ 'macaddr' => 'macaddr',
+ 'inet' => 'inet',
+ 'cidr' => 'cidr',
+ 'macaddr8' => 'macaddr8',
+ 'aclitem' => 'aclitem',
+ 'bpchar' => 'character',
+ 'varchar' => 'character varying',
+ 'date' => 'date',
+ 'time' => 'time without time zone',
+ 'timestamp' => 'timestamp without time zone',
+ 'timestamptz' => 'timestamp with time zone',
+ 'interval' => 'interval',
+ 'timetz' => 'time with time zone',
+ 'bit' => 'bit',
+ 'varbit' => 'bit varying',
+ 'numeric' => 'numeric',
+ 'refcursor' => 'refcursor',
+ 'regprocedure' => 'regprocedure',
+ 'regoper' => 'regoper',
+ 'regoperator' => 'regoperator',
+ 'regclass' => 'regclass',
+ 'regcollation' => 'regcollation',
+ 'regtype' => 'regtype',
+ 'regrole' => 'regrole',
+ 'regnamespace' => 'regnamespace',
+ 'uuid' => 'uuid',
+ 'pg_lsn' => 'pg_lsn',
+ 'tsvector' => 'tsvector',
+ 'gtsvector' => 'gtsvector',
+ 'tsquery' => 'tsquery',
+ 'regconfig' => 'regconfig',
+ 'regdictionary' => 'regdictionary',
+ 'jsonb' => 'jsonb',
+ 'jsonpath' => 'jsonpath',
+ 'txid_snapshot' => 'txid_snapshot',
+ 'pg_snapshot' => 'pg_snapshot'
+ }.freeze
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/schema_objects/column.rb b/lib/gitlab/database/schema_validation/schema_objects/column.rb
new file mode 100644
index 00000000000..38ad8e309a3
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/schema_objects/column.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module SchemaObjects
+ class Column
+ def initialize(adapter)
+ @adapter = adapter
+ end
+
+ attr_reader :adapter
+
+ delegate :name, :table_name, to: :adapter
+
+ def statement
+ [name, adapter.data_type, adapter.default, adapter.nullable].compact.join(' ')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/schema_objects/table.rb b/lib/gitlab/database/schema_validation/schema_objects/table.rb
index 6dc7ee32706..6f573e7027f 100644
--- a/lib/gitlab/database/schema_validation/schema_objects/table.rb
+++ b/lib/gitlab/database/schema_validation/schema_objects/table.rb
@@ -5,19 +5,34 @@ module Gitlab
module SchemaValidation
module SchemaObjects
class Table
- def initialize(name)
+ def initialize(name, columns)
@name = name
+ @columns = columns
end
+ attr_reader :name, :columns
+
def table_name
name
end
def statement
- nil
+ format('CREATE TABLE %s (%s)', name, columns_statement)
+ end
+
+ def fetch_column_by_name(column_name)
+ columns.find { |column| column.name == column_name }
end
- attr_reader :name
+ def column_exists?(column_name)
+ fetch_column_by_name(column_name).present?
+ end
+
+ private
+
+ def columns_statement
+ columns.map(&:statement).join(', ')
+ end
end
end
end
diff --git a/lib/gitlab/database/schema_validation/structure_sql.rb b/lib/gitlab/database/schema_validation/structure_sql.rb
index 687b3b73ec8..e93c33aedcd 100644
--- a/lib/gitlab/database/schema_validation/structure_sql.rb
+++ b/lib/gitlab/database/schema_validation/structure_sql.rb
@@ -36,7 +36,15 @@ module Gitlab
end
def tables
- @tables ||= table_statements.map { |stmt| SchemaObjects::Table.new(stmt.relation.relname) }
+ @tables ||= table_statements.map do |stmt|
+ table_name = stmt.relation.relname
+
+ columns = stmt.table_elts.select { |n| n.node == :column_def }.map do |column|
+ SchemaObjects::Column.new(Adapters::ColumnStructureSqlAdapter.new(table_name, column.column_def))
+ end
+
+ SchemaObjects::Table.new(table_name, columns)
+ end
end
private
diff --git a/lib/gitlab/database/schema_validation/validators/base_validator.rb b/lib/gitlab/database/schema_validation/validators/base_validator.rb
index 0593bb5f6ae..58e0bf5292b 100644
--- a/lib/gitlab/database/schema_validation/validators/base_validator.rb
+++ b/lib/gitlab/database/schema_validation/validators/base_validator.rb
@@ -15,11 +15,14 @@ module Gitlab
def self.all_validators
[
ExtraTables,
+ ExtraTableColumns,
ExtraIndexes,
ExtraTriggers,
MissingTables,
+ MissingTableColumns,
MissingIndexes,
MissingTriggers,
+ DifferentDefinitionTables,
DifferentDefinitionIndexes,
DifferentDefinitionTriggers
]
diff --git a/lib/gitlab/database/schema_validation/validators/different_definition_tables.rb b/lib/gitlab/database/schema_validation/validators/different_definition_tables.rb
new file mode 100644
index 00000000000..9fbddbd3fcd
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/different_definition_tables.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class DifferentDefinitionTables < BaseValidator
+ ERROR_MESSAGE = "The table %s has a different column statement between structure.sql and database"
+
+ def execute
+ structure_sql.tables.filter_map do |structure_sql_table|
+ table_name = structure_sql_table.name
+ database_table = database.fetch_table_by_name(table_name)
+
+ next unless database_table
+
+ db_diffs, structure_diffs = column_diffs(database_table, structure_sql_table.columns)
+
+ if db_diffs.any?
+ build_inconsistency(self.class,
+ SchemaObjects::Table.new(table_name, db_diffs),
+ SchemaObjects::Table.new(table_name, structure_diffs))
+ end
+ end
+ end
+
+ private
+
+ def column_diffs(db_table, columns)
+ db_diffs = []
+ structure_diffs = []
+
+ columns.each do |column|
+ db_column = db_table.fetch_column_by_name(column.name)
+
+ next unless db_column
+
+ next if db_column.statement == column.statement
+
+ db_diffs << db_column
+ structure_diffs << column
+ end
+
+ [db_diffs, structure_diffs]
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/extra_table_columns.rb b/lib/gitlab/database/schema_validation/validators/extra_table_columns.rb
new file mode 100644
index 00000000000..823b01cf808
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/extra_table_columns.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class ExtraTableColumns < BaseValidator
+ ERROR_MESSAGE = "The table %s has columns present in the database, but not in the structure.sql file"
+
+ def execute
+ database.tables.filter_map do |database_table|
+ table_name = database_table.name
+ structure_sql_table = structure_sql.fetch_table_by_name(table_name)
+
+ next unless structure_sql_table
+
+ inconsistencies = database_table.columns.filter_map do |database_table_column|
+ next if structure_sql_table.column_exists?(database_table_column.name)
+
+ database_table_column
+ end
+
+ if inconsistencies.any?
+ build_inconsistency(self.class, nil, SchemaObjects::Table.new(table_name, inconsistencies))
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_validation/validators/missing_table_columns.rb b/lib/gitlab/database/schema_validation/validators/missing_table_columns.rb
new file mode 100644
index 00000000000..b49d53823ee
--- /dev/null
+++ b/lib/gitlab/database/schema_validation/validators/missing_table_columns.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module SchemaValidation
+ module Validators
+ class MissingTableColumns < BaseValidator
+ ERROR_MESSAGE = "The table %s has columns missing from the database"
+
+ def execute
+ structure_sql.tables.filter_map do |structure_sql_table|
+ table_name = structure_sql_table.name
+ database_table = database.fetch_table_by_name(table_name)
+
+ next unless database_table
+
+ inconsistencies = structure_sql_table.columns.filter_map do |structure_table_column|
+ next if database_table.column_exists?(structure_table_column.name)
+
+ structure_table_column
+ end
+
+ if inconsistencies.any?
+ build_inconsistency(self.class, nil, SchemaObjects::Table.new(table_name, inconsistencies))
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/slug/environment.rb b/lib/gitlab/slug/environment.rb
index 892d5350db5..2305fcd0061 100644
--- a/lib/gitlab/slug/environment.rb
+++ b/lib/gitlab/slug/environment.rb
@@ -21,7 +21,7 @@ module Gitlab
slugified = name.to_s.downcase.gsub(/[^a-z0-9]/, '-')
# Must start with a letter
- slugified = "env-#{slugified}" unless slugified.match?(/^[a-z]/)
+ slugified = +"env-#{slugified}" unless slugified.match?(/^[a-z]/)
# Repeated dashes are invalid (OpenShift limitation)
slugified.squeeze!('-')
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 9aab7111dee..f3b9376b213 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1854,6 +1854,9 @@ msgstr ""
msgid "AI|Code Explanation"
msgstr ""
+msgid "AI|Experiment"
+msgstr ""
+
msgid "AI|Explain the code from %{filePath} in human understandable language presented in Markdown format. In the response add neither original code snippet nor any title. `%{text}`"
msgstr ""
@@ -18624,6 +18627,9 @@ msgstr ""
msgid "ForksDivergence|Source project has a limited visibility."
msgstr ""
+msgid "ForksDivergence|Successfully fetched and merged from the upstream repository."
+msgstr ""
+
msgid "ForksDivergence|The upstream changes could not be synchronized to this project due to file conflicts in the default branch. You must resolve the conflicts manually:"
msgstr ""
@@ -47819,13 +47825,7 @@ msgstr ""
msgid "User-based escalation rules must have a user with access to the project"
msgstr ""
-msgid "UserAvailability|%{author} %{spanStart}(Busy)%{spanEnd}"
-msgstr ""
-
-msgid "UserAvailability|%{author} (Busy)"
-msgstr ""
-
-msgid "UserAvailability|(Busy)"
+msgid "UserAvailability|%{author}%{badgeStart}Busy%{badgeEnd}"
msgstr ""
msgid "UserLists|Add"
@@ -47903,9 +47903,6 @@ msgstr ""
msgid "UserList|created %{timeago}"
msgstr ""
-msgid "UserProfile|(Busy)"
-msgstr ""
-
msgid "UserProfile|Activity"
msgstr ""
@@ -47915,6 +47912,9 @@ msgstr ""
msgid "UserProfile|Bot activity"
msgstr ""
+msgid "UserProfile|Busy"
+msgstr ""
+
msgid "UserProfile|Contributed projects"
msgstr ""
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 2e29d87dadd..ede26ebd032 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -1,11 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, feature_category: :continuous_integration do
+RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, feature_category: :continuous_integration, factory_default: :keep do
include ApiHelpers
include HttpIOHelpers
+ let_it_be(:namespace) { create_default(:namespace) }
let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
let_it_be(:owner) { create(:owner) }
let_it_be(:admin) { create(:admin) }
let_it_be(:maintainer) { create(:user) }
@@ -19,11 +21,16 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
project.add_developer(developer)
project.add_reporter(reporter)
project.add_guest(guest)
+ create_default(:owner)
+ create_default(:user)
+ create_default(:ci_trigger_request)
+ create_default(:ci_stage)
end
let(:user) { developer }
- let(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be_with_reload(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:default_pipeline) { create_default(:ci_pipeline) }
before do
stub_feature_flags(ci_enable_live_trace: true)
@@ -152,7 +159,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
end
context 'when requesting JSON' do
- let(:merge_request) { create(:merge_request, source_project: project) }
let(:user) { developer }
before do
@@ -211,9 +217,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
end
context 'when job has artifacts' do
- context 'with not expiry date' do
- let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
+ let_it_be(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
+ context 'with not expiry date' do
context 'when artifacts are unlocked' do
before do
job.pipeline.unlocked!
@@ -234,7 +240,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
context 'when artifacts are locked' do
before do
- job.pipeline.artifacts_locked!
+ job.pipeline.reload.artifacts_locked!
end
it 'exposes needed information' do
@@ -252,11 +258,13 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
end
context 'with expired artifacts' do
- let(:job) { create(:ci_build, :success, :artifacts, :expired, pipeline: pipeline) }
+ before do
+ job.update!(artifacts_expire_at: 1.minute.ago)
+ end
context 'when artifacts are unlocked' do
before do
- job.pipeline.unlocked!
+ job.pipeline.reload.unlocked!
end
it 'exposes needed information' do
@@ -275,7 +283,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
context 'when artifacts are locked' do
before do
- job.pipeline.artifacts_locked!
+ job.pipeline.reload.artifacts_locked!
end
it 'exposes needed information' do
@@ -292,19 +300,17 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
end
end
end
- end
-
- context 'when job passed with no trace' do
- let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
- it 'exposes empty state illustrations' do
- get_show_json
+ context 'when job passed with no trace' do
+ it 'exposes empty state illustrations' do
+ get_show_json
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('job/job_details')
- expect(json_response['status']['illustration']).to have_key('image')
- expect(json_response['status']['illustration']).to have_key('size')
- expect(json_response['status']['illustration']).to have_key('title')
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['status']['illustration']).to have_key('image')
+ expect(json_response['status']['illustration']).to have_key('size')
+ expect(json_response['status']['illustration']).to have_key('title')
+ end
end
end
@@ -320,7 +326,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
end
context 'with deployment' do
- let(:merge_request) { create(:merge_request, source_project: project) }
let(:environment) { create(:environment, project: project, name: 'staging', state: :available) }
let(:job) { create(:ci_build, :running, environment: environment.name, pipeline: pipeline) }
@@ -512,7 +517,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
end
context 'when requesting triggered job JSON' do
- let!(:merge_request) { create(:merge_request, source_project: project) }
let(:trigger) { create(:ci_trigger, project: project) }
let(:trigger_request) { create(:ci_trigger_request, pipeline: pipeline, trigger: trigger) }
let(:job) { create(:ci_build, pipeline: pipeline, trigger_request: trigger_request) }
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index 750bdf1e469..8c9d73f9c78 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -297,7 +297,7 @@ RSpec.describe 'User edit profile', feature_category: :user_profile do
end
page.within '.dropdown-menu-user' do
- expect(page).to have_content("#{user.name} (Busy)")
+ expect(page).to have_content("#{user.name} Busy")
end
end
@@ -308,7 +308,7 @@ RSpec.describe 'User edit profile', feature_category: :user_profile do
visit project_issue_path(project, issue)
wait_for_requests
- expect(page.find('.issuable-assignees')).to have_content("#{user.name} (Busy)")
+ expect(page.find('.issuable-assignees')).to have_content("#{user.name} Busy")
end
end
end
diff --git a/spec/fixtures/structure.sql b/spec/fixtures/structure.sql
index 6312545c593..5a7deb4fadf 100644
--- a/spec/fixtures/structure.sql
+++ b/spec/fixtures/structure.sql
@@ -35,8 +35,8 @@ CREATE TABLE test_table (
array_with_default_column character varying(255)[] DEFAULT '{one,two}'::character varying[] NOT NULL,
jsonb_column jsonb,
jsonb_with_default_column jsonb DEFAULT '[]'::jsonb NOT NULL,
- timestampz_column timestamp with time zone,
- timestampz_with_default_column timestamp with time zone DEFAULT now(),
+ timestamptz_column timestamp with time zone,
+ timestamptz_with_default_column timestamp(6) with time zone DEFAULT now(),
timestamp_column timestamp(6) without time zone NOT NULL,
timestamp_with_default_column timestamp(6) without time zone DEFAULT '2022-01-23 00:00:00+00'::timestamp without time zone NOT NULL,
date_column date,
diff --git a/spec/frontend/gfm_auto_complete_spec.js b/spec/frontend/gfm_auto_complete_spec.js
index e4fd8649263..73284fbe5e5 100644
--- a/spec/frontend/gfm_auto_complete_spec.js
+++ b/spec/frontend/gfm_auto_complete_spec.js
@@ -666,10 +666,11 @@ describe('GfmAutoComplete', () => {
username: 'my-group',
title: '',
icon: '<i class="icon"/>',
- availabilityStatus: '<span class="gl-text-gray-500"> (Busy)</span>',
+ availabilityStatus:
+ '<span class="badge badge-warning badge-pill gl-badge sm gl-ml-2">Busy</span>',
}),
).toBe(
- '<li>IMG my-group <small><span class="gl-text-gray-500"> (Busy)</span></small> <i class="icon"/></li>',
+ '<li>IMG my-group <small><span class="badge badge-warning badge-pill gl-badge sm gl-ml-2">Busy</span></small> <i class="icon"/></li>',
);
});
diff --git a/spec/frontend/repository/components/fork_info_spec.js b/spec/frontend/repository/components/fork_info_spec.js
index cbde60152e3..8aaf2806048 100644
--- a/spec/frontend/repository/components/fork_info_spec.js
+++ b/spec/frontend/repository/components/fork_info_spec.js
@@ -5,7 +5,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { stubComponent } from 'helpers/stub_component';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { createAlert } from '~/alert';
+import { createAlert, VARIANT_INFO } from '~/alert';
import ForkInfo, { i18n } from '~/repository/components/fork_info.vue';
import ConflictsModal from '~/repository/components/fork_sync_conflicts_modal.vue';
@@ -349,7 +349,16 @@ describe('ForkInfo component', () => {
mockResolvedForkDetailsQuery({ ahead: 0, behind: 0, isSyncing: false, hasConflicts: false });
});
- it('emits fork:update event to eventHub', async () => {
+ it('shows info alert once the fork is updated', async () => {
+ await startForkUpdate();
+ await waitForPolling();
+ expect(createAlert).toHaveBeenCalledWith({
+ message: i18n.successMessage,
+ variant: VARIANT_INFO,
+ });
+ });
+
+ it('emits fork:updated event to eventHub', async () => {
jest.spyOn(eventHub, '$emit').mockImplementation();
await startForkUpdate();
await waitForPolling();
diff --git a/spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js
index 7895274ab6d..25a19b5808b 100644
--- a/spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js
+++ b/spec/frontend/sidebar/components/assignees/sidebar_participant_spec.js
@@ -36,12 +36,13 @@ describe('Sidebar participant component', () => {
createComponent();
expect(findAvatar().props('label')).toBe(user.name);
+ expect(wrapper.text()).not.toContain('Busy');
});
it('shows `Busy` status when user is busy', () => {
createComponent({ status: { availability: 'BUSY' } });
- expect(findAvatar().props('label')).toBe(`${user.name} (Busy)`);
+ expect(wrapper.text()).toContain('Busy');
});
it('does not render a warning icon', () => {
diff --git a/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js b/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js
index 877d7cd61ee..e54ba31a30c 100644
--- a/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js
+++ b/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js
@@ -37,7 +37,7 @@ describe('UserNameWithStatus', () => {
});
it('will render "Busy"', () => {
- expect(wrapper.text()).toContain('(Busy)');
+ expect(wrapper.text()).toContain('Busy');
});
});
@@ -49,7 +49,7 @@ describe('UserNameWithStatus', () => {
});
it("renders user's name with pronouns", () => {
- expect(wrapper.text()).toMatchInterpolatedText(`${name} (${pronouns})`);
+ expect(wrapper.text()).toMatchInterpolatedText(`${name}(${pronouns})`);
});
});
diff --git a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
index 79ca6203459..41181ab9a68 100644
--- a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
+++ b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
@@ -275,7 +275,7 @@ describe('User Popover Component', () => {
createWrapper({ user });
- expect(wrapper.findByText('(Busy)').exists()).toBe(true);
+ expect(wrapper.findByText('Busy').exists()).toBe(true);
});
it('should hide the busy status for any other status', () => {
@@ -286,7 +286,7 @@ describe('User Popover Component', () => {
createWrapper({ user });
- expect(wrapper.findByText('(Busy)').exists()).toBe(false);
+ expect(wrapper.findByText('Busy').exists()).toBe(false);
});
it('shows pronouns when user has them set', () => {
diff --git a/spec/lib/gitlab/database/schema_validation/adapters/column_database_adapter_spec.rb b/spec/lib/gitlab/database/schema_validation/adapters/column_database_adapter_spec.rb
new file mode 100644
index 00000000000..13c4bc0b054
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/adapters/column_database_adapter_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Adapters::ColumnDatabaseAdapter, feature_category: :database do
+ subject(:adapter) { described_class.new(db_result) }
+
+ let(:column_name) { 'email' }
+ let(:column_default) { "'no-reply@gitlab.com'::character varying" }
+ let(:not_null) { true }
+ let(:db_result) do
+ {
+ 'table_name' => 'projects',
+ 'column_name' => column_name,
+ 'data_type' => 'character varying',
+ 'column_default' => column_default,
+ 'not_null' => not_null
+ }
+ end
+
+ describe '#name' do
+ it { expect(adapter.name).to eq('email') }
+ end
+
+ describe '#table_name' do
+ it { expect(adapter.table_name).to eq('projects') }
+ end
+
+ describe '#data_type' do
+ it { expect(adapter.data_type).to eq('character varying') }
+ end
+
+ describe '#default' do
+ context "when there's no default value in the column" do
+ let(:column_default) { nil }
+
+ it { expect(adapter.default).to be_nil }
+ end
+
+ context 'when the column name is id' do
+ let(:column_name) { 'id' }
+
+ it { expect(adapter.default).to be_nil }
+ end
+
+ context 'when the column default includes nextval' do
+ let(:column_default) { "nextval('my_seq'::regclass)" }
+
+ it { expect(adapter.default).to be_nil }
+ end
+
+ it { expect(adapter.default).to eq("DEFAULT 'no-reply@gitlab.com'::character varying") }
+ end
+
+ describe '#nullable' do
+ context 'when column is not null' do
+ it { expect(adapter.nullable).to eq('NOT NULL') }
+ end
+
+ context 'when column is nullable' do
+ let(:not_null) { false }
+
+ it { expect(adapter.nullable).to be_nil }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/adapters/column_structure_sql_adapter_spec.rb b/spec/lib/gitlab/database/schema_validation/adapters/column_structure_sql_adapter_spec.rb
new file mode 100644
index 00000000000..d7e5c6e896e
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/adapters/column_structure_sql_adapter_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Adapters::ColumnStructureSqlAdapter, feature_category: :database do
+ subject(:adapter) { described_class.new(table_name, column_def) }
+
+ let(:table_name) { 'my_table' }
+ let(:file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+ let(:table_stmts) { PgQuery.parse(File.read(file_path)).tree.stmts.filter_map { |s| s.stmt.create_stmt } }
+ let(:column_stmts) { table_stmts.find { |table| table.relation.relname == 'test_table' }.table_elts }
+ let(:column_def) { column_stmts.find { |col| col.column_def.colname == column_name }.column_def }
+
+ where(:column_name, :data_type, :default_value, :nullable) do
+ [
+ ['id', 'bigint', nil, 'NOT NULL'],
+ ['integer_column', 'integer', nil, nil],
+ ['integer_with_default_column', 'integer', 'DEFAULT 1', nil],
+ ['smallint_with_default_column', 'smallint', 'DEFAULT 0', 'NOT NULL'],
+ ['double_precision_with_default_column', 'double precision', 'DEFAULT 1.0', nil],
+ ['numeric_with_default_column', 'numeric', 'DEFAULT 1.0', 'NOT NULL'],
+ ['boolean_with_default_colum', 'boolean', 'DEFAULT true', 'NOT NULL'],
+ ['varying_with_default_column', 'character varying', "DEFAULT 'DEFAULT'::character varying", 'NOT NULL'],
+ ['varying_with_limit_and_default_column', 'character varying(255)', "DEFAULT 'DEFAULT'::character varying", nil],
+ ['text_with_default_column', 'text', "DEFAULT ''::text", 'NOT NULL'],
+ ['array_with_default_column', 'character varying(255)[]', "DEFAULT '{one,two}'::character varying[]", 'NOT NULL'],
+ ['jsonb_with_default_column', 'jsonb', "DEFAULT '[]'::jsonb", 'NOT NULL'],
+ ['timestamptz_with_default_column', 'timestamp(6) with time zone', "DEFAULT now()", nil],
+ ['timestamp_with_default_column', 'timestamp(6) without time zone',
+ "DEFAULT '2022-01-23 00:00:00+00'::timestamp without time zone", 'NOT NULL'],
+ ['date_with_default_column', 'date', 'DEFAULT 2023-04-05', nil],
+ ['inet_with_default_column', 'inet', "DEFAULT '0.0.0.0'::inet", 'NOT NULL'],
+ ['macaddr_with_default_column', 'macaddr', "DEFAULT '00-00-00-00-00-000'::macaddr", 'NOT NULL'],
+ ['uuid_with_default_column', 'uuid', "DEFAULT '00000000-0000-0000-0000-000000000000'::uuid", 'NOT NULL'],
+ ['bytea_with_default_column', 'bytea', "DEFAULT '\\xDEADBEEF'::bytea", nil]
+ ]
+ end
+
+ with_them do
+ describe '#name' do
+ it { expect(adapter.name).to eq(column_name) }
+ end
+
+ describe '#table_name' do
+ it { expect(adapter.table_name).to eq(table_name) }
+ end
+
+ describe '#data_type' do
+ it { expect(adapter.data_type).to eq(data_type) }
+ end
+
+ describe '#nullable' do
+ it { expect(adapter.nullable).to eq(nullable) }
+ end
+
+ describe '#default' do
+ it { expect(adapter.default).to eq(default_value) }
+ end
+ end
+
+ context 'when the data type is not mapped' do
+ let(:column_name) { 'unmapped_column_type' }
+ let(:error_class) { Gitlab::Database::SchemaValidation::Adapters::UndefinedPGType }
+
+ describe '#data_type' do
+ it { expect { adapter.data_type }.to raise_error(error_class) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/schema_objects/column_spec.rb b/spec/lib/gitlab/database/schema_validation/schema_objects/column_spec.rb
new file mode 100644
index 00000000000..74bc5f43b50
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/schema_objects/column_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::SchemaObjects::Column, feature_category: :database do
+ subject(:column) { described_class.new(adapter) }
+
+ let(:database_adapter) { 'Gitlab::Database::SchemaValidation::Adapters::ColumnDatabaseAdapter' }
+ let(:adapter) do
+ instance_double(database_adapter, name: 'id', table_name: 'projects',
+ data_type: 'bigint', default: nil, nullable: 'NOT NULL')
+ end
+
+ describe '#name' do
+ it { expect(column.name).to eq('id') }
+ end
+
+ describe '#table_name' do
+ it { expect(column.table_name).to eq('projects') }
+ end
+
+ describe '#statement' do
+ it { expect(column.statement).to eq('id bigint NOT NULL') }
+ end
+end
diff --git a/spec/lib/gitlab/database/schema_validation/schema_objects/table_spec.rb b/spec/lib/gitlab/database/schema_validation/schema_objects/table_spec.rb
index 7df37763643..6c2efee056b 100644
--- a/spec/lib/gitlab/database/schema_validation/schema_objects/table_spec.rb
+++ b/spec/lib/gitlab/database/schema_validation/schema_objects/table_spec.rb
@@ -3,9 +3,16 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::SchemaValidation::SchemaObjects::Table, feature_category: :database do
- subject(:table) { described_class.new(name) }
+ subject(:table) { described_class.new(name, columns) }
let(:name) { 'my_table' }
+ let(:column_class) { 'Gitlab::Database::SchemaValidation::SchemaObjects::Column' }
+ let(:columns) do
+ [
+ instance_double(column_class, name: 'id', statement: 'id bigint NOT NULL'),
+ instance_double(column_class, name: 'col', statement: 'col text')
+ ]
+ end
describe '#name' do
it { expect(table.name).to eq('my_table') }
@@ -14,4 +21,20 @@ RSpec.describe Gitlab::Database::SchemaValidation::SchemaObjects::Table, feature
describe '#table_name' do
it { expect(table.table_name).to eq('my_table') }
end
+
+ describe '#statement' do
+ it { expect(table.statement).to eq('CREATE TABLE my_table (id bigint NOT NULL, col text)') }
+ end
+
+ describe '#fetch_column_by_name' do
+ it { expect(table.fetch_column_by_name('col')).not_to be_nil }
+
+ it { expect(table.fetch_column_by_name('invalid')).to be_nil }
+ end
+
+ describe '#column_exists?' do
+ it { expect(table.column_exists?('col')).to eq(true) }
+
+ it { expect(table.column_exists?('invalid')).to eq(false) }
+ end
end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb
index 1ee69edda62..036ad6424f0 100644
--- a/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb
+++ b/spec/lib/gitlab/database/schema_validation/validators/base_validator_spec.rb
@@ -9,11 +9,14 @@ RSpec.describe Gitlab::Database::SchemaValidation::Validators::BaseValidator, fe
it 'returns an array of all validators' do
expect(all_validators).to eq([
Gitlab::Database::SchemaValidation::Validators::ExtraTables,
+ Gitlab::Database::SchemaValidation::Validators::ExtraTableColumns,
Gitlab::Database::SchemaValidation::Validators::ExtraIndexes,
Gitlab::Database::SchemaValidation::Validators::ExtraTriggers,
Gitlab::Database::SchemaValidation::Validators::MissingTables,
+ Gitlab::Database::SchemaValidation::Validators::MissingTableColumns,
Gitlab::Database::SchemaValidation::Validators::MissingIndexes,
Gitlab::Database::SchemaValidation::Validators::MissingTriggers,
+ Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionTables,
Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionIndexes,
Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionTriggers
])
diff --git a/spec/lib/gitlab/database/schema_validation/validators/different_definition_tables_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/different_definition_tables_spec.rb
new file mode 100644
index 00000000000..746418b757e
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/different_definition_tables_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionTables, feature_category: :database do
+ include_examples 'table validators', described_class, ['wrong_table']
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/extra_table_columns_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/extra_table_columns_spec.rb
new file mode 100644
index 00000000000..9d17a2fffa9
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/extra_table_columns_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::ExtraTableColumns, feature_category: :database do
+ include_examples 'table validators', described_class, ['extra_table_columns']
+end
diff --git a/spec/lib/gitlab/database/schema_validation/validators/missing_table_columns_spec.rb b/spec/lib/gitlab/database/schema_validation/validators/missing_table_columns_spec.rb
new file mode 100644
index 00000000000..de2956b4dd9
--- /dev/null
+++ b/spec/lib/gitlab/database/schema_validation/validators/missing_table_columns_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::SchemaValidation::Validators::MissingTableColumns, feature_category: :database do
+ include_examples 'table validators', described_class, ['missing_table_columns']
+end
diff --git a/spec/migrations/20230202131928_encrypt_ci_trigger_token_spec.rb b/spec/migrations/20230202131928_encrypt_ci_trigger_token_spec.rb
index a8896e7d3cf..597cd7c1581 100644
--- a/spec/migrations/20230202131928_encrypt_ci_trigger_token_spec.rb
+++ b/spec/migrations/20230202131928_encrypt_ci_trigger_token_spec.rb
@@ -9,14 +9,6 @@ RSpec.describe EncryptCiTriggerToken, migration: :gitlab_ci, feature_category: :
let!(:migration) { described_class::MIGRATION }
describe '#up' do
- shared_examples 'finalizes the migration' do
- it 'finalizes the migration' do
- allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner|
- expect(runner).to receive(:finalize).with('EncryptCiTriggerToken', :ci_triggers, :id, [])
- end
- end
- end
-
context 'with migration present' do
let!(:ci_trigger_token_encryption_migration) do
batched_migrations.create!(
@@ -51,25 +43,6 @@ RSpec.describe EncryptCiTriggerToken, migration: :gitlab_ci, feature_category: :
)
end
end
-
- context 'with different migration statuses' do
- using RSpec::Parameterized::TableSyntax
-
- where(:status, :description) do
- 0 | 'paused'
- 1 | 'active'
- 4 | 'failed'
- 5 | 'finalizing'
- end
-
- with_them do
- before do
- ci_trigger_token_encryption_migration.update!(status: status)
- end
-
- it_behaves_like 'finalizes the migration'
- end
- end
end
end
diff --git a/spec/migrations/20230412214119_finalize_encrypt_ci_trigger_token_spec.rb b/spec/migrations/20230412214119_finalize_encrypt_ci_trigger_token_spec.rb
new file mode 100644
index 00000000000..c30cafc915d
--- /dev/null
+++ b/spec/migrations/20230412214119_finalize_encrypt_ci_trigger_token_spec.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe FinalizeEncryptCiTriggerToken, migration: :gitlab_ci, feature_category: :continuous_integration do
+ let(:batched_migrations) { table(:batched_background_migrations) }
+ let(:batch_failed_status) { 2 }
+ let(:batch_finalized_status) { 3 }
+
+ let!(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ context 'when migration is missing' do
+ before do
+ batched_migrations.where(job_class_name: migration).delete_all
+ end
+
+ it 'warns migration not found' do
+ expect(Gitlab::AppLogger)
+ .to receive(:warn).with(/Could not find batched background migration for the given configuration:/)
+
+ migrate!
+ end
+ end
+
+ context 'with migration present' do
+ let!(:migration_record) do
+ batched_migrations.create!(
+ job_class_name: migration,
+ table_name: :ci_triggers,
+ column_name: :id,
+ job_arguments: [],
+ interval: 2.minutes,
+ min_value: 1,
+ max_value: 2,
+ batch_size: 1000,
+ sub_batch_size: 100,
+ max_batch_size: 2000,
+ gitlab_schema: :gitlab_ci,
+ status: batch_finalized_status
+ )
+ end
+
+ context 'when migration finished successfully' do
+ it 'does not raise exception' do
+ expect { migrate! }.not_to raise_error
+ end
+ end
+
+ context 'with different migration statuses', :redis do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:status, :description) do
+ 0 | 'paused'
+ 1 | 'active'
+ 4 | 'failed'
+ 5 | 'finalizing'
+ end
+
+ with_them do
+ let!(:failed_job) do
+ table(:batched_background_migration_jobs).create!(
+ batched_background_migration_id: migration_record.id,
+ status: batch_failed_status,
+ min_value: 1,
+ max_value: 10,
+ attempts: 2,
+ batch_size: 100,
+ sub_batch_size: 10
+ )
+ end
+
+ before do
+ migration_record.update!(status: status)
+ end
+
+ it 'finalizes the migration' do
+ expect do
+ migrate!
+
+ migration_record.reload
+ failed_job.reload
+ end.to(
+ change { migration_record.status }.from(status).to(batch_finalized_status)
+ .and(
+ change { failed_job.status }.from(batch_failed_status).to(batch_finalized_status)
+ )
+ )
+ end
+ end
+ end
+ end
+ end
+end