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--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue6
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_tabs.vue17
-rw-r--r--app/assets/javascripts/pipelines/constants.js2
-rw-r--r--app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue2
-rw-r--r--app/services/concerns/merge_requests/error_logger.rb31
-rw-r--r--app/services/merge_requests/base_service.rb27
-rw-r--r--app/services/merge_requests/merge_base_service.rb7
-rw-r--r--app/services/merge_requests/squash_service.rb20
-rw-r--r--app/views/admin/application_settings/_localization.html.haml2
-rw-r--r--app/views/devise/shared/_signup_omniauth_provider_list.haml4
-rw-r--r--app/views/shared/issue_type/_details_header.html.haml2
-rw-r--r--doc/administration/integration/terminal.md2
-rw-r--r--doc/administration/settings/index.md176
-rw-r--r--doc/development/code_review.md3
-rw-r--r--doc/development/integrations/index.md17
-rw-r--r--doc/development/sql.md28
-rw-r--r--doc/development/testing_guide/frontend_testing.md5
-rw-r--r--doc/integration/azure.md30
-rw-r--r--doc/user/profile/preferences.md3
-rw-r--r--patches/@vue+compat+3.2.47.patch15
-rw-r--r--qa/qa/page/element.rb33
-rw-r--r--qa/spec/page/element_spec.rb45
-rw-r--r--scripts/utils.sh3
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb14
-rw-r--r--spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js12
-rw-r--r--spec/frontend/pipelines/components/pipeline_tabs_spec.js63
-rw-r--r--spec/services/merge_requests/squash_service_spec.rb25
28 files changed, 285 insertions, 311 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index e4d7706f28a..dd9b3c2da91 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-49112bb2b4d8ea8e46e0f0d5e22ba2296a65a1b2
+0c10f5a60848a35049400dd775126b3ad4481663
diff --git a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
index ec7000120f1..f84ae13180d 100644
--- a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
+++ b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
@@ -3,10 +3,11 @@ import { GlButton, GlLink, GlTableLite } from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { __, s__ } from '~/locale';
import { createAlert } from '~/alert';
+import Tracking from '~/tracking';
import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
import RetryFailedJobMutation from '../../graphql/mutations/retry_failed_job.mutation.graphql';
-import { DEFAULT_FIELDS } from '../../constants';
+import { DEFAULT_FIELDS, TRACKING_CATEGORIES } from '../../constants';
export default {
fields: DEFAULT_FIELDS,
@@ -20,6 +21,7 @@ export default {
directives: {
SafeHtml,
},
+ mixins: [Tracking.mixin()],
props: {
failedJobs: {
type: Array,
@@ -28,6 +30,8 @@ export default {
},
methods: {
async retryJob(id) {
+ this.track('click_retry', { label: TRACKING_CATEGORIES.failed });
+
try {
const {
data: {
diff --git a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
index e14644ae0d5..35dde6379dd 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
@@ -1,12 +1,14 @@
<script>
import { GlBadge, GlTabs, GlTab } from '@gitlab/ui';
import { __ } from '~/locale';
+import Tracking from '~/tracking';
import {
failedJobsTabName,
jobsTabName,
needsTabName,
pipelineTabName,
testReportTabName,
+ TRACKING_CATEGORIES,
} from '../constants';
export default {
@@ -31,6 +33,7 @@ export default {
GlTab,
GlTabs,
},
+ mixins: [Tracking.mixin()],
inject: ['defaultTabValue', 'failedJobsCount', 'totalJobCount', 'testsCount'],
data() {
return {
@@ -56,6 +59,16 @@ export default {
this.$router.push({ name: tabName });
},
+ failedJobsTabClick() {
+ this.track('click_tab', { label: TRACKING_CATEGORIES.failed });
+
+ this.navigateTo(this.$options.tabNames.failures);
+ },
+ testsTabClick() {
+ this.track('click_tab', { label: TRACKING_CATEGORIES.tests });
+
+ this.navigateTo(this.$options.tabNames.tests);
+ },
},
};
</script>
@@ -100,7 +113,7 @@ export default {
:active="isActive($options.tabNames.failures)"
data-testid="failed-jobs-tab"
lazy
- @click="navigateTo($options.tabNames.failures)"
+ @click="failedJobsTabClick"
>
<template #title>
<span class="gl-mr-2">{{ $options.i18n.tabs.failedJobsTitle }}</span>
@@ -112,7 +125,7 @@ export default {
:active="isActive($options.tabNames.tests)"
data-testid="tests-tab"
lazy
- @click="navigateTo($options.tabNames.tests)"
+ @click="testsTabClick"
>
<template #title>
<span class="gl-mr-2">{{ $options.i18n.tabs.testsTitle }}</span>
diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js
index a6dd835bb15..d43e29dfae4 100644
--- a/app/assets/javascripts/pipelines/constants.js
+++ b/app/assets/javascripts/pipelines/constants.js
@@ -109,6 +109,8 @@ export const TRACKING_CATEGORIES = {
table: 'pipelines_table_component',
tabs: 'pipelines_filter_tabs',
search: 'pipelines_filtered_search',
+ failed: 'pipeline_failed_jobs_tab',
+ tests: 'pipeline_tests_tab',
};
// Pipeline Mini Graph
diff --git a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
index 1b7fecfde98..27276e55b13 100644
--- a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
+++ b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
@@ -192,7 +192,7 @@ export default {
>
<gl-button
icon="chevron-double-lg-left"
- class="gutter-toggle gl-display-block gl-sm-display-none!"
+ class="gl-ml-auto gl-display-block gl-sm-display-none!"
:aria-label="__('Expand sidebar')"
@click="handleRightSidebarToggleClick"
/>
diff --git a/app/services/concerns/merge_requests/error_logger.rb b/app/services/concerns/merge_requests/error_logger.rb
new file mode 100644
index 00000000000..c08525bf413
--- /dev/null
+++ b/app/services/concerns/merge_requests/error_logger.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module MergeRequests
+ module ErrorLogger
+ def log_error(exception:, message:, save_message_on_model: false)
+ reference = merge_request.to_reference(full: true)
+ data = {
+ class: self.class.name,
+ message: message,
+ merge_request_id: merge_request.id,
+ merge_request: reference,
+ save_message_on_model: save_message_on_model
+ }
+
+ if exception
+ Gitlab::ApplicationContext.with_context(user: current_user) do
+ Gitlab::ErrorTracking.track_exception(exception, data)
+ end
+
+ data[:"exception.message"] = exception.message
+ end
+
+ # TODO: Deprecate Gitlab::GitLogger since ErrorTracking should suffice:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/216379
+ data[:message] = "#{self.class.name} error (#{reference}): #{message}"
+ Gitlab::GitLogger.error(data)
+
+ merge_request.update(merge_error: message) if save_message_on_model
+ end
+ end
+end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index aaa91548d19..7074bf5bd29 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -4,6 +4,7 @@ module MergeRequests
class BaseService < ::IssuableBaseService
extend ::Gitlab::Utils::Override
include MergeRequests::AssignsMergeParams
+ include MergeRequests::ErrorLogger
delegate :repository, to: :project
@@ -260,32 +261,6 @@ module MergeRequests
end
end
- def log_error(exception:, message:, save_message_on_model: false)
- reference = merge_request.to_reference(full: true)
- data = {
- class: self.class.name,
- message: message,
- merge_request_id: merge_request.id,
- merge_request: reference,
- save_message_on_model: save_message_on_model
- }
-
- if exception
- Gitlab::ApplicationContext.with_context(user: current_user) do
- Gitlab::ErrorTracking.track_exception(exception, data)
- end
-
- data[:"exception.message"] = exception.message
- end
-
- # TODO: Deprecate Gitlab::GitLogger since ErrorTracking should suffice:
- # https://gitlab.com/gitlab-org/gitlab/-/issues/216379
- data[:message] = "#{self.class.name} error (#{reference}): #{message}"
- Gitlab::GitLogger.error(data)
-
- merge_request.update(merge_error: message) if save_message_on_model
- end
-
def trigger_merge_request_reviewers_updated(merge_request)
GraphqlTriggers.merge_request_reviewers_updated(merge_request)
end
diff --git a/app/services/merge_requests/merge_base_service.rb b/app/services/merge_requests/merge_base_service.rb
index 2a3c1e8bc26..fa0a4f808e2 100644
--- a/app/services/merge_requests/merge_base_service.rb
+++ b/app/services/merge_requests/merge_base_service.rb
@@ -60,8 +60,11 @@ module MergeRequests
end
def squash_sha!
- params[:merge_request] = merge_request
- squash_result = ::MergeRequests::SquashService.new(project: project, current_user: current_user, params: params).execute
+ squash_result = ::MergeRequests::SquashService.new(
+ merge_request: merge_request,
+ current_user: current_user,
+ commit_message: params[:squash_commit_message]
+ ).execute
case squash_result[:status]
when :success
diff --git a/app/services/merge_requests/squash_service.rb b/app/services/merge_requests/squash_service.rb
index f04682bf08a..0b1aefb30d7 100644
--- a/app/services/merge_requests/squash_service.rb
+++ b/app/services/merge_requests/squash_service.rb
@@ -1,7 +1,17 @@
# frozen_string_literal: true
module MergeRequests
- class SquashService < MergeRequests::BaseService
+ class SquashService
+ include BaseServiceUtility
+ include MergeRequests::ErrorLogger
+
+ def initialize(merge_request:, current_user:, commit_message:)
+ @merge_request = merge_request
+ @target_project = merge_request.target_project
+ @current_user = current_user
+ @commit_message = commit_message
+ end
+
def execute
# If performing a squash would result in no change, then
# immediately return a success message without performing a squash
@@ -16,6 +26,8 @@ module MergeRequests
private
+ attr_reader :merge_request, :target_project, :current_user, :commit_message
+
def squash!
squash_sha = repository.squash(current_user, merge_request, message)
@@ -34,12 +46,8 @@ module MergeRequests
target_project.repository
end
- def merge_request
- params[:merge_request]
- end
-
def message
- params[:squash_commit_message].presence || merge_request.default_squash_commit_message(user: current_user)
+ commit_message.presence || merge_request.default_squash_commit_message(user: current_user)
end
end
end
diff --git a/app/views/admin/application_settings/_localization.html.haml b/app/views/admin/application_settings/_localization.html.haml
index 19d321ca205..4002aa076f7 100644
--- a/app/views/admin/application_settings/_localization.html.haml
+++ b/app/views/admin/application_settings/_localization.html.haml
@@ -7,7 +7,7 @@
= f.select :first_day_of_week, first_day_of_week_choices, {}, class: 'form-control'
.form-text.text-muted
= _('Default first day of the week in calendars and date pickers.')
- = link_to _('Learn more.'), help_page_path('administration/settings/index.md', anchor: 'default-first-day-of-the-week'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to _('Learn more.'), help_page_path('administration/settings/index.md', anchor: 'change-the-default-first-day-of-the-week'), target: '_blank', rel: 'noopener noreferrer'
.form-group
= f.label :time_tracking, _('Time tracking'), class: 'label-bold'
diff --git a/app/views/devise/shared/_signup_omniauth_provider_list.haml b/app/views/devise/shared/_signup_omniauth_provider_list.haml
index 60c37316c62..e8c82e456ae 100644
--- a/app/views/devise/shared/_signup_omniauth_provider_list.haml
+++ b/app/views/devise/shared/_signup_omniauth_provider_list.haml
@@ -4,7 +4,7 @@
= _("Register with:")
.gl-text-center.gl-ml-auto.gl-mr-auto
- providers.each do |provider|
- = render Pajamas::ButtonComponent.new(href: omniauth_authorize_path(:user, provider, register_omniauth_params(local_assigns)), method: :post, variant: :default, button_options: { class: "gl-w-full gl-mb-4 js-oauth-login #{qa_selector_for_provider(provider)}", data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label}, id: "oauth-login-#{provider}" }) do
+ = button_to omniauth_authorize_path(:user, provider, register_omniauth_params(local_assigns)), class: "btn gl-button btn-default gl-w-full gl-mb-4 js-oauth-login #{qa_selector_for_provider(provider)}", data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label }, id: "oauth-login-#{provider}" do
- if provider_has_icon?(provider)
= provider_image_tag(provider)
%span.gl-button-text
@@ -14,7 +14,7 @@
= _("Create an account using:")
.gl-display-flex.gl-justify-content-between.gl-flex-wrap
- providers.each do |provider|
- = render Pajamas::ButtonComponent.new(href: omniauth_authorize_path(:user, provider, register_omniauth_params(local_assigns)), method: :post, variant: :default, button_options: { class: "gl-w-full gl-mb-4 js-oauth-login #{qa_selector_for_provider(provider)}", data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label}, id: "oauth-login-#{provider}" }) do
+ = button_to omniauth_authorize_path(:user, provider, register_omniauth_params(local_assigns)), class: "btn gl-button btn-default gl-w-full gl-mb-4 js-oauth-login #{qa_selector_for_provider(provider)}", data: { provider: provider, track_action: "#{provider}_sso", track_label: tracking_label }, id: "oauth-login-#{provider}" do
- if provider_has_icon?(provider)
= provider_image_tag(provider)
%span.gl-button-text
diff --git a/app/views/shared/issue_type/_details_header.html.haml b/app/views/shared/issue_type/_details_header.html.haml
index 4997d429587..558287480e1 100644
--- a/app/views/shared/issue_type/_details_header.html.haml
+++ b/app/views/shared/issue_type/_details_header.html.haml
@@ -16,6 +16,6 @@
#js-issuable-header-warnings{ data: { hidden: issue_hidden?(issuable).to_s } }
= issuable_meta(issuable, @project)
- = render Pajamas::ButtonComponent.new(href: '#', icon: 'chevron-double-lg-left', button_options: { class: 'gl-float-right gl-display-block gl-sm-display-none! gutter-toggle issuable-gutter-toggle js-sidebar-toggle' })
+ = render Pajamas::ButtonComponent.new(href: '#', icon: 'chevron-double-lg-left', button_options: { class: 'gl-ml-auto gl-display-block gl-sm-display-none! js-sidebar-toggle' })
.js-issue-header-actions{ data: issue_header_actions_data(@project, issuable, current_user, @issuable_sidebar) }
diff --git a/doc/administration/integration/terminal.md b/doc/administration/integration/terminal.md
index 1ab45d6ce99..add036ea5ec 100644
--- a/doc/administration/integration/terminal.md
+++ b/doc/administration/integration/terminal.md
@@ -114,5 +114,5 @@ lifetime in your GitLab instance:
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
-1. Select [**Settings > Web terminal**](../../administration/settings/index.md#general).
+1. Select **Settings > Web terminal**.
1. Set a `max session time`.
diff --git a/doc/administration/settings/index.md b/doc/administration/settings/index.md
index 067add353eb..a5746ad26e4 100644
--- a/doc/administration/settings/index.md
+++ b/doc/administration/settings/index.md
@@ -21,180 +21,8 @@ To access the **Admin Area**:
1. Sign in to your GitLab instance as an administrator.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
-1. Select **Settings**, and the group of settings to view:
- - [General](#general)
- - [Geo](#geo)
- - [CI/CD](#cicd)
- - [Integrations](#integrations)
- - [Metrics and profiling](#metrics-and-profiling)
- - [Network](#network)
- - [Preferences](#preferences)
- - [Reporting](#reporting)
- - [Repository](#repository)
- - [Templates](#templates)
-### General
-
-The **General** settings contain:
-
-- [Visibility and access controls](../settings/visibility_and_access_controls.md) - Set default and
- restrict visibility levels. Configure import sources and Git access protocol.
-- [Account and limit](../settings/account_and_limit_settings.md) - Set projects and maximum size limits,
- session duration, user options, and check feature availability for namespace plan.
-- [Diff limits](../diff_limits.md) - Diff content limits.
-- [Sign-up restrictions](../settings/sign_up_restrictions.md) - Configure the way a user creates a new account.
-- [Sign in restrictions](../settings/sign_in_restrictions.md) - Set requirements for a user to sign in.
- Enable mandatory two-factor authentication.
-- [Terms of Service and Privacy Policy](../settings/terms.md) - Include a Terms of Service agreement
- and Privacy Policy that all users must accept.
-- [External Authentication](../../administration/settings/external_authorization.md#configuration) - External Classification Policy Authorization.
-- [Web terminal](../integration/terminal.md#limiting-websocket-connection-time) -
- Set max session time for web terminal.
-- [FLoC](floc.md) - Enable or disable
- [Federated Learning of Cohorts (FLoC)](https://en.wikipedia.org/wiki/Federated_Learning_of_Cohorts) tracking.
-- [GitLab for Slack app](slack_app.md) - Enable and configure the GitLab for Slack app.
-
-### CI/CD
-
-The **CI/CD** settings contain:
-
-- [Continuous Integration and Deployment](../../administration/settings/continuous_integration.md) -
- Auto DevOps, runners and job artifacts.
-- [Required pipeline configuration](../../administration/settings/continuous_integration.md#required-pipeline-configuration) -
- Set an instance-wide auto included [pipeline configuration](../../ci/yaml/index.md).
- This pipeline configuration is run after the project's own configuration.
-- [Package Registry](../../administration/settings/continuous_integration.md#package-registry-configuration) -
- Settings related to the use and experience of using the GitLab Package Registry. Some
- [risks are involved](../../user/packages/container_registry/reduce_container_registry_storage.md#use-with-external-container-registries)
- in enabling some of these settings.
-
-## Security and Compliance settings
-
-- [License compliance settings](security_and_compliance.md#choose-package-registry-metadata-to-sync): Enable or disable synchronization of package metadata by a registry type.
-
-### Geo **(PREMIUM SELF)**
-
-The **Geo** setting contains:
-
-- [Geo](../geo/index.md) - Replicate your GitLab instance to other
- geographical locations. Redirects to **Admin Area > Geo > Settings** are no
- longer available at **Admin Area > Settings > Geo** in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/36896).
-
-### Integrations
-
-The **Integrations** settings contain:
-
-- [Elasticsearch](../../integration/advanced_search/elasticsearch.md#enable-advanced-search) -
- Elasticsearch integration. Elasticsearch AWS IAM.
-- [Kroki](../integration/kroki.md#enable-kroki-in-gitlab) -
- Allow rendering of diagrams in AsciiDoc and Markdown documents using [kroki.io](https://kroki.io).
-- [Mailgun](../integration/mailgun.md) - Enable your GitLab instance
- to receive invite email bounce events from Mailgun, if it is your email provider.
-- [PlantUML](../integration/plantuml.md) - Allow rendering of PlantUML
- diagrams in documents.
-- [Customer experience improvement and third-party offers](../settings/third_party_offers.md) -
- Control the display of customer experience improvement content and third-party offers.
-- [Snowplow](../../development/internal_analytics/snowplow/index.md) - Configure the Snowplow integration.
-- [Google GKE](../../user/project/clusters/add_gke_clusters.md) - Google GKE integration enables
- you to provision GKE clusters from GitLab.
-- [Amazon EKS](../../user/project/clusters/add_eks_clusters.md) - Amazon EKS integration enables
- you to provision EKS clusters from GitLab.
-
-### Metrics and profiling
-
-The **Metrics and profiling** settings contain:
-
-- [Metrics - Prometheus](../monitoring/prometheus/gitlab_metrics.md) -
- Enable and configure Prometheus metrics.
-- [Metrics - Grafana](../monitoring/performance/grafana_configuration.md#integrate-with-gitlab-ui) -
- Enable and configure Grafana.
-- [Profiling - Performance bar](../monitoring/performance/performance_bar.md#enable-the-performance-bar-for-non-administrators) -
- Enable access to the Performance Bar for non-administrator users in a given group.
-- [Usage statistics](../settings/usage_statistics.md) - Enable or disable version check and Service Ping.
-
-### Network
-
-The **Network** settings contain:
-
-- Performance optimization - Various settings that affect GitLab performance, including:
- - [Write to `authorized_keys` file](../operations/fast_ssh_key_lookup.md#set-up-fast-lookup).
- - [Push event activities limit and bulk push events](../settings/push_event_activities_limit.md).
-- [User and IP rate limits](../settings/user_and_ip_rate_limits.md) - Configure limits for web and API requests.
- These rate limits can be overridden:
- - [Package Registry Rate Limits](../settings/package_registry_rate_limits.md) - Configure specific
- limits for Packages API requests that supersede the user and IP rate limits.
- - [Git LFS Rate Limits](../settings/git_lfs_rate_limits.md) - Configure specific limits for
- Git LFS requests that supersede the user and IP rate limits.
- - [Files API Rate Limits](../settings/files_api_rate_limits.md) - Configure specific limits for
- Files API requests that supersede the user and IP rate limits.
- - [Search rate limits](../instance_limits.md#search-rate-limit) - Configure global search request rate limits for authenticated and unauthenticated users.
- - [Deprecated API Rate Limits](../settings/deprecated_api_rate_limits.md) - Configure specific limits
- for deprecated API requests that supersede the user and IP rate limits.
-- [Outbound requests](../../security/webhooks.md) - Allow requests to the local network from webhooks and integrations, or deny all outbound requests.
-- [Protected Paths](../settings/protected_paths.md) - Configure paths to be protected by Rack Attack.
-- [Incident Management Limits](../../operations/incident_management/index.md) - Limit the
- number of inbound alerts that can be sent to a project.
-- [Notes creation limit](../settings/rate_limit_on_notes_creation.md) - Set a rate limit on the note creation requests.
-- [Get single user limit](../settings/rate_limit_on_users_api.md) - Set a rate limit on users API endpoint to get a user by ID.
-- [Projects API rate limits for unauthenticated requests](../settings/rate_limit_on_projects_api.md) - Set a rate limit on Projects list API endpoint for unauthenticated requests.
-
-### Preferences
-
-The **Preferences** settings contain:
-
-- [Email](../settings/email.md) - Various email settings.
-- [What's new](../whats-new.md) - Configure **What's new** drawer and content.
-- [Help page](help_page.md) - Help page text and support page URL.
-- [Pages](../pages/index.md#custom-domain-verification) -
- Size and domain settings for static websites.
-- [Polling interval multiplier](../polling.md) -
- Configure how frequently the GitLab UI polls for updates.
-- [Gitaly timeouts](gitaly_timeouts.md) - Configure Gitaly timeouts.
-- Localization:
- - [Default first day of the week](../../user/profile/preferences.md).
- - [Time tracking](../../user/project/time_tracking.md#limit-displayed-units-to-hours).
-- [Sidekiq Job Limits](../settings/sidekiq_job_limits.md) - Limit the size of Sidekiq jobs stored in Redis.
-
-### Reporting
-
-The **Reporting** settings contain:
-
-- Spam and Anti-bot protection:
- - Anti-spam services, such as [reCAPTCHA](../../integration/recaptcha.md),
- [Akismet](../../integration/akismet.md), or [Spamcheck](../reporting/spamcheck.md).
- - [IP address restrictions](../reporting/ip_addr_restrictions.md).
-- [Abuse reports](../review_abuse_reports.md) - Set notification email for abuse reports.
-- [Git abuse rate limit](../reporting/git_abuse_rate_limit.md) - Configure Git abuse rate limit settings. **(ULTIMATE SELF)**
-
-### Repository
-
-The **Repository** settings contain:
-
-- [Repository's custom initial branch name](../../user/project/repository/branches/default.md#instance-level-custom-initial-branch-name) -
- Set a custom branch name for new repositories created in your instance.
-- [Repository's initial default branch protection](../../user/project/repository/branches/default.md#instance-level-default-branch-protection) -
- Configure the branch protections to apply to every repository's default branch.
-- [Repository mirror](visibility_and_access_controls.md#enable-project-mirroring) -
- Configure repository mirroring.
-- [Repository storage](../repository_storage_types.md) - Configure storage path settings.
-- Repository maintenance:
- - [Repository checks](../repository_checks.md) - Configure
- automatic Git checks on repositories.
- - [Housekeeping](../housekeeping.md). Configure automatic
- Git housekeeping on repositories.
- - [Inactive project deletion](../inactive_project_deletion.md). Configure inactive
- project deletion.
-- [Repository static objects](../static_objects_external_storage.md) -
- Serve repository static objects (for example, archives and blobs) from an external storage (for example, a CDN).
-
-### Templates **(PREMIUM SELF)**
-
-The **Templates** settings contain:
-
-- [Templates](instance_template_repository.md#configuration) - Set instance-wide template repository.
-- [Custom project templates](../custom_project_templates.md) - Select the custom project template source group.
-
-## Default first day of the week
+## Change the default first day of the week
You can change the [Default first day of the week](../../user/profile/preferences.md)
for the entire GitLab instance:
@@ -204,7 +32,7 @@ for the entire GitLab instance:
1. Select **Settings > Preferences**.
1. Scroll to the **Localization** section, and select your desired first day of the week.
-## Default language
+## Change the default language
You can change the [Default language](../../user/profile/preferences.md)
for the entire GitLab instance:
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 6aedb18c15d..f3c3062e217 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -201,7 +201,8 @@ by a reviewer before passing it to a maintainer as described in the
on the line of code in question with the SQL queries so they can give their advice.
1. User-facing changes include both visual changes (regardless of how minor),
and changes to the rendered DOM which impact how a screen reader may announce
- the content.
+ the content. Groups that do not have dedicated Product
+ Designers do not require a Product Designer to approve feature changes, unless the changes are community contributions.
1. End-to-end changes include all files in the `qa` directory.
#### Acceptance checklist
diff --git a/doc/development/integrations/index.md b/doc/development/integrations/index.md
index a01e35349cb..9c0a64c68b5 100644
--- a/doc/development/integrations/index.md
+++ b/doc/development/integrations/index.md
@@ -123,6 +123,23 @@ module Integrations
end
```
+### Security enhancement features
+
+#### Masking channel values
+
+Integrations that [inherit from `Integrations::BaseChatNotification`](#define-the-integration) can hide the
+values of their channel input fields. Integrations should hide these values whenever the
+fields contain sensitive information such as auth tokens.
+
+By default, `#mask_configurable_channels?` returns `false`. To mask the channel values, override the `#mask_configurable_channels?` method in the integration to return `true`:
+
+```ruby
+override :mask_configurable_channels?
+def mask_configurable_channels?
+ true
+end
+```
+
## Define configuration test
Optionally, you can define a configuration test of an integration's settings. The test is executed from the integration form's **Test** button, and results are returned to the user.
diff --git a/doc/development/sql.md b/doc/development/sql.md
index 1e3e5c7d0f6..101ccc239e7 100644
--- a/doc/development/sql.md
+++ b/doc/development/sql.md
@@ -315,6 +315,30 @@ union = Gitlab::SQL::Union.new([projects, more_projects, ...])
Project.from("(#{union.to_sql}) projects")
```
+The `FromUnion` model concern provides a more convenient method to produce the same result as above:
+
+```ruby
+class Project
+ include FromUnion
+ ...
+end
+
+Project.from_union(projects, more_projects, ...)
+```
+
+`UNION` is common through the codebase, but it's also possible to use the other SQL set operators of `EXCEPT` and `INTERSECT`:
+
+```ruby
+class Project
+ include FromIntersect
+ include FromExcept
+ ...
+end
+
+intersected = Project.from_intersect(all_projects, project_set_1, project_set_2)
+excepted = Project.from_except(all_projects, project_set_1, project_set_2)
+```
+
### Uneven columns in the `UNION` sub-queries
When the `UNION` query has uneven columns in the `SELECT` clauses, the database returns an error.
@@ -479,8 +503,8 @@ Simple usage of the `.upsert` method:
BuildTrace.upsert(
{
build_id: build_id,
- title: title
- },
+ title: title
+ },
unique_by: :build_id
)
```
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 1b50bd410c2..825a5e9f49b 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -228,16 +228,13 @@ it('exists', () => {
// Bad
wrapper.find('.js-foo');
wrapper.find('.btn-primary');
- wrapper.find('.qa-foo-component');
});
```
-It is recommended to use `kebab-case` for `data-testid` attribute.
+You should use `kebab-case` for `data-testid` attribute.
It is not recommended that you add `.js-*` classes just for testing purposes. Only do this if there are no other feasible options available.
-Do not use `.qa-*` class attributes for any tests other than QA end-to-end testing.
-
### Querying for child components
When testing Vue components with `@vue/test-utils` another possible approach is querying for child
diff --git a/doc/integration/azure.md b/doc/integration/azure.md
index ffd6ccc4888..4ef47a0ac51 100644
--- a/doc/integration/azure.md
+++ b/doc/integration/azure.md
@@ -326,3 +326,33 @@ Alternatively, add the `User.Read.All` application permission.
Read [Enable OmniAuth for an existing user](omniauth.md#enable-omniauth-for-an-existing-user)
for information on how existing GitLab users can connect to their new Azure AD accounts.
+
+## Troubleshooting
+
+### User sign in banner message: Extern UID has already been taken
+
+When signing in, you might get an error that states `Extern UID has already been taken`.
+
+To resolve this, use the [Rails console](../administration/operations/rails_console.md#starting-a-rails-console-session) to check if there is an existing user tied to the account:
+
+1. Find the `extern_uid`:
+
+ ```ruby
+ id = Identity.where(extern_uid: '<extern_uid>')
+ ```
+
+1. Print the content to find the username attached to that `extern_uid`:
+
+ ```ruby
+ pp id
+ ```
+
+If the `extern_uid` is attached to an account, you can use the username to sign in.
+
+If the `extern_uid` is not attached to any username, this might be because of a deletion error resulting in a ghost record.
+
+Run the following command to delete the identity to release the `extern uid`:
+
+```ruby
+ Identity.find('<id>').delete
+```
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index 17dea99e5ef..166833cc84f 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -157,7 +157,8 @@ You can choose one of the following options as the first day of the week:
- Sunday
- Monday
-If you select **System Default**, the [instance default](../../administration/settings/index.md#default-first-day-of-the-week) setting is used.
+If you select **System Default**, the first day of the week is set to the
+[instance default](../../administration/settings/index.md#change-the-default-first-day-of-the-week).
## Time preferences
diff --git a/patches/@vue+compat+3.2.47.patch b/patches/@vue+compat+3.2.47.patch
new file mode 100644
index 00000000000..20ee26a0308
--- /dev/null
+++ b/patches/@vue+compat+3.2.47.patch
@@ -0,0 +1,15 @@
+diff --git a/node_modules/@vue/compat/dist/vue.cjs.js b/node_modules/@vue/compat/dist/vue.cjs.js
+index 0d10385..d1a5185 100644
+--- a/node_modules/@vue/compat/dist/vue.cjs.js
++++ b/node_modules/@vue/compat/dist/vue.cjs.js
+@@ -5877,9 +5877,7 @@ function installCompatInstanceProperties(map) {
+ const res = {};
+ for (const key in i.slots) {
+ const fn = i.slots[key];
+- if (!fn._ns /* non-scoped slot */) {
+- res[key] = fn;
+- }
++ res[key] = fn;
+ }
+ return res;
+ },
diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb
index 5d36f8030b7..ec8aca76250 100644
--- a/qa/qa/page/element.rb
+++ b/qa/qa/page/element.rb
@@ -12,44 +12,39 @@ module QA
def initialize(name, *options)
@name = name
@attributes = options.extract_options!
- @attributes[:pattern] ||= selector
options.each do |option|
@attributes[:pattern] = option if option.is_a?(String) || option.is_a?(Regexp)
end
end
- def selector
- "qa-#{@name.to_s.tr('_', '-')}"
- end
-
def required?
!!@attributes[:required]
end
def selector_css
- %(#{qa_selector}#{additional_selectors},.#{selector})
+ [
+ %([data-testid="#{name}"]#{additional_selectors}),
+ %([data-qa-selector="#{name}"]#{additional_selectors})
+ ].join(',')
end
- def expression
- if @attributes[:pattern].is_a?(String)
- @_regexp ||= Regexp.new(Regexp.escape(@attributes[:pattern]))
+ def matches?(line)
+ if expression
+ !!(line =~ /["']#{name}['"]|#{expression}/)
else
- @attributes[:pattern]
+ !!(line =~ /["']#{name}['"]/)
end
end
- def matches?(line)
- !!(line =~ /["']#{name}['"]|#{expression}/)
- end
-
private
- def qa_selector
- [
- %([data-testid="#{name}"]#{additional_selectors}),
- %([data-qa-selector="#{name}"]#{additional_selectors})
- ].join(',')
+ def expression
+ if @attributes[:pattern].is_a?(String)
+ @_regexp ||= Regexp.new(Regexp.escape(@attributes[:pattern]))
+ else
+ @attributes[:pattern]
+ end
end
def additional_selectors
diff --git a/qa/spec/page/element_spec.rb b/qa/spec/page/element_spec.rb
index da1fd224564..c354d55fb19 100644
--- a/qa/spec/page/element_spec.rb
+++ b/qa/spec/page/element_spec.rb
@@ -1,17 +1,10 @@
# frozen_string_literal: true
RSpec.describe QA::Page::Element do
- describe '#selector' do
- it 'transforms element name into QA-specific selector' do
- expect(described_class.new(:sign_in_button).selector)
- .to eq 'qa-sign-in-button'
- end
- end
-
describe '#selector_css' do
it 'transforms element name into QA-specific clickable css selector' do
expect(described_class.new(:sign_in_button).selector_css)
- .to include('.qa-sign-in-button')
+ .to eq('[data-testid="sign_in_button"],[data-qa-selector="sign_in_button"]')
end
end
@@ -42,10 +35,6 @@ RSpec.describe QA::Page::Element do
context 'when pattern is not provided' do
subject { described_class.new(:some_name) }
- it 'matches when QA specific selector is present' do
- expect(subject.matches?('some qa-some-name selector')).to be true
- end
-
it 'does not match if QA selector is not there' do
expect(subject.matches?('some_name selector')).to be false
end
@@ -53,15 +42,18 @@ RSpec.describe QA::Page::Element do
it 'matches when element name is specified' do
expect(subject.matches?('data:{qa:{selector:"some_name"}}')).to be true
end
+
+ it 'matches when element name is specified (single quotes)' do
+ expect(subject.matches?("data:{qa:{selector:'some_name'}}")).to be true
+ end
end
describe 'attributes' do
context 'element with no args' do
subject { described_class.new(:something) }
- it 'defaults pattern to #selector' do
- expect(subject.attributes[:pattern]).to eq 'qa-something'
- expect(subject.attributes[:pattern]).to eq subject.selector
+ it 'has no attribute[pattern]' do
+ expect(subject.attributes[:pattern]).to be(nil)
end
it 'is not required by default' do
@@ -84,11 +76,6 @@ RSpec.describe QA::Page::Element do
context 'element with requirement; no pattern' do
subject { described_class.new(:something, required: true) }
- it 'has an attribute[pattern] of the selector' do
- expect(subject.attributes[:pattern]).to eq 'qa-something'
- expect(subject.attributes[:pattern]).to eq subject.selector
- end
-
it 'is required' do
expect(subject.required?).to be true
end
@@ -104,10 +91,6 @@ RSpec.describe QA::Page::Element do
it 'is required' do
expect(subject.required?).to be true
end
-
- it 'has a selector of the name' do
- expect(subject.selector).to eq 'qa-something'
- end
end
end
@@ -126,18 +109,20 @@ RSpec.describe QA::Page::Element do
let(:element) { described_class.new(:my_element, index: 3, another_match: 'something') }
let(:required_element) { described_class.new(:my_element, required: true, index: 3) }
- it 'matches on additional data-qa properties' do
- expect(element.selector_css).to include(%q([data-qa-selector="my_element"][data-qa-index="3"]))
+ it 'matches on additional data-qa properties translating snake_case to kebab-case' do
+ expect(element.selector_css)
+ .to include('[data-testid="my_element"][data-qa-index="3"][data-qa-another-match="something"]')
+ expect(element.selector_css)
+ .to include('[data-qa-selector="my_element"][data-qa-index="3"][data-qa-another-match="something"]')
end
it 'doesnt conflict with element requirement' do
+ expect(element).not_to be_required
+ expect(element.selector_css).not_to include(%q(data-qa-required))
+
expect(required_element).to be_required
expect(required_element.selector_css).not_to include(%q(data-qa-required))
end
-
- it 'translates snake_case to kebab-case' do
- expect(element.selector_css).to include(%q(data-qa-another-match))
- end
end
end
end
diff --git a/scripts/utils.sh b/scripts/utils.sh
index e19622d07c6..13a051e2b58 100644
--- a/scripts/utils.sh
+++ b/scripts/utils.sh
@@ -438,8 +438,9 @@ function download_local_gems() {
echo "Downloading ${folder_path}"
- url=${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/repository/archive
+ url="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/repository/archive"
curl -f \
+ --create-dirs \
--get \
--header "${private_token_header}" \
--output "${output}" \
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index f78d50bba24..0e3e3f31783 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -658,21 +658,17 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
let(:message) { 'My custom squash commit message' }
it 'passes the same message to SquashService', :sidekiq_inline do
- params = { squash: '1',
- squash_commit_message: message,
- sha: merge_request.diff_head_sha }
- expected_squash_params = { squash_commit_message: message,
- sha: merge_request.diff_head_sha,
- merge_request: merge_request }
-
- expect_next_instance_of(MergeRequests::SquashService, project: project, current_user: user, params: expected_squash_params) do |squash_service|
+ expect_next_instance_of(MergeRequests::SquashService,
+ merge_request: merge_request,
+ current_user: user,
+ commit_message: message) do |squash_service|
expect(squash_service).to receive(:execute).and_return({
status: :success,
squash_sha: SecureRandom.hex(20)
})
end
- merge_with_sha(params)
+ merge_with_sha(squash: '1', squash_commit_message: message, sha: merge_request.diff_head_sha)
end
end
diff --git a/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js b/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
index d5307b87a11..99a178120cc 100644
--- a/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
+++ b/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
@@ -2,12 +2,14 @@ import { GlButton, GlLink, GlTableLite } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { createAlert } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
import FailedJobsTable from '~/pipelines/components/jobs/failed_jobs_table.vue';
import RetryFailedJobMutation from '~/pipelines/graphql/mutations/retry_failed_job.mutation.graphql';
+import { TRACKING_CATEGORIES } from '~/pipelines/constants';
import {
successRetryMutationResponse,
failedRetryMutationResponse,
@@ -71,7 +73,9 @@ describe('Failed Jobs Table', () => {
expect(findFirstFailureMessage().text()).toBe('Job failed');
});
- it('calls the retry failed job mutation correctly', () => {
+ it('calls the retry failed job mutation and tracks the click', () => {
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+
createComponent(successRetryMutationHandler);
findRetryButton().trigger('click');
@@ -79,6 +83,12 @@ describe('Failed Jobs Table', () => {
expect(successRetryMutationHandler).toHaveBeenCalledWith({
id: mockFailedJobsData[0].id,
});
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_retry', {
+ label: TRACKING_CATEGORIES.failed,
+ });
+
+ unmockTracking();
});
it('redirects to the new job after the mutation', async () => {
diff --git a/spec/frontend/pipelines/components/pipeline_tabs_spec.js b/spec/frontend/pipelines/components/pipeline_tabs_spec.js
index fde13128662..0951e1ffb46 100644
--- a/spec/frontend/pipelines/components/pipeline_tabs_spec.js
+++ b/spec/frontend/pipelines/components/pipeline_tabs_spec.js
@@ -1,10 +1,14 @@
-import { shallowMount } from '@vue/test-utils';
import { GlTab } from '@gitlab/ui';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import PipelineTabs from '~/pipelines/components/pipeline_tabs.vue';
+import { TRACKING_CATEGORIES } from '~/pipelines/constants';
describe('The Pipeline Tabs', () => {
let wrapper;
+ let trackingSpy;
+
+ const $router = { push: jest.fn() };
const findDagTab = () => wrapper.findByTestId('dag-tab');
const findFailedJobsTab = () => wrapper.findByTestId('failed-jobs-tab');
@@ -24,18 +28,19 @@ describe('The Pipeline Tabs', () => {
};
const createComponent = (provide = {}) => {
- wrapper = extendedWrapper(
- shallowMount(PipelineTabs, {
- provide: {
- ...defaultProvide,
- ...provide,
- },
- stubs: {
- GlTab,
- RouterView: true,
- },
- }),
- );
+ wrapper = shallowMountExtended(PipelineTabs, {
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ stubs: {
+ GlTab,
+ RouterView: true,
+ },
+ mocks: {
+ $router,
+ },
+ });
};
describe('Tabs', () => {
@@ -76,4 +81,34 @@ describe('The Pipeline Tabs', () => {
expect(badgeComponent().text()).toBe(badgeText);
});
});
+
+ describe('Tab tracking', () => {
+ beforeEach(() => {
+ createComponent();
+
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('tracks failed jobs tab click', () => {
+ findFailedJobsTab().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', {
+ label: TRACKING_CATEGORIES.failed,
+ });
+ });
+
+ it('tracks tests tab click', () => {
+ findTestsTab().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', {
+ label: TRACKING_CATEGORIES.tests,
+ });
+ });
+ });
});
diff --git a/spec/services/merge_requests/squash_service_spec.rb b/spec/services/merge_requests/squash_service_spec.rb
index 1afca466fb5..ecbe2d7e097 100644
--- a/spec/services/merge_requests/squash_service_spec.rb
+++ b/spec/services/merge_requests/squash_service_spec.rb
@@ -3,16 +3,19 @@
require 'spec_helper'
RSpec.describe MergeRequests::SquashService, feature_category: :source_code_management do
- let(:service) { described_class.new(project: project, current_user: user, params: { merge_request: merge_request }) }
- let(:user) { project.first_owner }
- let(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { project.first_owner }
+
+ let(:service) { described_class.new(merge_request: merge_request, current_user: user, commit_message: commit_message) }
+ let(:commit_message) { nil }
let(:repository) { project.repository.raw }
let(:log_error) { "Failed to squash merge request #{merge_request.to_reference(full: true)}:" }
+
let(:squash_dir_path) do
File.join(Gitlab.config.shared.path, 'tmp/squash', repository.gl_repository, merge_request.id.to_s)
end
- let(:merge_request_with_one_commit) do
+ let_it_be(:merge_request_with_one_commit) do
create(
:merge_request,
source_branch: 'feature', source_project: project,
@@ -20,7 +23,7 @@ RSpec.describe MergeRequests::SquashService, feature_category: :source_code_mana
)
end
- let(:merge_request_with_only_new_files) do
+ let_it_be(:merge_request_with_only_new_files) do
create(
:merge_request,
source_branch: 'video', source_project: project,
@@ -28,7 +31,7 @@ RSpec.describe MergeRequests::SquashService, feature_category: :source_code_mana
)
end
- let(:merge_request_with_large_files) do
+ let_it_be(:merge_request_with_large_files) do
create(
:merge_request,
source_branch: 'squash-large-files', source_project: project,
@@ -66,7 +69,7 @@ RSpec.describe MergeRequests::SquashService, feature_category: :source_code_mana
end
context 'when squash message matches commit message' do
- let(:service) { described_class.new(project: project, current_user: user, params: { merge_request: merge_request, squash_commit_message: merge_request.first_commit.safe_message }) }
+ let(:commit_message) { merge_request.first_commit.safe_message }
it 'returns that commit SHA' do
result = service.execute
@@ -82,7 +85,7 @@ RSpec.describe MergeRequests::SquashService, feature_category: :source_code_mana
end
context 'when squash message matches commit message but without trailing new line' do
- let(:service) { described_class.new(project: project, current_user: user, params: { merge_request: merge_request, squash_commit_message: merge_request.first_commit.safe_message.strip }) }
+ let(:commit_message) { merge_request.first_commit.safe_message.strip }
it 'returns that commit SHA' do
result = service.execute
@@ -98,7 +101,7 @@ RSpec.describe MergeRequests::SquashService, feature_category: :source_code_mana
end
end
- context 'the squashed commit' do
+ describe 'the squashed commit' do
let(:squash_sha) { service.execute[:squash_sha] }
let(:squash_commit) { project.repository.commit(squash_sha) }
@@ -125,7 +128,7 @@ RSpec.describe MergeRequests::SquashService, feature_category: :source_code_mana
end
context 'if a message was provided' do
- let(:service) { described_class.new(project: project, current_user: user, params: { merge_request: merge_request, squash_commit_message: message }) }
+ let(:commit_message) { message }
let(:message) { 'My custom message' }
let(:squash_sha) { service.execute[:squash_sha] }
@@ -191,7 +194,7 @@ RSpec.describe MergeRequests::SquashService, feature_category: :source_code_mana
include_examples 'the squash succeeds'
end
- context 'git errors' do
+ describe 'git errors' do
let(:merge_request) { merge_request_with_only_new_files }
let(:error) { 'A test error' }