Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
04698e448a
commit
298ae510ce
2
Gemfile
2
Gemfile
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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' }
|
||||
|
|
|
|||
|
|
@ -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.')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove unneeded group label index
|
||||
merge_request: 51676
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update GraphqlExtractor return value to be original hash
|
||||
merge_request: 51596
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Designate optional sections in the codeowners file
|
||||
merge_request: 51643
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'CI: use commit SHA in persistent refspec'
|
||||
merge_request: 51208
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update pipeline alert text to be more readable
|
||||
merge_request: 49575
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update toast position on set status
|
||||
merge_request: 50886
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -5,4 +5,4 @@ rollout_issue_url:
|
|||
milestone: '13.8'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
69aae8d967fdb8af816a969fd818ed325b8d780b4faaa205c78a66c5d533ab2a
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
|||

|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue