diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-23 03:10:23 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-23 03:10:23 +0300 |
commit | 422294262e50d47bee73c2e85bfbc21473c2508a (patch) | |
tree | 6b14725468b36b6ca994aed39680ac872d91e49f | |
parent | 386dcdbe9d3cef9d5fa79c4582a722db27fe2c57 (diff) |
Add latest changes from gitlab-org/gitlab@master
28 files changed, 461 insertions, 69 deletions
diff --git a/.gitlab/ci/qa.gitlab-ci.yml b/.gitlab/ci/qa.gitlab-ci.yml index c2393e5e0d3..391e25956eb 100644 --- a/.gitlab/ci/qa.gitlab-ci.yml +++ b/.gitlab/ci/qa.gitlab-ci.yml @@ -251,3 +251,34 @@ e2e:code-suggestions-eval-results: expose_as: 'Code Suggestions evaluation results' paths: - scores.csv + +e2e:fulfillment-quarantine-report: + extends: + - .qa:rules:fulfillment-e2e-quarantine-report + stage: qa + before_script: + - cd qa && bundle install + - apt-get update && apt-get install -y jq + variables: + RSPEC_JSON: "tmp/rspec-fulfillment-quarantined.json" + NOTES_API: "https://gitlab.com/api/v4/projects/$CI_MERGE_REQUEST_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes" + USER_API: "https://gitlab.com/api/v4/user" + FULFILLMENT_SPECS_PATH: "qa/specs/features/ee/browser_ui/11_fulfillment" + script: + - bundle exec rspec $FULFILLMENT_SPECS_PATH --tag quarantine --format json --out $RSPEC_JSON --dry-run + - | + if [[ -f $RSPEC_JSON && $(cat $RSPEC_JSON | jq ".examples[]") ]] + then # quarantined tests found + bot_user_id=$(curl $USER_API -H "PRIVATE-TOKEN: $PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE" | jq ".id") + existing_comment=$(curl $NOTES_API -H "PRIVATE-TOKEN: $PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE" | jq ".[] | select((.author | .id | contains($bot_user_id)) and (.body | contains(\"# Quarantined Fulfillment QA E2E Tests\")))") + if [[ ! -z $existing_comment ]] + then + echo 'MR comment already exists, doing nothing' + else + COMMENT_HEADER=$'# Quarantined Fulfillment QA E2E Tests\nThe following Fulfillment QA E2E tests are in quarantine. If your changes would be covered by these tests, please be sure to perform manual testing.\n' + COMMENT_TABLE=$(cat $RSPEC_JSON | jq --raw-output '"|Description|Location|\n|---|---|\n" + ([.examples[] | "| \(.full_description) | \(.id) |\n"] | join(""))') + curl --request POST $NOTES_API -H "PRIVATE-TOKEN: $PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE" --data-urlencode "body=$COMMENT_HEADER $COMMENT_TABLE" + fi + else + echo 'No quarantined tests found' + fi diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 75d4292f524..fb9a7688166 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -50,6 +50,9 @@ .if-merge-request-and-specific-devops-stage: &if-merge-request-and-specific-devops-stage if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_LABELS =~ /devops::(create|govern|manage|plan|verify|package)/' +.if-merge-request-and-devops-fulfillment: &if-merge-request-and-devops-fulfillment + if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_LABELS =~ /devops::fulfillment/' + .if-merge-request-not-approved: &if-merge-request-not-approved if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_LABELS !~ /pipeline:mr-approved/' @@ -1918,6 +1921,14 @@ changes: *code-patterns allow_failure: true +.qa:rules:fulfillment-e2e-quarantine-report: + rules: + - <<: *if-not-ee + when: never + - <<: *if-merge-request-and-devops-fulfillment + changes: *code-patterns + allow_failure: true + ############### # Rails rules # ############### diff --git a/app/assets/javascripts/organizations/mock_data.js b/app/assets/javascripts/organizations/mock_data.js index 56aa0ea28a9..29898708a41 100644 --- a/app/assets/javascripts/organizations/mock_data.js +++ b/app/assets/javascripts/organizations/mock_data.js @@ -4,6 +4,13 @@ // https://gitlab.com/gitlab-org/gitlab/-/issues/420777 // https://gitlab.com/gitlab-org/gitlab/-/issues/421441 +export const defaultOrganization = { + id: 1, + name: 'Default', + web_url: '/-/organizations/default', + avatar_url: null, +}; + export const organizations = [ { id: 'gid://gitlab/Organizations::Organization/1', diff --git a/app/assets/javascripts/super_sidebar/components/organization_switcher.vue b/app/assets/javascripts/super_sidebar/components/organization_switcher.vue new file mode 100644 index 00000000000..7122f147d3e --- /dev/null +++ b/app/assets/javascripts/super_sidebar/components/organization_switcher.vue @@ -0,0 +1,144 @@ +<script> +import { GlDisclosureDropdown, GlAvatar, GlIcon, GlLoadingIcon } from '@gitlab/ui'; +import getCurrentUserOrganizations from '~/organizations/shared/graphql/queries/organizations.query.graphql'; +import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import { defaultOrganization } from '~/organizations/mock_data'; +import { s__ } from '~/locale'; + +export default { + AVATAR_SHAPE_OPTION_RECT, + ITEM_LOADING: { + id: 'loading', + text: 'loading', + extraAttrs: { disabled: true, class: 'gl-shadow-none!' }, + }, + ITEM_EMPTY: { + id: 'empty', + text: s__('Organization|No organizations available to switch to.'), + extraAttrs: { disabled: true, class: 'gl-shadow-none! gl-text-secondary' }, + }, + i18n: { + currentOrganization: s__('Organization|Current organization'), + switchOrganizations: s__('Organization|Switch organizations'), + }, + components: { GlDisclosureDropdown, GlAvatar, GlIcon, GlLoadingIcon }, + data() { + return { + organizations: {}, + dropdownShown: false, + }; + }, + apollo: { + organizations: { + query: getCurrentUserOrganizations, + update(data) { + return data.currentUser.organizations; + }, + skip() { + return !this.dropdownShown; + }, + error() { + this.organizations = { + nodes: [], + pageInfo: {}, + }; + }, + }, + }, + computed: { + loading() { + return this.$apollo.queries.organizations.loading; + }, + currentOrganization() { + // TODO - use `gon.current_organization` when backend supports it. + // https://gitlab.com/gitlab-org/gitlab/-/issues/437095 + return defaultOrganization; + }, + nodes() { + return this.organizations.nodes || []; + }, + items() { + const currentOrganizationGroup = { + name: this.$options.i18n.currentOrganization, + items: [ + { + id: this.currentOrganization.id, + text: this.currentOrganization.name, + href: this.currentOrganization.web_url, + avatarUrl: this.currentOrganization.avatar_url, + }, + ], + }; + + if (this.loading || !this.dropdownShown) { + return [ + currentOrganizationGroup, + { + name: this.$options.i18n.switchOrganizations, + items: [this.$options.ITEM_LOADING], + }, + ]; + } + + const items = this.nodes + .map((node) => ({ + id: getIdFromGraphQLId(node.id), + text: node.name, + href: node.webUrl, + avatarUrl: node.avatarUrl, + })) + .filter((item) => item.id !== this.currentOrganization.id); + + return [ + currentOrganizationGroup, + { + name: this.$options.i18n.switchOrganizations, + items: items.length ? items : [this.$options.ITEM_EMPTY], + }, + ]; + }, + }, + methods: { + onShown() { + this.dropdownShown = true; + }, + }, +}; +</script> + +<template> + <gl-disclosure-dropdown :items="items" class="gl-display-block" @shown="onShown"> + <template #toggle> + <button + class="organization-switcher-button gl-display-flex gl-align-items-center gl-gap-3 gl-p-3 gl-rounded-base gl-border-none gl-line-height-1 gl-w-full" + data-testid="toggle-button" + > + <gl-avatar + :size="24" + :shape="$options.AVATAR_SHAPE_OPTION_RECT" + :entity-id="currentOrganization.id" + :entity-name="currentOrganization.name" + :src="currentOrganization.avatar_url" + /> + <span>{{ currentOrganization.name }}</span> + <gl-icon class="gl-button-icon gl-new-dropdown-chevron" name="chevron-down" /> + </button> + </template> + + <template #list-item="{ item }"> + <gl-loading-icon v-if="item.id === $options.ITEM_LOADING.id" /> + <span v-else-if="item.id === $options.ITEM_EMPTY.id">{{ item.text }}</span> + <div v-else class="gl-display-flex gl-align-items-center gl-gap-3"> + <gl-avatar + :size="24" + :shape="$options.AVATAR_SHAPE_OPTION_RECT" + :entity-id="item.id" + :entity-name="item.text" + :src="item.avatarUrl" + /> + <span>{{ item.text }}</span> + </div> + </template> + </gl-disclosure-dropdown> +</template> diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue index 3c8bf62ff5c..794a8b2cea9 100644 --- a/app/assets/javascripts/super_sidebar/components/user_bar.vue +++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue @@ -6,6 +6,7 @@ import { createUserCountsManager, userCounts, } from '~/super_sidebar/user_counts_manager'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import BrandLogo from 'jh_else_ce/super_sidebar/components/brand_logo.vue'; import { JS_TOGGLE_COLLAPSE_CLASS } from '../constants'; import CreateMenu from './create_menu.vue'; @@ -35,6 +36,8 @@ export default { SuperSidebarToggle, BrandLogo, GlIcon, + OrganizationSwitcher: () => + import(/* webpackChunkName: 'organization_switcher' */ './organization_switcher.vue'), }, i18n: { issues: __('Issues'), @@ -52,6 +55,7 @@ export default { GlTooltip: GlTooltipDirective, GlModal: GlModalDirective, }, + mixins: [glFeatureFlagsMixin()], inject: ['isImpersonating'], props: { hasCollapseButton: { @@ -149,6 +153,7 @@ export default { data-testid="stop-impersonation-btn" /> </div> + <organization-switcher v-if="glFeatures.uiForOrganizations" /> <div v-if="sidebarData.is_logged_in" class="gl-display-flex gl-justify-content-space-between gl-gap-2" diff --git a/app/assets/stylesheets/framework/super_sidebar.scss b/app/assets/stylesheets/framework/super_sidebar.scss index 0cb35bc117b..4d0b22928cc 100644 --- a/app/assets/stylesheets/framework/super_sidebar.scss +++ b/app/assets/stylesheets/framework/super_sidebar.scss @@ -231,6 +231,18 @@ $super-sidebar-transition-hint-duration: $super-sidebar-transition-duration / 4; .user-bar { background-color: var(--super-sidebar-user-bar-bg); + .organization-switcher-button { + background-color: transparent; + color: var(--super-sidebar-user-bar-button-color); + + &:active, + &:hover, + &:focus { + background-color: var(--super-sidebar-user-bar-button-hover-bg); + color: var(--super-sidebar-user-bar-button-hover-color); + } + } + .user-bar-dropdown-toggle { padding: $gl-spacing-scale-2; @include gl-border-none; diff --git a/app/graphql/resolvers/codequality_reports_comparer_resolver.rb b/app/graphql/resolvers/codequality_reports_comparer_resolver.rb index 1c034887c0d..cbc31f77803 100644 --- a/app/graphql/resolvers/codequality_reports_comparer_resolver.rb +++ b/app/graphql/resolvers/codequality_reports_comparer_resolver.rb @@ -9,8 +9,6 @@ module Resolvers authorize :read_build def resolve - return unless Feature.enabled?(:sast_reports_in_inline_diff, object.project) - authorize!(object.actual_head_pipeline) object.compare_codequality_reports diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 3572cfd346b..f4ed9d899a7 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -237,17 +237,15 @@ module Types null: true, description: 'List of emoji reactions associated with the merge request.' - field :prepared_at, Types::TimeType, null: true, - description: 'Timestamp of when the merge request was prepared.' - field :codequality_reports_comparer, type: ::Types::Security::CodequalityReportsComparerType, null: true, - alpha: { milestone: '16.4' }, - description: 'Code quality reports comparison reported on the merge request. Returns `null` ' \ - 'if `sast_reports_in_inline_diff` feature flag is disabled.', + description: 'Code quality reports comparison reported on the merge request.', resolver: ::Resolvers::CodequalityReportsComparerResolver + field :prepared_at, Types::TimeType, null: true, + description: 'Timestamp of when the merge request was prepared.' + field :allows_multiple_assignees, GraphQL::Types::Boolean, method: :allows_multiple_assignees?, diff --git a/app/serializers/codequality_degradation_entity.rb b/app/serializers/codequality_degradation_entity.rb index 9f90a30bd2d..b9049bc90b9 100644 --- a/app/serializers/codequality_degradation_entity.rb +++ b/app/serializers/codequality_degradation_entity.rb @@ -2,9 +2,7 @@ class CodequalityDegradationEntity < Grape::Entity expose :description - expose :fingerprint, if: ->(_, options) do - Feature.enabled?(:sast_reports_in_inline_diff, options[:request]&.project) - end + expose :fingerprint expose :severity do |degradation| degradation.dig(:severity)&.downcase end diff --git a/app/views/shared/milestones/_header.html.haml b/app/views/shared/milestones/_header.html.haml index 3413d6ff399..2a3a0d3c658 100644 --- a/app/views/shared/milestones/_header.html.haml +++ b/app/views/shared/milestones/_header.html.haml @@ -19,11 +19,10 @@ = render Pajamas::ButtonComponent.new(href: update_milestone_path(milestone, { state_event: :activate }), method: :put, button_options: { class: 'gl-display-none gl-md-display-inline-block' }) do = _('Reopen milestone') - .btn-group.gl-md-ml-3.gl-display-flex.dropdown.gl-dropdown.gl-md-w-auto.gl-w-full - = button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret has-tooltip gl-display-none! gl-md-display-inline-flex!", data: { toggle: 'dropdown', title: _('Milestone actions'), testid: 'milestone-actions', 'aria-label': _('Milestone actions') }, aria: { label: _('Milestone actions') } do - = sprite_icon "ellipsis_v", size: 16, css_class: "dropdown-icon gl-icon" - = button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md btn-block gl-button gl-dropdown-toggle gl-md-display-none!", data: { 'toggle' => 'dropdown' } do - %span.gl-dropdown-button-text= _('Milestone actions') + .gl-md-ml-3.gl-display-flex.dropdown.gl-dropdown.gl-md-w-auto.gl-w-full + = render Pajamas::ButtonComponent.new(category: :tertiary, icon: 'ellipsis_v', button_options: { class: 'has-tooltip gl-display-none! gl-md-display-inline-flex!', 'aria-label': _('Milestone actions'), data: { toggle: 'dropdown', title: _('Milestone actions'), testid: 'milestone-actions' } }) + = render Pajamas::ButtonComponent.new(button_options: { class: 'btn-block gl-md-display-none!', data: { toggle: 'dropdown' } }) do + = _('Milestone actions') = sprite_icon "chevron-down", size: 16, css_class: "dropdown-icon gl-icon" .dropdown-menu.dropdown-menu-right .gl-dropdown-inner diff --git a/config/feature_flags/development/prefix_scim_tokens.yml b/config/feature_flags/development/prefix_scim_tokens.yml deleted file mode 100644 index 297327f26d2..00000000000 --- a/config/feature_flags/development/prefix_scim_tokens.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: prefix_scim_tokens -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139737 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/435423 -milestone: '16.8' -type: development -group: group::authentication -default_enabled: false diff --git a/config/feature_flags/development/sast_reports_in_inline_diff.yml b/config/feature_flags/development/sast_reports_in_inline_diff.yml deleted file mode 100644 index 78729ed1466..00000000000 --- a/config/feature_flags/development/sast_reports_in_inline_diff.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: sast_reports_in_inline_diff -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119975 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/410191 -milestone: '16.0' -type: development -group: group::static analysis -default_enabled: true diff --git a/data/deprecations/16-9-deprecate-v1-license-metadata-format.yml b/data/deprecations/16-9-deprecate-v1-license-metadata-format.yml new file mode 100644 index 00000000000..774bde9d645 --- /dev/null +++ b/data/deprecations/16-9-deprecate-v1-license-metadata-format.yml @@ -0,0 +1,13 @@ +- title: "Deprecate license metadata format V1" + removal_milestone: "17.0" + announcement_milestone: "16.9" + breaking_change: true + reporter: thiagocsf + stage: Secure + issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/438477 + body: | # (required) Don't change this line. + The license metadata format V1 dataset has been deprecated and will be removed + in GitLab 17.0. + + Users who have the `package_metadata_synchronization` feature flag enabled are advised to + upgrade to GitLab 16.3 or above, and remove the feature flag configuration. diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 0799c002a73..2cbf54934e4 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -16550,8 +16550,8 @@ Represents finding. | ---- | ---- | ----------- | | <a id="comparedsecurityreportfindingdescription"></a>`description` | [`String`](#string) | Description of the vulnerability finding. | | <a id="comparedsecurityreportfindingfoundbypipelineiid"></a>`foundByPipelineIid` | [`String`](#string) | IID of the pipeline. | -| <a id="comparedsecurityreportfindingidentifiers"></a>`identifiers` **{warning-solid}** | [`[VulnerabilityIdentifier!]`](#vulnerabilityidentifier) | **Introduced** in 16.3. This feature is an Experiment. It can be changed or removed at any time. Identifiers of the vulnerability finding. Returns `null` if `sast_reports_in_inline_diff` feature flag is disabled. | -| <a id="comparedsecurityreportfindinglocation"></a>`location` **{warning-solid}** | [`VulnerabilityLocation`](#vulnerabilitylocation) | **Introduced** in 16.3. This feature is an Experiment. It can be changed or removed at any time. Location of the vulnerability finding. Returns `null` if `sast_reports_in_inline_diff` feature flag is disabled. | +| <a id="comparedsecurityreportfindingidentifiers"></a>`identifiers` **{warning-solid}** | [`[VulnerabilityIdentifier!]`](#vulnerabilityidentifier) | **Introduced** in 16.3. This feature is an Experiment. It can be changed or removed at any time. Identifiers of the vulnerability finding. | +| <a id="comparedsecurityreportfindinglocation"></a>`location` **{warning-solid}** | [`VulnerabilityLocation`](#vulnerabilitylocation) | **Introduced** in 16.3. This feature is an Experiment. It can be changed or removed at any time. Location of the vulnerability finding. | | <a id="comparedsecurityreportfindingscanner"></a>`scanner` | [`ComparedSecurityReportScanner`](#comparedsecurityreportscanner) | Compared report vulnerability scanner. | | <a id="comparedsecurityreportfindingseverity"></a>`severity` | [`VulnerabilitySeverity`](#vulnerabilityseverity) | Severity of the vulnerability finding. | | <a id="comparedsecurityreportfindingstate"></a>`state` | [`VulnerabilityState`](#vulnerabilitystate) | Finding status. | @@ -21598,7 +21598,7 @@ Defines which user roles, users, or groups can merge into a protected branch. | <a id="mergerequestavailableautomergestrategies"></a>`availableAutoMergeStrategies` | [`[String!]`](#string) | Array of available auto merge strategies. | | <a id="mergerequestawardemoji"></a>`awardEmoji` | [`AwardEmojiConnection`](#awardemojiconnection) | List of emoji reactions associated with the merge request. (see [Connections](#connections)) | | <a id="mergerequestblockingmergerequests"></a>`blockingMergeRequests` **{warning-solid}** | [`BlockingMergeRequests`](#blockingmergerequests) | **Introduced** in 16.5. This feature is an Experiment. It can be changed or removed at any time. Merge requests that block another merge request from merging. | -| <a id="mergerequestcodequalityreportscomparer"></a>`codequalityReportsComparer` **{warning-solid}** | [`CodequalityReportsComparer`](#codequalityreportscomparer) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Code quality reports comparison reported on the merge request. Returns `null` if `sast_reports_in_inline_diff` feature flag is disabled. | +| <a id="mergerequestcodequalityreportscomparer"></a>`codequalityReportsComparer` | [`CodequalityReportsComparer`](#codequalityreportscomparer) | Code quality reports comparison reported on the merge request. | | <a id="mergerequestcommenters"></a>`commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | | <a id="mergerequestcommitcount"></a>`commitCount` | [`Int`](#int) | Number of commits in the merge request. | | <a id="mergerequestcommits"></a>`commits` | [`CommitConnection`](#commitconnection) | Merge request commits. (see [Connections](#connections)) | diff --git a/doc/ci/pipelines/downstream_pipelines.md b/doc/ci/pipelines/downstream_pipelines.md index ae2ca74e6f8..668337f4ea2 100644 --- a/doc/ci/pipelines/downstream_pipelines.md +++ b/doc/ci/pipelines/downstream_pipelines.md @@ -804,6 +804,12 @@ With multi-project pipelines, the trigger job fails and does not create the down to run pipelines against the protected branch. See [pipeline security for protected branches](index.md#pipeline-security-on-protected-branches) for more information. +To identify which user is having permission issues in the downstream project, you can check the trigger job using the following command in the [Rails console](../../administration/operations/rails_console.md) and look at the `user_id` attribute. + +```ruby +Ci::Bridge.find(<job_id>) +``` + ### Job in child pipeline is not created when the pipeline runs If the parent pipeline is a [merge request pipeline](merge_request_pipelines.md), diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md index 4f812712651..74767fe202f 100644 --- a/doc/development/documentation/styleguide/index.md +++ b/doc/development/documentation/styleguide/index.md @@ -112,7 +112,7 @@ features is limited by our linters, so, use regular Markdown and follow the rule linked style guide. You can't use Kramdown-specific markup (for example, `{:.class}`). For a complete Kramdown reference, see the -[GitLab Markdown Guide](https://about.gitlab.com/handbook/markdown-guide/). +[GitLab Markdown Guide](https://handbook.gitlab.com/handbook/markdown-guide/). The Markdown format is [tested](../testing.md) by using markdownlint and Vale. diff --git a/doc/development/documentation/versions.md b/doc/development/documentation/versions.md index 0168cd39f01..883de58eb46 100644 --- a/doc/development/documentation/versions.md +++ b/doc/development/documentation/versions.md @@ -115,13 +115,13 @@ To deprecate a page or topic: WARNING: This feature was [deprecated](<link-to-issue>) in GitLab 14.8 - and is planned for removal in 15.4. Use [feature X](<link-to-issue>) instead. + and is planned for removal in 15.4. Use [feature X](<link-to-docs>) instead. ``` If you're not sure when the feature will be removed or no replacement feature exists, you don't need to add this information. -1. If the deprecation is a breaking change, add this text: +1. If the deprecation is a [breaking change](../../update/terminology.md#breaking-change), add this text: ```markdown This change is a breaking change. @@ -139,7 +139,7 @@ To deprecate a page or topic: WARNING: This feature was [deprecated](<link-to-issue>) in GitLab 14.8 - and is planned for removal in 15.4. Use [feature X](<link-to-issue>) instead. + and is planned for removal in 15.4. Use [feature X](<link-to-docs>) instead. <!--- end_remove --> ``` @@ -174,7 +174,7 @@ To remove a page: This feature was [deprecated](<link-to-issue>) in GitLab X.Y and [removed](<link-to-issue>) in X.Y. - Use [feature X](<link-to-issue>) instead. + Use [feature X](<link-to-docs>) instead. ``` 1. Remove the page's entry from the global navigation by editing [`navigation.yaml`](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/content/_data/navigation.yaml) in `gitlab-docs`. @@ -199,7 +199,7 @@ To remove a topic: This feature was [deprecated](<link-to-issue>) in GitLab X.Y and [removed](<link-to-issue>) in X.Y. - Use [feature X](<link-to-issue>) instead. + Use [feature X](<link-to-docs>) instead. <!--- end_remove --> ``` diff --git a/doc/security/token_overview.md b/doc/security/token_overview.md index 9cd445ed47b..fdff31f8e68 100644 --- a/doc/security/token_overview.md +++ b/doc/security/token_overview.md @@ -245,7 +245,7 @@ The following tables show the prefixes for each type of token where applicable. | Incoming mail token | `glimt-` | | GitLab Agent for Kubernetes token | `glagent-` | | GitLab session cookies | `_gitlab_session=` | -| SCIM Tokens | `glsoat-` ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/435096) in GitLab 16.8 behind a feature flag named `prefix_scim_tokens`. Disabled by default.) | +| SCIM Tokens | `glsoat-` <br /> • ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/435096) in GitLab 16.8 behind a feature flag named `prefix_scim_tokens`. Disabled by default.) <br > • ([Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/435423) in GitLab 16.9. Feature flag `prefix_scim_tokens` removed.) | ### External system tokens diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md index 748556675c0..bdc83c31c22 100644 --- a/doc/update/deprecations.md +++ b/doc/update/deprecations.md @@ -575,6 +575,24 @@ The runner's legacy escape sequence mechanism to handle variable expansion imple <div class="deprecation breaking-change" data-milestone="17.0"> +### Deprecate license metadata format V1 + +<div class="deprecation-notes"> +- Announced in GitLab <span class="milestone">16.9</span> +- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change)) +- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/438477). +</div> + +The license metadata format V1 dataset has been deprecated and will be removed +in GitLab 17.0. + +Users who have the `package_metadata_synchronization` feature flag enabled are advised to +upgrade to GitLab 16.3 or above, and remove the feature flag configuration. + +</div> + +<div class="deprecation breaking-change" data-milestone="17.0"> + ### Deprecated parameters related to custom text in the sign-in page <div class="deprecation-notes"> diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md index da275c283f6..e0a97568b5b 100644 --- a/doc/user/application_security/sast/index.md +++ b/doc/user/application_security/sast/index.md @@ -265,6 +265,7 @@ were introduced by the changes made in the merge request. > - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10959) in GitLab 16.6 with a [flag](../../../administration/feature_flags.md) named `sast_reports_in_inline_diff`. Disabled by default. > - Enabled by default in GitLab 16.8. +> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/410191) in GitLab 16.9. SAST results display in the merge request **Changes** view. Lines containing SAST issues are marked by a symbol beside the gutter. Select the symbol to see the list of issues, then select an issue to see its details. diff --git a/doc/user/project/merge_requests/revert_changes.md b/doc/user/project/merge_requests/revert_changes.md index 07523b9f34c..72bc82bbf0f 100644 --- a/doc/user/project/merge_requests/revert_changes.md +++ b/doc/user/project/merge_requests/revert_changes.md @@ -52,14 +52,19 @@ Prerequisites: - You must have a role in the project that allows you to edit merge requests, and add code to the repository. +- The commit must not have already been reverted, as the **Revert** option is not + shown in this case. To do this: 1. On the left sidebar, select **Search or go to** and find your project. 1. If you know the merge request that contains the commit: - 1. Select **Code > Merge requests**, then identify and select your merge request. - 1. Select **Commits**, then select the title of the commit you want to revert. This displays the commit in the **Changes** tab of your merge request. - 1. Select the commit hash you want to revert. GitLab displays the contents of the commit. + 1. Select **Code > Merge requests**, then select your merge request. + 1. Select **Commits**, then select the title of the commit you want to revert. + This displays the commit in the context of your merge request. + 1. Below the secondary menu, the message **Viewing commit `00001111`** is shown, + where `00001111` is the hash of the commit. Select the commit hash to show + the commit's page. 1. If you don't know the merge request the commit originated from: 1. Select **Code > Commits**. 1. Select the title of the commit to display full information about the commit. @@ -68,8 +73,6 @@ To do this: 1. Optional. Select **Start a new merge request** to start a new merge request with the new revert commit. 1. Select **Revert**. -The option to **Revert** is no longer shown after a commit is reverted. - ### Revert a merge commit to a different parent commit When you revert a merge commit, the branch you merged to (usually `main`) is always the diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index 6420b2561dc..9d7e73ba1f2 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -77,6 +77,7 @@ module Gitlab push_frontend_feature_flag(:source_editor_toolbar) push_frontend_feature_flag(:vscode_web_ide, current_user) push_frontend_feature_flag(:key_contacts_management, current_user) + push_frontend_feature_flag(:ui_for_organizations, current_user) # To be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/399248 push_frontend_feature_flag(:remove_monitor_metrics) push_frontend_feature_flag(:custom_emoji) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d925ac87c1d..333b78b037d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -34232,6 +34232,9 @@ msgstr "" msgid "Organization|Create organization" msgstr "" +msgid "Organization|Current organization" +msgstr "" + msgid "Organization|Frequently visited groups" msgstr "" @@ -34256,6 +34259,9 @@ msgstr "" msgid "Organization|New organization" msgstr "" +msgid "Organization|No organizations available to switch to." +msgstr "" + msgid "Organization|Org ID" msgstr "" @@ -34319,6 +34325,9 @@ msgstr "" msgid "Organization|Select an organization" msgstr "" +msgid "Organization|Switch organizations" +msgstr "" + msgid "Organization|Unable to fetch organizations. Reload the page to try again." msgstr "" diff --git a/spec/features/nav/pinned_nav_items_spec.rb b/spec/features/nav/pinned_nav_items_spec.rb index a2428048a1a..a1137536dd5 100644 --- a/spec/features/nav/pinned_nav_items_spec.rb +++ b/spec/features/nav/pinned_nav_items_spec.rb @@ -170,6 +170,7 @@ RSpec.describe 'Navigation menu item pinning', :js, feature_category: :navigatio def add_pin(nav_item_title) nav_item = find("[data-testid=\"nav-item\"]", text: nav_item_title) + scroll_to(nav_item) nav_item.hover pin_button = nav_item.find("[data-testid=\"nav-item-pin\"]") pin_button.click @@ -178,6 +179,7 @@ RSpec.describe 'Navigation menu item pinning', :js, feature_category: :navigatio def remove_pin(nav_item_title) nav_item = find("[data-testid=\"nav-item\"]", text: nav_item_title) + scroll_to(nav_item) nav_item.hover unpin_button = nav_item.find("[data-testid=\"nav-item-unpin\"]") unpin_button.click diff --git a/spec/frontend/super_sidebar/components/organization_switcher_spec.js b/spec/frontend/super_sidebar/components/organization_switcher_spec.js new file mode 100644 index 00000000000..094cb4baedb --- /dev/null +++ b/spec/frontend/super_sidebar/components/organization_switcher_spec.js @@ -0,0 +1,148 @@ +import { GlAvatar, GlDisclosureDropdown, GlLoadingIcon } from '@gitlab/ui'; +import VueApollo from 'vue-apollo'; +import Vue from 'vue'; + +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import OrganizationSwitcher from '~/super_sidebar/components/organization_switcher.vue'; +import { + defaultOrganization as currentOrganization, + organizations as nodes, + pageInfo, + pageInfoEmpty, +} from '~/organizations/mock_data'; +import organizationsQuery from '~/organizations/shared/graphql/queries/organizations.query.graphql'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; + +Vue.use(VueApollo); + +describe('OrganizationSwitcher', () => { + let wrapper; + let mockApollo; + + const [, secondOrganization, thirdOrganization] = nodes; + + const organizations = { + nodes, + pageInfo, + }; + + const successHandler = jest.fn().mockResolvedValue({ + data: { + currentUser: { + id: 'gid://gitlab/User/1', + organizations, + }, + }, + }); + + const createComponent = (handler = successHandler) => { + mockApollo = createMockApollo([[organizationsQuery, handler]]); + + wrapper = mountExtended(OrganizationSwitcher, { + apolloProvider: mockApollo, + }); + }; + + const findDropdownItemByIndex = (index) => + wrapper.findAllByTestId('disclosure-dropdown-item').at(index); + const showDropdown = () => wrapper.findComponent(GlDisclosureDropdown).vm.$emit('shown'); + + afterEach(() => { + mockApollo = null; + }); + + it('renders disclosure dropdown with current organization selected', () => { + createComponent(); + + const toggleButton = wrapper.findByTestId('toggle-button'); + const dropdownItem = findDropdownItemByIndex(0); + + expect(toggleButton.text()).toContain(currentOrganization.name); + expect(toggleButton.findComponent(GlAvatar).props()).toMatchObject({ + src: currentOrganization.avatar_url, + entityId: currentOrganization.id, + entityName: currentOrganization.name, + }); + expect(dropdownItem.text()).toContain(currentOrganization.name); + expect(dropdownItem.findComponent(GlAvatar).props()).toMatchObject({ + src: currentOrganization.avatar_url, + entityId: currentOrganization.id, + entityName: currentOrganization.name, + }); + }); + + it('does not call GraphQL query', () => { + createComponent(); + + expect(successHandler).not.toHaveBeenCalled(); + }); + + describe('when dropdown is shown', () => { + it('calls GraphQL query and renders organizations that are available to switch to', async () => { + createComponent(); + showDropdown(); + + expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true); + + await waitForPromises(); + + expect(findDropdownItemByIndex(1).text()).toContain(secondOrganization.name); + expect(findDropdownItemByIndex(1).element.firstChild.getAttribute('href')).toBe( + secondOrganization.webUrl, + ); + expect(findDropdownItemByIndex(1).findComponent(GlAvatar).props()).toMatchObject({ + src: secondOrganization.avatarUrl, + entityId: getIdFromGraphQLId(secondOrganization.id), + entityName: secondOrganization.name, + }); + + expect(findDropdownItemByIndex(2).text()).toContain(thirdOrganization.name); + expect(findDropdownItemByIndex(2).element.firstChild.getAttribute('href')).toBe( + thirdOrganization.webUrl, + ); + expect(findDropdownItemByIndex(2).findComponent(GlAvatar).props()).toMatchObject({ + src: thirdOrganization.avatarUrl, + entityId: getIdFromGraphQLId(thirdOrganization.id), + entityName: thirdOrganization.name, + }); + }); + + describe('when there are no organizations to switch to', () => { + beforeEach(async () => { + createComponent( + jest.fn().mockResolvedValue({ + data: { + currentUser: { + id: 'gid://gitlab/User/1', + organizations: { + nodes: [], + pageInfo: pageInfoEmpty, + }, + }, + }, + }), + ); + showDropdown(); + await waitForPromises(); + }); + + it('renders empty message', () => { + expect(findDropdownItemByIndex(1).text()).toBe('No organizations available to switch to.'); + }); + }); + + describe('when there is an error fetching organizations', () => { + beforeEach(async () => { + createComponent(jest.fn().mockRejectedValue()); + showDropdown(); + await waitForPromises(); + }); + + it('renders empty message', () => { + expect(findDropdownItemByIndex(1).text()).toBe('No organizations available to switch to.'); + }); + }); + }); +}); diff --git a/spec/frontend/super_sidebar/components/user_bar_spec.js b/spec/frontend/super_sidebar/components/user_bar_spec.js index 27d65f27007..fa2c6fdf165 100644 --- a/spec/frontend/super_sidebar/components/user_bar_spec.js +++ b/spec/frontend/super_sidebar/components/user_bar_spec.js @@ -9,16 +9,20 @@ import UserMenu from '~/super_sidebar/components/user_menu.vue'; import SearchModal from '~/super_sidebar/components/global_search/components/global_search.vue'; import BrandLogo from 'jh_else_ce/super_sidebar/components/brand_logo.vue'; import MergeRequestMenu from '~/super_sidebar/components/merge_request_menu.vue'; +import OrganizationSwitcher from '~/super_sidebar/components/organization_switcher.vue'; import UserBar from '~/super_sidebar/components/user_bar.vue'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import waitForPromises from 'helpers/wait_for_promises'; import { userCounts } from '~/super_sidebar/user_counts_manager'; +import { stubComponent } from 'helpers/stub_component'; import { sidebarData as mockSidebarData, loggedOutSidebarData } from '../mock_data'; import { MOCK_DEFAULT_SEARCH_OPTIONS } from './global_search/mock_data'; describe('UserBar component', () => { let wrapper; + const OrganizationSwitcherStub = stubComponent(OrganizationSwitcher); + const findCreateMenu = () => wrapper.findComponent(CreateMenu); const findUserMenu = () => wrapper.findComponent(UserMenu); const findIssuesCounter = () => wrapper.findByTestId('issues-shortcut-button'); @@ -30,6 +34,7 @@ describe('UserBar component', () => { const findSearchButton = () => wrapper.findByTestId('super-sidebar-search-button'); const findSearchModal = () => wrapper.findComponent(SearchModal); const findStopImpersonationButton = () => wrapper.findByTestId('stop-impersonation-btn'); + const findOrganizationSwitcher = () => wrapper.findComponent(OrganizationSwitcherStub); Vue.use(Vuex); @@ -56,6 +61,9 @@ describe('UserBar component', () => { GlTooltip: createMockDirective('gl-tooltip'), }, store, + stubs: { + OrganizationSwitcher: OrganizationSwitcherStub, + }, }); }; @@ -252,4 +260,22 @@ describe('UserBar component', () => { expect(findTodosCounter().exists()).toBe(false); }); }); + + describe('when `ui_for_organizations` feature flag is enabled', () => { + it('renders `OrganizationSwitcher component', async () => { + createWrapper({ provideOverrides: { glFeatures: { uiForOrganizations: true } } }); + await waitForPromises(); + + expect(findOrganizationSwitcher().exists()).toBe(true); + }); + }); + + describe('when `ui_for_organizations` feature flag is disabled', () => { + it('renders `OrganizationSwitcher component', async () => { + createWrapper(); + await waitForPromises(); + + expect(findOrganizationSwitcher().exists()).toBe(false); + }); + }); }); diff --git a/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb b/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb index 09a229c2098..d9089538171 100644 --- a/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb +++ b/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb @@ -125,16 +125,6 @@ RSpec.describe 'Query.project.mergeRequest.codequalityReportsComparer', feature_ post_graphql(query, current_user: user) end - context 'when when sast_reports_in_inline_diff FF is disabled' do - before_all do - stub_feature_flags(sast_reports_in_inline_diff: false) - end - - it 'returns null for codequality_reports_comparer field' do - expect(result).to be_nil - end - end - it 'returns expected data' do expect(result).to match( a_hash_including( diff --git a/spec/serializers/codequality_degradation_entity_spec.rb b/spec/serializers/codequality_degradation_entity_spec.rb index 3d07564c5dc..dc15fa02a21 100644 --- a/spec/serializers/codequality_degradation_entity_spec.rb +++ b/spec/serializers/codequality_degradation_entity_spec.rb @@ -8,18 +8,6 @@ RSpec.describe CodequalityDegradationEntity, feature_category: :code_quality do describe '#as_json' do subject { entity.as_json } - context 'when sast_reports_in_inline_diff is disabled' do - before do - stub_feature_flags(sast_reports_in_inline_diff: false) - end - - let(:codequality_degradation) { build(:codequality_degradation_1) } - - it 'does not contain fingerprint' do - expect(subject[:fingerprint]).to be_nil - end - end - context 'when codequality contains an error' do context 'when line is included in location' do let(:codequality_degradation) { build(:codequality_degradation_2) } |