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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop_todo/rspec/context_wording.yml3
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/ci/job_details/components/job_header.vue21
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue52
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue4
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue18
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue6
-rw-r--r--app/assets/javascripts/ci/job_details/job_app.vue4
-rw-r--r--app/assets/stylesheets/page_bundles/build.scss4
-rw-r--r--app/controllers/concerns/google_analytics_csp.rb20
-rw-r--r--app/controllers/concerns/onboarding/redirectable.rb31
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb34
-rw-r--r--app/controllers/registrations/welcome_controller.rb15
-rw-r--r--app/controllers/registrations_controller.rb15
-rw-r--r--app/models/namespace/detail.rb2
-rw-r--r--app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb24
-rw-r--r--app/services/packages/nuget/odata_package_entry_service.rb39
-rw-r--r--config/feature_flags/development/composer_use_ssh_source_urls.yml2
-rw-r--r--config/feature_flags/development/use_offset_pagination_for_canceling_redundant_pipelines.yml8
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md58
-rw-r--r--doc/administration/settings/project_integration_management.md97
-rw-r--r--doc/api/lint.md154
-rw-r--r--doc/api/packages/nuget.md31
-rw-r--r--doc/ci/runners/new_creation_workflow.md5
-rw-r--r--doc/integration/jira/configure.md5
-rw-r--r--doc/user/packages/composer_repository/index.md6
-rw-r--r--doc/user/packages/nuget_repository/index.md49
-rw-r--r--doc/user/project/integrations/index.md104
-rw-r--r--lib/api/nuget_project_packages.rb18
-rw-r--r--lib/gitlab/metrics/web_transaction.rb16
-rw-r--r--locale/gitlab.pot15
-rw-r--r--spec/controllers/omniauth_callbacks_controller_spec.rb36
-rw-r--r--spec/controllers/registrations/welcome_controller_spec.rb119
-rw-r--r--spec/controllers/registrations_controller_spec.rb39
-rw-r--r--spec/features/invites_spec.rb10
-rw-r--r--spec/features/projects/jobs/permissions_spec.rb2
-rw-r--r--spec/features/projects/jobs/user_browses_job_spec.rb2
-rw-r--r--spec/features/registrations/oauth_registration_spec.rb18
-rw-r--r--spec/features/users/google_analytics_csp_spec.rb20
-rw-r--r--spec/features/users/google_syndication_csp_spec.rb2
-rw-r--r--spec/features/users/signup_spec.rb13
-rw-r--r--spec/frontend/ci/job_details/components/job_header_spec.js12
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/sidebar_header_spec.js6
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js3
-rw-r--r--spec/lib/gitlab/metrics/web_transaction_spec.rb31
-rw-r--r--spec/requests/api/nuget_project_packages_spec.rb7
-rw-r--r--spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb224
-rw-r--r--spec/services/packages/nuget/odata_package_entry_service_spec.rb33
-rw-r--r--spec/support/helpers/content_security_policy_helpers.rb4
-rw-r--r--spec/support/shared_examples/controllers/concerns/onboarding/redirectable_shared_examples.rb35
-rw-r--r--spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb7
51 files changed, 571 insertions, 914 deletions
diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml
index 9f6b07c397e..fc7a105179e 100644
--- a/.rubocop_todo/rspec/context_wording.yml
+++ b/.rubocop_todo/rspec/context_wording.yml
@@ -14,7 +14,6 @@ RSpec/ContextWording:
- 'ee/spec/controllers/ee/groups_controller_spec.rb'
- 'ee/spec/controllers/ee/projects/jobs_controller_spec.rb'
- 'ee/spec/controllers/ee/projects/merge_requests/content_controller_spec.rb'
- - 'ee/spec/controllers/ee/registrations_controller_spec.rb'
- 'ee/spec/controllers/ee/root_controller_spec.rb'
- 'ee/spec/controllers/ee/search_controller_spec.rb'
- 'ee/spec/controllers/ee/sent_notifications_controller_spec.rb'
@@ -996,7 +995,6 @@ RSpec/ContextWording:
- 'spec/controllers/metrics_controller_spec.rb'
- 'spec/controllers/oauth/applications_controller_spec.rb'
- 'spec/controllers/oauth/authorizations_controller_spec.rb'
- - 'spec/controllers/omniauth_callbacks_controller_spec.rb'
- 'spec/controllers/passwords_controller_spec.rb'
- 'spec/controllers/profiles/emails_controller_spec.rb'
- 'spec/controllers/profiles/notifications_controller_spec.rb'
@@ -1053,7 +1051,6 @@ RSpec/ContextWording:
- 'spec/controllers/projects/tree_controller_spec.rb'
- 'spec/controllers/projects/web_ide_terminals_controller_spec.rb'
- 'spec/controllers/projects_controller_spec.rb'
- - 'spec/controllers/registrations_controller_spec.rb'
- 'spec/controllers/repositories/lfs_storage_controller_spec.rb'
- 'spec/controllers/root_controller_spec.rb'
- 'spec/controllers/search_controller_spec.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index f24ca0f4db6..b3ef7c98239 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0a7e89fde7ab1745eebf9c7fd2299047e293d9ef
+fe325f21798715da4097e04f234f78fc116978dc
diff --git a/app/assets/javascripts/ci/job_details/components/job_header.vue b/app/assets/javascripts/ci/job_details/components/job_header.vue
index 13f3eebd447..38bedb989c3 100644
--- a/app/assets/javascripts/ci/job_details/components/job_header.vue
+++ b/app/assets/javascripts/ci/job_details/components/job_header.vue
@@ -89,18 +89,25 @@ export default {
<template>
<header
- class="page-content-header gl-md-display-flex gl-min-h-7"
+ class="page-content-header gl-md-display-flex gl-flex-wrap gl-min-h-7 gl-pb-2! gl-w-full"
data-testid="job-header-content"
>
- <section class="header-main-content gl-mr-3">
- <ci-badge-link class="gl-mr-3" :status="status" />
+ <div
+ v-if="name"
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full"
+ >
+ <h1 class="gl-font-size-h-display gl-my-0 gl-display-inline-block" data-testid="job-name">
+ {{ name }}
+ </h1>
+ </div>
- <strong data-testid="job-name">{{ name }}</strong>
+ <section class="gl-md-display-flex gl-align-items-center gl-mr-3">
+ <ci-badge-link class="gl-mr-3" :status="status" />
- <template v-if="shouldRenderTriggeredLabel">{{ __('started') }}</template>
- <template v-else>{{ __('created') }}</template>
+ <template v-if="shouldRenderTriggeredLabel">{{ __('Started') }}</template>
+ <template v-else>{{ __('Created') }}</template>
- <timeago-tooltip :time="time" />
+ <timeago-tooltip :time="time" class="gl-mx-2" />
{{ __('by') }}
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue
index 0ff3ed93847..860c4c83009 100644
--- a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue
@@ -1,10 +1,12 @@
<script>
+import { GlButton } from '@gitlab/ui';
import { isEmpty } from 'lodash';
// eslint-disable-next-line no-restricted-imports
import { mapActions, mapGetters, mapState } from 'vuex';
import { forwardDeploymentFailureModalId } from '~/ci/constants';
import { filterAnnotations } from '~/ci/job_details/utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { __ } from '~/locale';
import ArtifactsBlock from './artifacts_block.vue';
import CommitBlock from './commit_block.vue';
import ExternalLinksBlock from './external_links_block.vue';
@@ -16,9 +18,13 @@ import StagesDropdown from './stages_dropdown.vue';
import TriggerBlock from './trigger_block.vue';
export default {
+ i18n: {
+ toggleSidebar: __('Toggle Sidebar'),
+ },
name: 'JobSidebar',
forwardDeploymentFailureModalId,
components: {
+ GlButton,
ArtifactsBlock,
CommitBlock,
JobsContainer,
@@ -64,6 +70,15 @@ export default {
externalLinks() {
return filterAnnotations(this.job.annotations, 'external_link');
},
+ jobHasPath() {
+ return Boolean(
+ this.job.erase_path ||
+ this.job.new_issue_path ||
+ this.job.terminal_path ||
+ this.job.retry_path ||
+ this.job.cancel_path,
+ );
+ },
},
watch: {
job(value, oldValue) {
@@ -76,43 +91,62 @@ export default {
},
},
methods: {
- ...mapActions(['fetchJobsForStage']),
+ ...mapActions(['fetchJobsForStage', 'toggleSidebar']),
},
};
</script>
<template>
<aside class="right-sidebar build-sidebar" data-offset-top="101" data-spy="affix">
<div class="sidebar-container">
- <div class="blocks-container gl-p-4">
+ <div class="blocks-container gl-p-4 gl-pt-0">
+ <div
+ class="gl-py-4 gl-border-b gl-border-gray-50 gl-display-flex gl-md-display-none! gl-justify-content-end"
+ >
+ <gl-button
+ :aria-label="$options.i18n.toggleSidebar"
+ category="tertiary"
+ icon="chevron-double-lg-right"
+ @click="toggleSidebar"
+ />
+ </div>
<sidebar-header
- class="block gl-pb-4! gl-mb-2"
+ v-if="jobHasPath"
+ class="gl-py-4 gl-border-b gl-border-gray-50"
:rest-job="job"
:job-id="job.id"
@updateVariables="$emit('updateVariables')"
/>
- <job-sidebar-details-container class="block gl-mb-2" />
+ <job-sidebar-details-container class="gl-py-4 gl-border-b gl-border-gray-50" />
<artifacts-block
v-if="hasArtifact"
- class="block gl-mb-2"
+ class="gl-py-4 gl-border-b gl-border-gray-50"
:artifact="artifact"
:help-url="artifactHelpUrl"
/>
<external-links-block
v-if="hasExternalLinks"
- class="block gl-mb-2"
+ class="gl-py-4 gl-border-b gl-border-gray-50"
:external-links="externalLinks"
/>
- <trigger-block v-if="hasTriggers" class="block gl-mb-2" :trigger="job.trigger" />
+ <trigger-block
+ v-if="hasTriggers"
+ class="gl-py-4 gl-border-b gl-border-gray-50"
+ :trigger="job.trigger"
+ />
- <commit-block class="block gl-mb-2" :commit="commit" :merge-request="job.merge_request" />
+ <commit-block
+ class="gl-py-4 gl-border-b gl-border-gray-50"
+ :commit="commit"
+ :merge-request="job.merge_request"
+ />
<stages-dropdown
v-if="job.pipeline"
- class="block gl-mb-2"
+ class="gl-py-4 gl-border-b gl-border-gray-50"
:pipeline="job.pipeline"
:selected-stage="selectedStage"
:stages="stages"
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue
index 5b1bf354fd4..d7726b952de 100644
--- a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue
@@ -39,8 +39,8 @@ export default {
};
</script>
<template>
- <p class="build-sidebar-item gl-mb-2">
- <b v-if="hasTitle" class="gl-display-flex">{{ title }}:</b>
+ <p class="build-sidebar-item gl-line-height-normal gl-display-flex gl-mb-3">
+ <b v-if="hasTitle" class="gl-mr-3">{{ title }}:</b>
<gl-link
v-if="path"
:href="path"
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue
index 77e3ecb9b3c..2713b37e30e 100644
--- a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue
@@ -1,12 +1,9 @@
<script>
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
-// eslint-disable-next-line no-restricted-imports
-import { mapActions } from 'vuex';
import { createAlert } from '~/alert';
import { TYPENAME_COMMIT_STATUS } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { __, s__ } from '~/locale';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import { JOB_GRAPHQL_ERRORS, forwardDeploymentFailureModalId, PASSED_STATUS } from '~/ci/constants';
import GetJob from '../../graphql/queries/get_job.query.graphql';
import JobSidebarRetryButton from './job_sidebar_retry_button.vue';
@@ -20,7 +17,6 @@ export default {
eraseLogConfirmText: s__('Job|Are you sure you want to erase this job log and artifacts?'),
newIssue: __('New issue'),
retryJobLabel: s__('Job|Retry'),
- toggleSidebar: __('Toggle Sidebar'),
runAgainJobButtonLabel: s__('Job|Run again'),
},
forwardDeploymentFailureModalId,
@@ -30,7 +26,6 @@ export default {
components: {
GlButton,
JobSidebarRetryButton,
- TooltipOnTruncate,
},
inject: ['projectPath'],
apollo: {
@@ -86,17 +81,11 @@ export default {
return this.restJob.status && this.restJob.recoverable ? 'primary' : 'secondary';
},
},
- methods: {
- ...mapActions(['toggleSidebar']),
- },
};
</script>
<template>
<div>
- <tooltip-on-truncate :title="job.name" truncate-target="child"
- ><h4 class="gl-mt-0 gl-mb-3 gl-text-truncate" data-testid="job-name">{{ job.name }}</h4>
- </tooltip-on-truncate>
<div class="gl-display-flex gl-gap-3">
<gl-button
v-if="restJob.erase_path"
@@ -156,13 +145,6 @@ export default {
data-testid="cancel-button"
rel="nofollow"
/>
- <gl-button
- :aria-label="$options.i18n.toggleSidebar"
- category="secondary"
- class="gl-md-display-none gl-ml-2"
- icon="chevron-double-lg-right"
- @click="toggleSidebar"
- />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue
index ebef3ecaa3f..f04987a87b5 100644
--- a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue
@@ -44,14 +44,10 @@ export default {
this.job.finished_at ||
this.job.erased_at ||
this.job.queued_duration ||
- this.job.id ||
this.job.runner ||
this.job.coverage,
);
},
- jobId() {
- return this.job?.id ? `#${this.job.id}` : '';
- },
runnerId() {
const { id, short_sha: token, description } = this.job.runner;
@@ -87,7 +83,6 @@ export default {
RUNNER: __('Runner'),
TAGS: __('Tags'),
TIMEOUT: __('Timeout'),
- ID: __('Job ID'),
},
TIMEOUT_HELP_URL: helpPagePath('/ci/pipelines/settings.md', {
anchor: 'set-a-limit-for-how-long-jobs-can-run',
@@ -113,7 +108,6 @@ export default {
data-testid="job-timeout"
:title="$options.i18n.TIMEOUT"
/>
- <detail-row v-if="job.id" :value="jobId" :title="$options.i18n.ID" />
<detail-row
v-if="job.runner"
:value="runnerId"
diff --git a/app/assets/javascripts/ci/job_details/job_app.vue b/app/assets/javascripts/ci/job_details/job_app.vue
index 5137ebfeaa8..85a12a1dca9 100644
--- a/app/assets/javascripts/ci/job_details/job_app.vue
+++ b/app/assets/javascripts/ci/job_details/job_app.vue
@@ -130,7 +130,7 @@ export default {
},
jobName() {
- return sprintf(__('Job %{jobName}'), { jobName: this.job.name });
+ return sprintf(__('%{jobName}'), { jobName: this.job.name });
},
},
watch: {
@@ -224,7 +224,7 @@ export default {
<div class="build-page" data-testid="job-content">
<!-- Header Section -->
<header>
- <div class="build-header top-area">
+ <div class="build-header gl-display-flex">
<job-header
:status="job.status"
:time="headerTime"
diff --git a/app/assets/stylesheets/page_bundles/build.scss b/app/assets/stylesheets/page_bundles/build.scss
index 09c4d184f3f..a06a1513f7d 100644
--- a/app/assets/stylesheets/page_bundles/build.scss
+++ b/app/assets/stylesheets/page_bundles/build.scss
@@ -155,10 +155,6 @@
}
.build-sidebar-item {
- display: grid;
- grid-template-columns: 1fr 2fr;
- grid-gap: $gl-padding-8;
-
&:last-of-type {
@include gl-mb-0;
}
diff --git a/app/controllers/concerns/google_analytics_csp.rb b/app/controllers/concerns/google_analytics_csp.rb
index 1a8e405928d..4fffe298803 100644
--- a/app/controllers/concerns/google_analytics_csp.rb
+++ b/app/controllers/concerns/google_analytics_csp.rb
@@ -7,17 +7,33 @@ module GoogleAnalyticsCSP
content_security_policy do |policy|
next unless helpers.google_tag_manager_enabled? || policy.directives.present?
+ # Tag Manager with a Content Security Policy for Google Analytics 4
+ # https://developers.google.com/tag-platform/security/guides/csp#google_analytics_4_google_analytics
+
default_script_src = policy.directives['script-src'] || policy.directives['default-src']
script_src_values = Array.wrap(default_script_src) | ['*.googletagmanager.com']
policy.script_src(*script_src_values)
default_img_src = policy.directives['img-src'] || policy.directives['default-src']
- img_src_values = Array.wrap(default_img_src) | ['*.google-analytics.com', '*.googletagmanager.com']
+ img_src_values =
+ Array.wrap(default_img_src) |
+ [
+ '*.google-analytics.com',
+ '*.analytics.google.com',
+ '*.googletagmanager.com',
+ '*.g.doubleclick.net'
+ ]
policy.img_src(*img_src_values)
default_connect_src = policy.directives['connect-src'] || policy.directives['default-src']
connect_src_values =
- Array.wrap(default_connect_src) | ['*.google-analytics.com', '*.analytics.google.com', '*.googletagmanager.com']
+ Array.wrap(default_connect_src) |
+ [
+ '*.google-analytics.com',
+ '*.analytics.google.com',
+ '*.googletagmanager.com',
+ '*.g.doubleclick.net'
+ ]
policy.connect_src(*connect_src_values)
end
end
diff --git a/app/controllers/concerns/onboarding/redirectable.rb b/app/controllers/concerns/onboarding/redirectable.rb
new file mode 100644
index 00000000000..7e669db9199
--- /dev/null
+++ b/app/controllers/concerns/onboarding/redirectable.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Onboarding
+ module Redirectable
+ extend ActiveSupport::Concern
+
+ private
+
+ def after_sign_up_path
+ if onboarding_status.single_invite?
+ flash[:notice] = helpers.invite_accepted_notice(onboarding_status.last_invited_member)
+ onboarding_status.last_invited_member_source.activity_path
+ else
+ # Invites will come here if there is more than 1.
+ path_for_signed_in_user
+ end
+ end
+
+ def path_for_signed_in_user
+ stored_location_for(:user) || last_member_activity_path
+ end
+
+ def last_member_activity_path
+ return dashboard_projects_path unless onboarding_status.last_invited_member_source.present?
+
+ onboarding_status.last_invited_member_source.activity_path
+ end
+ end
+end
+
+Onboarding::Redirectable.prepend_mod
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 72b3516ae3f..a97516fddff 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -7,6 +7,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
include InitializesCurrentUserMode
include KnownSignIn
include AcceptsPendingInvitations
+ include Onboarding::Redirectable
after_action :verify_known_sign_in
@@ -169,38 +170,38 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def sign_in_user_flow(auth_user_class)
auth_user = build_auth_user(auth_user_class)
new_user = auth_user.new?
- user = auth_user.find_and_update!
+ @user = auth_user.find_and_update!
if auth_user.valid_sign_in?
# In this case the `#current_user` would not be set. So we can't fetch it
# from that in `#context_user`. Pushing it manually here makes the information
# available in the logs for this request.
- Gitlab::ApplicationContext.push(user: user)
- track_event(user, oauth['provider'], 'succeeded')
- Gitlab::Tracking.event(self.class.name, "#{oauth['provider']}_sso", user: user) if new_user
+ Gitlab::ApplicationContext.push(user: @user)
+ track_event(@user, oauth['provider'], 'succeeded')
+ Gitlab::Tracking.event(self.class.name, "#{oauth['provider']}_sso", user: @user) if new_user
- set_remember_me(user)
+ set_remember_me(@user)
- if user.two_factor_enabled? && !auth_user.bypass_two_factor?
- prompt_for_two_factor(user)
+ if @user.two_factor_enabled? && !auth_user.bypass_two_factor?
+ prompt_for_two_factor(@user)
store_idp_two_factor_status(false)
else
- if user.deactivated?
- user.activate
+ if @user.deactivated?
+ @user.activate
flash[:notice] = _('Welcome back! Your account had been deactivated due to inactivity but is now reactivated.')
end
# session variable for storing bypass two-factor request from IDP
store_idp_two_factor_status(true)
- accept_pending_invitations(user: user) if new_user
- persist_accepted_terms_if_required(user) if new_user
+ accept_pending_invitations(user: @user) if new_user
+ persist_accepted_terms_if_required(@user) if new_user
- perform_registration_tasks(user, oauth['provider']) if new_user
- sign_in_and_redirect_or_verify_identity(user, auth_user, new_user)
+ perform_registration_tasks(@user, oauth['provider']) if new_user
+ sign_in_and_redirect_or_verify_identity(@user, auth_user, new_user)
end
else
- fail_login(user)
+ fail_login(@user)
end
rescue Gitlab::Auth::OAuth::User::SigninDisabledForProviderError
handle_disabled_provider
@@ -323,9 +324,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
store_location_for(:user, after_sign_up_path)
end
- def after_sign_up_path
- users_sign_up_welcome_path
+ def onboarding_status
+ Onboarding::Status.new(params.to_unsafe_h.deep_symbolize_keys, session, @user)
end
+ strong_memoize_attr :onboarding_status
# overridden in EE
def sign_in_and_redirect_or_verify_identity(user, _, _)
diff --git a/app/controllers/registrations/welcome_controller.rb b/app/controllers/registrations/welcome_controller.rb
index f7a601ec0bd..bdbb7b00c40 100644
--- a/app/controllers/registrations/welcome_controller.rb
+++ b/app/controllers/registrations/welcome_controller.rb
@@ -6,6 +6,7 @@ module Registrations
include GoogleAnalyticsCSP
include GoogleSyndicationCSP
include ::Gitlab::Utils::StrongMemoize
+ include Onboarding::Redirectable
layout 'minimal'
# TODO: Once this is an ee + SaaS only feature, we can remove this.
@@ -18,7 +19,7 @@ module Registrations
feature_category :user_management
def show
- return redirect_to path_for_signed_in_user(current_user) if completed_welcome_step?
+ return redirect_to path_for_signed_in_user if completed_welcome_step?
track_event('render')
end
@@ -52,16 +53,6 @@ module Registrations
params.require(:user).permit(:role, :setup_for_company)
end
- def path_for_signed_in_user(user)
- stored_location_for(user) || last_member_activity_path
- end
-
- def last_member_activity_path
- return dashboard_projects_path unless onboarding_status.last_invited_member_source.present?
-
- onboarding_status.last_invited_member_source.activity_path
- end
-
def update_success_path
if onboarding_status.continue_full_onboarding? # trials/regular registration on .com
signup_onboarding_path
@@ -71,7 +62,7 @@ module Registrations
else
# Subscription registrations goes through here as well.
# Invites will come here too if there is more than 1.
- path_for_signed_in_user(current_user)
+ path_for_signed_in_user
end
end
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index a8b5ca81f49..abc00d7c19b 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -14,6 +14,7 @@ class RegistrationsController < Devise::RegistrationsController
include SkipsAlreadySignedInMessage
include Gitlab::RackLoadBalancingHelpers
include ::Gitlab::Utils::StrongMemoize
+ include Onboarding::Redirectable
layout 'devise'
@@ -60,7 +61,7 @@ class RegistrationsController < Devise::RegistrationsController
# Devise sets a flash message on both successful & failed signups,
# but we only want to show a message if the resource is blocked by a pending approval.
- flash[:notice] = nil unless resource.blocked_pending_approval?
+ flash[:notice] = nil unless allow_flash_content?(resource)
rescue Gitlab::Access::AccessDeniedError
redirect_to(new_user_session_path)
end
@@ -121,6 +122,9 @@ class RegistrationsController < Devise::RegistrationsController
def after_sign_up_path_for(user)
Gitlab::AppLogger.info(user_created_message(confirmed: user.confirmed?))
+ # Member#accept_invite! operates on the member record to change the association, so the user needs reloaded
+ # to update the collection.
+ user.reset
after_sign_up_path
end
@@ -146,8 +150,13 @@ class RegistrationsController < Devise::RegistrationsController
private
- def after_sign_up_path
- users_sign_up_welcome_path
+ def onboarding_status
+ Onboarding::Status.new(params.to_unsafe_h.deep_symbolize_keys, session, resource)
+ end
+ strong_memoize_attr :onboarding_status
+
+ def allow_flash_content?(user)
+ user.blocked_pending_approval? || onboarding_status.single_invite?
end
# overridden in EE
diff --git a/app/models/namespace/detail.rb b/app/models/namespace/detail.rb
index a65027733e9..36027d47591 100644
--- a/app/models/namespace/detail.rb
+++ b/app/models/namespace/detail.rb
@@ -5,8 +5,6 @@ class Namespace::Detail < ApplicationRecord
ignore_column :dashboard_notification_at, remove_with: '16.5', remove_after: '2023-08-22'
ignore_column :dashboard_enforcement_at, remove_with: '16.5', remove_after: '2023-08-22'
- ignore_column :next_over_limit_check_at, remove_with: '16.5', remove_after: '2023-08-22'
- ignore_column :free_user_cap_over_limit_notified_at, remove_with: '16.5', remove_after: '2023-08-22'
belongs_to :namespace, inverse_of: :namespace_details
validates :namespace, presence: true
diff --git a/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb b/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb
index 05cd20a152b..c18984953a1 100644
--- a/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb
+++ b/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb
@@ -19,20 +19,11 @@ module Ci
return if pipeline.parent_pipeline? # skip if child pipeline
return unless project.auto_cancel_pending_pipelines?
- if Feature.enabled?(:use_offset_pagination_for_canceling_redundant_pipelines, project)
- paginator.each do |ids|
- pipelines = parent_and_child_pipelines(ids)
+ paginator.each do |ids|
+ pipelines = parent_and_child_pipelines(ids)
- Gitlab::OptimisticLocking.retry_lock(pipelines, name: 'cancel_pending_pipelines') do |cancelables|
- auto_cancel_interruptible_pipelines(cancelables.ids)
- end
- end
- else
- Gitlab::OptimisticLocking
- .retry_lock(parent_and_child_pipelines, name: 'cancel_pending_pipelines') do |cancelables|
- cancelables.select(:id).each_batch(of: BATCH_SIZE) do |cancelables_batch|
- auto_cancel_interruptible_pipelines(cancelables_batch.ids)
- end
+ Gitlab::OptimisticLocking.retry_lock(pipelines, name: 'cancel_pending_pipelines') do |cancelables|
+ auto_cancel_interruptible_pipelines(cancelables.ids)
end
end
end
@@ -61,7 +52,7 @@ module Ci
end
end
- def parent_auto_cancelable_pipelines(ids = nil)
+ def parent_auto_cancelable_pipelines(ids)
scope = project.all_pipelines
.created_after(pipelines_created_after)
.for_ref(pipeline.ref)
@@ -70,11 +61,10 @@ module Ci
.for_status(CommitStatus::AVAILABLE_STATUSES) # Force usage of project_id_and_status_and_created_at_index
.ci_sources
- scope = scope.id_in(ids) if ids.present?
- scope
+ scope.id_in(ids)
end
- def parent_and_child_pipelines(ids = nil)
+ def parent_and_child_pipelines(ids)
Ci::Pipeline.object_hierarchy(parent_auto_cancelable_pipelines(ids), project_condition: :same)
.base_and_descendants
.alive_or_scheduled
diff --git a/app/services/packages/nuget/odata_package_entry_service.rb b/app/services/packages/nuget/odata_package_entry_service.rb
index 0cdcc38de16..679b01d6c48 100644
--- a/app/services/packages/nuget/odata_package_entry_service.rb
+++ b/app/services/packages/nuget/odata_package_entry_service.rb
@@ -5,9 +5,6 @@ module Packages
class OdataPackageEntryService
include API::Helpers::RelatedResourcesHelpers
- SEMVER_LATEST_VERSION_PLACEHOLDER = '0.0.0-latest-version'
- LATEST_VERSION_FOR_V2_DOWNLOAD_ENDPOINT = 'latest'
-
def initialize(project, params)
@project = project
@params = params
@@ -29,42 +26,40 @@ module Packages
<title type='text'>#{params[:package_name]}</title>
<content type='application/zip' src="#{download_url}"/>
<m:properties>
- <d:Version>#{package_version}</d:Version>
+ <d:Version>#{params[:package_version]}</d:Version>
</m:properties>
</entry>
XML
end
- def package_version
- params[:package_version] || SEMVER_LATEST_VERSION_PLACEHOLDER
- end
-
def id_url
expose_url "#{api_v4_projects_packages_nuget_v2_path(id: project.id)}" \
- "/Packages(Id='#{params[:package_name]}',Version='#{package_version}')"
+ "/Packages(Id='#{params[:package_name]}',Version='#{params[:package_version]}')"
end
- # TODO: use path helper when download endpoint is merged
def download_url
- expose_url "#{api_v4_projects_packages_nuget_v2_path(id: project.id)}" \
- "/download/#{params[:package_name]}/#{download_url_package_version}"
- end
-
- def download_url_package_version
- if latest_version?
- LATEST_VERSION_FOR_V2_DOWNLOAD_ENDPOINT
+ if params[:package_version].present?
+ expose_url api_v4_projects_packages_nuget_download_package_name_package_version_package_filename_path(
+ {
+ id: project.id,
+ package_name: params[:package_name],
+ package_version: params[:package_version],
+ package_filename: file_name
+ },
+ true
+ )
else
- params[:package_version]
+ xml_base
end
end
- def latest_version?
- params[:package_version].nil? || params[:package_version] == SEMVER_LATEST_VERSION_PLACEHOLDER
- end
-
def xml_base
expose_url api_v4_projects_packages_nuget_v2_path(id: project.id)
end
+
+ def file_name
+ "#{params[:package_name]}.#{params[:package_version]}.nupkg"
+ end
end
end
end
diff --git a/config/feature_flags/development/composer_use_ssh_source_urls.yml b/config/feature_flags/development/composer_use_ssh_source_urls.yml
index 26111623ea3..d74dcdf9806 100644
--- a/config/feature_flags/development/composer_use_ssh_source_urls.yml
+++ b/config/feature_flags/development/composer_use_ssh_source_urls.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422171
milestone: '16.4'
type: development
group: group::package registry
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/use_offset_pagination_for_canceling_redundant_pipelines.yml b/config/feature_flags/development/use_offset_pagination_for_canceling_redundant_pipelines.yml
deleted file mode 100644
index 72475948793..00000000000
--- a/config/feature_flags/development/use_offset_pagination_for_canceling_redundant_pipelines.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: use_offset_pagination_for_canceling_redundant_pipelines
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122764
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414459
-milestone: '16.1'
-type: development
-group: group::optimize
-default_enabled: true
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index d91fd5f8156..b921195922e 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -37,10 +37,10 @@ The following metrics are available:
| Metric | Type | Since | Description | Labels |
| :--------------------------------------------------------------- | :---------- | ------: | :-------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------- |
-| `gitlab_cache_misses_total` | Counter | 10.2 | Cache read miss | `controller`, `action`, `store` |
-| `gitlab_cache_operation_duration_seconds` | Histogram | 10.2 | Cache access time | `operation`, `store` |
-| `gitlab_cache_operations_total` | Counter | 12.2 | Cache operations by controller or action | `controller`, `action`, `operation`, `store` |
-| `gitlab_cache_read_multikey_count` | Histogram | 15.7 | Count of keys in multi-key cache read operations | `controller`, `action`, `store` |
+| `gitlab_cache_misses_total` | Counter | 10.2 | Cache read miss | `controller`, `action`, `store`, `endpoint_id` |
+| `gitlab_cache_operation_duration_seconds` | Histogram | 10.2 | Cache access time | `operation`, `store`, `endpoint_id` |
+| `gitlab_cache_operations_total` | Counter | 12.2 | Cache operations by controller or action | `controller`, `action`, `operation`, `store`, `endpoint_id` |
+| `gitlab_cache_read_multikey_count` | Histogram | 15.7 | Count of keys in multi-key cache read operations | `controller`, `action`, `store`, `endpoint_id` |
| `gitlab_ci_pipeline_builder_scoped_variables_duration` | Histogram | 14.5 | Time in seconds it takes to create the scoped variables for a CI/CD job
| `gitlab_ci_pipeline_creation_duration_seconds` | Histogram | 13.0 | Time in seconds it takes to create a CI/CD pipeline | `gitlab` |
| `gitlab_ci_pipeline_size_builds` | Histogram | 13.1 | Total number of builds within a pipeline grouped by a pipeline source | `source` |
@@ -65,9 +65,9 @@ The following metrics are available:
| `gitlab_transaction_cache_<key>_duration_total` | Counter | 10.2 | Counter for total time (seconds) spent in Rails cache calls (per key) | |
| `gitlab_transaction_cache_count_total` | Counter | 10.2 | Counter for total Rails cache calls (aggregate) | |
| `gitlab_transaction_cache_duration_total` | Counter | 10.2 | Counter for total time (seconds) spent in Rails cache calls (aggregate) | |
-| `gitlab_transaction_cache_read_hit_count_total` | Counter | 10.2 | Counter for cache hits for Rails cache calls | `controller`, `action`, `store` |
-| `gitlab_transaction_cache_read_miss_count_total` | Counter | 10.2 | Counter for cache misses for Rails cache calls | `controller`, `action`, `store` |
-| `gitlab_transaction_duration_seconds` | Histogram | 10.2 | Duration for successful requests (`gitlab_transaction_*` metrics) | `controller`, `action` |
+| `gitlab_transaction_cache_read_hit_count_total` | Counter | 10.2 | Counter for cache hits for Rails cache calls | `controller`, `action`, `store`, `endpoint_id` |
+| `gitlab_transaction_cache_read_miss_count_total` | Counter | 10.2 | Counter for cache misses for Rails cache calls | `controller`, `action`, `store`, `endpoint_id` |
+| `gitlab_transaction_duration_seconds` | Histogram | 10.2 | Duration for successful requests (`gitlab_transaction_*` metrics) | `controller`, `action`, `endpoint_id` |
| `gitlab_transaction_event_build_found_total` | Counter | 9.4 | Counter for build found for API /jobs/request | |
| `gitlab_transaction_event_build_invalid_total` | Counter | 9.4 | Counter for build invalid due to concurrency conflict for API /jobs/request | |
| `gitlab_transaction_event_build_not_found_cached_total` | Counter | 9.4 | Counter for cached response of build not found for API /jobs/request | |
@@ -95,20 +95,20 @@ The following metrics are available:
| `gitlab_transaction_event_stuck_import_jobs_total` | Counter | 9.4 | Count of stuck import jobs | `projects_without_jid_count`, `projects_with_jid_count` |
| `gitlab_transaction_event_update_build_total` | Counter | 9.4 | Counter for update build for API `/jobs/request/:id` | |
| `gitlab_transaction_new_redis_connections_total` | Counter | 9.4 | Counter for new Redis connections | |
-| `gitlab_transaction_rails_queue_duration_total` | Counter | 9.4 | Measures latency between GitLab Workhorse forwarding a request to Rails | `controller`, `action` |
-| `gitlab_transaction_view_duration_total` | Counter | 9.4 | Duration for views | `controller`, `action`, `view` |
-| `gitlab_view_rendering_duration_seconds` | Histogram | 10.2 | Duration for views (histogram) | `controller`, `action`, `view` |
+| `gitlab_transaction_rails_queue_duration_total` | Counter | 9.4 | Measures latency between GitLab Workhorse forwarding a request to Rails | `controller`, `action`, `endpoint_id` |
+| `gitlab_transaction_view_duration_total` | Counter | 9.4 | Duration for views | `controller`, `action`, `view`, `endpoint_id` |
+| `gitlab_view_rendering_duration_seconds` | Histogram | 10.2 | Duration for views (histogram) | `controller`, `action`, `view`, `endpoint_id` |
| `http_requests_total` | Counter | 9.4 | Rack request count | `method`, `status` |
| `http_request_duration_seconds` | Histogram | 9.4 | HTTP response time from rack middleware for successful requests | `method` |
-| `gitlab_transaction_db_count_total` | Counter | 13.1 | Counter for total number of SQL calls | `controller`, `action` |
-| `gitlab_transaction_db_<role>_count_total` | Counter | 13.10 | Counter for total number of SQL calls, grouped by database roles (primary/replica) | `controller`, `action` |
-| `gitlab_transaction_db_write_count_total` | Counter | 13.1 | Counter for total number of write SQL calls | `controller`, `action` |
-| `gitlab_transaction_db_cached_count_total` | Counter | 13.1 | Counter for total number of cached SQL calls | `controller`, `action` |
-| `gitlab_transaction_db_<role>_cached_count_total` | Counter | 13.1 | Counter for total number of cached SQL calls, grouped by database roles (primary/replica) | `controller`, `action` |
-| `gitlab_transaction_db_<role>_wal_count_total` | Counter | 14.0 | Counter for total number of WAL (write ahead log location) queries, grouped by database roles (primary/replica) | `controller`, `action` |
-| `gitlab_transaction_db_<role>_wal_cached_count_total` | Counter | 14.1 | Counter for total number of cached WAL (write ahead log location) queries, grouped by database roles (primary/replica)| `controller`, `action` |
-| `http_elasticsearch_requests_duration_seconds` **(PREMIUM ALL)** | Histogram | 13.1 | Elasticsearch requests duration during web transactions | `controller`, `action` |
-| `http_elasticsearch_requests_total` **(PREMIUM ALL)** | Counter | 13.1 | Elasticsearch requests count during web transactions | `controller`, `action` |
+| `gitlab_transaction_db_count_total` | Counter | 13.1 | Counter for total number of SQL calls | `controller`, `action`, `endpoint_id` |
+| `gitlab_transaction_db_<role>_count_total` | Counter | 13.10 | Counter for total number of SQL calls, grouped by database roles (primary/replica) | `controller`, `action`, `endpoint_id` |
+| `gitlab_transaction_db_write_count_total` | Counter | 13.1 | Counter for total number of write SQL calls | `controller`, `action`, `endpoint_id` |
+| `gitlab_transaction_db_cached_count_total` | Counter | 13.1 | Counter for total number of cached SQL calls | `controller`, `action`, `endpoint_id` |
+| `gitlab_transaction_db_<role>_cached_count_total` | Counter | 13.1 | Counter for total number of cached SQL calls, grouped by database roles (primary/replica) | `controller`, `action`, `endpoint_id` |
+| `gitlab_transaction_db_<role>_wal_count_total` | Counter | 14.0 | Counter for total number of WAL (write ahead log location) queries, grouped by database roles (primary/replica) | `controller`, `action`, `endpoint_id` |
+| `gitlab_transaction_db_<role>_wal_cached_count_total` | Counter | 14.1 | Counter for total number of cached WAL (write ahead log location) queries, grouped by database roles (primary/replica)| `controller`, `action`, `endpoint_id` |
+| `http_elasticsearch_requests_duration_seconds` **(PREMIUM ALL)** | Histogram | 13.1 | Elasticsearch requests duration during web transactions | `controller`, `action`, `endpoint_id` |
+| `http_elasticsearch_requests_total` **(PREMIUM ALL)** | Counter | 13.1 | Elasticsearch requests count during web transactions | `controller`, `action`, `endpoint_id` |
| `pipelines_created_total` | Counter | 9.4 | Counter of pipelines created | |
| `rack_uncaught_errors_total` | Counter | 9.4 | Rack connections handling uncaught errors count | |
| `user_session_logins_total` | Counter | 9.4 | Counter of how many users have logged in since GitLab was started or restarted | |
@@ -137,7 +137,7 @@ The following metrics are available:
| `gitlab_ci_trace_finalize_duration_seconds` | Histogram | 13.6 | Duration of build trace chunks migration to object storage | |
| `gitlab_vulnerability_report_branch_comparison_real_duration_seconds` | Histogram | 15.11 | Execution duration of vulnerability report present on default branch sql query | |
| `gitlab_vulnerability_report_branch_comparison_cpu_duration_seconds` | Histogram | 15.11 | Execution duration of vulnerability report present on default branch sql query | |
-| `gitlab_external_http_total` | Counter | 13.8 | Total number of HTTP calls to external systems | `controller`, `action` |
+| `gitlab_external_http_total` | Counter | 13.8 | Total number of HTTP calls to external systems | `controller`, `action`, `endpoint_id` |
| `gitlab_external_http_duration_seconds` | Counter | 13.8 | Duration in seconds spent on each HTTP call to external systems | |
| `gitlab_external_http_exception_total` | Counter | 13.8 | Total number of exceptions raised when making external HTTP calls | |
| `ci_report_parser_duration_seconds` | Histogram | 13.9 | Time to parse CI/CD report artifacts | `parser` |
@@ -153,18 +153,18 @@ The following metrics are available:
| `gitlab_snowplow_failed_events_total` | Counter | 14.1 | Total number of GitLab Snowplow Analytics Instrumentation events emission failures | |
| `gitlab_snowplow_successful_events_total` | Counter | 14.1 | Total number of GitLab Snowplow Analytics Instrumentation events emission successes | |
| `gitlab_ci_build_trace_errors_total` | Counter | 14.4 | Total amount of different error types on a build trace | `error_reason` |
-| `gitlab_presentable_object_cacheless_render_real_duration_seconds` | Histogram | 15.3 | Duration of real time spent caching and representing specific web request objects | `controller`, `action` |
-| `cached_object_operations_total` | Counter | 15.3 | Total number of objects cached for specific web requests | `controller`, `action` |
+| `gitlab_presentable_object_cacheless_render_real_duration_seconds` | Histogram | 15.3 | Duration of real time spent caching and representing specific web request objects | `controller`, `action`, `endpoint_id` |
+| `cached_object_operations_total` | Counter | 15.3 | Total number of objects cached for specific web requests | `controller`, `action`, `endpoint_id` |
| `redis_hit_miss_operations_total` | Counter | 15.6 | Total number of Redis cache hits and misses | `cache_hit`, `cache_identifier`, `feature_category`, `backing_resource` |
| `redis_cache_generation_duration_seconds` | Histogram | 15.6 | Time to generate Redis cache | `cache_hit`, `cache_identifier`, `feature_category`, `backing_resource` |
-| `gitlab_diffs_reorder_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spend on reordering of diff files on diffs batch request | `controller`, `action` |
-| `gitlab_diffs_collection_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on querying merge request diff files on diffs batch request | `controller`, `action` |
-| `gitlab_diffs_comparison_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on getting comparison data on diffs batch request | `controller`, `action` |
+| `gitlab_diffs_reorder_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spend on reordering of diff files on diffs batch request | `controller`, `action`, `endpoint_id` |
+| `gitlab_diffs_collection_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on querying merge request diff files on diffs batch request | `controller`, `action`, `endpoint_id` |
+| `gitlab_diffs_comparison_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on getting comparison data on diffs batch request | `controller`, `action`, `endpoint_id` |
| `gitlab_diffs_unfoldable_positions_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on getting unfoldable note positions on diffs batch request | `controller`, `action` |
-| `gitlab_diffs_unfold_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on unfolding positions on diffs batch request | `controller`, `action` |
-| `gitlab_diffs_write_cache_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on caching highlighted lines and stats on diffs batch request | `controller`, `action` |
-| `gitlab_diffs_highlight_cache_decorate_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on setting highlighted lines from cache on diffs batch request | `controller`, `action` |
-| `gitlab_diffs_render_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on serializing and rendering diffs on diffs batch request | `controller`, `action` |
+| `gitlab_diffs_unfold_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on unfolding positions on diffs batch request | `controller`, `action`, `endpoint_id` |
+| `gitlab_diffs_write_cache_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on caching highlighted lines and stats on diffs batch request | `controller`, `action`, `endpoint_id` |
+| `gitlab_diffs_highlight_cache_decorate_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on setting highlighted lines from cache on diffs batch request | `controller`, `action`, `endpoint_id` |
+| `gitlab_diffs_render_real_duration_seconds` | Histogram | 15.8 | Duration in seconds spent on serializing and rendering diffs on diffs batch request | `controller`, `action`, `endpoint_id` |
| `gitlab_memwd_violations_total` | Counter | 15.9 | Total number of times a Ruby process violated a memory threshold | |
| `gitlab_memwd_violations_handled_total` | Counter | 15.9 | Total number of times Ruby process memory violations were handled | |
| `gitlab_sli_rails_request_apdex_total` | Counter | 14.4 | Total number of request Apdex measurements. For more information, see [Rails request SLIs](../../../development/application_slis/rails_request.md) | `endpoint_id`, `feature_category`, `request_urgency` |
diff --git a/doc/administration/settings/project_integration_management.md b/doc/administration/settings/project_integration_management.md
index ad43c70e253..32756e65eaf 100644
--- a/doc/administration/settings/project_integration_management.md
+++ b/doc/administration/settings/project_integration_management.md
@@ -4,7 +4,10 @@ group: Import and Integrate
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
---
-# Project integration management **(FREE SELF)**
+# Project integration administration **(FREE SELF)**
+
+NOTE:
+This page contains information about administering project integrations for self-managed instances. For user documentation, see [Project integrations](../../user/project/integrations/index.md).
Project integrations can be configured and enabled by project administrators. As a GitLab instance
administrator, you can set default configuration parameters for a given integration that all projects
@@ -53,7 +56,7 @@ When you make further changes to the instance defaults:
- Groups and projects with custom settings selected for the integration are not immediately affected and may
choose to use the latest defaults at any time.
-If [group-level settings](#manage-group-level-default-settings-for-a-project-integration) have also
+If [group-level settings](../../user/project/integrations/index.md#manage-group-level-default-settings-for-a-project-integration) have also
been configured for the same integration, projects in that group inherit the group-level settings
instead of the instance-level settings.
@@ -84,98 +87,10 @@ Prerequisite:
- You must have administrator access to the instance.
-To view projects in your instance that [use custom settings](#use-custom-settings-for-a-project-or-group-integration):
+To view projects in your instance that [use custom settings](../../user/project/integrations/index.md#use-custom-settings-for-a-project-or-group-integration):
1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Integrations**.
1. Select an integration.
1. Select the **Projects using custom settings** tab.
-
-## Manage group-level default settings for a project integration **(FREE ALL)**
-
-Prerequisite:
-
-- You must have at least the Maintainer role for the group.
-
-To manage group-level default settings for a project integration:
-
-1. On the left sidebar, select **Search or go to** and find your group.
-1. Select **Settings > Integrations**.
-1. Select an integration.
-1. Complete the fields.
-1. Select **Save changes**.
-
-WARNING:
-This may affect all or most of the subgroups and projects belonging to the group. Review the details below.
-
-If this is the first time you are setting up group-level settings for an integration:
-
-- The integration is enabled for all subgroups and projects belonging to the group that don't already have
- this integration configured, if you have the **Enable integration** toggle turned on in the group-level
- settings.
-- Subgroups and projects that already have the integration configured are not affected, but can choose to use
- the inherited settings at any time.
-
-When you make further changes to the group defaults:
-
-- They are immediately applied to all subgroups and projects belonging to the group that have the integration
- set to use default settings.
-- They are immediately applied to newer subgroups and projects, even those created after you last saved defaults for the
- integration. If your group-level default setting has the **Enable integration** toggle turned on,
- the integration is automatically enabled for all such subgroups and projects.
-- Subgroups and projects with custom settings selected for the integration are not immediately affected and
- may choose to use the latest defaults at any time.
-
-If [instance-level settings](#manage-instance-level-default-settings-for-a-project-integration)
-have also been configured for the same integration, projects in the group inherit settings from the group.
-
-Only the entire settings for an integration can be inherited. Per-field inheritance
-is proposed in [epic 2137](https://gitlab.com/groups/gitlab-org/-/epics/2137).
-
-### Remove a group-level default setting
-
-Prerequisite:
-
-- You must have at least the Maintainer role for the group.
-
-To remove a group-level default setting:
-
-1. On the left sidebar, select **Search or go to** and find your group.
-1. Select **Settings > Integrations**.
-1. Select an integration.
-1. Select **Reset** and confirm.
-
-Resetting a group-level default setting removes integrations that use default settings and belong to a project or subgroup of the group.
-
-## Use instance-level or group-level default settings for a project integration **(FREE ALL)**
-
-Prerequisite:
-
-- You must have at least the Maintainer role for the project.
-
-To use instance-level or group-level default settings for a project integration:
-
-1. On the left sidebar, select **Search or go to** and find your project.
-1. Select **Settings > Integrations**.
-1. Select an integration.
-1. On the right, from the dropdown list, select **Use default settings**.
-1. Under **Enable integration**, ensure the **Active** checkbox is selected.
-1. Complete the fields.
-1. Select **Save changes**.
-
-## Use custom settings for a project or group integration **(FREE ALL)**
-
-Prerequisite:
-
-- You must have at least the Maintainer role for the project or group.
-
-To use custom settings for a project or group integration:
-
-1. On the left sidebar, select **Search or go to** and find your project or group.
-1. Select **Settings > Integrations**.
-1. Select an integration.
-1. On the right, from the dropdown list, select **Use custom settings**.
-1. Under **Enable integration**, ensure the **Active** checkbox is selected.
-1. Complete the fields.
-1. Select **Save changes**.
diff --git a/doc/api/lint.md b/doc/api/lint.md
index 32318b9955d..9e29e8dccb4 100644
--- a/doc/api/lint.md
+++ b/doc/api/lint.md
@@ -102,160 +102,6 @@ Example responses:
}
```
-<!--- start_remove The following content will be removed on remove_date: '2023-08-22' -->
-
-## Validate the CI YAML configuration (deprecated)
-
-WARNING:
-This endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/381669) in GitLab 15.7
-and was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/403256) in 16.0. Use [`POST /projects/:id/ci/lint`](#validate-the-cicd-configuration-for-a-namespace) instead.
-
-Checks if CI/CD YAML configuration is valid. This endpoint validates basic CI/CD
-configuration syntax. It doesn't have any namespace-specific context.
-
-Access to this endpoint does not require authentication when the instance
-[allows new sign ups](../administration/settings/sign_up_restrictions.md#disable-new-sign-ups)
-and:
-
-- Does not have an [allowlist or denylist](../administration/settings/sign_up_restrictions.md#allow-or-deny-sign-ups-using-specific-email-domains).
-- Does not [require administrator approval for new sign ups](../administration/settings/sign_up_restrictions.md#require-administrator-approval-for-new-sign-ups).
-- Does not have additional [sign up restrictions](../administration/settings/sign_up_restrictions.md).
-
-Otherwise, authentication is required.
-
-```plaintext
-POST /ci/lint
-```
-
-| Attribute | Type | Required | Description |
-|-----------------------|---------|----------|-------------|
-| `content` | string | Yes | The CI/CD configuration content. |
-| `include_merged_yaml` | boolean | No | If the [expanded CI/CD configuration](#yaml-expansion) should be included in the response. |
-| `include_jobs` | boolean | No | If the list of jobs should be included in the response. Default: `false`. |
-
-```shell
-curl --header "Content-Type: application/json" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/ci/lint" --data '{"content": "{ \"image\": \"ruby:2.6\", \"services\": [\"postgres\"], \"before_script\": [\"bundle install\", \"bundle exec rake db:create\"], \"variables\": {\"DB_NAME\": \"postgres\"}, \"types\": [\"test\", \"deploy\", \"notify\"], \"rspec\": { \"script\": \"rake spec\", \"tags\": [\"ruby\", \"postgres\"], \"only\": [\"branches\"]}}"}'
-```
-
-Be sure to paste the exact contents of your GitLab CI/CD YAML configuration because YAML
-is very sensitive about indentation and spacing.
-
-Example responses:
-
-- Valid content:
-
- ```json
- {
- "status": "valid",
- "errors": [],
- "warnings": []
- }
- ```
-
-- Valid content with warnings:
-
- ```json
- {
- "status": "valid",
- "errors": [],
- "warnings": ["jobs:job may allow multiple pipelines to run for a single action due to
- `rules:when` clause with no `workflow:rules` - read more:
- https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings"]
- }
- ```
-
-- Invalid content:
-
- ```json
- {
- "status": "invalid",
- "errors": [
- "variables config should be a hash of key value pairs"
- ],
- "warnings": []
- }
- ```
-
-- Without the content attribute:
-
- ```json
- {
- "error": "content is missing"
- }
- ```
-
-### YAML expansion
-
-The CI lint returns an expanded version of the configuration. The expansion does not
-work for CI configuration added with [`include: local`](../ci/yaml/index.md#includelocal),
-and the [`extends:`](../ci/yaml/index.md#extends) keyword is [not fully supported](https://gitlab.com/gitlab-org/gitlab/-/issues/258843).
-
-Example contents of a `.gitlab-ci.yml` passed to the CI Lint API with
-`include_merged_yaml` and `include_jobs` set as true:
-
-```yaml
-include:
- remote: 'https://example.com/remote.yaml'
-
-test:
- stage: test
- script:
- - echo 1
-```
-
-Example contents of `https://example.com/remote.yaml`:
-
-```yaml
-another_test:
- stage: test
- script:
- - echo 2
-```
-
-Example response:
-
-```json
-{
- "status": "valid",
- "errors": [],
- "merged_yaml": "---\n:another_test:\n :stage: test\n :script: echo 2\n:test:\n :stage: test\n :script: echo 1\n",
- "jobs": [
- {
- "name":"test",
- "stage":"test",
- "before_script":[],
- "script":["echo 1"],
- "after_script":[],
- "tag_list":[],
- "environment":null,
- "when":"on_success",
- "allow_failure":false,
- "only":{
- "refs":["branches","tags"]
- },
- "except":null
- },
- {
- "name":"another_test",
- "stage":"test",
- "before_script":[],
- "script":["echo 2"],
- "after_script":[],
- "tag_list":[],
- "environment":null,
- "when":"on_success",
- "allow_failure":false,
- "only":{
- "refs":["branches","tags"]
- },
- "except":null
- }
- ]
-}
-```
-
-<!--- end_remove -->
-
## Use jq to create and process YAML & JSON payloads
To `POST` a YAML configuration to the CI Lint endpoint, it must be properly escaped and JSON encoded.
diff --git a/doc/api/packages/nuget.md b/doc/api/packages/nuget.md
index ee304ab28df..e28f42fa931 100644
--- a/doc/api/packages/nuget.md
+++ b/doc/api/packages/nuget.md
@@ -488,10 +488,29 @@ Example response:
| `GET projects/:id/packages/nuget/v2/FindPackagesById()?id='<package_name>'` | Returns an OData XML document containing information about the package with the given name. |
| `GET projects/:id/packages/nuget/v2/Packages(Id='<package_name>',Version='<package_version>')` | Returns an OData XML document containing information about the package with the given name and version. |
+```shell
+curl "https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/Packages(Id='mynugetpkg',Version='1.0.0')"
+```
+
+Example response:
+
+```xml
+<entry xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xml:base="https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2">
+ <id>https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/Packages(Id='mynugetpkg',Version='1.0.0')</id>
+ <category term="V2FeedPackage" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
+ <title type="text">mynugetpkg</title>
+ <content type="application/zip" src="https://gitlab.example.com/api/v4/projects/1/packages/nuget/download/mynugetpkg/1.0.0/mynugetpkg.1.0.0.nupkg"/>
+ <m:properties>
+ <d:Version>1.0.0</d:Version>
+ </m:properties>
+ </entry>
+```
+
NOTE:
-GitLab doesn't receive an authentication token for the `Packages()` and `FindPackagesByID()` endpoints.
-To not reveal the package version to unauthenticated users, the actual latest package version is not returned. Instead, a placeholder version is returned.
-The latest version is obtained in the subsequent download request where the authentication token is sent.
+GitLab doesn't receive an authentication token for the `Packages()` and
+`FindPackagesByID()` endpoints, so the latest version of the package
+cannot be returned. You must provide the version when you install
+or upgrade a package with the NuGet v2 feed.
```shell
curl "https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/Packages()?$filter=(tolower(Id) eq 'mynugetpkg')"
@@ -501,12 +520,12 @@ Example response:
```xml
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xml:base="https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2">
- <id>https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/Packages(Id='mynugetpkg',Version='0.0.0-latest-version')</id>
+ <id>https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/Packages(Id='mynugetpkg',Version='')</id>
<category term="V2FeedPackage" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
<title type="text">mynugetpkg</title>
- <content type="application/zip" src="https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/download/mynugetpkg/latest"/>
+ <content type="application/zip" src="https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2"/>
<m:properties>
- <d:Version>0.0.0-latest-version</d:Version>
+ <d:Version></d:Version>
</m:properties>
</entry>
```
diff --git a/doc/ci/runners/new_creation_workflow.md b/doc/ci/runners/new_creation_workflow.md
index c4c2fbebb12..2f53f3b9bc3 100644
--- a/doc/ci/runners/new_creation_workflow.md
+++ b/doc/ci/runners/new_creation_workflow.md
@@ -203,3 +203,8 @@ data:
NOTE:
If your secret management solution doesn't allow you to set an empty string for `runner-registration-token`,
you can set it to any string - it will be ignored when `runner-token` is present.
+
+## Known issues
+
+- When you use the new registration workflow to register your runners with the Helm chart, the pod name is not visible
+ in the runner details page. For more information, see [issue 423523](https://gitlab.com/gitlab-org/gitlab/-/issues/423523).
diff --git a/doc/integration/jira/configure.md b/doc/integration/jira/configure.md
index dd43c6417e8..8072ae2432f 100644
--- a/doc/integration/jira/configure.md
+++ b/doc/integration/jira/configure.md
@@ -22,7 +22,10 @@ Prerequisites:
- Jira personal access token (GitLab 16.0 and later).
You can enable the Jira issue integration by configuring your project settings in GitLab.
-You can configure these settings at the [group level](../../administration/settings/project_integration_management.md#manage-group-level-default-settings-for-a-project-integration) or at the [instance level](../../administration/settings/project_integration_management.md#manage-instance-level-default-settings-for-a-project-integration) for self-managed GitLab.
+You can also configure these settings at the:
+
+- [Group level](../../user/project/integrations/index.md#manage-group-level-default-settings-for-a-project-integration)
+- [Instance level](../../administration/settings/project_integration_management.md#manage-instance-level-default-settings-for-a-project-integration) for self-managed GitLab
To configure your project settings in GitLab:
diff --git a/doc/user/packages/composer_repository/index.md b/doc/user/packages/composer_repository/index.md
index 3c80e739465..a61df9fc6ab 100644
--- a/doc/user/packages/composer_repository/index.md
+++ b/doc/user/packages/composer_repository/index.md
@@ -312,11 +312,11 @@ You can install from source by pulling the Git repository directly. To do so, ei
#### SSH access
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119739) in GitLab 16.4 [with a flag](../../../administration/feature_flags.md) named `composer_use_ssh_source_urls`. Disabled by default.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119739) in GitLab 16.4 [with a flag](../../../administration/feature_flags.md) named `composer_use_ssh_source_urls`. Enabled by default.
FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available, an administrator can
-[enable the feature flag](../../../administration/feature_flags.md) named `composer_use_ssh_source_urls`.
+On self-managed GitLab, by default this feature is available. To hide the feature per project, an administrator can
+[disable the feature flag](../../../administration/feature_flags.md) named `composer_use_ssh_source_urls`.
When you install from source, the `composer` configures an
access to the project's Git repository.
diff --git a/doc/user/packages/nuget_repository/index.md b/doc/user/packages/nuget_repository/index.md
index 340df4a3c5f..4f8bb56bda8 100644
--- a/doc/user/packages/nuget_repository/index.md
+++ b/doc/user/packages/nuget_repository/index.md
@@ -492,6 +492,55 @@ dotnet add package <package_id> \
- `<package_id>` is the package ID.
- `<package_version>` is the package version. Optional.
+### Install a package using NuGet v2 feed
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/416405) in GitLab 16.5.
+
+Prerequisites:
+
+- The project-level Package Registry is a [v2 feed source](#add-a-source-with-chocolatey-cli) for Chocolatey.
+- A version must be provided when installing or upgrading a package using NuGet v2 feed.
+
+To install a package with the Chocolatey CLI:
+
+```shell
+choco install <package_id> -Source <source_url> -Version <package_version>
+```
+
+In this command:
+
+- `<package_id>` is the package ID.
+- `<source_url>` is the URL or name of the NuGet v2 feed Package Registry.
+- `<package_version>` is the package version.
+
+For example:
+
+```shell
+choco install MyPackage -Source gitlab -Version 1.0.2
+
+# or
+
+choco install MyPackage -Source "https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/nuget/v2" -u <username> -p <gitlab_personal_access_token, deploy_token or job token> -Version 1.0.2
+```
+
+To upgrade a package with the Chocolatey CLI:
+
+```shell
+choco upgrade <package_id> -Source <source_url> -Version <package_version>
+```
+
+In this command:
+
+- `<package_id>` is the package ID.
+- `<source_url>` is the URL or name of the NuGet v2 feed Package Registry.
+- `<package_version>` is the package version.
+
+For example:
+
+```shell
+choco upgrade MyPackage -Source gitlab -Version 1.0.3
+```
+
## Symbol packages
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/262081) in GitLab 14.1.
diff --git a/doc/user/project/integrations/index.md b/doc/user/project/integrations/index.md
index 59b5043b8f7..c62b5a3e668 100644
--- a/doc/user/project/integrations/index.md
+++ b/doc/user/project/integrations/index.md
@@ -6,28 +6,108 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Project integrations **(FREE ALL)**
-You can integrate your GitLab projects with other applications. Integrations are
-like plugins, and give you the freedom to add
-functionality to GitLab.
+NOTE:
+This page contains information about configuring project integrations on GitLab.com. For administrator documentation, see [Project integration administration](../../../administration/settings/project_integration_management.md).
+
+You can integrate with external applications to add functionality to GitLab.
+
+You can view and manage integrations at the [instance level](../../../administration/settings/project_integration_management.md#manage-instance-level-default-settings-for-a-project-integration) or the
+[group level](#manage-group-level-default-settings-for-a-project-integration).
+For any project, you can:
+
+- Inherit the instance-level or group-level settings.
+- Use custom settings.
+
+Integration management at the instance and group level replaces service templates, which
+were [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/268032) in GitLab 14.0.
+
+## Manage group-level default settings for a project integration
+
+Prerequisite:
+
+- You must have at least the Maintainer role for the group.
+
+To manage group-level default settings for a project integration:
+
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **Settings > Integrations**.
+1. Select an integration.
+1. Complete the fields.
+1. Select **Save changes**.
+
+WARNING:
+This may affect all or most of the subgroups and projects belonging to the group. Review the details below.
+
+If this is the first time you are setting up group-level settings for an integration:
+
+- The integration is enabled for all subgroups and projects belonging to the group that don't already have
+ this integration configured, if you have the **Enable integration** toggle turned on in the group-level
+ settings.
+- Subgroups and projects that already have the integration configured are not affected, but can choose to use
+ the inherited settings at any time.
+
+When you make further changes to the group defaults:
-## View project integrations
+- They are immediately applied to all subgroups and projects belonging to the group that have the integration
+ set to use default settings.
+- They are immediately applied to newer subgroups and projects, even those created after you last saved defaults for the
+ integration. If your group-level default setting has the **Enable integration** toggle turned on,
+ the integration is automatically enabled for all such subgroups and projects.
+- Subgroups and projects with custom settings selected for the integration are not immediately affected and
+ may choose to use the latest defaults at any time.
-Prerequisites:
+If [instance-level settings](../../../administration/settings/project_integration_management.md#manage-instance-level-default-settings-for-a-project-integration)
+have also been configured for the same integration, projects in the group inherit settings from the group.
+
+Only the entire settings for an integration can be inherited. Per-field inheritance
+is proposed in [epic 2137](https://gitlab.com/groups/gitlab-org/-/epics/2137).
+
+### Remove a group-level default setting
+
+Prerequisite:
+
+- You must have at least the Maintainer role for the group.
+
+To remove a group-level default setting:
+
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **Settings > Integrations**.
+1. Select an integration.
+1. Select **Reset** and confirm.
+
+Resetting a group-level default setting removes integrations that use default settings and belong to a project or subgroup of the group.
+
+## Use instance-level or group-level default settings for a project integration
+
+Prerequisite:
- You must have at least the Maintainer role for the project.
-To view the available integrations for your project:
+To use instance-level or group-level default settings for a project integration:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
+1. Select an integration.
+1. On the right, from the dropdown list, select **Use default settings**.
+1. Under **Enable integration**, ensure the **Active** checkbox is selected.
+1. Complete the fields.
+1. Select **Save changes**.
-You can also view and manage integration settings across [all projects in an instance or group](../../admin_area/settings/project_integration_management.md).
-For a single project, you can choose to inherit the instance or group configuration,
-or provide custom settings.
+## Use custom settings for a project or group integration
-NOTE:
-Instance and group-based integration management replaces service templates, which
-were [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/268032) in GitLab 14.0.
+Prerequisite:
+
+- You must have at least the Maintainer role for the project or group.
+
+To use custom settings for a project or group integration:
+
+1. On the left sidebar, select **Search or go to** and find your project or group.
+1. Select **Settings > Integrations**.
+1. Select an integration.
+1. On the right, from the dropdown list, select **Use custom settings**.
+1. Under **Enable integration**, ensure the **Active** checkbox is selected.
+1. Complete the fields.
+1. Select **Save changes**.
## Manage SSL verification
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index dbc789c68b6..3da05b4e7d9 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -113,9 +113,7 @@ module API
track_package_event(
symbol_package ? 'push_symbol_package' : 'push_package',
:nuget,
- **{ category: 'API::NugetPackages',
- project: package.project,
- namespace: package.project.namespace }.tap { |args| args[:feed] = 'v2' if request.path.include?('nuget/v2') }
+ **track_package_event_attrs(package.project)
)
end
rescue ObjectStorage::RemoteStoreError => e
@@ -148,6 +146,16 @@ module API
present odata_entry
end
+
+ def track_package_event_attrs(project)
+ attrs = {
+ category: 'API::NugetPackages',
+ project: project,
+ namespace: project.namespace
+ }
+ attrs[:feed] = 'v2' if request.path.include?('nuget/v2')
+ attrs
+ end
end
params do
@@ -216,9 +224,7 @@ module API
track_package_event(
params[:format] == 'snupkg' ? 'pull_symbol_package' : 'pull_package',
:nuget,
- category: 'API::NugetPackages',
- project: package_file.project,
- namespace: package_file.project.namespace
+ **track_package_event_attrs(package.project)
)
# nuget and dotnet don't support 302 Moved status codes, supports_direct_download has to be set to false
diff --git a/lib/gitlab/metrics/web_transaction.rb b/lib/gitlab/metrics/web_transaction.rb
index f3c1e6897af..a6bc74badca 100644
--- a/lib/gitlab/metrics/web_transaction.rb
+++ b/lib/gitlab/metrics/web_transaction.rb
@@ -9,7 +9,7 @@ module Gitlab
# etc.
class WebTransaction < Transaction
THREAD_KEY = :_gitlab_metrics_transaction
- BASE_LABEL_KEYS = %i[controller action feature_category].freeze
+ BASE_LABEL_KEYS = %i[controller action feature_category endpoint_id].freeze
CONTROLLER_KEY = 'action_controller.instance'
ENDPOINT_KEY = 'api.endpoint'
@@ -95,7 +95,12 @@ module Gitlab
action = "#{action}.#{suffix}"
end
- { controller: controller.class.name, action: action, feature_category: feature_category }
+ {
+ controller: controller.class.name,
+ action: action,
+ feature_category: feature_category,
+ endpoint_id: controller.class.endpoint_id_for_action(action)
+ }
end
def labels_from_endpoint
@@ -112,7 +117,12 @@ module Gitlab
if route
path = endpoint_paths_cache[route.request_method][route.path]
- { controller: 'Grape', action: "#{route.request_method} #{path}", feature_category: feature_category }
+ {
+ controller: 'Grape',
+ action: "#{route.request_method} #{path}",
+ feature_category: feature_category,
+ endpoint_id: API::Base.endpoint_id_for_route(route)
+ }
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 188a6cd5e42..9be0befdbed 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -815,6 +815,9 @@ msgstr ""
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
+msgid "%{jobName}"
+msgstr ""
+
msgid "%{jobName} job is being retried"
msgstr ""
@@ -26731,15 +26734,9 @@ msgstr ""
msgid "Job"
msgstr ""
-msgid "Job %{jobName}"
-msgstr ""
-
msgid "Job Failed #%{build_id}"
msgstr ""
-msgid "Job ID"
-msgstr ""
-
msgid "Job artifacts"
msgstr ""
@@ -55839,9 +55836,6 @@ msgstr ""
msgid "could not read private key, is the passphrase correct?"
msgstr ""
-msgid "created"
-msgstr ""
-
msgid "created %{issuable_created} by %{author}"
msgstr ""
@@ -57169,9 +57163,6 @@ msgstr ""
msgid "ssh:"
msgstr ""
-msgid "started"
-msgstr ""
-
msgid "started a discussion on %{design_link}"
msgstr ""
diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb
index 8d2face0233..847f7aeae7c 100644
--- a/spec/controllers/omniauth_callbacks_controller_spec.rb
+++ b/spec/controllers/omniauth_callbacks_controller_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
Rails.application.env_config['omniauth.auth'] = @original_env_config_omniauth_auth
end
- context 'authentication succeeds' do
+ context 'when authentication succeeds' do
let(:extern_uid) { 'my-uid' }
let(:provider) { :github }
@@ -77,7 +77,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
end
end
- context 'a deactivated user' do
+ context 'for a deactivated user' do
let(:provider) { :github }
let(:extern_uid) { 'my-uid' }
@@ -216,8 +216,8 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
end
end
- context 'strategies' do
- shared_context 'sign_up' do
+ context 'with strategies' do
+ shared_context 'with sign_up' do
let(:user) { double(email: 'new@example.com') }
before do
@@ -225,7 +225,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
end
end
- context 'github' do
+ context 'for github' do
let(:extern_uid) { 'my-uid' }
let(:provider) { :github }
@@ -299,7 +299,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
end
context 'for sign up' do
- include_context 'sign_up'
+ include_context 'with sign_up'
it 'is allowed' do
post provider
@@ -307,10 +307,10 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
expect(request.env['warden']).to be_authenticated
end
- it 'redirects to welcome path' do
- post provider
+ it_behaves_like Onboarding::Redirectable do
+ let(:email) { user.email }
- expect(response).to redirect_to(users_sign_up_welcome_path)
+ subject(:post_create) { post provider }
end
end
@@ -341,8 +341,8 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
expect { post provider }.to change { user.reload.identities.count }.by(1)
end
- context 'sign up' do
- include_context 'sign_up'
+ context 'for sign up' do
+ include_context 'with sign_up'
it 'is prevented' do
post provider
@@ -353,7 +353,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
end
end
- context 'auth0' do
+ context 'for auth0' do
let(:extern_uid) { '' }
let(:provider) { :auth0 }
@@ -366,7 +366,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
end
end
- context 'atlassian_oauth2' do
+ context 'for atlassian_oauth2' do
let(:provider) { :atlassian_oauth2 }
let(:extern_uid) { 'my-uid' }
@@ -424,7 +424,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
end
end
- context 'salesforce' do
+ context 'for salesforce' do
let(:extern_uid) { 'my-uid' }
let(:provider) { :salesforce }
let(:additional_info) { { extra: { email_verified: false } } }
@@ -440,7 +440,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
end
context 'with verified email' do
- include_context 'sign_up'
+ include_context 'with sign_up'
let(:additional_info) { { extra: { email_verified: true } } }
it 'allows sign in' do
@@ -532,7 +532,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
let(:post_action) { post :saml, params: { SAMLResponse: mock_saml_response } }
end
- context 'sign up' do
+ context 'for sign up' do
before do
user.destroy!
end
@@ -683,7 +683,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
expect(subject.current_user_mode.admin_mode?).to be(expected_admin_mode)
end
- context 'user and admin mode requested by the same user' do
+ context 'when user and admin mode is requested by the same user' do
before do
sign_in user
@@ -724,7 +724,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller, feature_category:
end
end
- context 'user and admin mode requested by different users' do
+ context 'when user and admin mode is requested by different users' do
let(:reauth_extern_uid) { 'another_uid' }
let(:reauth_user) { create(:omniauth_user, extern_uid: reauth_extern_uid, provider: provider) }
diff --git a/spec/controllers/registrations/welcome_controller_spec.rb b/spec/controllers/registrations/welcome_controller_spec.rb
deleted file mode 100644
index 0bac52c8dca..00000000000
--- a/spec/controllers/registrations/welcome_controller_spec.rb
+++ /dev/null
@@ -1,119 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Registrations::WelcomeController, feature_category: :system_access do
- let(:user) { create(:user) }
-
- describe '#show' do
- subject(:show) { get :show }
-
- context 'without a signed in user' do
- it { is_expected.to redirect_to new_user_registration_path }
- end
-
- context 'when setup_for_company is not set' do
- before do
- sign_in(user)
- end
-
- it { is_expected.to render_template(:show) }
-
- render_views
-
- it 'has the expected submission url' do
- show
-
- expect(response.body).to include("action=\"#{users_sign_up_welcome_path}\"")
- end
- end
-
- context 'when setup_for_company is set' do
- before do
- user.update!(setup_for_company: false)
- sign_in(user)
- end
-
- it { is_expected.to redirect_to(dashboard_projects_path) }
- end
-
- context 'when 2FA is required from group' do
- before do
- user = create(:user, require_two_factor_authentication_from_group: true)
- sign_in(user)
- end
-
- it 'does not perform a redirect' do
- expect(subject).not_to redirect_to(profile_two_factor_auth_path)
- end
- end
-
- context 'when welcome step is completed' do
- before do
- user.update!(setup_for_company: true)
- end
-
- context 'when user is confirmed' do
- before do
- sign_in(user)
- end
-
- it { is_expected.to redirect_to dashboard_projects_path }
- end
-
- context 'when user is not confirmed' do
- before do
- stub_application_setting_enum('email_confirmation_setting', 'hard')
-
- sign_in(user)
-
- user.update!(confirmed_at: nil)
- end
-
- it { is_expected.to redirect_to user_session_path }
- end
- end
- end
-
- describe '#update' do
- subject(:update) do
- patch :update, params: { user: { role: 'software_developer', setup_for_company: 'false' } }
- end
-
- context 'without a signed in user' do
- it { is_expected.to redirect_to new_user_registration_path }
- end
-
- context 'with a signed in user' do
- before do
- sign_in(user)
- end
-
- it { is_expected.to redirect_to(dashboard_projects_path) }
-
- context 'when the new user already has any accepted group membership' do
- let!(:member1) { create(:group_member, user: user) }
-
- it 'redirects to the group activity page' do
- expect(subject).to redirect_to(activity_group_path(member1.source))
- end
-
- context 'when the new user already has more than 1 accepted group membership' do
- it 'redirects to the most recent membership group activity page' do
- member2 = create(:group_member, user: user)
-
- expect(subject).to redirect_to(activity_group_path(member2.source))
- end
- end
-
- context 'when the member has an orphaned source at the time of the welcome' do
- it 'redirects to the project dashboard page' do
- member1.source.delete
-
- expect(subject).to redirect_to(dashboard_projects_path)
- end
- end
- end
- end
- end
-end
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index 9aa8a2ae605..156479c7044 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
subject(:post_create) { post(:create, params: user_params, session: session_params) }
- context '`blocked_pending_approval` state' do
+ context 'with `blocked_pending_approval` state' do
context 'when the `require_admin_approval_after_user_signup` setting is turned on' do
before do
stub_application_setting(require_admin_approval_after_user_signup: true)
@@ -82,7 +82,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
subject
end
- context 'email confirmation' do
+ context 'for email confirmation' do
context 'when email confirmation setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
@@ -95,7 +95,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
- context 'audit events' do
+ context 'with audit events' do
context 'when not licensed' do
before do
stub_licensed_features(admin_audit_log: false)
@@ -129,7 +129,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
subject
end
- context 'email confirmation' do
+ context 'with email confirmation' do
context 'when email confirmation setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
@@ -145,7 +145,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
- context 'private profile' do
+ context 'with private profile' do
context 'when the `user_defaults_to_private_profile` setting is turned on' do
before do
stub_application_setting(user_defaults_to_private_profile: true)
@@ -160,7 +160,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
- context 'email confirmation' do
+ context 'with email confirmation' do
before do
stub_feature_flags(identity_verification: false)
end
@@ -209,7 +209,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
context 'when member exists from the session key value' do
it 'tracks the invite acceptance' do
- subject
+ post_create
expect_snowplow_event(
category: 'RegistrationsController',
@@ -299,7 +299,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
it 'authenticates the user and sends a confirmation email' do
expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
expect(controller.current_user).to be_present
- expect(response).to redirect_to(users_sign_up_welcome_path)
+ expect(response).to redirect_to(dashboard_projects_path)
end
it 'does not track an almost there redirect' do
@@ -312,6 +312,11 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
)
end
+ it_behaves_like Onboarding::Redirectable do
+ let(:email) { user_params.dig(:user, :email) }
+ let(:session_params) { { invite_email: email } }
+ end
+
context 'when invite email matches email used on registration' do
let(:session_params) { { invite_email: user_params.dig(:user, :email) } }
@@ -375,10 +380,10 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
- it 'redirects to the welcome page when the reCAPTCHA is solved' do
+ it 'redirects to the dashboard projects page when the reCAPTCHA is solved' do
subject
- expect(response).to redirect_to(users_sign_up_welcome_path)
+ expect(response).to redirect_to(dashboard_projects_path)
end
end
@@ -430,7 +435,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
describe 'timestamp spam detection' do
let(:auth_log_message) { 'Invisible_Captcha_Timestamp_Request' }
- context 'the sign up form has been submitted without the invisible_captcha_timestamp parameter' do
+ context 'when the sign up form has been submitted without the invisible_captcha_timestamp parameter' do
let(:session_params) { nil }
it 'logs the request, refuses to create an account and displays a flash alert' do
@@ -446,7 +451,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
- context 'the sign up form has been submitted too quickly' do
+ context 'when the sign up form has been submitted too quickly' do
let(:submit_time) { form_rendered_time }
it 'logs the request, refuses to create an account and displays a flash alert' do
@@ -464,7 +469,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
- context 'terms of service' do
+ context 'with terms of service' do
context 'when terms are enforced' do
before do
enforce_terms
@@ -674,7 +679,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
expect(response).to redirect_to new_user_session_path
end
- context 'user requires password confirmation' do
+ context 'when user requires password confirmation' do
it 'fails if password confirmation is not provided' do
post :destroy
@@ -694,7 +699,7 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
- context 'user does not require password confirmation' do
+ context 'when user does not require password confirmation' do
before do
stub_application_setting(password_authentication_enabled_for_web: false)
stub_application_setting(password_authentication_enabled_for_git: false)
@@ -719,8 +724,8 @@ RSpec.describe RegistrationsController, feature_category: :user_profile do
end
end
- context 'prerequisites for account deletion' do
- context 'solo-owned groups' do
+ context 'for prerequisites for account deletion' do
+ context 'with solo-owned groups' do
let(:group) { create(:group) }
context 'if the user is the sole owner of at least one group' do
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index a56df7bdecc..0a270adbd01 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -113,7 +113,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
it 'declines application and redirects to dashboard' do
- expect(page).to have_current_path(dashboard_projects_path, ignore_query: true)
+ expect(page).to have_current_path(dashboard_projects_path)
expect(page).to have_content('You have declined the invitation to join group Owned.')
expect { group_invite.reload }.to raise_error ActiveRecord::RecordNotFound
end
@@ -178,7 +178,6 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
context 'when the user signs up for an account with the invitation email address' do
it 'redirects to the most recent membership activity page with all invitations automatically accepted' do
fill_in_sign_up_form(new_user)
- fill_in_welcome_form
expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
expect(page).to have_content('You have been granted Owner access to group Owned.')
@@ -190,7 +189,6 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
it 'signs up and redirects to the projects dashboard' do
fill_in_sign_up_form(new_user)
- fill_in_welcome_form
expect_to_be_on_projects_dashboard_with_zero_authorized_projects
end
@@ -226,7 +224,6 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
context 'when the user signs up for an account with the invitation email address' do
it 'redirects to the most recent membership activity page with all invitations automatically accepted' do
fill_in_sign_up_form(new_user)
- fill_in_welcome_form
expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
end
@@ -245,7 +242,6 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
fill_in_sign_up_form(new_user)
confirm_email(new_user)
gitlab_sign_in(new_user, remember: true, visit: false)
- fill_in_welcome_form
expect_to_be_on_projects_dashboard_with_zero_authorized_projects
end
@@ -259,7 +255,6 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
it 'signs up and redirects to the projects dashboard' do
fill_in_sign_up_form(new_user)
- fill_in_welcome_form
expect_to_be_on_projects_dashboard_with_zero_authorized_projects
end
@@ -283,7 +278,8 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
fill_in_sign_up_form(new_user, 'Register')
- expect(page).to have_current_path(users_sign_up_welcome_path, ignore_query: true)
+ expect(page).to have_current_path(activity_group_path(group))
+ expect(page).to have_content('You have been granted Owner access to group Owned.')
end
end
diff --git a/spec/features/projects/jobs/permissions_spec.rb b/spec/features/projects/jobs/permissions_spec.rb
index e1bcc160092..73635480b95 100644
--- a/spec/features/projects/jobs/permissions_spec.rb
+++ b/spec/features/projects/jobs/permissions_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe 'Project Jobs Permissions', feature_category: :groups_and_project
it_behaves_like 'recent job page details responds with status', 200 do
it 'renders job details', :js do
- expect(page).to have_content "Job #{job.name}"
+ expect(page).to have_content(job.name)
expect(page).to have_css '.log-line'
end
end
diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb
index 795084f8008..448db8b6d89 100644
--- a/spec/features/projects/jobs/user_browses_job_spec.rb
+++ b/spec/features/projects/jobs/user_browses_job_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe 'User browses a job', :js, feature_category: :groups_and_projects
visit(project_job_path(project, build))
wait_for_requests
- expect(page).to have_content("Job #{build.name}")
+ expect(page).to have_content(build.name)
expect(page).to have_css('.job-log')
# scroll to the top of the page first
diff --git a/spec/features/registrations/oauth_registration_spec.rb b/spec/features/registrations/oauth_registration_spec.rb
index c88a018a592..98300cbeaaa 100644
--- a/spec/features/registrations/oauth_registration_spec.rb
+++ b/spec/features/registrations/oauth_registration_spec.rb
@@ -50,11 +50,11 @@ RSpec.describe 'OAuth Registration', :js, :allow_forgery_protection, feature_cat
stub_omniauth_setting(block_auto_created_users: false)
end
- it 'redirects to the initial welcome path' do
+ it 'redirects to the dashboard projects path' do
register_via(provider, uid, email, additional_info: additional_info)
- expect(page).to have_current_path users_sign_up_welcome_path
- expect(page).to have_content('Welcome to GitLab, mockuser!')
+ expect(page).to have_current_path dashboard_projects_path
+ expect(page).to have_content('Welcome to GitLab')
end
context 'when terms are enforced' do
@@ -62,11 +62,11 @@ RSpec.describe 'OAuth Registration', :js, :allow_forgery_protection, feature_cat
enforce_terms
end
- it 'auto accepts terms and redirects to the initial welcome path' do
+ it 'auto accepts terms and redirects to the dashboard projects path' do
register_via(provider, uid, email, additional_info: additional_info)
- expect(page).to have_current_path users_sign_up_welcome_path
- expect(page).to have_content('Welcome to GitLab, mockuser!')
+ expect(page).to have_current_path dashboard_projects_path
+ expect(page).to have_content('Welcome to GitLab')
end
end
@@ -108,7 +108,6 @@ RSpec.describe 'OAuth Registration', :js, :allow_forgery_protection, feature_cat
it 'redirects to the activity page with all the projects/groups invitations accepted' do
visit invite_path(group_invite.raw_invite_token, extra_params)
click_link_or_button "oauth-login-#{provider}"
- fill_in_welcome_form
expect(page).to have_content('You have been granted Owner access to group Owned.')
expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
@@ -116,9 +115,4 @@ RSpec.describe 'OAuth Registration', :js, :allow_forgery_protection, feature_cat
end
end
end
-
- def fill_in_welcome_form
- select 'Software Developer', from: 'user_role'
- click_button 'Get started!'
- end
end
diff --git a/spec/features/users/google_analytics_csp_spec.rb b/spec/features/users/google_analytics_csp_spec.rb
index 45cc6c5f39d..0837296922c 100644
--- a/spec/features/users/google_analytics_csp_spec.rb
+++ b/spec/features/users/google_analytics_csp_spec.rb
@@ -3,13 +3,29 @@
require 'spec_helper'
RSpec.describe 'Google Analytics 4 content security policy', feature_category: :purchase do
+ include ContentSecurityPolicyHelpers
+
+ subject(:csp_header) { response_headers['Content-Security-Policy'] }
+
it 'includes the GA4 content security policy headers' do
visit root_path
- expect(response_headers['Content-Security-Policy']).to include(
+ expect(find_csp_directive('script-src', header: csp_header)).to include(
+ '*.googletagmanager.com'
+ )
+
+ expect(find_csp_directive('connect-src', header: csp_header)).to include(
+ '*.googletagmanager.com',
+ '*.google-analytics.com',
+ '*.analytics.google.com',
+ '*.g.doubleclick.net'
+ )
+
+ expect(find_csp_directive('img-src', header: csp_header)).to include(
'*.googletagmanager.com',
'*.google-analytics.com',
- '*.analytics.google.com'
+ '*.analytics.google.com',
+ '*.g.doubleclick.net'
)
end
end
diff --git a/spec/features/users/google_syndication_csp_spec.rb b/spec/features/users/google_syndication_csp_spec.rb
index e71539f87c8..801716449c8 100644
--- a/spec/features/users/google_syndication_csp_spec.rb
+++ b/spec/features/users/google_syndication_csp_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'Google Syndication content security policy', feature_category: :
let_it_be(:google_analytics_src) do
'localhost https://cdn.cookielaw.org https://*.onetrust.com *.google-analytics.com ' \
- '*.analytics.google.com *.googletagmanager.com'
+ '*.analytics.google.com *.googletagmanager.com *.g.doubleclick.net'
end
let_it_be(:allowed_src) do
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index 111c0cce1b1..73e745db6f8 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -249,7 +249,7 @@ RSpec.describe 'Signup', :js, feature_category: :user_profile do
fill_in_signup_form
expect { click_button 'Register' }.to change { User.count }.by(1)
- expect(page).to have_current_path users_sign_up_welcome_path, ignore_query: true
+ expect(page).to have_current_path dashboard_projects_path
end
end
end
@@ -265,7 +265,7 @@ RSpec.describe 'Signup', :js, feature_category: :user_profile do
fill_in_signup_form
click_button "Register"
- expect(page).to have_current_path users_sign_up_welcome_path, ignore_query: true
+ expect(page).to have_current_path dashboard_projects_path
end
end
@@ -331,15 +331,6 @@ RSpec.describe 'Signup', :js, feature_category: :user_profile do
fill_in_signup_form
click_button 'Register'
- expect(page).to have_current_path(users_sign_up_welcome_path), ignore_query: true
-
- select 'Software Developer', from: 'user_role'
- click_button 'Get started!'
-
- created_user = User.find_by_username(new_user.username)
-
- expect(created_user.software_developer_role?).to be_truthy
- expect(created_user.setup_for_company).to be_nil
expect(page).to have_current_path(dashboard_projects_path)
end
diff --git a/spec/frontend/ci/job_details/components/job_header_spec.js b/spec/frontend/ci/job_details/components/job_header_spec.js
index 6fc55732353..c37d44d67ba 100644
--- a/spec/frontend/ci/job_details/components/job_header_spec.js
+++ b/spec/frontend/ci/job_details/components/job_header_spec.js
@@ -16,7 +16,7 @@ describe('Header CI Component', () => {
text: 'failed',
details_path: 'path',
},
- name: 'Job build_job',
+ name: 'build_job',
time: '2017-05-08T14:57:39.781Z',
user: {
id: 1234,
@@ -69,6 +69,10 @@ describe('Header CI Component', () => {
it('should not render header action buttons when slot is empty', () => {
expect(findActionButtons().exists()).toBe(false);
});
+
+ it('renders the correct job name', () => {
+ expect(findJobName().text()).toBe(defaultProps.name);
+ });
});
describe('user avatar', () => {
@@ -130,7 +134,7 @@ describe('Header CI Component', () => {
});
it('should render the job name', () => {
- expect(findJobName().text()).toBe('Job build_job');
+ expect(findJobName().text()).toBe('build_job');
});
});
@@ -147,8 +151,8 @@ describe('Header CI Component', () => {
it('should render created keyword when the shouldRenderTriggeredLabel is false', () => {
createComponent({ shouldRenderTriggeredLabel: false });
- expect(wrapper.text()).toContain('created');
- expect(wrapper.text()).not.toContain('started');
+ expect(wrapper.text()).toContain('Created');
+ expect(wrapper.text()).not.toContain('Started');
});
});
});
diff --git a/spec/frontend/ci/job_details/components/sidebar/sidebar_header_spec.js b/spec/frontend/ci/job_details/components/sidebar/sidebar_header_spec.js
index 1063bec6f3b..81181fc71b2 100644
--- a/spec/frontend/ci/job_details/components/sidebar/sidebar_header_spec.js
+++ b/spec/frontend/ci/job_details/components/sidebar/sidebar_header_spec.js
@@ -55,15 +55,9 @@ describe('Sidebar Header', () => {
const findEraseButton = () => wrapper.findByTestId('job-log-erase-link');
const findNewIssueButton = () => wrapper.findByTestId('job-new-issue');
const findTerminalLink = () => wrapper.findByTestId('terminal-link');
- const findJobName = () => wrapper.findByTestId('job-name');
const findRetryButton = () => wrapper.findComponent(JobRetryButton);
describe('when rendering contents', () => {
- it('renders the correct job name', async () => {
- await createComponentWithApollo();
- expect(findJobName().text()).toBe(mockJobResponse.data.project.job.name);
- });
-
it('does not render buttons with no paths', async () => {
await createComponentWithApollo();
expect(findCancelButton().exists()).toBe(false);
diff --git a/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js b/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js
index e188d99b8b1..37a2ca75df0 100644
--- a/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js
+++ b/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js
@@ -53,7 +53,6 @@ describe('Job Sidebar Details Container', () => {
['erased_at', 'Erased: 3 weeks ago'],
['finished_at', 'Finished: 3 weeks ago'],
['queued_duration', 'Queued: 9 seconds'],
- ['id', 'Job ID: #4757'],
['runner', 'Runner: #1 (ABCDEFGH) local ci runner'],
['coverage', 'Coverage: 20%'],
])('uses %s to render job-%s', async (detail, value) => {
@@ -78,7 +77,7 @@ describe('Job Sidebar Details Container', () => {
createWrapper();
await store.dispatch('receiveJobSuccess', job);
- expect(findAllDetailsRow()).toHaveLength(8);
+ expect(findAllDetailsRow()).toHaveLength(7);
});
describe('duration row', () => {
diff --git a/spec/lib/gitlab/metrics/web_transaction_spec.rb b/spec/lib/gitlab/metrics/web_transaction_spec.rb
index dc59fa804c4..139091eb456 100644
--- a/spec/lib/gitlab/metrics/web_transaction_spec.rb
+++ b/spec/lib/gitlab/metrics/web_transaction_spec.rb
@@ -64,7 +64,7 @@ RSpec.describe Gitlab::Metrics::WebTransaction do
describe '#labels' do
context 'when request goes to Grape endpoint' do
before do
- route = double(:route, request_method: 'GET', path: '/:version/projects/:id/archive(.:format)')
+ route = double(:route, request_method: 'GET', path: '/:version/projects/:id/archive(.:format)', origin: '/:version/projects/:id/archive')
endpoint = double(:endpoint, route: route,
options: { for: API::Projects, path: [":id/archive"] },
namespace: "/projects")
@@ -76,7 +76,12 @@ RSpec.describe Gitlab::Metrics::WebTransaction do
end
it 'provides labels with the method and path of the route in the grape endpoint' do
- expect(transaction.labels).to eq({ controller: 'Grape', action: 'GET /projects/:id/archive', feature_category: 'projects' })
+ expect(transaction.labels).to eq({
+ controller: 'Grape',
+ action: 'GET /projects/:id/archive',
+ feature_category: 'projects',
+ endpoint_id: 'GET /:version/projects/:id/archive'
+ })
end
it 'contains only the labels defined for transactions' do
@@ -99,11 +104,14 @@ RSpec.describe Gitlab::Metrics::WebTransaction do
before do
controller = double(:controller, class: controller_class, action_name: 'show', request: request)
+ allow(controller_class).to receive(:endpoint_id_for_action)
+ .with(controller.action_name)
+ .and_return("#{controller_class.name}##{controller.action_name}")
env['action_controller.instance'] = controller
end
it 'tags a transaction with the name and action of a controller' do
- expect(transaction.labels).to eq({ controller: 'TestController', action: 'show', feature_category: ::Gitlab::FeatureCategories::FEATURE_CATEGORY_DEFAULT })
+ expect(transaction.labels).to eq({ controller: 'TestController', action: 'show', feature_category: ::Gitlab::FeatureCategories::FEATURE_CATEGORY_DEFAULT, endpoint_id: 'TestController#show' })
end
it 'contains only the labels defined for transactions' do
@@ -113,8 +121,14 @@ RSpec.describe Gitlab::Metrics::WebTransaction do
context 'when the request content type is not :html' do
let(:request) { double(:request, format: double(:format, ref: :json)) }
+ before do
+ allow(controller_class).to receive(:endpoint_id_for_action)
+ .with("show.json")
+ .and_return("#{controller_class.name}#show.json")
+ end
+
it 'appends the mime type to the transaction action' do
- expect(transaction.labels).to eq({ controller: 'TestController', action: 'show.json', feature_category: ::Gitlab::FeatureCategories::FEATURE_CATEGORY_DEFAULT })
+ expect(transaction.labels).to eq({ controller: 'TestController', action: 'show.json', feature_category: ::Gitlab::FeatureCategories::FEATURE_CATEGORY_DEFAULT, endpoint_id: 'TestController#show.json' })
end
end
@@ -122,7 +136,7 @@ RSpec.describe Gitlab::Metrics::WebTransaction do
let(:request) { double(:request, format: double(:format, ref: 'http://example.com')) }
it 'does not append the MIME type to the transaction action' do
- expect(transaction.labels).to eq({ controller: 'TestController', action: 'show', feature_category: ::Gitlab::FeatureCategories::FEATURE_CATEGORY_DEFAULT })
+ expect(transaction.labels).to eq({ controller: 'TestController', action: 'show', feature_category: ::Gitlab::FeatureCategories::FEATURE_CATEGORY_DEFAULT, endpoint_id: 'TestController#show' })
end
end
@@ -131,7 +145,7 @@ RSpec.describe Gitlab::Metrics::WebTransaction do
# This is needed since we're not actually making a request, which would trigger the controller pushing to the context
::Gitlab::ApplicationContext.push(feature_category: 'source_code_management')
- expect(transaction.labels).to eq({ controller: 'TestController', action: 'show', feature_category: "source_code_management" })
+ expect(transaction.labels).to eq({ controller: 'TestController', action: 'show', feature_category: 'source_code_management', endpoint_id: 'TestController#show' })
end
end
end
@@ -147,9 +161,12 @@ RSpec.describe Gitlab::Metrics::WebTransaction do
let(:controller) { double(:controller, class: controller_class, action_name: 'show', request: request) }
let(:transaction_obj) { described_class.new({ 'action_controller.instance' => controller }) }
- let(:labels) { { controller: 'TestController', action: 'show', feature_category: 'projects' } }
+ let(:labels) { { controller: 'TestController', action: 'show', feature_category: 'projects', endpoint_id: 'TestController#show' } }
before do
+ allow(controller_class).to receive(:endpoint_id_for_action)
+ .with(controller.action_name)
+ .and_return("#{controller_class.name}##{controller.action_name}")
::Gitlab::ApplicationContext.push(feature_category: 'projects')
end
end
diff --git a/spec/requests/api/nuget_project_packages_spec.rb b/spec/requests/api/nuget_project_packages_spec.rb
index b55d992c1e4..1dcae4cf295 100644
--- a/spec/requests/api/nuget_project_packages_spec.rb
+++ b/spec/requests/api/nuget_project_packages_spec.rb
@@ -203,11 +203,12 @@ RSpec.describe API::NugetProjectPackages, feature_category: :package_registry do
describe 'GET /api/v4/projects/:id/packages/nuget/download/*package_name/*package_version/*package_filename' do
let_it_be(:package) { create(:nuget_package, :with_symbol_package, :with_metadatum, project: project, name: package_name, version: '0.1') }
+ let_it_be(:package_version) { package.version }
let(:format) { 'nupkg' }
- let(:url) { "/projects/#{target.id}/packages/nuget/download/#{package.name}/#{package.version}/#{package.name}.#{package.version}.#{format}" }
+ let(:url) { "/projects/#{target.id}/packages/nuget/download/#{package.name}/#{package_version}/#{package.name}.#{package_version}.#{format}" }
- subject { get api(url) }
+ subject { get api(url), headers: headers }
context 'with valid target' do
where(:visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
@@ -236,8 +237,6 @@ RSpec.describe API::NugetProjectPackages, feature_category: :package_registry do
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
let(:snowplow_gitlab_standard_context) { snowplow_context(user_role: user_role) }
- subject { get api(url), headers: headers }
-
before do
update_visibility_to(Gitlab::VisibilityLevel.const_get(visibility_level, false))
end
diff --git a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
index fffac0fd64b..a5dda1d13aa 100644
--- a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
+++ b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
@@ -267,230 +267,6 @@ RSpec.describe Ci::PipelineCreation::CancelRedundantPipelinesService, feature_ca
end
end
- context 'when the use_offset_pagination_for_canceling_redundant_pipelines FF is off' do
- # copy-paste from above
-
- before do
- stub_feature_flags(use_offset_pagination_for_canceling_redundant_pipelines: false)
- end
-
- describe '#execute!' do
- subject(:execute) { service.execute }
-
- context 'when build statuses are set up correctly' do
- it 'has builds of all statuses' do
- expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
- expect(build_statuses(pipeline)).to contain_exactly('pending')
- end
- end
-
- context 'when auto-cancel is enabled' do
- before do
- project.update!(auto_cancel_pending_pipelines: 'enabled')
- end
-
- it 'cancels only previous interruptible builds' do
- execute
-
- expect(build_statuses(prev_pipeline)).to contain_exactly('canceled', 'success', 'canceled')
- expect(build_statuses(pipeline)).to contain_exactly('pending')
- end
-
- it 'logs canceled pipelines' do
- allow(Gitlab::AppLogger).to receive(:info)
-
- execute
-
- expect(Gitlab::AppLogger).to have_received(:info).with(
- class: described_class.name,
- message: "Pipeline #{pipeline.id} auto-canceling pipeline #{prev_pipeline.id}",
- canceled_pipeline_id: prev_pipeline.id,
- canceled_by_pipeline_id: pipeline.id,
- canceled_by_pipeline_source: pipeline.source
- )
- end
-
- context 'when the previous pipeline has a child pipeline' do
- let(:child_pipeline) { create(:ci_pipeline, child_of: prev_pipeline) }
-
- context 'with another nested child pipeline' do
- let(:another_child_pipeline) { create(:ci_pipeline, child_of: child_pipeline) }
-
- before do
- create(:ci_build, :interruptible, :running, pipeline: another_child_pipeline)
- create(:ci_build, :interruptible, :running, pipeline: another_child_pipeline)
- end
-
- it 'cancels all nested child pipeline builds' do
- expect(build_statuses(another_child_pipeline)).to contain_exactly('running', 'running')
-
- execute
-
- expect(build_statuses(another_child_pipeline)).to contain_exactly('canceled', 'canceled')
- end
- end
-
- context 'when started after pipeline was finished' do
- before do
- create(:ci_build, :interruptible, :running, pipeline: child_pipeline)
- prev_pipeline.update!(status: "success")
- end
-
- it 'cancels child pipeline builds' do
- expect(build_statuses(child_pipeline)).to contain_exactly('running')
-
- execute
-
- expect(build_statuses(child_pipeline)).to contain_exactly('canceled')
- end
- end
-
- context 'when the child pipeline has interruptible running jobs' do
- before do
- create(:ci_build, :interruptible, :running, pipeline: child_pipeline)
- create(:ci_build, :interruptible, :running, pipeline: child_pipeline)
- end
-
- it 'cancels all child pipeline builds' do
- expect(build_statuses(child_pipeline)).to contain_exactly('running', 'running')
-
- execute
-
- expect(build_statuses(child_pipeline)).to contain_exactly('canceled', 'canceled')
- end
-
- context 'when the child pipeline includes completed interruptible jobs' do
- before do
- create(:ci_build, :interruptible, :failed, pipeline: child_pipeline)
- create(:ci_build, :interruptible, :success, pipeline: child_pipeline)
- end
-
- it 'cancels all child pipeline builds with a cancelable_status' do
- expect(build_statuses(child_pipeline)).to contain_exactly('running', 'running', 'failed', 'success')
-
- execute
-
- expect(build_statuses(child_pipeline)).to contain_exactly('canceled', 'canceled', 'failed', 'success')
- end
- end
- end
-
- context 'when the child pipeline has started non-interruptible job' do
- before do
- create(:ci_build, :interruptible, :running, pipeline: child_pipeline)
- # non-interruptible started
- create(:ci_build, :success, pipeline: child_pipeline)
- end
-
- it 'does not cancel any child pipeline builds' do
- expect(build_statuses(child_pipeline)).to contain_exactly('running', 'success')
-
- execute
-
- expect(build_statuses(child_pipeline)).to contain_exactly('running', 'success')
- end
- end
-
- context 'when the child pipeline has non-interruptible non-started job' do
- before do
- create(:ci_build, :interruptible, :running, pipeline: child_pipeline)
- end
-
- not_started_statuses = Ci::HasStatus::AVAILABLE_STATUSES - Ci::HasStatus::STARTED_STATUSES
- context 'when the jobs are cancelable' do
- cancelable_not_started_statuses =
- Set.new(not_started_statuses).intersection(Ci::HasStatus::CANCELABLE_STATUSES)
- cancelable_not_started_statuses.each do |status|
- it "cancels all child pipeline builds when build status #{status} included" do
- # non-interruptible but non-started
- create(:ci_build, status.to_sym, pipeline: child_pipeline)
-
- expect(build_statuses(child_pipeline)).to contain_exactly('running', status)
-
- execute
-
- expect(build_statuses(child_pipeline)).to contain_exactly('canceled', 'canceled')
- end
- end
- end
-
- context 'when the jobs are not cancelable' do
- not_cancelable_not_started_statuses = not_started_statuses - Ci::HasStatus::CANCELABLE_STATUSES
- not_cancelable_not_started_statuses.each do |status|
- it "does not cancel child pipeline builds when build status #{status} included" do
- # non-interruptible but non-started
- create(:ci_build, status.to_sym, pipeline: child_pipeline)
-
- expect(build_statuses(child_pipeline)).to contain_exactly('running', status)
-
- execute
-
- expect(build_statuses(child_pipeline)).to contain_exactly('canceled', status)
- end
- end
- end
- end
- end
-
- context 'when the pipeline is a child pipeline' do
- let!(:parent_pipeline) { create(:ci_pipeline, project: project, sha: new_commit.sha) }
- let(:pipeline) { create(:ci_pipeline, child_of: parent_pipeline) }
-
- before do
- create(:ci_build, :interruptible, :running, pipeline: parent_pipeline)
- create(:ci_build, :interruptible, :running, pipeline: parent_pipeline)
- end
-
- it 'does not cancel any builds' do
- expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
- expect(build_statuses(parent_pipeline)).to contain_exactly('running', 'running')
-
- execute
-
- expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
- expect(build_statuses(parent_pipeline)).to contain_exactly('running', 'running')
- end
- end
-
- context 'when the previous pipeline source is webide' do
- let(:prev_pipeline) { create(:ci_pipeline, :webide, project: project) }
-
- it 'does not cancel builds of the previous pipeline' do
- execute
-
- expect(build_statuses(prev_pipeline)).to contain_exactly('created', 'running', 'success')
- expect(build_statuses(pipeline)).to contain_exactly('pending')
- end
- end
-
- it 'does not cancel future pipelines' do
- expect(prev_pipeline.id).to be < pipeline.id
- expect(build_statuses(pipeline)).to contain_exactly('pending')
- expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
-
- described_class.new(prev_pipeline).execute
-
- expect(build_statuses(pipeline.reload)).to contain_exactly('pending')
- end
-
- it_behaves_like 'time limits pipeline cancellation'
- end
-
- context 'when auto-cancel is disabled' do
- before do
- project.update!(auto_cancel_pending_pipelines: 'disabled')
- end
-
- it 'does not cancel any build' do
- subject
-
- expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
- expect(build_statuses(pipeline)).to contain_exactly('pending')
- end
- end
- end
- end
-
private
def build_statuses(pipeline)
diff --git a/spec/services/packages/nuget/odata_package_entry_service_spec.rb b/spec/services/packages/nuget/odata_package_entry_service_spec.rb
index d4c47538ce2..b4a22fef32b 100644
--- a/spec/services/packages/nuget/odata_package_entry_service_spec.rb
+++ b/spec/services/packages/nuget/odata_package_entry_service_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Packages::Nuget::OdataPackageEntryService, feature_category: :package_registry do
+ include GrapePathHelpers::NamedRouteMatcher
+
let_it_be(:project) { build_stubbed(:project) }
let_it_be(:params) { { package_name: 'dummy', package_version: '1.0.0' } }
let(:doc) { Nokogiri::XML(subject.payload) }
@@ -10,7 +12,7 @@ RSpec.describe Packages::Nuget::OdataPackageEntryService, feature_category: :pac
subject { described_class.new(project, params).execute }
describe '#execute' do
- shared_examples 'returning a package entry with the correct attributes' do |pkg_version, content_url_pkg_version|
+ shared_examples 'returning a package entry with the correct attributes' do |pkg_version = ''|
it 'returns a package entry with the correct attributes' do
expect(doc.root.name).to eq('entry')
expect(doc_node('id').text).to include(
@@ -18,7 +20,7 @@ RSpec.describe Packages::Nuget::OdataPackageEntryService, feature_category: :pac
)
expect(doc_node('title').text).to eq(params[:package_name])
expect(doc_node('content').attr('src')).to include(
- content_url(project.id, params[:package_name], content_url_pkg_version)
+ content_url(project.id, params[:package_name], pkg_version)
)
expect(doc_node('Version').text).to eq(pkg_version)
end
@@ -29,29 +31,17 @@ RSpec.describe Packages::Nuget::OdataPackageEntryService, feature_category: :pac
expect(subject).to be_success
end
- it_behaves_like 'returning a package entry with the correct attributes', '1.0.0', '1.0.0'
+ it_behaves_like 'returning a package entry with the correct attributes', '1.0.0'
end
- context 'when package_version is nil' do
+ context 'when package_version is not present' do
let(:params) { { package_name: 'dummy', package_version: nil } }
it 'returns a success ServiceResponse' do
expect(subject).to be_success
end
- it_behaves_like 'returning a package entry with the correct attributes',
- described_class::SEMVER_LATEST_VERSION_PLACEHOLDER, described_class::LATEST_VERSION_FOR_V2_DOWNLOAD_ENDPOINT
- end
-
- context 'when package_version is 0.0.0-latest-version' do
- let(:params) { { package_name: 'dummy', package_version: described_class::SEMVER_LATEST_VERSION_PLACEHOLDER } }
-
- it 'returns a success ServiceResponse' do
- expect(subject).to be_success
- end
-
- it_behaves_like 'returning a package entry with the correct attributes',
- described_class::SEMVER_LATEST_VERSION_PLACEHOLDER, described_class::LATEST_VERSION_FOR_V2_DOWNLOAD_ENDPOINT
+ it_behaves_like 'returning a package entry with the correct attributes'
end
end
@@ -64,6 +54,13 @@ RSpec.describe Packages::Nuget::OdataPackageEntryService, feature_category: :pac
end
def content_url(id, package_name, package_version)
- "api/v4/projects/#{id}/packages/nuget/v2/download/#{package_name}/#{package_version}"
+ if package_version.present?
+ filename = "#{package_name}.#{package_version}.nupkg"
+ api_v4_projects_packages_nuget_download_package_name_package_version_package_filename_path(
+ { id: id, package_name: package_name, package_version: package_version, package_filename: filename }, true
+ )
+ else
+ api_v4_projects_packages_nuget_v2_path(id: id)
+ end
end
end
diff --git a/spec/support/helpers/content_security_policy_helpers.rb b/spec/support/helpers/content_security_policy_helpers.rb
index 50a1bb62bc5..b12ebcbd4b9 100644
--- a/spec/support/helpers/content_security_policy_helpers.rb
+++ b/spec/support/helpers/content_security_policy_helpers.rb
@@ -24,8 +24,8 @@ any_time: false)
# ```
# find_csp_directive('connect-src')
# ```
- def find_csp_directive(key)
- csp = response.headers['Content-Security-Policy']
+ def find_csp_directive(key, header: nil)
+ csp = header || response.headers['Content-Security-Policy']
# Transform "default-src foo bar; connect-src foo bar; script-src ..."
# into array of values for a single directive based on the given key
diff --git a/spec/support/shared_examples/controllers/concerns/onboarding/redirectable_shared_examples.rb b/spec/support/shared_examples/controllers/concerns/onboarding/redirectable_shared_examples.rb
new file mode 100644
index 00000000000..b448ea16128
--- /dev/null
+++ b/spec/support/shared_examples/controllers/concerns/onboarding/redirectable_shared_examples.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Onboarding::Redirectable do
+ it { is_expected.to redirect_to dashboard_projects_path }
+
+ context 'when the new user already has any accepted group membership' do
+ let!(:single_member) { create(:group_member, invite_email: email) }
+
+ it 'redirects to activity group path with a flash message' do
+ post_create
+
+ expect(response).to redirect_to activity_group_path(single_member.source)
+ expect(controller).to set_flash[:notice].to(/You have been granted/)
+ end
+
+ context 'when the new user already has more than 1 accepted group membership' do
+ let!(:last_member) { create(:group_member, invite_email: email) }
+
+ it 'redirects to the last member activity group path without a flash message' do
+ post_create
+
+ expect(response).to redirect_to activity_group_path(last_member.source)
+ expect(controller).not_to set_flash[:notice].to(/You have been granted/)
+ end
+ end
+
+ context 'when the member has an orphaned source at the time of registering' do
+ before do
+ single_member.source.delete
+ end
+
+ it { is_expected.to redirect_to dashboard_projects_path }
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
index 1be99040ae5..0b67f12fb8d 100644
--- a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
@@ -357,12 +357,7 @@ RSpec.shared_examples 'process nuget download content request' do |user_type, st
end
context 'with normalized package version' do
- let(:normalized_version) { '0.1.0' }
- let(:url) { "/projects/#{target.id}/packages/nuget/download/#{package.name}/#{normalized_version}/#{package.name}.#{package.version}.#{format}" }
-
- before do
- package.nuget_metadatum.update_column(:normalized_version, normalized_version)
- end
+ let(:package_version) { '0.1.0' }
it_behaves_like 'returning response status', status