Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
97815325b8
commit
9297127929
|
|
@ -1 +1 @@
|
|||
49112bb2b4d8ea8e46e0f0d5e22ba2296a65a1b2
|
||||
0c10f5a60848a35049400dd775126b3ad4481663
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
},
|
||||
|
|
@ -12,25 +12,33 @@ 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 matches?(line)
|
||||
if expression
|
||||
!!(line =~ /["']#{name}['"]|#{expression}/)
|
||||
else
|
||||
!!(line =~ /["']#{name}['"]/)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def expression
|
||||
if @attributes[:pattern].is_a?(String)
|
||||
@_regexp ||= Regexp.new(Regexp.escape(@attributes[:pattern]))
|
||||
|
|
@ -39,19 +47,6 @@ module QA
|
|||
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(',')
|
||||
end
|
||||
|
||||
def additional_selectors
|
||||
@attributes.dup.delete_if { |attr| attr == :pattern || attr == :required }.map do |key, value|
|
||||
%([data-qa-#{key.to_s.tr('_', '-')}="#{value}"])
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}" \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 () => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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' }
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue