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-09-09 18:09:24 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-09 18:09:24 +0300
commita3596259bcca06bf4adcdb391d0ea3110fe7deff (patch)
treedeba3f6bbb1836133c4cafeb2ffe921d6bf3fed7
parent7ce86c261b3f910cf17b0b47a4200847578947df (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/batch_comments/components/review_bar.vue3
-rw-r--r--app/assets/javascripts/batch_comments/index.js13
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_bundle.js9
-rw-r--r--app/assets/javascripts/commit/pipelines/utils.js11
-rw-r--r--app/assets/javascripts/content_editor/content_editor.stories.js27
-rw-r--r--app/assets/javascripts/diffs/components/pre_renderer.vue1
-rw-r--r--app/assets/javascripts/diffs/index.js96
-rw-r--r--app/assets/javascripts/init_issuable_sidebar.js10
-rw-r--r--app/assets/javascripts/lib/utils/number_utils.js9
-rw-r--r--app/assets/javascripts/merge_request.js27
-rw-r--r--app/assets/javascripts/mr_notes/index.js36
-rw-r--r--app/assets/javascripts/pages/projects/issues/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js8
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/show/index.js11
-rw-r--r--app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue9
-rw-r--r--app/assets/javascripts/pipeline_editor/components/ui/pipeline_editor_empty_state.vue5
-rw-r--r--app/assets/javascripts/pipelines/components/parsing_utils.js52
-rw-r--r--app/assets/javascripts/pipelines/utils.js52
-rw-r--r--app/assets/javascripts/projects/storage_counter/components/app.vue79
-rw-r--r--app/assets/javascripts/projects/storage_counter/components/storage_table.vue74
-rw-r--r--app/assets/javascripts/projects/storage_counter/constants.js61
-rw-r--r--app/assets/javascripts/projects/storage_counter/index.js22
-rw-r--r--app/assets/javascripts/projects/storage_counter/utils.js49
-rw-r--r--app/assets/javascripts/reports/components/issue_body.js16
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js56
-rw-r--r--app/assets/javascripts/sidebar/sidebar_bundle.js6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/index.js4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue15
-rw-r--r--app/controllers/projects/ci/pipeline_editor_controller.rb1
-rw-r--r--app/controllers/projects/usage_quotas_controller.rb12
-rw-r--r--app/views/admin/application_settings/_ci_cd.html.haml2
-rw-r--r--app/views/projects/usage_quotas/index.html.haml8
-rw-r--r--config/feature_flags/development/pipeline_editor_branch_switcher.yml8
-rw-r--r--config/feature_flags/development/vuln_report_new_project_filter.yml4
-rw-r--r--config/initializers/database_config.rb2
-rw-r--r--doc/administration/geo/disaster_recovery/background_verification.md2
-rw-r--r--doc/administration/geo/index.md8
-rw-r--r--doc/administration/geo/replication/faq.md2
-rw-r--r--doc/administration/geo/replication/usage.md2
-rw-r--r--doc/administration/geo/setup/external_database.md2
-rw-r--r--doc/administration/maintenance_mode/index.md2
-rw-r--r--doc/administration/monitoring/gitlab_self_monitoring_project/index.md2
-rw-r--r--doc/administration/pages/index.md78
-rw-r--r--doc/api/dependency_proxy.md4
-rw-r--r--doc/api/deploy_keys.md4
-rw-r--r--doc/api/deploy_tokens.md4
-rw-r--r--doc/api/deployments.md2
-rw-r--r--doc/api/dora/metrics.md4
-rw-r--r--doc/api/dora4_project_analytics.md2
-rw-r--r--doc/api/feature_flag_specs.md2
-rw-r--r--doc/api/features.md2
-rw-r--r--doc/api/freeze_periods.md2
-rw-r--r--doc/api/group_protected_environments.md10
-rw-r--r--doc/api/releases/index.md6
-rw-r--r--doc/api/releases/links.md2
-rw-r--r--doc/ci/environments/protected_environments.md4
-rw-r--r--doc/ci/runners/build_cloud/macos_build_cloud.md3
-rw-r--r--doc/development/contributing/merge_request_workflow.md25
-rw-r--r--doc/development/documentation/feature_flags.md11
-rw-r--r--doc/development/documentation/styleguide/index.md6
-rw-r--r--doc/development/documentation/styleguide/word_list.md8
-rw-r--r--doc/public_access/public_access.md24
-rw-r--r--doc/topics/gitlab_flow.md14
-rw-r--r--doc/topics/img/gitlab_flow.pngbin46844 -> 0 bytes
-rw-r--r--doc/topics/img/gitlab_flow_ci_mr.pngbin12024 -> 0 bytes
-rw-r--r--doc/topics/img/gitlab_flow_close_issue_mr.pngbin42108 -> 0 bytes
-rw-r--r--doc/topics/img/gitlab_flow_git_pull.pngbin28701 -> 0 bytes
-rw-r--r--doc/topics/img/gitlab_flow_merge_commits.pngbin7564 -> 0 bytes
-rw-r--r--doc/topics/img/gitlab_flow_merge_request.pngbin47225 -> 0 bytes
-rw-r--r--doc/topics/img/gitlab_flow_messy_flow.pngbin11663 -> 0 bytes
-rw-r--r--doc/user/gitlab_com/index.md2
-rw-r--r--doc/user/permissions.md3
-rw-r--r--lib/gitlab/database.rb15
-rw-r--r--lib/gitlab/database/connection.rb22
-rw-r--r--lib/gitlab/database/load_balancing.rb70
-rw-r--r--lib/gitlab/database/load_balancing/configuration.rb79
-rw-r--r--lib/gitlab/database/load_balancing/host.rb12
-rw-r--r--lib/gitlab/database/load_balancing/load_balancer.rb15
-rw-r--r--locale/gitlab.pot45
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb2
-rw-r--r--spec/features/merge_request/batch_comments_spec.rb4
-rw-r--r--spec/features/projects/ci/editor_spec.rb4
-rw-r--r--spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js18
-rw-r--r--spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js13
-rw-r--r--spec/frontend/pipelines/__snapshots__/utils_spec.js.snap (renamed from spec/frontend/pipelines/__snapshots__/parsing_utils_spec.js.snap)0
-rw-r--r--spec/frontend/pipelines/utils_spec.js (renamed from spec/frontend/pipelines/parsing_utils_spec.js)2
-rw-r--r--spec/frontend/projects/storage_counter/app_spec.js83
-rw-r--r--spec/frontend/projects/storage_counter/components/app_spec.js150
-rw-r--r--spec/frontend/projects/storage_counter/components/storage_table_spec.js62
-rw-r--r--spec/frontend/projects/storage_counter/mock_data.js107
-rw-r--r--spec/frontend/projects/storage_counter/utils_spec.js17
-rw-r--r--spec/lib/gitlab/database/connection_spec.rb23
-rw-r--r--spec/lib/gitlab/database/load_balancing/configuration_spec.rb109
-rw-r--r--spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb5
-rw-r--r--spec/lib/gitlab/database/load_balancing/host_list_spec.rb7
-rw-r--r--spec/lib/gitlab/database/load_balancing/host_spec.rb7
-rw-r--r--spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb22
-rw-r--r--spec/lib/gitlab/database/load_balancing/primary_host_spec.rb7
-rw-r--r--spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb17
-rw-r--r--spec/lib/gitlab/database/load_balancing_spec.rb199
-rw-r--r--spec/lib/gitlab/database_spec.rb16
-rw-r--r--spec/requests/api/merge_requests_spec.rb2
-rw-r--r--spec/requests/api/users_spec.rb99
-rw-r--r--spec/requests/projects/usage_quotas_spec.rb10
-rw-r--r--spec/services/groups/group_links/create_service_spec.rb18
-rw-r--r--spec/support/database_load_balancing.rb5
-rw-r--r--storybook/config/preview.js10
-rw-r--r--storybook/package.json4
108 files changed, 1409 insertions, 914 deletions
diff --git a/app/assets/javascripts/batch_comments/components/review_bar.vue b/app/assets/javascripts/batch_comments/components/review_bar.vue
index 080a5543e53..158b5f45d1c 100644
--- a/app/assets/javascripts/batch_comments/components/review_bar.vue
+++ b/app/assets/javascripts/batch_comments/components/review_bar.vue
@@ -10,7 +10,6 @@ export default {
},
computed: {
...mapGetters(['isNotesFetched']),
- ...mapGetters('batchComments', ['draftsCount']),
},
watch: {
isNotesFetched() {
@@ -25,7 +24,7 @@ export default {
};
</script>
<template>
- <div v-show="draftsCount > 0">
+ <div>
<nav class="review-bar-component" data-testid="review_bar_component">
<div
class="review-bar-content d-flex gl-justify-content-end"
diff --git a/app/assets/javascripts/batch_comments/index.js b/app/assets/javascripts/batch_comments/index.js
index 9c763e70d63..65fd34dcb00 100644
--- a/app/assets/javascripts/batch_comments/index.js
+++ b/app/assets/javascripts/batch_comments/index.js
@@ -1,7 +1,6 @@
import Vue from 'vue';
-import { mapActions } from 'vuex';
+import { mapActions, mapGetters } from 'vuex';
import store from '~/mr_notes/stores';
-import ReviewBar from './components/review_bar.vue';
export const initReviewBar = () => {
const el = document.getElementById('js-review-bar');
@@ -10,6 +9,12 @@ export const initReviewBar = () => {
new Vue({
el,
store,
+ components: {
+ ReviewBar: () => import('./components/review_bar.vue'),
+ },
+ computed: {
+ ...mapGetters('batchComments', ['draftsCount']),
+ },
mounted() {
this.fetchDrafts();
},
@@ -17,7 +22,9 @@ export const initReviewBar = () => {
...mapActions('batchComments', ['fetchDrafts']),
},
render(createElement) {
- return createElement(ReviewBar);
+ if (this.draftsCount === 0) return null;
+
+ return createElement('review-bar');
},
});
};
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
index 8d88b682df2..2109aecdf03 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
+++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import { initPipelineCountListener } from './utils';
/**
* Used in:
@@ -12,13 +13,7 @@ export default () => {
if (pipelineTableViewEl) {
// Update MR and Commits tabs
- pipelineTableViewEl.addEventListener('update-pipelines-count', (event) => {
- if (event.detail.pipelineCount) {
- const badge = document.querySelector('.js-pipelines-mr-count');
-
- badge.textContent = event.detail.pipelineCount;
- }
- });
+ initPipelineCountListener(pipelineTableViewEl);
if (pipelineTableViewEl.dataset.disableInitialization === undefined) {
const table = new Vue({
diff --git a/app/assets/javascripts/commit/pipelines/utils.js b/app/assets/javascripts/commit/pipelines/utils.js
new file mode 100644
index 00000000000..52cbe52fa9b
--- /dev/null
+++ b/app/assets/javascripts/commit/pipelines/utils.js
@@ -0,0 +1,11 @@
+export function initPipelineCountListener(el) {
+ if (!el) return;
+
+ el.addEventListener('update-pipelines-count', (event) => {
+ if (event.detail.pipelineCount) {
+ const badge = document.querySelector('.js-pipelines-mr-count');
+
+ badge.textContent = event.detail.pipelineCount;
+ }
+ });
+}
diff --git a/app/assets/javascripts/content_editor/content_editor.stories.js b/app/assets/javascripts/content_editor/content_editor.stories.js
new file mode 100644
index 00000000000..8f2ce8feb5d
--- /dev/null
+++ b/app/assets/javascripts/content_editor/content_editor.stories.js
@@ -0,0 +1,27 @@
+import { ContentEditor } from './index';
+
+export default {
+ component: ContentEditor,
+ title: 'Components/Content Editor',
+};
+
+const Template = (_, { argTypes }) => ({
+ components: { ContentEditor },
+ props: Object.keys(argTypes),
+ template: '<content-editor v-bind="$props" @initialized="loadContent" />',
+ methods: {
+ loadContent(contentEditor) {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ contentEditor.setSerializedContent('Hello content editor');
+ },
+ },
+});
+
+export const Default = Template.bind({});
+
+Default.args = {
+ renderMarkdown: () => '<p>Hello content editor</p>',
+ uploadsPath: '/uploads/',
+ serializerConfig: {},
+ extensions: [],
+};
diff --git a/app/assets/javascripts/diffs/components/pre_renderer.vue b/app/assets/javascripts/diffs/components/pre_renderer.vue
index c357aa2d924..e4320c40d2c 100644
--- a/app/assets/javascripts/diffs/components/pre_renderer.vue
+++ b/app/assets/javascripts/diffs/components/pre_renderer.vue
@@ -17,7 +17,6 @@ export default {
},
mounted() {
this.width = this.$el.parentNode.offsetWidth;
- window.test = this;
this.$_itemsWithSizeWatcher = this.$watch('vscrollParent.itemsWithSize', async () => {
await this.$nextTick();
diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js
index bddc28c4758..1b1ab59b2b4 100644
--- a/app/assets/javascripts/diffs/index.js
+++ b/app/assets/javascripts/diffs/index.js
@@ -3,7 +3,6 @@ import Vue from 'vue';
import { mapActions, mapState, mapGetters } from 'vuex';
import { parseBoolean } from '~/lib/utils/common_utils';
import { getParameterValues } from '~/lib/utils/url_utility';
-import FindFile from '~/vue_shared/components/file_finder/index.vue';
import eventHub from '../notes/event_hub';
import diffsApp from './components/app.vue';
@@ -12,51 +11,7 @@ import { getReviewsForMergeRequest } from './utils/file_reviews';
import { getDerivedMergeRequestInformation } from './utils/merge_request';
export default function initDiffsApp(store) {
- const fileFinderEl = document.getElementById('js-diff-file-finder');
-
- if (fileFinderEl) {
- // eslint-disable-next-line no-new
- new Vue({
- el: fileFinderEl,
- store,
- computed: {
- ...mapState('diffs', ['fileFinderVisible', 'isLoading']),
- ...mapGetters('diffs', ['flatBlobsList']),
- },
- watch: {
- fileFinderVisible(newVal, oldVal) {
- if (newVal && !oldVal && !this.flatBlobsList.length) {
- eventHub.$emit('fetchDiffData');
- }
- },
- },
- methods: {
- ...mapActions('diffs', ['toggleFileFinder', 'scrollToFile']),
- openFile(file) {
- window.mrTabs.tabShown('diffs');
- this.scrollToFile(file.path);
- },
- },
- render(createElement) {
- return createElement(FindFile, {
- props: {
- files: this.flatBlobsList,
- visible: this.fileFinderVisible,
- loading: this.isLoading,
- showDiffStats: true,
- clearSearchOnClose: false,
- },
- on: {
- toggle: this.toggleFileFinder,
- click: this.openFile,
- },
- class: ['diff-file-finder'],
- });
- },
- });
- }
-
- return new Vue({
+ const vm = new Vue({
el: '#js-diffs-app',
name: 'MergeRequestDiffs',
components: {
@@ -157,4 +112,53 @@ export default function initDiffsApp(store) {
});
},
});
+
+ const fileFinderEl = document.getElementById('js-diff-file-finder');
+
+ if (fileFinderEl) {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: fileFinderEl,
+ store,
+ components: {
+ FindFile: () => import('~/vue_shared/components/file_finder/index.vue'),
+ },
+ computed: {
+ ...mapState('diffs', ['fileFinderVisible', 'isLoading']),
+ ...mapGetters('diffs', ['flatBlobsList']),
+ },
+ watch: {
+ fileFinderVisible(newVal, oldVal) {
+ if (newVal && !oldVal && !this.flatBlobsList.length) {
+ eventHub.$emit('fetchDiffData');
+ }
+ },
+ },
+ methods: {
+ ...mapActions('diffs', ['toggleFileFinder', 'scrollToFile']),
+ openFile(file) {
+ window.mrTabs.tabShown('diffs');
+ this.scrollToFile(file.path);
+ },
+ },
+ render(createElement) {
+ return createElement('find-file', {
+ props: {
+ files: this.flatBlobsList,
+ visible: this.fileFinderVisible,
+ loading: this.isLoading,
+ showDiffStats: true,
+ clearSearchOnClose: false,
+ },
+ on: {
+ toggle: this.toggleFileFinder,
+ click: this.openFile,
+ },
+ class: ['diff-file-finder'],
+ });
+ },
+ });
+ }
+
+ return vm;
}
diff --git a/app/assets/javascripts/init_issuable_sidebar.js b/app/assets/javascripts/init_issuable_sidebar.js
index 17c73fdf1c3..7a70d893008 100644
--- a/app/assets/javascripts/init_issuable_sidebar.js
+++ b/app/assets/javascripts/init_issuable_sidebar.js
@@ -1,9 +1,7 @@
/* eslint-disable no-new */
-import { mountSidebarLabels, getSidebarOptions } from '~/sidebar/mount_sidebar';
+import { getSidebarOptions } from '~/sidebar/mount_sidebar';
import IssuableContext from './issuable_context';
-import LabelsSelect from './labels_select';
-import MilestoneSelect from './milestone_select';
import Sidebar from './right_sidebar';
export default () => {
@@ -13,12 +11,6 @@ export default () => {
const sidebarOptions = getSidebarOptions(sidebarOptEl);
- new MilestoneSelect({
- full_path: sidebarOptions.fullPath,
- });
- new LabelsSelect();
new IssuableContext(sidebarOptions.currentUser);
Sidebar.initialize();
-
- mountSidebarLabels();
};
diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js
index f3dedb7726a..f46263c0e4d 100644
--- a/app/assets/javascripts/lib/utils/number_utils.js
+++ b/app/assets/javascripts/lib/utils/number_utils.js
@@ -69,19 +69,20 @@ export function bytesToGiB(number) {
* representation (e.g., giving it 1500 yields 1.5 KB).
*
* @param {Number} size
+ * @param {Number} digits - The number of digits to appear after the decimal point
* @returns {String}
*/
-export function numberToHumanSize(size) {
+export function numberToHumanSize(size, digits = 2) {
const abs = Math.abs(size);
if (abs < BYTES_IN_KIB) {
return sprintf(__('%{size} bytes'), { size });
} else if (abs < BYTES_IN_KIB ** 2) {
- return sprintf(__('%{size} KiB'), { size: bytesToKiB(size).toFixed(2) });
+ return sprintf(__('%{size} KiB'), { size: bytesToKiB(size).toFixed(digits) });
} else if (abs < BYTES_IN_KIB ** 3) {
- return sprintf(__('%{size} MiB'), { size: bytesToMiB(size).toFixed(2) });
+ return sprintf(__('%{size} MiB'), { size: bytesToMiB(size).toFixed(digits) });
}
- return sprintf(__('%{size} GiB'), { size: bytesToGiB(size).toFixed(2) });
+ return sprintf(__('%{size} GiB'), { size: bytesToGiB(size).toFixed(digits) });
}
/**
diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js
index 0ddb2c2334c..e89b886df83 100644
--- a/app/assets/javascripts/merge_request.js
+++ b/app/assets/javascripts/merge_request.js
@@ -19,11 +19,9 @@ function MergeRequest(opts) {
this.opts = opts != null ? opts : {};
this.submitNoteForm = this.submitNoteForm.bind(this);
this.$el = $('.merge-request');
- this.$('.show-all-commits').on('click', () => this.showAllCommits());
this.initTabs();
this.initMRBtnListeners();
- this.initCommitMessageListeners();
if ($('.description.js-task-list-container').length) {
this.taskList = new TaskList({
@@ -59,11 +57,6 @@ MergeRequest.prototype.initTabs = function () {
window.mrTabs = new MergeRequestTabs(this.opts);
};
-MergeRequest.prototype.showAllCommits = function () {
- this.$('.first-commits').remove();
- return this.$('.all-commits').removeClass('hide');
-};
-
MergeRequest.prototype.initMRBtnListeners = function () {
const _this = this;
const draftToggles = document.querySelectorAll('.js-draft-toggle-button');
@@ -128,26 +121,6 @@ MergeRequest.prototype.submitNoteForm = function (form, $button) {
}
};
-MergeRequest.prototype.initCommitMessageListeners = function () {
- $(document).on('click', 'a.js-with-description-link', (e) => {
- const textarea = $('textarea.js-commit-message');
- e.preventDefault();
-
- textarea.val(textarea.data('messageWithDescription'));
- $('.js-with-description-hint').hide();
- $('.js-without-description-hint').show();
- });
-
- $(document).on('click', 'a.js-without-description-link', (e) => {
- const textarea = $('textarea.js-commit-message');
- e.preventDefault();
-
- textarea.val(textarea.data('messageWithoutDescription'));
- $('.js-with-description-hint').show();
- $('.js-without-description-hint').hide();
- });
-};
-
MergeRequest.decreaseCounter = function (by = 1) {
const $el = $('.js-merge-counter');
const count = Math.max(parseInt($el.text().replace(/[^\d]/, ''), 10) - by, 0);
diff --git a/app/assets/javascripts/mr_notes/index.js b/app/assets/javascripts/mr_notes/index.js
index a7696a716d0..ea3e4e5604c 100644
--- a/app/assets/javascripts/mr_notes/index.js
+++ b/app/assets/javascripts/mr_notes/index.js
@@ -19,6 +19,7 @@ export default function initMrNotes() {
action: mrShowNode.dataset.mrAction,
});
+ initDiffsApp(store);
initNotesApp();
document.addEventListener('merged:UpdateActions', () => {
@@ -26,20 +27,25 @@ export default function initMrNotes() {
initCherryPickCommitModal();
});
- // eslint-disable-next-line no-new
- new Vue({
- el: '#js-vue-discussion-counter',
- name: 'DiscussionCounter',
- components: {
- discussionCounter,
- },
- store,
- render(createElement) {
- return createElement('discussion-counter');
- },
- });
+ requestIdleCallback(() => {
+ const el = document.getElementById('js-vue-discussion-counter');
- initDiscussionFilters(store);
- initSortDiscussions(store);
- initDiffsApp(store);
+ if (el) {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ name: 'DiscussionCounter',
+ components: {
+ discussionCounter,
+ },
+ store,
+ render(createElement) {
+ return createElement('discussion-counter');
+ },
+ });
+ }
+
+ initDiscussionFilters(store);
+ initSortDiscussions(store);
+ });
}
diff --git a/app/assets/javascripts/pages/projects/issues/show/index.js b/app/assets/javascripts/pages/projects/issues/show/index.js
index e4f99d1e7fd..1282d2aa303 100644
--- a/app/assets/javascripts/pages/projects/issues/show/index.js
+++ b/app/assets/javascripts/pages/projects/issues/show/index.js
@@ -1,7 +1,8 @@
+import { store } from '~/notes/stores';
import initRelatedIssues from '~/related_issues';
import initSidebarBundle from '~/sidebar/sidebar_bundle';
import initShow from '../show';
initShow();
-initSidebarBundle();
+initSidebarBundle(store);
initRelatedIssues();
diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
index 25864149378..dadf0988582 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
@@ -2,11 +2,10 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import loadAwardsHandler from '~/awards_handler';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
-import initPipelines from '~/commit/pipelines/pipelines_bundle';
+import { initPipelineCountListener } from '~/commit/pipelines/utils';
import initIssuableSidebar from '~/init_issuable_sidebar';
import StatusBox from '~/issuable/components/status_box.vue';
import createDefaultClient from '~/lib/graphql';
-import { handleLocationHash } from '~/lib/utils/common_utils';
import initSourcegraph from '~/sourcegraph';
import ZenMode from '~/zen_mode';
import getStateQuery from './queries/get_state.query.graphql';
@@ -15,11 +14,10 @@ export default function initMergeRequestShow() {
const awardEmojiEl = document.getElementById('js-vue-awards-block');
new ZenMode(); // eslint-disable-line no-new
- initIssuableSidebar();
- initPipelines();
+ initPipelineCountListener(document.querySelector('#commit-pipeline-table-view'));
new ShortcutsIssuable(true); // eslint-disable-line no-new
- handleLocationHash();
initSourcegraph();
+ initIssuableSidebar();
if (awardEmojiEl) {
import('~/emoji/awards_app')
.then((m) => m.default(awardEmojiEl))
diff --git a/app/assets/javascripts/pages/projects/merge_requests/show/index.js b/app/assets/javascripts/pages/projects/merge_requests/show/index.js
index 546fa66eda6..25dede33880 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/show/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/show/index.js
@@ -5,8 +5,11 @@ import initSidebarBundle from '~/sidebar/sidebar_bundle';
import initIssuableHeaderWarning from '~/vue_shared/components/issuable/init_issuable_header_warning';
import initShow from '../init_merge_request_show';
-initShow();
-initSidebarBundle();
initMrNotes();
-initReviewBar();
-initIssuableHeaderWarning(store);
+initShow();
+
+requestIdleCallback(() => {
+ initSidebarBundle(store);
+ initReviewBar();
+ initIssuableHeaderWarning(store);
+});
diff --git a/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue b/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
index ebe73bdcec3..551a0430fbf 100644
--- a/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
+++ b/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
@@ -1,21 +1,14 @@
<script>
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import BranchSwitcher from './branch_switcher.vue';
export default {
components: {
BranchSwitcher,
},
- mixins: [glFeatureFlagsMixin()],
- computed: {
- showBranchSwitcher() {
- return this.glFeatures.pipelineEditorBranchSwitcher;
- },
- },
};
</script>
<template>
<div class="gl-mb-4">
- <branch-switcher v-if="showBranchSwitcher" v-on="$listeners" />
+ <branch-switcher v-on="$listeners" />
</div>
</template>
diff --git a/app/assets/javascripts/pipeline_editor/components/ui/pipeline_editor_empty_state.vue b/app/assets/javascripts/pipeline_editor/components/ui/pipeline_editor_empty_state.vue
index 0ac4a40ff4a..fbb66231f16 100644
--- a/app/assets/javascripts/pipeline_editor/components/ui/pipeline_editor_empty_state.vue
+++ b/app/assets/javascripts/pipeline_editor/components/ui/pipeline_editor_empty_state.vue
@@ -24,9 +24,6 @@ export default {
},
},
computed: {
- showFileNav() {
- return this.glFeatures.pipelineEditorBranchSwitcher;
- },
showCTAButton() {
return this.glFeatures.pipelineEditorEmptyStateAction;
},
@@ -40,7 +37,7 @@ export default {
</script>
<template>
<div>
- <pipeline-editor-file-nav v-if="showFileNav" v-on="$listeners" />
+ <pipeline-editor-file-nav v-on="$listeners" />
<div class="gl-display-flex gl-flex-direction-column gl-align-items-center gl-mt-11">
<img :src="emptyStateIllustrationPath" />
<h1 class="gl-font-size-h1">{{ $options.i18n.title }}</h1>
diff --git a/app/assets/javascripts/pipelines/components/parsing_utils.js b/app/assets/javascripts/pipelines/components/parsing_utils.js
index 48658c7ffe0..fa7330ce890 100644
--- a/app/assets/javascripts/pipelines/components/parsing_utils.js
+++ b/app/assets/javascripts/pipelines/components/parsing_utils.js
@@ -1,58 +1,8 @@
import { memoize } from 'lodash';
+import { createNodeDict } from '../utils';
import { createSankey } from './dag/drawing_utils';
/*
- The following functions are the main engine in transforming the data as
- received from the endpoint into the format the d3 graph expects.
-
- Input is of the form:
- [nodes]
- nodes: [{category, name, jobs, size}]
- category is the stage name
- name is a group name; in the case that the group has one job, it is
- also the job name
- size is the number of parallel jobs
- jobs: [{ name, needs}]
- job name is either the same as the group name or group x/y
- needs: [job-names]
- needs is an array of job-name strings
-
- Output is of the form:
- { nodes: [node], links: [link] }
- node: { name, category }, + unused info passed through
- link: { source, target, value }, with source & target being node names
- and value being a constant
-
- We create nodes in the GraphQL update function, and then here we create the node dictionary,
- then create links, and then dedupe the links, so that in the case where
- job 4 depends on job 1 and job 2, and job 2 depends on job 1, we show only a single link
- from job 1 to job 2 then another from job 2 to job 4.
-
- CREATE LINKS
- nodes.name -> target
- nodes.name.needs.each -> source (source is the name of the group, not the parallel job)
- 10 -> value (constant)
- */
-
-export const createNodeDict = (nodes) => {
- return nodes.reduce((acc, node) => {
- const newNode = {
- ...node,
- needs: node.jobs.map((job) => job.needs || []).flat(),
- };
-
- if (node.size > 1) {
- node.jobs.forEach((job) => {
- acc[job.name] = newNode;
- });
- }
-
- acc[node.name] = newNode;
- return acc;
- }, {});
-};
-
-/*
A peformant alternative to lodash's isEqual. Because findIndex always finds
the first instance of a match, if the found index is not the first, we know
it is in fact a duplicate.
diff --git a/app/assets/javascripts/pipelines/utils.js b/app/assets/javascripts/pipelines/utils.js
index 02a9e5b7fc6..e28eb74fb1b 100644
--- a/app/assets/javascripts/pipelines/utils.js
+++ b/app/assets/javascripts/pipelines/utils.js
@@ -1,8 +1,58 @@
import * as Sentry from '@sentry/browser';
import { pickBy } from 'lodash';
-import { createNodeDict } from './components/parsing_utils';
import { SUPPORTED_FILTER_PARAMETERS } from './constants';
+/*
+ The following functions are the main engine in transforming the data as
+ received from the endpoint into the format the d3 graph expects.
+
+ Input is of the form:
+ [nodes]
+ nodes: [{category, name, jobs, size}]
+ category is the stage name
+ name is a group name; in the case that the group has one job, it is
+ also the job name
+ size is the number of parallel jobs
+ jobs: [{ name, needs}]
+ job name is either the same as the group name or group x/y
+ needs: [job-names]
+ needs is an array of job-name strings
+
+ Output is of the form:
+ { nodes: [node], links: [link] }
+ node: { name, category }, + unused info passed through
+ link: { source, target, value }, with source & target being node names
+ and value being a constant
+
+ We create nodes in the GraphQL update function, and then here we create the node dictionary,
+ then create links, and then dedupe the links, so that in the case where
+ job 4 depends on job 1 and job 2, and job 2 depends on job 1, we show only a single link
+ from job 1 to job 2 then another from job 2 to job 4.
+
+ CREATE LINKS
+ nodes.name -> target
+ nodes.name.needs.each -> source (source is the name of the group, not the parallel job)
+ 10 -> value (constant)
+ */
+
+export const createNodeDict = (nodes) => {
+ return nodes.reduce((acc, node) => {
+ const newNode = {
+ ...node,
+ needs: node.jobs.map((job) => job.needs || []).flat(),
+ };
+
+ if (node.size > 1) {
+ node.jobs.forEach((job) => {
+ acc[job.name] = newNode;
+ });
+ }
+
+ acc[node.name] = newNode;
+ return acc;
+ }, {});
+};
+
export const validateParams = (params) => {
return pickBy(params, (val, key) => SUPPORTED_FILTER_PARAMETERS.includes(key) && val);
};
diff --git a/app/assets/javascripts/projects/storage_counter/components/app.vue b/app/assets/javascripts/projects/storage_counter/components/app.vue
index cfb08c11f0e..1a911ea3d9b 100644
--- a/app/assets/javascripts/projects/storage_counter/components/app.vue
+++ b/app/assets/javascripts/projects/storage_counter/components/app.vue
@@ -1,17 +1,30 @@
<script>
-import { GlAlert } from '@gitlab/ui';
-import { s__ } from '~/locale';
+import { GlAlert, GlLink, GlLoadingIcon } from '@gitlab/ui';
+import { sprintf } from '~/locale';
import UsageGraph from '~/vue_shared/components/storage_counter/usage_graph.vue';
+import {
+ ERROR_MESSAGE,
+ LEARN_MORE_LABEL,
+ USAGE_QUOTAS_LABEL,
+ TOTAL_USAGE_TITLE,
+ TOTAL_USAGE_SUBTITLE,
+ TOTAL_USAGE_DEFAULT_TEXT,
+ HELP_LINK_ARIA_LABEL,
+} from '../constants';
import getProjectStorageCount from '../queries/project_storage.query.graphql';
import { parseGetProjectStorageResults } from '../utils';
+import StorageTable from './storage_table.vue';
export default {
name: 'StorageCounterApp',
components: {
GlAlert,
+ GlLink,
+ GlLoadingIcon,
+ StorageTable,
UsageGraph,
},
- inject: ['projectPath'],
+ inject: ['projectPath', 'helpLinks'],
apollo: {
project: {
query: getProjectStorageCount,
@@ -20,11 +33,11 @@ export default {
fullPath: this.projectPath,
};
},
- update: parseGetProjectStorageResults,
+ update(data) {
+ return parseGetProjectStorageResults(data, this.helpLinks);
+ },
error() {
- this.error = s__(
- 'UsageQuota|Something went wrong while fetching project storage statistics',
- );
+ this.error = ERROR_MESSAGE;
},
},
},
@@ -34,24 +47,60 @@ export default {
error: '',
};
},
+ computed: {
+ totalUsage() {
+ return this.project?.storage?.totalUsage || TOTAL_USAGE_DEFAULT_TEXT;
+ },
+ storageTypes() {
+ return this.project?.storage?.storageTypes || [];
+ },
+ },
methods: {
clearError() {
this.error = '';
},
+ helpLinkAriaLabel(linkTitle) {
+ return sprintf(HELP_LINK_ARIA_LABEL, {
+ linkTitle,
+ });
+ },
},
- i18n: {
- placeholder: s__('UsageQuota|Usage'),
- },
+ LEARN_MORE_LABEL,
+ USAGE_QUOTAS_LABEL,
+ TOTAL_USAGE_TITLE,
+ TOTAL_USAGE_SUBTITLE,
};
</script>
<template>
- <div>
- <gl-alert v-if="error" variant="danger" @dismiss="clearError">
- {{ error }}
- </gl-alert>
- <div v-else>{{ $options.i18n.placeholder }}</div>
+ <gl-loading-icon v-if="$apollo.queries.project.loading" class="gl-mt-5" size="md" />
+ <gl-alert v-else-if="error" variant="danger" @dismiss="clearError">
+ {{ error }}
+ </gl-alert>
+ <div v-else>
+ <div class="gl-pt-5 gl-px-3">
+ <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
+ <div>
+ <p class="gl-m-0 gl-font-lg gl-font-weight-bold">{{ $options.TOTAL_USAGE_TITLE }}</p>
+ <p class="gl-m-0 gl-text-gray-400">
+ {{ $options.TOTAL_USAGE_SUBTITLE }}
+ <gl-link
+ :href="helpLinks.usageQuotasHelpPagePath"
+ target="_blank"
+ :aria-label="helpLinkAriaLabel($options.USAGE_QUOTAS_LABEL)"
+ data-testid="usage-quotas-help-link"
+ >
+ {{ $options.LEARN_MORE_LABEL }}
+ </gl-link>
+ </p>
+ </div>
+ <p class="gl-m-0 gl-font-size-h-display gl-font-weight-bold" data-testid="total-usage">
+ {{ totalUsage }}
+ </p>
+ </div>
+ </div>
<div v-if="project.statistics" class="gl-w-full">
<usage-graph :root-storage-statistics="project.statistics" :limit="0" />
</div>
+ <storage-table :storage-types="storageTypes" />
</div>
</template>
diff --git a/app/assets/javascripts/projects/storage_counter/components/storage_table.vue b/app/assets/javascripts/projects/storage_counter/components/storage_table.vue
new file mode 100644
index 00000000000..50aa70ecc9d
--- /dev/null
+++ b/app/assets/javascripts/projects/storage_counter/components/storage_table.vue
@@ -0,0 +1,74 @@
+<script>
+import { GlLink, GlIcon, GlTable, GlSprintf } from '@gitlab/ui';
+import { thWidthClass } from '~/lib/utils/table_utility';
+import { sprintf } from '~/locale';
+import { PROJECT_TABLE_LABELS, HELP_LINK_ARIA_LABEL } from '../constants';
+
+export default {
+ name: 'StorageTable',
+ components: {
+ GlLink,
+ GlIcon,
+ GlTable,
+ GlSprintf,
+ },
+ props: {
+ storageTypes: {
+ type: Array,
+ required: true,
+ },
+ },
+ methods: {
+ helpLinkAriaLabel(linkTitle) {
+ return sprintf(HELP_LINK_ARIA_LABEL, {
+ linkTitle,
+ });
+ },
+ },
+ projectTableFields: [
+ {
+ key: 'storageType',
+ label: PROJECT_TABLE_LABELS.STORAGE_TYPE,
+ thClass: thWidthClass(90),
+ sortable: true,
+ },
+ {
+ key: 'value',
+ label: PROJECT_TABLE_LABELS.VALUE,
+ thClass: thWidthClass(10),
+ sortable: true,
+ },
+ ],
+};
+</script>
+<template>
+ <gl-table :items="storageTypes" :fields="$options.projectTableFields">
+ <template #cell(storageType)="{ item }">
+ <p class="gl-font-weight-bold gl-mb-0" :data-testid="`${item.storageType.id}-name`">
+ {{ item.storageType.name }}
+ <gl-link
+ v-if="item.storageType.helpPath"
+ :href="item.storageType.helpPath"
+ target="_blank"
+ :aria-label="helpLinkAriaLabel(item.storageType.name)"
+ :data-testid="`${item.storageType.id}-help-link`"
+ >
+ <gl-icon name="question" :size="12" />
+ </gl-link>
+ </p>
+ <p class="gl-mb-0" :data-testid="`${item.storageType.id}-description`">
+ {{ item.storageType.description }}
+ </p>
+ <p v-if="item.storageType.warningMessage" class="gl-mb-0 gl-font-sm">
+ <gl-icon name="warning" :size="12" />
+ <gl-sprintf :message="item.storageType.warningMessage">
+ <template #warningLink="{ content }">
+ <gl-link :href="item.storageType.warningLink" target="_blank" class="gl-font-sm">{{
+ content
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </template>
+ </gl-table>
+</template>
diff --git a/app/assets/javascripts/projects/storage_counter/constants.js b/app/assets/javascripts/projects/storage_counter/constants.js
new file mode 100644
index 00000000000..d9b28abfbe7
--- /dev/null
+++ b/app/assets/javascripts/projects/storage_counter/constants.js
@@ -0,0 +1,61 @@
+import { s__, __ } from '~/locale';
+
+export const PROJECT_STORAGE_TYPES = [
+ {
+ id: 'buildArtifactsSize',
+ name: s__('UsageQuota|Artifacts'),
+ description: s__('UsageQuota|Pipeline artifacts and job artifacts, created with CI/CD.'),
+ warningMessage: s__(
+ 'UsageQuota|There is a known issue with Artifact storage where the total could be incorrect for some projects. More details and progress are available in %{warningLinkStart}the epic%{warningLinkEnd}.',
+ ),
+ warningLink: 'https://gitlab.com/groups/gitlab-org/-/epics/5380',
+ },
+ {
+ id: 'lfsObjectsSize',
+ name: s__('UsageQuota|LFS Storage'),
+ description: s__('UsageQuota|Audio samples, videos, datasets, and graphics.'),
+ },
+ {
+ id: 'packagesSize',
+ name: s__('UsageQuota|Packages'),
+ description: s__('UsageQuota|Code packages and container images.'),
+ },
+ {
+ id: 'repositorySize',
+ name: s__('UsageQuota|Repository'),
+ description: s__('UsageQuota|Git repository, managed by the Gitaly service.'),
+ },
+ {
+ id: 'snippetsSize',
+ name: s__('UsageQuota|Snippets'),
+ description: s__('UsageQuota|Shared bits of code and text.'),
+ },
+ {
+ id: 'uploadsSize',
+ name: s__('UsageQuota|Uploads'),
+ description: s__('UsageQuota|File attachments and smaller design graphics.'),
+ },
+ {
+ id: 'wikiSize',
+ name: s__('UsageQuota|Wiki'),
+ description: s__('UsageQuota|Wiki content.'),
+ },
+];
+
+export const PROJECT_TABLE_LABELS = {
+ STORAGE_TYPE: s__('UsageQuota|Storage type'),
+ VALUE: s__('UsageQuota|Usage'),
+};
+
+export const ERROR_MESSAGE = s__(
+ 'UsageQuota|Something went wrong while fetching project storage statistics',
+);
+
+export const LEARN_MORE_LABEL = s__('Learn more.');
+export const USAGE_QUOTAS_LABEL = s__('UsageQuota|Usage Quotas');
+export const HELP_LINK_ARIA_LABEL = s__('UsageQuota|%{linkTitle} help link');
+export const TOTAL_USAGE_DEFAULT_TEXT = __('N/A');
+export const TOTAL_USAGE_TITLE = s__('UsageQuota|Usage Breakdown');
+export const TOTAL_USAGE_SUBTITLE = s__(
+ 'UsageQuota|Includes project registry, artifacts, packages, wiki, uploads and other items.',
+);
diff --git a/app/assets/javascripts/projects/storage_counter/index.js b/app/assets/javascripts/projects/storage_counter/index.js
index 8812bfb56a2..10668f08402 100644
--- a/app/assets/javascripts/projects/storage_counter/index.js
+++ b/app/assets/javascripts/projects/storage_counter/index.js
@@ -12,7 +12,17 @@ export default (containerId = 'js-project-storage-count-app') => {
return false;
}
- const { projectPath } = el.dataset;
+ const {
+ projectPath,
+ usageQuotasHelpPagePath,
+ buildArtifactsHelpPagePath,
+ lfsObjectsHelpPagePath,
+ packagesHelpPagePath,
+ repositoryHelpPagePath,
+ snippetsHelpPagePath,
+ uploadsHelpPagePath,
+ wikiHelpPagePath,
+ } = el.dataset;
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient({}, { assumeImmutableResults: true }),
@@ -23,6 +33,16 @@ export default (containerId = 'js-project-storage-count-app') => {
apolloProvider,
provide: {
projectPath,
+ helpLinks: {
+ usageQuotasHelpPagePath,
+ buildArtifactsHelpPagePath,
+ lfsObjectsHelpPagePath,
+ packagesHelpPagePath,
+ repositoryHelpPagePath,
+ snippetsHelpPagePath,
+ uploadsHelpPagePath,
+ wikiHelpPagePath,
+ },
},
render(createElement) {
return createElement(StorageCounterApp);
diff --git a/app/assets/javascripts/projects/storage_counter/utils.js b/app/assets/javascripts/projects/storage_counter/utils.js
index cfc5f14b26a..7b7182cbbf0 100644
--- a/app/assets/javascripts/projects/storage_counter/utils.js
+++ b/app/assets/javascripts/projects/storage_counter/utils.js
@@ -1,36 +1,5 @@
import { numberToHumanSize } from '~/lib/utils/number_utils';
-import { s__ } from '~/locale';
-
-const projectStorageTypes = [
- {
- id: 'buildArtifactsSize',
- name: s__('UsageQuota|Artifacts'),
- },
- {
- id: 'lfsObjectsSize',
- name: s__('UsageQuota|LFS Storage'),
- },
- {
- id: 'packagesSize',
- name: s__('UsageQuota|Packages'),
- },
- {
- id: 'repositorySize',
- name: s__('UsageQuota|Repository'),
- },
- {
- id: 'snippetsSize',
- name: s__('UsageQuota|Snippets'),
- },
- {
- id: 'uploadsSize',
- name: s__('UsageQuota|Uploads'),
- },
- {
- id: 'wikiSize',
- name: s__('UsageQuota|Wiki'),
- },
-];
+import { PROJECT_STORAGE_TYPES } from './constants';
/**
* This method parses the results from `getProjectStorageCount` call.
@@ -38,26 +7,32 @@ const projectStorageTypes = [
* @param {Object} data graphql result
* @returns {Object}
*/
-export const parseGetProjectStorageResults = (data) => {
+export const parseGetProjectStorageResults = (data, helpLinks) => {
const projectStatistics = data?.project?.statistics;
if (!projectStatistics) {
return {};
}
const { storageSize, ...storageStatistics } = projectStatistics;
- const storageTypes = projectStorageTypes.reduce((types, currentType) => {
+ const storageTypes = PROJECT_STORAGE_TYPES.reduce((types, currentType) => {
if (!storageStatistics[currentType.id]) {
return types;
}
+ const helpPathKey = currentType.id.replace(`Size`, `HelpPagePath`);
+ const helpPath = helpLinks[helpPathKey];
+
return types.concat({
- ...currentType,
- value: numberToHumanSize(storageStatistics[currentType.id]),
+ storageType: {
+ ...currentType,
+ helpPath,
+ },
+ value: numberToHumanSize(storageStatistics[currentType.id], 1),
});
}, []);
return {
storage: {
- totalUsage: numberToHumanSize(storageSize),
+ totalUsage: numberToHumanSize(storageSize, 1),
storageTypes,
},
statistics: projectStatistics,
diff --git a/app/assets/javascripts/reports/components/issue_body.js b/app/assets/javascripts/reports/components/issue_body.js
index 6014d9d6ad8..04e72809e62 100644
--- a/app/assets/javascripts/reports/components/issue_body.js
+++ b/app/assets/javascripts/reports/components/issue_body.js
@@ -1,18 +1,16 @@
import IssueStatusIcon from '~/reports/components/issue_status_icon.vue';
-import AccessibilityIssueBody from '../accessibility_report/components/accessibility_issue_body.vue';
-import CodequalityIssueBody from '../codequality_report/components/codequality_issue_body.vue';
-import TestIssueBody from '../grouped_test_report/components/test_issue_body.vue';
export const components = {
- AccessibilityIssueBody,
- CodequalityIssueBody,
- TestIssueBody,
+ AccessibilityIssueBody: () =>
+ import('../accessibility_report/components/accessibility_issue_body.vue'),
+ CodequalityIssueBody: () => import('../codequality_report/components/codequality_issue_body.vue'),
+ TestIssueBody: () => import('../grouped_test_report/components/test_issue_body.vue'),
};
export const componentNames = {
- AccessibilityIssueBody: AccessibilityIssueBody.name,
- CodequalityIssueBody: CodequalityIssueBody.name,
- TestIssueBody: TestIssueBody.name,
+ AccessibilityIssueBody: 'AccessibilityIssueBody',
+ CodequalityIssueBody: 'CodequalityIssueBody',
+ TestIssueBody: 'TestIssueBody',
};
export const iconComponents = {
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 12d9d9ab222..10ab80f4ec2 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -1,7 +1,6 @@
import $ from 'jquery';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
-import createFlash from '~/flash';
import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
@@ -13,7 +12,6 @@ import {
isInIncidentPage,
parseBoolean,
} from '~/lib/utils/common_utils';
-import { __ } from '~/locale';
import CollapsedAssigneeList from '~/sidebar/components/assignees/collapsed_assignee_list.vue';
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
@@ -363,10 +361,10 @@ function mountReferenceComponent() {
});
}
-function mountLockComponent() {
+function mountLockComponent(store) {
const el = document.getElementById('js-lock-entry-point');
- if (!el) {
+ if (!el || !store) {
return;
}
@@ -375,37 +373,20 @@ function mountLockComponent() {
const dataNode = document.getElementById('js-lock-issue-data');
const initialData = JSON.parse(dataNode.innerHTML);
- let importStore;
- if (isInIssuePage() || isInIncidentPage()) {
- importStore = import(/* webpackChunkName: 'notesStore' */ '~/notes/stores').then(
- ({ store }) => store,
- );
- } else {
- importStore = import(/* webpackChunkName: 'mrNotesStore' */ '~/mr_notes/stores').then(
- (store) => store.default,
- );
- }
-
- importStore
- .then(
- (store) =>
- new Vue({
- el,
- store,
- provide: {
- fullPath,
- },
- render: (createElement) =>
- createElement(IssuableLockForm, {
- props: {
- isEditable: initialData.is_editable,
- },
- }),
- }),
- )
- .catch(() => {
- createFlash({ message: __('Failed to load sidebar lock status') });
- });
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ store,
+ provide: {
+ fullPath,
+ },
+ render: (createElement) =>
+ createElement(IssuableLockForm, {
+ props: {
+ isEditable: initialData.is_editable,
+ },
+ }),
+ });
}
function mountParticipantsComponent() {
@@ -537,7 +518,7 @@ function mountCopyEmailComponent() {
const isAssigneesWidgetShown =
(isInIssuePage() || isInDesignPage()) && gon.features.issueAssigneesWidget;
-export function mountSidebar(mediator) {
+export function mountSidebar(mediator, store) {
initInviteMembersModal();
initInviteMembersTrigger();
@@ -548,11 +529,12 @@ export function mountSidebar(mediator) {
mountAssigneesComponentDeprecated(mediator);
}
mountReviewersComponent(mediator);
+ mountSidebarLabels();
mountMilestoneSelect();
mountConfidentialComponent(mediator);
mountDueDateComponent(mediator);
mountReferenceComponent(mediator);
- mountLockComponent();
+ mountLockComponent(store);
mountParticipantsComponent();
mountSubscriptionsComponent();
mountCopyEmailComponent();
diff --git a/app/assets/javascripts/sidebar/sidebar_bundle.js b/app/assets/javascripts/sidebar/sidebar_bundle.js
index 063e3313a3c..1be670f7590 100644
--- a/app/assets/javascripts/sidebar/sidebar_bundle.js
+++ b/app/assets/javascripts/sidebar/sidebar_bundle.js
@@ -1,9 +1,9 @@
-import { mountSidebar, getSidebarOptions } from './mount_sidebar';
+import { mountSidebar, getSidebarOptions } from 'ee_else_ce/sidebar/mount_sidebar';
import Mediator from './sidebar_mediator';
-export default () => {
+export default (store) => {
const mediator = new Mediator(getSidebarOptions());
mediator.fetch();
- mountSidebar(mediator);
+ mountSidebar(mediator, store);
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/index.js b/app/assets/javascripts/vue_merge_request_widget/index.js
index 3a3a1329483..b10e0e2bc88 100644
--- a/app/assets/javascripts/vue_merge_request_widget/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/index.js
@@ -7,8 +7,6 @@ import VueApollo from 'vue-apollo';
import MrWidgetOptions from 'ee_else_ce/vue_merge_request_widget/mr_widget_options.vue';
import createDefaultClient from '~/lib/graphql';
import Translate from '../vue_shared/translate';
-import { registerExtension } from './components/extensions';
-import issueExtension from './extensions/issues';
Vue.use(Translate);
Vue.use(VueApollo);
@@ -28,8 +26,6 @@ export default () => {
gl.mrWidgetData.gitlabLogo = gon.gitlab_logo;
gl.mrWidgetData.defaultAvatarUrl = gon.default_avatar_url;
- registerExtension(issueExtension);
-
const vm = new Vue({
el: '#js-vue-mr-widget',
provide: {
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index c17fdbe1e47..f8e6dcf7ec0 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -12,9 +12,6 @@ import { sprintf, s__, __ } from '~/locale';
import Project from '~/pages/projects/project';
import SmartInterval from '~/smart_interval';
import { setFaviconOverlay } from '../lib/utils/favicon';
-import GroupedAccessibilityReportsApp from '../reports/accessibility_report/grouped_accessibility_reports_app.vue';
-import GroupedCodequalityReportsApp from '../reports/codequality_report/grouped_codequality_reports_app.vue';
-import GroupedTestReportsApp from '../reports/grouped_test_report/grouped_test_reports_app.vue';
import Loading from './components/loading.vue';
import MrWidgetAlertMessage from './components/mr_widget_alert_message.vue';
import WidgetHeader from './components/mr_widget_header.vue';
@@ -42,7 +39,6 @@ import ShaMismatch from './components/states/sha_mismatch.vue';
import UnresolvedDiscussionsState from './components/states/unresolved_discussions.vue';
import WorkInProgressState from './components/states/work_in_progress.vue';
// import ExtensionsContainer from './components/extensions/container';
-import TerraformPlan from './components/terraform/mr_widget_terraform_container.vue';
import eventHub from './event_hub';
import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variables';
import getStateQuery from './queries/get_state.query.graphql';
@@ -84,10 +80,13 @@ export default {
'mr-widget-auto-merge-failed': AutoMergeFailed,
'mr-widget-rebase': RebaseState,
SourceBranchRemovalStatus,
- GroupedCodequalityReportsApp,
- GroupedTestReportsApp,
- TerraformPlan,
- GroupedAccessibilityReportsApp,
+ GroupedCodequalityReportsApp: () =>
+ import('../reports/codequality_report/grouped_codequality_reports_app.vue'),
+ GroupedTestReportsApp: () =>
+ import('../reports/grouped_test_report/grouped_test_reports_app.vue'),
+ TerraformPlan: () => import('./components/terraform/mr_widget_terraform_container.vue'),
+ GroupedAccessibilityReportsApp: () =>
+ import('../reports/accessibility_report/grouped_accessibility_reports_app.vue'),
MrWidgetApprovals,
SecurityReportsApp: () => import('~/vue_shared/security_reports/security_reports_app.vue'),
},
diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb
index ed1d5ca9594..550877548e1 100644
--- a/app/controllers/projects/ci/pipeline_editor_controller.rb
+++ b/app/controllers/projects/ci/pipeline_editor_controller.rb
@@ -4,7 +4,6 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController
before_action :check_can_collaborate!
before_action do
push_frontend_feature_flag(:pipeline_editor_empty_state_action, @project, default_enabled: :yaml)
- push_frontend_feature_flag(:pipeline_editor_branch_switcher, @project, default_enabled: :yaml)
push_frontend_feature_flag(:pipeline_editor_drawer, @project, default_enabled: :yaml)
push_frontend_feature_flag(:schema_linting, @project, default_enabled: :yaml)
end
diff --git a/app/controllers/projects/usage_quotas_controller.rb b/app/controllers/projects/usage_quotas_controller.rb
index 6e2f7e45e8f..179c7fc8db1 100644
--- a/app/controllers/projects/usage_quotas_controller.rb
+++ b/app/controllers/projects/usage_quotas_controller.rb
@@ -8,6 +8,18 @@ class Projects::UsageQuotasController < Projects::ApplicationController
feature_category :utilization
+ def index
+ @storage_app_data = {
+ project_path: @project.full_path,
+ usage_quotas_help_page_path: help_page_path('user/usage_quotas'),
+ build_artifacts_help_page_path: help_page_path('ci/pipelines/job_artifacts', anchor: 'when-job-artifacts-are-deleted'),
+ packages_help_page_path: help_page_path('user/packages/package_registry/index.md', anchor: 'delete-a-package'),
+ repository_help_page_path: help_page_path('user/project/repository/reducing_the_repo_size_using_git'),
+ snippets_help_page_path: help_page_path('user/snippets', anchor: 'reduce-snippets-repository-size'),
+ wiki_help_page_path: help_page_path('administration/wikis/index.md', anchor: 'reduce-wiki-repository-size')
+ }
+ end
+
private
def verify_usage_quotas_enabled!
diff --git a/app/views/admin/application_settings/_ci_cd.html.haml b/app/views/admin/application_settings/_ci_cd.html.haml
index ee97a678aaa..fea116bd419 100644
--- a/app/views/admin/application_settings/_ci_cd.html.haml
+++ b/app/views/admin/application_settings/_ci_cd.html.haml
@@ -41,7 +41,7 @@
= f.label :default_artifacts_expire_in, _('Default artifacts expiration'), class: 'label-bold'
= f.text_field :default_artifacts_expire_in, class: 'form-control gl-form-input'
.form-text.text-muted
- = html_escape(_("The default expiration time for job artifacts. 0 for unlimited. The default unit is in seconds, but you can use other units, for example %{code_open}4 mins 2 sec%{code_close}, %{code_open}2h42min%{code_close}.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
+ = html_escape(_("Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration')
.form-group
.form-check
diff --git a/app/views/projects/usage_quotas/index.html.haml b/app/views/projects/usage_quotas/index.html.haml
index a6b3ba7153d..dfd46af0499 100644
--- a/app/views/projects/usage_quotas/index.html.haml
+++ b/app/views/projects/usage_quotas/index.html.haml
@@ -4,8 +4,10 @@
= s_('UsageQuota|Usage Quotas')
.row
- .col-sm-6
- = s_('UsageQuota|Usage of project resources across the %{strong_start}%{project_name}%{strong_end} project').html_safe % { strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe, project_name: @project.name }
+ .col-sm-12
+ = s_('UsageQuota|Usage of project resources across the %{strong_start}%{project_name}%{strong_end} project').html_safe % { strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe, project_name: @project.name } + '.'
+ %a{ href: help_page_path('user/usage_quotas.md') }
+ = s_('UsageQuota|Learn more about usage quotas') + '.'
.top-area.scrolling-tabs-container.inner-page-scroll-tabs
%ul.nav.nav-tabs.nav-links.scrolling-tabs.separator.js-usage-quota-tabs{ role: 'tablist' }
@@ -14,4 +16,4 @@
= s_('UsageQuota|Storage')
.tab-content
.tab-pane#storage-quota-tab
- #js-project-storage-count-app{ data: { project_path: @project.full_path } }
+ #js-project-storage-count-app{ data: @storage_app_data }
diff --git a/config/feature_flags/development/pipeline_editor_branch_switcher.yml b/config/feature_flags/development/pipeline_editor_branch_switcher.yml
deleted file mode 100644
index 49cf2a07a2c..00000000000
--- a/config/feature_flags/development/pipeline_editor_branch_switcher.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: pipeline_editor_branch_switcher
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57562
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326189
-milestone: '13.11'
-type: development
-group: group::pipeline authoring
-default_enabled: true
diff --git a/config/feature_flags/development/vuln_report_new_project_filter.yml b/config/feature_flags/development/vuln_report_new_project_filter.yml
index 79c2afaca07..3eb02054205 100644
--- a/config/feature_flags/development/vuln_report_new_project_filter.yml
+++ b/config/feature_flags/development/vuln_report_new_project_filter.yml
@@ -2,7 +2,7 @@
name: vuln_report_new_project_filter
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55745
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334380
-milestone: '14.2'
+milestone: '14.3'
type: development
group: group::threat insights
-default_enabled: false
+default_enabled: true
diff --git a/config/initializers/database_config.rb b/config/initializers/database_config.rb
index 6bdd0e377da..e9f10abd0b9 100644
--- a/config/initializers/database_config.rb
+++ b/config/initializers/database_config.rb
@@ -24,7 +24,7 @@ ActiveRecord::Base.establish_connection(Gitlab::Database.main.db_config_with_def
Gitlab.ee do
if Gitlab::Runtime.sidekiq? && Gitlab::Geo.geo_database_configured?
- Rails.configuration.geo_database['pool'] = Gitlab::Database.main.default_pool_size
+ Rails.configuration.geo_database['pool'] = Gitlab::Database.default_pool_size
Geo::TrackingBase.establish_connection(Rails.configuration.geo_database)
end
end
diff --git a/doc/administration/geo/disaster_recovery/background_verification.md b/doc/administration/geo/disaster_recovery/background_verification.md
index c5956c5cd56..caa806c92c8 100644
--- a/doc/administration/geo/disaster_recovery/background_verification.md
+++ b/doc/administration/geo/disaster_recovery/background_verification.md
@@ -89,7 +89,7 @@ in sync.
## Repository re-verification
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8550) in GitLab Enterprise Edition 11.6. Available in [GitLab Premium](https://about.gitlab.com/pricing/).
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8550) in GitLab 11.6.
Due to bugs or transient infrastructure failures, it is possible for Git
repositories to change unexpectedly without being marked for verification.
diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md
index d2d53f52418..4ee3c77da2e 100644
--- a/doc/administration/geo/index.md
+++ b/doc/administration/geo/index.md
@@ -7,12 +7,6 @@ type: howto
# Geo **(PREMIUM SELF)**
-> - Introduced in GitLab Enterprise Edition 8.9.
-> - Using Geo in combination with
-> [multi-node architectures](../reference_architectures/index.md)
-> is considered **Generally Available** (GA) in
-> [GitLab Premium](https://about.gitlab.com/pricing/) 10.4.
-
Geo is the solution for widely distributed development teams and for providing a warm-standby as part of a disaster recovery strategy.
## Overview
@@ -218,7 +212,7 @@ For information on how to update your Geo site(s) to the latest GitLab version,
### Pausing and resuming replication
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35913) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35913) in GitLab 13.2.
WARNING:
In GitLab 13.2 and 13.3, promoting a secondary site to a primary while the
diff --git a/doc/administration/geo/replication/faq.md b/doc/administration/geo/replication/faq.md
index 28030dccb3b..70a6e506c28 100644
--- a/doc/administration/geo/replication/faq.md
+++ b/doc/administration/geo/replication/faq.md
@@ -52,7 +52,7 @@ query.
## Can I `git push` to a **secondary** site?
-Yes! Pushing directly to a **secondary** site (for both HTTP and SSH, including Git LFS) was [introduced](https://about.gitlab.com/releases/2018/09/22/gitlab-11-3-released/) in [GitLab Premium](https://about.gitlab.com/pricing/#self-managed) 11.3.
+Yes! Pushing directly to a **secondary** site (for both HTTP and SSH, including Git LFS) was [introduced](https://about.gitlab.com/releases/2018/09/22/gitlab-11-3-released/) in GitLab 11.3.
## How long does it take to have a commit replicated to a **secondary** site?
diff --git a/doc/administration/geo/replication/usage.md b/doc/administration/geo/replication/usage.md
index ad3fb1f42cf..f3c8f6ac759 100644
--- a/doc/administration/geo/replication/usage.md
+++ b/doc/administration/geo/replication/usage.md
@@ -11,7 +11,7 @@ type: howto
After you set up the [database replication and configure the Geo nodes](../index.md#setup-instructions), use your closest GitLab site as you would do with the primary one.
-You can push directly to a **secondary** site (for both HTTP, SSH including Git LFS), and the request will be proxied to the primary site instead ([introduced](https://about.gitlab.com/releases/2018/09/22/gitlab-11-3-released/) in [GitLab Premium](https://about.gitlab.com/pricing/#self-managed) 11.3).
+You can push directly to a **secondary** site (for both HTTP, SSH including Git LFS), and the request will be proxied to the primary site instead ([introduced](https://about.gitlab.com/releases/2018/09/22/gitlab-11-3-released/) in GitLab 11.3).
Example of the output you will see when pushing to a **secondary** site:
diff --git a/doc/administration/geo/setup/external_database.md b/doc/administration/geo/setup/external_database.md
index 56d196b54ec..13dbf9d1434 100644
--- a/doc/administration/geo/setup/external_database.md
+++ b/doc/administration/geo/setup/external_database.md
@@ -249,7 +249,7 @@ the tracking database on port 5432.
gitlab-rake geo:db:create
```
-1. The reconfigure should automatically migrate the database. You can migrate the database manually if needed, for example if `gitlab_rails['auto_migrate'] = false`:
+1. The reconfigure should automatically migrate the database. You can migrate the database manually if needed, for example if `geo_secondary['auto_migrate'] = false`:
```shell
gitlab-rake geo:db:migrate
diff --git a/doc/administration/maintenance_mode/index.md b/doc/administration/maintenance_mode/index.md
index dbba8cb5087..39ee357cc2f 100644
--- a/doc/administration/maintenance_mode/index.md
+++ b/doc/administration/maintenance_mode/index.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab Maintenance Mode **(PREMIUM SELF)**
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2149) in GitLab Premium 13.9.
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2149) in GitLab 13.9.
Maintenance Mode allows administrators to reduce write operations to a minimum while maintenance tasks are performed. The main goal is to block all external actions that change the internal state, including the PostgreSQL database, but especially files, Git repositories, Container repositories, and so on.
diff --git a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
index 197cbbdec94..90d0b65dbe5 100644
--- a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
+++ b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
@@ -14,7 +14,7 @@ GitLab provides administrators insights into the health of their GitLab instance
To provide a native experience (similar interacting with an application deployed using GitLab), a
project called **Monitoring** is created:
-- With [internal visibility](../../../public_access/public_access.md#internal-projects).
+- With [internal visibility](../../../public_access/public_access.md#internal-projects-and-groups).
- Under a group called **GitLab Instance**.
The project is created specifically for visualizing and configuring the monitoring of your GitLab
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index 06199495dc4..ef8330f8696 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -196,43 +196,6 @@ to use the HTTPS protocol.
WARNING:
Multiple wildcards for one instance is not supported. Only one wildcard per instance can be assigned.
-### Additional configuration for Docker container
-
-The GitLab Pages daemon doesn't have permissions to bind mounts when it runs
-in a Docker container. To overcome this issue, you must change the `chroot`
-behavior:
-
-1. Edit `/etc/gitlab/gitlab.rb`.
-1. Set the `inplace_chroot` to `true` for GitLab Pages:
-
- ```ruby
- gitlab_pages['inplace_chroot'] = true
- ```
-
-1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
-
-NOTE:
-`inplace_chroot` option might not work with the other features, such as [Pages Access Control](#access-control).
-The [GitLab Pages README](https://gitlab.com/gitlab-org/gitlab-pages#caveats) has more information about caveats and workarounds.
-
-### Jailing mechanism disabled by default for API-based configuration
-
-Starting from GitLab 14.1 the [jailing/chroot mechanism is disabled by default](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/589).
-If you are using API-based configuration and the new [Zip storage architecture](#zip-storage)
-there is nothing you need to do.
-
-If you run into any problems, [open a new issue](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/new)
-and enable the jail again by setting the environment variable:
-
-1. Edit `/etc/gitlab/gitlab.rb`.
-1. Set the `DAEMON_ENABLE_JAIL` environment variable to `true` for GitLab Pages:
-
- ```ruby
- gitlab_pages['env']['DAEMON_ENABLE_JAIL'] = "true"
- ```
-
-1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
-
### Global settings
Below is a table of all configuration settings known to Pages in Omnibus GitLab,
@@ -270,7 +233,7 @@ control over how the Pages daemon runs and serves content in your environment.
| `auth_scope` | The OAuth application scope to use for authentication. Must match GitLab Pages OAuth application settings. Leave blank to use `api` scope by default. |
| `gitlab_server` | Server to use for authentication when access control is enabled; defaults to GitLab `external_url`. |
| `headers` | Specify any additional http headers that should be sent to the client with each response. Multiple headers can be given as an array, header and value as one string, for example `['my-header: myvalue', 'my-other-header: my-other-value']` |
-| `inplace_chroot` | On [systems that don't support bind-mounts](index.md#additional-configuration-for-docker-container), this instructs GitLab Pages to `chroot` into its `pages_path` directory. Some caveats exist when using in-place `chroot`; refer to the GitLab Pages [README](https://gitlab.com/gitlab-org/gitlab-pages/blob/master/README.md#caveats) for more information. |
+| `inplace_chroot` | [REMOVED in GitLab 14.3.](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/561) On [systems that don't support bind-mounts](index.md#gitlab-pages-fails-to-start-in-docker-container), this instructs GitLab Pages to `chroot` into its `pages_path` directory. Some caveats exist when using in-place `chroot`; refer to the GitLab Pages [README](https://gitlab.com/gitlab-org/gitlab-pages/blob/master/README.md#caveats) for more information. |
| `enable_disk` | Allows the GitLab Pages daemon to serve content from disk. Shall be disabled if shared disk storage isn't available. |
| `insecure_ciphers` | Use default list of cipher suites, may contain insecure ones like 3DES and RC4. |
| `internal_gitlab_server` | Internal GitLab server address used exclusively for API requests. Useful if you want to send that traffic over an internal load balancer. Defaults to GitLab `external_url`. |
@@ -300,7 +263,7 @@ control over how the Pages daemon runs and serves content in your environment.
| `enable` | Include a virtual host `server{}` block for Pages inside NGINX. Needed for NGINX to proxy traffic back to the Pages daemon. Set to `false` if the Pages daemon should directly receive all requests, for example, when using [custom domains](index.md#custom-domains). |
| `FF_ENABLE_REDIRECTS` | Feature flag to enable/disable redirects (enabled by default). Read the [redirects documentation](../../user/project/pages/redirects.md#feature-flag-for-redirects) for more information. |
| `FF_ENABLE_PLACEHOLDERS` | Feature flag to enable/disable rewrites (disabled by default). Read the [redirects documentation](../../user/project/pages/redirects.md#feature-flag-for-rewrites) for more information. |
-| `use_legacy_storage` | Temporarily-introduced parameter allowing to use legacy domain configuration source and storage. [Will be removed in GitLab 14.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6166). |
+| `use_legacy_storage` | Temporarily-introduced parameter allowing to use legacy domain configuration source and storage. [Removed in 14.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6166). |
---
@@ -1108,6 +1071,9 @@ You can also find the log file in `/var/log/gitlab/gitlab-pages/current`.
### `open /etc/ssl/ca-bundle.pem: permission denied`
+WARNING:
+This issue is fixed in GitLab 14.3 and above, try upgrading GitLab first.
+
GitLab Pages runs inside a `chroot` jail, usually in a uniquely numbered directory like
`/tmp/gitlab-pages-*`.
@@ -1139,6 +1105,9 @@ sudo gitlab-ctl restart gitlab-pages
### `dial tcp: lookup gitlab.example.com` and `x509: certificate signed by unknown authority`
+WARNING:
+This issue is fixed in GitLab 14.3 and above, try upgrading GitLab first.
+
When setting both `inplace_chroot` and `access_control` to `true`, you might encounter errors like:
```plaintext
@@ -1404,16 +1373,11 @@ both servers.
GitLab 14.0 introduces a number of changes to GitLab Pages which may require manual intervention.
1. Firstly [follow the migration guide](#migrate-gitlab-pages-to-140).
+1. Try to upgrade to GitLab 14.3 or above. Some of the issues were fixed in GitLab 14.1, 14.2 and 14.3.
1. If it doesn't work, see [GitLab Pages logs](#how-to-see-gitlab-pages-logs), and if you see any errors there then search them on this page.
-The most common problem is when using [`inplace_chroot`](#dial-tcp-lookup-gitlabexamplecom-and-x509-certificate-signed-by-unknown-authority).
-
-NOTE:
-Starting from 14.1, the chroot/jailing mechanism is
-[disabled by default for API-based configuration](#jailing-mechanism-disabled-by-default-for-api-based-configuration).
-
WARNING:
-As the last resort you can temporarily enable legacy storage and configuration mechanisms. Support for them [will be removed in GitLab 14.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6166), so GitLab Pages will stop working if don't resolve the underlying issue.
+In GitLab 14.0-14.2 you can temporarily enable legacy storage and configuration mechanisms.
To do that:
@@ -1426,3 +1390,25 @@ To do that:
```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+
+### GitLab Pages fails to start in Docker container
+
+WARNING:
+This issue is fixed in GitLab 14.3 and above, try upgrading GitLab first.
+
+The GitLab Pages daemon doesn't have permissions to bind mounts when it runs
+in a Docker container. To overcome this issue, you must change the `chroot`
+behavior:
+
+1. Edit `/etc/gitlab/gitlab.rb`.
+1. Set the `inplace_chroot` to `true` for GitLab Pages:
+
+ ```ruby
+ gitlab_pages['inplace_chroot'] = true
+ ```
+
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+
+NOTE:
+`inplace_chroot` option might not work with the other features, such as [Pages Access Control](#access-control).
+The [GitLab Pages README](https://gitlab.com/gitlab-org/gitlab-pages#caveats) has more information about caveats and workarounds.
diff --git a/doc/api/dependency_proxy.md b/doc/api/dependency_proxy.md
index e9ddc1e9df9..14f772f9aa1 100644
--- a/doc/api/dependency_proxy.md
+++ b/doc/api/dependency_proxy.md
@@ -4,12 +4,12 @@ group: Package
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
---
-# Dependency Proxy API
+# Dependency Proxy API **(FREE)**
## Purge the dependency proxy for a group
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11631) in GitLab 12.10.
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/273655) to [GitLab Free](https://about.gitlab.com/pricing/) in GitLab 13.6.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/273655) from GitLab Premium to GitLab Free in 13.6.
Deletes the cached manifests and blobs for a group. This endpoint requires the [Owner role](../user/permissions.md)
for the group.
diff --git a/doc/api/deploy_keys.md b/doc/api/deploy_keys.md
index be4207ea681..bb719b5bc79 100644
--- a/doc/api/deploy_keys.md
+++ b/doc/api/deploy_keys.md
@@ -4,9 +4,9 @@ group: Release
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
---
-# Deploy keys API
+# Deploy keys API **(FREE)**
-## List all deploy keys
+## List all deploy keys **(FREE SELF)**
Get a list of all deploy keys across all projects of the GitLab instance. This
endpoint requires an administrator role and is not available on GitLab.com.
diff --git a/doc/api/deploy_tokens.md b/doc/api/deploy_tokens.md
index 6ed8f76583f..3de7ff4ac44 100644
--- a/doc/api/deploy_tokens.md
+++ b/doc/api/deploy_tokens.md
@@ -4,9 +4,9 @@ group: Release
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
---
-# Deploy Tokens API
+# Deploy Tokens API **(FREE)**
-## List all deploy tokens
+## List all deploy tokens **(FREE SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21811) in GitLab 12.9.
diff --git a/doc/api/deployments.md b/doc/api/deployments.md
index 3ed431cf63d..5f710271d60 100644
--- a/doc/api/deployments.md
+++ b/doc/api/deployments.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: concepts, howto
---
-# Deployments API
+# Deployments API **(FREE)**
## List project deployments
diff --git a/doc/api/dora/metrics.md b/doc/api/dora/metrics.md
index 38f1f50839e..8c82446db2e 100644
--- a/doc/api/dora/metrics.md
+++ b/doc/api/dora/metrics.md
@@ -7,7 +7,7 @@ type: reference, api
# DevOps Research and Assessment (DORA) key metrics API **(ULTIMATE)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/279039) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.10.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/279039) in GitLab 13.10.
> - The legacy key/value pair `{ "<date>" => "<value>" }` was removed from the payload in GitLab 14.0.
All methods require [reporter permissions and above](../../user/permissions.md).
@@ -52,7 +52,7 @@ Example response:
## Get group-level DORA metrics
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/279039) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.10.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/279039) in GitLab 13.10.
Get group-level DORA metrics.
diff --git a/doc/api/dora4_project_analytics.md b/doc/api/dora4_project_analytics.md
index efea9723ac4..5a6e1576a3d 100644
--- a/doc/api/dora4_project_analytics.md
+++ b/doc/api/dora4_project_analytics.md
@@ -7,7 +7,7 @@ type: reference, api
# DORA4 Analytics Project API **(ULTIMATE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/279039) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.7.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/279039) in GitLab 13.7.
WARNING:
These endpoints are deprecated and will be removed in GitLab 14.0. Use the [DORA metrics API](dora/metrics.md) instead.
diff --git a/doc/api/feature_flag_specs.md b/doc/api/feature_flag_specs.md
index 33e454d50c4..f2853efc5f2 100644
--- a/doc/api/feature_flag_specs.md
+++ b/doc/api/feature_flag_specs.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Feature Flag Specs API **(PREMIUM)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9566) in GitLab 12.5.
This API was removed in [GitLab 14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/213369).
Please use [the new API](feature_flags.md) instead.
diff --git a/doc/api/features.md b/doc/api/features.md
index 87bd565e2bd..30efacb1d00 100644
--- a/doc/api/features.md
+++ b/doc/api/features.md
@@ -4,7 +4,7 @@ group: Release
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
---
-# Features flags API
+# Feature flags API **(FREE SELF)**
This API is for managing Flipper-based [feature flags used in development of GitLab](../development/feature_flags/index.md).
diff --git a/doc/api/freeze_periods.md b/doc/api/freeze_periods.md
index a562423b2af..6ca69d047da 100644
--- a/doc/api/freeze_periods.md
+++ b/doc/api/freeze_periods.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: concepts, howto
---
-# Freeze Periods API
+# Freeze Periods API **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29382) in GitLab 13.0.
diff --git a/doc/api/group_protected_environments.md b/doc/api/group_protected_environments.md
index ff0f3e3c5e9..0e1cd149c51 100644
--- a/doc/api/group_protected_environments.md
+++ b/doc/api/group_protected_environments.md
@@ -7,15 +7,11 @@ type: concepts, howto
# Group-level protected environments API **(PREMIUM)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215888) in [GitLab Premium](https://about.gitlab.com/pricing/) 14.0. [Deployed behind the `group_level_protected_environments` flag](../administration/feature_flags.md), disabled by default.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215888) in GitLab 14.0. [Deployed behind the `group_level_protected_environments` flag](../administration/feature_flags.md), disabled by default.
> - [Feature flag `group_level_protected_environments`](https://gitlab.com/gitlab-org/gitlab/-/issues/331085) removed in GitLab 14.3.
-> - [Generally Available](https://gitlab.com/gitlab-org/gitlab/-/issues/331085) on [GitLab Premium](https://about.gitlab.com/pricing/) and on GitLab.com in 14.3.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/331085) in GitLab 14.3.
-This in-development feature might not be available for your use. There can be
-[risks when enabling features still in development](../administration/feature_flags.md#risks-when-enabling-features-still-in-development).
-Refer to this feature's version history for more details.
-
-Read more about [group-level protected environments](../ci/environments/protected_environments.md#group-level-protected-environments),
+Read more about [group-level protected environments](../ci/environments/protected_environments.md#group-level-protected-environments).
## Valid access levels
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index 8b57326902e..72627783947 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -4,7 +4,7 @@ group: Release
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
---
-# Releases API
+# Releases API **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41766) in GitLab 11.7.
> - Using this API you can manipulate GitLab [Release](../../user/project/releases/index.md) entries.
@@ -499,7 +499,7 @@ Example response:
### Group milestones **(PREMIUM SELF)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235391) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235391) in GitLab 13.5.
Group milestones associated with the project may be specified in the `milestones`
array for [Create a release](#create-a-release) and [Update a release](#update-a-release)
@@ -508,7 +508,7 @@ adding milestones for ancestor groups raises an error.
## Collect release evidence **(PREMIUM SELF)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199065) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199065) in GitLab 12.10.
Create Evidence for an existing Release.
diff --git a/doc/api/releases/links.md b/doc/api/releases/links.md
index 2f8dc363124..c9d183b8351 100644
--- a/doc/api/releases/links.md
+++ b/doc/api/releases/links.md
@@ -4,7 +4,7 @@ group: Release
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
---
-# Release links API
+# Release links API **(FREE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41766) in GitLab 11.7.
diff --git a/doc/ci/environments/protected_environments.md b/doc/ci/environments/protected_environments.md
index 71a25146706..7caac7df64e 100644
--- a/doc/ci/environments/protected_environments.md
+++ b/doc/ci/environments/protected_environments.md
@@ -157,9 +157,9 @@ For more information, see [Deployment safety](deployment_safety.md).
## Group-level protected environments
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215888) in [GitLab Premium](https://about.gitlab.com/pricing/) 14.0. [Deployed behind the `group_level_protected_environments` flag](../../administration/feature_flags.md), disabled by default.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215888) in GitLab 14.0. [Deployed behind the `group_level_protected_environments` flag](../../administration/feature_flags.md), disabled by default.
> - [Feature flag `group_level_protected_environments`](https://gitlab.com/gitlab-org/gitlab/-/issues/331085) removed in GitLab 14.3.
-> - [Generally Available](https://gitlab.com/gitlab-org/gitlab/-/issues/331085) on [GitLab Premium](https://about.gitlab.com/pricing/) and on GitLab.com in 14.3.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/331085) in GitLab 14.3.
This in-development feature might not be available for your use. There can be
[risks when enabling features still in development](../../administration/feature_flags.md#risks-when-enabling-features-still-in-development).
diff --git a/doc/ci/runners/build_cloud/macos_build_cloud.md b/doc/ci/runners/build_cloud/macos_build_cloud.md
index 35b25d3c9a3..794bc2e597d 100644
--- a/doc/ci/runners/build_cloud/macos_build_cloud.md
+++ b/doc/ci/runners/build_cloud/macos_build_cloud.md
@@ -24,8 +24,7 @@ access has been granted and your build environment configured, you must configur
1. Specify the [image](macos/environment.md#vm-images) you want to use.
1. Commit a change to your repository.
-The runners automatically run your build. For more detailed setup instructions,
-view [how to set up macOS runners](macos/setup.md).
+The runners automatically run your build.
## Example `.gitlab-ci.yml` file
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index 534150e4d37..ff1ea3a2bca 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -225,9 +225,17 @@ the contribution acceptance criteria below:
If you contribute to GitLab please know that changes involve more than just
code. We use the following [definition of done](https://www.agilealliance.org/glossary/definition-of-done).
+To reach the definition of done, the merge request must create no regressions and meet all these criteria:
+
+- Verified as working in production on GitLab.com.
+- Verified as working for self-managed instances.
+
+If a regression occurs, we prefer you revert the change. We break the definition of done into two phases: [MR Merge](#mr-merge) and [Production use](#production-use).
Your contribution is not *done* until you have made sure it meets all of these
requirements.
+### MR Merge
+
1. Clear description explaining the relevancy of the contribution.
1. Working and clean code that is commented where needed.
1. [Unit, integration, and system tests](../testing_guide/index.md) that all pass
@@ -239,16 +247,23 @@ requirements.
1. [Documented](../documentation/index.md) in the `/doc` directory.
1. [Changelog entry added](../changelog.md), if necessary.
1. Reviewed by relevant reviewers and all concerns are addressed for Availability, Regressions, Security. Documentation reviews should take place as soon as possible, but they should not block a merge request.
-1. Merged by a project maintainer.
1. Create an issue in the [infrastructure issue tracker](https://gitlab.com/gitlab-com/gl-infra/infrastructure/-/issues) to inform the Infrastructure department when your contribution is changing default settings or introduces a new setting, if relevant.
-1. Confirmed to be working in the [Canary stage](https://about.gitlab.com/handbook/engineering/#canary-testing) with no new [Sentry](https://about.gitlab.com/handbook/engineering/#sentry) errors or on GitLab.com once the contribution is deployed.
-1. Added to the [release post](https://about.gitlab.com/handbook/marketing/blog/release-posts/),
- if relevant.
-1. Added to [the website](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/features.yml), if relevant.
1. [Black-box tests/end-to-end tests](../testing_guide/testing_levels.md#black-box-tests-at-the-system-level-aka-end-to-end-tests)
added if required. Please contact [the quality team](https://about.gitlab.com/handbook/engineering/quality/#teams)
with any questions.
1. The new feature does not degrade the user experience of the product.
+1. An agreed upon rollout plan.
+1. Merged by a project maintainer.
+
+### Production use
+
+1. Confirmed to be working in the production with no new [Sentry](https://about.gitlab.com/handbook/engineering/#sentry) errors after the contribution is deployed.
+1. *If the merge request uses feature flags, per-project or per-group enablement, and a staged rollout:*
+ - Confirmed to be working on GitLab projects.
+ - Confirmed to be working at each stage for all projects added.
+1. Added to the [release post](https://about.gitlab.com/handbook/marketing/blog/release-posts/),
+ if relevant.
+1. Added to [the website](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/features.yml), if relevant.
Contributions do not require approval from the [Product team](https://about.gitlab.com/handbook/product/product-processes/#gitlab-pms-arent-the-arbiters-of-community-contributions).
diff --git a/doc/development/documentation/feature_flags.md b/doc/development/documentation/feature_flags.md
index d69badab2a4..5a4d365ed20 100644
--- a/doc/development/documentation/feature_flags.md
+++ b/doc/development/documentation/feature_flags.md
@@ -67,10 +67,12 @@ When the state of a flag changes (for example, disabled by default to enabled by
Possible version history entries are:
```markdown
+> - [Introduced](issue-link) in GitLab X.X. [Deployed behind the <flag name> flag](../../administration/feature_flags.md), disabled by default.
> - [Enabled on GitLab.com](issue-link) in GitLab X.X.
> - [Enabled on GitLab.com](issue-link) in GitLab X.X. Available to GitLab.com administrators only.
> - [Enabled on self-managed](issue-link) in GitLab X.X.
-> - [Feature flag <flag name> removed](issue-line) in GitLab X.X.
+> - [Feature flag <flag name> removed](issue-link) in GitLab X.X.
+> - [Generally available](issue-link) in GitLab X.X.
```
## Feature flag documentation examples
@@ -78,7 +80,7 @@ Possible version history entries are:
The following examples show the progression of a feature flag.
```markdown
-> Introduced in GitLab 13.7.
+> Introduced in GitLab 13.7. [Deployed behind the `forti_token_cloud` flag](../../administration/feature_flags.md), disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available,
@@ -89,7 +91,7 @@ The feature is not ready for production use.
When the feature is enabled in production, you can update the version history:
```markdown
-> - Introduced in GitLab 13.7.
+> - Introduced in GitLab 13.7. [Deployed behind the `forti_token_cloud` flag](../../administration/feature_flags.md), disabled by default.
> - [Enabled on self-managed](https://gitlab.com/issue/etc) GitLab 13.8.
FLAG:
@@ -100,8 +102,9 @@ ask an administrator to [disable the `forti_token_cloud` flag](../administration
And, when the feature is done and fully available to all users:
```markdown
-> - Introduced in GitLab 13.7.
+> - Introduced in GitLab 13.7. [Deployed behind the `forti_token_cloud` flag](../../administration/feature_flags.md), disabled by default.
> - [Enabled on self-managed](https://gitlab.com/issue/etc) GitLab 13.8.
> - [Enabled on GitLab.com](https://gitlab.com/issue/etc) in GitLab 13.9.
> - [Feature flag `forti_token_cloud`](https://gitlab.com/issue/etc) removed in GitLab 14.0.
+> - [Generally available](issue-link) in GitLab 14.0.
```
diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md
index 577303a313c..d9b908b3823 100644
--- a/doc/development/documentation/styleguide/index.md
+++ b/doc/development/documentation/styleguide/index.md
@@ -1479,10 +1479,6 @@ tagged and released set of documentation for your installed version:
When a feature is added or updated, you can include its version information
either as a **Version history** item or as an inline text reference.
-Version text shouldn't include information about the tier in which the feature
-is available. This information is provided by the [product badge](#product-tier-badges)
-displayed for the page or feature.
-
#### Version text in the **Version History**
If all content in a section is related, add version text after the header for
@@ -1498,6 +1494,8 @@ the section. The version information must:
- Whenever possible, include a link to the completed issue, merge request, or epic
that introduced the feature. An issue is preferred over a merge request, and
a merge request is preferred over an epic.
+- Do not include information about the tier, or a link to the pricing page.
+ The tier is provided by the [product badge](#product-tier-badges) on the heading.
```markdown
## Feature name
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index 3f3c7fff6cd..6df221fe609 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -188,6 +188,10 @@ Do not use **e-mail** with a hyphen. When plural, use **emails** or **email mess
See [the Microsoft style guide](https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/e/enable-enables) for guidance.
Use **active** or **on** instead. ([Vale](../testing.md#vale) rule: [`InclusionAbleism.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/InclusionAbleism.yml))
+## enter
+
+Use instead of **type** when talking about putting values into text boxes.
+
## epic
Lowercase.
@@ -581,6 +585,10 @@ You **turn on** or **turn off** a toggle. For example:
- Turn on the **blah** toggle.
+## type
+
+Do not use if you can avoid it. Use **enter** instead.
+
## useful
Do not use. If the user doesn't find the process to be useful, we lose their trust.
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index 2cbcae31db3..1b4e1e64562 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -5,9 +5,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: reference
---
-# Project visibility
+# Project and group visibility
-GitLab allows [Owners](../user/permissions.md) to set a project's visibility as:
+GitLab allows [Owners](../user/permissions.md) to set a project's or group's visibility as:
- **Public**
- **Internal**
@@ -18,7 +18,7 @@ for your GitLab instance). For example, <https://gitlab.com/public>.
You can control the visibility of individual features with
[project feature settings](../user/permissions.md#project-features).
-## Public projects
+## Public projects and groups
Public projects can be cloned **without any** authentication over HTTPS.
@@ -31,7 +31,7 @@ By default, `/public` is visible to unauthenticated users. However, if the
[**Public** visibility level](../user/admin_area/settings/visibility_and_access_controls.md#restrict-visibility-levels)
is restricted, `/public` is visible only to signed-in users.
-## Internal projects
+## Internal projects and groups
Internal projects can be cloned by any signed-in user except
[external users](../user/permissions.md#external-users).
@@ -47,7 +47,7 @@ and snippets on GitLab.com. Existing projects, groups, and snippets using the `I
visibility setting keep this setting. You can read more about the change in the
[relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/12388).
-## Private projects
+## Private projects and groups
Private projects can only be cloned and viewed by project members (except for guests).
@@ -62,7 +62,19 @@ Prerequisite:
1. On the top bar, select **Menu > Projects** and find your project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
-1. Change **Project visibility** to either Public, Internal, or Private.
+1. Change **Project visibility** to either **Private**, **Internal**, or **Public**.
+1. Select **Save changes**.
+
+## Change group visibility
+
+Prerequisite:
+
+- You must have the Owner role for a group.
+
+1. On the top bar, select **Menu > Groups** and find your project.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Naming, visibility**.
+1. Under **Visibility level** select either **Private**, **Internal**, or **Public**.
1. Select **Save changes**.
## Restrict use of public or internal projects
diff --git a/doc/topics/gitlab_flow.md b/doc/topics/gitlab_flow.md
index 307a28a0f2e..e831c35a8ea 100644
--- a/doc/topics/gitlab_flow.md
+++ b/doc/topics/gitlab_flow.md
@@ -7,8 +7,6 @@ disqus_identifier: 'https://docs.gitlab.com/ee/workflow/gitlab_flow.html'
# Introduction to GitLab Flow **(FREE)**
-![GitLab Flow](img/gitlab_flow.png)
-
Git allows a wide variety of branching strategies and workflows.
Because of this, many organizations end up with workflows that are too complicated, not clearly defined, or not integrated with issue tracking systems.
Therefore, we propose GitLab flow as a clearly defined set of best practices.
@@ -33,8 +31,6 @@ In Git, you add files from the working copy to the staging area. After that, you
The third step is pushing to a shared remote repository.
After getting used to these three steps, the next challenge is the branching model.
-![Multiple long-running branches and merging in all directions](img/gitlab_flow_messy_flow.png)
-
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.
@@ -237,8 +233,6 @@ When you reopen an issue you need to create a new merge request.
## Issue tracking with GitLab flow
-![Merge request with the branch name "15-require-a-password-to-change-it" and assignee field shown](img/gitlab_flow_merge_request.png)
-
GitLab flow is a way to make the relation between the code and the issue tracker more transparent.
Any significant change to the code should start with an issue that describes the goal.
@@ -277,8 +271,6 @@ 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 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.
@@ -339,8 +331,6 @@ Git does not allow you to merge the code again otherwise.
## Reducing merge commits in feature branches
-![List of sequential merge commits](img/gitlab_flow_merge_commits.png)
-
Having lots of merge commits can make your repository history messy.
Therefore, you should try to avoid merge commits in feature branches.
Often, people avoid merge commits by just using rebase to reorder their commits after the commits on the `main` branch.
@@ -427,8 +417,6 @@ Issue: gitlab.com/gitlab-org/gitlab/-/issues/1
## Testing before merging
-![Merge requests showing the test states: red, yellow, and green](img/gitlab_flow_ci_mr.png)
-
In old workflows, the continuous integration (CI) server commonly ran tests on the `main` branch only.
Developers had to ensure their code did not break the `main` branch.
When using GitLab flow, developers create their branches from this `main` branch, so it is essential that it never breaks.
@@ -444,8 +432,6 @@ As said before, if you often have feature branches that last for more than a few
## Working with feature branches
-![Shell output showing git pull output](img/gitlab_flow_git_pull.png)
-
When creating a feature branch, always branch from an up-to-date `main`.
If you know before you start that your work depends on another branch, you can also branch from there.
If you need to merge in another branch after starting, explain the reason in the merge commit.
diff --git a/doc/topics/img/gitlab_flow.png b/doc/topics/img/gitlab_flow.png
deleted file mode 100644
index c12405455f9..00000000000
--- a/doc/topics/img/gitlab_flow.png
+++ /dev/null
Binary files differ
diff --git a/doc/topics/img/gitlab_flow_ci_mr.png b/doc/topics/img/gitlab_flow_ci_mr.png
deleted file mode 100644
index 85a609cb814..00000000000
--- a/doc/topics/img/gitlab_flow_ci_mr.png
+++ /dev/null
Binary files differ
diff --git a/doc/topics/img/gitlab_flow_close_issue_mr.png b/doc/topics/img/gitlab_flow_close_issue_mr.png
deleted file mode 100644
index 70de2fb6cee..00000000000
--- a/doc/topics/img/gitlab_flow_close_issue_mr.png
+++ /dev/null
Binary files differ
diff --git a/doc/topics/img/gitlab_flow_git_pull.png b/doc/topics/img/gitlab_flow_git_pull.png
deleted file mode 100644
index 0e56e59471c..00000000000
--- a/doc/topics/img/gitlab_flow_git_pull.png
+++ /dev/null
Binary files differ
diff --git a/doc/topics/img/gitlab_flow_merge_commits.png b/doc/topics/img/gitlab_flow_merge_commits.png
deleted file mode 100644
index 4a80811c6e3..00000000000
--- a/doc/topics/img/gitlab_flow_merge_commits.png
+++ /dev/null
Binary files differ
diff --git a/doc/topics/img/gitlab_flow_merge_request.png b/doc/topics/img/gitlab_flow_merge_request.png
deleted file mode 100644
index 010e95983fc..00000000000
--- a/doc/topics/img/gitlab_flow_merge_request.png
+++ /dev/null
Binary files differ
diff --git a/doc/topics/img/gitlab_flow_messy_flow.png b/doc/topics/img/gitlab_flow_messy_flow.png
deleted file mode 100644
index 4fa22d2bb5d..00000000000
--- a/doc/topics/img/gitlab_flow_messy_flow.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index afc75ca38c5..dc409c972fc 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -362,7 +362,7 @@ doesn't return the following headers:
### Visibility settings
If created before GitLab 12.2 (July 2019), these items have the
-[Internal visibility](../../public_access/public_access.md#internal-projects)
+[Internal visibility](../../public_access/public_access.md#internal-projects-and-groups)
setting [disabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/12388):
- Projects
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index e5333e5dbb5..bc13ef15d15 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -280,6 +280,7 @@ The following table lists group permissions available for each role:
|--------------------------------------------------------|-------|----------|-----------|------------|-------|
| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ |
| Edit SAML SSO Billing **(PREMIUM SAAS)** | ✓ | ✓ | ✓ | ✓ | ✓ (4) |
+| Pull a container image using the dependency proxy | ✓ | ✓ | ✓ | ✓ | ✓ |
| View Contribution analytics | ✓ | ✓ | ✓ | ✓ | ✓ |
| View group epic **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ |
| View group wiki pages **(PREMIUM)** | ✓ (6) | ✓ | ✓ | ✓ | ✓ |
@@ -301,7 +302,6 @@ The following table lists group permissions available for each role:
| Create/edit/delete iterations | | | ✓ | ✓ | ✓ |
| Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ |
| Enable/disable a dependency proxy | | | ✓ | ✓ | ✓ |
-| Pull a container image using the dependency proxy | ✓ | ✓ | ✓ | ✓ | ✓ |
| Purge the dependency proxy for a group | | | | | ✓ |
| Publish [packages](packages/index.md) | | | ✓ | ✓ | ✓ |
| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
@@ -314,6 +314,7 @@ The following table lists group permissions available for each role:
| View/manage group-level Kubernetes cluster | | | | ✓ | ✓ |
| Administer project compliance frameworks | | | | | ✓ |
| Create/Delete group deploy tokens | | | | | ✓ |
+| Change group visibility level | | | | | ✓ |
| Delete group | | | | | ✓ |
| Delete group epic **(PREMIUM)** | | | | | ✓ |
| Disable notification emails | | | | | ✓ |
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index ce198061a49..f3f0d0305d3 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -6,6 +6,7 @@ module Gitlab
MAIN_DATABASE_NAME = 'main'
CI_DATABASE_NAME = 'ci'
+ DEFAULT_POOL_HEADROOM = 10
# This constant is used when renaming tables concurrently.
# If you plan to rename a table using the `rename_table_safely` method, add your table here one milestone before the rename.
@@ -62,6 +63,20 @@ module Gitlab
DATABASES[PRIMARY_DATABASE_NAME]
end
+ # We configure the database connection pool size automatically based on the
+ # configured concurrency. We also add some headroom, to make sure we don't
+ # run out of connections when more threads besides the 'user-facing' ones
+ # are running.
+ #
+ # Read more about this in
+ # doc/development/database/client_side_connection_pool.md
+ def self.default_pool_size
+ headroom =
+ (ENV["DB_POOL_HEADROOM"].presence || DEFAULT_POOL_HEADROOM).to_i
+
+ Gitlab::Runtime.max_threads + headroom
+ end
+
def self.has_config?(database_name)
Gitlab::Application.config.database_configuration[Rails.env].include?(database_name.to_s)
end
diff --git a/lib/gitlab/database/connection.rb b/lib/gitlab/database/connection.rb
index 348b7207b23..6eac115be13 100644
--- a/lib/gitlab/database/connection.rb
+++ b/lib/gitlab/database/connection.rb
@@ -5,8 +5,6 @@ module Gitlab
# Configuration settings and methods for interacting with a PostgreSQL
# database, with support for multiple databases.
class Connection
- DEFAULT_POOL_HEADROOM = 10
-
attr_reader :scope
# Initializes a new `Database`.
@@ -20,20 +18,6 @@ module Gitlab
@open_transactions_baseline = 0
end
- # We configure the database connection pool size automatically based on
- # the configured concurrency. We also add some headroom, to make sure we
- # don't run out of connections when more threads besides the 'user-facing'
- # ones are running.
- #
- # Read more about this in
- # doc/development/database/client_side_connection_pool.md
- def default_pool_size
- headroom =
- (ENV["DB_POOL_HEADROOM"].presence || DEFAULT_POOL_HEADROOM).to_i
-
- Gitlab::Runtime.max_threads + headroom
- end
-
def config
# The result of this method must not be cached, as other methods may use
# it after making configuration changes and expect those changes to be
@@ -48,7 +32,7 @@ module Gitlab
end
def pool_size
- config[:pool] || default_pool_size
+ config[:pool] || Database.default_pool_size
end
def username
@@ -77,7 +61,9 @@ module Gitlab
def db_config_with_default_pool_size
db_config_object = scope.connection_db_config
- config = db_config_object.configuration_hash.merge(pool: default_pool_size)
+ config = db_config_object
+ .configuration_hash
+ .merge(pool: Database.default_pool_size)
ActiveRecord::DatabaseConfigurations::HashConfig.new(
db_config_object.env_name,
diff --git a/lib/gitlab/database/load_balancing.rb b/lib/gitlab/database/load_balancing.rb
index 65c35b5aaf2..d4f168ba188 100644
--- a/lib/gitlab/database/load_balancing.rb
+++ b/lib/gitlab/database/load_balancing.rb
@@ -36,94 +36,42 @@ module Gitlab
# Returns a Hash containing the load balancing configuration.
def self.configuration
- Gitlab::Database.main.config[:load_balancing] || {}
- end
-
- # Returns the maximum replica lag size in bytes.
- def self.max_replication_difference
- (configuration['max_replication_difference'] || 8.megabytes).to_i
- end
-
- # Returns the maximum lag time for a replica.
- def self.max_replication_lag_time
- (configuration['max_replication_lag_time'] || 60.0).to_f
- end
-
- # Returns the interval (in seconds) to use for checking the status of a
- # replica.
- def self.replica_check_interval
- (configuration['replica_check_interval'] || 60).to_f
- end
-
- # Returns the additional hosts to use for load balancing.
- def self.hosts
- configuration['hosts'] || []
- end
-
- def self.service_discovery_enabled?
- configuration.dig('discover', 'record').present?
- end
-
- def self.service_discovery_configuration
- conf = configuration['discover'] || {}
-
- {
- nameserver: conf['nameserver'] || 'localhost',
- port: conf['port'] || 8600,
- record: conf['record'],
- record_type: conf['record_type'] || 'A',
- interval: conf['interval'] || 60,
- disconnect_timeout: conf['disconnect_timeout'] || 120,
- use_tcp: conf['use_tcp'] || false
- }
- end
-
- def self.pool_size
- Gitlab::Database.main.pool_size
+ @configuration ||= Configuration.for_model(ActiveRecord::Base)
end
# Returns true if load balancing is to be enabled.
def self.enable?
return false if Gitlab::Runtime.rake?
- return false unless self.configured?
- true
+ configured?
end
- # Returns true if load balancing has been configured. Since
- # Sidekiq does not currently use load balancing, we
- # may want Web application servers to detect replication lag by
- # posting the write location of the database if load balancing is
- # configured.
def self.configured?
- hosts.any? || service_discovery_enabled?
+ configuration.load_balancing_enabled? ||
+ configuration.service_discovery_enabled?
end
def self.start_service_discovery
- return unless service_discovery_enabled?
+ return unless configuration.service_discovery_enabled?
ServiceDiscovery
- .new(proxy.load_balancer, **service_discovery_configuration)
+ .new(proxy.load_balancer, **configuration.service_discovery)
.start
end
# Configures proxying of requests.
def self.configure_proxy
- lb = LoadBalancer.new(hosts, primary_only: !enable?)
+ lb = LoadBalancer.new(configuration, primary_only: !enable?)
ActiveRecord::Base.load_balancing_proxy = ConnectionProxy.new(lb)
# Populate service discovery immediately if it is configured
- if service_discovery_enabled?
+ if configuration.service_discovery_enabled?
ServiceDiscovery
- .new(lb, **service_discovery_configuration)
+ .new(lb, **configuration.service_discovery)
.perform_service_discovery
end
end
- def self.active_record_models
- ActiveRecord::Base.descendants
- end
-
DB_ROLES = [
ROLE_PRIMARY = :primary,
ROLE_REPLICA = :replica,
diff --git a/lib/gitlab/database/load_balancing/configuration.rb b/lib/gitlab/database/load_balancing/configuration.rb
new file mode 100644
index 00000000000..6bd94bad5cf
--- /dev/null
+++ b/lib/gitlab/database/load_balancing/configuration.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module LoadBalancing
+ # Configuration settings for a single LoadBalancer instance.
+ class Configuration
+ attr_accessor :hosts, :max_replication_difference,
+ :max_replication_lag_time, :replica_check_interval,
+ :service_discovery, :pool_size, :model
+
+ # Creates a configuration object for the given ActiveRecord model.
+ def self.for_model(model)
+ cfg = model.connection_db_config.configuration_hash
+ lb_cfg = cfg[:load_balancing] || {}
+ config = new(model)
+
+ if (size = cfg[:pool])
+ config.pool_size = size
+ end
+
+ if (diff = lb_cfg[:max_replication_difference])
+ config.max_replication_difference = diff
+ end
+
+ if (lag = lb_cfg[:max_replication_lag_time])
+ config.max_replication_lag_time = lag.to_f
+ end
+
+ if (interval = lb_cfg[:replica_check_interval])
+ config.replica_check_interval = interval.to_f
+ end
+
+ if (hosts = lb_cfg[:hosts])
+ config.hosts = hosts
+ end
+
+ discover = (lb_cfg[:discover] || {}).symbolize_keys
+
+ # We iterate over the known/default keys so we don't end up with
+ # random keys in our configuration hash.
+ config.service_discovery.each do |key, _|
+ if (value = discover[key])
+ config.service_discovery[key] = value
+ end
+ end
+
+ config
+ end
+
+ def initialize(model, hosts = [])
+ @max_replication_difference = 8.megabytes
+ @max_replication_lag_time = 60.0
+ @replica_check_interval = 60.0
+ @model = model
+ @hosts = hosts
+ @pool_size = Database.default_pool_size
+ @service_discovery = {
+ nameserver: 'localhost',
+ port: 8600,
+ record: nil,
+ record_type: 'A',
+ interval: 60,
+ disconnect_timeout: 120,
+ use_tcp: false
+ }
+ end
+
+ def load_balancing_enabled?
+ hosts.any? || service_discovery_enabled?
+ end
+
+ def service_discovery_enabled?
+ service_discovery[:record].present?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/load_balancing/host.rb b/lib/gitlab/database/load_balancing/host.rb
index 4c5357ae8e3..670a373ded1 100644
--- a/lib/gitlab/database/load_balancing/host.rb
+++ b/lib/gitlab/database/load_balancing/host.rb
@@ -29,11 +29,15 @@ module Gitlab
@host = host
@port = port
@load_balancer = load_balancer
- @pool = load_balancer.create_replica_connection_pool(::Gitlab::Database::LoadBalancing.pool_size, host, port)
+ @pool = load_balancer.create_replica_connection_pool(
+ load_balancer.configuration.pool_size,
+ host,
+ port
+ )
@online = true
@last_checked_at = Time.zone.now
- interval = ::Gitlab::Database::LoadBalancing.replica_check_interval
+ interval = load_balancer.configuration.replica_check_interval
@intervals = (interval..(interval * 2)).step(0.5).to_a
end
@@ -108,7 +112,7 @@ module Gitlab
def replication_lag_below_threshold?
if (lag_time = replication_lag_time)
- lag_time <= ::Gitlab::Database::LoadBalancing.max_replication_lag_time
+ lag_time <= load_balancer.configuration.max_replication_lag_time
else
false
end
@@ -125,7 +129,7 @@ module Gitlab
# only do this if we haven't replicated in a while so we only need
# to connect to the primary when truly necessary.
if (lag_size = replication_lag_size)
- lag_size <= ::Gitlab::Database::LoadBalancing.max_replication_difference
+ lag_size <= load_balancer.configuration.max_replication_difference
else
false
end
diff --git a/lib/gitlab/database/load_balancing/load_balancer.rb b/lib/gitlab/database/load_balancing/load_balancer.rb
index cdaeebde4df..0fb8faae8ce 100644
--- a/lib/gitlab/database/load_balancing/load_balancer.rb
+++ b/lib/gitlab/database/load_balancing/load_balancer.rb
@@ -12,20 +12,21 @@ module Gitlab
REPLICA_SUFFIX = '_replica'
- attr_reader :host_list
+ attr_reader :host_list, :configuration
- # hosts - The hostnames/addresses of the additional databases.
- # model - The ActiveRecord base model the load balancer is enabled for.
+ # configuration - An instance of `LoadBalancing::Configuration` that
+ # contains the configuration details (such as the hosts)
+ # for this load balancer.
# primary_only - If set, the replicas are ignored and the primary is
# always used.
- def initialize(hosts = [], model = ActiveRecord::Base, primary_only: false)
+ def initialize(configuration, primary_only: false)
+ @configuration = configuration
@primary_only = primary_only
- @model = model
@host_list =
if primary_only
HostList.new([PrimaryHost.new(self)])
else
- HostList.new(hosts.map { |addr| Host.new(addr, self) })
+ HostList.new(configuration.hosts.map { |addr| Host.new(addr, self) })
end
end
@@ -231,7 +232,7 @@ module Gitlab
# leverage that.
def pool
ActiveRecord::Base.connection_handler.retrieve_connection_pool(
- @model.connection_specification_name,
+ @configuration.model.connection_specification_name,
role: ActiveRecord::Base.writing_role,
shard: ActiveRecord::Base.default_shard
)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index f0ed6be6962..f4944017380 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -13938,9 +13938,6 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
-msgid "Failed to load sidebar lock status"
-msgstr ""
-
msgid "Failed to load stacktrace."
msgstr ""
@@ -30659,6 +30656,9 @@ msgstr ""
msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
msgstr ""
+msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
+msgstr ""
+
msgid "Set the due date to %{due_date}."
msgstr ""
@@ -33334,9 +33334,6 @@ msgstr ""
msgid "The default branch for this project has been changed. Please update your bookmarks."
msgstr ""
-msgid "The default expiration time for job artifacts. 0 for unlimited. The default unit is in seconds, but you can use other units, for example %{code_open}4 mins 2 sec%{code_close}, %{code_open}2h42min%{code_close}."
-msgstr ""
-
msgid "The dependency list details information about the components used within your project."
msgstr ""
@@ -36156,6 +36153,9 @@ msgstr ""
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
+msgid "UsageQuota|%{linkTitle} help link"
+msgstr ""
+
msgid "UsageQuota|%{percentageLeft} of purchased storage is available"
msgstr ""
@@ -36165,6 +36165,9 @@ msgstr ""
msgid "UsageQuota|Artifacts is a sum of build and pipeline artifacts."
msgstr ""
+msgid "UsageQuota|Audio samples, videos, datasets, and graphics."
+msgstr ""
+
msgid "UsageQuota|Buy additional minutes"
msgstr ""
@@ -36174,9 +36177,21 @@ msgstr ""
msgid "UsageQuota|CI minutes usage by project"
msgstr ""
+msgid "UsageQuota|Code packages and container images."
+msgstr ""
+
msgid "UsageQuota|Current period usage"
msgstr ""
+msgid "UsageQuota|File attachments and smaller design graphics."
+msgstr ""
+
+msgid "UsageQuota|Git repository, managed by the Gitaly service."
+msgstr ""
+
+msgid "UsageQuota|Includes project registry, artifacts, packages, wiki, uploads and other items."
+msgstr ""
+
msgid "UsageQuota|Increase storage temporarily"
msgstr ""
@@ -36195,6 +36210,9 @@ msgstr ""
msgid "UsageQuota|Packages"
msgstr ""
+msgid "UsageQuota|Pipeline artifacts and job artifacts, created with CI/CD."
+msgstr ""
+
msgid "UsageQuota|Pipelines"
msgstr ""
@@ -36213,6 +36231,9 @@ msgstr ""
msgid "UsageQuota|Seats"
msgstr ""
+msgid "UsageQuota|Shared bits of code and text."
+msgstr ""
+
msgid "UsageQuota|Snippets"
msgstr ""
@@ -36222,6 +36243,12 @@ msgstr ""
msgid "UsageQuota|Storage"
msgstr ""
+msgid "UsageQuota|Storage type"
+msgstr ""
+
+msgid "UsageQuota|There is a known issue with Artifact storage where the total could be incorrect for some projects. More details and progress are available in %{warningLinkStart}the epic%{warningLinkEnd}."
+msgstr ""
+
msgid "UsageQuota|This is the total amount of storage used across your projects within this namespace."
msgstr ""
@@ -36261,6 +36288,9 @@ msgstr ""
msgid "UsageQuota|Usage"
msgstr ""
+msgid "UsageQuota|Usage Breakdown"
+msgstr ""
+
msgid "UsageQuota|Usage Quotas"
msgstr ""
@@ -36285,6 +36315,9 @@ msgstr ""
msgid "UsageQuota|Wiki"
msgstr ""
+msgid "UsageQuota|Wiki content."
+msgstr ""
+
msgid "UsageQuota|Wikis"
msgstr ""
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb
index b66bdba7af7..1a2d450f7eb 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb
@@ -58,14 +58,12 @@ module QA
end
before do
- Runtime::Feature.enable(:pipeline_editor_branch_switcher)
Flow::Login.sign_in
project.visit!
Page::Project::Menu.perform(&:go_to_pipeline_editor)
end
after do
- Runtime::Feature.disable(:pipeline_editor_branch_switcher)
project.remove_via_api!
Page::Main::Menu.perform(&:sign_out)
end
diff --git a/spec/features/merge_request/batch_comments_spec.rb b/spec/features/merge_request/batch_comments_spec.rb
index c646698219b..f695b225915 100644
--- a/spec/features/merge_request/batch_comments_spec.rb
+++ b/spec/features/merge_request/batch_comments_spec.rb
@@ -25,10 +25,6 @@ RSpec.describe 'Merge request > Batch comments', :js do
visit_diffs
end
- it 'has review bar' do
- expect(page).to have_selector('[data-testid="review_bar_component"]', visible: false)
- end
-
it 'adds draft note' do
write_diff_comment
diff --git a/spec/features/projects/ci/editor_spec.rb b/spec/features/projects/ci/editor_spec.rb
index 192bccd6f6e..7fe1c63f490 100644
--- a/spec/features/projects/ci/editor_spec.rb
+++ b/spec/features/projects/ci/editor_spec.rb
@@ -27,10 +27,6 @@ RSpec.describe 'Pipeline Editor', :js do
end
context 'branch switcher' do
- before do
- stub_feature_flags(pipeline_editor_branch_switcher: true)
- end
-
def switch_to_branch(branch)
find('[data-testid="branch-selector"]').click
diff --git a/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js b/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
index 94a0a7d14ee..e24de832d6d 100644
--- a/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
+++ b/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
@@ -4,16 +4,10 @@ import PipelineEditorFileNav from '~/pipeline_editor/components/file_nav/pipelin
describe('Pipeline editor file nav', () => {
let wrapper;
- const mockProvide = {
- glFeatures: {
- pipelineEditorBranchSwitcher: true,
- },
- };
const createComponent = ({ provide = {} } = {}) => {
wrapper = shallowMount(PipelineEditorFileNav, {
provide: {
- ...mockProvide,
...provide,
},
});
@@ -34,16 +28,4 @@ describe('Pipeline editor file nav', () => {
expect(findBranchSwitcher().exists()).toBe(true);
});
});
-
- describe('with branch switcher feature flag OFF', () => {
- it('does not render the branch switcher', () => {
- createComponent({
- provide: {
- glFeatures: { pipelineEditorBranchSwitcher: false },
- },
- });
-
- expect(findBranchSwitcher().exists()).toBe(false);
- });
- });
});
diff --git a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js
index 76c68e21180..b019bae886c 100644
--- a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js
+++ b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js
@@ -7,7 +7,6 @@ describe('Pipeline editor empty state', () => {
let wrapper;
const defaultProvide = {
glFeatures: {
- pipelineEditorBranchSwitcher: true,
pipelineEditorEmptyStateAction: false,
},
emptyStateIllustrationPath: 'my/svg/path',
@@ -82,17 +81,5 @@ describe('Pipeline editor empty state', () => {
await findConfirmButton().vm.$emit('click');
expect(wrapper.emitted(expectedEvent)).toHaveLength(1);
});
-
- describe('with branch switcher feature flag OFF', () => {
- it('does not render the file nav', () => {
- createComponent({
- provide: {
- glFeatures: { pipelineEditorBranchSwitcher: false },
- },
- });
-
- expect(findFileNav().exists()).toBe(false);
- });
- });
});
});
diff --git a/spec/frontend/pipelines/__snapshots__/parsing_utils_spec.js.snap b/spec/frontend/pipelines/__snapshots__/utils_spec.js.snap
index 60625d301c0..60625d301c0 100644
--- a/spec/frontend/pipelines/__snapshots__/parsing_utils_spec.js.snap
+++ b/spec/frontend/pipelines/__snapshots__/utils_spec.js.snap
diff --git a/spec/frontend/pipelines/parsing_utils_spec.js b/spec/frontend/pipelines/utils_spec.js
index 3a270c1c1b5..1c23a7e4fcf 100644
--- a/spec/frontend/pipelines/parsing_utils_spec.js
+++ b/spec/frontend/pipelines/utils_spec.js
@@ -1,6 +1,5 @@
import { createSankey } from '~/pipelines/components/dag/drawing_utils';
import {
- createNodeDict,
makeLinksFromNodes,
filterByAncestors,
generateColumnsFromLayersListBare,
@@ -9,6 +8,7 @@ import {
removeOrphanNodes,
getMaxNodes,
} from '~/pipelines/components/parsing_utils';
+import { createNodeDict } from '~/pipelines/utils';
import { mockParsedGraphQLNodes, missingJob } from './components/dag/mock_data';
import { generateResponse, mockPipelineResponse } from './graph/mock_data';
diff --git a/spec/frontend/projects/storage_counter/app_spec.js b/spec/frontend/projects/storage_counter/app_spec.js
deleted file mode 100644
index db099527015..00000000000
--- a/spec/frontend/projects/storage_counter/app_spec.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import { GlAlert } from '@gitlab/ui';
-import { shallowMount, createLocalVue } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import StorageCounterApp from '~/projects/storage_counter/components/app.vue';
-import getProjectStorageCount from '~/projects/storage_counter/queries/project_storage.query.graphql';
-import UsageGraph from '~/vue_shared/components/storage_counter/usage_graph.vue';
-import { projectStorageCountResponse } from './mock_data';
-
-const localVue = createLocalVue();
-
-describe('Storage counter app', () => {
- let wrapper;
-
- const createMockApolloProvider = ({ mutationMock }) => {
- localVue.use(VueApollo);
-
- const requestHandlers = [[getProjectStorageCount, mutationMock]];
-
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = ({ provide = {}, mockApollo } = {}) => {
- const defaultProvideValues = {
- projectPath: 'test-project',
- };
-
- wrapper = shallowMount(StorageCounterApp, {
- localVue,
- apolloProvider: mockApollo,
- provide: {
- ...defaultProvideValues,
- ...provide,
- },
- });
- };
-
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findUsageGraph = () => wrapper.findComponent(UsageGraph);
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders app successfully', () => {
- expect(wrapper.text()).toBe('Usage');
- });
-
- describe('handling apollo fetching error', () => {
- const mutationMock = jest.fn().mockRejectedValue(new Error('GraphQL error'));
-
- beforeEach(() => {
- const mockApollo = createMockApolloProvider({ mutationMock });
- createComponent({ mockApollo });
- });
-
- it('renders gl-alert if there is an error', () => {
- expect(findAlert().exists()).toBe(true);
- });
- });
-
- describe('rendering <usage-graph />', () => {
- const mutationMock = jest.fn().mockResolvedValue(projectStorageCountResponse);
-
- beforeEach(() => {
- const mockApollo = createMockApolloProvider({ mutationMock });
- createComponent({ mockApollo });
- });
-
- it('renders usage-graph component if project.statistics exists', () => {
- expect(findUsageGraph().exists()).toBe(true);
- });
-
- it('passes project.statistics to usage-graph component', () => {
- const { __typename, ...statistics } = projectStorageCountResponse.data.project.statistics;
- expect(findUsageGraph().props('rootStorageStatistics')).toMatchObject(statistics);
- });
- });
-});
diff --git a/spec/frontend/projects/storage_counter/components/app_spec.js b/spec/frontend/projects/storage_counter/components/app_spec.js
new file mode 100644
index 00000000000..f3da01e0602
--- /dev/null
+++ b/spec/frontend/projects/storage_counter/components/app_spec.js
@@ -0,0 +1,150 @@
+import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import StorageCounterApp from '~/projects/storage_counter/components/app.vue';
+import { TOTAL_USAGE_DEFAULT_TEXT } from '~/projects/storage_counter/constants';
+import getProjectStorageCount from '~/projects/storage_counter/queries/project_storage.query.graphql';
+import UsageGraph from '~/vue_shared/components/storage_counter/usage_graph.vue';
+import {
+ mockGetProjectStorageCountGraphQLResponse,
+ mockEmptyResponse,
+ projectData,
+ defaultProvideValues,
+} from '../mock_data';
+
+const localVue = createLocalVue();
+localVue.use(VueApollo);
+
+describe('Storage counter app', () => {
+ let wrapper;
+
+ const createMockApolloProvider = ({ reject = false, mockedValue } = {}) => {
+ let response;
+
+ if (reject) {
+ response = jest.fn().mockRejectedValue(mockedValue || new Error('GraphQL error'));
+ } else {
+ response = jest.fn().mockResolvedValue(mockedValue);
+ }
+
+ const requestHandlers = [[getProjectStorageCount, response]];
+
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = ({ provide = {}, mockApollo } = {}) => {
+ wrapper = extendedWrapper(
+ shallowMount(StorageCounterApp, {
+ localVue,
+ apolloProvider: mockApollo,
+ provide: {
+ ...defaultProvideValues,
+ ...provide,
+ },
+ }),
+ );
+ };
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findUsagePercentage = () => wrapper.findByTestId('total-usage');
+ const findUsageQuotasHelpLink = () => wrapper.findByTestId('usage-quotas-help-link');
+ const findUsageGraph = () => wrapper.findComponent(UsageGraph);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('with apollo fetching successful', () => {
+ let mockApollo;
+
+ beforeEach(async () => {
+ mockApollo = createMockApolloProvider({
+ mockedValue: mockGetProjectStorageCountGraphQLResponse,
+ });
+ createComponent({ mockApollo });
+ await waitForPromises();
+ });
+
+ it('renders correct total usage', () => {
+ expect(findUsagePercentage().text()).toBe(projectData.storage.totalUsage);
+ });
+
+ it('renders correct usage quotas help link', () => {
+ expect(findUsageQuotasHelpLink().attributes('href')).toBe(
+ defaultProvideValues.helpLinks.usageQuotasHelpPagePath,
+ );
+ });
+ });
+
+ describe('with apollo loading', () => {
+ let mockApollo;
+
+ beforeEach(() => {
+ mockApollo = createMockApolloProvider({
+ mockedValue: new Promise(() => {}),
+ });
+ createComponent({ mockApollo });
+ });
+
+ it('should show loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('with apollo returning empty data', () => {
+ let mockApollo;
+
+ beforeEach(async () => {
+ mockApollo = createMockApolloProvider({
+ mockedValue: mockEmptyResponse,
+ });
+ createComponent({ mockApollo });
+ await waitForPromises();
+ });
+
+ it('shows default text for total usage', () => {
+ expect(findUsagePercentage().text()).toBe(TOTAL_USAGE_DEFAULT_TEXT);
+ });
+ });
+
+ describe('with apollo fetching error', () => {
+ let mockApollo;
+
+ beforeEach(() => {
+ mockApollo = createMockApolloProvider();
+ createComponent({ mockApollo, reject: true });
+ });
+
+ it('renders gl-alert', () => {
+ expect(findAlert().exists()).toBe(true);
+ });
+ });
+
+ describe('rendering <usage-graph />', () => {
+ let mockApollo;
+
+ beforeEach(async () => {
+ mockApollo = createMockApolloProvider({
+ mockedValue: mockGetProjectStorageCountGraphQLResponse,
+ });
+ createComponent({ mockApollo });
+ await waitForPromises();
+ });
+
+ it('renders usage-graph component if project.statistics exists', () => {
+ expect(findUsageGraph().exists()).toBe(true);
+ });
+
+ it('passes project.statistics to usage-graph component', () => {
+ const {
+ __typename,
+ ...statistics
+ } = mockGetProjectStorageCountGraphQLResponse.data.project.statistics;
+ expect(findUsageGraph().props('rootStorageStatistics')).toMatchObject(statistics);
+ });
+ });
+});
diff --git a/spec/frontend/projects/storage_counter/components/storage_table_spec.js b/spec/frontend/projects/storage_counter/components/storage_table_spec.js
new file mode 100644
index 00000000000..14298318fff
--- /dev/null
+++ b/spec/frontend/projects/storage_counter/components/storage_table_spec.js
@@ -0,0 +1,62 @@
+import { GlTable } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import StorageTable from '~/projects/storage_counter/components/storage_table.vue';
+import { projectData, defaultProvideValues } from '../mock_data';
+
+describe('StorageTable', () => {
+ let wrapper;
+
+ const defaultProps = {
+ storageTypes: projectData.storage.storageTypes,
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = extendedWrapper(
+ mount(StorageTable, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ }),
+ );
+ };
+
+ const findTable = () => wrapper.findComponent(GlTable);
+
+ beforeEach(() => {
+ createComponent();
+ });
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('with storage types', () => {
+ it.each(projectData.storage.storageTypes)(
+ 'renders table row correctly %o',
+ ({ storageType: { id, name, description } }) => {
+ expect(wrapper.findByTestId(`${id}-name`).text()).toBe(name);
+ expect(wrapper.findByTestId(`${id}-description`).text()).toBe(description);
+ expect(wrapper.findByTestId(`${id}-help-link`).attributes('href')).toBe(
+ defaultProvideValues.helpLinks[id.replace(`Size`, `HelpPagePath`)]
+ .replace(`Size`, ``)
+ .replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`),
+ );
+ },
+ );
+ });
+
+ describe('without storage types', () => {
+ beforeEach(() => {
+ createComponent({ storageTypes: [] });
+ });
+
+ it('should render the table header <th>', () => {
+ expect(findTable().find('th').exists()).toBe(true);
+ });
+
+ it('should not render any table data <td>', () => {
+ expect(findTable().find('td').exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/projects/storage_counter/mock_data.js b/spec/frontend/projects/storage_counter/mock_data.js
index 27c576a0619..a7e19e679d2 100644
--- a/spec/frontend/projects/storage_counter/mock_data.js
+++ b/spec/frontend/projects/storage_counter/mock_data.js
@@ -1,19 +1,108 @@
-export const projectStorageCountResponse = {
+export const mockGetProjectStorageCountGraphQLResponse = {
data: {
project: {
id: 'gid://gitlab/Project/20',
statistics: {
- buildArtifactsSize: 400000,
- lfsObjectsSize: 4800000,
- packagesSize: 3800000,
- repositorySize: 39000000,
- snippetsSize: 0,
- storageSize: 39930000,
- uploadsSize: 0,
- wikiSize: 300000,
+ buildArtifactsSize: 400000.0,
+ lfsObjectsSize: 4800000.0,
+ packagesSize: 3800000.0,
+ repositorySize: 3900000.0,
+ snippetsSize: 1200000.0,
+ storageSize: 15300000.0,
+ uploadsSize: 900000.0,
+ wikiSize: 300000.0,
__typename: 'ProjectStatistics',
},
__typename: 'Project',
},
},
};
+
+export const mockEmptyResponse = { data: { project: null } };
+
+export const defaultProvideValues = {
+ projectPath: '/project-path',
+ helpLinks: {
+ usageQuotasHelpPagePath: '/usage-quotas',
+ buildArtifactsHelpPagePath: '/build-artifacts',
+ lfsObjectsHelpPagePath: '/lsf-objects',
+ packagesHelpPagePath: '/packages',
+ repositoryHelpPagePath: '/repository',
+ snippetsHelpPagePath: '/snippets',
+ uploadsHelpPagePath: '/uploads',
+ wikiHelpPagePath: '/wiki',
+ },
+};
+
+export const projectData = {
+ storage: {
+ totalUsage: '14.6 MiB',
+ storageTypes: [
+ {
+ storageType: {
+ id: 'buildArtifactsSize',
+ name: 'Artifacts',
+ description: 'Pipeline artifacts and job artifacts, created with CI/CD.',
+ warningMessage:
+ 'There is a known issue with Artifact storage where the total could be incorrect for some projects. More details and progress are available in %{warningLinkStart}the epic%{warningLinkEnd}.',
+ helpPath: '/build-artifacts',
+ },
+ value: '390.6 KiB',
+ },
+ {
+ storageType: {
+ id: 'lfsObjectsSize',
+ name: 'LFS Storage',
+ description: 'Audio samples, videos, datasets, and graphics.',
+ helpPath: '/lsf-objects',
+ },
+ value: '4.6 MiB',
+ },
+ {
+ storageType: {
+ id: 'packagesSize',
+ name: 'Packages',
+ description: 'Code packages and container images.',
+ helpPath: '/packages',
+ },
+ value: '3.6 MiB',
+ },
+ {
+ storageType: {
+ id: 'repositorySize',
+ name: 'Repository',
+ description: 'Git repository, managed by the Gitaly service.',
+ helpPath: '/repository',
+ },
+ value: '3.7 MiB',
+ },
+ {
+ storageType: {
+ id: 'snippetsSize',
+ name: 'Snippets',
+ description: 'Shared bits of code and text.',
+ helpPath: '/snippets',
+ },
+ value: '1.1 MiB',
+ },
+ {
+ storageType: {
+ id: 'uploadsSize',
+ name: 'Uploads',
+ description: 'File attachments and smaller design graphics.',
+ helpPath: '/uploads',
+ },
+ value: '878.9 KiB',
+ },
+ {
+ storageType: {
+ id: 'wikiSize',
+ name: 'Wiki',
+ description: 'Wiki content.',
+ helpPath: '/wiki',
+ },
+ value: '293.0 KiB',
+ },
+ ],
+ },
+};
diff --git a/spec/frontend/projects/storage_counter/utils_spec.js b/spec/frontend/projects/storage_counter/utils_spec.js
new file mode 100644
index 00000000000..57c755266a0
--- /dev/null
+++ b/spec/frontend/projects/storage_counter/utils_spec.js
@@ -0,0 +1,17 @@
+import { parseGetProjectStorageResults } from '~/projects/storage_counter/utils';
+import {
+ mockGetProjectStorageCountGraphQLResponse,
+ projectData,
+ defaultProvideValues,
+} from './mock_data';
+
+describe('parseGetProjectStorageResults', () => {
+ it('parses project statistics correctly', () => {
+ expect(
+ parseGetProjectStorageResults(
+ mockGetProjectStorageCountGraphQLResponse.data,
+ defaultProvideValues.helpLinks,
+ ),
+ ).toMatchObject(projectData);
+ });
+});
diff --git a/spec/lib/gitlab/database/connection_spec.rb b/spec/lib/gitlab/database/connection_spec.rb
index 4d1e78fe425..7f94d7af4a9 100644
--- a/spec/lib/gitlab/database/connection_spec.rb
+++ b/spec/lib/gitlab/database/connection_spec.rb
@@ -5,29 +5,14 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::Connection do
let(:connection) { described_class.new }
- describe '#default_pool_size' do
- before do
- allow(Gitlab::Runtime).to receive(:max_threads).and_return(7)
- end
-
- it 'returns the max thread size plus a fixed headroom of 10' do
- expect(connection.default_pool_size).to eq(17)
- end
-
- it 'returns the max thread size plus a DB_POOL_HEADROOM if this env var is present' do
- stub_env('DB_POOL_HEADROOM', '7')
-
- expect(connection.default_pool_size).to eq(14)
- end
- end
-
describe '#config' do
it 'returns a HashWithIndifferentAccess' do
expect(connection.config).to be_an_instance_of(HashWithIndifferentAccess)
end
it 'returns a default pool size' do
- expect(connection.config).to include(pool: connection.default_pool_size)
+ expect(connection.config)
+ .to include(pool: Gitlab::Database.default_pool_size)
end
it 'does not cache its results' do
@@ -43,7 +28,7 @@ RSpec.describe Gitlab::Database::Connection do
it 'returns the default pool size' do
expect(connection).to receive(:config).and_return({ pool: nil })
- expect(connection.pool_size).to eq(connection.default_pool_size)
+ expect(connection.pool_size).to eq(Gitlab::Database.default_pool_size)
end
end
@@ -129,7 +114,7 @@ RSpec.describe Gitlab::Database::Connection do
describe '#db_config_with_default_pool_size' do
it 'returns db_config with our default pool size' do
- allow(connection).to receive(:default_pool_size).and_return(9)
+ allow(Gitlab::Database).to receive(:default_pool_size).and_return(9)
expect(connection.db_config_with_default_pool_size.pool).to eq(9)
end
diff --git a/spec/lib/gitlab/database/load_balancing/configuration_spec.rb b/spec/lib/gitlab/database/load_balancing/configuration_spec.rb
new file mode 100644
index 00000000000..d4843d873bb
--- /dev/null
+++ b/spec/lib/gitlab/database/load_balancing/configuration_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::LoadBalancing::Configuration do
+ describe '.for_model' do
+ let(:model) do
+ config = ActiveRecord::DatabaseConfigurations::HashConfig
+ .new('main', 'test', configuration_hash)
+
+ double(:model, connection_db_config: config)
+ end
+
+ context 'when load balancing is not configured' do
+ let(:configuration_hash) { {} }
+
+ it 'uses the default settings' do
+ config = described_class.for_model(model)
+
+ expect(config.hosts).to eq([])
+ expect(config.max_replication_difference).to eq(8.megabytes)
+ expect(config.max_replication_lag_time).to eq(60.0)
+ expect(config.replica_check_interval).to eq(60.0)
+ expect(config.service_discovery).to eq(
+ nameserver: 'localhost',
+ port: 8600,
+ record: nil,
+ record_type: 'A',
+ interval: 60,
+ disconnect_timeout: 120,
+ use_tcp: false
+ )
+ expect(config.pool_size).to eq(Gitlab::Database.default_pool_size)
+ end
+ end
+
+ context 'when load balancing is configured' do
+ let(:configuration_hash) do
+ {
+ pool: 4,
+ load_balancing: {
+ max_replication_difference: 1,
+ max_replication_lag_time: 2,
+ replica_check_interval: 3,
+ hosts: %w[foo bar],
+ discover: {
+ 'record' => 'foo.example.com'
+ }
+ }
+ }
+ end
+
+ it 'uses the custom configuration settings' do
+ config = described_class.for_model(model)
+
+ expect(config.hosts).to eq(%w[foo bar])
+ expect(config.max_replication_difference).to eq(1)
+ expect(config.max_replication_lag_time).to eq(2.0)
+ expect(config.replica_check_interval).to eq(3.0)
+ expect(config.service_discovery).to eq(
+ nameserver: 'localhost',
+ port: 8600,
+ record: 'foo.example.com',
+ record_type: 'A',
+ interval: 60,
+ disconnect_timeout: 120,
+ use_tcp: false
+ )
+ expect(config.pool_size).to eq(4)
+ end
+ end
+ end
+
+ describe '#load_balancing_enabled?' do
+ it 'returns true when hosts are configured' do
+ config = described_class.new(ActiveRecord::Base, %w[foo bar])
+
+ expect(config.load_balancing_enabled?).to eq(true)
+ end
+
+ it 'returns true when a service discovery record is configured' do
+ config = described_class.new(ActiveRecord::Base)
+ config.service_discovery[:record] = 'foo'
+
+ expect(config.load_balancing_enabled?).to eq(true)
+ end
+
+ it 'returns false when no hosts are configured and service discovery is disabled' do
+ config = described_class.new(ActiveRecord::Base)
+
+ expect(config.load_balancing_enabled?).to eq(false)
+ end
+ end
+
+ describe '#service_discovery_enabled?' do
+ it 'returns true when a record is configured' do
+ config = described_class.new(ActiveRecord::Base)
+ config.service_discovery[:record] = 'foo'
+
+ expect(config.service_discovery_enabled?).to eq(true)
+ end
+
+ it 'returns false when no record is configured' do
+ config = described_class.new(ActiveRecord::Base)
+
+ expect(config.service_discovery_enabled?).to eq(false)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb b/spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb
index 52c3d49086c..ba2f9485066 100644
--- a/spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb
@@ -4,7 +4,10 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::ConnectionProxy do
let(:proxy) do
- described_class.new(Gitlab::Database::LoadBalancing::LoadBalancer.new([]))
+ config = Gitlab::Database::LoadBalancing::Configuration
+ .new(ActiveRecord::Base)
+
+ described_class.new(Gitlab::Database::LoadBalancing::LoadBalancer.new(config))
end
describe '#select' do
diff --git a/spec/lib/gitlab/database/load_balancing/host_list_spec.rb b/spec/lib/gitlab/database/load_balancing/host_list_spec.rb
index ad4ca18d5e6..9bb8116c434 100644
--- a/spec/lib/gitlab/database/load_balancing/host_list_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/host_list_spec.rb
@@ -4,7 +4,12 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::HostList do
let(:db_host) { ActiveRecord::Base.connection_pool.db_config.host }
- let(:load_balancer) { double(:load_balancer) }
+ let(:load_balancer) do
+ Gitlab::Database::LoadBalancing::LoadBalancer.new(
+ Gitlab::Database::LoadBalancing::Configuration.new(ActiveRecord::Base)
+ )
+ end
+
let(:host_count) { 2 }
let(:hosts) { Array.new(host_count) { Gitlab::Database::LoadBalancing::Host.new(db_host, load_balancer, port: 5432) } }
let(:host_list) { described_class.new(hosts) }
diff --git a/spec/lib/gitlab/database/load_balancing/host_spec.rb b/spec/lib/gitlab/database/load_balancing/host_spec.rb
index f42ac8be1bb..e2011692228 100644
--- a/spec/lib/gitlab/database/load_balancing/host_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/host_spec.rb
@@ -3,7 +3,10 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::Host do
- let(:load_balancer) { Gitlab::Database::LoadBalancing::LoadBalancer.new }
+ let(:load_balancer) do
+ Gitlab::Database::LoadBalancing::LoadBalancer
+ .new(Gitlab::Database::LoadBalancing::Configuration.new(ActiveRecord::Base))
+ end
let(:host) do
Gitlab::Database::LoadBalancing::Host.new('localhost', load_balancer)
@@ -274,7 +277,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::Host do
end
it 'returns false when the data is not recent enough' do
- diff = Gitlab::Database::LoadBalancing.max_replication_difference * 2
+ diff = load_balancer.configuration.max_replication_difference * 2
expect(host)
.to receive(:query_and_release)
diff --git a/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb b/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
index 5d8440123e6..86fae14b961 100644
--- a/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
@@ -5,7 +5,12 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store do
let(:conflict_error) { Class.new(RuntimeError) }
let(:db_host) { ActiveRecord::Base.connection_pool.db_config.host }
- let(:lb) { described_class.new([db_host, db_host]) }
+ let(:config) do
+ Gitlab::Database::LoadBalancing::Configuration
+ .new(ActiveRecord::Base, [db_host, db_host])
+ end
+
+ let(:lb) { described_class.new(config) }
let(:request_cache) { lb.send(:request_cache) }
before do
@@ -43,7 +48,9 @@ RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store do
describe '#initialize' do
it 'ignores the hosts when the primary_only option is enabled' do
- lb = described_class.new([db_host], primary_only: true)
+ config = Gitlab::Database::LoadBalancing::Configuration
+ .new(ActiveRecord::Base, [db_host])
+ lb = described_class.new(config, primary_only: true)
hosts = lb.host_list.hosts
expect(hosts.length).to eq(1)
@@ -134,7 +141,9 @@ RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store do
end
it 'uses the primary when the primary_only option is enabled' do
- lb = described_class.new(primary_only: true)
+ config = Gitlab::Database::LoadBalancing::Configuration
+ .new(ActiveRecord::Base)
+ lb = described_class.new(config, primary_only: true)
# When no hosts are configured, we don't want to produce any warnings, as
# they aren't useful/too noisy.
@@ -174,8 +183,11 @@ RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store do
end
it 'does not create conflicts with other load balancers when caching hosts' do
- lb1 = described_class.new([db_host, db_host], ActiveRecord::Base)
- lb2 = described_class.new([db_host, db_host], Ci::CiDatabaseRecord)
+ ci_config = Gitlab::Database::LoadBalancing::Configuration
+ .new(Ci::CiDatabaseRecord, [db_host, db_host])
+
+ lb1 = described_class.new(config)
+ lb2 = described_class.new(ci_config)
host1 = lb1.host
host2 = lb2.host
diff --git a/spec/lib/gitlab/database/load_balancing/primary_host_spec.rb b/spec/lib/gitlab/database/load_balancing/primary_host_spec.rb
index a2f8e52db2f..92c07a489bb 100644
--- a/spec/lib/gitlab/database/load_balancing/primary_host_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/primary_host_spec.rb
@@ -3,7 +3,12 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::PrimaryHost do
- let(:load_balancer) { Gitlab::Database::LoadBalancing::LoadBalancer.new }
+ let(:load_balancer) do
+ Gitlab::Database::LoadBalancing::LoadBalancer.new(
+ Gitlab::Database::LoadBalancing::Configuration.new(ActiveRecord::Base)
+ )
+ end
+
let(:host) { Gitlab::Database::LoadBalancing::PrimaryHost.new(load_balancer) }
describe '#connection' do
diff --git a/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb b/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb
index c3f7cf5059f..e9bc465b1c7 100644
--- a/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb
@@ -3,7 +3,12 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery do
- let(:load_balancer) { Gitlab::Database::LoadBalancing::LoadBalancer.new([]) }
+ let(:load_balancer) do
+ Gitlab::Database::LoadBalancing::LoadBalancer.new(
+ Gitlab::Database::LoadBalancing::Configuration.new(ActiveRecord::Base)
+ )
+ end
+
let(:service) do
described_class.new(
load_balancer,
@@ -184,7 +189,10 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery do
let(:address_bar) { described_class::Address.new('bar') }
let(:load_balancer) do
- Gitlab::Database::LoadBalancing::LoadBalancer.new([address_foo])
+ Gitlab::Database::LoadBalancing::LoadBalancer.new(
+ Gitlab::Database::LoadBalancing::Configuration
+ .new(ActiveRecord::Base, [address_foo])
+ )
end
before do
@@ -307,7 +315,10 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery do
describe '#addresses_from_load_balancer' do
let(:load_balancer) do
- Gitlab::Database::LoadBalancing::LoadBalancer.new(%w[b a])
+ Gitlab::Database::LoadBalancing::LoadBalancer.new(
+ Gitlab::Database::LoadBalancing::Configuration
+ .new(ActiveRecord::Base, %w[b a])
+ )
end
it 'returns the ordered host names of the load balancer' do
diff --git a/spec/lib/gitlab/database/load_balancing_spec.rb b/spec/lib/gitlab/database/load_balancing_spec.rb
index c1df02cb584..f40ad444081 100644
--- a/spec/lib/gitlab/database/load_balancing_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing_spec.rb
@@ -40,106 +40,25 @@ RSpec.describe Gitlab::Database::LoadBalancing do
end
describe '.configuration' do
- it 'returns a Hash' do
- lb_config = { 'hosts' => %w(foo) }
+ it 'returns the configuration for the load balancer' do
+ raw = ActiveRecord::Base.connection_db_config.configuration_hash
+ cfg = described_class.configuration
- original_db_config = Gitlab::Database.main.config
- modified_db_config = original_db_config.merge(load_balancing: lb_config)
- expect(Gitlab::Database.main).to receive(:config).and_return(modified_db_config)
-
- expect(described_class.configuration).to eq(lb_config)
- end
- end
-
- describe '.max_replication_difference' do
- context 'without an explicitly configured value' do
- it 'returns the default value' do
- allow(described_class)
- .to receive(:configuration)
- .and_return({})
-
- expect(described_class.max_replication_difference).to eq(8.megabytes)
- end
- end
-
- context 'with an explicitly configured value' do
- it 'returns the configured value' do
- allow(described_class)
- .to receive(:configuration)
- .and_return({ 'max_replication_difference' => 4 })
-
- expect(described_class.max_replication_difference).to eq(4)
- end
- end
- end
-
- describe '.max_replication_lag_time' do
- context 'without an explicitly configured value' do
- it 'returns the default value' do
- allow(described_class)
- .to receive(:configuration)
- .and_return({})
-
- expect(described_class.max_replication_lag_time).to eq(60)
- end
- end
-
- context 'with an explicitly configured value' do
- it 'returns the configured value' do
- allow(described_class)
- .to receive(:configuration)
- .and_return({ 'max_replication_lag_time' => 4 })
-
- expect(described_class.max_replication_lag_time).to eq(4)
- end
- end
- end
-
- describe '.replica_check_interval' do
- context 'without an explicitly configured value' do
- it 'returns the default value' do
- allow(described_class)
- .to receive(:configuration)
- .and_return({})
-
- expect(described_class.replica_check_interval).to eq(60)
- end
- end
-
- context 'with an explicitly configured value' do
- it 'returns the configured value' do
- allow(described_class)
- .to receive(:configuration)
- .and_return({ 'replica_check_interval' => 4 })
-
- expect(described_class.replica_check_interval).to eq(4)
- end
- end
- end
-
- describe '.hosts' do
- it 'returns a list of hosts' do
- allow(described_class)
- .to receive(:configuration)
- .and_return({ 'hosts' => %w(foo bar baz) })
-
- expect(described_class.hosts).to eq(%w(foo bar baz))
- end
- end
-
- describe '.pool_size' do
- it 'returns a Fixnum' do
- expect(described_class.pool_size).to be_a_kind_of(Integer)
+ # There isn't much to test here as the load balancing settings might not
+ # (and likely aren't) set when running tests.
+ expect(cfg.pool_size).to eq(raw[:pool])
end
end
describe '.enable?' do
before do
- allow(described_class).to receive(:hosts).and_return(%w(foo))
+ allow(described_class.configuration)
+ .to receive(:hosts)
+ .and_return(%w(foo))
end
it 'returns false when no hosts are specified' do
- allow(described_class).to receive(:hosts).and_return([])
+ allow(described_class.configuration).to receive(:hosts).and_return([])
expect(described_class.enable?).to eq(false)
end
@@ -163,10 +82,10 @@ RSpec.describe Gitlab::Database::LoadBalancing do
end
it 'returns true when service discovery is enabled' do
- allow(described_class).to receive(:hosts).and_return([])
+ allow(described_class.configuration).to receive(:hosts).and_return([])
allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(false)
- allow(described_class)
+ allow(described_class.configuration)
.to receive(:service_discovery_enabled?)
.and_return(true)
@@ -175,17 +94,17 @@ RSpec.describe Gitlab::Database::LoadBalancing do
end
describe '.configured?' do
- it 'returns true when Sidekiq is being used' do
- allow(described_class).to receive(:hosts).and_return(%w(foo))
- allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
+ it 'returns true when hosts are configured' do
+ allow(described_class.configuration)
+ .to receive(:hosts)
+ .and_return(%w[foo])
+
expect(described_class.configured?).to eq(true)
end
- it 'returns true when service discovery is enabled in Sidekiq' do
- allow(described_class).to receive(:hosts).and_return([])
- allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
-
- allow(described_class)
+ it 'returns true when service discovery is enabled' do
+ allow(described_class.configuration).to receive(:hosts).and_return([])
+ allow(described_class.configuration)
.to receive(:service_discovery_enabled?)
.and_return(true)
@@ -193,9 +112,8 @@ RSpec.describe Gitlab::Database::LoadBalancing do
end
it 'returns false when neither service discovery nor hosts are configured' do
- allow(described_class).to receive(:hosts).and_return([])
-
- allow(described_class)
+ allow(described_class.configuration).to receive(:hosts).and_return([])
+ allow(described_class.configuration)
.to receive(:service_discovery_enabled?)
.and_return(false)
@@ -219,9 +137,9 @@ RSpec.describe Gitlab::Database::LoadBalancing do
it 'runs initial service discovery when configuring the connection proxy' do
discover = instance_spy(Gitlab::Database::LoadBalancing::ServiceDiscovery)
- allow(described_class)
- .to receive(:configuration)
- .and_return('discover' => { 'record' => 'foo' })
+ allow(described_class.configuration)
+ .to receive(:service_discovery)
+ .and_return({ record: 'foo' })
expect(Gitlab::Database::LoadBalancing::ServiceDiscovery)
.to receive(:new)
@@ -238,60 +156,6 @@ RSpec.describe Gitlab::Database::LoadBalancing do
end
end
- describe '.active_record_models' do
- it 'returns an Array' do
- expect(described_class.active_record_models).to be_an_instance_of(Array)
- end
- end
-
- describe '.service_discovery_enabled?' do
- it 'returns true if service discovery is enabled' do
- allow(described_class)
- .to receive(:configuration)
- .and_return('discover' => { 'record' => 'foo' })
-
- expect(described_class.service_discovery_enabled?).to eq(true)
- end
-
- it 'returns false if service discovery is disabled' do
- expect(described_class.service_discovery_enabled?).to eq(false)
- end
- end
-
- describe '.service_discovery_configuration' do
- context 'when no configuration is provided' do
- it 'returns a default configuration Hash' do
- expect(described_class.service_discovery_configuration).to eq(
- nameserver: 'localhost',
- port: 8600,
- record: nil,
- record_type: 'A',
- interval: 60,
- disconnect_timeout: 120,
- use_tcp: false
- )
- end
- end
-
- context 'when configuration is provided' do
- it 'returns a Hash including the custom configuration' do
- allow(described_class)
- .to receive(:configuration)
- .and_return('discover' => { 'record' => 'foo', 'record_type' => 'SRV' })
-
- expect(described_class.service_discovery_configuration).to eq(
- nameserver: 'localhost',
- port: 8600,
- record: 'foo',
- record_type: 'SRV',
- interval: 60,
- disconnect_timeout: 120,
- use_tcp: false
- )
- end
- end
- end
-
describe '.start_service_discovery' do
it 'does not start if service discovery is disabled' do
expect(Gitlab::Database::LoadBalancing::ServiceDiscovery)
@@ -301,12 +165,14 @@ RSpec.describe Gitlab::Database::LoadBalancing do
end
it 'starts service discovery if enabled' do
- allow(described_class)
+ allow(described_class.configuration)
.to receive(:service_discovery_enabled?)
.and_return(true)
instance = double(:instance)
- lb = Gitlab::Database::LoadBalancing::LoadBalancer.new([])
+ config = Gitlab::Database::LoadBalancing::Configuration
+ .new(ActiveRecord::Base)
+ lb = Gitlab::Database::LoadBalancing::LoadBalancer.new(config)
proxy = Gitlab::Database::LoadBalancing::ConnectionProxy.new(lb)
allow(described_class)
@@ -345,7 +211,12 @@ RSpec.describe Gitlab::Database::LoadBalancing do
context 'when the load balancing is configured' do
let(:db_host) { ActiveRecord::Base.connection_pool.db_config.host }
- let(:load_balancer) { described_class::LoadBalancer.new([db_host]) }
+ let(:config) do
+ Gitlab::Database::LoadBalancing::Configuration
+ .new(ActiveRecord::Base, [db_host])
+ end
+
+ let(:load_balancer) { described_class::LoadBalancer.new(config) }
let(:proxy) { described_class::ConnectionProxy.new(load_balancer) }
context 'when a proxy connection is used' do
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index c67b5af5e3c..35fe2c41c0c 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -15,6 +15,22 @@ RSpec.describe Gitlab::Database do
end
end
+ describe '.default_pool_size' do
+ before do
+ allow(Gitlab::Runtime).to receive(:max_threads).and_return(7)
+ end
+
+ it 'returns the max thread size plus a fixed headroom of 10' do
+ expect(described_class.default_pool_size).to eq(17)
+ end
+
+ it 'returns the max thread size plus a DB_POOL_HEADROOM if this env var is present' do
+ stub_env('DB_POOL_HEADROOM', '7')
+
+ expect(described_class.default_pool_size).to eq(14)
+ end
+ end
+
describe '.has_config?' do
context 'two tier database config' do
before do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 4b5fc57571b..7a587e82683 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -1072,7 +1072,7 @@ RSpec.describe API::MergeRequests do
end
describe "GET /groups/:id/merge_requests" do
- let_it_be(:group) { create(:group, :public) }
+ let_it_be(:group, reload: true) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, :repository, creator: user, namespace: group, only_allow_merge_if_pipeline_succeeds: false) }
include_context 'with merge requests'
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 788febc7f2b..8a98c516f64 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -3031,32 +3031,75 @@ RSpec.describe API::Users do
end
end
- describe 'POST /users/:id/unblock' do
- let(:blocked_user) { create(:user, state: 'blocked') }
- let(:deactivated_user) { create(:user, state: 'deactivated') }
+ describe 'POST /users/:id/unblock', :aggregate_failures do
+ context 'when admin' do
+ subject(:unblock_user) { post api("/users/#{user_id}/unblock", admin) }
- it 'unblocks existing user' do
- post api("/users/#{user.id}/unblock", admin)
- expect(response).to have_gitlab_http_status(:created)
- expect(user.reload.state).to eq('active')
- end
+ context 'with an existing user' do
+ let(:user_id) { user.id }
- it 'unblocks a blocked user' do
- post api("/users/#{blocked_user.id}/unblock", admin)
- expect(response).to have_gitlab_http_status(:created)
- expect(blocked_user.reload.state).to eq('active')
- end
+ it 'unblocks existing user' do
+ unblock_user
- it 'does not unblock ldap blocked users' do
- post api("/users/#{ldap_blocked_user.id}/unblock", admin)
- expect(response).to have_gitlab_http_status(:forbidden)
- expect(ldap_blocked_user.reload.state).to eq('ldap_blocked')
- end
+ expect(response).to have_gitlab_http_status(:created)
+ expect(user.reload.state).to eq('active')
+ end
+ end
- it 'does not unblock deactivated users' do
- post api("/users/#{deactivated_user.id}/unblock", admin)
- expect(response).to have_gitlab_http_status(:forbidden)
- expect(deactivated_user.reload.state).to eq('deactivated')
+ context 'with a blocked user' do
+ let(:blocked_user) { create(:user, state: 'blocked') }
+ let(:user_id) { blocked_user.id }
+
+ it 'unblocks a blocked user' do
+ unblock_user
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(blocked_user.reload.state).to eq('active')
+ end
+ end
+
+ context 'with a ldap blocked user' do
+ let(:user_id) { ldap_blocked_user.id }
+
+ it 'does not unblock ldap blocked users' do
+ unblock_user
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(ldap_blocked_user.reload.state).to eq('ldap_blocked')
+ end
+ end
+
+ context 'with a deactivated user' do
+ let(:user_id) { deactivated_user.id }
+
+ it 'does not unblock deactivated users' do
+ unblock_user
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(deactivated_user.reload.state).to eq('deactivated')
+ end
+ end
+
+ context 'with a non existent user' do
+ let(:user_id) { non_existing_record_id }
+
+ it 'returns a 404 error if user id not found' do
+ unblock_user
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+ end
+
+ context 'with an invalid user id' do
+ let(:user_id) { 'ASDF' }
+
+ it 'returns a 404' do
+ unblock_user
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
end
it 'is not available for non admin users' do
@@ -3064,18 +3107,6 @@ RSpec.describe API::Users do
expect(response).to have_gitlab_http_status(:forbidden)
expect(user.reload.state).to eq('active')
end
-
- it 'returns a 404 error if user id not found' do
- post api('/users/0/block', admin)
- expect(response).to have_gitlab_http_status(:not_found)
- expect(json_response['message']).to eq('404 User Not Found')
- end
-
- it "returns a 404 for invalid ID" do
- post api("/users/ASDF/block", admin)
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
end
describe 'POST /users/:id/ban', :aggregate_failures do
diff --git a/spec/requests/projects/usage_quotas_spec.rb b/spec/requests/projects/usage_quotas_spec.rb
index 4586d3bec4f..04e01da61ef 100644
--- a/spec/requests/projects/usage_quotas_spec.rb
+++ b/spec/requests/projects/usage_quotas_spec.rb
@@ -28,10 +28,20 @@ RSpec.describe 'Project Usage Quotas' do
end
it 'renders usage quotas path' do
+ mock_storage_app_data = {
+ project_path: project.full_path,
+ usage_quotas_help_page_path: help_page_path('user/usage_quotas'),
+ build_artifacts_help_page_path: help_page_path('ci/pipelines/job_artifacts', anchor: 'when-job-artifacts-are-deleted'),
+ packages_help_page_path: help_page_path('user/packages/package_registry/index.md', anchor: 'delete-a-package'),
+ repository_help_page_path: help_page_path('user/project/repository/reducing_the_repo_size_using_git'),
+ snippets_help_page_path: help_page_path('user/snippets', anchor: 'reduce-snippets-repository-size'),
+ wiki_help_page_path: help_page_path('administration/wikis/index.md', anchor: 'reduce-wiki-repository-size')
+ }
get project_usage_quotas_path(project)
expect(response).to have_gitlab_http_status(:ok)
expect(response.body).to include(project_usage_quotas_path(project))
+ expect(assigns[:storage_app_data]).to eq(mock_storage_app_data)
expect(response.body).to include("Usage of project resources across the <strong>#{project.name}</strong> project")
end
diff --git a/spec/services/groups/group_links/create_service_spec.rb b/spec/services/groups/group_links/create_service_spec.rb
index b1bb9a8de23..03dac14be54 100644
--- a/spec/services/groups/group_links/create_service_spec.rb
+++ b/spec/services/groups/group_links/create_service_spec.rb
@@ -6,18 +6,20 @@ RSpec.describe Groups::GroupLinks::CreateService, '#execute' do
let(:parent_group_user) { create(:user) }
let(:group_user) { create(:user) }
let(:child_group_user) { create(:user) }
+ let(:prevent_sharing) { false }
let_it_be(:group_parent) { create(:group, :private) }
let_it_be(:group) { create(:group, :private, parent: group_parent) }
let_it_be(:group_child) { create(:group, :private, parent: group) }
- let_it_be(:shared_group_parent, refind: true) { create(:group, :private) }
- let_it_be(:shared_group, refind: true) { create(:group, :private, parent: shared_group_parent) }
- let_it_be(:shared_group_child) { create(:group, :private, parent: shared_group) }
+ let(:ns_for_parent) { create(:namespace_settings, prevent_sharing_groups_outside_hierarchy: prevent_sharing) }
+ let(:shared_group_parent) { create(:group, :private, namespace_settings: ns_for_parent) }
+ let(:shared_group) { create(:group, :private, parent: shared_group_parent) }
+ let(:shared_group_child) { create(:group, :private, parent: shared_group) }
- let_it_be(:project_parent) { create(:project, group: shared_group_parent) }
- let_it_be(:project) { create(:project, group: shared_group) }
- let_it_be(:project_child) { create(:project, group: shared_group_child) }
+ let(:project_parent) { create(:project, group: shared_group_parent) }
+ let(:project) { create(:project, group: shared_group) }
+ let(:project_child) { create(:project, group: shared_group_child) }
let(:opts) do
{
@@ -129,9 +131,7 @@ RSpec.describe Groups::GroupLinks::CreateService, '#execute' do
end
context 'sharing outside the hierarchy is disabled' do
- before do
- shared_group_parent.namespace_settings.update!(prevent_sharing_groups_outside_hierarchy: true)
- end
+ let(:prevent_sharing) { true }
it 'prevents sharing with a group outside the hierarchy' do
result = subject.execute
diff --git a/spec/support/database_load_balancing.rb b/spec/support/database_load_balancing.rb
index 7b0f49cb1b4..f22c69ea613 100644
--- a/spec/support/database_load_balancing.rb
+++ b/spec/support/database_load_balancing.rb
@@ -4,8 +4,9 @@ RSpec.configure do |config|
config.before(:each, :db_load_balancing) do
allow(Gitlab::Database::LoadBalancing).to receive(:enable?).and_return(true)
- lb = ::Gitlab::Database::LoadBalancing::LoadBalancer
- .new([Gitlab::Database.main.config['host']])
+ config = Gitlab::Database::LoadBalancing::Configuration
+ .new(ActiveRecord::Base, [Gitlab::Database.main.config['host']])
+ lb = ::Gitlab::Database::LoadBalancing::LoadBalancer.new(config)
proxy = ::Gitlab::Database::LoadBalancing::ConnectionProxy.new(lb)
allow(ActiveRecord::Base).to receive(:load_balancing_proxy).and_return(proxy)
diff --git a/storybook/config/preview.js b/storybook/config/preview.js
index a372aea68ad..4f496665de6 100644
--- a/storybook/config/preview.js
+++ b/storybook/config/preview.js
@@ -1,7 +1,15 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
+import Vue from 'vue';
+import translateMixin from '../../app/assets/javascripts/vue_shared/translate';
+
const stylesheetsRequireCtx = require.context(
'../../app/assets/stylesheets',
true,
- /application\.scss$/,
+ /(application|application_utilities)\.scss$/,
);
+window.gon = {};
+translateMixin(Vue);
+
stylesheetsRequireCtx('./application.scss');
+stylesheetsRequireCtx('./application_utilities.scss');
diff --git a/storybook/package.json b/storybook/package.json
index 028133dd5e3..4b922a4776c 100644
--- a/storybook/package.json
+++ b/storybook/package.json
@@ -5,7 +5,9 @@
"start": "start-storybook -p 9002 -c config",
"build": "build-storybook -c config -o public"
},
- "dependencies": {},
+ "blockedDependencies": {
+ "vue": "https://gitlab.com/gitlab-org/gitlab/-/issues/340511"
+ },
"devDependencies": {
"@storybook/addon-a11y": "^6.2.9",
"@storybook/addon-actions": "^6.2.9",