Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-01-14 06:11:16 +00:00
parent 04698e448a
commit 298ae510ce
40 changed files with 622 additions and 184 deletions

View File

@ -113,7 +113,7 @@ gem 'carrierwave', '~> 1.3'
gem 'mini_magick', '~> 4.10.1'
# for backups
gem 'fog-aws', '~> 3.7'
gem 'fog-aws', '~> 3.8'
# Locked until fog-google resolves https://github.com/fog/fog-google/issues/421.
# Also see config/initializers/fog_core_patch.rb.
gem 'fog-core', '= 2.1.0'

View File

@ -360,7 +360,7 @@ GEM
fog-json
ipaddress (~> 0.8)
xml-simple (~> 1.1)
fog-aws (3.7.0)
fog-aws (3.8.0)
fog-core (~> 2.1)
fog-json (~> 1.1)
fog-xml (~> 0.1)
@ -1346,7 +1346,7 @@ DEPENDENCIES
flipper-active_support_cache_store (~> 0.17.1)
flowdock (~> 0.7)
fog-aliyun (~> 0.3)
fog-aws (~> 3.7)
fog-aws (~> 3.8)
fog-core (= 2.1.0)
fog-google (~> 1.12)
fog-local (~> 0.6)

View File

@ -1,4 +1,5 @@
import { sortBy } from 'lodash';
import { __ } from '~/locale';
import { ListType } from './constants';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
@ -8,14 +9,15 @@ export function getMilestone() {
export function updateListPosition(listObj) {
const { listType } = listObj;
let { position } = listObj;
let { position, title } = listObj;
if (listType === ListType.closed) {
position = Infinity;
} else if (listType === ListType.backlog) {
position = -Infinity;
title = __('Open');
}
return { ...listObj, position };
return { ...listObj, title, position };
}
export function formatBoardLists(lists) {

View File

@ -12,6 +12,7 @@ import {
fullBoardId,
formatListsPageInfo,
formatIssue,
updateListPosition,
} from '../boards_util';
import createFlash from '~/flash';
import { __ } from '~/locale';
@ -131,7 +132,7 @@ export default {
},
addList: ({ commit }, list) => {
commit(types.RECEIVE_ADD_LIST_SUCCESS, list);
commit(types.RECEIVE_ADD_LIST_SUCCESS, updateListPosition(list));
},
fetchLabels: ({ state, commit }, searchTerm) => {

View File

@ -16,6 +16,7 @@ import {
GlSearchBoxByType,
GlSprintf,
GlLoadingIcon,
GlSafeHtmlDirective as SafeHtml,
} from '@gitlab/ui';
import * as Sentry from '~/sentry/wrapper';
import { s__, __, n__ } from '~/locale';
@ -34,7 +35,7 @@ export default {
'Pipeline|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used by default.',
),
formElementClasses: 'gl-mr-3 gl-mb-3 gl-flex-basis-quarter gl-flex-shrink-0 gl-flex-grow-0',
errorTitle: __('The form contains the following error:'),
errorTitle: __('Pipeline cannot be run.'),
warningTitle: __('The form contains the following warning:'),
maxWarningsSummary: __('%{total} warnings found: showing first %{warningsDisplayed}'),
components: {
@ -53,6 +54,7 @@ export default {
GlSprintf,
GlLoadingIcon,
},
directives: { SafeHtml },
props: {
pipelinesPath: {
type: String,
@ -335,8 +337,9 @@ export default {
variant="danger"
class="gl-mb-4"
data-testid="run-pipeline-error-alert"
>{{ error }}</gl-alert
>
<span v-safe-html="error"></span>
</gl-alert>
<gl-alert
v-if="shouldShowWarning"
:title="$options.warningTitle"
@ -365,7 +368,7 @@ export default {
</p>
</details>
</gl-alert>
<gl-form-group :label="s__('Pipeline|Run for')">
<gl-form-group :label="s__('Pipeline|Run for branch name or tag')">
<gl-dropdown :text="refShortName" block>
<gl-search-box-by-type v-model.trim="searchTerm" :placeholder="__('Search refs')" />
<gl-dropdown-section-header>{{ __('Branches') }}</gl-dropdown-section-header>
@ -391,12 +394,6 @@ export default {
{{ tag.shortName }}
</gl-dropdown-item>
</gl-dropdown>
<template #description>
<div>
{{ s__('Pipeline|Existing branch name or tag') }}
</div></template
>
</gl-form-group>
<gl-loading-icon v-if="isLoading" class="gl-mb-5" size="lg" />

View File

@ -172,10 +172,7 @@ export default {
.catch(this.onUpdateFail);
},
onUpdateSuccess() {
this.$toast.show(s__('SetStatusModal|Status updated'), {
type: 'success',
position: 'top-center',
});
this.$toast.show(s__('SetStatusModal|Status updated'));
this.closeModal();
window.location.reload();
},

0
app/enums/.keep Normal file
View File

View File

@ -5,6 +5,25 @@ module Types
extend GitlabStyleDeprecations
class << self
# Registers enum definition by the given DeclarativeEnum module
#
# @param enum_mod [Module] The enum module to be used
# @param use_name [Boolean] Does not override the name if set `false`
# @param use_description [Boolean] Does not override the description if set `false`
#
# Example:
#
# class MyEnum < BaseEnum
# declarative_enum MyDeclarativeEnum
# end
#
def declarative_enum(enum_mod, use_name: true, use_description: true)
graphql_name(enum_mod.name) if use_name
description(enum_mod.description) if use_description
enum_mod.definition.each { |key, content| value(key.to_s.upcase, content) }
end
def value(*args, **kwargs, &block)
enum[args[0].downcase] = kwargs[:value] || args[0]
kwargs = gitlab_deprecation(kwargs)

View File

@ -77,4 +77,9 @@ class ApplicationRecord < ActiveRecord::Base
def self.where_exists(query)
where('EXISTS (?)', query.select(1))
end
def self.declarative_enum(enum_mod)
values = enum_mod.definition.transform_values { |v| v[:value] }
enum(enum_mod.key => values)
end
end

View File

@ -93,7 +93,22 @@ module Ci
end
def refspec_for_persistent_ref
"+#{persistent_ref_path}:#{persistent_ref_path}"
#
# End-to-end test coverage for CI fetching seems to not be strong, so we
# are using a feature flag here to close the confidence gap. My (JV)
# confidence about the change is very high but if something is wrong
# with it after all, this would cause all CI jobs on gitlab.com to fail.
#
# The roll-out will be tracked in
# https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/746.
#
if Feature.enabled?(:scalability_ci_fetch_sha, type: :ops)
# Use persistent_ref.sha because it causes 'git fetch' to do less work.
# See https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/746.
"+#{pipeline.persistent_ref.sha}:#{pipeline.persistent_ref.path}"
else
"+#{pipeline.persistent_ref.path}:#{pipeline.persistent_ref.path}"
end
end
def persistent_ref_exist?
@ -107,10 +122,6 @@ module Ci
pipeline.persistent_ref.exist?
end
def persistent_ref_path
pipeline.persistent_ref.path
end
def git_depth_variable
strong_memoize(:git_depth_variable) do
variables&.find { |variable| variable[:key] == 'GIT_DEPTH' }

View File

@ -3,12 +3,12 @@
%li
= html_escape(_('The repository must be accessible over %{code_open}http://%{code_close},
%{code_open}https://%{code_close}, %{code_open}ssh://%{code_close} or %{code_open}git://%{code_close}.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li= html_escape(_('When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, please provide the exact URL to the repository. HTTP redirects will not be followed.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li= html_escape(_('When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, provide the exact URL to the repository. HTTP redirects will not be followed.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li= html_escape(_('Include the username in the URL if required: %{code_open}https://username@gitlab.company.com/group/project.git%{code_close}.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li
- minutes = Gitlab.config.gitlab_shell.git_timeout / 60
= _("The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination.") % { number_of_minutes: minutes }
%li= mirror_lfs_sync_message
%li
= _('This user will be the author of all events in the activity feed that are the result of an update,
= _('In case of pull mirroring, your user will be the author of all events in the activity feed that are the result of an update,
like new branches being created or new commits being pushed to existing branches.')

View File

@ -10,7 +10,7 @@
= expanded ? _('Collapse') : _('Expand')
%p
= _('Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically.')
= link_to _('Read more'), help_page_path('user/project/repository/repository_mirroring.md'), target: '_blank'
= link_to _('How do I mirror repositories?'), help_page_path('user/project/repository/repository_mirroring'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
- if mirror_settings_enabled
@ -21,7 +21,7 @@
.form-group.has-feedback
= label_tag :url, _('Git repository URL'), class: 'label-light'
= text_field_tag :url, nil, class: 'form-control js-mirror-url js-repo-url qa-mirror-repository-url-input', placeholder: _('Input your repository URL'), required: true, pattern: "(#{protocols}):\/\/.+", autocomplete: 'new-password'
= text_field_tag :url, nil, class: 'form-control js-mirror-url js-repo-url qa-mirror-repository-url-input', placeholder: _('Input the remote repository URL'), required: true, pattern: "(#{protocols}):\/\/.+", autocomplete: 'new-password'
= render 'projects/mirrors/instructions'
@ -29,8 +29,10 @@
.form-check.gl-mb-3
= check_box_tag :only_protected_branches, '1', false, class: 'js-mirror-protected form-check-input'
= label_tag :only_protected_branches, _('Only mirror protected branches'), class: 'form-check-label'
= link_to sprite_icon('question-o'), help_page_path('user/project/protected_branches'), target: '_blank'
= label_tag :only_protected_branches, _('Mirror only protected branches'), class: 'form-check-label'
.form-text.text-muted
= _('If enabled, only protected branches will be mirrored.')
= link_to _('Learn more.'), help_page_path('user/project/repository/repository_mirroring', anchor: 'mirror-only-protected-branches'), target: '_blank', rel: 'noopener noreferrer'
.panel-footer
= f.submit _('Mirror repository'), class: 'gl-button btn btn-success js-mirror-submit qa-mirror-repository-button', name: :update_remote_mirror

View File

@ -10,4 +10,6 @@
.form-check.gl-mb-3
= check_box_tag :keep_divergent_refs, '1', false, class: 'js-mirror-keep-divergent-refs form-check-input'
= label_tag :keep_divergent_refs, _('Keep divergent refs'), class: 'form-check-label'
= link_to sprite_icon('question-o'), help_page_path('user/project/repository/repository_mirroring', anchor: 'keep-divergent-refs'), target: '_blank'
.form-text.text-muted
= _('By default, if any ref (branch, tag, or commit) on the remote mirror has diverged from the local repository, the entire push will fail, and nothing will be updated. Choose this option to override this behavior. After the mirror is created, this can only be modified via the API.')
= link_to _('Learn more.'), help_page_path('user/project/repository/repository_mirroring', anchor: 'keep-divergent-refs'), target: '_blank', rel: 'noopener noreferrer'

View File

@ -0,0 +1,5 @@
---
title: Remove unneeded group label index
merge_request: 51676
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Update GraphqlExtractor return value to be original hash
merge_request: 51596
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Designate optional sections in the codeowners file
merge_request: 51643
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: 'CI: use commit SHA in persistent refspec'
merge_request: 51208
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Update pipeline alert text to be more readable
merge_request: 49575
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Update toast position on set status
merge_request: 50886
author:
type: fixed

View File

@ -5,4 +5,4 @@ rollout_issue_url:
milestone: '13.8'
type: development
group: group::source code
default_enabled: false
default_enabled: true

View File

@ -0,0 +1,8 @@
---
name: scalability_ci_fetch_sha
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51208
rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/746
milestone: '13.8'
type: ops
group: team::Scalability
default_enabled: false

View File

@ -23,7 +23,9 @@ module CarrierWave
# Multithreaded uploads are essential for copying large amounts of data
# within the request timeout.
if ::Feature.enabled?(:s3_multithreaded_uploads, default_enabled: true) && fog_provider == 'AWS'
file.concurrency = 10 # AWS SDK uses 10 threads by default
# AWS SDK uses 10 threads by default and a multipart chunk size of 10 MB
file.concurrency = 10
file.multipart_chunk_size = 10485760
file.copy(@uploader.fog_directory, new_path, copy_to_options)
else
# Some Fog providers may issue a GET request (https://github.com/fog/fog-google/issues/512)

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class RemoveGroupIdTitleIndex < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
INDEX_NAME = 'index_labels_on_group_id_and_title_with_null_project_id'
LABELS_TABLE = :labels
def up
remove_concurrent_index_by_name LABELS_TABLE, INDEX_NAME
end
def down
add_concurrent_index LABELS_TABLE, [:group_id, :title], where: 'project_id IS NULL', name: INDEX_NAME
end
end

View File

@ -0,0 +1 @@
69aae8d967fdb8af816a969fd818ed325b8d780b4faaa205c78a66c5d533ab2a

View File

@ -22045,8 +22045,6 @@ CREATE UNIQUE INDEX index_labels_on_group_id_and_project_id_and_title ON labels
CREATE UNIQUE INDEX index_labels_on_group_id_and_title_unique ON labels USING btree (group_id, title) WHERE (project_id IS NULL);
CREATE INDEX index_labels_on_group_id_and_title_with_null_project_id ON labels USING btree (group_id, title) WHERE (project_id IS NULL);
CREATE INDEX index_labels_on_project_id ON labels USING btree (project_id);
CREATE UNIQUE INDEX index_labels_on_project_id_and_title_unique ON labels USING btree (project_id, title) WHERE (group_id IS NULL);

View File

@ -89,9 +89,9 @@ This table lists the refspecs injected for each pipeline type:
| Pipeline type | Refspecs |
|--------------- |---------------------------------------- |
| Pipeline for Branches | `+refs/pipelines/<id>:refs/pipelines/<id>` and `+refs/heads/<name>:refs/remotes/origin/<name>` |
| pipeline for Tags | `+refs/pipelines/<id>:refs/pipelines/<id>` and `+refs/tags/<name>:refs/tags/<name>` |
| [Pipeline for Merge Requests](../merge_request_pipelines/index.md) | `+refs/pipelines/<id>:refs/pipelines/<id>` |
| Pipeline for Branches | `+<sha>:refs/pipelines/<id>` and `+refs/heads/<name>:refs/remotes/origin/<name>` |
| pipeline for Tags | `+<sha>:refs/pipelines/<id>` and `+refs/tags/<name>:refs/tags/<name>` |
| [Pipeline for Merge Requests](../merge_request_pipelines/index.md) | `+<sha>:refs/pipelines/<id>` |
The refs `refs/heads/<name>` and `refs/tags/<name>` exist in your
project repository. GitLab generates the special ref `refs/pipelines/<id>` during a

View File

@ -6,24 +6,34 @@ info: "See the Technical Writers assigned to Development Guidelines: https://abo
# Feature flags in development of GitLab
**NOTE**:
The documentation below covers feature flags used by GitLab to deploy its own features, which **is not** the same
as the [feature flags offered as part of the product](../../operations/feature_flags.md).
## When to use feature flags
Starting with GitLab 11.4, developers are required to use feature flags for
non-trivial changes. Such changes include:
Developers are required to use feature flags for changes that could affect availability of existing GitLab functionality (if it only affects the new feature you're making that is probably acceptable).
Such changes include:
- New features (e.g. a new merge request widget, epics, etc).
- Complex performance improvements that may require additional testing in
production, such as rewriting complex queries.
- Invasive changes to the user interface, such as a new navigation bar or the
removal of a sidebar.
- Adding support for importing projects from a third-party service.
- Risk of data loss
1. New features in high traffic areas (e.g. a new merge request widget, new option in issues/epics, new CI functionality).
1. Complex performance improvements that may require additional testing in production (e.g. rewriting complex queries, changes to frequently used API endpoints).
1. Invasive changes to the user interface (e.g. introducing a new navigation bar, removal of a sidebar, UI element change in issues or MR interface).
1. Introducing dependencies on third-party services (e.g. adding support for importing projects).
1. Changes to features that can cause data corruption or cause data loss (e.g. features processing repository data or user uploaded content).
In all cases, those working on the changes can best decide if a feature flag is
necessary. For example, changing the color of a button doesn't need a feature
flag, while changing the navigation bar definitely needs one. In case you are
uncertain if a feature flag is necessary, simply ask about this in the merge
request, and those reviewing the changes will likely provide you with an answer.
Situations where you might consider not using a feature flag:
1. Adding a new API endpoint
1. Introducing new features in low traffic areas (e.g. adding a new export functionality in the admin area/group settings/project settings)
1. Non-invasive frontend changes (e.g. changing the color of a button, or moving a UI element in a low traffic area)
In all cases, those working on the changes should ask themselves:
> Why do I need to add a feature flag? If I don't add one, what options do I have to control the impact on application reliability, and user experience?
For perspective on why we limit our use of feature flags please see the following [video](https://www.youtube.com/watch?v=DQaGqyolOd8).
In case you are uncertain if a feature flag is necessary, simply ask about this in an early merge request, and those reviewing the changes will likely provide you with an answer.
When using a feature flag for UI elements, make sure to _also_ use a feature
flag for the underlying backend code, if there is any. This ensures there is
@ -36,35 +46,29 @@ they are new features or performance improvements. By using feature flags,
you can determine the impact of GitLab-directed changes, while still being able
to disable those changes without having to revert an entire release.
Before using feature flags for GitLab development, review the following development guides:
NOTE:
The feature flags used by GitLab to deploy its own features **are not** the same
as the [feature flags offered as part of the product](../../operations/feature_flags.md).
For an overview about starting with feature flags in GitLab development,
use this [training template](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/.gitlab/issue_templates/feature-flag-training.md).
Development guides:
Before using feature flags for GitLab development, review the following development guides:
- [Process for using features flags](process.md): When you should use
1. [Process for using features flags](process.md): When you should use
feature flags in the development of GitLab, what's the cost of using them,
and how to include them in a release.
- [Developing with feature flags](development.md): Learn about the types of
1. [Developing with feature flags](development.md): Learn about the types of
feature flags, their definition and validation, how to create them, frontend and
backend details, and other information.
- [Documenting features deployed behind feature flags](../documentation/feature_flags.md):
1. [Documenting features deployed behind feature flags](../documentation/feature_flags.md):
How to document features deployed behind feature flags, and how to update the
documentation for features' flags when their states change.
- [Controlling feature flags](controls.md): Learn the process for deploying
1. [Controlling feature flags](controls.md): Learn the process for deploying
a new feature, enabling it on GitLab.com, communicating the change,
logging, and cleaning up.
User guides:
- [How GitLab administrators can enable and disable features behind flags](../../administration/feature_flags.md):
1. [How GitLab administrators can enable and disable features behind flags](../../administration/feature_flags.md):
An explanation for GitLab administrators about how they can
enable or disable GitLab features behind feature flags.
- [What "features deployed behind flags" means to the GitLab user](../../user/feature_flags.md):
1. [What "features deployed behind flags" means to the GitLab user](../../user/feature_flags.md):
An explanation for GitLab users regarding how certain features
might not be available to them until they are enabled.

View File

@ -8,19 +8,16 @@ disqus_identifier: 'https://docs.gitlab.com/ee/workflow/repository_mirroring.htm
# Repository mirroring
Repository mirroring allows for mirroring of repositories to and from external sources. It can be
used to mirror branches, tags, and commits between repositories.
used to mirror branches, tags, and commits between repositories. It is useful when you want to use
a repository outside of GitLab.
A repository mirror at GitLab will be updated automatically. You can also manually trigger an update
at most once every 5 minutes on GitLab.com with [the limit set by the administrator on self-managed instances](../../../administration/instance_limits.md#pull-mirroring-interval).
## Overview
Repository mirroring is useful when you want to use a repository outside of GitLab.
There are two kinds of repository mirroring supported by GitLab:
- Push: for mirroring a GitLab repository to another location.
- Pull: for mirroring a repository from another location to GitLab. **(STARTER)**
- [Push](#pushing-to-a-remote-repository): for mirroring a GitLab repository to another location. **(CORE)**
- [Pull](#pulling-from-a-remote-repository): for mirroring a repository from another location to GitLab. **(STARTER)**
When the mirror repository is updated, all new branches, tags, and commits will be visible in the
project's activity feed.
@ -31,8 +28,7 @@ immediate update, unless:
- The mirror is already being updated.
- The [limit for pull mirroring interval seconds](../../../administration/instance_limits.md#pull-mirroring-interval) has not elapsed since its last update.
For security reasons, in [GitLab 12.10 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27166),
the URL to the original repository is only displayed to users with
For security reasons, the URL to the original repository is only displayed to users with
Maintainer or Owner permissions to the mirrored project.
## Use cases
@ -62,7 +58,8 @@ For an existing project, you can set up push mirroring as follows:
1. Navigate to your project's **Settings > Repository** and expand the **Mirroring repositories** section.
1. Enter a repository URL.
1. Select **Push** from the **Mirror direction** dropdown.
1. Select an authentication method from the **Authentication method** dropdown, if necessary.
1. Select an authentication method from the **Authentication method** dropdown.
You can authenticate with either a password or an [SSH key](#ssh-authentication).
1. Check the **Only mirror protected branches** box, if necessary.
1. Check the **Keep divergent refs** box, if desired.
1. Click the **Mirror repository** button to save the configuration.
@ -88,17 +85,7 @@ section.
You can also create and modify project push mirrors through the
[remote mirrors API](../../../api/remote_mirrors.md).
### Push only protected branches **(CORE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3350) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
> - [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18715) in 10.8.
You can choose to only push your protected branches from GitLab to your remote repository.
To use this option, check the **Only mirror protected branches** box when creating a repository
mirror.
### Keep divergent refs **(CORE)**
### Keep divergent refs
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/208828) in GitLab 13.0.
@ -119,7 +106,7 @@ update.
NOTE:
After the mirror is created, this option can currently only be modified via the [API](../../../api/remote_mirrors.md).
## Setting up a push mirror from GitLab to GitHub **(CORE)**
### Setting up a push mirror from GitLab to GitHub
To set up a mirror from GitLab to GitHub, you need to follow these steps:
@ -132,7 +119,7 @@ The mirrored repository will be listed. For example, `https://*****:*****@github
The repository will push soon. To force a push, click the **Update now** (**{retry}**) button.
## Setting up a push mirror from GitLab to AWS CodeCommit
### Setting up a push mirror from GitLab to AWS CodeCommit
AWS CodeCommit push mirroring is currently the best way to connect GitLab repositories to AWS CodePipeline, as GitLab is not yet supported as one of their Source Code Management (SCM) providers.
@ -210,7 +197,7 @@ To test mirroring by forcing a push, click the half-circle arrows button (hover
If **Last successful update** shows a date, you have configured mirroring correctly.
If it is not working correctly a red `error` tag appears and shows the error message as hover text.
## Setting up a push mirror to another GitLab instance with 2FA activated
### Setting up a push mirror to another GitLab instance with 2FA activated
1. On the destination GitLab instance, create a [personal access token](../../profile/personal_access_tokens.md) with `write_repository` scope.
1. On the source GitLab instance:
@ -249,8 +236,8 @@ To configure mirror pulling for an existing project:
![Repository mirroring pull settings screen - lower part](img/repository_mirroring_pull_settings_lower.png)
Because GitLab is now set to pull changes from the upstream repository, you should not push commits
directly to the repository on GitLab. Instead, any commits should be pushed to the upstream repository.
Changes pushed to the upstream repository will be pulled into the GitLab repository, either:
directly to the repository on GitLab. Instead, any commits should be pushed to the remote repository.
Changes pushed to the remote repository will be pulled into the GitLab repository, either:
- Automatically within a certain period of time.
- When a [forced update](#forcing-an-update) is initiated.
@ -275,10 +262,62 @@ Repository mirrors are updated as Sidekiq becomes available to process them. If
- Fails (for example, a branch diverged from upstream), it will be attempted again later. Mirrors can fail
up to 14 times before they will not be enqueued for update again.
### SSH authentication
### Overwrite diverged branches **(STARTER)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/2551) for Pull mirroring in [GitLab Starter](https://about.gitlab.com/pricing/) 9.5.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22982) for Push mirroring in [GitLab Core](https://about.gitlab.com/pricing/) 11.6
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4559) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.6.
You can choose to always update your local branches with remote versions, even if they have
diverged from the remote.
WARNING:
For mirrored branches, enabling this option results in the loss of local changes.
To use this option, check the **Overwrite diverged branches** box when creating a repository mirror.
### Trigger pipelines for mirror updates **(STARTER)**
If this option is enabled, pipelines will be triggered when branches or tags are
updated from the remote repository. Depending on the activity of the remote
repository, this may greatly increase the load on your CI runners. Only enable
this if you know they can handle the load. CI will run using the credentials
assigned when you set up pull mirroring.
### Hard failure **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3117) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.2.
Once the mirroring process is unsuccessfully retried 14 times in a row, it will get marked as hard
failed. This will become visible in either the:
- Project's main dashboard.
- Pull mirror settings page.
When a project is hard failed, it will no longer get picked up for mirroring.
You can resume the project mirroring again by [forcing an update](#forcing-an-update).
### Trigger an update using the API **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3453) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
Pull mirroring uses polling to detect new branches and commits added upstream, often minutes
afterwards. If you notify GitLab by [API](../../../api/projects.md#start-the-pull-mirroring-process-for-a-project),
updates will be pulled immediately.
For more information, see [Start the pull mirroring process for a Project](../../../api/projects.md#start-the-pull-mirroring-process-for-a-project).
## Mirror only protected branches **(STARTER)**
Based on the mirror direction that you choose, you can opt to mirror only the
[protected branches](../protected_branches.md) from/to your remote repository.
For pull mirroring, non-protected branches are not mirrored and can diverge.
To use this option, check the **Only mirror protected branches** box when
creating a repository mirror.
## SSH authentication
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/2551) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.5 for Pull mirroring.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22982) in [GitLab Core](https://about.gitlab.com/pricing/) 11.6 for Push mirroring.
SSH authentication is mutual:
@ -367,50 +406,6 @@ NOTE:
The generated keys are stored in the GitLab database, not in the filesystem. Therefore,
SSH public key authentication for mirrors cannot be used in a pre-receive hook.
### Overwrite diverged branches **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4559) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.6.
You can choose to always update your local branches with remote versions, even if they have
diverged from the remote.
WARNING:
For mirrored branches, enabling this option results in the loss of local changes.
To use this option, check the **Overwrite diverged branches** box when creating a repository mirror.
### Only mirror protected branches **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3326) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
You can choose to pull mirror only the protected branches from your remote repository to GitLab.
Non-protected branches are not mirrored and can diverge.
To use this option, check the **Only mirror protected branches** box when creating a repository mirror.
### Hard failure **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3117) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.2.
Once the mirroring process is unsuccessfully retried 14 times in a row, it will get marked as hard
failed. This will become visible in either the:
- Project's main dashboard.
- Pull mirror settings page.
When a project is hard failed, it will no longer get picked up for mirroring. A user can resume the
project mirroring again by [Forcing an update](#forcing-an-update).
### Trigger update using API **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3453) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
Pull mirroring uses polling to detect new branches and commits added upstream, often minutes
afterwards. If you notify GitLab by [API](../../../api/projects.md#start-the-pull-mirroring-process-for-a-project),
updates will be pulled immediately.
For more information, see [Start the pull mirroring process for a Project](../../../api/projects.md#start-the-pull-mirroring-process-for-a-project).
## Forcing an update **(CORE)**
While mirrors are scheduled to update automatically, you can always force an update by using the
@ -429,10 +424,7 @@ bidirectional mirroring, you should prepare for the likely conflicts by deciding
them and how they will be resolved.
Rewriting any mirrored commit on either remote will cause conflicts and mirroring to fail. This can
be prevented by:
- [Pulling only protected branches](#only-mirror-protected-branches).
- [Pushing only protected branches](#push-only-protected-branches).
be prevented by [mirroring only protected branches](#mirror-only-protected-branches).
You should [protect the branches](../protected_branches.md) you wish to mirror on both
remotes to prevent conflicts caused by rewriting history.

View File

@ -11,14 +11,10 @@ module BulkImports
def extract(context)
client = graphql_client(context)
Enumerator.new do |yielder|
result = client.execute(
client.parse(query.to_s),
query.variables(context.entity)
)
yielder << result.original_hash.deep_dup
end
client.execute(
client.parse(query.to_s),
query.variables(context.entity)
).original_hash.deep_dup
end
private

105
lib/declarative_enum.rb Normal file
View File

@ -0,0 +1,105 @@
# frozen_string_literal: true
# Extending this module will give you the ability of defining
# enum values in a declarative way.
#
# module DismissalReasons
# extend DeclarativeEnum
#
# key :dismissal_reason
# name 'DismissalReasonOfVulnerability'
#
# description <<~TEXT
# This enum holds the user selected dismissal reason
# when they are dismissing the vulnerabilities
# TEXT
#
# define do
# acceptable_risk value: 0, description: 'The vulnerability is known but is considered to be an acceptable business risk.'
# false_positive value: 1, description: 'An error in reporting the presence of a vulnerability in a system when the vulnerability is not present.'
# used_in_tests value: 2, description: 'The finding is not a vulnerability because it is part of a test or is test data.'
# end
#
# Then we can use this module to register enums for our Active Record models like so,
#
# class VulnerabilityFeedback
# declarative_enum DismissalReasons
# end
#
# Also we can use this module to create GraphQL Enum types like so,
#
# module Types
# module Vulnerabilities
# class DismissalReasonEnum < BaseEnum
# declarative_enum DismissalReasons
# end
# end
# end
#
# rubocop:disable Gitlab/ModuleWithInstanceVariables
module DeclarativeEnum
# This `prepended` hook will merge the enum definition
# of the prepended module into the base module to be
# used by `prepend_if_ee` helper method.
def prepended(base)
base.definition.merge!(definition)
end
def key(new_key = nil)
@key = new_key if new_key
@key
end
def name(new_name = nil)
@name = new_name if new_name
@name
end
def description(new_description = nil)
@description = new_description if new_description
@description
end
def define(&block)
raise LocalJumpError.new('No block given') unless block
@definition = Builder.new(definition, block).build
end
# We can use this method later to apply some sanity checks
# but for now, returning a Hash without any check is enough.
def definition
@definition.to_h
end
class Builder
KeyCollisionError = Class.new(StandardError)
def initialize(definition, block)
@definition = definition
@block = block
end
def build
instance_exec(&@block)
@definition
end
private
def method_missing(name, *arguments, value: nil, description: nil, &block)
key = name.downcase.to_sym
raise KeyCollisionError, "'#{key}' collides with an existing enum key!" if @definition[key]
@definition[key] = {
value: value,
description: description
}
end
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables

View File

@ -19,7 +19,7 @@ module Gitlab
end
unless allowed_to_write_ref?
error("Insufficient permissions for protected ref '#{command.ref}'")
error("You do not have sufficient permission to run a pipeline on '#{command.ref}'. Please select a different branch or contact your administrator for assistance. <a href=https://docs.gitlab.com/ee/ci/pipelines/#pipeline-security-on-protected-branches>Learn more</a>".html_safe)
end
end

View File

@ -4915,6 +4915,9 @@ msgstr ""
msgid "By default, all projects and groups will use the global notifications setting."
msgstr ""
msgid "By default, if any ref (branch, tag, or commit) on the remote mirror has diverged from the local repository, the entire push will fail, and nothing will be updated. Choose this option to override this behavior. After the mirror is created, this can only be modified via the API."
msgstr ""
msgid "ByAuthor|by"
msgstr ""
@ -14454,6 +14457,9 @@ msgstr ""
msgid "How do I configure runners?"
msgstr ""
msgid "How do I mirror repositories?"
msgstr ""
msgid "How does cleanup work?"
msgstr ""
@ -14595,6 +14601,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
msgid "If enabled, only protected branches will be mirrored."
msgstr ""
msgid "If the YouTube URL is https://www.youtube.com/watch?v=0t1DgySidms then the video ID is %{id}"
msgstr ""
@ -14841,6 +14850,9 @@ msgstr ""
msgid "In %{time_to_now}"
msgstr ""
msgid "In case of pull mirroring, your user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
@ -15090,7 +15102,7 @@ msgstr ""
msgid "Input host keys manually"
msgstr ""
msgid "Input your repository URL"
msgid "Input the remote repository URL"
msgstr ""
msgid "Insert a code block"
@ -18325,6 +18337,9 @@ msgstr ""
msgid "Mirror direction"
msgstr ""
msgid "Mirror only protected branches"
msgstr ""
msgid "Mirror repository"
msgstr ""
@ -19890,9 +19905,6 @@ msgstr ""
msgid "Only admins can delete project"
msgstr ""
msgid "Only mirror protected branches"
msgstr ""
msgid "Only policy:"
msgstr ""
@ -20634,6 +20646,9 @@ msgstr ""
msgid "Pipeline Schedules"
msgstr ""
msgid "Pipeline cannot be run."
msgstr ""
msgid "Pipeline minutes quota"
msgstr ""
@ -20967,6 +20982,9 @@ msgstr ""
msgid "Pipeline|Run for"
msgstr ""
msgid "Pipeline|Run for branch name or tag"
msgstr ""
msgid "Pipeline|Running"
msgstr ""
@ -28022,9 +28040,6 @@ msgstr[1] ""
msgid "The fork relationship has been removed."
msgstr ""
msgid "The form contains the following error:"
msgstr ""
msgid "The form contains the following errors:"
msgstr ""
@ -29078,9 +29093,6 @@ msgstr ""
msgid "This user is the author of this %{noteable}."
msgstr ""
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
msgid "This variable can not be masked."
msgstr ""
@ -29909,7 +29921,7 @@ msgstr ""
msgid "Trigger pipelines for mirror updates"
msgstr ""
msgid "Trigger pipelines when branches or tags are updated from the upstream repository. Depending on the activity of the upstream repository, this may greatly increase the load on your CI runners. Only enable this if you know they can handle the load."
msgid "Trigger pipelines when branches or tags are updated in the upstream repository. Depending on the activity of the upstream repository, this may greatly increase the load on your CI runners. Only enable this if you know they can handle the load."
msgstr ""
msgid "Trigger removed."
@ -31772,6 +31784,9 @@ msgstr[1] ""
msgid "When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, please provide the exact URL to the repository. HTTP redirects will not be followed."
msgstr ""
msgid "When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, provide the exact URL to the repository. HTTP redirects will not be followed."
msgstr ""
msgid "When:"
msgstr ""

View File

@ -204,10 +204,7 @@ describe('SetStatusModalWrapper', () => {
findModal().vm.$emit('ok');
await wrapper.vm.$nextTick();
expect($toast.show).toHaveBeenCalledWith('Status updated', {
position: 'top-center',
type: 'success',
});
expect($toast.show).toHaveBeenCalledWith('Status updated');
});
});

View File

@ -3,7 +3,75 @@
require 'spec_helper'
RSpec.describe Types::BaseEnum do
describe '#enum' do
describe '.declarative_enum' do
let(:use_name) { true }
let(:use_description) { true }
let(:enum_type) do
Class.new(described_class) do
graphql_name 'OriginalName'
description 'Original description'
end
end
let(:enum_module) do
Module.new do
extend DeclarativeEnum
name 'Name'
description 'Description'
define do
foo value: 0, description: 'description of foo'
end
end
end
subject(:set_declarative_enum) { enum_type.declarative_enum(enum_module, use_name: use_name, use_description: use_description) }
describe '#graphql_name' do
context 'when the use_name is `true`' do
it 'changes the graphql_name' do
expect { set_declarative_enum }.to change { enum_type.graphql_name }.from('OriginalName').to('Name')
end
end
context 'when the use_name is `false`' do
let(:use_name) { false }
it 'does not change the graphql_name' do
expect { set_declarative_enum }.not_to change { enum_type.graphql_name }.from('OriginalName')
end
end
end
describe '#description' do
context 'when the use_description is `true`' do
it 'changes the description' do
expect { set_declarative_enum }.to change { enum_type.description }.from('Original description').to('Description')
end
end
context 'when the use_description is `false`' do
let(:use_description) { false }
it 'does not change the description' do
expect { set_declarative_enum }.not_to change { enum_type.description }.from('Original description')
end
end
end
describe '#values' do
it 'sets the values defined by the declarative enum' do
set_declarative_enum
expect(enum_type.values.keys).to eq(['FOO'])
expect(enum_type.values.values.map(&:description)).to eq(['description of foo'])
expect(enum_type.values.values.map(&:value)).to eq([0])
end
end
end
describe '.enum' do
let(:enum) do
Class.new(described_class) do
value 'TEST', value: 3

View File

@ -39,6 +39,14 @@ RSpec.describe 'CarrierWave::Storage::Fog::File' do
let(:dest_filename) { 'copied.txt'}
it 'copies the file' do
fog_file = subject.send(:file)
expect(fog_file).to receive(:concurrency=).with(10).and_call_original
# multipart_chunk_size must be explicitly set in order to leverage
# multithreaded, multipart transfers for files below 5GB.
expect(fog_file).to receive(:multipart_chunk_size=).with(10.megabytes).and_call_original
expect(fog_file).to receive(:copy).with(bucket_name, dest_filename, anything).and_call_original
result = subject.copy_to(dest_filename)
expect(result.exists?).to be true

View File

@ -27,11 +27,8 @@ RSpec.describe BulkImports::Common::Extractors::GraphqlExtractor do
allow(graphql_client).to receive(:execute).and_return(response)
end
it 'returns an enumerator with fetched results' do
response = subject.extract(context)
expect(response).to be_instance_of(Enumerator)
expect(response.first).to eq({ foo: :bar })
it 'returns original hash' do
expect(subject.extract(context)).to eq({ foo: :bar })
end
end

View File

@ -0,0 +1,147 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe DeclarativeEnum do
let(:enum_module) do
Module.new do
extend DeclarativeEnum
key :my_enum
name 'MyEnumName'
description "Enum description"
define do
foo value: 0, description: 'description of foo'
bar value: 1, description: 'description of bar'
end
end
end
let(:original_definition) do
{
foo: { description: 'description of foo', value: 0 },
bar: { description: 'description of bar', value: 1 }
}
end
describe '.key' do
subject(:key) { enum_module.key(new_key) }
context 'when the argument is set' do
let(:new_key) { :new_enum_key }
it 'changes the key' do
expect { key }.to change { enum_module.key }.from(:my_enum).to(:new_enum_key)
end
end
context 'when the argument is `nil`' do
let(:new_key) { nil }
it { is_expected.to eq(:my_enum) }
end
end
describe '.name' do
subject(:name) { enum_module.name(new_name) }
context 'when the argument is set' do
let(:new_name) { 'NewMyEnumName' }
it 'changes the name' do
expect { name }.to change { enum_module.name }.from('MyEnumName').to('NewMyEnumName')
end
end
context 'when the argument is `nil`' do
let(:new_name) { nil }
it { is_expected.to eq('MyEnumName') }
end
end
describe '.description' do
subject(:description) { enum_module.description(new_description) }
context 'when the argument is set' do
let(:new_description) { 'New enum description' }
it 'changes the description' do
expect { description }.to change { enum_module.description }.from('Enum description').to('New enum description')
end
end
context 'when the argument is `nil`' do
let(:new_description) { nil }
it { is_expected.to eq('Enum description') }
end
end
describe '.define' do
subject(:define) { enum_module.define(&block) }
context 'when there is a block given' do
context 'when the given block tries to register the same key' do
let(:block) do
proc do
foo value: 2, description: 'description of foo'
end
end
it 'raises a `KeyCollisionError`' do
expect { define }.to raise_error(DeclarativeEnum::Builder::KeyCollisionError)
end
end
context 'when the given block does not try to register the same key' do
let(:expected_new_definition) { original_definition.merge(zoo: { description: 'description of zoo', value: 0 }) }
let(:block) do
proc do
zoo value: 0, description: 'description of zoo'
end
end
it 'appends the new definition' do
expect { define }.to change { enum_module.definition }.from(original_definition).to(expected_new_definition)
end
end
end
context 'when there is no block given' do
let(:block) { nil }
it 'raises a LocalJumpError' do
expect { define }.to raise_error(LocalJumpError)
end
end
end
describe '.definition' do
subject { enum_module.definition }
it { is_expected.to eq(original_definition) }
end
describe 'extending the enum module' do
let(:extended_definition) { original_definition.merge(zoo: { value: 2, description: 'description of zoo' }) }
let(:new_enum_module) do
Module.new do
extend DeclarativeEnum
define do
zoo value: 2, description: 'description of zoo'
end
end
end
subject(:prepend_new_enum_module) { enum_module.prepend(new_enum_module) }
it 'extends the values of the base enum module' do
expect { prepend_new_enum_module }.to change { enum_module.definition }.from(original_definition)
.to(extended_definition)
end
end
end

View File

@ -189,7 +189,21 @@ RSpec.describe Ci::BuildRunnerPresenter do
it 'returns the correct refspecs' do
is_expected.to contain_exactly("+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}",
"+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}")
"+#{pipeline.sha}:refs/pipelines/#{pipeline.id}")
end
it 'uses a SHA in the persistent refspec' do
expect(subject[0]).to match(/^\+[0-9a-f]{40}:refs\/pipelines\/[0-9]+$/)
end
context 'when the scalability_ci_fetch_sha feature flag is disabled' do
before do
stub_feature_flags(scalability_ci_fetch_sha: false)
end
it 'fetches the ref by name' do
expect(subject[0]).to eq("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}")
end
end
context 'when ref is tag' do
@ -197,7 +211,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
it 'returns the correct refspecs' do
is_expected.to contain_exactly("+refs/tags/#{build.ref}:refs/tags/#{build.ref}",
"+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}")
"+#{pipeline.sha}:refs/pipelines/#{pipeline.id}")
end
context 'when GIT_DEPTH is zero' do
@ -208,7 +222,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
it 'returns the correct refspecs' do
is_expected.to contain_exactly('+refs/tags/*:refs/tags/*',
'+refs/heads/*:refs/remotes/origin/*',
"+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}")
"+#{pipeline.sha}:refs/pipelines/#{pipeline.id}")
end
end
end
@ -224,7 +238,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
it 'returns the correct refspecs' do
is_expected
.to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}")
.to contain_exactly("+#{pipeline.sha}:refs/pipelines/#{pipeline.id}")
end
context 'when GIT_DEPTH is zero' do
@ -234,7 +248,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
it 'returns the correct refspecs' do
is_expected
.to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
.to contain_exactly("+#{pipeline.sha}:refs/pipelines/#{pipeline.id}",
'+refs/heads/*:refs/remotes/origin/*',
'+refs/tags/*:refs/tags/*')
end
@ -244,7 +258,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) }
it 'returns the correct refspecs' do
is_expected.to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
is_expected.to contain_exactly("+#{pipeline.sha}:refs/pipelines/#{pipeline.id}",
"+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}")
end
end
@ -262,7 +276,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
it 'exposes the persistent pipeline ref' do
is_expected
.to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
.to contain_exactly("+#{pipeline.sha}:refs/pipelines/#{pipeline.id}",
"+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}")
end
end

View File

@ -156,7 +156,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
'sha' => job.sha,
'before_sha' => job.before_sha,
'ref_type' => 'branch',
'refspecs' => ["+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
'refspecs' => ["+#{pipeline.sha}:refs/pipelines/#{pipeline.id}",
"+refs/heads/#{job.ref}:refs/remotes/origin/#{job.ref}"],
'depth' => project.ci_default_git_depth }
end
@ -284,7 +284,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(response).to have_gitlab_http_status(:created)
expect(json_response['git_info']['refspecs'])
.to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
.to contain_exactly("+#{pipeline.sha}:refs/pipelines/#{pipeline.id}",
'+refs/tags/*:refs/tags/*',
'+refs/heads/*:refs/remotes/origin/*')
end
@ -346,7 +346,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(response).to have_gitlab_http_status(:created)
expect(json_response['git_info']['refspecs'])
.to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
.to contain_exactly("+#{pipeline.sha}:refs/pipelines/#{pipeline.id}",
'+refs/tags/*:refs/tags/*',
'+refs/heads/*:refs/remotes/origin/*')
end

View File

@ -27,11 +27,11 @@ RSpec.describe MergeRequests::ExportCsvService do
let_it_be(:merge_request) { create(:merge_request, assignees: create_list(:user, 2)) }
it 'contains the names of assignees' do
expect(csv['Assignees']).to eq(merge_request.assignees.map(&:name).join(', '))
expect(csv['Assignees'].split(', ')).to match_array(merge_request.assignees.map(&:name))
end
it 'contains the usernames of assignees' do
expect(csv['Assignee Usernames']).to eq(merge_request.assignees.map(&:username).join(', '))
expect(csv['Assignee Usernames'].split(', ')).to match_array(merge_request.assignees.map(&:username))
end
end