diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-14 12:09:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-14 12:09:02 +0300 |
commit | 6d8f30ab0ae82678f10450d2158f24772f0c765c (patch) | |
tree | f308a3feb16199440421980e68501d5efa0a9b10 | |
parent | c192f26df39e9a2ab122c2d097b86e461599bde8 (diff) |
Add latest changes from gitlab-org/gitlab@master
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 Binary files differdeleted file mode 100644 index 63301ebdc14..00000000000 --- a/doc/user/profile/img/busy_indicator_note_header_v13_9.png +++ /dev/null diff --git a/doc/user/profile/img/busy_indicator_notes_v13_9.png b/doc/user/profile/img/busy_indicator_notes_v13_9.png Binary files differdeleted file mode 100644 index 2efe075c72b..00000000000 --- a/doc/user/profile/img/busy_indicator_notes_v13_9.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index c8e969f38db..00000000000 --- a/doc/user/profile/img/busy_indicator_profile_page_v13_6.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 711638541dd..00000000000 --- a/doc/user/profile/img/busy_indicator_settings_menu_v13_6.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 3dca88ec8cc..00000000000 --- a/doc/user/profile/img/busy_indicator_sidebar_collapsed_v13_9.png +++ /dev/null diff --git a/doc/user/profile/img/busy_indicator_sidebar_v13_9.png b/doc/user/profile/img/busy_indicator_sidebar_v13_9.png Binary files differdeleted file mode 100644 index 83024b319bf..00000000000 --- a/doc/user/profile/img/busy_indicator_sidebar_v13_9.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 16fb0e6556b..00000000000 --- a/doc/user/profile/img/busy_indicator_user_popovers_v13_6.png +++ /dev/null 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 |