diff options
28 files changed, 152 insertions, 119 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/init_gfm.js b/app/assets/javascripts/behaviors/markdown/init_gfm.js deleted file mode 100644 index d9c7cee50da..00000000000 --- a/app/assets/javascripts/behaviors/markdown/init_gfm.js +++ /dev/null @@ -1,13 +0,0 @@ -import $ from 'jquery'; -import { renderGFM } from '~/behaviors/markdown/render_gfm'; - -$.fn.renderGFM = function plugin() { - this.get().forEach(renderGFM); - return this; -}; -requestIdleCallback( - () => { - renderGFM(document.body); - }, - { timeout: 500 }, -); diff --git a/app/assets/javascripts/behaviors/preview_markdown.js b/app/assets/javascripts/behaviors/preview_markdown.js index 86a05f24dfc..32e395e4f3c 100644 --- a/app/assets/javascripts/behaviors/preview_markdown.js +++ b/app/assets/javascripts/behaviors/preview_markdown.js @@ -1,10 +1,10 @@ /* eslint-disable func-names */ import $ from 'jquery'; +import { renderGFM } from '~/behaviors/markdown/render_gfm'; import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { __ } from '~/locale'; -import '~/behaviors/markdown/init_gfm'; // MarkdownPreview // @@ -51,7 +51,7 @@ MarkdownPreview.prototype.showPreview = function ($form) { } preview.removeClass('md-preview-loading').html(body); - preview.renderGFM(); + renderGFM(preview.get(0)); this.renderReferencedUsers(response.references.users, $form); if (response.references.commands) { diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js index 439c4258805..5e85e4cea38 100644 --- a/app/assets/javascripts/blob/viewer/index.js +++ b/app/assets/javascripts/blob/viewer/index.js @@ -1,5 +1,5 @@ import $ from 'jquery'; -import '~/behaviors/markdown/init_gfm'; +import { renderGFM } from '~/behaviors/markdown/render_gfm'; import { createAlert } from '~/flash'; import { __ } from '~/locale'; import { @@ -195,7 +195,7 @@ export class BlobViewer { this.toggleCopyButtonState(); loadViewer(newViewer) .then((viewer) => { - $(viewer).renderGFM(); + renderGFM(viewer); window.requestIdleCallback(() => { this.$fileHolder.trigger('highlight:line'); handleLocationHash(); diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js index 46b3f16df77..a3d11d90ed2 100644 --- a/app/assets/javascripts/blob_edit/edit_blob.js +++ b/app/assets/javascripts/blob_edit/edit_blob.js @@ -1,4 +1,5 @@ import $ from 'jquery'; +import { renderGFM } from '~/behaviors/markdown/render_gfm'; import { SourceEditorExtension } from '~/editor/extensions/source_editor_extension_base'; import { FileTemplateExtension } from '~/editor/extensions/source_editor_file_template_ext'; import { ToolbarExtension } from '~/editor/extensions/source_editor_toolbar_ext'; @@ -9,7 +10,6 @@ import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown'; import { insertFinalNewline } from '~/lib/utils/text_utility'; import TemplateSelectorMediator from '../blob/file_template_mediator'; import { BLOB_EDITOR_ERROR, BLOB_PREVIEW_ERROR } from './constants'; -import '~/behaviors/markdown/init_gfm'; export default class EditBlob { // The options object has: @@ -140,7 +140,7 @@ export default class EditBlob { }) .then(({ data }) => { currentPane.empty().append(data); - currentPane.renderGFM(); + renderGFM(currentPane.get(0)); }) .catch(() => createAlert({ diff --git a/app/assets/javascripts/deprecated_notes.js b/app/assets/javascripts/deprecated_notes.js index c090a66a69d..5c6874593a4 100644 --- a/app/assets/javascripts/deprecated_notes.js +++ b/app/assets/javascripts/deprecated_notes.js @@ -15,6 +15,7 @@ import Autosize from 'autosize'; import $ from 'jquery'; import { escape, uniqueId } from 'lodash'; import Vue from 'vue'; +import { renderGFM } from '~/behaviors/markdown/render_gfm'; import { createAlert, VARIANT_INFO } from '~/flash'; import '~/lib/utils/jquery_at_who'; import AjaxCache from '~/lib/utils/ajax_cache'; @@ -40,7 +41,6 @@ import { localTimeAgo } from './lib/utils/datetime_utility'; import { getLocationHash } from './lib/utils/url_utility'; import { sprintf, s__, __ } from './locale'; import TaskList from './task_list'; -import '~/behaviors/markdown/init_gfm'; window.autosize = Autosize; @@ -516,7 +516,11 @@ export default class Notes { } if (discussionContainer.length === 0) { if (noteEntity.diff_discussion_html) { - const $discussion = $(noteEntity.diff_discussion_html).renderGFM(); + const discussionElement = document.createElement('table'); + // eslint-disable-next-line no-unsanitized/method + discussionElement.insertAdjacentHTML('afterbegin', noteEntity.diff_discussion_html); + renderGFM(discussionElement); + const $discussion = $(discussionElement).unwrap(); if (!this.isParallelView() || row.hasClass('js-temp-notes-holder') || noteEntity.on_image) { // insert the note and the reply button after the temp row @@ -708,7 +712,7 @@ export default class Notes { $noteAvatar.append($targetNoteBadge); this.revertNoteEditForm($targetNote); - $noteEntityEl.renderGFM(); + renderGFM($noteEntityEl.get(0)); // Find the note's `li` element by ID and replace it with the updated HTML const $note_li = $(`.note-row-${noteEntity.id}`); @@ -1382,7 +1386,8 @@ export default class Notes { static animateAppendNote(noteHtml, $notesList) { const $note = $(noteHtml); - $note.addClass('fade-in-full').renderGFM(); + $note.addClass('fade-in-full'); + renderGFM($note.get(0)); $notesList.append($note); return $note; } @@ -1390,7 +1395,8 @@ export default class Notes { static animateUpdateNote(noteHtml, $note) { const $updatedNote = $(noteHtml); - $updatedNote.addClass('fade-in').renderGFM(); + $updatedNote.addClass('fade-in'); + renderGFM($updatedNote.get(0)); $note.replaceWith($updatedNote); return $updatedNote; } diff --git a/app/assets/javascripts/mr_notes/init_notes.js b/app/assets/javascripts/mr_notes/init_notes.js index e10605609b0..f5f10aa4a9b 100644 --- a/app/assets/javascripts/mr_notes/init_notes.js +++ b/app/assets/javascripts/mr_notes/init_notes.js @@ -1,5 +1,6 @@ import Vue from 'vue'; import { mapActions, mapState, mapGetters } from 'vuex'; +import { renderGFM } from '~/behaviors/markdown/render_gfm'; import { parseBoolean } from '~/lib/utils/common_utils'; import store from '~/mr_notes/stores'; import notesEventHub from '~/notes/event_hub'; @@ -9,6 +10,13 @@ import { getNotesFilterData } from '../notes/utils/get_notes_filter_data'; import initWidget from '../vue_merge_request_widget'; export default () => { + requestIdleCallback( + () => { + renderGFM(document.getElementById('diff-notes-app')); + }, + { timeout: 500 }, + ); + const el = document.getElementById('js-vue-mr-discussions'); if (!el) { return; diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue index 30528ce8d17..c498f12d5c7 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue @@ -1,5 +1,5 @@ <script> -import { GlDropdown, GlDropdownItem, GlEmptyState, GlIcon, GlLoadingIcon } from '@gitlab/ui'; +import { GlEmptyState, GlIcon, GlLoadingIcon, GlCollapsibleListbox } from '@gitlab/ui'; import { isEqual } from 'lodash'; import { createAlert, VARIANT_INFO, VARIANT_WARNING } from '~/flash'; import { getParameterByName } from '~/lib/utils/url_utility'; @@ -26,8 +26,7 @@ export default { PipelineKeyOptions, components: { EmptyState, - GlDropdown, - GlDropdownItem, + GlCollapsibleListbox, GlEmptyState, GlIcon, GlLoadingIcon, @@ -315,7 +314,7 @@ export default { this.updateContent(this.requestData); }, changeVisibilityPipelineID(val) { - this.selectedPipelineKeyOption = val; + this.selectedPipelineKeyOption = PipelineKeyOptions.find((e) => val === e.value); }, }, }; @@ -355,21 +354,12 @@ export default { :params="validatedParams" @filterPipelines="filterPipelines" /> - <gl-dropdown - class="gl-display-flex" - :text="selectedPipelineKeyOption.text" - data-testid="pipeline-key-dropdown" - > - <gl-dropdown-item - v-for="(val, index) in $options.PipelineKeyOptions" - :key="index" - :is-checked="selectedPipelineKeyOption.key === val.key" - is-check-item - @click="changeVisibilityPipelineID(val)" - > - {{ val.text }} - </gl-dropdown-item> - </gl-dropdown> + <gl-collapsible-listbox + data-testid="pipeline-key-collapsible-box" + :toggle-text="selectedPipelineKeyOption.text" + :items="$options.PipelineKeyOptions" + @select="changeVisibilityPipelineID" + /> </div> </div> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue index 346f5735576..ed32d643c0e 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue @@ -161,7 +161,7 @@ export default { <pipeline-url :pipeline="item" :pipeline-schedule-url="pipelineScheduleUrl" - :pipeline-key="pipelineKeyOption.key" + :pipeline-key="pipelineKeyOption.value" /> </template> diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js index ed8ec614304..2f37f90e625 100644 --- a/app/assets/javascripts/pipelines/constants.js +++ b/app/assets/javascripts/pipelines/constants.js @@ -71,12 +71,12 @@ export const PipelineKeyOptions = [ { text: __('Show Pipeline ID'), label: __('Pipeline ID'), - key: 'id', + value: 'id', }, { text: __('Show Pipeline IID'), label: __('Pipeline IID'), - key: 'iid', + value: 'iid', }, ]; diff --git a/app/services/ci/job_artifacts/destroy_associations_service.rb b/app/services/ci/job_artifacts/destroy_associations_service.rb index 4604d35ec23..6e3ccc175b4 100644 --- a/app/services/ci/job_artifacts/destroy_associations_service.rb +++ b/app/services/ci/job_artifacts/destroy_associations_service.rb @@ -2,6 +2,11 @@ module Ci module JobArtifacts + # This class is used by Ci::JobArtifact's FastDestroyAll implementation. + # Ci::JobArtifact.begin_fast_destroy instantiates this service and calls #destroy_records. + # This will set @statistics_updates instance variables. + # The same instance is passed to Ci::JobArtifact.finalize_fast_destroy, which then calls + # #update_statistics, using @statistics_updates set by #destroy_records. class DestroyAssociationsService BATCH_SIZE = 100 diff --git a/doc/integration/saml.md b/doc/integration/saml.md index c31d242fc59..26375975214 100644 --- a/doc/integration/saml.md +++ b/doc/integration/saml.md @@ -919,13 +919,13 @@ For example configurations, see the [notes on specific providers](#set-up-identi | Term | Description | |--------------------------------|-------------| -| Identity provider (IdP) | The service which manages your user identities, such as Okta or OneLogin. | -| Service provider (SP) | GitLab can be configured as a SAML 2.0 SP. | -| Assertion | A piece of information about a user's identity, such as their name or role. Also known as claims or attributes. | -| Single Sign-On (SSO) | Name of authentication scheme. | -| Assertion consumer service URL | The callback on GitLab where users are redirected after successfully authenticating with the identity provider. | -| Issuer | How GitLab identifies itself to the identity provider. Also known as a "Relying party trust identifier". | -| Certificate fingerprint | Used to confirm that communications over SAML are secure by checking that the server is signing communications with the correct certificate. Also known as a certificate thumbprint. | +| Identity provider (IdP) | The service that manages your user identities, such as Okta or OneLogin. | +| Service provider (SP) | Consumes assertions from a SAML IdP, such as Okta, to authenticate users. You can configure GitLab as a SAML 2.0 SP. | +| Assertion | A piece of information about a user's identity, such as their name or role. Also known as a claim or an attribute. | +| Single Sign-On (SSO) | Name of the authentication scheme. | +| Assertion consumer service URL | The callback on GitLab where users are redirected after successfully authenticating with the IdP. | +| Issuer | How GitLab identifies itself to the IdP. Also known as a "Relying party trust identifier". | +| Certificate fingerprint | Confirms that communications over SAML are secure by checking that the server is signing communications with the correct certificate. Also known as a certificate thumbprint. | ## Troubleshooting diff --git a/doc/subscriptions/gitlab_com/index.md b/doc/subscriptions/gitlab_com/index.md index 552e9c46c4a..d560e44850c 100644 --- a/doc/subscriptions/gitlab_com/index.md +++ b/doc/subscriptions/gitlab_com/index.md @@ -231,28 +231,15 @@ amounts at which the alert displays. | 100-999 | 8% of seats have been used. | | 1000+ | 5% of seats have been used | -## Change the linked account - -To change the GitLab.com account linked to your Customers Portal account: - -1. Log in to the - [Customers Portal](https://customers.gitlab.com/customers/sign_in). -1. In a separate browser tab, go to [GitLab SaaS](https://gitlab.com/users/sign_in) and ensure you - are not logged in. -1. On the Customers Portal page, select **My account > Account details**. -1. Under **Your GitLab.com account**, select **Change linked account**. -1. Log in to the [GitLab SaaS](https://gitlab.com/users/sign_in) account you want to link to the Customers Portal - account. - ## Change the linked namespace To change the namespace linked to a subscription: 1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in) with a - [linked](#change-the-linked-account) GitLab SaaS account. -1. Navigate to the **Manage Purchases** page. + [linked](../index.md#change-the-linked-account) GitLab.com account. +1. Go to the **Manage Purchases** page. 1. Select **Change linked namespace**. -1. Select the desired group from the **This subscription is for** dropdown. For a group to appear here, you must have the Owner role for that group. +1. Select the desired group from the **This subscription is for** dropdown list. For a group to appear here, you must have the Owner role for that group. 1. Select **Proceed to checkout**. <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> diff --git a/doc/subscriptions/index.md b/doc/subscriptions/index.md index 98ce40c9e9b..9fec4abe8e7 100644 --- a/doc/subscriptions/index.md +++ b/doc/subscriptions/index.md @@ -73,7 +73,7 @@ With the [Customers Portal](https://customers.gitlab.com/) you can: - [Change account owner information](#change-account-owner-information) - [Change your company details](#change-your-company-details) - [Change your payment method](#change-your-payment-method) -- [Change the linked account](gitlab_com/index.md#change-the-linked-account) +- [Change the linked account](#change-the-linked-account) - [Change the namespace the subscription is linked to](gitlab_com/index.md#change-the-linked-namespace) - [Change customers portal account password](#change-customers-portal-account-password) @@ -83,8 +83,9 @@ reseller, you must contact them directly for assistance with your subscription. ### Change account owner information -Account owner personal details are used on invoices. The account owner email -address is used for the Customers Portal login and license-related email. +Account owner personal details are used on invoices. The account owner email address is used for the Customers Portal legacy login and license-related email. + +If you have registered a Customers Portal account through a GitLab.com account, the GitLab.com account is used for login. To change account owner information, including name, billing address, and email address: @@ -95,8 +96,10 @@ To change account owner information, including name, billing address, and email 1. Select **Save changes**. If you want to transfer ownership of the Customers Portal account -to another person, after you enter that person's personal details, you must also -[change the Customers Portal account password](#change-customers-portal-account-password). +to another person, after you enter that person's personal details, you must also: + +- [Change the Customers Portal account password](#change-customers-portal-account-password). +- [Change the linked GitLab.com account](#change-the-linked-account), if you have one linked. ### Change your company details @@ -134,6 +137,19 @@ method as the default: 1. **Edit** the selected payment method and check the **Make default payment method** checkbox. 1. Select **Save Changes**. +### Change the linked account + +To change the GitLab.com account linked to your Customers Portal account: + +1. Log in to the + [Customers Portal](https://customers.gitlab.com/customers/sign_in). +1. In a separate browser tab, go to [GitLab.com](https://gitlab.com/users/sign_in) and ensure you + are not logged in. +1. On the Customers Portal page, select **My account > Account details**. +1. Under **Your GitLab.com account**, select **Change linked account**. +1. Log in to the [GitLab.com](https://gitlab.com/users/sign_in) account you want to link to the Customers Portal + account. + ### Change Customers Portal account password To change the password for this customers portal account: diff --git a/doc/subscriptions/self_managed/index.md b/doc/subscriptions/self_managed/index.md index 93cf5afad63..e16dd2a53ce 100644 --- a/doc/subscriptions/self_managed/index.md +++ b/doc/subscriptions/self_managed/index.md @@ -18,6 +18,10 @@ GitLab subscription management requires access to the Customers Portal. GitLab provides the [Customers Portal](../index.md#customers-portal) where you can manage your subscriptions and your account details. +Customers are required to use their GitLab.com account to register for a new Customers Portal account. + +If you have a legacy Customers Portal account that is not linked to a GitLab.com account, you may still [sign in](https://customers.gitlab.com/customers/sign_in?legacy=true) using an email and password. However, you should [create](https://gitlab.com/users/sign_up) and [link a GitLab.com account](../index.md#change-the-linked-account) to ensure continued access to the Customers Portal. + Customers of resellers do not have access to this portal and should contact their reseller for any changes to their subscription. diff --git a/doc/user/group/access_and_permissions.md b/doc/user/group/access_and_permissions.md index a7358db54df..64ad451f0e6 100644 --- a/doc/user/group/access_and_permissions.md +++ b/doc/user/group/access_and_permissions.md @@ -75,7 +75,7 @@ Administrators can combine restricted access by IP address with You should consider some security implications before configuring IP address restrictions. - Administrators and group owners can access group settings from any IP address, regardless of IP restriction. However: - - Groups owners cannot access projects belonging to the group when accessing from a disallowed IP address. + - Group owners can access the subgroups, but not the projects belonging to the group or subgroups, when accessing from a disallowed IP address. - Administrators can access projects belonging to the group when accessing from a disallowed IP address. Access to projects includes cloning code from them. - Users can still see group and project names and hierarchies. Only the following are restricted: diff --git a/lib/api/rubygem_packages.rb b/lib/api/rubygem_packages.rb index af0ceb1acfc..896d8fcc727 100644 --- a/lib/api/rubygem_packages.rb +++ b/lib/api/rubygem_packages.rb @@ -25,13 +25,19 @@ module API .sent_through(:http_token) end + helpers do + def project + user_project(action: :read_package) + end + end + before do require_packages_enabled! authenticate_non_get! end after_validation do - not_found! unless Feature.enabled?(:rubygem_packages, user_project) + not_found! unless Feature.enabled?(:rubygem_packages, project) end params do @@ -85,14 +91,14 @@ module API requires :file_name, type: String, desc: 'Package file name', documentation: { type: 'file' } end get "gems/:file_name", requirements: FILE_NAME_REQUIREMENTS do - authorize_read_package!(user_project) + authorize_read_package!(project) package_files = ::Packages::PackageFile - .for_rubygem_with_file_name(user_project, params[:file_name]) + .for_rubygem_with_file_name(project, params[:file_name]) package_file = package_files.installable.last! - track_package_event('pull_package', :rubygems, project: user_project, namespace: user_project.namespace) + track_package_event('pull_package', :rubygems, project: project, namespace: project.namespace) present_package_file!(package_file) end @@ -109,9 +115,9 @@ module API end post 'gems/authorize' do authorize_workhorse!( - subject: user_project, + subject: project, has_length: false, - maximum_size: user_project.actual_limits.rubygems_max_file_size + maximum_size: project.actual_limits.rubygems_max_file_size ) end @@ -129,16 +135,16 @@ module API requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' } end post 'gems' do - authorize_upload!(user_project) - bad_request!('File is too large') if user_project.actual_limits.exceeded?(:rubygems_max_file_size, params[:file].size) + authorize_upload!(project) + bad_request!('File is too large') if project.actual_limits.exceeded?(:rubygems_max_file_size, params[:file].size) - track_package_event('push_package', :rubygems, user: current_user, project: user_project, namespace: user_project.namespace) + track_package_event('push_package', :rubygems, user: current_user, project: project, namespace: project.namespace) package_file = nil ApplicationRecord.transaction do package = ::Packages::CreateTemporaryPackageService.new( - user_project, current_user, declared_params.merge(build: current_authenticated_job) + project, current_user, declared_params.merge(build: current_authenticated_job) ).execute(:rubygems, name: ::Packages::Rubygems::TEMPORARY_PACKAGE_NAME) file_params = { @@ -159,7 +165,7 @@ module API bad_request!('Package creation failed') end rescue ObjectStorage::RemoteStoreError => e - Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: user_project.id }) + Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: project.id }) forbidden! end @@ -179,13 +185,13 @@ module API optional :gems, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma delimited gem names' end get 'dependencies' do - authorize_read_package! + authorize_read_package!(project) if params[:gems].blank? status :ok else results = params[:gems].map do |gem_name| - service_result = Packages::Rubygems::DependencyResolverService.new(user_project, current_user, gem_name: gem_name).execute + service_result = Packages::Rubygems::DependencyResolverService.new(project, current_user, gem_name: gem_name).execute render_api_error!(service_result.message, service_result.http_status) if service_result.error? service_result.payload diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d22abbb6603..6309e4f4075 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -34795,9 +34795,6 @@ msgstr "" msgid "Replaces the clone URL root." msgstr "" -msgid "Replication" -msgstr "" - msgid "Reply" msgstr "" diff --git a/qa/qa/fixtures/package_managers/nuget/nuget_install_package.yaml.erb b/qa/qa/fixtures/package_managers/nuget/nuget_install_package.yaml.erb index 39b65a55884..823525d648a 100644 --- a/qa/qa/fixtures/package_managers/nuget/nuget_install_package.yaml.erb +++ b/qa/qa/fixtures/package_managers/nuget/nuget_install_package.yaml.erb @@ -1,4 +1,4 @@ -image: mcr.microsoft.com/dotnet/sdk:5.0 +image: mcr.microsoft.com/dotnet/sdk:7.0 stages: - install diff --git a/qa/qa/fixtures/package_managers/nuget/nuget_upload_package.yaml.erb b/qa/qa/fixtures/package_managers/nuget/nuget_upload_package.yaml.erb index 7c88eb49be0..dc3311d3a1d 100644 --- a/qa/qa/fixtures/package_managers/nuget/nuget_upload_package.yaml.erb +++ b/qa/qa/fixtures/package_managers/nuget/nuget_upload_package.yaml.erb @@ -1,4 +1,4 @@ -image: mcr.microsoft.com/dotnet/sdk:5.0 +image: mcr.microsoft.com/dotnet/sdk:7.0 stages: - deploy diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb index d44bc8fa2ad..6466491a6e1 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb @@ -137,7 +137,7 @@ module QA <PropertyGroup> <OutputType>Exe</OutputType> - <TargetFramework>net5.0</TargetFramework> + <TargetFramework>net7.0</TargetFramework> </PropertyGroup> </Project> diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index d6067e22952..c9c79680c1c 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -18,6 +18,8 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do end shared_context 'pipeline builds' do + let!(:external_stage) { create(:ci_stage, name: 'external', pipeline: pipeline) } + let!(:build_passed) do create(:ci_build, :success, pipeline: pipeline, stage: 'build', stage_idx: 0, name: 'build') @@ -52,7 +54,7 @@ RSpec.describe 'Pipeline', :js, feature_category: :projects do create(:generic_commit_status, status: 'success', pipeline: pipeline, name: 'jenkins', - stage: 'external', + ci_stage: external_stage, ref: 'master', target_url: 'http://gitlab.com/status') end diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 3bdabd672c7..26ef0cd52f7 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -594,7 +594,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do end it 'changes the Pipeline ID column for Pipeline IID' do - page.find('[data-testid="pipeline-key-dropdown"]').click + page.find('[data-testid="pipeline-key-collapsible-box"]').click within '.gl-dropdown-contents' do dropdown_options = page.find_all '.gl-dropdown-item' @@ -618,6 +618,8 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do user: user) end + let(:external_stage) { create(:ci_stage, name: 'external', pipeline: pipeline) } + before do create_build('build', 0, 'build', :success) create_build('test', 1, 'rspec 0:2', :pending) @@ -627,7 +629,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :projects do create_build('test', 1, 'audit', :created) create_build('deploy', 2, 'production', :created) - create(:generic_commit_status, pipeline: pipeline, stage: 'external', name: 'jenkins', stage_idx: 3, ref: 'master') + create(:generic_commit_status, pipeline: pipeline, ci_stage: external_stage, name: 'jenkins', ref: 'master') visit project_pipeline_path(project, pipeline) wait_for_requests diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js index a3f15e25f36..351572fc83a 100644 --- a/spec/frontend/pipelines/pipelines_spec.js +++ b/spec/frontend/pipelines/pipelines_spec.js @@ -71,7 +71,7 @@ describe('Pipelines', () => { const findTablePagination = () => wrapper.findComponent(TablePagination); const findTab = (tab) => wrapper.findByTestId(`pipelines-tab-${tab}`); - const findPipelineKeyDropdown = () => wrapper.findByTestId('pipeline-key-dropdown'); + const findPipelineKeyCollapsibleBox = () => wrapper.findByTestId('pipeline-key-collapsible-box'); const findRunPipelineButton = () => wrapper.findByTestId('run-pipeline-button'); const findCiLintButton = () => wrapper.findByTestId('ci-lint-button'); const findCleanCacheButton = () => wrapper.findByTestId('clear-cache-button'); @@ -545,8 +545,8 @@ describe('Pipelines', () => { expect(findFilteredSearch().exists()).toBe(true); }); - it('renders the pipeline key dropdown', () => { - expect(findPipelineKeyDropdown().exists()).toBe(true); + it('renders the pipeline key collapsible box', () => { + expect(findPipelineKeyCollapsibleBox().exists()).toBe(true); }); it('renders tab empty state finished scope', async () => { @@ -578,7 +578,7 @@ describe('Pipelines', () => { }); it('does not render the pipeline key dropdown', () => { - expect(findPipelineKeyDropdown().exists()).toBe(false); + expect(findPipelineKeyCollapsibleBox().exists()).toBe(false); }); it('does not render tabs nor buttons', () => { diff --git a/spec/presenters/ci/stage_presenter_spec.rb b/spec/presenters/ci/stage_presenter_spec.rb index 368f03b0150..e7187b4ac16 100644 --- a/spec/presenters/ci/stage_presenter_spec.rb +++ b/spec/presenters/ci/stage_presenter_spec.rb @@ -10,7 +10,7 @@ RSpec.describe Ci::StagePresenter do let!(:retried_build) { create(:ci_build, :tags, :artifacts, :retried, pipeline: stage.pipeline, stage: stage.name) } before do - create(:generic_commit_status, pipeline: stage.pipeline, stage: stage.name) + create(:generic_commit_status, pipeline: stage.pipeline, ci_stage: stage) end shared_examples 'preloaded associations for CI status' do diff --git a/spec/requests/api/graphql/project/jobs_spec.rb b/spec/requests/api/graphql/project/jobs_spec.rb index d05d4a2f4b6..aea6cad9e62 100644 --- a/spec/requests/api/graphql/project/jobs_spec.rb +++ b/spec/requests/api/graphql/project/jobs_spec.rb @@ -33,10 +33,10 @@ RSpec.describe 'Query.project.jobs', feature_category: :continuous_integration d it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do build_stage = create(:ci_stage, position: 1, name: 'build', project: project, pipeline: pipeline) test_stage = create(:ci_stage, position: 2, name: 'test', project: project, pipeline: pipeline) - create(:ci_build, pipeline: pipeline, stage_idx: build_stage.position, name: 'docker 1 2', stage: build_stage) - create(:ci_build, pipeline: pipeline, stage_idx: build_stage.position, name: 'docker 2 2', stage: build_stage) - create(:ci_build, pipeline: pipeline, stage_idx: test_stage.position, name: 'rspec 1 2', stage: test_stage) - test_job = create(:ci_build, pipeline: pipeline, stage_idx: test_stage.position, name: 'rspec 2 2', stage: test_stage) + create(:ci_build, pipeline: pipeline, name: 'docker 1 2', ci_stage: build_stage) + create(:ci_build, pipeline: pipeline, name: 'docker 2 2', ci_stage: build_stage) + create(:ci_build, pipeline: pipeline, name: 'rspec 1 2', ci_stage: test_stage) + test_job = create(:ci_build, pipeline: pipeline, name: 'rspec 2 2', ci_stage: test_stage) create(:ci_build_need, build: test_job, name: 'docker 1 2') post_graphql(query, current_user: user) @@ -45,8 +45,8 @@ RSpec.describe 'Query.project.jobs', feature_category: :continuous_integration d post_graphql(query, current_user: user) end - create(:ci_build, name: 'test-a', stage: test_stage, stage_idx: test_stage.position, pipeline: pipeline) - test_b_job = create(:ci_build, name: 'test-b', stage: test_stage, stage_idx: test_stage.position, pipeline: pipeline) + create(:ci_build, name: 'test-a', ci_stage: test_stage, pipeline: pipeline) + test_b_job = create(:ci_build, name: 'test-b', ci_stage: test_stage, pipeline: pipeline) create(:ci_build_need, build: test_b_job, name: 'docker 2 2') expect do diff --git a/spec/requests/api/graphql/project/pipeline_spec.rb b/spec/requests/api/graphql/project/pipeline_spec.rb index 0eeb382510e..abfdf07c288 100644 --- a/spec/requests/api/graphql/project/pipeline_spec.rb +++ b/spec/requests/api/graphql/project/pipeline_spec.rb @@ -348,10 +348,10 @@ RSpec.describe 'getting pipeline information nested in a project', feature_categ it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do build_stage = create(:ci_stage, position: 1, name: 'build', project: project, pipeline: pipeline) test_stage = create(:ci_stage, position: 2, name: 'test', project: project, pipeline: pipeline) - create(:ci_build, pipeline: pipeline, stage_idx: build_stage.position, name: 'docker 1 2', stage: build_stage) - create(:ci_build, pipeline: pipeline, stage_idx: build_stage.position, name: 'docker 2 2', stage: build_stage) - create(:ci_build, pipeline: pipeline, stage_idx: test_stage.position, name: 'rspec 1 2', stage: test_stage) - test_job = create(:ci_build, pipeline: pipeline, stage_idx: test_stage.position, name: 'rspec 2 2', stage: test_stage) + create(:ci_build, pipeline: pipeline, name: 'docker 1 2', ci_stage: build_stage) + create(:ci_build, pipeline: pipeline, name: 'docker 2 2', ci_stage: build_stage) + create(:ci_build, pipeline: pipeline, name: 'rspec 1 2', ci_stage: test_stage) + test_job = create(:ci_build, pipeline: pipeline, name: 'rspec 2 2', ci_stage: test_stage) create(:ci_build_need, build: test_job, name: 'docker 1 2') post_graphql(query, current_user: current_user) @@ -360,8 +360,8 @@ RSpec.describe 'getting pipeline information nested in a project', feature_categ post_graphql(query, current_user: current_user) end - create(:ci_build, name: 'test-a', stage: test_stage, stage_idx: test_stage.position, pipeline: pipeline) - test_b_job = create(:ci_build, name: 'test-b', stage: test_stage, stage_idx: test_stage.position, pipeline: pipeline) + create(:ci_build, name: 'test-a', ci_stage: test_stage, pipeline: pipeline) + test_b_job = create(:ci_build, name: 'test-b', ci_stage: test_stage, pipeline: pipeline) create(:ci_build_need, build: test_b_job, name: 'docker 2 2') expect do @@ -409,7 +409,8 @@ RSpec.describe 'getting pipeline information nested in a project', feature_categ it 'does not generate N+1 queries', :request_store, :use_sql_query_cache do # create extra statuses - create(:generic_commit_status, :pending, name: 'generic-build-a', pipeline: pipeline, stage_idx: 0, stage: 'build') + external_stage = create(:ci_stage, position: 10, name: 'external', project: project, pipeline: pipeline) + create(:generic_commit_status, :pending, name: 'generic-build-a', pipeline: pipeline, ci_stage: external_stage) create(:ci_bridge, :failed, name: 'deploy-a', pipeline: pipeline, stage_idx: 2, stage: 'deploy') # warm up @@ -419,7 +420,7 @@ RSpec.describe 'getting pipeline information nested in a project', feature_categ post_graphql(query, current_user: current_user) end - create(:generic_commit_status, :pending, name: 'generic-build-b', pipeline: pipeline, stage_idx: 0, stage: 'build') + create(:generic_commit_status, :pending, name: 'generic-build-b', pipeline: pipeline, ci_stage: external_stage) create(:ci_build, :failed, name: 'test-a', pipeline: pipeline, stage_idx: 1, stage: 'test') create(:ci_build, :running, name: 'test-b', pipeline: pipeline, stage_idx: 1, stage: 'test') create(:ci_build, :pending, name: 'deploy-b', pipeline: pipeline, stage_idx: 2, stage: 'deploy') diff --git a/spec/requests/api/rubygem_packages_spec.rb b/spec/requests/api/rubygem_packages_spec.rb index 6f048fa57a8..34cf6033811 100644 --- a/spec/requests/api/rubygem_packages_spec.rb +++ b/spec/requests/api/rubygem_packages_spec.rb @@ -55,11 +55,11 @@ RSpec.describe API::RubygemPackages, feature_category: :package_registry do end where(:user_role, :token_type, :valid_token, :status) do - :guest | :personal_access_token | true | :not_found + :guest | :personal_access_token | true | :forbidden :guest | :personal_access_token | false | :unauthorized :guest | :deploy_token | true | :not_found :guest | :deploy_token | false | :unauthorized - :guest | :job_token | true | :not_found + :guest | :job_token | true | :forbidden :guest | :job_token | false | :unauthorized :reporter | :personal_access_token | true | :not_found :reporter | :personal_access_token | false | :unauthorized @@ -174,6 +174,17 @@ RSpec.describe API::RubygemPackages, feature_category: :package_registry do end end + context 'with access to package registry for everyone' do + let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_rubygems_user' } } + + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC) + end + + it_behaves_like 'Rubygems gem download', :anonymous, :success + end + context 'with package files pending destruction' do let_it_be(:package_file_pending_destruction) { create(:package_file, :pending_destruction, :xml, package: package, file_name: file_name) } @@ -423,5 +434,16 @@ RSpec.describe API::RubygemPackages, feature_category: :package_registry do it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member] end end + + context 'with access to package registry for everyone' do + let(:params) { {} } + + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC) + end + + it_behaves_like 'dependency endpoint success', :anonymous, :success + end end end diff --git a/spec/serializers/stage_entity_spec.rb b/spec/serializers/stage_entity_spec.rb index 95d3fd254d4..5cb5724ebdc 100644 --- a/spec/serializers/stage_entity_spec.rb +++ b/spec/serializers/stage_entity_spec.rb @@ -63,7 +63,7 @@ RSpec.describe StageEntity do context 'and contains commit status' do before do - create(:generic_commit_status, pipeline: pipeline, stage: 'test') + create(:generic_commit_status, pipeline: pipeline, ci_stage: stage) end it 'contains commit status' do |