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-08-16 21:10:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-16 21:10:51 +0300
commite684f438e60b801b4eb8b19dd9489dce84503c03 (patch)
tree115e9d137f570580b17825ed13057d663a0761c0
parentd872c89ce4828a16d72ddeed8695077fdcaf7b30 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/content_editor/components/toolbar_table_button.vue42
-rw-r--r--app/assets/javascripts/integrations/overrides/api.js10
-rw-r--r--app/assets/javascripts/integrations/overrides/components/integration_overrides.vue114
-rw-r--r--app/assets/javascripts/jobs/components/stages_dropdown.vue13
-rw-r--r--app/assets/javascripts/notes/components/comment_field_layout.vue10
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue1
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js8
-rw-r--r--app/assets/stylesheets/components/content_editor.scss19
-rw-r--r--app/controllers/admin/integrations_controller.rb4
-rw-r--r--app/helpers/clusters_helper.rb3
-rw-r--r--app/helpers/integrations_helper.rb11
-rw-r--r--app/presenters/merge_request_presenter.rb17
-rw-r--r--app/serializers/merge_request_widget_entity.rb8
-rw-r--r--app/views/layouts/nav/sidebar/_group_menus.html.haml3
-rw-r--r--app/views/layouts/nav/sidebar/_wiki_link.html.haml11
-rw-r--r--app/views/shared/integrations/_form.html.haml3
-rw-r--r--app/views/shared/integrations/_tabs.html.haml28
-rw-r--r--app/views/shared/integrations/edit.html.haml6
-rw-r--r--app/views/shared/integrations/overrides.html.haml2
-rw-r--r--config/application.rb15
-rw-r--r--db/post_migrate/20210805192450_update_trial_plans_ci_daily_pipeline_schedule_triggers.rb48
-rw-r--r--db/schema_migrations/202108051924501
-rw-r--r--doc/.vale/gitlab/spelling-exceptions.txt5
-rw-r--r--doc/administration/geo/replication/disable_geo.md1
-rw-r--r--doc/administration/geo/replication/version_specific_updates.md10
-rw-r--r--doc/administration/get_started.md2
-rw-r--r--doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md2
-rw-r--r--doc/api/repositories.md4
-rw-r--r--doc/development/import_project.md2
-rw-r--r--doc/operations/incident_management/paging.md9
-rw-r--r--doc/operations/incident_management/status_page.md34
-rw-r--r--doc/user/admin_area/analytics/dev_ops_report.md2
-rw-r--r--doc/user/admin_area/settings/floc.md4
-rw-r--r--doc/user/admin_area/settings/rate_limit_on_notes_creation.md2
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md2
-rw-r--r--doc/user/analytics/value_stream_analytics.md4
-rw-r--r--doc/user/clusters/management_project_template.md10
-rw-r--r--doc/user/infrastructure/clusters/manage/management_project_applications/sentry.md2
-rw-r--r--doc/user/infrastructure/index.md2
-rw-r--r--doc/user/project/clusters/add_remove_clusters.md4
-rw-r--r--doc/user/project/import/gitlab_com.md2
-rw-r--r--doc/user/project/index.md2
-rw-r--r--doc/user/project/repository/reducing_the_repo_size_using_git.md4
-rw-r--r--doc/user/project/settings/import_export.md20
-rw-r--r--doc/user/project/settings/index.md2
-rw-r--r--locale/gitlab.pot29
-rw-r--r--package.json2
-rw-r--r--spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb18
-rw-r--r--spec/features/merge_request/user_sees_closing_issues_message_spec.rb16
-rw-r--r--spec/frontend/content_editor/components/toolbar_table_button_spec.js24
-rw-r--r--spec/frontend/integrations/overrides/components/integration_overrides_spec.js146
-rw-r--r--spec/frontend/jobs/components/stages_dropdown_spec.js13
-rw-r--r--spec/frontend/notes/components/comment_field_layout_spec.js14
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js21
-rw-r--r--spec/helpers/clusters_helper_spec.rb4
-rw-r--r--spec/migrations/20210805192450_update_trial_plans_ci_daily_pipeline_schedule_triggers_spec.rb137
-rw-r--r--spec/serializers/merge_request_widget_entity_spec.rb2
-rw-r--r--yarn.lock8
60 files changed, 786 insertions, 169 deletions
diff --git a/app/assets/javascripts/content_editor/components/toolbar_table_button.vue b/app/assets/javascripts/content_editor/components/toolbar_table_button.vue
index 1b394f76641..46db806da94 100644
--- a/app/assets/javascripts/content_editor/components/toolbar_table_button.vue
+++ b/app/assets/javascripts/content_editor/components/toolbar_table_button.vue
@@ -5,17 +5,17 @@ import { clamp } from '../services/utils';
export const tableContentType = 'table';
-const MIN_ROWS = 3;
-const MIN_COLS = 3;
-const MAX_ROWS = 8;
-const MAX_COLS = 8;
+const MIN_ROWS = 5;
+const MIN_COLS = 5;
+const MAX_ROWS = 10;
+const MAX_COLS = 10;
export default {
components: {
+ GlButton,
GlDropdown,
GlDropdownDivider,
GlDropdownForm,
- GlButton,
},
inject: ['tiptapEditor'],
data() {
@@ -62,22 +62,22 @@ export default {
};
</script>
<template>
- <gl-dropdown size="small" category="tertiary" icon="table">
- <gl-dropdown-form class="gl-px-3! gl-w-auto!">
- <div class="gl-w-auto!">
- <div v-for="r of list(maxRows)" :key="r" class="gl-display-flex">
- <gl-button
- v-for="c of list(maxCols)"
- :key="c"
- :data-testid="`table-${r}-${c}`"
- :class="{ 'gl-bg-blue-50!': r <= rows && c <= cols }"
- :aria-label="getButtonLabel(r, c)"
- class="gl-display-inline! gl-px-0! gl-w-5! gl-h-5! gl-rounded-0!"
- @mouseover="setRowsAndCols(r, c)"
- @click="insertTable()"
- />
- </div>
- <gl-dropdown-divider />
+ <gl-dropdown size="small" category="tertiary" icon="table" class="table-dropdown">
+ <gl-dropdown-form class="gl-px-3!">
+ <div v-for="r of list(maxRows)" :key="r" class="gl-display-flex">
+ <gl-button
+ v-for="c of list(maxCols)"
+ :key="c"
+ :data-testid="`table-${r}-${c}`"
+ :class="{ 'active gl-bg-blue-50!': r <= rows && c <= cols }"
+ :aria-label="getButtonLabel(r, c)"
+ class="table-creator-grid-item gl-display-inline gl-rounded-0! gl-w-6! gl-h-6! gl-p-0!"
+ @mouseover="setRowsAndCols(r, c)"
+ @click="insertTable()"
+ />
+ </div>
+ <gl-dropdown-divider class="gl-my-3! gl-mx-n3!" />
+ <div class="gl-px-1">
{{ getButtonLabel(rows, cols) }}
</div>
</gl-dropdown-form>
diff --git a/app/assets/javascripts/integrations/overrides/api.js b/app/assets/javascripts/integrations/overrides/api.js
new file mode 100644
index 00000000000..a379a864f9c
--- /dev/null
+++ b/app/assets/javascripts/integrations/overrides/api.js
@@ -0,0 +1,10 @@
+import axios from '~/lib/utils/axios_utils';
+
+export const fetchOverrides = (overridesPath, { page, perPage }) => {
+ return axios.get(overridesPath, {
+ params: {
+ page,
+ per_page: perPage,
+ },
+ });
+};
diff --git a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue
index bfb16779854..707ac946b98 100644
--- a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue
+++ b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue
@@ -1,15 +1,127 @@
<script>
+import { GlLink, GlLoadingIcon, GlPagination, GlTable } from '@gitlab/ui';
+
+import { DEFAULT_PER_PAGE } from '~/api';
+import createFlash from '~/flash';
+import { fetchOverrides } from '~/integrations/overrides/api';
+import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
+import { truncateNamespace } from '~/lib/utils/text_utility';
+import { __, s__ } from '~/locale';
+import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
+
export default {
name: 'IntegrationOverrides',
+ components: {
+ GlLink,
+ GlLoadingIcon,
+ GlPagination,
+ GlTable,
+ ProjectAvatar,
+ },
props: {
overridesPath: {
type: String,
required: true,
},
},
+ fields: [
+ {
+ key: 'name',
+ label: __('Project'),
+ },
+ ],
+ data() {
+ return {
+ isLoading: true,
+ overrides: [],
+ page: 1,
+ totalItems: 0,
+ };
+ },
+ computed: {
+ showPagination() {
+ return this.totalItems > this.$options.DEFAULT_PER_PAGE && this.overrides.length > 0;
+ },
+ },
+ mounted() {
+ this.loadOverrides();
+ },
+ methods: {
+ loadOverrides(page = this.page) {
+ this.isLoading = true;
+
+ fetchOverrides(this.overridesPath, {
+ page,
+ perPage: this.$options.DEFAULT_PER_PAGE,
+ })
+ .then(({ data, headers }) => {
+ const { page: newPage, total } = parseIntPagination(normalizeHeaders(headers));
+ this.page = newPage;
+ this.totalItems = total;
+ this.overrides = data;
+ })
+ .catch((error) => {
+ createFlash({
+ message: this.$options.i18n.defaultErrorMessage,
+ error,
+ captureError: true,
+ });
+ })
+ .finally(() => {
+ this.isLoading = false;
+ });
+ },
+ truncateNamespace,
+ },
+ DEFAULT_PER_PAGE,
+ i18n: {
+ defaultErrorMessage: s__(
+ 'Integrations|An error occurred while loading projects using custom settings.',
+ ),
+ tableEmptyText: s__('Integrations|There are no projects using custom settings'),
+ },
};
</script>
<template>
- <div></div>
+ <div>
+ <gl-table
+ :items="overrides"
+ :fields="$options.fields"
+ :busy="isLoading"
+ show-empty
+ :empty-text="$options.i18n.tableEmptyText"
+ >
+ <template #cell(name)="{ item }">
+ <gl-link
+ class="gl-display-inline-flex gl-align-items-center gl-hover-text-decoration-none gl-text-body!"
+ :href="item.full_path"
+ >
+ <project-avatar
+ class="gl-mr-3"
+ :project-avatar-url="item.avatar_url"
+ :project-name="item.name"
+ aria-hidden="true"
+ />
+ {{ truncateNamespace(item.full_name) }} /&nbsp;
+
+ <strong>{{ item.name }}</strong>
+ </gl-link>
+ </template>
+
+ <template #table-busy>
+ <gl-loading-icon size="md" class="gl-my-2" />
+ </template>
+ </gl-table>
+ <div class="gl-display-flex gl-justify-content-center gl-mt-5">
+ <gl-pagination
+ v-if="showPagination"
+ :per-page="$options.DEFAULT_PER_PAGE"
+ :total-items="totalItems"
+ :value="page"
+ :disabled="isLoading"
+ @input="loadOverrides"
+ />
+ </div>
+ </div>
</template>
diff --git a/app/assets/javascripts/jobs/components/stages_dropdown.vue b/app/assets/javascripts/jobs/components/stages_dropdown.vue
index 36b0ad43b14..1780afd39e8 100644
--- a/app/assets/javascripts/jobs/components/stages_dropdown.vue
+++ b/app/assets/javascripts/jobs/components/stages_dropdown.vue
@@ -2,10 +2,12 @@
import { GlLink, GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { isEmpty } from 'lodash';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
export default {
components: {
CiIcon,
+ clipboardButton,
GlDropdown,
GlDropdownItem,
GlLink,
@@ -45,7 +47,7 @@ export default {
<template>
<div class="dropdown">
<div class="js-pipeline-info" data-testid="pipeline-info">
- <ci-icon :status="pipeline.details.status" class="vertical-align-middle" />
+ <ci-icon :status="pipeline.details.status" />
<span class="font-weight-bold">{{ s__('Job|Pipeline') }}</span>
<gl-link
@@ -85,7 +87,14 @@ export default {
</template>
<gl-link v-else :href="pipeline.ref.path" class="link-commit ref-name">{{
pipeline.ref.name
- }}</gl-link>
+ }}</gl-link
+ ><clipboard-button
+ :text="pipeline.ref.name"
+ :title="__('Copy reference')"
+ category="tertiary"
+ size="small"
+ data-testid="copy-source-ref-link"
+ />
</template>
</div>
diff --git a/app/assets/javascripts/notes/components/comment_field_layout.vue b/app/assets/javascripts/notes/components/comment_field_layout.vue
index 47d14783d5d..9638c20e28c 100644
--- a/app/assets/javascripts/notes/components/comment_field_layout.vue
+++ b/app/assets/javascripts/notes/components/comment_field_layout.vue
@@ -14,6 +14,11 @@ export default {
type: Object,
required: true,
},
+ noteIsConfidential: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
noteableType: {
type: String,
required: false,
@@ -38,6 +43,9 @@ export default {
emailParticipants() {
return this.noteableData.issue_email_participants?.map(({ email }) => email) || [];
},
+ showEmailParticipantsWarning() {
+ return this.emailParticipants.length && !this.noteIsConfidential;
+ },
},
};
</script>
@@ -61,7 +69,7 @@ export default {
/>
<slot></slot>
<email-participants-warning
- v-if="emailParticipants.length"
+ v-if="showEmailParticipantsWarning"
class="gl-border-t-1 gl-border-t-solid gl-border-t-gray-100 gl-rounded-base gl-rounded-top-left-none! gl-rounded-top-right-none!"
:emails="emailParticipants"
/>
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 9504ed78778..2ebebd76e1e 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -380,6 +380,7 @@ export default {
<comment-field-layout
:with-alert-container="true"
:noteable-data="getNoteableData"
+ :note-is-confidential="noteIsConfidential"
:noteable-type="noteableType"
>
<markdown-field
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 4ce81219f11..f2336e1b6f5 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -326,7 +326,10 @@ export default {
></div>
<div class="flash-container timeline-content"></div>
<form :data-line-code="lineCode" class="edit-note common-note-form js-quick-submit gfm-form">
- <comment-field-layout :noteable-data="getNoteableData">
+ <comment-field-layout
+ :noteable-data="getNoteableData"
+ :note-is-confidential="discussion.confidential"
+ >
<markdown-field
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
index 43317130b08..ac6368a3025 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
@@ -1,6 +1,6 @@
<script>
/* eslint-disable vue/no-v-html */
-import { s__ } from '~/locale';
+import { s__, n__ } from '~/locale';
export default {
name: 'MRWidgetRelatedLinks',
@@ -24,7 +24,8 @@ export default {
if (this.state === 'closed') {
return s__('mrWidget|Did not close');
}
- return s__('mrWidget|Closes');
+
+ return n__('mrWidget|Closes issue', 'mrWidget|Closes issues', this.relatedLinks.closingCount);
},
},
};
@@ -33,7 +34,8 @@ export default {
<section class="mr-info-list gl-ml-7 gl-pb-5">
<p v-if="relatedLinks.closing">{{ closesText }} <span v-html="relatedLinks.closing"></span></p>
<p v-if="relatedLinks.mentioned">
- {{ s__('mrWidget|Mentions') }} <span v-html="relatedLinks.mentioned"></span>
+ {{ n__('mrWidget|Mentions issue', 'mrWidget|Mentions issues', relatedLinks.mentionedCount) }}
+ <span v-html="relatedLinks.mentioned"></span>
</p>
<p v-if="relatedLinks.assignToMe"><span v-html="relatedLinks.assignToMe"></span></p>
</section>
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 035fd51d8e3..8979fe621ac 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -72,7 +72,13 @@ export default class MergeRequestStore {
const assignToMe = links.assign_to_closing;
if (closing || mentioned || assignToMe) {
- this.relatedLinks = { closing, mentioned, assignToMe };
+ this.relatedLinks = {
+ closing,
+ mentioned,
+ assignToMe,
+ closingCount: links.closing_count,
+ mentionedCount: links.mentioned_count,
+ };
}
}
diff --git a/app/assets/stylesheets/components/content_editor.scss b/app/assets/stylesheets/components/content_editor.scss
index ed352b2cc76..64abf5574fa 100644
--- a/app/assets/stylesheets/components/content_editor.scss
+++ b/app/assets/stylesheets/components/content_editor.scss
@@ -35,3 +35,22 @@
}
}
}
+
+.table-creator-grid-item {
+ box-shadow: inset 0 0 0 $gl-spacing-scale-2 $white,
+ inset $gl-spacing-scale-1 $gl-spacing-scale-1 0 #{$gl-spacing-scale-2 * 3 / 4} $gray-100,
+ inset #{-$gl-spacing-scale-1} #{-$gl-spacing-scale-1} 0 #{$gl-spacing-scale-2 * 3 / 4} $gray-100 !important;
+
+ &.active {
+ box-shadow: inset 0 0 0 $gl-spacing-scale-2 $white,
+ inset $gl-spacing-scale-1 $gl-spacing-scale-1 0 $gl-spacing-scale-2 $blue-500,
+ inset #{-$gl-spacing-scale-1} #{-$gl-spacing-scale-1} 0 $gl-spacing-scale-2 $blue-500 !important;
+ }
+}
+
+.table-dropdown .dropdown-menu {
+ @include gl-min-w-0;
+ @include gl-w-auto;
+
+ @include gl-white-space-nowrap;
+}
diff --git a/app/controllers/admin/integrations_controller.rb b/app/controllers/admin/integrations_controller.rb
index 108c7068fe2..50f97deb99d 100644
--- a/app/controllers/admin/integrations_controller.rb
+++ b/app/controllers/admin/integrations_controller.rb
@@ -26,8 +26,4 @@ class Admin::IntegrationsController < Admin::ApplicationController
def find_or_initialize_non_project_specific_integration(name)
Integration.find_or_initialize_non_project_specific_integration(name, instance: true)
end
-
- def instance_level_integration_overrides?
- Feature.enabled?(:instance_level_integration_overrides, default_enabled: :yaml)
- end
end
diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb
index e9a75babb97..c355fa5cc67 100644
--- a/app/helpers/clusters_helper.rb
+++ b/app/helpers/clusters_helper.rb
@@ -24,7 +24,8 @@ module ClustersHelper
agent_docs_url: help_page_path('user/clusters/agent/index'),
install_docs_url: help_page_path('administration/clusters/kas'),
get_started_docs_url: help_page_path('user/clusters/agent/index', anchor: 'define-a-configuration-repository'),
- integration_docs_url: help_page_path('user/clusters/agent/index', anchor: 'get-started-with-gitops-and-the-gitlab-agent')
+ integration_docs_url: help_page_path('user/clusters/agent/index', anchor: 'get-started-with-gitops-and-the-gitlab-agent'),
+ kas_address: Gitlab::Kas.external_url
}
end
diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb
index 734820f0e74..d06746c06e3 100644
--- a/app/helpers/integrations_helper.rb
+++ b/app/helpers/integrations_helper.rb
@@ -125,6 +125,17 @@ module IntegrationsHelper
!Gitlab.com?
end
+ def integration_tabs(integration:)
+ [
+ { key: 'edit', text: _('Settings'), href: scoped_edit_integration_path(integration) },
+ ({ key: 'overrides', text: s_('Integrations|Projects using custom settings'), href: scoped_overrides_integration_path(integration) } if instance_level_integration_overrides?)
+ ].compact
+ end
+
+ def instance_level_integration_overrides?
+ Feature.enabled?(:instance_level_integration_overrides, default_enabled: :yaml)
+ end
+
def jira_issue_breadcrumb_link(issue_reference)
link_to '', { class: 'gl-display-flex gl-align-items-center gl-white-space-nowrap' } do
icon = image_tag image_path('illustrations/logos/jira.svg'), width: 15, height: 15, class: 'gl-mr-2'
diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb
index 6bf5e0bd1b0..fc8a290f5f7 100644
--- a/app/presenters/merge_request_presenter.rb
+++ b/app/presenters/merge_request_presenter.rb
@@ -139,7 +139,6 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
def mentioned_issues_links
- mentioned_issues = issues_mentioned_but_not_closing(current_user)
markdown(
issues_sentence(project, mentioned_issues),
pipeline: :gfm,
@@ -239,6 +238,18 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
APPROVALS_WIDGET_BASE_TYPE
end
+ def closing_issues
+ strong_memoize(:closing_issues) do
+ visible_closing_issues_for(current_user)
+ end
+ end
+
+ def mentioned_issues
+ strong_memoize(:mentioned_issues) do
+ issues_mentioned_but_not_closing(current_user)
+ end
+ end
+
private
def cached_can_be_reverted?
@@ -253,10 +264,6 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
# rubocop: enable CodeReuse/ServiceClass
end
- def closing_issues
- @closing_issues ||= visible_closing_issues_for(current_user)
- end
-
def pipeline
@pipeline ||= actual_head_pipeline
end
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 232e14fad1c..1c033dee5ff 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -110,9 +110,17 @@ class MergeRequestWidgetEntity < Grape::Entity
presenter(merge_request).closing_issues_links
end
+ expose :closing_count do |merge_request|
+ presenter(merge_request).closing_issues.size
+ end
+
expose :mentioned_but_not_closing do |merge_request|
presenter(merge_request).mentioned_issues_links
end
+
+ expose :mentioned_count do |merge_request|
+ presenter(merge_request).mentioned_issues.size
+ end
end
expose :codeclimate, if: -> (mr, _) { head_pipeline_downloadable_path_for_report_type(:codequality) } do
diff --git a/app/views/layouts/nav/sidebar/_group_menus.html.haml b/app/views/layouts/nav/sidebar/_group_menus.html.haml
index 8a6183f8efe..a31d61a3eaf 100644
--- a/app/views/layouts/nav/sidebar/_group_menus.html.haml
+++ b/app/views/layouts/nav/sidebar/_group_menus.html.haml
@@ -1,6 +1,3 @@
-- if group_sidebar_link?(:wiki)
- = render 'layouts/nav/sidebar/wiki_link', wiki_url: @group.wiki.web_url
-
- if group_sidebar_link?(:settings)
= nav_link(path: group_settings_nav_link_paths) do
= link_to edit_group_path(@group), class: 'has-sub-items' do
diff --git a/app/views/layouts/nav/sidebar/_wiki_link.html.haml b/app/views/layouts/nav/sidebar/_wiki_link.html.haml
deleted file mode 100644
index b6b63b75fcc..00000000000
--- a/app/views/layouts/nav/sidebar/_wiki_link.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-= nav_link(controller: :wikis) do
- = link_to wiki_url, class: 'shortcuts-wiki', data: { qa_selector: 'wiki_link' } do
- .nav-icon-container
- = sprite_icon('book')
- %span.nav-item-name
- = _('Wiki')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: :wikis, html_options: { class: "fly-out-top-item" } ) do
- = link_to wiki_url do
- %strong.fly-out-top-item-name
- = _('Wiki')
diff --git a/app/views/shared/integrations/_form.html.haml b/app/views/shared/integrations/_form.html.haml
index 62f8d986296..35f302a28a6 100644
--- a/app/views/shared/integrations/_form.html.haml
+++ b/app/views/shared/integrations/_form.html.haml
@@ -1,7 +1,4 @@
- integration = local_assigns.fetch(:integration)
-%h3.page-title
- = integration.title
-
= form_for integration, as: :service, url: scoped_integration_path(integration), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'test-url' => scoped_test_integration_path(integration) } } do |form|
= render 'shared/service_settings', form: form, integration: integration
diff --git a/app/views/shared/integrations/_tabs.html.haml b/app/views/shared/integrations/_tabs.html.haml
index ff97e371374..553401e47bd 100644
--- a/app/views/shared/integrations/_tabs.html.haml
+++ b/app/views/shared/integrations/_tabs.html.haml
@@ -1,14 +1,18 @@
-.tabs.gl-tabs
- %div
- %ul.nav.gl-tabs-nav{ role: 'tablist' }
- %li.nav-item{ role: 'presentation' }
- %a.nav-link.gl-tab-nav-item{ role: 'tab', href: scoped_edit_integration_path(integration) }
- = _('Settings')
+- active_tab = local_assigns.fetch(:active_tab, 'edit')
+- active_classes = 'gl-tab-nav-item-active gl-tab-nav-item-active-indigo active'
+- tabs = integration_tabs(integration: integration)
- %li.nav-item{ role: 'presentation' }
- %a.nav-link.gl-tab-nav-item.gl-tab-nav-item-active.gl-tab-nav-item-active-indigo.active{ role: 'tab', href: scoped_overrides_integration_path(integration) }
- = s_('Integrations|Projects using custom settings')
+- if tabs.length <= 1
+ = yield
+- else
+ .tabs.gl-tabs
+ %div
+ %ul.nav.gl-tabs-nav{ role: 'tablist' }
+ - tabs.each do |tab|
+ %li.nav-item{ role: 'presentation' }
+ %a.nav-link.gl-tab-nav-item{ role: 'tab', class: (active_classes if tab[:key] == active_tab), href: tab[:href] }
+ = tab[:text]
- .tab-content.gl-tab-content
- .tab-pane.active{ role: 'tabpanel' }
- = yield
+ .tab-content.gl-tab-content
+ .tab-pane.gl-pt-3.active{ role: 'tabpanel' }
+ = yield
diff --git a/app/views/shared/integrations/edit.html.haml b/app/views/shared/integrations/edit.html.haml
index a996f72e2f4..02cb94e3555 100644
--- a/app/views/shared/integrations/edit.html.haml
+++ b/app/views/shared/integrations/edit.html.haml
@@ -3,4 +3,8 @@
- page_title @integration.title, _('Integrations')
- @content_class = 'limit-container-width' unless fluid_layout
-= render 'shared/integrations/form', integration: @integration
+%h3.page-title
+ = @integration.title
+
+= render 'shared/integrations/tabs', integration: @integration, active_tab: 'edit' do
+ = render 'shared/integrations/form', integration: @integration
diff --git a/app/views/shared/integrations/overrides.html.haml b/app/views/shared/integrations/overrides.html.haml
index 4d8cc94e967..dc87fae704c 100644
--- a/app/views/shared/integrations/overrides.html.haml
+++ b/app/views/shared/integrations/overrides.html.haml
@@ -6,5 +6,5 @@
%h3.page-title
= @integration.title
-= render 'shared/integrations/tabs', integration: @integration do
+= render 'shared/integrations/tabs', integration: @integration, active_tab: 'overrides' do
.js-vue-integration-overrides{ data: integration_overrides_data(@integration) }
diff --git a/config/application.rb b/config/application.rb
index 2ef2ead8a8e..06a5a726d92 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -434,6 +434,21 @@ module Gitlab
end
end
+ # Load JH initializers under JH. Load ordering is:
+ # 1. prepend_helpers_path
+ # 2. before_zeitwerk
+ # 3. let_zeitwerk_take_over
+ # 4. move_initializers
+ # 5. load_config_initializers
+ # 6. load_jh_config_initializers
+ Gitlab.jh do
+ initializer :load_jh_config_initializers, after: :load_config_initializers do
+ Dir[Rails.root.join('jh/config/initializers/*.rb')].sort.each do |initializer|
+ load_config_initializer(initializer)
+ end
+ end
+ end
+
# Add assets for variants of GitLab. They should take precedence over CE.
# This means if multiple files exist, e.g.:
#
diff --git a/db/post_migrate/20210805192450_update_trial_plans_ci_daily_pipeline_schedule_triggers.rb b/db/post_migrate/20210805192450_update_trial_plans_ci_daily_pipeline_schedule_triggers.rb
new file mode 100644
index 00000000000..9552058dd73
--- /dev/null
+++ b/db/post_migrate/20210805192450_update_trial_plans_ci_daily_pipeline_schedule_triggers.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+class UpdateTrialPlansCiDailyPipelineScheduleTriggers < ActiveRecord::Migration[6.1]
+ include Gitlab::Database::MigrationHelpers
+
+ PREMIUM_TRIAL = 'premium_trial'
+ ULTIMATE_TRIAL = 'ultimate_trial'
+ EVERY_5_MINUTES = (1.day.in_minutes / 5).to_i
+
+ class Plan < ActiveRecord::Base
+ self.table_name = 'plans'
+ self.inheritance_column = :_type_disabled
+
+ has_one :limits, class_name: 'PlanLimits'
+ end
+
+ class PlanLimits < ActiveRecord::Base
+ self.table_name = 'plan_limits'
+ self.inheritance_column = :_type_disabled
+
+ belongs_to :plan
+ end
+
+ def plan_limits_present?
+ premium_trial_plan = Plan.find_by(name: PREMIUM_TRIAL)
+ ultimate_trial_plan = Plan.find_by(name: ULTIMATE_TRIAL)
+
+ premium_trial_plan && premium_trial_plan.limits && ultimate_trial_plan && ultimate_trial_plan.limits
+ end
+
+ def up
+ return unless Gitlab.dev_env_or_com?
+
+ if plan_limits_present?
+ create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', PREMIUM_TRIAL, EVERY_5_MINUTES)
+ create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', ULTIMATE_TRIAL, EVERY_5_MINUTES)
+ end
+ end
+
+ def down
+ return unless Gitlab.dev_env_or_com?
+
+ if plan_limits_present?
+ create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', PREMIUM_TRIAL, 0)
+ create_or_update_plan_limit('ci_daily_pipeline_schedule_triggers', ULTIMATE_TRIAL, 0)
+ end
+ end
+end
diff --git a/db/schema_migrations/20210805192450 b/db/schema_migrations/20210805192450
new file mode 100644
index 00000000000..1b9ae3880e0
--- /dev/null
+++ b/db/schema_migrations/20210805192450
@@ -0,0 +1 @@
+a63f878d89269eb8a2a3cc3b0c81d700861031a079a4a69b56d45d73c4c7946e \ No newline at end of file
diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt
index f9db0f99973..43ff584b550 100644
--- a/doc/.vale/gitlab/spelling-exceptions.txt
+++ b/doc/.vale/gitlab/spelling-exceptions.txt
@@ -14,6 +14,7 @@ anonymized
Ansible
Anthos
Apdex
+Apparmor
approvers
architected
architecting
@@ -28,6 +29,7 @@ Atlassian
auditability
Auth0
Authentiq
+Authy
autocomplete
autocompleted
autocompletes
@@ -186,6 +188,7 @@ enum
enums
ETag
Excon
+exfiltration
expirable
Facebook
failover
@@ -202,6 +205,7 @@ Filebeat
Fio
firewalled
firewalling
+fixup
Flawfinder
Flowdock
Fluentd
@@ -246,6 +250,7 @@ Haswell
heatmap
heatmaps
Helm
+Helmfile
Heroku
Herokuish
Hexo
diff --git a/doc/administration/geo/replication/disable_geo.md b/doc/administration/geo/replication/disable_geo.md
index ba01c55a157..485a5ee1950 100644
--- a/doc/administration/geo/replication/disable_geo.md
+++ b/doc/administration/geo/replication/disable_geo.md
@@ -35,6 +35,7 @@ to do that.
To remove the **primary** site:
+1. [Remove all secondary Geo sites](remove_geo_site.md)
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. On the left sidebar, select **Geo > Nodes**.
1. Select **Remove** for the **primary** node.
diff --git a/doc/administration/geo/replication/version_specific_updates.md b/doc/administration/geo/replication/version_specific_updates.md
index e193fc630b9..155c06f90b8 100644
--- a/doc/administration/geo/replication/version_specific_updates.md
+++ b/doc/administration/geo/replication/version_specific_updates.md
@@ -11,6 +11,16 @@ Review this page for update instructions for your version. These steps
accompany the [general steps](updating_the_geo_nodes.md#general-update-steps)
for updating Geo nodes.
+## Updating to GitLab 14.0/14.1
+
+We found an issue where [Primary sites can not be removed from the UI](https://gitlab.com/gitlab-org/gitlab/-/issues/338231).
+
+This bug only exists in the UI and does not block the removal of Primary sites using any other method.
+
+### If you have already updated to an affected version and need to remove your Primary site
+
+You can manually remove the Primary site by using the [Geo Nodes API](../../../api/geo_nodes.md#delete-a-geo-node).
+
## Updating to GitLab 13.12
We found an issue where [secondary nodes re-download all LFS files](https://gitlab.com/gitlab-org/gitlab/-/issues/334550) upon update. This bug:
diff --git a/doc/administration/get_started.md b/doc/administration/get_started.md
index ac717769d4f..6fe66aa1642 100644
--- a/doc/administration/get_started.md
+++ b/doc/administration/get_started.md
@@ -146,7 +146,7 @@ Backups of GitLab databases and filesystems are taken every 24 hours, and are ke
- GitLab SaaS creates backups to ensure your data is secure, but you can't use these methods to export or back up your data yourself.
- Issues are stored in the database. They can't be stored in Git itself.
- You can use the project export option in:
- - [The UI](../user/project/settings/import_export.md#exporting-a-project-and-its-data).
+ - [The UI](../user/project/settings/import_export.md#export-a-project-and-its-data).
- [The API](../api/project_import_export.md#schedule-an-export).
- [Group export](../user/group/settings/import_export.md) does *not* export the projects in it, but does export:
- Epics
diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
index 9fccc280677..ee6e308d443 100644
--- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
+++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
@@ -466,7 +466,7 @@ sudo gitlab-rake cache:clear
### Export a repository
-It's typically recommended to export a project through [the web interface](../../user/project/settings/import_export.md#exporting-a-project-and-its-data) or through [the API](../../api/project_import_export.md). In situations where this is not working as expected, it may be preferable to export a project directly via the Rails console:
+It's typically recommended to export a project through [the web interface](../../user/project/settings/import_export.md#export-a-project-and-its-data) or through [the API](../../api/project_import_export.md). In situations where this is not working as expected, it may be preferable to export a project directly via the Rails console:
```ruby
user = User.find_by_username('USERNAME')
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 0ef305d0240..9d464c94d99 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -112,8 +112,8 @@ Supported attributes:
| Attribute | Type | Required | Description |
| :-------- | :------- | :------- | :---------- |
-| `id` | datatype | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `sha` | datatype | yes | The blob SHA. |
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `sha` | string | yes | The blob SHA. |
## Get file archive
diff --git a/doc/development/import_project.md b/doc/development/import_project.md
index 71d8f8b34b9..69e5873cd87 100644
--- a/doc/development/import_project.md
+++ b/doc/development/import_project.md
@@ -16,7 +16,7 @@ There are several ways to import a project.
### Importing via UI
-The first option is to simply [import the Project tarball file via the GitLab UI](../user/project/settings/import_export.md#importing-the-project):
+The first option is to simply [import the Project tarball file via the GitLab UI](../user/project/settings/import_export.md#import-the-project):
1. Create the group `qa-perf-testing`
1. Import the [GitLab FOSS project tarball](https://gitlab.com/gitlab-org/quality/performance-data/-/blob/master/projects_export/gitlabhq_export.tar.gz) into the Group.
diff --git a/doc/operations/incident_management/paging.md b/doc/operations/incident_management/paging.md
index db419001343..6fdf880783a 100644
--- a/doc/operations/incident_management/paging.md
+++ b/doc/operations/incident_management/paging.md
@@ -27,10 +27,11 @@ Email notifications are available in projects for triggered alerts. Project
members with the **Owner** or **Maintainer** roles have the option to receive
a single email notification for new alerts.
-1. Navigate to **Settings > Monitor**.
-1. Expand the **Alerts** section.
-1. In the **Integration settings** tab, select the checkbox
- **Send a single email notification to Owners and Maintainers for new alerts**.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Monitor**.
+1. Expand **Alerts**.
+1. On the **Alert settings** tab, select the
+ **Send a single email notification to Owners and Maintainers for new alerts** checkbox.
1. Select **Save changes**.
## Paging **(PREMIUM)**
diff --git a/doc/operations/incident_management/status_page.md b/doc/operations/incident_management/status_page.md
index d14e4120511..db7b55424dd 100644
--- a/doc/operations/incident_management/status_page.md
+++ b/doc/operations/incident_management/status_page.md
@@ -39,19 +39,23 @@ To configure a GitLab Status Page you must:
Only AWS S3 is supported as a deploy target.
+Prerequisite:
+
+- You must have at least the Maintainer [role](../../user/permissions.md).
+
To provide GitLab with the AWS account information needed to push content to your Status Page:
-1. Sign into GitLab as a user with Maintainer or greater [permissions](../../user/permissions.md).
-1. Navigate to **{settings}** **Settings > Monitor**. Next to **Status Page**,
- click **Expand**.
-1. Click **Active** to enable the Status Page feature.
-1. In **Status Page URL**, provide the URL to your external status page.
-1. Provide the **S3 Bucket name**. For more information, see
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Monitor**.
+1. Expand **Status Page**.
+1. Select the **Active** checkbox.
+1. In the **Status Page URL** box, provide the URL for your external status page.
+1. In the **S3 Bucket name** box, type the name of your S3 bucket. For more information, see
[Bucket configuration documentation](https://docs.aws.amazon.com/AmazonS3/latest/dev/HostingWebsiteOnS3Setup.html).
-1. Provide the **AWS region** for your bucket. For more information, see the
+1. In the **AWS region** box, type the region for your bucket. For more information, see the
[AWS documentation](https://github.com/aws/aws-sdk-ruby#configuration).
-1. Provide your **AWS access key ID** and **AWS Secret access key**.
-1. Click **Save changes**.
+1. Enter your **AWS access key ID** and **AWS Secret access key**.
+1. Select **Save changes**.
### Configure your AWS account
@@ -69,8 +73,8 @@ the necessary CI/CD variables to deploy the Status Page to AWS S3:
1. Fork the [Status Page](https://gitlab.com/gitlab-org/status-page) project.
You can do this through [Repository Mirroring](https://gitlab.com/gitlab-org/status-page#repository-mirroring),
which ensures you get the up-to-date Status Page features.
-1. Navigate to **{settings}** **Settings > CI/CD**.
-1. Scroll to **Variables**, and click **Expand**.
+1. On the left sidebar, select **Settings > CI/CD**.
+1. Expand **Variables**.
1. Add the following variables from your Amazon Console:
- `S3_BUCKET_NAME` - The name of the Amazon S3 bucket.
If no bucket with the provided name exists, the first pipeline run creates
@@ -80,8 +84,8 @@ the necessary CI/CD variables to deploy the Status Page to AWS S3:
- `AWS_DEFAULT_REGION` - The AWS region.
- `AWS_ACCESS_KEY_ID` - The AWS access key ID.
- `AWS_SECRET_ACCESS_KEY` - The AWS secret.
-1. Navigate to **CI/CD > Pipelines > Run Pipeline**, and run the pipeline to
- deploy the Status Page to S3.
+1. On the left sidebar, select **CI/CD > Pipelines**.
+1. To deploy the Status Page to S3, select **Run pipeline**.
WARNING:
Consider limiting who can access issues in this project, as any user who can view
@@ -92,7 +96,9 @@ the issue can potentially [publish comments to your GitLab Status Page](#publish
After creating the CI/CD variables, configure the Project you want to use for
Incident issues:
-1. To view the Status Page settings, navigate to **{settings}** **Settings > Monitor > Status Page**.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Monitor**.
+1. Expand **Status page**.
1. Fill in your cloud provider's credentials and make sure to select the **Active** checkbox.
1. Select **Save changes**.
diff --git a/doc/user/admin_area/analytics/dev_ops_report.md b/doc/user/admin_area/analytics/dev_ops_report.md
index 5a335718c6e..f07ccc11c60 100644
--- a/doc/user/admin_area/analytics/dev_ops_report.md
+++ b/doc/user/admin_area/analytics/dev_ops_report.md
@@ -44,7 +44,7 @@ feature is available.
> - DAST and SAST metrics [added](https://gitlab.com/gitlab-org/gitlab/-/issues/328033) in GitLab 14.1.
> - Fuzz Testing metrics [added](https://gitlab.com/gitlab-org/gitlab/-/issues/330398) in GitLab 14.2.
> - Dependency Scanning metrics [added](https://gitlab.com/gitlab-org/gitlab/-/issues/328034) in GitLab 14.2.
-> - Multiselect [added](https://gitlab.com/gitlab-org/gitlab/-/issues/333586) in GitLab 14.2.
+> - Multi-select [added](https://gitlab.com/gitlab-org/gitlab/-/issues/333586) in GitLab 14.2.
DevOps Adoption shows you which groups in your organization are using the most essential features of GitLab:
diff --git a/doc/user/admin_area/settings/floc.md b/doc/user/admin_area/settings/floc.md
index 31a626478ed..0e9d4e5d0c1 100644
--- a/doc/user/admin_area/settings/floc.md
+++ b/doc/user/admin_area/settings/floc.md
@@ -8,8 +8,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60933) in GitLab Free 13.12.
-Federated Learning of Conhorts (FLoC) is a feature that the Chrome browser has
-rolled out, where users are categorized into different cohorts, so that
+Federated Learning of Cohorts (FLoC) is a new feature of the Chrome browser.
+It works by categorizing users into different cohorts, so that
advertisers can use this data to uniquely target and track users. For more
information, visit the [FLoC repository](https://github.com/WICG/floc).
diff --git a/doc/user/admin_area/settings/rate_limit_on_notes_creation.md b/doc/user/admin_area/settings/rate_limit_on_notes_creation.md
index 193f39542cf..7615ad6f81d 100644
--- a/doc/user/admin_area/settings/rate_limit_on_notes_creation.md
+++ b/doc/user/admin_area/settings/rate_limit_on_notes_creation.md
@@ -17,7 +17,7 @@ To change the note creation rate limit:
1. On the left sidebar, select **Settings > Network**.
1. Expand **Notes Rate Limits**.
1. Under **Max requests per minute per user**, enter the new value.
-1. Optional. Under **List of users to be excluded from the limit**, list users to be excluded fromt the limit.
+1. Optional. Under **List of users to be excluded from the limit**, list users to be excluded from the limit.
1. Select **Save changes**.
This limit is:
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index 45256187a7e..c46aec76e57 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -211,7 +211,7 @@ You can specify from which hosting sites users can [import their projects](../..
## Enable project export
To enable the export of
-[projects and their data](../../../user/project/settings/import_export.md#exporting-a-project-and-its-data):
+[projects and their data](../../../user/project/settings/import_export.md#export-a-project-and-its-data):
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu >** **{admin}** **Admin**.
diff --git a/doc/user/analytics/value_stream_analytics.md b/doc/user/analytics/value_stream_analytics.md
index 4ad3a03a5b0..9a1aed9c39f 100644
--- a/doc/user/analytics/value_stream_analytics.md
+++ b/doc/user/analytics/value_stream_analytics.md
@@ -124,9 +124,9 @@ From the previous example we see the time used for each stage:
- **Issue**: 2 hrs (09:00 to 11:00)
- **Plan**: 1 hr (11:00 to 12:00)
- **Code**: 2 hrs (12:00 to 14:00)
-- **Test**: 5 mins
+- **Test**: 5 minutes
- **Review**: 5 hrs (14:00 to 19:00)
-- **Staging**: 30 mins (19:00 to 19:30)
+- **Staging**: 30 minutes (19:00 to 19:30)
More information:
diff --git a/doc/user/clusters/management_project_template.md b/doc/user/clusters/management_project_template.md
index 22fc01de4b6..1de17396bf4 100644
--- a/doc/user/clusters/management_project_template.md
+++ b/doc/user/clusters/management_project_template.md
@@ -53,13 +53,13 @@ project. This image consists of a set of Bash utility scripts to support [Helm v
This file has a list of paths to other Helmfiles for each app. They're all commented out by default, so you must uncomment
the paths for the apps that you would like to manage.
-By default, each `helmfile.yaml` in these sub-paths will have the attribute `installed: true`, which signifies that everytime
-the pipeline runs, Helmfile will try to either install or update your apps according to the current state of your
-cluster and Helm releases. If you change this attribute to `installed: false`, Helmfile will try to uninstall this app
+By default, each `helmfile.yaml` in these sub-paths have the attribute `installed: true`. This signifies that every time
+the pipeline runs, Helmfile tries to either install or update your apps according to the current state of your
+cluster and Helm releases. If you change this attribute to `installed: false`, Helmfile tries try to uninstall this app
from your cluster. [Read more](https://github.com/roboll/helmfile) about how Helmfile works.
Furthermore, each app has an `applications/{app}/values.yaml` file. This is the
-place where you can define some default values for your app's Helm chart. Some apps will already have defaults
+place where you can define some default values for your app's Helm chart. Some apps already have defaults
pre-defined by GitLab.
#### Built-in applications
@@ -80,7 +80,7 @@ The [built-in supported applications](https://gitlab.com/gitlab-org/project-temp
- [Sentry](../infrastructure/clusters/manage/management_project_applications/sentry.md)
- [Vault](../infrastructure/clusters/manage/management_project_applications/vault.md)
-### Migrating from GitLab Managed Apps
+### Migrate from GitLab Managed Apps
If you had GitLab Managed Apps, either One-Click or CI/CD install, read the docs on how to
[migrate from GitLab Managed Apps to project template](migrating_from_gma_to_project_template.md)
diff --git a/doc/user/infrastructure/clusters/manage/management_project_applications/sentry.md b/doc/user/infrastructure/clusters/manage/management_project_applications/sentry.md
index 1fe9b57cd4b..4d82fe389d2 100644
--- a/doc/user/infrastructure/clusters/manage/management_project_applications/sentry.md
+++ b/doc/user/infrastructure/clusters/manage/management_project_applications/sentry.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: Health
+group: Monitor
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
---
diff --git a/doc/user/infrastructure/index.md b/doc/user/infrastructure/index.md
index 7e334e93c4f..b2d75a22615 100644
--- a/doc/user/infrastructure/index.md
+++ b/doc/user/infrastructure/index.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Infrastructure management **(FREE)**
GitLab provides you with great solutions to help you manage your
-infrastrucure:
+infrastructure:
- [Infrastructure as Code and GitOps](iac/index.md)
- [Kubernetes clusters](../project/clusters/index.md)
diff --git a/doc/user/project/clusters/add_remove_clusters.md b/doc/user/project/clusters/add_remove_clusters.md
index dc55b34d4ba..fba02183be5 100644
--- a/doc/user/project/clusters/add_remove_clusters.md
+++ b/doc/user/project/clusters/add_remove_clusters.md
@@ -42,8 +42,8 @@ providers. To host them on premises and with other providers,
use either the EKS or GKE method to guide you through and enter your cluster's
settings manually:
-- [New cluster hosted on Google Kubernetes Engine (GKE)](add_eks_clusters.md).
-- [New cluster hosted on Amazon Elastic Kubernetes Service (EKS)](add_gke_clusters.md).
+- [New cluster hosted on Google Kubernetes Engine (GKE)](add_gke_clusters.md).
+- [New cluster hosted on Amazon Elastic Kubernetes Service (EKS)](add_eks_clusters.md).
## Add existing cluster
diff --git a/doc/user/project/import/gitlab_com.md b/doc/user/project/import/gitlab_com.md
index f7eb5e43a79..f25b29317a7 100644
--- a/doc/user/project/import/gitlab_com.md
+++ b/doc/user/project/import/gitlab_com.md
@@ -15,7 +15,7 @@ To get to the importer page you need to go to "New project" page.
NOTE:
If you are interested in importing Wiki and Merge Request data to your new instance,
-you'll need to follow the instructions for [exporting a project](../settings/import_export.md#exporting-a-project-and-its-data)
+you'll need to follow the instructions for [exporting a project](../settings/import_export.md#export-a-project-and-its-data)
![New project page](img/gitlab_new_project_page_v12_2.png)
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index 8d61813dd5a..668a0dffd32 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -121,7 +121,7 @@ Kubernetes, Slack, and a lot more.
- [Bitbucket to GitLab](import/bitbucket.md)
- [Gitea to GitLab](import/gitea.md)
- [FogBugz to GitLab](import/fogbugz.md)
-- [Export a project from GitLab](settings/import_export.md#exporting-a-project-and-its-data)
+- [Export a project from GitLab](settings/import_export.md#export-a-project-and-its-data)
- [Importing and exporting projects between GitLab instances](settings/import_export.md)
## GitLab Workflow - VS Code extension
diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md
index ecb32feff55..81429ea5384 100644
--- a/doc/user/project/repository/reducing_the_repo_size_using_git.md
+++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md
@@ -23,7 +23,7 @@ over [`git filter-branch`](https://git-scm.com/docs/git-filter-branch) and
WARNING:
Rewriting repository history is a destructive operation. Make sure to back up your repository before
you begin. The best way back up a repository is to
-[export the project](../settings/import_export.md#exporting-a-project-and-its-data).
+[export the project](../settings/import_export.md#export-a-project-and-its-data).
## Purge files from repository history
@@ -44,7 +44,7 @@ To purge files from a GitLab repository:
using a supported package manager or from source.
1. Generate a fresh [export from the
- project](../settings/import_export.html#exporting-a-project-and-its-data) and download it.
+ project](../settings/import_export.html#export-a-project-and-its-data) and download it.
This project export contains a backup copy of your repository *and* refs
we can use to purge files from your repository.
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index cd0fa351e29..d0511419d38 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -32,8 +32,8 @@ To set up a project import/export:
Note the following:
-- Before you can import a project, you need to export the data first.
- See [Exporting a project and its data](#exporting-a-project-and-its-data)
+- Before you can import a project, you must export the data first.
+ See [Export a project and its data](#export-a-project-and-its-data)
for how you can export a project through the UI.
- Imports from a newer version of GitLab are not supported.
The Importing GitLab version must be greater than or equal to the Exporting GitLab version.
@@ -42,7 +42,7 @@ Note the following:
- Exports are generated in your configured `shared_path`, a temporary shared directory,
and are moved to your configured `uploads_directory`. Every 24 hours, a specific worker deletes these export files.
- Group members are exported as project members, as long as the user has
- maintainer or administrator access to the group where the exported project lives.
+ a maintainer or administrator role in the group where the exported project lives.
- Project members with the [Owner role](../../permissions.md) are imported as Maintainers.
- Imported users can be mapped by their primary email on self-managed instances, if an administrative user (not an owner) does the import.
Otherwise, a supplementary comment is left to mention that the original author and
@@ -51,10 +51,10 @@ Note the following:
possible through a [professional services engagement](https://about.gitlab.com/services/migration/).
- If an imported project contains merge requests originating from forks,
then new branches associated with such merge requests are created
- within a project during the import/export. Thus, the number of branches
+ in a project during the import/export. Thus, the number of branches
in the exported project could be bigger than in the original project.
- Deploy keys allowed to push to protected branches are not exported. Therefore,
- you need to recreate this association by first enabling these deploy keys in your
+ you must recreate this association by first enabling these deploy keys in your
imported project and then updating your protected branches accordingly.
## Version history
@@ -141,7 +141,7 @@ NOTE:
For more details on the specific data persisted in a project export, see the
[`import_export.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/import_export/project/import_export.yml) file.
-## Exporting a project and its data
+## Export a project and its data
Full project export functionality is limited to project maintainers and owners.
You can configure such functionality through [project settings](index.md):
@@ -156,18 +156,18 @@ To export a project and its data, follow these steps:
![Export button](img/import_export_export_button.png)
-1. Once the export is generated, you should receive an email with a link to
+1. After the export is generated, you should receive an email with a link to
download the file:
![Email download link](img/import_export_mail_link.png)
1. Alternatively, you can come back to the project settings and download the
- file from there, or generate a new export. Once the file is available, the page
+ file from there, or generate a new export. After the file is available, the page
should show the **Download export** button:
![Download export](img/import_export_download_export.png)
-## Importing the project
+## Import the project
1. The GitLab project import feature is the first import option when creating a
new project. Click on **GitLab export**:
@@ -215,7 +215,7 @@ GitLab.com may have [different settings](../../gitlab_com/index.md#importexport)
### Import workaround for large repositories
-[Maximum import size limitations](#importing-the-project)
+[Maximum import size limitations](#import-the-project)
can prevent an import from being successful.
If changing the import limits is not possible,
the following local workflow can be used to temporarily
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 179fa755918..66fdace81ba 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -271,7 +271,7 @@ Enable [Service Desk](../service_desk.md) for your project to offer customer sup
### Export project
-Learn how to [export a project](import_export.md#importing-the-project) in GitLab.
+Learn how to [export a project](import_export.md#import-the-project) in GitLab.
### Advanced settings
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 9255d3dd4fe..ebf23280570 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -7181,6 +7181,9 @@ msgstr ""
msgid "ClusterAgents|Go to the repository"
msgstr ""
+msgid "ClusterAgents|Install a new GitLab Agent"
+msgstr ""
+
msgid "ClusterAgents|Install new Agent"
msgstr ""
@@ -7196,9 +7199,6 @@ msgstr ""
msgid "ClusterAgents|Learn how to create an agent access token"
msgstr ""
-msgid "ClusterAgents|Learn more about installing the GitLab Agent"
-msgstr ""
-
msgid "ClusterAgents|Name"
msgstr ""
@@ -14966,13 +14966,10 @@ msgstr ""
msgid "Geo|Remove node"
msgstr ""
-msgid "Geo|Remove secondary node"
-msgstr ""
-
msgid "Geo|Remove tracking database entry"
msgstr ""
-msgid "Geo|Removing a Geo secondary node stops the synchronization to that node. Are you sure?"
+msgid "Geo|Removing a Geo node stops the synchronization to and from that node. Are you sure?"
msgstr ""
msgid "Geo|Replicated data is verified with the secondary node(s) using checksums"
@@ -17912,6 +17909,9 @@ msgstr ""
msgid "Integrations|All projects inheriting these settings will also be reset."
msgstr ""
+msgid "Integrations|An error occurred while loading projects using custom settings."
+msgstr ""
+
msgid "Integrations|Browser limitations"
msgstr ""
@@ -18032,6 +18032,9 @@ msgstr ""
msgid "Integrations|Standard"
msgstr ""
+msgid "Integrations|There are no projects using custom settings"
+msgstr ""
+
msgid "Integrations|This integration, and inheriting projects were reset."
msgstr ""
@@ -39694,8 +39697,10 @@ msgstr ""
msgid "mrWidget|Closed by"
msgstr ""
-msgid "mrWidget|Closes"
-msgstr ""
+msgid "mrWidget|Closes issue"
+msgid_plural "mrWidget|Closes issues"
+msgstr[0] ""
+msgstr[1] ""
msgid "mrWidget|Delete source branch"
msgstr ""
@@ -39730,8 +39735,10 @@ msgstr ""
msgid "mrWidget|Members who can merge are allowed to add commits."
msgstr ""
-msgid "mrWidget|Mentions"
-msgstr ""
+msgid "mrWidget|Mentions issue"
+msgid_plural "mrWidget|Mentions issues"
+msgstr[0] ""
+msgstr[1] ""
msgid "mrWidget|Merge"
msgstr ""
diff --git a/package.json b/package.json
index 29680e1a904..f941cfcee1b 100644
--- a/package.json
+++ b/package.json
@@ -125,7 +125,7 @@
"dateformat": "^4.5.1",
"deckar01-task_list": "^2.3.1",
"diff": "^3.4.0",
- "dompurify": "^2.3.0",
+ "dompurify": "^2.3.1",
"dropzone": "^4.2.0",
"editorconfig": "^0.15.3",
"emoji-regex": "^7.0.3",
diff --git a/spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb b/spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb
index 6f091d37995..c4626996d0c 100644
--- a/spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb
+++ b/spec/features/admin/integrations/user_activates_mattermost_slash_command_spec.rb
@@ -11,6 +11,24 @@ RSpec.describe 'User activates the instance-level Mattermost Slash Command integ
end
let(:edit_path) { edit_admin_application_settings_integration_path(:mattermost_slash_commands) }
+ let(:overrides_path) { overrides_admin_application_settings_integration_path(:mattermost_slash_commands) }
include_examples 'user activates the Mattermost Slash Command integration'
+
+ it 'displays navigation tabs' do
+ expect(page).to have_link('Settings', href: edit_path)
+ expect(page).to have_link('Projects using custom settings', href: overrides_path)
+ end
+
+ context 'when instance_level_integration_overrides is disabled' do
+ before do
+ stub_feature_flags(instance_level_integration_overrides: false)
+ visit_instance_integration('Mattermost slash commands')
+ end
+
+ it 'does not display the overrides tab' do
+ expect(page).not_to have_link('Settings', href: edit_path)
+ expect(page).not_to have_link('Projects using custom settings', href: overrides_path)
+ end
+ end
end
diff --git a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb
index d6cdc15005b..7b7fff5c936 100644
--- a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb
+++ b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_description) { "Description\n\nclosing #{issue_1.to_reference}, #{issue_2.to_reference}" }
it 'does not display closing issue message' do
- expect(page).to have_content("Closes #{issue_1.to_reference} and #{issue_2.to_reference}")
+ expect(page).to have_content("Closes issues #{issue_1.to_reference} and #{issue_2.to_reference}")
end
end
@@ -39,7 +39,7 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_description) { "Description\n\nRefers to #{issue_1.to_reference} and #{issue_2.to_reference}" }
it 'does not display closing issue message' do
- expect(page).to have_content("Mentions #{issue_1.to_reference} and #{issue_2.to_reference}")
+ expect(page).to have_content("Mentions issues #{issue_1.to_reference} and #{issue_2.to_reference}")
end
end
@@ -47,8 +47,8 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_title) { "closes #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" }
it 'does not display closing issue message' do
- expect(page).to have_content("Closes #{issue_1.to_reference}")
- expect(page).to have_content("Mentions #{issue_2.to_reference}")
+ expect(page).to have_content("Closes issue #{issue_1.to_reference}")
+ expect(page).to have_content("Mentions issue #{issue_2.to_reference}")
end
end
@@ -56,7 +56,7 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_title) { "closing #{issue_1.to_reference}, #{issue_2.to_reference}" }
it 'does not display closing issue message' do
- expect(page).to have_content("Closes #{issue_1.to_reference} and #{issue_2.to_reference}")
+ expect(page).to have_content("Closes issues #{issue_1.to_reference} and #{issue_2.to_reference}")
end
end
@@ -64,7 +64,7 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_title) { "Refers to #{issue_1.to_reference} and #{issue_2.to_reference}" }
it 'does not display closing issue message' do
- expect(page).to have_content("Mentions #{issue_1.to_reference} and #{issue_2.to_reference}")
+ expect(page).to have_content("Mentions issues #{issue_1.to_reference} and #{issue_2.to_reference}")
end
end
@@ -72,8 +72,8 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do
let(:merge_request_title) { "closes #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" }
it 'does not display closing issue message' do
- expect(page).to have_content("Closes #{issue_1.to_reference}")
- expect(page).to have_content("Mentions #{issue_2.to_reference}")
+ expect(page).to have_content("Closes issue #{issue_1.to_reference}")
+ expect(page).to have_content("Mentions issue #{issue_2.to_reference}")
end
end
end
diff --git a/spec/frontend/content_editor/components/toolbar_table_button_spec.js b/spec/frontend/content_editor/components/toolbar_table_button_spec.js
index 336391f9b63..056e5e04e1f 100644
--- a/spec/frontend/content_editor/components/toolbar_table_button_spec.js
+++ b/spec/frontend/content_editor/components/toolbar_table_button_spec.js
@@ -29,17 +29,17 @@ describe('content_editor/components/toolbar_table_button', () => {
wrapper.destroy();
});
- it('renders a grid of 3x3 buttons to create a table', () => {
- expect(getNumButtons()).toBe(9); // 3 x 3
+ it('renders a grid of 5x5 buttons to create a table', () => {
+ expect(getNumButtons()).toBe(25); // 5x5
});
describe.each`
row | col | numButtons | tableSize
- ${1} | ${2} | ${9} | ${'1x2'}
- ${2} | ${2} | ${9} | ${'2x2'}
- ${2} | ${3} | ${12} | ${'2x3'}
- ${3} | ${2} | ${12} | ${'3x2'}
- ${3} | ${3} | ${16} | ${'3x3'}
+ ${3} | ${4} | ${25} | ${'3x4'}
+ ${4} | ${4} | ${25} | ${'4x4'}
+ ${4} | ${5} | ${30} | ${'4x5'}
+ ${5} | ${4} | ${30} | ${'5x4'}
+ ${5} | ${5} | ${36} | ${'5x5'}
`('button($row, $col) in the table creator grid', ({ row, col, numButtons, tableSize }) => {
describe('on mouse over', () => {
beforeEach(async () => {
@@ -50,9 +50,7 @@ describe('content_editor/components/toolbar_table_button', () => {
it('marks all rows and cols before it as active', () => {
const prevRow = Math.max(1, row - 1);
const prevCol = Math.max(1, col - 1);
- expect(wrapper.findByTestId(`table-${prevRow}-${prevCol}`).element).toHaveClass(
- 'gl-bg-blue-50!',
- );
+ expect(wrapper.findByTestId(`table-${prevRow}-${prevCol}`).element).toHaveClass('active');
});
it('shows a help text indicating the size of the table being inserted', () => {
@@ -89,8 +87,8 @@ describe('content_editor/components/toolbar_table_button', () => {
});
});
- it('does not create more buttons than a 8x8 grid', async () => {
- for (let i = 3; i < 8; i += 1) {
+ it('does not create more buttons than a 10x10 grid', async () => {
+ for (let i = 5; i < 10; i += 1) {
expect(getNumButtons()).toBe(i * i);
// eslint-disable-next-line no-await-in-loop
@@ -98,6 +96,6 @@ describe('content_editor/components/toolbar_table_button', () => {
expect(findDropdown().element).toHaveText(`Insert a ${i}x${i} table.`);
}
- expect(getNumButtons()).toBe(64); // 8x8 (and not 9x9)
+ expect(getNumButtons()).toBe(100); // 10x10 (and not 11x11)
});
});
diff --git a/spec/frontend/integrations/overrides/components/integration_overrides_spec.js b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js
new file mode 100644
index 00000000000..dbed236d7df
--- /dev/null
+++ b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js
@@ -0,0 +1,146 @@
+import { GlTable, GlLink, GlPagination } from '@gitlab/ui';
+import { shallowMount, mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
+import { DEFAULT_PER_PAGE } from '~/api';
+import createFlash from '~/flash';
+import IntegrationOverrides from '~/integrations/overrides/components/integration_overrides.vue';
+import axios from '~/lib/utils/axios_utils';
+import httpStatus from '~/lib/utils/http_status';
+import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
+
+jest.mock('~/flash');
+
+const mockOverrides = Array(DEFAULT_PER_PAGE * 3)
+ .fill(1)
+ .map((_, index) => ({
+ name: `test-proj-${index}`,
+ avatar_url: `avatar-${index}`,
+ full_path: `test-proj-${index}`,
+ full_name: `test-proj-${index}`,
+ }));
+
+describe('IntegrationOverrides', () => {
+ let wrapper;
+ let mockAxios;
+
+ const defaultProps = {
+ overridesPath: 'mock/overrides',
+ };
+
+ const createComponent = ({ mountFn = shallowMount } = {}) => {
+ wrapper = mountFn(IntegrationOverrides, {
+ propsData: defaultProps,
+ });
+ };
+
+ beforeEach(() => {
+ mockAxios = new MockAdapter(axios);
+ mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, mockOverrides, {
+ 'X-TOTAL': mockOverrides.length,
+ 'X-PAGE': 1,
+ });
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ wrapper.destroy();
+ });
+
+ const findGlTable = () => wrapper.findComponent(GlTable);
+ const findPagination = () => wrapper.findComponent(GlPagination);
+ const findRowsAsModel = () =>
+ findGlTable()
+ .findAllComponents(GlLink)
+ .wrappers.map((link) => {
+ const avatar = link.findComponent(ProjectAvatar);
+
+ return {
+ href: link.attributes('href'),
+ avatarUrl: avatar.props('projectAvatarUrl'),
+ avatarName: avatar.props('projectName'),
+ text: link.text(),
+ };
+ });
+
+ describe('while loading', () => {
+ it('sets GlTable `busy` attribute to `true`', () => {
+ createComponent();
+
+ const table = findGlTable();
+ expect(table.exists()).toBe(true);
+ expect(table.attributes('busy')).toBe('true');
+ });
+ });
+
+ describe('when initial request is successful', () => {
+ it('sets GlTable `busy` attribute to `false`', async () => {
+ createComponent();
+ await waitForPromises();
+
+ const table = findGlTable();
+ expect(table.exists()).toBe(true);
+ expect(table.attributes('busy')).toBeFalsy();
+ });
+
+ describe('table template', () => {
+ beforeEach(async () => {
+ createComponent({ mountFn: mount });
+ await waitForPromises();
+ });
+
+ it('renders overrides as rows in table', () => {
+ expect(findRowsAsModel()).toEqual(
+ mockOverrides.map((x) => ({
+ href: x.full_path,
+ avatarUrl: x.avatar_url,
+ avatarName: x.name,
+ text: expect.stringContaining(x.full_name),
+ })),
+ );
+ });
+ });
+ });
+
+ describe('when request fails', () => {
+ beforeEach(async () => {
+ mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.INTERNAL_SERVER_ERROR);
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('calls createFlash', () => {
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith({
+ message: IntegrationOverrides.i18n.defaultErrorMessage,
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+ });
+
+ describe('pagination', () => {
+ it('triggers fetch when `input` event is emitted', async () => {
+ createComponent();
+ jest.spyOn(axios, 'get');
+ await waitForPromises();
+
+ await findPagination().vm.$emit('input', 2);
+ expect(axios.get).toHaveBeenCalledWith(defaultProps.overridesPath, {
+ params: { page: 2, per_page: DEFAULT_PER_PAGE },
+ });
+ });
+
+ it('does not render with <=1 page', async () => {
+ mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, [mockOverrides[0]], {
+ 'X-TOTAL': 1,
+ 'X-PAGE': 1,
+ });
+
+ createComponent();
+ await waitForPromises();
+
+ expect(findPagination().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/jobs/components/stages_dropdown_spec.js b/spec/frontend/jobs/components/stages_dropdown_spec.js
index b75d1707a8d..b0e95a2d5b6 100644
--- a/spec/frontend/jobs/components/stages_dropdown_spec.js
+++ b/spec/frontend/jobs/components/stages_dropdown_spec.js
@@ -20,6 +20,7 @@ describe('Stages Dropdown', () => {
const findPipelineInfoText = () => wrapper.findByTestId('pipeline-info').text();
const findPipelinePath = () => wrapper.findByTestId('pipeline-path').attributes('href');
const findMRLinkPath = () => wrapper.findByTestId('mr-link').attributes('href');
+ const findCopySourceBranchBtn = () => wrapper.findByTestId('copy-source-ref-link');
const findSourceBranchLinkPath = () =>
wrapper.findByTestId('source-branch-link').attributes('href');
const findTargetBranchLinkPath = () =>
@@ -70,6 +71,10 @@ describe('Stages Dropdown', () => {
expect(actual).toBe(expected);
});
+
+ it(`renders the source ref copy button`, () => {
+ expect(findCopySourceBranchBtn().exists()).toBe(true);
+ });
});
describe('with an "attached" merge request pipeline', () => {
@@ -103,6 +108,10 @@ describe('Stages Dropdown', () => {
mockPipelineWithAttachedMR.merge_request.target_branch_path,
);
});
+
+ it(`renders the source ref copy button`, () => {
+ expect(findCopySourceBranchBtn().exists()).toBe(true);
+ });
});
describe('with a detached merge request pipeline', () => {
@@ -130,5 +139,9 @@ describe('Stages Dropdown', () => {
mockPipelineDetached.merge_request.source_branch_path,
);
});
+
+ it(`renders the source ref copy button`, () => {
+ expect(findCopySourceBranchBtn().exists()).toBe(true);
+ });
});
});
diff --git a/spec/frontend/notes/components/comment_field_layout_spec.js b/spec/frontend/notes/components/comment_field_layout_spec.js
index 4d9b4ea8c6f..90c989540b9 100644
--- a/spec/frontend/notes/components/comment_field_layout_spec.js
+++ b/spec/frontend/notes/components/comment_field_layout_spec.js
@@ -134,4 +134,18 @@ describe('Comment Field Layout Component', () => {
]);
});
});
+
+ describe('issue has email participants, but note is confidential', () => {
+ it('does not show EmailParticipantsWarning', () => {
+ createWrapper({
+ noteableData: {
+ ...noteableDataMock,
+ issue_email_participants: [{ email: 'someone@gitlab.com' }],
+ },
+ noteIsConfidential: true,
+ });
+
+ expect(findEmailParticipantsWarning().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js
index a879b06e858..6ea8ca10c02 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_related_links_spec.js
@@ -17,7 +17,7 @@ describe('MRWidgetRelatedLinks', () => {
it('returns Closes text for open merge request', () => {
createComponent({ state: 'open', relatedLinks: {} });
- expect(wrapper.vm.closesText).toBe('Closes');
+ expect(wrapper.vm.closesText).toBe('Closes issues');
});
it('returns correct text for closed merge request', () => {
@@ -38,6 +38,7 @@ describe('MRWidgetRelatedLinks', () => {
createComponent({
relatedLinks: {
closing: '<a href="#">#23</a> and <a>#42</a>',
+ closingCount: 2,
},
});
const content = wrapper
@@ -45,7 +46,7 @@ describe('MRWidgetRelatedLinks', () => {
.replace(/\n(\s)+/g, ' ')
.trim();
- expect(content).toContain('Closes #23 and #42');
+ expect(content).toContain('Closes issues #23 and #42');
expect(content).not.toContain('Mentions');
});
@@ -53,11 +54,17 @@ describe('MRWidgetRelatedLinks', () => {
createComponent({
relatedLinks: {
mentioned: '<a href="#">#7</a>',
+ mentionedCount: 1,
},
});
- expect(wrapper.text().trim()).toContain('Mentions #7');
- expect(wrapper.text().trim()).not.toContain('Closes');
+ const content = wrapper
+ .text()
+ .replace(/\n(\s)+/g, ' ')
+ .trim();
+
+ expect(content).toContain('Mentions issue #7');
+ expect(content).not.toContain('Closes issues');
});
it('should have closing and mentioned issues at the same time', () => {
@@ -65,6 +72,8 @@ describe('MRWidgetRelatedLinks', () => {
relatedLinks: {
closing: '<a href="#">#7</a>',
mentioned: '<a href="#">#23</a> and <a>#42</a>',
+ closingCount: 1,
+ mentionedCount: 2,
},
});
const content = wrapper
@@ -72,8 +81,8 @@ describe('MRWidgetRelatedLinks', () => {
.replace(/\n(\s)+/g, ' ')
.trim();
- expect(content).toContain('Closes #7');
- expect(content).toContain('Mentions #23 and #42');
+ expect(content).toContain('Closes issue #7');
+ expect(content).toContain('Mentions issues #23 and #42');
});
it('should have assing issues link', () => {
diff --git a/spec/helpers/clusters_helper_spec.rb b/spec/helpers/clusters_helper_spec.rb
index f64afa1ed71..f1e19f17c72 100644
--- a/spec/helpers/clusters_helper_spec.rb
+++ b/spec/helpers/clusters_helper_spec.rb
@@ -82,6 +82,10 @@ RSpec.describe ClustersHelper do
expect(subject[:get_started_docs_url]).to eq(help_page_path('user/clusters/agent/index', anchor: 'define-a-configuration-repository'))
expect(subject[:integration_docs_url]).to eq(help_page_path('user/clusters/agent/index', anchor: 'get-started-with-gitops-and-the-gitlab-agent'))
end
+
+ it 'displays kas address' do
+ expect(subject[:kas_address]).to eq(Gitlab::Kas.external_url)
+ end
end
describe '#js_clusters_list_data' do
diff --git a/spec/migrations/20210805192450_update_trial_plans_ci_daily_pipeline_schedule_triggers_spec.rb b/spec/migrations/20210805192450_update_trial_plans_ci_daily_pipeline_schedule_triggers_spec.rb
new file mode 100644
index 00000000000..819120d43ef
--- /dev/null
+++ b/spec/migrations/20210805192450_update_trial_plans_ci_daily_pipeline_schedule_triggers_spec.rb
@@ -0,0 +1,137 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!('update_trial_plans_ci_daily_pipeline_schedule_triggers')
+
+RSpec.describe UpdateTrialPlansCiDailyPipelineScheduleTriggers, :migration do
+ let!(:plans) { table(:plans) }
+ let!(:plan_limits) { table(:plan_limits) }
+ let!(:premium_trial_plan) { plans.create!(name: 'premium_trial', title: 'Premium Trial') }
+ let!(:ultimate_trial_plan) { plans.create!(name: 'ultimate_trial', title: 'Ultimate Trial') }
+
+ describe '#up' do
+ let!(:premium_trial_plan_limits) { plan_limits.create!(plan_id: premium_trial_plan.id, ci_daily_pipeline_schedule_triggers: 0) }
+ let!(:ultimate_trial_plan_limits) { plan_limits.create!(plan_id: ultimate_trial_plan.id, ci_daily_pipeline_schedule_triggers: 0) }
+
+ context 'when the environment is dev or com' do
+ before do
+ allow(Gitlab).to receive(:dev_env_or_com?).and_return(true)
+ end
+
+ it 'sets the trial plan limits for ci_daily_pipeline_schedule_triggers' do
+ disable_migrations_output { migrate! }
+
+ expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
+ expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
+ end
+
+ it 'does not change the plan limits if the ultimate trial plan is missing' do
+ ultimate_trial_plan.destroy!
+
+ expect { disable_migrations_output { migrate! } }.not_to change { plan_limits.count }
+ expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
+ end
+
+ it 'does not change the plan limits if the ultimate trial plan limits is missing' do
+ ultimate_trial_plan_limits.destroy!
+
+ expect { disable_migrations_output { migrate! } }.not_to change { plan_limits.count }
+ expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
+ end
+
+ it 'does not change the plan limits if the premium trial plan is missing' do
+ premium_trial_plan.destroy!
+
+ expect { disable_migrations_output { migrate! } }.not_to change { plan_limits.count }
+ expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
+ end
+
+ it 'does not change the plan limits if the premium trial plan limits is missing' do
+ premium_trial_plan_limits.destroy!
+
+ expect { disable_migrations_output { migrate! } }.not_to change { plan_limits.count }
+ expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
+ end
+ end
+
+ context 'when the environment is anything other than dev or com' do
+ before do
+ allow(Gitlab).to receive(:dev_env_or_com?).and_return(false)
+ end
+
+ it 'does not update the plan limits' do
+ disable_migrations_output { migrate! }
+
+ expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
+ expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
+ end
+ end
+ end
+
+ describe '#down' do
+ let!(:premium_trial_plan_limits) { plan_limits.create!(plan_id: premium_trial_plan.id, ci_daily_pipeline_schedule_triggers: 288) }
+ let!(:ultimate_trial_plan_limits) { plan_limits.create!(plan_id: ultimate_trial_plan.id, ci_daily_pipeline_schedule_triggers: 288) }
+
+ context 'when the environment is dev or com' do
+ before do
+ allow(Gitlab).to receive(:dev_env_or_com?).and_return(true)
+ end
+
+ it 'sets the trial plan limits ci_daily_pipeline_schedule_triggers to zero' do
+ migrate_down!
+
+ expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
+ expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(0)
+ end
+
+ it 'does not change the plan limits if the ultimate trial plan is missing' do
+ ultimate_trial_plan.destroy!
+
+ expect { migrate_down! }.not_to change { plan_limits.count }
+ expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
+ end
+
+ it 'does not change the plan limits if the ultimate trial plan limits is missing' do
+ ultimate_trial_plan_limits.destroy!
+
+ expect { migrate_down! }.not_to change { plan_limits.count }
+ expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
+ end
+
+ it 'does not change the plan limits if the premium trial plan is missing' do
+ premium_trial_plan.destroy!
+
+ expect { migrate_down! }.not_to change { plan_limits.count }
+ expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
+ end
+
+ it 'does not change the plan limits if the premium trial plan limits is missing' do
+ premium_trial_plan_limits.destroy!
+
+ expect { migrate_down! }.not_to change { plan_limits.count }
+ expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
+ end
+ end
+
+ context 'when the environment is anything other than dev or com' do
+ before do
+ allow(Gitlab).to receive(:dev_env_or_com?).and_return(false)
+ end
+
+ it 'does not change the ultimate trial plan limits' do
+ migrate_down!
+
+ expect(ultimate_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
+ expect(premium_trial_plan_limits.reload.ci_daily_pipeline_schedule_triggers).to eq(288)
+ end
+ end
+ end
+
+ def migrate_down!
+ disable_migrations_output do
+ migrate!
+ described_class.new.down
+ end
+ end
+end
diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb
index fb1d157b360..35846b0d4ea 100644
--- a/spec/serializers/merge_request_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_widget_entity_spec.rb
@@ -58,7 +58,7 @@ RSpec.describe MergeRequestWidgetEntity do
data = described_class.new(resource, request: request, issues_links: true).as_json
expect(data).to include(:issues_links)
- expect(data[:issues_links]).to include(:assign_to_closing, :closing, :mentioned_but_not_closing)
+ expect(data[:issues_links]).to include(:assign_to_closing, :closing, :mentioned_but_not_closing, :closing_count, :mentioned_count)
end
it 'omits issue links by default' do
diff --git a/yarn.lock b/yarn.lock
index 319045af9d0..940b76ae245 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4568,10 +4568,10 @@ domhandler@^4.0.0, domhandler@^4.2.0:
dependencies:
domelementtype "^2.2.0"
-dompurify@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.0.tgz#07bb39515e491588e5756b1d3e8375b5964814e2"
- integrity sha512-VV5C6Kr53YVHGOBKO/F86OYX6/iLTw2yVSI721gKetxpHCK/V5TaLEf9ODjRgl1KLSWRMY6cUhAbv/c+IUnwQw==
+dompurify@^2.3.0, dompurify@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.1.tgz#a47059ca21fd1212d3c8f71fdea6943b8bfbdf6a"
+ integrity sha512-xGWt+NHAQS+4tpgbOAI08yxW0Pr256Gu/FNE2frZVTbgrBUn8M7tz7/ktS/LZ2MHeGqz6topj0/xY+y8R5FBFw==
domutils@^1.5.1:
version "1.7.0"