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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-01-28 18:09:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-01-28 18:09:06 +0300
commitc6ee7ef0f577e0155740d022babdc1b2b0e28d87 (patch)
tree8037a9487329eba19009520ba6c8e573beb1d63c
parent8c2b139cf778cd1d152f06bbc090a4313f975b81 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/api.js4
-rw-r--r--app/assets/javascripts/diffs/components/diff_discussion_reply.vue9
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_note_form.vue10
-rw-r--r--app/assets/javascripts/header.js6
-rw-r--r--app/assets/javascripts/issuable_list/components/issuable_item.vue6
-rw-r--r--app/assets/javascripts/issuable_list/components/issuable_list_root.vue2
-rw-r--r--app/assets/javascripts/issuable_list/components/issuable_tabs.vue7
-rw-r--r--app/assets/javascripts/notes.js13
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue11
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue41
-rw-r--r--app/assets/javascripts/pages/projects/blame/show/index.js2
-rw-r--r--app/assets/stylesheets/framework/diffs.scss4
-rw-r--r--app/assets/stylesheets/framework/files.scss6
-rw-r--r--app/assets/stylesheets/framework/filters.scss9
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/pages/issues.scss12
-rw-r--r--app/assets/stylesheets/pages/note_form.scss6
-rw-r--r--app/assets/stylesheets/pages/notes.scss26
-rw-r--r--app/services/groups/import_export/export_service.rb48
-rw-r--r--app/services/groups/import_export/import_service.rb50
-rw-r--r--app/services/jira/requests/base.rb8
-rw-r--r--app/services/quick_actions/interpret_service.rb9
-rw-r--r--app/views/discussions/_notes.html.haml2
-rw-r--r--app/views/shared/notes/_edit_form.html.haml2
-rw-r--r--app/views/shared/notes/_notes_with_form.html.haml3
-rw-r--r--changelogs/unreleased/292391-quickactions-usage-ping.yml5
-rw-r--r--changelogs/unreleased/84402-remove-avatar-from-comment-forms.yml5
-rw-r--r--config/feature_flags/development/jira_issues_show_integration.yml8
-rw-r--r--config/feature_flags/development/usage_data_track_quickactions.yml8
-rw-r--r--doc/administration/file_hooks.md29
-rw-r--r--doc/administration/git_annex.md18
-rw-r--r--doc/administration/lfs/index.md86
-rw-r--r--doc/administration/pages/source.md2
-rw-r--r--doc/development/code_review.md7
-rw-r--r--doc/integration/README.md4
-rw-r--r--doc/integration/gmail_action_buttons_for_gitlab.md8
-rw-r--r--doc/integration/img/oauth_provider_application_form.pngbin12553 -> 0 bytes
-rw-r--r--doc/integration/img/oauth_provider_application_id_secret.pngbin15280 -> 0 bytes
-rw-r--r--doc/integration/img/oauth_provider_authorized_application.pngbin14657 -> 0 bytes
-rw-r--r--doc/integration/img/oauth_provider_user_wide_applications.pngbin17526 -> 0 bytes
-rw-r--r--doc/integration/jenkins_deprecated.md2
-rw-r--r--doc/integration/jira_development_panel.md56
-rw-r--r--doc/integration/oauth_provider.md82
-rw-r--r--doc/integration/omniauth.md27
-rw-r--r--doc/integration/openid_connect_provider.md3
-rw-r--r--doc/push_rules/push_rules.md58
-rw-r--r--doc/topics/git/troubleshooting_git.md21
-rw-r--r--doc/topics/gitlab_flow.md80
-rw-r--r--lib/gitlab/import_export/group/tree_restorer.rb2
-rw-r--r--lib/gitlab/import_export/repo_saver.rb3
-rw-r--r--lib/gitlab/usage_data_counters/known_events/quickactions.yml326
-rw-r--r--lib/gitlab/usage_data_counters/quick_action_activity_unique_counter.rb88
-rw-r--r--rubocop/cop/migration/add_limit_to_text_columns.rb31
-rw-r--r--rubocop/migration_helpers.rb2
-rw-r--r--spec/experiments/application_experiment_spec.rb6
-rw-r--r--spec/frontend/api_spec.js22
-rw-r--r--spec/frontend/issuable_list/components/issuable_item_spec.js17
-rw-r--r--spec/frontend/notes/components/comment_form_spec.js9
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js26
-rw-r--r--spec/lib/gitlab/import_export/group/tree_restorer_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/repo_saver_spec.rb8
-rw-r--r--spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb3
-rw-r--r--spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb163
-rw-r--r--spec/lib/gitlab/utils/markdown_spec.rb44
-rw-r--r--spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb18
-rw-r--r--spec/services/groups/import_export/export_service_spec.rb10
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb18
-rw-r--r--spec/support/gitlab_experiment.rb9
68 files changed, 1133 insertions, 479 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 7043da5017d..e8d433d36c9 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -179,9 +179,9 @@ const Api = {
});
},
- groupLabels(namespace) {
+ groupLabels(namespace, options = {}) {
const url = Api.buildUrl(Api.groupLabelsPath).replace(':namespace_path', namespace);
- return axios.get(url).then(({ data }) => data);
+ return axios.get(url, options).then(({ data }) => data);
},
// Return namespaces list. Filtered by query
diff --git a/app/assets/javascripts/diffs/components/diff_discussion_reply.vue b/app/assets/javascripts/diffs/components/diff_discussion_reply.vue
index 531ebaddacd..a7a6b38235b 100644
--- a/app/assets/javascripts/diffs/components/diff_discussion_reply.vue
+++ b/app/assets/javascripts/diffs/components/diff_discussion_reply.vue
@@ -2,14 +2,12 @@
import { mapGetters } from 'vuex';
import NoteSignedOutWidget from '~/notes/components/note_signed_out_widget.vue';
import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
-import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
export default {
name: 'DiffDiscussionReply',
components: {
NoteSignedOutWidget,
ReplyPlaceholder,
- UserAvatarLink,
},
props: {
hasForm: {
@@ -36,13 +34,6 @@ export default {
<template v-if="userCanReply">
<slot v-if="hasForm" name="form"></slot>
<template v-else-if="renderReplyPlaceholder">
- <user-avatar-link
- :link-href="currentUser.path"
- :img-src="currentUser.avatar_url"
- :img-alt="currentUser.name"
- :img-size="40"
- class="d-none d-sm-block"
- />
<reply-placeholder
:button-text="__('Start a new discussion...')"
@onClick="$emit('showNewDiscussionForm')"
diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
index 463b7f5cff4..e4c64bb0e07 100644
--- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
@@ -6,7 +6,6 @@ import { s__ } from '~/locale';
import noteForm from '../../notes/components/note_form.vue';
import MultilineCommentForm from '../../notes/components/multiline_comment_form.vue';
import autosave from '../../notes/mixins/autosave';
-import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import { DIFF_NOTE_TYPE, INLINE_DIFF_LINES_KEY, PARALLEL_DIFF_VIEW_TYPE } from '../constants';
import {
commentLineOptions,
@@ -16,7 +15,6 @@ import {
export default {
components: {
noteForm,
- userAvatarLink,
MultilineCommentForm,
},
mixins: [autosave, diffLineNoteFormMixin, glFeatureFlagsMixin()],
@@ -174,14 +172,6 @@ export default {
:comment-line-options="commentLineOptions"
/>
</div>
- <user-avatar-link
- v-if="author"
- :link-href="author.path"
- :img-src="author.avatar_url"
- :img-alt="author.name"
- :img-size="40"
- class="d-none d-sm-block"
- />
<note-form
ref="noteForm"
:is-editing="true"
diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js
index 9f9708bf879..bcafb09bc66 100644
--- a/app/assets/javascripts/header.js
+++ b/app/assets/javascripts/header.js
@@ -106,7 +106,5 @@ export function initNavUserDropdownTracking() {
}
}
-document.addEventListener('DOMContentLoaded', () => {
- requestIdleCallback(initStatusTriggers);
- requestIdleCallback(initNavUserDropdownTracking);
-});
+requestIdleCallback(initStatusTriggers);
+requestIdleCallback(initNavUserDropdownTracking);
diff --git a/app/assets/javascripts/issuable_list/components/issuable_item.vue b/app/assets/javascripts/issuable_list/components/issuable_item.vue
index 23471c250e0..df303665538 100644
--- a/app/assets/javascripts/issuable_list/components/issuable_item.vue
+++ b/app/assets/javascripts/issuable_list/components/issuable_item.vue
@@ -139,6 +139,12 @@ export default {
<div class="issuable-main-info">
<div data-testid="issuable-title" class="issue-title title">
<span class="issue-title-text" dir="auto">
+ <gl-icon
+ v-if="issuable.confidential"
+ v-gl-tooltip
+ name="eye-slash"
+ :title="__('Confidential')"
+ />
<gl-link :href="issuable.webUrl" v-bind="issuableTitleProps"
>{{ issuable.title
}}<gl-icon v-if="isIssuableUrlExternal" name="external-link" class="gl-ml-2"
diff --git a/app/assets/javascripts/issuable_list/components/issuable_list_root.vue b/app/assets/javascripts/issuable_list/components/issuable_list_root.vue
index c5475a34d3c..30078903b85 100644
--- a/app/assets/javascripts/issuable_list/components/issuable_list_root.vue
+++ b/app/assets/javascripts/issuable_list/components/issuable_list_root.vue
@@ -230,7 +230,7 @@ export default {
:initial-sort-by="initialSortBy"
:show-checkbox="showBulkEditSidebar"
:checkbox-checked="allIssuablesChecked"
- class="gl-flex-grow-1 row-content-block"
+ class="gl-flex-grow-1 gl-border-t-none row-content-block"
@checked-input="handleAllIssuablesCheckedInput"
@onFilter="$emit('filter', $event)"
@onSort="$emit('sort', $event)"
diff --git a/app/assets/javascripts/issuable_list/components/issuable_tabs.vue b/app/assets/javascripts/issuable_list/components/issuable_tabs.vue
index d9aab004077..57da030e22e 100644
--- a/app/assets/javascripts/issuable_list/components/issuable_tabs.vue
+++ b/app/assets/javascripts/issuable_list/components/issuable_tabs.vue
@@ -32,7 +32,10 @@ export default {
<template>
<div class="top-area">
- <gl-tabs class="nav-links mobile-separator issuable-state-filters">
+ <gl-tabs
+ class="gl-display-flex gl-flex-fill-1 gl-p-0 gl-m-0 mobile-separator issuable-state-filters"
+ nav-class="gl-border-b-0"
+ >
<gl-tab
v-for="tab in tabs"
:key="tab.id"
@@ -41,7 +44,7 @@ export default {
>
<template #title>
<span :title="tab.titleTooltip">{{ tab.title }}</span>
- <gl-badge v-if="tabCounts" variant="neutral" size="sm" class="gl-px-2 gl-py-1!">{{
+ <gl-badge v-if="tabCounts" variant="neutral" size="sm" class="gl-tab-counter-badge">{{
tabCounts[tab.name]
}}</gl-badge>
</template>
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index 857e5a34db6..78e89f28542 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -904,18 +904,7 @@ export default class Notes {
// DiffNote
form.find('#note_position').val(dataHolder.attr('data-position'));
- form
- .prepend(
- `<a href="${escape(
- gon.current_username,
- )}" class="user-avatar-link d-none d-sm-block"><img class="avatar s40" src="${encodeURI(
- gon.current_user_avatar_url || gon.default_avatar_url,
- )}" alt="${escape(gon.current_user_fullname)}" /></a>`,
- )
- .append('</div>')
- .find('.js-close-discussion-note-form')
- .show()
- .removeClass('hide');
+ form.append('</div>').find('.js-close-discussion-note-form').show().removeClass('hide');
form.find('.js-note-target-close').remove();
form.find('.js-note-new-discussion').remove();
this.setupNoteForm(form);
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index b52053168b3..46b8db0b955 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -18,7 +18,6 @@ import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests
import * as constants from '../constants';
import eventHub from '../event_hub';
import markdownField from '~/vue_shared/components/markdown/field.vue';
-import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import noteSignedOutWidget from './note_signed_out_widget.vue';
import discussionLockedWidget from './discussion_locked_widget.vue';
@@ -31,7 +30,6 @@ export default {
noteSignedOutWidget,
discussionLockedWidget,
markdownField,
- userAvatarLink,
GlButton,
TimelineEntryItem,
GlIcon,
@@ -301,15 +299,6 @@ export default {
<ul v-else-if="canCreateNote" class="notes notes-form timeline">
<timeline-entry-item class="note-form">
<div class="flash-container error-alert timeline-content"></div>
- <div class="timeline-icon d-none d-md-block">
- <user-avatar-link
- v-if="author"
- :link-href="author.path"
- :img-src="author.avatar_url"
- :img-alt="author.name"
- :img-size="40"
- />
- </div>
<div class="timeline-content timeline-content-form">
<form ref="commentForm" class="new-note common-note-form gfm-form js-main-target-form">
<comment-field-layout
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index ef946cf3c4f..527b38663e4 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -267,14 +267,6 @@ export default {
:class="{ 'is-replying': isReplying }"
class="discussion-reply-holder gl-border-t-0! clearfix"
>
- <user-avatar-link
- v-if="!isReplying && userCanReply"
- :link-href="currentUser.path"
- :img-src="currentUser.avatar_url"
- :img-alt="currentUser.name"
- :img-size="40"
- class="d-none d-sm-block"
- />
<discussion-actions
v-if="!isReplying && userCanReply"
:discussion="discussion"
@@ -285,27 +277,18 @@ export default {
@showReplyForm="showReplyForm"
@resolve="resolveHandler"
/>
- <div v-if="isReplying" class="avatar-note-form-holder">
- <user-avatar-link
- v-if="currentUser"
- :link-href="currentUser.path"
- :img-src="currentUser.avatar_url"
- :img-alt="currentUser.name"
- :img-size="40"
- class="d-none d-sm-block"
- />
- <note-form
- ref="noteForm"
- :discussion="discussion"
- :is-editing="false"
- :line="diffLine"
- save-button-title="Comment"
- :autosave-key="autosaveKey"
- @handleFormUpdateAddToReview="addReplyToReview"
- @handleFormUpdate="saveReply"
- @cancelForm="cancelReplyForm"
- />
- </div>
+ <note-form
+ v-if="isReplying"
+ ref="noteForm"
+ :discussion="discussion"
+ :is-editing="false"
+ :line="diffLine"
+ save-button-title="Comment"
+ :autosave-key="autosaveKey"
+ @handleFormUpdateAddToReview="addReplyToReview"
+ @handleFormUpdate="saveReply"
+ @cancelForm="cancelReplyForm"
+ />
<note-signed-out-widget v-if="!isLoggedIn" />
</div>
</template>
diff --git a/app/assets/javascripts/pages/projects/blame/show/index.js b/app/assets/javascripts/pages/projects/blame/show/index.js
index 80d0bff92fa..fa22c11d1d7 100644
--- a/app/assets/javascripts/pages/projects/blame/show/index.js
+++ b/app/assets/javascripts/pages/projects/blame/show/index.js
@@ -1,3 +1,3 @@
import initBlob from '~/pages/projects/init_blob';
-document.addEventListener('DOMContentLoaded', initBlob);
+initBlob();
diff --git a/app/assets/stylesheets/framework/diffs.scss b/app/assets/stylesheets/framework/diffs.scss
index 499b9c00116..e30caeb1dfb 100644
--- a/app/assets/stylesheets/framework/diffs.scss
+++ b/app/assets/stylesheets/framework/diffs.scss
@@ -1136,10 +1136,6 @@ table.code {
display: block;
}
}
-
- .note-edit-form {
- margin-left: $note-icon-gutter-width;
- }
}
.discussion-body .image .frame {
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 27a439651e6..103d59382b4 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -444,12 +444,6 @@ span.idiff {
.user-avatar-link.new-comment {
position: absolute;
margin: 40px $gl-padding 0 116px;
-
- ~ .note-edit-form form.edit-note {
- @include media-breakpoint-up(sm) {
- margin-left: $note-icon-gutter-width;
- }
- }
}
}
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 5f56fa3be86..07d59847829 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -475,6 +475,15 @@
}
}
+ .sort-dropdown-container {
+ // This property is set to have borders
+ // around sort dropdown match with filter
+ // input field.
+ .gl-button {
+ box-shadow: inset 0 0 0 1px $gray-400;
+ }
+ }
+
@include media-breakpoint-up(md) {
.sort-dropdown-container {
margin-left: 10px;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 7db172c55a1..4bf9236407f 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -627,7 +627,6 @@ $search-input-xl-width: 320px;
$note-disabled-comment-color: #b2b2b2;
$note-targe3-outside: #fffff0;
$note-targe3-inside: #ffffd3;
-$note-icon-gutter-width: 55px;
/*
* Identicon
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 1caf62067a6..1c1e9d93909 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -203,15 +203,9 @@ ul.related-merge-requests > li {
}
}
-.discussion-reply-holder {
- .avatar-note-form-holder .note-edit-form {
- display: block;
- margin-left: $note-icon-gutter-width;
-
- @include media-breakpoint-down(xs) {
- margin-left: 0;
- }
- }
+.discussion-reply-holder,
+.note-edit-form {
+ display: block;
}
.issue-sort-dropdown {
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 254ad96bb57..ffbfa47f9bd 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -212,8 +212,12 @@ table {
}
}
-.note-edit-form {
+// Snippets are the only non-vue form left
+.snippets.note-edit-form {
display: none;
+}
+
+.note-edit-form {
font-size: 14px;
.md-area {
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 141e401a17a..8dc2e2e9455 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -1,6 +1,5 @@
$system-note-icon-size: 32px;
$system-note-svg-size: 16px;
-$note-form-margin-left: 72px;
@mixin vertical-line($left) {
&::before {
@@ -54,16 +53,6 @@ $note-form-margin-left: 72px;
&.note-form {
margin-left: 0;
- @include notes-media('min', map-get($grid-breakpoints, md)) {
- margin-left: $note-form-margin-left;
- }
-
- .timeline-icon {
- @include notes-media('min', map-get($grid-breakpoints, sm)) {
- margin-left: -$note-icon-gutter-width;
- }
- }
-
.timeline-content {
margin-left: 0;
}
@@ -529,21 +518,6 @@ $note-form-margin-left: 72px;
.code-commit .notes-content,
.diff-viewer > .image ~ .note-container {
background-color: $white;
-
- .avatar-note-form-holder {
- .user-avatar-link img {
- margin: 13px $gl-padding $gl-padding;
- }
-
- form,
- ~ .discussion-form-container {
- padding: $gl-padding;
-
- @include media-breakpoint-up(sm) {
- margin-left: $note-icon-gutter-width;
- }
- }
- }
}
.diff-viewer > .image ~ .note-container form.new-note {
diff --git a/app/services/groups/import_export/export_service.rb b/app/services/groups/import_export/export_service.rb
index b45deda6855..5a1b695dcd6 100644
--- a/app/services/groups/import_export/export_service.rb
+++ b/app/services/groups/import_export/export_service.rb
@@ -12,13 +12,13 @@ module Groups
end
def async_execute
- GroupExportWorker.perform_async(@current_user.id, @group.id, @params)
+ GroupExportWorker.perform_async(current_user.id, group.id, params)
end
def execute
validate_user_permissions
- remove_existing_export! if @group.export_file_exists?
+ remove_existing_export! if group.export_file_exists?
save!
ensure
@@ -27,25 +27,29 @@ module Groups
private
+ attr_reader :group, :current_user, :params
attr_accessor :shared
def validate_user_permissions
- unless @current_user.can?(:admin_group, @group)
- @shared.error(::Gitlab::ImportExport::Error.permission_error(@current_user, @group))
+ unless current_user.can?(:admin_group, group)
+ shared.error(::Gitlab::ImportExport::Error.permission_error(current_user, group))
notify_error!
end
end
def remove_existing_export!
- import_export_upload = @group.import_export_upload
+ import_export_upload = group.import_export_upload
import_export_upload.remove_export_file!
import_export_upload.save
end
def save!
- if savers.all?(&:save)
+ # We cannot include the file_saver with the other savers because
+ # it removes the tmp dir. This means that if we want to add new savers
+ # in EE the data won't be available.
+ if savers.all?(&:save) && file_saver.save
notify_success
else
notify_error!
@@ -53,32 +57,36 @@ module Groups
end
def savers
- [version_saver, tree_exporter, file_saver]
+ [version_saver, tree_exporter]
end
def tree_exporter
tree_exporter_class.new(
- group: @group,
- current_user: @current_user,
- shared: @shared,
- params: @params
+ group: group,
+ current_user: current_user,
+ shared: shared,
+ params: params
)
end
def tree_exporter_class
- if ::Feature.enabled?(:group_export_ndjson, @group&.parent, default_enabled: true)
+ if ndjson?
Gitlab::ImportExport::Group::TreeSaver
else
Gitlab::ImportExport::Group::LegacyTreeSaver
end
end
+ def ndjson?
+ ::Feature.enabled?(:group_export_ndjson, group&.parent, default_enabled: :yaml)
+ end
+
def version_saver
Gitlab::ImportExport::VersionSaver.new(shared: shared)
end
def file_saver
- Gitlab::ImportExport::Saver.new(exportable: @group, shared: @shared)
+ Gitlab::ImportExport::Saver.new(exportable: group, shared: shared)
end
def remove_archive_tmp_dir
@@ -94,22 +102,22 @@ module Groups
def notify_success
@logger.info(
message: 'Group Export succeeded',
- group_id: @group.id,
- group_name: @group.name
+ group_id: group.id,
+ group_name: group.name
)
- notification_service.group_was_exported(@group, @current_user)
+ notification_service.group_was_exported(group, current_user)
end
def notify_error
@logger.error(
message: 'Group Export failed',
- group_id: @group.id,
- group_name: @group.name,
- errors: @shared.errors.join(', ')
+ group_id: group.id,
+ group_name: group.name,
+ errors: shared.errors.join(', ')
)
- notification_service.group_was_not_exported(@group, @current_user, @shared.errors)
+ notification_service.group_was_not_exported(group, current_user, shared.errors)
end
def notification_service
diff --git a/app/services/groups/import_export/import_service.rb b/app/services/groups/import_export/import_service.rb
index a0ddc50e5e0..b62d91366e9 100644
--- a/app/services/groups/import_export/import_service.rb
+++ b/app/services/groups/import_export/import_service.rb
@@ -3,7 +3,7 @@
module Groups
module ImportExport
class ImportService
- attr_reader :current_user, :group, :params
+ attr_reader :current_user, :group, :shared
def initialize(group:, user:)
@group = group
@@ -26,10 +26,10 @@ module Groups
end
def execute
- if valid_user_permissions? && import_file && restorer.restore
+ if valid_user_permissions? && import_file && restorers.all?(&:restore)
notify_success
- @group
+ group
else
notify_error!
end
@@ -43,37 +43,41 @@ module Groups
def import_file
@import_file ||= Gitlab::ImportExport::FileImporter.import(
- importable: @group,
+ importable: group,
archive_file: nil,
- shared: @shared
+ shared: shared
)
end
- def restorer
- @restorer ||=
+ def restorers
+ [tree_restorer]
+ end
+
+ def tree_restorer
+ @tree_restorer ||=
if ndjson?
Gitlab::ImportExport::Group::TreeRestorer.new(
- user: @current_user,
- shared: @shared,
- group: @group
+ user: current_user,
+ shared: shared,
+ group: group
)
else
Gitlab::ImportExport::Group::LegacyTreeRestorer.new(
- user: @current_user,
- shared: @shared,
- group: @group,
+ user: current_user,
+ shared: shared,
+ group: group,
group_hash: nil
)
end
end
def ndjson?
- ::Feature.enabled?(:group_import_ndjson, @group&.parent, default_enabled: true) &&
- File.exist?(File.join(@shared.export_path, 'tree/groups/_all.ndjson'))
+ ::Feature.enabled?(:group_import_ndjson, group&.parent, default_enabled: true) &&
+ File.exist?(File.join(shared.export_path, 'tree/groups/_all.ndjson'))
end
def remove_import_file
- upload = @group.import_export_upload
+ upload = group.import_export_upload
return unless upload&.import_file&.file
@@ -85,7 +89,7 @@ module Groups
if current_user.can?(:admin_group, group)
true
else
- @shared.error(::Gitlab::ImportExport::Error.permission_error(current_user, group))
+ shared.error(::Gitlab::ImportExport::Error.permission_error(current_user, group))
false
end
@@ -93,16 +97,16 @@ module Groups
def notify_success
@logger.info(
- group_id: @group.id,
- group_name: @group.name,
+ group_id: group.id,
+ group_name: group.name,
message: 'Group Import/Export: Import succeeded'
)
end
def notify_error
@logger.error(
- group_id: @group.id,
- group_name: @group.name,
+ group_id: group.id,
+ group_name: group.name,
message: "Group Import/Export: Errors occurred, see '#{Gitlab::ErrorTracking::Logger.file_name}' for details"
)
end
@@ -110,11 +114,11 @@ module Groups
def notify_error!
notify_error
- raise Gitlab::ImportExport::Error.new(@shared.errors.to_sentence)
+ raise Gitlab::ImportExport::Error.new(shared.errors.to_sentence)
end
def remove_base_tmp_dir
- FileUtils.rm_rf(@shared.base_path)
+ FileUtils.rm_rf(shared.base_path)
end
end
end
diff --git a/app/services/jira/requests/base.rb b/app/services/jira/requests/base.rb
index 098aae9284c..bae8298d5c8 100644
--- a/app/services/jira/requests/base.rb
+++ b/app/services/jira/requests/base.rb
@@ -18,15 +18,15 @@ module Jira
request
end
+ private
+
+ attr_reader :jira_service, :project
+
# We have to add the context_path here because the Jira client is not taking it into account
def base_api_url
"#{context_path}/rest/api/#{api_version}"
end
- private
-
- attr_reader :jira_service, :project
-
def context_path
client.options[:context_path].to_s
end
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index de1cd7cd981..ea90d8e3dd8 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -164,6 +164,7 @@ module QuickActions
next unless definition
definition.execute(self, arg)
+ usage_ping_tracking(name, arg)
end
end
@@ -178,6 +179,14 @@ module QuickActions
ext.references(type)
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ def usage_ping_tracking(quick_action_name, arg)
+ Gitlab::UsageDataCounters::QuickActionActivityUniqueCounter.track_unique_action(
+ quick_action_name,
+ args: arg&.strip,
+ user: current_user
+ )
+ end
end
end
diff --git a/app/views/discussions/_notes.html.haml b/app/views/discussions/_notes.html.haml
index 7db318f83b1..beac4946fd7 100644
--- a/app/views/discussions/_notes.html.haml
+++ b/app/views/discussions/_notes.html.haml
@@ -19,8 +19,6 @@
.discussion-reply-holder
- if can_create_note?
- %a.user-avatar-link.d-none.d-sm-block{ href: user_path(current_user) }
- = image_tag avatar_icon_for_user(current_user), alt: current_user.to_reference, class: 'avatar s40'
.discussion-with-resolve-btn
= link_to_reply_discussion(discussion)
- elsif !current_user
diff --git a/app/views/shared/notes/_edit_form.html.haml b/app/views/shared/notes/_edit_form.html.haml
index 79d42bd5f6d..63c895a5a03 100644
--- a/app/views/shared/notes/_edit_form.html.haml
+++ b/app/views/shared/notes/_edit_form.html.haml
@@ -1,4 +1,4 @@
-.note-edit-form
+.snippets.note-edit-form
= form_tag '#', method: :put, class: 'edit-note common-note-form js-quick-submit' do
= hidden_field_tag :target_id, '', class: 'js-form-target-id'
= hidden_field_tag :target_type, '', class: 'js-form-target-type'
diff --git a/app/views/shared/notes/_notes_with_form.html.haml b/app/views/shared/notes/_notes_with_form.html.haml
index 1b03225d48d..f7f5c02370d 100644
--- a/app/views/shared/notes/_notes_with_form.html.haml
+++ b/app/views/shared/notes/_notes_with_form.html.haml
@@ -12,9 +12,6 @@
.timeline-entry-inner
.flash-container.timeline-content
- .timeline-icon.d-none.d-md-block
- %a.author-link{ href: user_path(current_user) }
- = image_tag avatar_icon_for_user(current_user), alt: current_user.to_reference, class: 'avatar s40'
.timeline-content.timeline-content-form
= render "shared/notes/form", view: diff_view, supports_autocomplete: autocomplete
- elsif !current_user
diff --git a/changelogs/unreleased/292391-quickactions-usage-ping.yml b/changelogs/unreleased/292391-quickactions-usage-ping.yml
new file mode 100644
index 00000000000..64050f281bb
--- /dev/null
+++ b/changelogs/unreleased/292391-quickactions-usage-ping.yml
@@ -0,0 +1,5 @@
+---
+title: Track monthly active users for QuickActions
+merge_request: 52398
+author:
+type: added
diff --git a/changelogs/unreleased/84402-remove-avatar-from-comment-forms.yml b/changelogs/unreleased/84402-remove-avatar-from-comment-forms.yml
new file mode 100644
index 00000000000..5662f79a071
--- /dev/null
+++ b/changelogs/unreleased/84402-remove-avatar-from-comment-forms.yml
@@ -0,0 +1,5 @@
+---
+title: Remove Avatar from Comment Forms
+merge_request: 52180
+author: Lee Tickett @leetickett
+type: other
diff --git a/config/feature_flags/development/jira_issues_show_integration.yml b/config/feature_flags/development/jira_issues_show_integration.yml
new file mode 100644
index 00000000000..dd89ace22be
--- /dev/null
+++ b/config/feature_flags/development/jira_issues_show_integration.yml
@@ -0,0 +1,8 @@
+---
+name: jira_issues_show_integration
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52446
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/299832
+milestone: '13.9'
+type: development
+group: group::ecosystem
+default_enabled: false
diff --git a/config/feature_flags/development/usage_data_track_quickactions.yml b/config/feature_flags/development/usage_data_track_quickactions.yml
new file mode 100644
index 00000000000..57f698f7031
--- /dev/null
+++ b/config/feature_flags/development/usage_data_track_quickactions.yml
@@ -0,0 +1,8 @@
+---
+name: usage_data_track_quickactions
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52398
+rollout_issue_url:
+milestone: '13.9'
+type: development
+group: group::project management
+default_enabled: false
diff --git a/doc/administration/file_hooks.md b/doc/administration/file_hooks.md
index 5de2e4aec3f..cfaeda546cc 100644
--- a/doc/administration/file_hooks.md
+++ b/doc/administration/file_hooks.md
@@ -19,19 +19,20 @@ directly to the GitLab source code and contribute back upstream. This way we can
ensure functionality is preserved across versions and covered by tests.
NOTE:
-File hooks must be configured on the filesystem of the GitLab server. Only GitLab
-server administrators will be able to complete these tasks. Explore
-[system hooks](../system_hooks/system_hooks.md) or [webhooks](../user/project/integrations/webhooks.md) as an option if you do not have filesystem access.
-
-A file hook will run on each event so it's up to you to filter events or projects
-within a file hook code. You can have as many file hooks as you want. Each file hook will
-be triggered by GitLab asynchronously in case of an event. For a list of events
+File hooks must be configured on the file system of the GitLab server. Only GitLab
+server administrators can complete these tasks. Explore
+[system hooks](../system_hooks/system_hooks.md) or [webhooks](../user/project/integrations/webhooks.md)
+as an option if you do not have file system access.
+
+A file hook runs on each event. You can filter events or projects
+in a file hook's code, and create many file hooks as you need. Each file hook is
+triggered by GitLab asynchronously in case of an event. For a list of events
see the [system hooks](../system_hooks/system_hooks.md) documentation.
## Setup
The file hooks must be placed directly into the `file_hooks` directory, subdirectories
-will be ignored. There is an
+are ignored. There is an
[`example` directory inside `file_hooks`](https://gitlab.com/gitlab-org/gitlab/tree/master/file_hooks/examples)
where you can find some basic examples.
@@ -52,23 +53,23 @@ Follow the steps below to set up a custom hook:
in any language, and ensure the 'shebang' at the top properly reflects the
language type. For example, if the script is in Ruby the shebang will
probably be `#!/usr/bin/env ruby`.
-1. The data to the file hook will be provided as JSON on STDIN. It will be exactly
+1. The data to the file hook is provided as JSON on STDIN. It is exactly the
same as for [system hooks](../system_hooks/system_hooks.md).
-That's it! Assuming the file hook code is properly implemented, the hook will fire
+That's it! Assuming the file hook code is properly implemented, the hook fires
as appropriate. The file hooks file list is updated for each event, there is no
need to restart GitLab to apply a new file hook.
If a file hook executes with non-zero exit code or GitLab fails to execute it, a
-message will be logged to:
+message is logged to:
- `gitlab-rails/plugin.log` in an Omnibus installation.
- `log/plugin.log` in a source installation.
## Creating file hooks
-Below is an example that will only response on the event `project_create` and
-will inform the admins from the GitLab instance that a new project has been created.
+This example responds only on the event `project_create`, and
+the GitLab instance informs the administrators that a new project has been created.
```ruby
#!/opt/gitlab/embedded/bin/ruby
@@ -97,7 +98,7 @@ end
Writing your own file hook can be tricky and it's easier if you can check it
without altering the system. A Rake task is provided so that you can use it
in a staging environment to test your file hook before using it in production.
-The Rake task will use a sample data and execute each of file hook. The output
+The Rake task uses a sample data and execute each of file hook. The output
should be enough to determine if the system sees your file hook and if it was
executed without errors.
diff --git a/doc/administration/git_annex.md b/doc/administration/git_annex.md
index e21a8ac7e84..07b7b1730e3 100644
--- a/doc/administration/git_annex.md
+++ b/doc/administration/git_annex.md
@@ -38,7 +38,7 @@ very fast file copying tool.
## GitLab git-annex Configuration
-`git-annex` is disabled by default in GitLab. Below you will find the
+`git-annex` is disabled by default in GitLab. Below are the
configuration options required to enable it.
### Requirements
@@ -60,7 +60,7 @@ sudo yum install epel-release && sudo yum install git-annex
### Configuration for Omnibus packages
For Omnibus GitLab packages, only one configuration setting is needed.
-The Omnibus package will internally set the correct options in all locations.
+The Omnibus package internally sets the correct options in all locations.
1. In `/etc/gitlab/gitlab.rb` add the following line:
@@ -148,15 +148,15 @@ To example.com:group/project.git
ok
```
-Your files can be found in the `master` branch, but you'll notice that there
-are more branches created by the `annex sync` command.
+Your files can be found in the `master` branch, but more branches are created
+by the `annex sync` command.
-Git Annex will also create a new directory at `.git/annex/` and will record the
+Git Annex creates a new directory at `.git/annex/` and records the
tracked files in the `.git/config` file. The files you assign to be tracked
-with `git-annex` will not affect the existing `.git/config` records. The files
+with `git-annex` don't affect the existing `.git/config` records. The files
are turned into symbolic links that point to data in `.git/annex/objects/`.
-The `debian.iso` file in the example will contain the symbolic link:
+The `debian.iso` file in the example contain the symbolic link:
```plaintext
.git/annex/objects/ZW/1k/SHA256E-s82701--6384039733b5035b559efd5a2e25a493ab6e09aabfd5162cc03f6f0ec238429d.png/SHA256E-s82701--6384039733b5035b559efd5a2e25a493ab6e09aabfd5162cc03f6f0ec238429d.iso
@@ -167,7 +167,7 @@ repository.
---
-Downloading a single large file is also very simple:
+You can download a single large file with these commands:
```shell
git clone git@gitlab.example.com:group/project.git
@@ -185,7 +185,7 @@ git annex sync --content # sync Git branches and download all the large files
```
By using `git-annex` without GitLab, anyone that can access the server can also
-access the files of all projects, but GitLab Annex ensures that you can only
+access the files of all projects. GitLab Annex ensures that you can only
access files of projects you have access to (developer, maintainer, or owner role).
## How it works
diff --git a/doc/administration/lfs/index.md b/doc/administration/lfs/index.md
index 2546556560b..862c26abac8 100644
--- a/doc/administration/lfs/index.md
+++ b/doc/administration/lfs/index.md
@@ -12,11 +12,11 @@ disqus_identifier: 'https://docs.gitlab.com/ee/workflow/lfs/lfs_administration.h
> - Support for object storage, such as AWS S3, was introduced in 10.0.
> - LFS is enabled in GitLab self-managed instances by default.
-Documentation on how to use Git LFS are under [Managing large binary files with Git LFS doc](../../topics/git/lfs/index.md).
+Documentation about how to use Git LFS are under [Managing large binary files with Git LFS doc](../../topics/git/lfs/index.md).
## Requirements
-- Users need to install [Git LFS client](https://git-lfs.github.com) version 1.0.1 and up.
+- Users need to install [Git LFS client](https://git-lfs.github.com) version 1.0.1 or later.
## Configuration
@@ -25,9 +25,9 @@ GitLab is installed on.
There are various configuration options to help GitLab server administrators:
-- Enabling/disabling Git LFS support
-- Changing the location of LFS object storage
-- Setting up object storage supported by [Fog](http://fog.io/about/provider_documentation.html)
+- Enabling/disabling Git LFS support.
+- Changing the location of LFS object storage.
+- Setting up object storage supported by [Fog](http://fog.io/about/provider_documentation.html).
### Configuration for Omnibus installations
@@ -43,7 +43,7 @@ gitlab_rails['lfs_enabled'] = false
gitlab_rails['lfs_storage_path'] = "/mnt/storage/lfs-objects"
```
-After you update settings in `/etc/gitlab/gitlab.rb`, make sure to run [Omnibus GitLab reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+After you update settings in `/etc/gitlab/gitlab.rb`, run [Omnibus GitLab reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
### Configuration for installations from source
@@ -58,14 +58,12 @@ In `config/gitlab.yml`:
## Storing LFS objects in remote object storage
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/2760) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.0. Brought to GitLab Core in 10.7.
-
-It is possible to store LFS objects in remote object storage which allows you
-to offload local hard disk R/W operations, and free up disk space significantly.
+You can store LFS objects in remote object storage. This allows you
+to offload reads and writes to the local disk, and free up disk space significantly.
GitLab is tightly integrated with `Fog`, so you can refer to its [documentation](http://fog.io/about/provider_documentation.html)
to check which storage services can be integrated with GitLab.
You can also use external object storage in a private local network. For example,
-[MinIO](https://min.io/) is a standalone object storage service, is easy to set up, and works well with GitLab instances.
+[MinIO](https://min.io/) is a standalone object storage service that works with GitLab instances.
GitLab provides two different options for the uploading mechanism: "Direct upload" and "Background upload".
@@ -78,26 +76,26 @@ This section describes the earlier configuration format.
**Option 1. Direct upload**
-1. User pushes an `lfs` file to the GitLab instance
-1. GitLab-workhorse uploads the file directly to the external object storage
-1. GitLab-workhorse notifies GitLab-rails that the upload process is complete
+1. User pushes an `lfs` file to the GitLab instance.
+1. GitLab-workhorse uploads the file directly to the external object storage.
+1. GitLab-workhorse notifies GitLab-rails that the upload process is complete.
**Option 2. Background upload**
-1. User pushes an `lfs` file to the GitLab instance
-1. GitLab-rails stores the file in the local file storage
-1. GitLab-rails then uploads the file to the external object storage asynchronously
+1. User pushes an `lfs` file to the GitLab instance.
+1. GitLab-rails stores the file in the local file storage.
+1. GitLab-rails then uploads the file to the external object storage asynchronously.
The following general settings are supported.
-| Setting | Description | Default |
-|---------|-------------|---------|
-| `enabled` | Enable/disable object storage | `false` |
-| `remote_directory` | The bucket name where LFS objects will be stored| |
-| `direct_upload` | Set to true to enable direct upload of LFS without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | `false` |
-| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
-| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
-| `connection` | Various connection options described below | |
+| Setting | Description | Default |
+|---------------------|-------------|---------|
+| `enabled` | Enable/disable object storage. | `false` |
+| `remote_directory` | The bucket name where LFS objects are stored. | |
+| `direct_upload` | Set to true to enable direct upload of LFS without the need of local shared storage. Option may be removed after we decide to support only single storage for all files. | `false` |
+| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3. | `true` |
+| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data. | `false` |
+| `connection` | Various connection options described below. | |
See [the available connection settings for different providers](../object_storage.md#connection-settings).
@@ -131,10 +129,9 @@ end
### S3 for Omnibus installations
-On Omnibus installations, the settings are prefixed by `lfs_object_store_`:
+On Omnibus GitLab installations, the settings are prefixed by `lfs_object_store_`:
-1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with
- the values you want:
+1. Edit `/etc/gitlab/gitlab.rb` and add the following lines, replacing values based on your needs:
```ruby
gitlab_rails['lfs_object_store_enabled'] = true
@@ -151,17 +148,17 @@ On Omnibus installations, the settings are prefixed by `lfs_object_store_`:
}
```
-1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. Migrate any existing local LFS objects to the object storage:
```shell
gitlab-rake gitlab:lfs:migrate
```
- This will migrate existing LFS objects to object storage. New LFS objects
- will be forwarded to object storage unless
+ This migrates existing LFS objects to object storage. New LFS objects
+ are forwarded to object storage unless
`gitlab_rails['lfs_object_store_background_upload']` and `gitlab_rails['lfs_object_store_direct_upload']` is set to `false`.
-1. Optional: Verify all files migrated properly.
+1. (Optional) Verify all files migrated properly.
From [PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database)
(`sudo gitlab-psql -d gitlabhq_production`) verify `objectstg` below (where `file_store=2`) has count of all artifacts:
@@ -204,17 +201,17 @@ For source installations the settings are nested under `lfs:` and then
path_style: true
```
-1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
+1. Save the file, and then [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
1. Migrate any existing local LFS objects to the object storage:
```shell
sudo -u git -H bundle exec rake gitlab:lfs:migrate RAILS_ENV=production
```
- This will migrate existing LFS objects to object storage. New LFS objects
- will be forwarded to object storage unless `background_upload` and `direct_upload` is set to
+ This migrates existing LFS objects to object storage. New LFS objects
+ are forwarded to object storage unless `background_upload` and `direct_upload` is set to
`false`.
-1. Optional: Verify all files migrated properly.
+1. (Optional) Verify all files migrated properly.
From PostgreSQL console (`sudo -u git -H psql -d gitlabhq_production`) verify `objectstg` below (where `file_store=2`) has count of all artifacts:
```shell
@@ -233,7 +230,7 @@ For source installations the settings are nested under `lfs:` and then
### Migrating back to local storage
-In order to migrate back to local storage:
+To migrate back to local storage:
1. Set both `direct_upload` and `background_upload` to `false` under the LFS object storage settings. Don't forget to restart GitLab.
1. Run `rake gitlab:lfs:migrate_to_local` on your console.
@@ -241,17 +238,18 @@ In order to migrate back to local storage:
## Storage statistics
-You can see the total storage used for LFS objects on groups and projects
-in the administration area, as well as through the [groups](../../api/groups.md)
-and [projects APIs](../../api/projects.md).
+You can see the total storage used for LFS objects on groups and projects:
+
+- In the administration area.
+- In the [groups](../../api/groups.md) and [projects APIs](../../api/projects.md).
## Troubleshooting: `Google::Apis::TransmissionError: execution expired`
If LFS integration is configured with Google Cloud Storage and background uploads (`background_upload: true` and `direct_upload: false`),
Sidekiq workers may encounter this error. This is because the uploading timed out with very large files.
-LFS files up to 6Gb can be uploaded without any extra steps, otherwise you need to use the following workaround.
+LFS files up to 6 GB can be uploaded without any extra steps, otherwise you need to use the following workaround.
-Log into Rails console:
+Sign in to Rails console:
```shell
sudo gitlab-rails console
@@ -282,6 +280,6 @@ See more information in [!19581](https://gitlab.com/gitlab-org/gitlab-foss/-/mer
- Support for removing unreferenced LFS objects was added in 8.14 onward.
- LFS authentications via SSH was added with GitLab 8.12.
-- Only compatible with the Git LFS client versions 1.1.0 and up, or 1.0.2.
-- The storage statistics currently count each LFS object multiple times for
+- Only compatible with the Git LFS client versions 1.1.0 and later, or 1.0.2.
+- The storage statistics count each LFS object multiple times for
every project linking to it.
diff --git a/doc/administration/pages/source.md b/doc/administration/pages/source.md
index 0aebeaf2ebe..d1a8b703860 100644
--- a/doc/administration/pages/source.md
+++ b/doc/administration/pages/source.md
@@ -407,7 +407,7 @@ Pages access control is disabled by default. To enable it:
```
1. [Restart GitLab](../restart_gitlab.md#installations-from-source).
-1. Create a new [system OAuth application](../../integration/oauth_provider.md#adding-an-application-through-the-profile).
+1. Create a new [system OAuth application](../../integration/oauth_provider.md#add-an-application-through-the-profile).
This should be called `GitLab Pages` and have a `Redirect URL` of
`https://projects.example.io/auth`. It does not need to be a "trusted"
application, but it does need the `api` scope.
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 04b8c66888e..be655e105bd 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -177,8 +177,11 @@ warrant a comment could be:
Avoid:
-- Adding comments (referenced above, or TODO items) directly to the source code unless the reviewer requires you to do so. If the comments are added due to an actionable task,
-a link to an issue must be included.
+- Adding TODO comments (referenced above) directly to the source code unless the reviewer requires
+ you to do so. If TODO comments are added due to an actionable task,
+ [include a link to the relevant issue](code_comments.md).
+- Adding comments which only explain what the code is doing. If non-TODO comments are added, they should
+ [_explain why, not what_](https://blog.codinghorror.com/code-tells-you-how-comments-tell-you-why/).
- Assigning merge requests with failed tests to maintainers. If the tests are failing and you have to assign, ensure you leave a comment with an explanation.
- Excessively mentioning maintainers through email or Slack (if the maintainer is reachable
through Slack). If you can't assign a merge request, `@` mentioning a maintainer in a comment is acceptable and in all other cases assigning the merge request is sufficient.
diff --git a/doc/integration/README.md b/doc/integration/README.md
index 1070655cc6c..0a6f9a7277a 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -65,7 +65,9 @@ Integration with services such as Campfire, Flowdock, HipChat, Pivotal Tracker,
### SSL certificate errors
-When trying to integrate GitLab with services that are using self-signed certificates, it is very likely that SSL certificate errors occur in different parts of the application, most likely Sidekiq.
+When trying to integrate GitLab with services using self-signed certificates,
+SSL certificate errors can occur in different parts of the application. Sidekiq
+is a common culprit.
There are two approaches you can take to solve this:
diff --git a/doc/integration/gmail_action_buttons_for_gitlab.md b/doc/integration/gmail_action_buttons_for_gitlab.md
index 93e8820300f..af9972e825e 100644
--- a/doc/integration/gmail_action_buttons_for_gitlab.md
+++ b/doc/integration/gmail_action_buttons_for_gitlab.md
@@ -15,20 +15,24 @@ If correctly set up, emails that require an action are marked in Gmail.
To get this functioning, you need to be registered with Google. For instructions, see
[Register with Google](https://developers.google.com/gmail/markup/registering-with-google).
-*This process has a lot of steps so make sure that you fulfill all requirements set by Google to avoid your application being rejected by Google.*
+This process has many steps. Make sure that you fulfill all requirements set by Google to avoid your application being rejected by Google.
In particular, note:
+<!-- vale gitlab.InclusionCultural = NO -->
+
- The email account used by GitLab to send notification emails must:
- Have a "Consistent history of sending a high volume of mail from your domain
(order of hundred emails a day minimum to Gmail) for a few weeks at least".
- Have a very low rate of spam complaints from users.
- Emails must be authenticated via DKIM or SPF.
-- Before sending the final form ("Gmail Schema Whitelist Request"), you must
+- Before sending the final form (**Gmail Schema Whitelist Request**), you must
send a real email from your production server. This means that you must find
a way to send this email from the email address you are registering. You can
do this by forwarding the real email from the email address you are
registering. You can also go into the Rails console on the GitLab server and
trigger sending the email from there.
+<!-- vale gitlab.InclusionCultural = YES -->
+
You can check how it looks going through all the steps laid out in the "Registering with Google" doc in [this GitLab.com issue](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/1517).
diff --git a/doc/integration/img/oauth_provider_application_form.png b/doc/integration/img/oauth_provider_application_form.png
deleted file mode 100644
index c4546d8b3f5..00000000000
--- a/doc/integration/img/oauth_provider_application_form.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/img/oauth_provider_application_id_secret.png b/doc/integration/img/oauth_provider_application_id_secret.png
deleted file mode 100644
index 21e442b5d04..00000000000
--- a/doc/integration/img/oauth_provider_application_id_secret.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/img/oauth_provider_authorized_application.png b/doc/integration/img/oauth_provider_authorized_application.png
deleted file mode 100644
index ebff8529b4e..00000000000
--- a/doc/integration/img/oauth_provider_authorized_application.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/img/oauth_provider_user_wide_applications.png b/doc/integration/img/oauth_provider_user_wide_applications.png
deleted file mode 100644
index 9cc12555574..00000000000
--- a/doc/integration/img/oauth_provider_user_wide_applications.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/jenkins_deprecated.md b/doc/integration/jenkins_deprecated.md
index b5d68e3183f..2ed87456ea1 100644
--- a/doc/integration/jenkins_deprecated.md
+++ b/doc/integration/jenkins_deprecated.md
@@ -50,7 +50,7 @@ Now navigate to GitLab services page and activate Jenkins
![screen](img/jenkins_gitlab_service.png)
-Done! Now when you push to GitLab - it creates a build for Jenkins, and you can view the merge request build status with a link to the Jenkins build.
+Done! When you push to GitLab, it creates a build for Jenkins. You can view the merge request build status with a link to the Jenkins build.
### Multi-project Configuration
diff --git a/doc/integration/jira_development_panel.md b/doc/integration/jira_development_panel.md
index a49e2a74259..d91e03de45d 100644
--- a/doc/integration/jira_development_panel.md
+++ b/doc/integration/jira_development_panel.md
@@ -62,8 +62,8 @@ self-managed GitLab) set up the integration to simplify administration.
### Jira DVCS configuration
-If you're using GitLab.com and Jira Cloud, we recommend you use the
-[GitLab for Jira app](#gitlab-for-jira-app), unless you have a specific need for the DVCS Connector.
+If you're using GitLab.com and Jira Cloud, use the
+[GitLab for Jira app](#gitlab-for-jira-app) unless you have a specific need for the DVCS Connector.
When configuring Jira DVCS Connector:
@@ -79,13 +79,11 @@ create and use a single-purpose `jira` user in GitLab.
1. In GitLab, create a new application to allow Jira to connect with your GitLab account.
- While signed in to the GitLab account that you want Jira to use to connect to GitLab,
- click your profile avatar at the top right, and then click **Settings > Applications**.
- Use the form to create a new application.
-
- In the **Name** field, enter a descriptive name for the integration, such as `Jira`.
-
- For the **Redirect URI** field, enter `https://<gitlab.example.com>/login/oauth/callback`,
+1. Sign in to the GitLab account that you want Jira to use to connect to GitLab.
+1. In the top right corner, click your profile avatar.
+1. Click **Settings > Applications** to display the form to create a new application.
+1. In the **Name** field, enter a descriptive name for the integration, such as `Jira`.
+1. In the **Redirect URI** field, enter `https://<gitlab.example.com>/login/oauth/callback`,
replacing `<gitlab.example.com>` with your GitLab instance domain. For example, if you are using GitLab.com,
this would be `https://gitlab.com/login/oauth/callback`.
@@ -97,15 +95,15 @@ create and use a single-purpose `jira` user in GitLab.
![GitLab application setup](img/jira_dev_panel_gl_setup_1.png)
- - Check **API** in the Scopes section and uncheck any other checkboxes.
+1. Check **API** in the Scopes section, and uncheck any other checkboxes.
1. Click **Save application**. GitLab displays the generated **Application ID**
and **Secret** values. Copy these values, which you use in Jira.
#### Jira DVCS Connector setup
-If you're using GitLab.com and Jira Cloud, we recommend you use the
-[GitLab for Jira app](#gitlab-for-jira-app), unless you have a specific need for the DVCS Connector.
+If you're using GitLab.com and Jira Cloud, use the
+[GitLab for Jira app](#gitlab-for-jira-app) unless you have a specific need for the DVCS Connector.
1. Ensure you have completed the [GitLab configuration](#gitlab-account-configuration-for-dvcs).
1. If you're using Jira Server, go to **Settings (gear) > Applications > DVCS accounts**.
@@ -114,37 +112,39 @@ If you're using GitLab.com and Jira Cloud, we recommend you use the
(We're pretending to be GitHub in this integration, until there's additional platform support in Jira.)
1. Complete the form:
- Select **GitHub Enterprise** for the **Host** field.
+1. Select **GitHub Enterprise** for the **Host** field.
+
+1. In the **Team or User Account** field, enter either:
- In the **Team or User Account** field, enter the relative path of a top-level GitLab group that you have access to,
- or the relative path of your personal namespace.
+ - The relative path of a top-level GitLab group that you have access to.
+ - The relative path of your personal namespace.
![Creation of Jira DVCS integration](img/jira_dev_panel_jira_setup_2.png)
- In the **Host URL** field, enter `https://<gitlab.example.com>/`,
+1. In the **Host URL** field, enter `https://<gitlab.example.com>/`,
replacing `<gitlab.example.com>` with your GitLab instance domain. For example, if you are using GitLab.com,
this would be `https://gitlab.com/`.
NOTE:
If using a GitLab version earlier than 11.3 the **Host URL** value should be `https://<gitlab.example.com>/-/jira`
- For the **Client ID** field, use the **Application ID** value from the previous section.
+1. For the **Client ID** field, use the **Application ID** value from the previous section.
- For the **Client Secret** field, use the **Secret** value from the previous section.
+1. For the **Client Secret** field, use the **Secret** value from the previous section.
- Ensure that the rest of the checkboxes are checked.
+1. Ensure that the rest of the checkboxes are checked.
1. Click **Add** to complete and create the integration.
- Jira takes up to a few minutes to know about (import behind the scenes) all the commits and branches
- for all the projects in the GitLab group you specified in the previous step. These are refreshed
- every 60 minutes.
+ Jira takes up to a few minutes to know about (import behind the scenes) all the commits and branches
+ for all the projects in the GitLab group you specified in the previous step. These are refreshed
+ every 60 minutes.
- In the future, we plan on implementing real-time integration. If you need
- to refresh the data manually, you can do this from the `Applications -> DVCS
- accounts` screen where you initially set up the integration:
+ In the future, we plan on implementing real-time integration. If you need
+ to refresh the data manually, you can do this from the `Applications -> DVCS
+ accounts` screen where you initially set up the integration:
- ![Refresh GitLab information in Jira](img/jira_dev_panel_manual_refresh.png)
+ ![Refresh GitLab information in Jira](img/jira_dev_panel_manual_refresh.png)
To connect additional GitLab projects from other GitLab top-level groups (or personal namespaces), repeat the previous
steps with additional Jira DVCS accounts.
@@ -252,7 +252,7 @@ resynchronize the information. To do so:
You can integrate GitLab.com and Jira Cloud using the [GitLab for Jira](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud) app in the Atlassian Marketplace.
-This method is recommended when using GitLab.com and Jira Cloud because data is synchronized in real-time, while the DVCS connector updates data only once per hour. If you are not using both of these environments, use the [Jira DVCS Connector](#jira-dvcs-configuration) method.
+This method is recommended when using GitLab.com and Jira Cloud because data is synchronized in real-time. The DVCS connector updates data only once per hour. If you are not using both of these environments, use the [Jira DVCS Connector](#jira-dvcs-configuration) method.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For a walkthrough of the integration with GitLab for Jira, watch [Configure GitLab Jira Integration using Marketplace App](https://youtu.be/SwR-g1s1zTo) on YouTube.
@@ -285,7 +285,7 @@ For more information, see [Usage](#usage).
#### Troubleshooting GitLab for Jira
-The GitLab for Jira App uses an iframe to add namespaces on the settings page. Some browsers block cross-site cookies which can lead to a message saying that the user needs to log in on GitLab.com even though the user is already logged in.
+The GitLab for Jira App uses an iframe to add namespaces on the settings page. Some browsers block cross-site cookies. This can lead to a message saying that the user needs to log in on GitLab.com even though the user is already logged in.
> "You need to sign in or sign up before continuing."
diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md
index 2302ab2d853..8f1c625d142 100644
--- a/doc/integration/oauth_provider.md
+++ b/doc/integration/oauth_provider.md
@@ -1,82 +1,74 @@
---
-stage: Create
-group: Ecosystem
+stage: Manage
+group: Access
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# GitLab as OAuth2 authentication service provider
-This document is about using GitLab as an OAuth authentication service provider
-to sign in to other services.
+This document describes how you can use GitLab as an OAuth 2
+authentication service provider.
If you want to use:
- The [OAuth2](https://oauth.net/2/) protocol to access GitLab resources on user's behalf,
- see [OAuth2 provider](../api/oauth2.md)
-- Other OAuth authentication service providers to sign in to
+ see [OAuth2 provider](../api/oauth2.md).
+- Other OAuth 2 authentication service providers to sign in to
GitLab, see the [OAuth2 client documentation](omniauth.md).
- The related API, see [Applications API](../api/applications.md).
## Introduction to OAuth
-[OAuth](https://oauth.net/2/) provides to client applications a 'secure delegated access' to server
-resources on behalf of a resource owner. OAuth allows an authorization
-server to issue access tokens to third-party clients with the approval of the
-resource owner, or the end-user.
+[OAuth 2](https://oauth.net/2/) provides to client applications a 'secure delegated
+access' to server resources on behalf of a resource owner. OAuth 2 allows
+authorization servers to issue access tokens to third-party clients with the approval
+of the resource owner or the end-user.
-OAuth is mostly used as a Single Sign-On service (SSO), but you can find a
-lot of different uses for this functionality. For example, you can allow users
-to sign in to your application with their GitLab.com account. You can also use GitLab.com
-for authentication to your GitLab instance (see [GitLab OmniAuth](gitlab.md)).
+OAuth 2 can be used:
-The 'GitLab Importer' feature is also using the OAuth protocol to give access
+- To allow users to sign in to your application with their GitLab.com account.
+- To set up GitLab.com for authentication to your GitLab instance.
+(see [GitLab OmniAuth](gitlab.md)).
+
+The 'GitLab Importer' feature also uses OAuth 2 to give access
to repositories without sharing user credentials to your GitLab.com account.
-GitLab supports two ways of adding a new OAuth2 application to an instance. You
-can either add an application as a regular user or add it in the Admin Area.
-What this means is that GitLab can actually have instance-wide and a user-wide
-applications. There is no difference between them except for the different
-permission levels they are set (user or administrator). The default callback URL is
-`http://your-gitlab.example.com/users/auth/gitlab/callback`
+GitLab supports two ways of adding a new OAuth 2 application to an instance:
-## Adding an application through the profile
+- As a regular user, for applications owned by an individual.
+- Through the Admin Area menu for instance-wide apps.
-In order to add a new application via your profile, navigate to
-**Profile Settings > Applications** and select **New Application**.
+The only difference between these two methods is the [permission](../user/permissions.md)
+levels. The default callback URL is `http://your-gitlab.example.com/users/auth/gitlab/callback`.
-![New OAuth application](img/oauth_provider_user_wide_applications.png)
+## Add an application through the profile
-In the application form, enter a **Name** (arbitrary), and make sure to set up
-correctly the **Redirect URI** which is the URL where users are sent after
-they authorize with GitLab.
+To add a new application via your profile, select your avatar in the top right, and then select
+**Settings > Applications**. You can then enter a **Name**, **Redirect URI** and
+OAuth 2 scopes as defined in [Authorized Applications](#authorized-applications).
-![New OAuth application form](img/oauth_provider_application_form.png)
+- The **Redirect URI** is the URL where users are sent after they authorize with GitLab.
-When you click **Submit** you are provided with the application ID and
-the application secret which you can then use with your application that
-connects to GitLab.
+When you select **Save application**, GitLab displays:
-![OAuth application ID and secret](img/oauth_provider_application_id_secret.png)
+- Application ID: OAuth 2 Client ID.
+- Secret: OAuth 2 Client Secret.
## OAuth applications in the Admin Area
-To create an application that does not belong to a certain user, you can create
-it from the Admin Area.
-
-![OAuth administrator applications](img/oauth_provider_admin_application.png)
+To create an application for your GitLab instance, select
+**Admin Area > Applications > New application**.
-You're also able to mark an application as _trusted_ when creating it through the Admin Area. By doing that,
-the user authorization step is automatically skipped for this application.
+When creating an **Admin Area** application, you can mark it as _trusted_.
+The user authorization step is automatically skipped for this application.
## Authorized applications
-Every application you authorized to use your GitLab credentials is shown
-in the **Authorized applications** section under **Profile Settings > Applications**.
-
-![Authorized_applications](img/oauth_provider_authorized_application.png)
+Every application you authorize with your GitLab credentials is shown
+in the **Authorized applications** section under **Settings > Applications**.
-The GitLab OAuth applications support scopes, which allow various actions that any given
-application can perform. The available scopes are depicted in the following table.
+The GitLab OAuth 2 applications support scopes, which allow various actions that any given
+application can perform. Available scopes are depicted in the following table.
| Scope | Description |
| ------------------ | ----------- |
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index cd582c2edc3..54fa5b0a732 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -66,7 +66,7 @@ earlier version, you must explicitly enable it.
NOTE:
If you set `block_auto_created_users` to `false`, make sure to only
define providers under `allow_single_sign_on` that you are able to control, like
-SAML, Shibboleth, Crowd, or Google, or set it to `false` otherwise any user on
+SAML, Shibboleth, Crowd, or Google. Otherwise, set it to `false`, or any user on
the Internet can successfully sign in to your GitLab without
administrative approval.
@@ -168,8 +168,6 @@ omniauth:
## Configure OmniAuth Providers as External
-> Introduced in GitLab 8.7.
-
You can define which OmniAuth providers you want to be `external`. Users
creating accounts, or logging in by using these `external` providers cannot have
access to internal projects. You must use the full name of the provider,
@@ -215,7 +213,7 @@ from the OmniAuth provider's documentation.
sudo service gitlab stop
```
-- Add the gem to your [Gemfile](https://gitlab.com/gitlab-org/gitlab/blob/master/Gemfile):
+- Add the gem to your [`Gemfile`](https://gitlab.com/gitlab-org/gitlab/blob/master/Gemfile):
```shell
gem "omniauth-your-auth-provider"
@@ -240,25 +238,28 @@ from the OmniAuth provider's documentation.
If you have successfully set up a provider that is not shipped with GitLab itself,
please let us know.
+Share your experience [in the public Wiki](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Custom-omniauth-provider-configurations).
You can help others by reporting successful configurations and probably share a
-few insights or provide warnings for common errors or pitfalls by sharing your
-experience [in the public Wiki](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Custom-omniauth-provider-configurations).
+few insights or provide warnings for common errors or pitfalls.
While we can't officially support every possible authentication mechanism out there,
we'd like to at least help those with specific needs.
## Enable or disable Sign In with an OmniAuth provider without disabling import sources
-> Introduced in GitLab 8.8.
-
-Administrators are able to enable or disable Sign In by using some OmniAuth providers.
+Administrators are able to enable or disable **Sign In** by using some OmniAuth providers.
NOTE:
-By default Sign In is enabled by using all the OAuth Providers that have been configured in `config/gitlab.yml`.
+By default, **Sign In** is enabled by using all the OAuth Providers that have been configured in `config/gitlab.yml`.
+
+To enable/disable an OmniAuth provider:
-In order to enable/disable an OmniAuth provider, go to Admin Area -> Settings -> Sign-in Restrictions section -> Enabled OAuth Sign-In sources and select the providers you want to enable or disable.
+1. In the top navigation bar, go to **Admin Area**.
+1. In the left sidebar, go to **Settings**.
+1. Scroll to the **Sign-in Restrictions** section, and click **Expand**.
+1. Next to **Enabled OAuth Sign-In sources**, select the check box for each provider you want to enable or disable.
-![Enabled OAuth Sign-In sources](img/enabled-oauth-sign-in-sources.png)
+ ![Enabled OAuth Sign-In sources](img/enabled-oauth-sign-in-sources.png)
## Disabling OmniAuth
@@ -325,7 +326,7 @@ omniauth:
You can add the `auto_sign_in_with_provider` setting to your GitLab
configuration to redirect login requests to your OmniAuth provider for
-authentication, removing the need to click a button before actually signing in.
+authentication. This removes the need to click a button before actually signing in.
For example, when using the Azure integration, set the following to enable auto
sign-in:
diff --git a/doc/integration/openid_connect_provider.md b/doc/integration/openid_connect_provider.md
index 6161f463b99..4455ace3e1f 100644
--- a/doc/integration/openid_connect_provider.md
+++ b/doc/integration/openid_connect_provider.md
@@ -17,8 +17,7 @@ OAuth 2.0 protocol. It allows clients to:
- Verify the identity of the end-user based on the authentication performed by GitLab.
- Obtain basic profile information about the end-user in an interoperable and REST-like manner.
-OIDC performs many of the same tasks as OpenID 2.0,
-but does so in a way that is API-friendly and usable by native and
+OIDC performs many of the same tasks as OpenID 2.0, but is API-friendly and usable by native and
mobile applications.
On the client side, you can use [OmniAuth::OpenIDConnect](https://github.com/jjbohn/omniauth-openid-connect/) for Rails
diff --git a/doc/push_rules/push_rules.md b/doc/push_rules/push_rules.md
index b80d65a62b5..37880f22ffe 100644
--- a/doc/push_rules/push_rules.md
+++ b/doc/push_rules/push_rules.md
@@ -10,16 +10,16 @@ type: reference, howto
Gain additional control over what can and can't be pushed to your repository by using
regular expressions to reject pushes based on commit contents, branch names or file details.
-## Overview
-
GitLab already offers [protected branches](../user/project/protected_branches.md), but there are
-cases when you need some specific rules like preventing Git tag removal or
+cases when you need some specific rules. Some common scenarios: preventing Git tag removal, or
enforcing a special format for commit messages.
-Push rules are essentially [pre-receive Git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) that are easy to
-enable in a user-friendly interface. They are defined globally if you are an
-admin or per project so you can have different rules applied to different
-projects depending on your needs.
+Push rules are [pre-receive Git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) you
+can enable in a user-friendly interface. They are defined either:
+
+- Globally if you are an administrator.
+- Per project, so you can have different rules applied to different
+ projects depending on your needs.
## Use cases
@@ -32,24 +32,24 @@ Let's assume you have the following requirements for your workflow:
- every commit should reference a Jira issue, for example: `Refactored css. Fixes JIRA-123.`
- users should not be able to remove Git tags with `git push`
-All you need to do is write a simple regular expression that requires the mention
+Write a regular expression that requires the mention
of a Jira issue in the commit message, like `JIRA\-\d+`.
-Now when a user tries to push a commit with a message `Bugfix`, their push will
-be declined. Only pushing commits with messages like `Bugfix according to JIRA-123`
-will be accepted.
+Now when a user tries to push a commit with a message `Bugfix`, their push is
+declined. Only pushing commits with messages like `Bugfix according to JIRA-123`
+is accepted.
### Restrict branch names
-Let's assume there's a strict policy for branch names in your company, and
-you want the branches to start with a certain name because you have different
-GitLab CI/CD jobs (`feature`, `hotfix`, `docker`, `android`, etc.) that rely on the
+If your company has a strict policy for branch names, you may want the branches to start
+with a certain name. This approach enables different
+GitLab CI/CD jobs (such as `feature`, `hotfix`, `docker`, `android`) that rely on the
branch name.
-Your developers, however, don't always remember that policy, so they might push to
+Your developers may not remember that policy, so they might push to
various branches, and CI pipelines might not work as expected. By restricting the
branch names globally in Push Rules, such mistakes are prevented.
-Any branch name that doesn't match your push rule will get rejected.
+Any branch name that doesn't match your push rule is rejected.
Note that the name of your default branch is always allowed, regardless of the branch naming
regular expression (regex) specified. GitLab is configured this way
@@ -64,7 +64,7 @@ which already limits users from pushing directly.
> Introduced in GitLab 12.10.
By default, GitLab restricts certain formats of branch names for security purposes.
-Currently 40-character hexadecimal names, similar to Git commit hashes, are prohibited.
+40-character hexadecimal names, similar to Git commit hashes, are prohibited.
### Custom Push Rules **(FREE SELF)**
@@ -77,7 +77,7 @@ See [server hooks](../administration/server_hooks.md) for more information.
NOTE:
GitLab administrators can set push rules globally under
-**Admin Area > Push Rules** that all new projects will inherit. You can later
+**Admin Area > Push Rules** that all new projects inherit. You can later
override them in a project's settings. They can be also set on a [group level](../user/group/index.md#group-push-rules).
1. Navigate to your project's **Settings > Repository** and expand **Push Rules**
@@ -88,11 +88,11 @@ The following options are available:
| Push rule | Description |
|---------------------------------|-------------|
-| Removal of tags with `git push` | Forbid users to remove Git tags with `git push`. Tags will still be able to be deleted through the web UI. |
+| Removal of tags with `git push` | Forbid users to remove Git tags with `git push`. Tags can be deleted through the web UI. |
| Check whether author is a GitLab user | Restrict commits by author (email) to existing GitLab users. |
-| Committer restriction **(PREMIUM)** | GitLab will reject any commit that was not committed by the current authenticated user. |
+| Committer restriction **(PREMIUM)** | GitLab rejects any commit that was not committed by the current authenticated user. |
| Check whether commit is signed through GPG **(PREMIUM)** | Reject commit when it is not signed through GPG. Read [signing commits with GPG](../user/project/repository/gpg_signed_commits/index.md). |
-| Prevent committing secrets to Git | GitLab will reject any files that are likely to contain secrets. Read [what files are forbidden](#prevent-pushing-secrets-to-the-repository). |
+| Prevent committing secrets to Git | GitLab rejects any files that are likely to contain secrets. Read [what files are forbidden](#prevent-pushing-secrets-to-the-repository). |
| Restrict by commit message | Only commit messages that match this regular expression are allowed to be pushed. Leave empty to allow any commit message. Uses multiline mode, which can be disabled using `(?-m)`. |
| Restrict by commit message (negative match) | Only commit messages that do not match this regular expression are allowed to be pushed. Leave empty to allow any commit message. Uses multiline mode, which can be disabled using `(?-m)`. |
| Restrict by branch name | Only branch names that match this regular expression are allowed to be pushed. Leave empty to allow any branch name. |
@@ -108,8 +108,8 @@ GitLab uses [RE2 syntax](https://github.com/google/re2/wiki/Syntax) for regular
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/385) in [GitLab Starter](https://about.gitlab.com/pricing/) 8.12.
Secrets such as credential files, SSH private keys, and other files containing secrets should never be committed to source control.
-GitLab allows you to turn on a predefined denylist of files which won't be allowed to be
-pushed to a repository, stopping those commits from reaching the remote repository.
+GitLab enables you to turn on a predefined denylist of files which can't be
+pushed to a repository. The list stops those commits from reaching the remote repository.
By selecting the checkbox *Prevent committing secrets to Git*, GitLab prevents
pushes to the repository when a file matches a regular expression as read from
@@ -117,9 +117,9 @@ pushes to the repository when a file matches a regular expression as read from
as your GitLab version when viewing this file).
NOTE:
-Files already committed won't get restricted by this push rule.
+Files already committed aren't restricted by this push rule.
-Below is an example list of what will be rejected by these regular expressions:
+Below is an example list of what GitLab rejects with these regular expressions:
```shell
#####################
@@ -204,13 +204,17 @@ Example: prevent a specific configuration file in a known directory from being p
^directory-name\/config\.yml$
```
-Example: prevent the specific file named `install.exe` from being pushed to any location in the repository. Note that the parenthesized expression `(^|\/)` will match either a file following a directory separator or a file in the root directory of the repository:
+Example: prevent the specific file named `install.exe` from being pushed to any
+location in the repository. The parenthesized expression `(^|\/)` matches either
+a file following a directory separator or a file in the root directory of the repository:
```plaintext
(^|\/)install\.exe$
```
-Example: combining all of the above in a single expression. Note that all of the preceding expressions rely on the end of string character `$`, so we can move that part of each expression to the end of the grouped collection of match conditions where it will be appended to all matches:
+Example: combining all of the above in a single expression. The preceding expressions rely
+on the end-of-string character `$`. We can move that part of each expression to the
+end of the grouped collection of match conditions where it is appended to all matches:
```plaintext
(\.exe|^config\.yml|^directory-name\/config\.yml|(^|\/)install\.exe)$
diff --git a/doc/topics/git/troubleshooting_git.md b/doc/topics/git/troubleshooting_git.md
index aace979004f..0724e503923 100644
--- a/doc/topics/git/troubleshooting_git.md
+++ b/doc/topics/git/troubleshooting_git.md
@@ -14,7 +14,7 @@ with Git.
## Broken pipe errors on `git push`
'Broken pipe' errors can occur when attempting to push to a remote repository.
-When pushing you will usually see:
+When pushing you usually see:
```plaintext
Write failed: Broken pipe
@@ -45,14 +45,13 @@ set to 50MB. The default is 1MB.
**If pushing over SSH**, first check your SSH configuration as 'Broken pipe'
errors can sometimes be caused by underlying issues with SSH (such as
authentication). Make sure that SSH is correctly configured by following the
-instructions in the [SSH troubleshooting](../../ssh/README.md#troubleshooting) docs.
+instructions in the [SSH troubleshooting](../../ssh/README.md#troubleshooting) documentation.
-There's another option where you can prevent session timeouts by configuring
-SSH 'keep alive' either on the client or on the server (if you are a GitLab
-admin and have access to the server).
+If you're a GitLab administrator and have access to the server, you can also prevent
+session timeouts by configuring SSH `keep alive` either on the client or on the server.
NOTE:
-Configuring *both* the client and the server is unnecessary.
+Configuring both the client and the server is unnecessary.
**To configure SSH on the client side**:
@@ -67,7 +66,7 @@ Configuring *both* the client and the server is unnecessary.
- On Windows, if you are using PuTTY, go to your session properties, then
navigate to "Connection" and under "Sending of null packets to keep
- session active", set "Seconds between keepalives (0 to turn off)" to `60`.
+ session active", set `Seconds between keepalives (0 to turn off)` to `60`.
**To configure SSH on the server side**, edit `/etc/ssh/sshd_config` and add:
@@ -125,7 +124,7 @@ MaxStartups 100:30:200
```
`100:30:200` means up to 100 SSH sessions are allowed without restriction,
-after which 30% of connections will be dropped until reaching an absolute maximum of 200.
+after which 30% of connections are dropped until reaching an absolute maximum of 200.
Once configured, restart the SSH daemon for the change to take effect.
@@ -140,7 +139,7 @@ sudo service sshd restart
## Timeout during `git push` / `git pull`
If pulling/pushing from/to your repository ends up taking more than 50 seconds,
-a timeout will be issued with a log of the number of operations performed
+a timeout is issued. It contains a log of the number of operations performed
and their respective timings, like the example below:
```plaintext
@@ -154,7 +153,7 @@ and provide GitLab with more information on how to improve the service.
## `git clone` over HTTP fails with `transfer closed with outstanding read data remaining` error
-If the buffer size is lower than what is allowed in the request, the action will fail with an error similar to the one below:
+If the buffer size is lower than what is allowed in the request, the action fails with an error similar to the one below:
```plaintext
error: RPC failed; curl 18 transfer closed with outstanding read data remaining
@@ -163,7 +162,7 @@ fatal: early EOF
fatal: index-pack failed
```
-This can be fixed by increasing the existing `http.postBuffer` value to one greater than the repository size. For example, if `git clone` fails when cloning a 500M repository, the solution will be to set `http.postBuffer` to `524288000` so that the request only starts buffering after the first 524288000 bytes.
+This can be fixed by increasing the existing `http.postBuffer` value to one greater than the repository size. For example, if `git clone` fails when cloning a 500M repository, you should set `http.postBuffer` to `524288000`. That setting ensures the request only starts buffering after the first 524288000 bytes.
NOTE:
The default value of `http.postBuffer`, 1 MiB, is applied if the setting is not configured.
diff --git a/doc/topics/gitlab_flow.md b/doc/topics/gitlab_flow.md
index dc320192717..97135e421f8 100644
--- a/doc/topics/gitlab_flow.md
+++ b/doc/topics/gitlab_flow.md
@@ -16,7 +16,7 @@ It combines [feature-driven development](https://en.wikipedia.org/wiki/Feature-d
Organizations coming to Git from other version control systems frequently find it hard to develop a productive workflow.
This article describes GitLab flow, which integrates the Git workflow with an issue tracking system.
-It offers a simple, transparent, and effective way to work with Git.
+It offers a transparent and effective way to work with Git.
![Four stages (working copy, index, local repository, remote repository) and three steps between them](img/gitlab_flow_four_stages.png)
@@ -28,7 +28,7 @@ After getting used to these three steps, the next challenge is the branching mod
![Multiple long-running branches and merging in all directions](img/gitlab_flow_messy_flow.png)
-Since many organizations new to Git have no conventions for how to work with it, their repositories can quickly become messy.
+Because many organizations new to Git have no conventions for how to work with it, their repositories can quickly become messy.
The biggest problem is that many long-running branches emerge that all contain part of the changes.
People have a hard time figuring out which branch has the latest code, or which branch to deploy to production.
Frequently, the reaction to this problem is to adopt a standardized pattern such as [Git flow](https://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html).
@@ -51,7 +51,7 @@ The development happens on the `develop` branch, moves to a release branch, and
Git flow is a well-defined standard, but its complexity introduces two problems.
The first problem is that developers must use the `develop` branch and not `master`. `master` is reserved for code that is released to production.
It is a convention to call your default branch `master` and to mostly branch from and merge to this.
-Since most tools automatically use the `master` branch as the default, it is annoying to have to switch to another branch.
+Because most tools automatically use the `master` branch as the default, it is annoying to have to switch to another branch.
The second problem of Git flow is the complexity introduced by the hotfix and release branches.
These branches can be a good idea for some organizations but are overkill for the vast majority of them.
@@ -65,28 +65,32 @@ For example, many projects do releases but don't need to do hotfixes.
## GitHub flow as a simpler alternative
-![Master branch with feature branches merged in](img/gitlab_flow_github_flow.png)
+![Branch with feature branches merged in](img/gitlab_flow_github_flow.png)
In reaction to Git flow, GitHub created a simpler alternative.
[GitHub flow](https://guides.github.com/introduction/flow/index.html) has only feature branches and a `master` branch.
This flow is clean and straightforward, and many organizations have adopted it with great success.
Atlassian recommends [a similar strategy](https://www.atlassian.com/blog/git/simple-git-workflow-is-simple), although they rebase feature branches.
-Merging everything into the `master` branch and frequently deploying means you minimize the amount of unreleased code, which is in line with lean and continuous delivery best practices.
+Merging everything into the `master` branch and frequently deploying means you minimize the amount of unreleased code. This approach is in line with lean and continuous delivery best practices.
However, this flow still leaves a lot of questions unanswered regarding deployments, environments, releases, and integrations with issues.
With GitLab flow, we offer additional guidance for these questions.
## Production branch with GitLab flow
-![Master branch and production branch with an arrow that indicates a deployment](img/gitlab_flow_production_branch.png)
+![Branches with an arrow that indicates a deployment](img/gitlab_flow_production_branch.png)
GitHub flow assumes you can deploy to production every time you merge a feature branch.
-While this is possible in some cases, such as SaaS applications, there are many cases where this is not possible.
-One case is where you don't control the timing of a release, for example, an iOS application that is released when it passes App Store validation.
-Another case is when you have deployment windows &mdash; for example, workdays from 10&nbsp;AM to 4&nbsp;PM when the operations team is at full capacity &mdash; but you also merge code at other times.
+While this is possible in some cases, such as SaaS applications, there are some cases where this is not possible, such as:
+
+- You don't control the timing of a release. For example, an iOS application that
+ is released when it passes App Store validation.
+- You have deployment windows - for example, workdays from 10 AM to 4 PM when the
+ operations team is at full capacity - but you also merge code at other times.
+
In these cases, you can make a production branch that reflects the deployed code.
You can deploy a new version by merging `master` into the production branch.
-If you need to know what code is in production, you can just checkout the production branch to see.
-The approximate time of deployment is easily visible as the merge commit in the version control system.
+If you need to know what code is in production, you can check out the production branch to see.
+The approximate time of deployment is visible as the merge commit in the version control system.
This time is pretty accurate if you automatically deploy your production branch.
If you need a more exact time, you can have your deployment script create a tag on each deployment.
This flow prevents the overhead of releasing, tagging, and merging that happens with Git flow.
@@ -109,10 +113,10 @@ If this is not possible because more manual testing is required, you can send me
## Release branches with GitLab flow
-![Master and multiple release branches that vary in length with cherry-picks from master](img/gitlab_flow_release_branches.png)
+![Multiple release branches that vary in length with cherry-picks](img/gitlab_flow_release_branches.png)
You only need to work with release branches if you need to release software to the outside world.
-In this case, each branch contains a minor version, for example, 2-3-stable, 2-4-stable, etc.
+In this case, each branch contains a minor version, such as `2-3-stable` or `2-4-stable`.
Create stable branches using `master` as a starting point, and branch as late as possible.
By doing this, you minimize the length of time during which you have to apply bug fixes to multiple branches.
After announcing a release branch, only add serious bug fixes to the branch.
@@ -128,11 +132,11 @@ In this flow, it is not common to have a production branch (or Git flow `master`
![Merge request with inline comments](img/gitlab_flow_mr_inline_comments.png)
Merge or pull requests are created in a Git management application. They ask an assigned person to merge two branches.
-Tools such as GitHub and Bitbucket choose the name "pull request" since the first manual action is to pull the feature branch.
-Tools such as GitLab and others choose the name "merge request" since the final action is to merge the feature branch.
-In this article, we'll refer to them as merge requests.
+Tools such as GitHub and Bitbucket choose the name "pull request", because the first manual action is to pull the feature branch.
+Tools such as GitLab and others choose the name "merge request", because the final action is to merge the feature branch.
+This article refers to them as merge requests.
-If you work on a feature branch for more than a few hours, it is good to share the intermediate result with the rest of the team.
+If you work on a feature branch for more than a few hours, share the intermediate result with the rest of your team.
To do this, create a merge request without assigning it to anyone.
Instead, mention people in the description or a comment, for example, "/cc @mark @susan."
This indicates that the merge request is not ready to be merged yet, but feedback is welcome.
@@ -147,7 +151,7 @@ Also, mention any other people from whom you would like feedback.
After the assigned person feels comfortable with the result, they can merge the branch.
If the assigned person does not feel comfortable, they can request more changes or close the merge request without merging.
-In GitLab, it is common to protect the long-lived branches, e.g., the `master` branch, so that [most developers can't modify them](../user/permissions.md).
+In GitLab, it is common to protect the long-lived branches, such as the `master` branch, so [most developers can't modify them](../user/permissions.md).
So, if you want to merge into a protected branch, assign your merge request to someone with maintainer permissions.
After you merge a feature branch, you should remove it from the source control software.
@@ -169,10 +173,10 @@ GitLab flow is a way to make the relation between the code and the issue tracker
Any significant change to the code should start with an issue that describes the goal.
Having a reason for every code change helps to inform the rest of the team and to keep the scope of a feature branch small.
In GitLab, each change to the codebase starts with an issue in the issue tracking system.
-If there is no issue yet, create the issue, as long as the change will take a significant amount of work, i.e., more than 1 hour.
+If there is no issue yet, create the issue if the change requires more than an hour's work.
In many organizations, raising an issue is part of the development process because they are used in sprint planning.
The issue title should describe the desired state of the system.
-For example, the issue title "As an administrator, I want to remove users without receiving an error" is better than "Admin can't remove users."
+For example, the issue title "As an administrator, I want to remove users without receiving an error" is better than "Administrators can't remove users."
When you are ready to code, create a branch for the issue from the `master` branch.
This branch is the place for any work related to this change.
@@ -189,20 +193,20 @@ Start the title of the merge request with `[Draft]`, `Draft:` or `(Draft)` to pr
When you think the code is ready, assign the merge request to a reviewer.
The reviewer can merge the changes when they think the code is ready for inclusion in the `master` branch.
-When they press the merge button, GitLab merges the code and creates a merge commit that makes this event easily visible later on.
+When they press the merge button, GitLab merges the code and creates a merge commit that makes this event visible later on.
Merge requests always create a merge commit, even when the branch could be merged without one.
This merge strategy is called "no fast-forward" in Git.
-After the merge, delete the feature branch since it is no longer needed.
+After the merge, delete the feature branch, because it is no longer needed.
In GitLab, this deletion is an option when merging.
Suppose that a branch is merged but a problem occurs and the issue is reopened.
-In this case, it is no problem to reuse the same branch name since the first branch was deleted when it was merged.
+In this case, it is no problem to reuse the same branch name, because the first branch was deleted when it was merged.
At any time, there is at most one branch for every issue.
It is possible that one feature branch solves more than one issue.
## Linking and closing issues from merge requests
-![Merge request showing the linked issues that will be closed](img/gitlab_flow_close_issue_mr.png)
+![Merge request showing the linked issues to close](img/gitlab_flow_close_issue_mr.png)
Link to issues by mentioning them in commit messages or the description of a merge request, for example, "Fixes #16" or "Duck typing is preferred. See #12."
GitLab then creates links to the mentioned issues and creates comments in the issues linking back to the merge request.
@@ -216,12 +220,12 @@ If you have an issue that spans across multiple repositories, create an issue fo
![Vim screen showing the rebase view](img/gitlab_flow_rebase.png)
With Git, you can use an interactive rebase (`rebase -i`) to squash multiple commits into one or reorder them.
-This functionality is useful if you want to replace a couple of small commits with a single commit, or if you want to make the order more logical.
+This feature helps you replace a couple of small commits with a single commit, or if you want to make the order more logical.
However, you should avoid rebasing commits you have pushed to a remote server if you have other active contributors in the same branch.
-Since rebasing creates new commits for all your changes, it can cause confusion because the same change would have multiple identifiers.
+Because rebasing creates new commits for all your changes, it can cause confusion because the same change would have multiple identifiers.
It would cause merge errors for anyone working on the same branch because their history would not match with yours. It can be really troublesome for the author or other contributors.
-Also, if someone has already reviewed your code, rebasing makes it hard to tell what changed since the last review.
+Also, if someone has already reviewed your code, rebasing makes it hard to tell what changed after the last review.
You should never rebase commits authored by other people unless you've agreed otherwise.
Not only does this rewrite history, but it also loses authorship information.
@@ -229,7 +233,7 @@ Rebasing prevents the other authors from being attributed and sharing part of th
If a merge involves many commits, it may seem more difficult to undo.
You might consider solving this by squashing all the changes into one commit just before merging by using the GitLab [Squash-and-Merge](../user/project/merge_requests/squash_and_merge.md) feature.
-Fortunately, there is an easy way to undo a merge with all its commits.
+Fortunately, you can undo a merge with all its commits.
The way to do this is by reverting the merge commit.
Preserving this ability to revert a merge is a good reason to always use the "no fast-forward" (`--no-ff`) strategy when you merge manually.
@@ -247,8 +251,8 @@ Often, people avoid merge commits by just using rebase to reorder their commits
Using rebase prevents a merge commit when merging `master` into your feature branch, and it creates a neat linear history.
However, as discussed in [the section about rebasing](#squashing-commits-with-rebase), you should avoid rebasing commits in a feature branch that you're sharing with others.
-Rebasing could create more work, since every time you rebase, you may need to resolve the same conflicts.
-Sometimes you can reuse recorded resolutions (`rerere`), but merging is better since you only have to resolve conflicts once.
+Rebasing could create more work, as every time you rebase, you may need to resolve the same conflicts.
+Sometimes you can reuse recorded resolutions (`rerere`), but merging is better, because you only have to resolve conflicts once.
Atlassian has a more thorough explanation of the tradeoffs between merging and rebasing [on their blog](https://www.atlassian.com/blog/git/git-team-workflows-merge-or-rebase).
A good way to prevent creating many merge commits is to not frequently merge `master` into the feature branch.
@@ -274,8 +278,8 @@ You could also use [feature toggles](https://martinfowler.com/bliki/FeatureToggl
NOTE:
Don't confuse automatic branch testing with continuous integration.
-Martin Fowler makes this distinction in [his article about feature branches](https://martinfowler.com/bliki/FeatureBranch.html):
-"I've heard people say they are doing CI because they are running builds, perhaps using a CI server, on every branch with every commit.
+Martin Fowler makes this distinction in [an article about feature branches](https://martinfowler.com/bliki/FeatureBranch.html):
+"\[People\] say they are doing CI because they are running builds, perhaps using a CI server, on every branch with every commit.
That's continuous building, and a Good Thing, but there's no *integration*, so it's not CI."
In conclusion, you should try to prevent merge commits, but not eliminate them.
@@ -289,19 +293,19 @@ If you rebase code, the history is incorrect, and there is no way for tools to r
Another way to make your development work easier is to commit often.
Every time you have a working set of tests and code, you should make a commit.
Splitting up work into individual commits provides context for developers looking at your code later.
-Smaller commits make it clear how a feature was developed, and they make it easy to roll back to a specific good point in time or to revert one code change without reverting several unrelated changes.
+Smaller commits make it clear how a feature was developed. They help you roll back to a specific good point in time, or to revert one code change without reverting several unrelated changes.
-Committing often also makes it easy to share your work, which is important so that everyone is aware of what you are working on.
+Committing often also helps you share your work, which is important so that everyone is aware of what you are working on.
You should push your feature branch frequently, even when it is not yet ready for review.
By sharing your work in a feature branch or [a merge request](#mergepull-requests-with-gitlab-flow), you prevent your team members from duplicating work.
-Sharing your work before it's complete also allows for discussion and feedback about the changes, which can help improve the code before it gets to review.
+Sharing your work before it's complete also allows for discussion and feedback about the changes. This feedback can help improve the code before it gets to review.
## How to write a good commit message
![Good and bad commit message](img/gitlab_flow_good_commit.png)
A commit message should reflect your intention, not just the contents of the commit.
-It is easy to see the changes in a commit, so the commit message should explain why you made those changes.
+You can see the changes in a commit, so the commit message should explain why you made those changes.
An example of a good commit message is: "Combine templates to reduce duplicate code in the user views."
The words "change," "improve," "fix," and "refactor" don't add much information to a commit message.
For example, "Improve XML generation" could be better written as "Properly escape special characters in XML generation."
@@ -315,12 +319,12 @@ In old workflows, the continuous integration (CI) server commonly ran tests on t
Developers had to ensure their code did not break the `master` branch.
When using GitLab flow, developers create their branches from this `master` branch, so it is essential that it never breaks.
Therefore, each merge request must be tested before it is accepted.
-CI software like Travis CI and GitLab CI/CD show the build results right in the merge request itself to make this easy.
+CI software like Travis CI and GitLab CI/CD show the build results right in the merge request itself to simplify the process.
There is one drawback to testing merge requests: the CI server only tests the feature branch itself, not the merged result.
Ideally, the server could also test the `master` branch after each change.
However, retesting on every commit to `master` is computationally expensive and means you are more frequently waiting for test results.
-Since feature branches should be short-lived, testing just the branch is an acceptable risk.
+Because feature branches should be short-lived, testing just the branch is an acceptable risk.
If new commits in `master` cause merge conflicts with the feature branch, merge `master` back into the branch to make the CI server re-run the tests.
As said before, if you often have feature branches that last for more than a few days, you should make your issues smaller.
diff --git a/lib/gitlab/import_export/group/tree_restorer.rb b/lib/gitlab/import_export/group/tree_restorer.rb
index dfe27118d66..925ab6680ba 100644
--- a/lib/gitlab/import_export/group/tree_restorer.rb
+++ b/lib/gitlab/import_export/group/tree_restorer.rb
@@ -6,7 +6,7 @@ module Gitlab
class TreeRestorer
include Gitlab::Utils::StrongMemoize
- attr_reader :user, :shared
+ attr_reader :user, :shared, :groups_mapping
def initialize(user:, shared:, group:)
@user = user
diff --git a/lib/gitlab/import_export/repo_saver.rb b/lib/gitlab/import_export/repo_saver.rb
index 5db99f9b431..0fdd0722b65 100644
--- a/lib/gitlab/import_export/repo_saver.rb
+++ b/lib/gitlab/import_export/repo_saver.rb
@@ -37,7 +37,8 @@ module Gitlab
end
def bundle_to_disk
- mkdir_p(shared.export_path)
+ mkdir_p(File.dirname(bundle_full_path))
+
repository.bundle_to_disk(bundle_full_path)
rescue => e
shared.error(e)
diff --git a/lib/gitlab/usage_data_counters/known_events/quickactions.yml b/lib/gitlab/usage_data_counters/known_events/quickactions.yml
new file mode 100644
index 00000000000..bf292047da0
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/known_events/quickactions.yml
@@ -0,0 +1,326 @@
+---
+- name: i_quickactions_approve
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_assign_single
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_assign_multiple
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_assign_self
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_assign_reviewer
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_award
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_board_move
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_child_epic
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_clear_weight
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_clone
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_close
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_confidential
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_copy_metadata_merge_request
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_copy_metadata_issue
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_create_merge_request
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_done
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_draft
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_due
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_duplicate
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_epic
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_estimate
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_iteration
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_label
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_lock
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_merge
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_milestone
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_move
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_parent_epic
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_promote
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_publish
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_reassign
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_reassign_reviewer
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_rebase
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_relabel
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_relate
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_remove_child_epic
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_remove_due_date
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_remove_epic
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_remove_estimate
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_remove_iteration
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_remove_milestone
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_remove_parent_epic
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_remove_time_spent
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_remove_zoom
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_reopen
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_shrug
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_spend_subtract
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_spend_add
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_submit_review
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_subscribe
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_tableflip
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_tag
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_target_branch
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_title
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_todo
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_unassign_specific
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_unassign_all
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_unassign_reviewer
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_unlabel_specific
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_unlabel_all
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_unlock
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_unsubscribe
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_weight
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_wip
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
+- name: i_quickactions_zoom
+ category: quickactions
+ redis_slot: quickactions
+ aggregation: weekly
+ feature_flag: usage_data_track_quickactions
diff --git a/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter.rb
new file mode 100644
index 00000000000..f757b51f73c
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module UsageDataCounters
+ module QuickActionActivityUniqueCounter
+ class << self
+ # Tracks the quick action with name `name`.
+ # `args` is expected to be a single string, will be split internally when necessary.
+ def track_unique_action(name, args:, user:)
+ return unless Feature.enabled?(:usage_data_track_quickactions, default_enabled: :yaml)
+ return unless user
+
+ args ||= ''
+ name = prepare_name(name, args)
+
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:"i_quickactions_#{name}", values: user.id)
+ end
+
+ private
+
+ def prepare_name(name, args)
+ case name
+ when 'assign'
+ event_name_for_assign(args)
+ when 'copy_metadata'
+ event_name_for_copy_metadata(args)
+ when 'remove_reviewer'
+ 'unassign_reviewer'
+ when 'request_review', 'reviewer'
+ 'assign_reviewer'
+ when 'spend'
+ event_name_for_spend(args)
+ when 'unassign'
+ event_name_for_unassign(args)
+ when 'unlabel', 'remove_label'
+ event_name_for_unlabel(args)
+ else
+ name
+ end
+ end
+
+ def event_name_for_assign(args)
+ args = args.split
+
+ if args.count == 1 && args.first == 'me'
+ 'assign_self'
+ elsif args.count == 1
+ 'assign_single'
+ else
+ 'assign_multiple'
+ end
+ end
+
+ def event_name_for_copy_metadata(args)
+ if args.start_with?('#')
+ 'copy_metadata_issue'
+ else
+ 'copy_metadata_merge_request'
+ end
+ end
+
+ def event_name_for_spend(args)
+ if args.start_with?('-')
+ 'spend_subtract'
+ else
+ 'spend_add'
+ end
+ end
+
+ def event_name_for_unassign(args)
+ if args.present?
+ 'unassign_specific'
+ else
+ 'unassign_all'
+ end
+ end
+
+ def event_name_for_unlabel(args)
+ if args.present?
+ 'unlabel_specific'
+ else
+ 'unlabel_all'
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/migration/add_limit_to_text_columns.rb b/rubocop/cop/migration/add_limit_to_text_columns.rb
index b2e37ad5137..126e4e21f22 100644
--- a/rubocop/cop/migration/add_limit_to_text_columns.rb
+++ b/rubocop/cop/migration/add_limit_to_text_columns.rb
@@ -20,6 +20,10 @@ module RuboCop
(def :down ...)
PATTERN
+ def_node_matcher :set_text_limit?, <<~PATTERN
+ (send _ :text_limit ...)
+ PATTERN
+
def_node_matcher :add_text_limit?, <<~PATTERN
(send _ :add_text_limit ...)
PATTERN
@@ -111,20 +115,31 @@ module RuboCop
limit_found = false
node.each_descendant(:send) do |send_node|
- next unless add_text_limit?(send_node)
-
- limit_table = send_node.children[2].value
- limit_attribute = send_node.children[3].value
-
- if limit_table == table_name && limit_attribute == attribute_name
- limit_found = true
- break
+ if set_text_limit?(send_node)
+ limit_found = matching_set_text_limit?(send_node, attribute_name)
+ elsif add_text_limit?(send_node)
+ limit_found = matching_add_text_limit?(send_node, table_name, attribute_name)
end
+
+ break if limit_found
end
!limit_found
end
+ def matching_set_text_limit?(send_node, attribute_name)
+ limit_attribute = send_node.children[2].value
+
+ limit_attribute == attribute_name
+ end
+
+ def matching_add_text_limit?(send_node, table_name, attribute_name)
+ limit_table = send_node.children[2].value
+ limit_attribute = send_node.children[3].value
+
+ limit_table == table_name && limit_attribute == attribute_name
+ end
+
def encrypted_attribute_name?(attribute_name)
attribute_name.to_s.start_with?('encrypted_')
end
diff --git a/rubocop/migration_helpers.rb b/rubocop/migration_helpers.rb
index c06d69a4359..dffceb2b2c8 100644
--- a/rubocop/migration_helpers.rb
+++ b/rubocop/migration_helpers.rb
@@ -19,7 +19,7 @@ module RuboCop
# or through a create/alter table (TABLE_METHODS)
ADD_COLUMN_METHODS = %i(add_column add_column_with_default change_column_type_concurrently).freeze
- TABLE_METHODS = %i(create_table create_table_if_not_exists change_table).freeze
+ TABLE_METHODS = %i(create_table create_table_if_not_exists change_table create_table_with_constraints).freeze
def high_traffic_tables
@high_traffic_tables ||= rubocop_migrations_config.dig('Migration/UpdateLargeTable', 'HighTrafficTables')
diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb
index ece52d37351..2a908a83f5c 100644
--- a/spec/experiments/application_experiment_spec.rb
+++ b/spec/experiments/application_experiment_spec.rb
@@ -5,6 +5,12 @@ require 'spec_helper'
RSpec.describe ApplicationExperiment do
subject { described_class.new(:stub) }
+ it "naively assumes a 1x1 relationship to feature flags for tests" do
+ expect(Feature).to receive(:persist_used!).with('stub')
+
+ described_class.new(:stub)
+ end
+
describe "publishing results" do
it "tracks the assignment" do
expect(subject).to receive(:track).with(:assignment)
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js
index 76d67195499..6bfc4a7b7c8 100644
--- a/spec/frontend/api_spec.js
+++ b/spec/frontend/api_spec.js
@@ -260,6 +260,28 @@ describe('Api', () => {
});
});
+ describe('groupLabels', () => {
+ it('fetches group labels', (done) => {
+ const options = { params: { search: 'foo' } };
+ const expectedGroup = 'gitlab-org';
+ const expectedUrl = `${dummyUrlRoot}/groups/${expectedGroup}/-/labels`;
+ mock.onGet(expectedUrl).reply(httpStatus.OK, [
+ {
+ id: 1,
+ title: 'Foo Label',
+ },
+ ]);
+
+ Api.groupLabels(expectedGroup, options)
+ .then((res) => {
+ expect(res.length).toBe(1);
+ expect(res[0].title).toBe('Foo Label');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
describe('namespaces', () => {
it('fetches namespaces', (done) => {
const query = 'dummy query';
diff --git a/spec/frontend/issuable_list/components/issuable_item_spec.js b/spec/frontend/issuable_list/components/issuable_item_spec.js
index 3c01bf2d319..65e52d05084 100644
--- a/spec/frontend/issuable_list/components/issuable_item_spec.js
+++ b/spec/frontend/issuable_list/components/issuable_item_spec.js
@@ -257,6 +257,23 @@ describe('IssuableItem', () => {
);
});
+ it('renders issuable confidential icon when issuable is confidential', async () => {
+ wrapper.setProps({
+ issuable: {
+ ...mockIssuable,
+ confidential: true,
+ },
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const confidentialEl = wrapper.find('[data-testid="issuable-title"]').find(GlIcon);
+
+ expect(confidentialEl.exists()).toBe(true);
+ expect(confidentialEl.props('name')).toBe('eye-slash');
+ expect(confidentialEl.attributes('title')).toBe('Confidential');
+ });
+
it('renders issuable reference', () => {
const referenceEl = wrapper.find('[data-testid="issuable-reference"]');
diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js
index 002c4f206cb..8394d1d0ab2 100644
--- a/spec/frontend/notes/components/comment_form_spec.js
+++ b/spec/frontend/notes/components/comment_form_spec.js
@@ -9,7 +9,6 @@ import CommentForm from '~/notes/components/comment_form.vue';
import * as constants from '~/notes/constants';
import eventHub from '~/notes/event_hub';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
-import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import { loggedOutnoteableData, notesDataMock, userDataMock, noteableDataMock } from '../mock_data';
jest.mock('autosize');
@@ -64,14 +63,6 @@ describe('issue_comment_form component', () => {
});
describe('user is logged in', () => {
- describe('avatar', () => {
- it('should render user avatar with link', () => {
- mountComponent({ mountFunction: mount });
-
- expect(wrapper.find(UserAvatarLink).attributes('href')).toBe(userDataMock.path);
- });
- });
-
describe('handleSave', () => {
it('should request to save note when note is entered', () => {
mountComponent({ mountFunction: mount, initialData: { note: 'hello world' } });
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js
index 8847e4e6bdd..bd77a1d657e 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js
@@ -1,25 +1,27 @@
-import Vue from 'vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
-import { removeBreakLine } from 'helpers/text_helper';
-import pipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue';
+import { shallowMount, mount } from '@vue/test-utils';
+import PipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue';
describe('MRWidgetPipelineBlocked', () => {
- let vm;
- beforeEach(() => {
- const Component = Vue.extend(pipelineBlockedComponent);
- vm = mountComponent(Component);
- });
+ let wrapper;
+
+ const createWrapper = (mountFn = shallowMount) => {
+ wrapper = mountFn(PipelineBlockedComponent);
+ };
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
it('renders warning icon', () => {
- expect(vm.$el.querySelector('.ci-status-icon-warning')).not.toBe(null);
+ createWrapper(mount);
+
+ expect(wrapper.find('.ci-status-icon-warning').exists()).toBe(true);
});
it('renders information text', () => {
- expect(removeBreakLine(vm.$el.textContent).trim()).toContain(
+ createWrapper();
+
+ expect(wrapper.text()).toBe(
'Pipeline blocked. The pipeline for this merge request requires a manual action to proceed',
);
});
diff --git a/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb
index 2794acb8980..d2153221e8f 100644
--- a/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb
@@ -21,6 +21,7 @@ RSpec.describe Gitlab::ImportExport::Group::TreeRestorer do
group_tree_restorer = described_class.new(user: user, shared: @shared, group: @group)
expect(group_tree_restorer.restore).to be_truthy
+ expect(group_tree_restorer.groups_mapping).not_to be_empty
end
end
diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb
index 3887ee7294e..52001e778d6 100644
--- a/spec/lib/gitlab/import_export/repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb
@@ -25,6 +25,14 @@ RSpec.describe Gitlab::ImportExport::RepoSaver do
expect(bundler.save).to be true
end
+ it 'creates the directory for the repository' do
+ allow(bundler).to receive(:bundle_full_path).and_return('/foo/bar/file.tar.gz')
+
+ expect(FileUtils).to receive(:mkdir_p).with('/foo/bar', anything)
+
+ bundler.save # rubocop:disable Rails/SaveBang
+ end
+
context 'when the repo is empty' do
let!(:project) { create(:project) }
diff --git a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
index b8eddc0ca7f..59c601f54de 100644
--- a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
@@ -39,7 +39,8 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
'snippets',
'code_review',
'terraform',
- 'ci_templates'
+ 'ci_templates',
+ 'quickactions'
)
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb
new file mode 100644
index 00000000000..d4c423f57fe
--- /dev/null
+++ b/spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb
@@ -0,0 +1,163 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::UsageDataCounters::QuickActionActivityUniqueCounter, :clean_gitlab_redis_shared_state do
+ let(:user) { build(:user, id: 1) }
+ let(:note) { build(:note, author: user) }
+ let(:args) { nil }
+
+ shared_examples_for 'a tracked quick action unique event' do
+ specify do
+ expect { 3.times { subject } }
+ .to change {
+ Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(
+ event_names: action,
+ start_date: 2.weeks.ago,
+ end_date: 2.weeks.from_now
+ )
+ }
+ .by(1)
+ end
+ end
+
+ subject { described_class.track_unique_action(quickaction_name, args: args, user: user) }
+
+ describe '.track_unique_action' do
+ let(:quickaction_name) { 'approve' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_approve' }
+ end
+ end
+
+ context 'tracking assigns' do
+ let(:quickaction_name) { 'assign' }
+
+ context 'single assignee' do
+ let(:args) { '@one' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_assign_single' }
+ end
+ end
+
+ context 'multiple assignees' do
+ let(:args) { '@one @two' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_assign_multiple' }
+ end
+ end
+
+ context 'assigning "me"' do
+ let(:args) { 'me' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_assign_self' }
+ end
+ end
+
+ context 'assigning a reviewer' do
+ let(:quickaction_name) { 'assign_reviewer' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_assign_reviewer' }
+ end
+ end
+
+ context 'assigning a reviewer with request review alias' do
+ let(:quickaction_name) { 'request_review' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_assign_reviewer' }
+ end
+ end
+ end
+
+ context 'tracking copy_metadata' do
+ let(:quickaction_name) { 'copy_metadata' }
+
+ context 'for issues' do
+ let(:args) { '#123' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_copy_metadata_issue' }
+ end
+ end
+
+ context 'for merge requests' do
+ let(:args) { '!123' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_copy_metadata_merge_request' }
+ end
+ end
+ end
+
+ context 'tracking spend' do
+ let(:quickaction_name) { 'spend' }
+
+ context 'adding time' do
+ let(:args) { '1d' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_spend_add' }
+ end
+ end
+
+ context 'removing time' do
+ let(:args) { '-1d' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_spend_subtract' }
+ end
+ end
+ end
+
+ context 'tracking unassign' do
+ let(:quickaction_name) { 'unassign' }
+
+ context 'unassigning everyone' do
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_unassign_all' }
+ end
+ end
+
+ context 'unassigning specific users' do
+ let(:args) { '@hello' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_unassign_specific' }
+ end
+ end
+ end
+
+ context 'tracking unlabel' do
+ context 'called as unlabel' do
+ let(:quickaction_name) { 'unlabel' }
+
+ context 'removing all labels' do
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_unlabel_all' }
+ end
+ end
+
+ context 'removing specific labels' do
+ let(:args) { '~wow' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_unlabel_specific' }
+ end
+ end
+ end
+
+ context 'called as remove_label' do
+ let(:quickaction_name) { 'remove_label' }
+
+ it_behaves_like 'a tracked quick action unique event' do
+ let(:action) { 'i_quickactions_unlabel_all' }
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/utils/markdown_spec.rb b/spec/lib/gitlab/utils/markdown_spec.rb
index 23cd770d168..acc5bd47c8c 100644
--- a/spec/lib/gitlab/utils/markdown_spec.rb
+++ b/spec/lib/gitlab/utils/markdown_spec.rb
@@ -53,33 +53,23 @@ RSpec.describe Gitlab::Utils::Markdown do
end
context 'when string has a product suffix' do
- let(:string) { 'My Header (ULTIMATE)' }
-
- it 'ignores a product suffix' do
- is_expected.to eq 'my-header'
- end
-
- context 'with self modifier' do
- let(:string) { 'My Header (PREMIUM SELF)' }
-
- it 'ignores a product suffix' do
- is_expected.to eq 'my-header'
- end
- end
-
- context 'with "*" around a product suffix' do
- let(:string) { 'My Header **(PREMIUM)**' }
-
- it 'ignores a product suffix' do
- is_expected.to eq 'my-header'
- end
- end
-
- context 'with "*" around a product suffix and sass modifier' do
- let(:string) { 'My Header **(PREMIUM SASS)**' }
-
- it 'ignores a product suffix' do
- is_expected.to eq 'my-header'
+ %w[CORE STARTER PREMIUM ULTIMATE FREE BRONZE SILVER GOLD].each do |tier|
+ ['', ' ONLY', ' SELF', ' SASS'].each do |modifier|
+ context "#{tier}#{modifier}" do
+ let(:string) { "My Header (#{tier}#{modifier})" }
+
+ it 'ignores a product suffix' do
+ is_expected.to eq 'my-header'
+ end
+
+ context 'with "*" around a product suffix' do
+ let(:string) { "My Header **(#{tier}#{modifier})**" }
+
+ it 'ignores a product suffix' do
+ is_expected.to eq 'my-header'
+ end
+ end
+ end
end
end
end
diff --git a/spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb b/spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb
index 97b9d0d1ee2..149fb0a48eb 100644
--- a/spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb
+++ b/spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb
@@ -28,6 +28,15 @@ RSpec.describe RuboCop::Cop::Migration::AddLimitToTextColumns do
^^^^ #{described_class::MSG}
end
+ create_table_with_constraints :test_text_limits_create do |t|
+ t.integer :test_id, null: false
+ t.text :title
+ t.text :description
+ ^^^^ #{described_class::MSG}
+
+ t.text_limit :title, 100
+ end
+
add_column :test_text_limits, :email, :text
^^^^^^^^^^ #{described_class::MSG}
@@ -57,6 +66,15 @@ RSpec.describe RuboCop::Cop::Migration::AddLimitToTextColumns do
t.text :name
end
+ create_table_with_constraints :test_text_limits_create do |t|
+ t.integer :test_id, null: false
+ t.text :title
+ t.text :description
+
+ t.text_limit :title, 100
+ t.text_limit :description, 255
+ end
+
add_column :test_text_limits, :email, :text
add_column_with_default :test_text_limits, :role, :text, default: 'default'
change_column_type_concurrently :test_text_limits, :test_id, :text
diff --git a/spec/services/groups/import_export/export_service_spec.rb b/spec/services/groups/import_export/export_service_spec.rb
index 6b78822de04..d6ce40f413b 100644
--- a/spec/services/groups/import_export/export_service_spec.rb
+++ b/spec/services/groups/import_export/export_service_spec.rb
@@ -71,6 +71,16 @@ RSpec.describe Groups::ImportExport::ExportService do
service.execute
end
+ it 'compresses and removes tmp files' do
+ expect(group.import_export_upload).to be_nil
+ expect(Gitlab::ImportExport::Saver).to receive(:new).and_call_original
+
+ service.execute
+
+ expect(Dir.exist?(shared.archive_path)).to eq false
+ expect(File.exist?(group.import_export_upload.export_file.path)).to eq true
+ end
+
it 'notifies the user' do
expect_next_instance_of(NotificationService) do |instance|
expect(instance).to receive(:group_was_exported)
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index e668bace116..c0452e18f52 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1793,6 +1793,24 @@ RSpec.describe QuickActions::InterpretService do
expect(text).to eq(" - list\n\ntest")
end
+ it 'tracks MAU for commands' do
+ content = "/shrug test\n/assign me\n/milestone %4"
+
+ expect(Gitlab::UsageDataCounters::QuickActionActivityUniqueCounter)
+ .to receive(:track_unique_action)
+ .with('shrug', args: 'test', user: developer)
+
+ expect(Gitlab::UsageDataCounters::QuickActionActivityUniqueCounter)
+ .to receive(:track_unique_action)
+ .with('assign', args: 'me', user: developer)
+
+ expect(Gitlab::UsageDataCounters::QuickActionActivityUniqueCounter)
+ .to receive(:track_unique_action)
+ .with('milestone', args: '%4', user: developer)
+
+ service.execute(content, issue)
+ end
+
context '/create_merge_request command' do
let(:branch_name) { '1-feature' }
let(:content) { "/create_merge_request #{branch_name}" }
diff --git a/spec/support/gitlab_experiment.rb b/spec/support/gitlab_experiment.rb
index 1f283e4f06c..45f733201e2 100644
--- a/spec/support/gitlab_experiment.rb
+++ b/spec/support/gitlab_experiment.rb
@@ -1,4 +1,13 @@
# frozen_string_literal: true
+# This is a temporary fix until we have a larger discussion around the
+# challenges raised in https://gitlab.com/gitlab-org/gitlab/-/issues/300104
+class ApplicationExperiment < Gitlab::Experiment # rubocop:disable Gitlab/NamespacedClass
+ def initialize(*args)
+ super
+ Feature.persist_used!(name)
+ end
+end
+
# Disable all caching for experiments in tests.
Gitlab::Experiment::Configuration.cache = nil