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>2020-11-20 00:09:07 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-11-20 00:09:07 +0300
commitdf40cd1c38116a25089930be960d511b0be732ad (patch)
tree6f32db75c0fa073a990873b4d6689390dbf3bbc3
parent71c85847eb6645f6cca91febd70668d544a4125d (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue90
-rw-r--r--app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js142
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_mentions.vue238
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue8
-rw-r--r--app/models/namespace.rb1
-rw-r--r--app/models/namespace_onboarding_action.rb5
-rw-r--r--changelogs/unreleased/nicolasdular-namespace-onboarding-actions-table.yml5
-rw-r--r--db/migrate/20201118093135_create_namespace_onboarding_actions.rb23
-rw-r--r--db/schema_migrations/202011180931351
-rw-r--r--db/structure.sql26
-rw-r--r--doc/administration/auditor_users.md2
-rw-r--r--doc/administration/auth/ldap/index.md2
-rw-r--r--doc/administration/index.md2
-rw-r--r--doc/administration/libravatar.md2
-rw-r--r--doc/administration/load_balancer.md30
-rw-r--r--doc/administration/pseudonymizer.md4
-rw-r--r--doc/administration/raketasks/check.md6
-rw-r--r--doc/administration/raketasks/github_import.md8
-rw-r--r--doc/administration/raketasks/maintenance.md8
-rw-r--r--doc/administration/raketasks/project_import_export.md2
-rw-r--r--doc/administration/raketasks/uploads/migrate.md4
-rw-r--r--doc/administration/raketasks/uploads/sanitize.md6
-rw-r--r--doc/api/avatar.md2
-rw-r--r--doc/api/custom_attributes.md4
-rw-r--r--doc/api/graphql/getting_started.md12
-rw-r--r--doc/api/group_badges.md14
-rw-r--r--doc/api/groups.md52
-rw-r--r--doc/api/import.md2
-rw-r--r--doc/api/issue_links.md2
-rw-r--r--doc/api/issues_statistics.md8
-rw-r--r--doc/api/license.md2
-rw-r--r--doc/api/members.md2
-rw-r--r--doc/api/namespaces.md4
-rw-r--r--doc/api/services.md18
-rw-r--r--doc/api/settings.md34
-rw-r--r--doc/api/system_hooks.md6
-rw-r--r--doc/api/templates/licenses.md2
-rw-r--r--doc/api/users.md30
-rw-r--r--doc/development/testing_guide/best_practices.md26
-rw-r--r--doc/downgrade_ee_to_ce/README.md3
-rw-r--r--doc/migrate_ci_to_ce/README.md32
-rw-r--r--doc/public_access/public_access.md14
-rw-r--r--doc/raketasks/cleanup.md12
-rw-r--r--doc/raketasks/features.md4
-rw-r--r--doc/topics/application_development_platform/index.md4
-rw-r--r--doc/topics/git/lfs/migrate_to_git_lfs.md11
-rw-r--r--doc/topics/index.md2
-rw-r--r--doc/topics/offline/quick_start_guide.md4
-rw-r--r--doc/user/admin_area/appearance.md12
-rw-r--r--doc/user/admin_area/settings/external_authorization.md51
-rw-r--r--doc/user/admin_area/settings/index.md4
-rw-r--r--doc/user/admin_area/settings/terms.md16
-rw-r--r--locale/gitlab.pot3
-rw-r--r--package.json2
-rw-r--r--spec/controllers/help_controller_spec.rb5
-rw-r--r--spec/features/projects/blobs/balsamiq_spec.rb17
-rw-r--r--spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap8
-rw-r--r--spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_new_spec.js.snap6
-rw-r--r--spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap2
-rw-r--r--spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap2
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap2
-rw-r--r--spec/frontend/issuable/related_issues/components/issue_token_spec.js2
-rw-r--r--spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap2
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap4
-rw-r--r--spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap47
-rw-r--r--spec/frontend/vue_shared/components/gfm_autocomplete/gfm_autocomplete_spec.js (renamed from spec/frontend/vue_shared/components/gl_mentions_spec.js)8
-rw-r--r--spec/frontend/vue_shared/components/gfm_autocomplete/utils_spec.js344
-rw-r--r--spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap1
-rw-r--r--spec/helpers/icons_helper_spec.rb2
-rw-r--r--spec/initializers/secret_token_spec.rb9
-rw-r--r--spec/javascripts/blob/balsamiq/balsamiq_viewer_browser_spec.js59
-rw-r--r--spec/lib/feature/definition_spec.rb4
-rw-r--r--spec/lib/gitlab/email/smime/certificate_spec.rb14
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb2
-rw-r--r--spec/lib/gitlab/webpack/manifest_spec.rb4
-rw-r--r--spec/lib/gitlab_spec.rb11
-rw-r--r--spec/models/instance_configuration_spec.rb16
-rw-r--r--spec/models/namespace_onboarding_action_spec.rb7
-rw-r--r--spec/models/namespace_spec.rb1
-rw-r--r--spec/services/clusters/aws/fetch_credentials_service_spec.rb4
-rw-r--r--spec/services/clusters/aws/provision_service_spec.rb4
-rw-r--r--spec/services/metrics/dashboard/clone_dashboard_service_spec.rb2
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/helpers/file_read_helpers.rb48
-rw-r--r--spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb2
-rw-r--r--spec/tasks/gitlab/db_rake_spec.rb2
-rw-r--r--spec/tooling/lib/tooling/test_map_generator_spec.rb7
-rw-r--r--yarn.lock8
88 files changed, 1091 insertions, 575 deletions
diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue
new file mode 100644
index 00000000000..c45666e69eb
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue
@@ -0,0 +1,90 @@
+<script>
+import Tribute from 'tributejs';
+import createFlash from '~/flash';
+import axios from '~/lib/utils/axios_utils';
+import { __ } from '~/locale';
+import SidebarMediator from '~/sidebar/sidebar_mediator';
+import { GfmAutocompleteType, tributeConfig } from '~/vue_shared/components/gfm_autocomplete/utils';
+
+export default {
+ errorMessage: __(
+ 'An error occurred while getting autocomplete data. Please refresh the page and try again.',
+ ),
+ props: {
+ autocompleteTypes: {
+ type: Array,
+ required: false,
+ default: () => Object.values(GfmAutocompleteType),
+ },
+ dataSources: {
+ type: Object,
+ required: false,
+ default: () => gl.GfmAutoComplete?.dataSources || {},
+ },
+ },
+ computed: {
+ config() {
+ return this.autocompleteTypes.map(type => ({
+ ...tributeConfig[type].config,
+ values: this.getValues(type),
+ }));
+ },
+ },
+ mounted() {
+ this.cache = {};
+ this.tribute = new Tribute({ collection: this.config });
+
+ const input = this.$slots.default?.[0]?.elm;
+ this.tribute.attach(input);
+ },
+ beforeDestroy() {
+ const input = this.$slots.default?.[0]?.elm;
+ this.tribute.detach(input);
+ },
+ methods: {
+ cacheAssignees() {
+ const isAssigneesLengthSame =
+ this.assignees?.length === SidebarMediator.singleton?.store?.assignees?.length;
+
+ if (!this.assignees || !isAssigneesLengthSame) {
+ this.assignees =
+ SidebarMediator.singleton?.store?.assignees?.map(assignee => assignee.username) || [];
+ }
+ },
+ filterValues(type) {
+ // The assignees AJAX response can come after the user first invokes autocomplete
+ // so we need to check more than once if we need to update the assignee cache
+ this.cacheAssignees();
+
+ return tributeConfig[type].filterValues
+ ? tributeConfig[type].filterValues({
+ assignees: this.assignees,
+ collection: this.cache[type],
+ fullText: this.$slots.default?.[0]?.elm?.value,
+ selectionStart: this.$slots.default?.[0]?.elm?.selectionStart,
+ })
+ : this.cache[type];
+ },
+ getValues(type) {
+ return (inputText, processValues) => {
+ if (this.cache[type]) {
+ processValues(this.filterValues(type));
+ } else if (this.dataSources[type]) {
+ axios
+ .get(this.dataSources[type])
+ .then(response => {
+ this.cache[type] = response.data;
+ processValues(this.filterValues(type));
+ })
+ .catch(() => createFlash({ message: this.$options.errorMessage }));
+ } else {
+ processValues([]);
+ }
+ };
+ },
+ },
+ render(createElement) {
+ return createElement('div', this.$slots.default);
+ },
+};
+</script>
diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js
new file mode 100644
index 00000000000..b2e995d0f17
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js
@@ -0,0 +1,142 @@
+import { escape, last } from 'lodash';
+import { spriteIcon } from '~/lib/utils/common_utils';
+
+const groupType = 'Group'; // eslint-disable-line @gitlab/require-i18n-strings
+
+const nonWordOrInteger = /\W|^\d+$/;
+
+export const GfmAutocompleteType = {
+ Issues: 'issues',
+ Labels: 'labels',
+ Members: 'members',
+ MergeRequests: 'mergeRequests',
+ Milestones: 'milestones',
+ Snippets: 'snippets',
+};
+
+function doesCurrentLineStartWith(searchString, fullText, selectionStart) {
+ const currentLineNumber = fullText.slice(0, selectionStart).split('\n').length;
+ const currentLine = fullText.split('\n')[currentLineNumber - 1];
+ return currentLine.startsWith(searchString);
+}
+
+export const tributeConfig = {
+ [GfmAutocompleteType.Issues]: {
+ config: {
+ trigger: '#',
+ lookup: value => value.iid + value.title,
+ menuItemTemplate: ({ original }) =>
+ `<small>${original.reference || original.iid}</small> ${escape(original.title)}`,
+ selectTemplate: ({ original }) => original.reference || `#${original.iid}`,
+ },
+ },
+
+ [GfmAutocompleteType.Labels]: {
+ config: {
+ trigger: '~',
+ lookup: 'title',
+ menuItemTemplate: ({ original }) => `
+ <span class="dropdown-label-box" style="background: ${escape(original.color)};"></span>
+ ${escape(original.title)}`,
+ selectTemplate: ({ original }) =>
+ nonWordOrInteger.test(original.title)
+ ? `~"${escape(original.title)}"`
+ : `~${escape(original.title)}`,
+ },
+ filterValues({ collection, fullText, selectionStart }) {
+ if (doesCurrentLineStartWith('/label', fullText, selectionStart)) {
+ return collection.filter(label => !label.set);
+ }
+
+ if (doesCurrentLineStartWith('/unlabel', fullText, selectionStart)) {
+ return collection.filter(label => label.set);
+ }
+
+ return collection;
+ },
+ },
+
+ [GfmAutocompleteType.Members]: {
+ config: {
+ trigger: '@',
+ fillAttr: 'username',
+ lookup: value =>
+ value.type === groupType ? last(value.name.split(' / ')) : value.name + value.username,
+ menuItemTemplate: ({ original }) => {
+ const commonClasses = 'gl-avatar gl-avatar-s24 gl-flex-shrink-0';
+ const noAvatarClasses = `${commonClasses} gl-rounded-small
+ gl-display-flex gl-align-items-center gl-justify-content-center`;
+
+ const avatar = original.avatar_url
+ ? `<img class="${commonClasses} gl-avatar-circle" src="${original.avatar_url}" alt="" />`
+ : `<div class="${noAvatarClasses}" aria-hidden="true">
+ ${original.username.charAt(0).toUpperCase()}</div>`;
+
+ let displayName = original.name;
+ let parentGroupOrUsername = `@${original.username}`;
+
+ if (original.type === groupType) {
+ const splitName = original.name.split(' / ');
+ displayName = splitName.pop();
+ parentGroupOrUsername = splitName.pop();
+ }
+
+ const count = original.count && !original.mentionsDisabled ? ` (${original.count})` : '';
+
+ const disabledMentionsIcon = original.mentionsDisabled
+ ? spriteIcon('notifications-off', 's16 gl-ml-3')
+ : '';
+
+ return `
+ <div class="gl-display-flex gl-align-items-center">
+ ${avatar}
+ <div class="gl-font-sm gl-line-height-normal gl-ml-3">
+ <div>${escape(displayName)}${count}</div>
+ <div class="gl-text-gray-700">${escape(parentGroupOrUsername)}</div>
+ </div>
+ ${disabledMentionsIcon}
+ </div>
+ `;
+ },
+ },
+ filterValues({ assignees, collection, fullText, selectionStart }) {
+ if (doesCurrentLineStartWith('/assign', fullText, selectionStart)) {
+ return collection.filter(member => !assignees.includes(member.username));
+ }
+
+ if (doesCurrentLineStartWith('/unassign', fullText, selectionStart)) {
+ return collection.filter(member => assignees.includes(member.username));
+ }
+
+ return collection;
+ },
+ },
+
+ [GfmAutocompleteType.MergeRequests]: {
+ config: {
+ trigger: '!',
+ lookup: value => value.iid + value.title,
+ menuItemTemplate: ({ original }) =>
+ `<small>${original.reference || original.iid}</small> ${escape(original.title)}`,
+ selectTemplate: ({ original }) => original.reference || `!${original.iid}`,
+ },
+ },
+
+ [GfmAutocompleteType.Milestones]: {
+ config: {
+ trigger: '%',
+ lookup: 'title',
+ menuItemTemplate: ({ original }) => escape(original.title),
+ selectTemplate: ({ original }) => `%"${escape(original.title)}"`,
+ },
+ },
+
+ [GfmAutocompleteType.Snippets]: {
+ config: {
+ trigger: '$',
+ fillAttr: 'id',
+ lookup: value => value.id + value.title,
+ menuItemTemplate: ({ original }) => `<small>${original.id}</small> ${escape(original.title)}`,
+ },
+ },
+};
diff --git a/app/assets/javascripts/vue_shared/components/gl_mentions.vue b/app/assets/javascripts/vue_shared/components/gl_mentions.vue
deleted file mode 100644
index dde7e3ebe13..00000000000
--- a/app/assets/javascripts/vue_shared/components/gl_mentions.vue
+++ /dev/null
@@ -1,238 +0,0 @@
-<script>
-import { escape, last } from 'lodash';
-import Tribute from 'tributejs';
-import axios from '~/lib/utils/axios_utils';
-import { spriteIcon } from '~/lib/utils/common_utils';
-import SidebarMediator from '~/sidebar/sidebar_mediator';
-
-const AutoComplete = {
- Issues: 'issues',
- Labels: 'labels',
- Members: 'members',
- MergeRequests: 'mergeRequests',
- Milestones: 'milestones',
- Snippets: 'snippets',
-};
-
-const groupType = 'Group'; // eslint-disable-line @gitlab/require-i18n-strings
-
-function doesCurrentLineStartWith(searchString, fullText, selectionStart) {
- const currentLineNumber = fullText.slice(0, selectionStart).split('\n').length;
- const currentLine = fullText.split('\n')[currentLineNumber - 1];
- return currentLine.startsWith(searchString);
-}
-
-const autoCompleteMap = {
- [AutoComplete.Issues]: {
- filterValues() {
- return this[AutoComplete.Issues];
- },
- menuItemTemplate({ original }) {
- return `<small>${original.reference || original.iid}</small> ${escape(original.title)}`;
- },
- },
- [AutoComplete.Labels]: {
- filterValues() {
- const fullText = this.$slots.default?.[0]?.elm?.value;
- const selectionStart = this.$slots.default?.[0]?.elm?.selectionStart;
-
- if (doesCurrentLineStartWith('/label', fullText, selectionStart)) {
- return this.labels.filter(label => !label.set);
- }
-
- if (doesCurrentLineStartWith('/unlabel', fullText, selectionStart)) {
- return this.labels.filter(label => label.set);
- }
-
- return this.labels;
- },
- menuItemTemplate({ original }) {
- return `
- <span class="dropdown-label-box" style="background: ${escape(original.color)};"></span>
- ${escape(original.title)}`;
- },
- },
- [AutoComplete.Members]: {
- filterValues() {
- const fullText = this.$slots.default?.[0]?.elm?.value;
- const selectionStart = this.$slots.default?.[0]?.elm?.selectionStart;
-
- // Need to check whether sidebar store assignees has been updated
- // in the case where the assignees AJAX response comes after the user does @ autocomplete
- const isAssigneesLengthSame =
- this.assignees?.length === SidebarMediator.singleton?.store?.assignees?.length;
-
- if (!this.assignees || !isAssigneesLengthSame) {
- this.assignees =
- SidebarMediator.singleton?.store?.assignees?.map(assignee => assignee.username) || [];
- }
-
- if (doesCurrentLineStartWith('/assign', fullText, selectionStart)) {
- return this.members.filter(member => !this.assignees.includes(member.username));
- }
-
- if (doesCurrentLineStartWith('/unassign', fullText, selectionStart)) {
- return this.members.filter(member => this.assignees.includes(member.username));
- }
-
- return this.members;
- },
- menuItemTemplate({ original }) {
- const commonClasses = 'gl-avatar gl-avatar-s24 gl-flex-shrink-0';
- const noAvatarClasses = `${commonClasses} gl-rounded-small
- gl-display-flex gl-align-items-center gl-justify-content-center`;
-
- const avatar = original.avatar_url
- ? `<img class="${commonClasses} gl-avatar-circle" src="${original.avatar_url}" alt="" />`
- : `<div class="${noAvatarClasses}" aria-hidden="true">
- ${original.username.charAt(0).toUpperCase()}</div>`;
-
- let displayName = original.name;
- let parentGroupOrUsername = `@${original.username}`;
-
- if (original.type === groupType) {
- const splitName = original.name.split(' / ');
- displayName = splitName.pop();
- parentGroupOrUsername = splitName.pop();
- }
-
- const count = original.count && !original.mentionsDisabled ? ` (${original.count})` : '';
-
- const disabledMentionsIcon = original.mentionsDisabled
- ? spriteIcon('notifications-off', 's16 gl-ml-3')
- : '';
-
- return `
- <div class="gl-display-flex gl-align-items-center">
- ${avatar}
- <div class="gl-font-sm gl-line-height-normal gl-ml-3">
- <div>${escape(displayName)}${count}</div>
- <div class="gl-text-gray-700">${escape(parentGroupOrUsername)}</div>
- </div>
- ${disabledMentionsIcon}
- </div>
- `;
- },
- },
- [AutoComplete.MergeRequests]: {
- filterValues() {
- return this[AutoComplete.MergeRequests];
- },
- menuItemTemplate({ original }) {
- return `<small>${original.reference || original.iid}</small> ${escape(original.title)}`;
- },
- },
- [AutoComplete.Milestones]: {
- filterValues() {
- return this[AutoComplete.Milestones];
- },
- menuItemTemplate({ original }) {
- return escape(original.title);
- },
- },
- [AutoComplete.Snippets]: {
- filterValues() {
- return this[AutoComplete.Snippets];
- },
- menuItemTemplate({ original }) {
- return `<small>${original.id}</small> ${escape(original.title)}`;
- },
- },
-};
-
-export default {
- name: 'GlMentions',
- props: {
- dataSources: {
- type: Object,
- required: false,
- default: () => gl.GfmAutoComplete?.dataSources || {},
- },
- },
- mounted() {
- const NON_WORD_OR_INTEGER = /\W|^\d+$/;
-
- this.tribute = new Tribute({
- collection: [
- {
- trigger: '#',
- lookup: value => value.iid + value.title,
- menuItemTemplate: autoCompleteMap[AutoComplete.Issues].menuItemTemplate,
- selectTemplate: ({ original }) => original.reference || `#${original.iid}`,
- values: this.getValues(AutoComplete.Issues),
- },
- {
- trigger: '@',
- fillAttr: 'username',
- lookup: value =>
- value.type === groupType ? last(value.name.split(' / ')) : value.name + value.username,
- menuItemTemplate: autoCompleteMap[AutoComplete.Members].menuItemTemplate,
- values: this.getValues(AutoComplete.Members),
- },
- {
- trigger: '~',
- lookup: 'title',
- menuItemTemplate: autoCompleteMap[AutoComplete.Labels].menuItemTemplate,
- selectTemplate: ({ original }) =>
- NON_WORD_OR_INTEGER.test(original.title)
- ? `~"${escape(original.title)}"`
- : `~${escape(original.title)}`,
- values: this.getValues(AutoComplete.Labels),
- },
- {
- trigger: '!',
- lookup: value => value.iid + value.title,
- menuItemTemplate: autoCompleteMap[AutoComplete.MergeRequests].menuItemTemplate,
- selectTemplate: ({ original }) => original.reference || `!${original.iid}`,
- values: this.getValues(AutoComplete.MergeRequests),
- },
- {
- trigger: '%',
- lookup: 'title',
- menuItemTemplate: autoCompleteMap[AutoComplete.Milestones].menuItemTemplate,
- selectTemplate: ({ original }) => `%"${escape(original.title)}"`,
- values: this.getValues(AutoComplete.Milestones),
- },
- {
- trigger: '$',
- fillAttr: 'id',
- lookup: value => value.id + value.title,
- menuItemTemplate: autoCompleteMap[AutoComplete.Snippets].menuItemTemplate,
- values: this.getValues(AutoComplete.Snippets),
- },
- ],
- });
-
- const input = this.$slots.default?.[0]?.elm;
- this.tribute.attach(input);
- },
- beforeDestroy() {
- const input = this.$slots.default?.[0]?.elm;
- this.tribute.detach(input);
- },
- methods: {
- getValues(autoCompleteType) {
- return (inputText, processValues) => {
- if (this[autoCompleteType]) {
- const filteredValues = autoCompleteMap[autoCompleteType].filterValues.call(this);
- processValues(filteredValues);
- } else if (this.dataSources[autoCompleteType]) {
- axios
- .get(this.dataSources[autoCompleteType])
- .then(response => {
- this[autoCompleteType] = response.data;
- const filteredValues = autoCompleteMap[autoCompleteType].filterValues.call(this);
- processValues(filteredValues);
- })
- .catch(() => {});
- } else {
- processValues([]);
- }
- };
- },
- },
- render(createElement) {
- return createElement('div', this.$slots.default);
- },
-};
-</script>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index 9cfba85e0d8..0d703545073 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -10,14 +10,14 @@ import { deprecatedCreateFlash as Flash } from '~/flash';
import GLForm from '~/gl_form';
import MarkdownHeader from './header.vue';
import MarkdownToolbar from './toolbar.vue';
-import GlMentions from '~/vue_shared/components/gl_mentions.vue';
+import GfmAutocomplete from '~/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue';
import Suggestions from '~/vue_shared/components/markdown/suggestions.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import axios from '~/lib/utils/axios_utils';
export default {
components: {
- GlMentions,
+ GfmAutocomplete,
MarkdownHeader,
MarkdownToolbar,
GlIcon,
@@ -246,9 +246,9 @@ export default {
/>
<div v-show="!previewMarkdown" class="md-write-holder">
<div class="zen-backdrop">
- <gl-mentions v-if="glFeatures.tributeAutocomplete">
+ <gfm-autocomplete v-if="glFeatures.tributeAutocomplete">
<slot name="textarea"></slot>
- </gl-mentions>
+ </gfm-autocomplete>
<slot v-else name="textarea"></slot>
<a
class="zen-control zen-control-leave js-zen-leave gl-text-gray-500"
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 232d0a6b05d..238e8f70778 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -28,6 +28,7 @@ class Namespace < ApplicationRecord
has_many :runner_namespaces, inverse_of: :namespace, class_name: 'Ci::RunnerNamespace'
has_many :runners, through: :runner_namespaces, source: :runner, class_name: 'Ci::Runner'
+ has_many :namespace_onboarding_actions
# This should _not_ be `inverse_of: :namespace`, because that would also set
# `user.namespace` when this user creates a group with themselves as `owner`.
diff --git a/app/models/namespace_onboarding_action.rb b/app/models/namespace_onboarding_action.rb
new file mode 100644
index 00000000000..ea0d9d495ae
--- /dev/null
+++ b/app/models/namespace_onboarding_action.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class NamespaceOnboardingAction < ApplicationRecord
+ belongs_to :namespace
+end
diff --git a/changelogs/unreleased/nicolasdular-namespace-onboarding-actions-table.yml b/changelogs/unreleased/nicolasdular-namespace-onboarding-actions-table.yml
new file mode 100644
index 00000000000..688a3d8d93e
--- /dev/null
+++ b/changelogs/unreleased/nicolasdular-namespace-onboarding-actions-table.yml
@@ -0,0 +1,5 @@
+---
+title: Create namespace onboarding actions table
+merge_request: 48018
+author:
+type: added
diff --git a/db/migrate/20201118093135_create_namespace_onboarding_actions.rb b/db/migrate/20201118093135_create_namespace_onboarding_actions.rb
new file mode 100644
index 00000000000..6b38a0dddca
--- /dev/null
+++ b/db/migrate/20201118093135_create_namespace_onboarding_actions.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class CreateNamespaceOnboardingActions < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ with_lock_retries do
+ create_table :namespace_onboarding_actions do |t|
+ t.references :namespace, index: true, null: false, foreign_key: { on_delete: :cascade }
+ t.datetime_with_timezone :created_at, null: false
+ t.integer :action, limit: 2, null: false
+ end
+ end
+ end
+
+ def down
+ with_lock_retries do
+ drop_table :namespace_onboarding_actions
+ end
+ end
+end
diff --git a/db/schema_migrations/20201118093135 b/db/schema_migrations/20201118093135
new file mode 100644
index 00000000000..7bf60967db0
--- /dev/null
+++ b/db/schema_migrations/20201118093135
@@ -0,0 +1 @@
+4be52737be2bc74e666e973fa42f17a16e652cb4fa2368c7f347c3f1f8941dbb \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index acbda95a500..6b812881e2d 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -13869,6 +13869,22 @@ CREATE TABLE namespace_limits (
temporary_storage_increase_ends_on date
);
+CREATE TABLE namespace_onboarding_actions (
+ id bigint NOT NULL,
+ namespace_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ action smallint NOT NULL
+);
+
+CREATE SEQUENCE namespace_onboarding_actions_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE namespace_onboarding_actions_id_seq OWNED BY namespace_onboarding_actions.id;
+
CREATE TABLE namespace_root_storage_statistics (
namespace_id integer NOT NULL,
updated_at timestamp with time zone NOT NULL,
@@ -18058,6 +18074,8 @@ ALTER TABLE ONLY metrics_users_starred_dashboards ALTER COLUMN id SET DEFAULT ne
ALTER TABLE ONLY milestones ALTER COLUMN id SET DEFAULT nextval('milestones_id_seq'::regclass);
+ALTER TABLE ONLY namespace_onboarding_actions ALTER COLUMN id SET DEFAULT nextval('namespace_onboarding_actions_id_seq'::regclass);
+
ALTER TABLE ONLY namespace_statistics ALTER COLUMN id SET DEFAULT nextval('namespace_statistics_id_seq'::regclass);
ALTER TABLE ONLY namespaces ALTER COLUMN id SET DEFAULT nextval('namespaces_id_seq'::regclass);
@@ -19309,6 +19327,9 @@ ALTER TABLE ONLY namespace_aggregation_schedules
ALTER TABLE ONLY namespace_limits
ADD CONSTRAINT namespace_limits_pkey PRIMARY KEY (namespace_id);
+ALTER TABLE ONLY namespace_onboarding_actions
+ ADD CONSTRAINT namespace_onboarding_actions_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY namespace_root_storage_statistics
ADD CONSTRAINT namespace_root_storage_statistics_pkey PRIMARY KEY (namespace_id);
@@ -21337,6 +21358,8 @@ CREATE INDEX index_mr_metrics_on_target_project_id_merged_at_nulls_last ON merge
CREATE UNIQUE INDEX index_namespace_aggregation_schedules_on_namespace_id ON namespace_aggregation_schedules USING btree (namespace_id);
+CREATE INDEX index_namespace_onboarding_actions_on_namespace_id ON namespace_onboarding_actions USING btree (namespace_id);
+
CREATE UNIQUE INDEX index_namespace_root_storage_statistics_on_namespace_id ON namespace_root_storage_statistics USING btree (namespace_id);
CREATE UNIQUE INDEX index_namespace_statistics_on_namespace_id ON namespace_statistics USING btree (namespace_id);
@@ -23717,6 +23740,9 @@ ALTER TABLE ONLY merge_request_assignees
ALTER TABLE ONLY packages_dependency_links
ADD CONSTRAINT fk_rails_4437bf4070 FOREIGN KEY (dependency_id) REFERENCES packages_dependencies(id) ON DELETE CASCADE;
+ALTER TABLE ONLY namespace_onboarding_actions
+ ADD CONSTRAINT fk_rails_4504f6875a FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY project_auto_devops
ADD CONSTRAINT fk_rails_45436b12b2 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
diff --git a/doc/administration/auditor_users.md b/doc/administration/auditor_users.md
index c41065abd17..30493597194 100644
--- a/doc/administration/auditor_users.md
+++ b/doc/administration/auditor_users.md
@@ -58,7 +58,7 @@ helpful:
To create a new Auditor user:
1. Create a new user or edit an existing one by navigating to
- **Admin Area > Users**. You will find the option of the access level in
+ **Admin Area > Users**. The option of the access level is located in
the 'Access' section.
![Admin Area Form](img/auditor_access_form.png)
diff --git a/doc/administration/auth/ldap/index.md b/doc/administration/auth/ldap/index.md
index 9d88d66bf46..a9823c36d44 100644
--- a/doc/administration/auth/ldap/index.md
+++ b/doc/administration/auth/ldap/index.md
@@ -170,7 +170,7 @@ production:
| `label` | A human-friendly name for your LDAP server. It will be displayed on your sign-in page. | yes | `'Paris'` or `'Acme, Ltd.'` |
| `host` | IP address or domain name of your LDAP server. | yes | `'ldap.mydomain.com'` |
| `port` | The port to connect with on your LDAP server. Always an integer, not a string. | yes | `389` or `636` (for SSL) |
-| `uid` | LDAP attribute for username. Should be the attribute, not the value that maps to the `uid`. | yes | `'sAMAccountName'`, `'uid'`, `'userPrincipalName'` |
+| `uid` | LDAP attribute for username. Should be the attribute, not the value that maps to the `uid`. | yes | `'sAMAccountName'` or `'uid'` or `'userPrincipalName'` |
| `bind_dn` | The full DN of the user you will bind with. | no | `'america\momo'` or `'CN=Gitlab,OU=Users,DC=domain,DC=com'` |
| `password` | The password of the bind user. | no | `'your_great_password'` |
| `encryption` | Encryption method. The `method` key is deprecated in favor of `encryption`. | yes | `'start_tls'` or `'simple_tls'` or `'plain'` |
diff --git a/doc/administration/index.md b/doc/administration/index.md
index 0aa94b86371..f667bdb5d2e 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -135,7 +135,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Issue closing pattern](issue_closing_pattern.md): Customize how to close an issue from commit messages.
- [Gitaly](gitaly/index.md): Configuring Gitaly, GitLab's Git repository storage service.
-- [Default labels](../user/admin_area/labels.md): Create labels that will be automatically added to every new project.
+- [Default labels](../user/admin_area/labels.md): Create labels that are automatically added to every new project.
- [Restrict the use of public or internal projects](../public_access/public_access.md#restricting-the-use-of-public-or-internal-projects): Restrict the use of visibility levels for users when they create a project or a snippet.
- [Custom project templates](../user/admin_area/custom_project_templates.md): Configure a set of projects to be used as custom templates when creating a new project. **(PREMIUM ONLY)**
diff --git a/doc/administration/libravatar.md b/doc/administration/libravatar.md
index a92e6fade03..5d92a0162bf 100644
--- a/doc/administration/libravatar.md
+++ b/doc/administration/libravatar.md
@@ -41,7 +41,7 @@ the configuration options as follows:
### Your own Libravatar server
If you are [running your own Libravatar service](https://wiki.libravatar.org/running_your_own/),
-the URL will be different in the configuration, but you must provide the same
+the URL is different in the configuration, but you must provide the same
placeholders so GitLab can parse the URL correctly.
For example, you host a service on `http://libravatar.example.com` and the
diff --git a/doc/administration/load_balancer.md b/doc/administration/load_balancer.md
index 410381ff2b0..1ab87fb4b4c 100644
--- a/doc/administration/load_balancer.md
+++ b/doc/administration/load_balancer.md
@@ -7,17 +7,17 @@ type: reference
# Load Balancer for multi-node GitLab
-In an multi-node GitLab configuration, you will need a load balancer to route
+In an multi-node GitLab configuration, you need a load balancer to route
traffic to the application servers. The specifics on which load balancer to use
or the exact configuration is beyond the scope of GitLab documentation. We hope
that if you're managing HA systems like GitLab you have a load balancer of
choice already. Some examples including HAProxy (open-source), F5 Big-IP LTM,
-and Citrix Net Scaler. This documentation will outline what ports and protocols
+and Citrix Net Scaler. This documentation outlines what ports and protocols
you need to use with GitLab.
## SSL
-How will you handle SSL in your multi-node environment? There are several different
+How do you want to handle SSL in your multi-node environment? There are several different
options:
- Each application node terminates SSL
@@ -29,8 +29,8 @@ options:
### Application nodes terminate SSL
Configure your load balancer(s) to pass connections on port 443 as 'TCP' rather
-than 'HTTP(S)' protocol. This will pass the connection to the application nodes
-NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
+than 'HTTP(S)' protocol. This passes the connection to the application nodes
+NGINX service untouched. NGINX has the SSL certificate and listen on port 443.
See [NGINX HTTPS documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
for details on managing SSL certificates and configuring NGINX.
@@ -38,10 +38,10 @@ for details on managing SSL certificates and configuring NGINX.
### Load Balancer(s) terminate SSL without backend SSL
Configure your load balancer(s) to use the 'HTTP(S)' protocol rather than 'TCP'.
-The load balancer(s) will then be responsible for managing SSL certificates and
+The load balancer(s) is be responsible for managing SSL certificates and
terminating SSL.
-Since communication between the load balancer(s) and GitLab will not be secure,
+Since communication between the load balancer(s) and GitLab isn't secure,
there is some additional configuration needed. See
[NGINX Proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#supporting-proxied-ssl)
for details.
@@ -49,12 +49,12 @@ for details.
### Load Balancer(s) terminate SSL with backend SSL
Configure your load balancer(s) to use the 'HTTP(S)' protocol rather than 'TCP'.
-The load balancer(s) will be responsible for managing SSL certificates that
-end users will see.
+The load balancer(s) is responsible for managing SSL certificates that
+end users see.
-Traffic will also be secure between the load balancer(s) and NGINX in this
+Traffic is secure between the load balancer(s) and NGINX in this
scenario. There is no need to add configuration for proxied SSL since the
-connection will be secure all the way. However, configuration will need to be
+connection is secure all the way. However, configuration must be
added to GitLab to configure SSL certificates. See
[NGINX HTTPS documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
for details on managing SSL certificates and configuring NGINX.
@@ -75,13 +75,13 @@ for details on managing SSL certificates and configuring NGINX.
to pass through the `Connection` and `Upgrade` hop-by-hop headers. See the
[web terminal](integration/terminal.md) integration guide for
more details.
-- (*2*): When using HTTPS protocol for port 443, you will need to add an SSL
+- (*2*): When using HTTPS protocol for port 443, you must add an SSL
certificate to the load balancers. If you wish to terminate SSL at the
GitLab application server instead, use TCP protocol.
### GitLab Pages Ports
-If you're using GitLab Pages with custom domain support you will need some
+If you're using GitLab Pages with custom domain support you need some
additional port configurations.
GitLab Pages requires a separate virtual IP address. Configure DNS to point the
`pages_external_url` from `/etc/gitlab/gitlab.rb` at the new virtual IP address. See the
@@ -103,7 +103,7 @@ GitLab Pages requires a separate virtual IP address. Configure DNS to point the
Some organizations have policies against opening SSH port 22. In this case,
it may be helpful to configure an alternate SSH hostname that allows users
-to use SSH on port 443. An alternate SSH hostname will require a new virtual IP address
+to use SSH on port 443. An alternate SSH hostname requires a new virtual IP address
compared to the other GitLab HTTP configuration above.
Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
@@ -114,7 +114,7 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
## Readiness check
-It is strongly recommend that multi-node deployments configure load balancers to use the [readiness check](../user/admin_area/monitoring/health_check.md#readiness) to ensure a node is ready to accept traffic, before routing traffic to it. This is especially important when utilizing Puma, as there is a brief period during a restart where Puma will not accept requests.
+It is strongly recommend that multi-node deployments configure load balancers to use the [readiness check](../user/admin_area/monitoring/health_check.md#readiness) to ensure a node is ready to accept traffic, before routing traffic to it. This is especially important when utilizing Puma, as there is a brief period during a restart where Puma doesn't accept requests.
<!-- ## Troubleshooting
diff --git a/doc/administration/pseudonymizer.md b/doc/administration/pseudonymizer.md
index 41a7ec087ac..2098708d6d9 100644
--- a/doc/administration/pseudonymizer.md
+++ b/doc/administration/pseudonymizer.md
@@ -28,7 +28,7 @@ To configure the pseudonymizer, you need to:
- Provide a manifest file that describes which fields should be included or
pseudonymized ([example `manifest.yml` file](https://gitlab.com/gitlab-org/gitlab/tree/master/config/pseudonymizer.yml)).
- A default manifest is provided with the GitLab installation. Using a relative file path will be resolved from the Rails root.
+ A default manifest is provided with the GitLab installation, using a relative file path that resolves from the Rails root.
Alternatively, you can use an absolute file path.
- Use an object storage and specify the connection parameters in the `pseudonymizer.upload.connection` configuration option.
@@ -100,7 +100,7 @@ sudo gitlab-rake gitlab:db:pseudonymizer
sudo -u git -H bundle exec rake gitlab:db:pseudonymizer RAILS_ENV=production
```
-This will produce some CSV files that might be very large, so make sure the
+This produces some CSV files that might be very large, so make sure the
`PSEUDONYMIZER_OUTPUT_DIR` has sufficient space. As a rule of thumb, at least
10% of the database size is recommended.
diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md
index f61a3107b3d..13f23815760 100644
--- a/doc/administration/raketasks/check.md
+++ b/doc/administration/raketasks/check.md
@@ -56,7 +56,7 @@ sudo -u git -H bundle exec rake gitlab:git:fsck RAILS_ENV=production
Various types of files can be uploaded to a GitLab installation by users.
These integrity checks can detect missing files. Additionally, for locally
stored files, checksums are generated and stored in the database upon upload,
-and these checks will verify them against current files.
+and these checks verify them against current files.
Currently, integrity checks are supported for the following types of file:
@@ -137,8 +137,8 @@ Done!
## LDAP check
-The LDAP check Rake task will test the bind DN and password credentials
-(if configured) and will list a sample of LDAP users. This task is also
+The LDAP check Rake task tests the bind DN and password credentials
+(if configured) and lists a sample of LDAP users. This task is also
executed as part of the `gitlab:check` task, but can run independently.
See [LDAP Rake Tasks - LDAP Check](ldap.md#check) for details.
diff --git a/doc/administration/raketasks/github_import.md b/doc/administration/raketasks/github_import.md
index d549110c32f..a28cf488218 100644
--- a/doc/administration/raketasks/github_import.md
+++ b/doc/administration/raketasks/github_import.md
@@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
To retrieve and import GitHub repositories, you need a [GitHub personal access token](https://github.com/settings/tokens).
A username should be passed as the second argument to the Rake task,
-which will become the owner of the project. You can resume an import
+which becomes the owner of the project. You can resume an import
with the same command.
Bear in mind that the syntax is very specific. Remove any spaces within the argument block and
@@ -20,7 +20,7 @@ before/after the brackets. Also, some shells (for example, `zsh`) can interpret
## Caveats
If the GitHub [rate limit](https://developer.github.com/v3/#rate-limiting) is reached while importing,
-the importing process will wait (`sleep()`) until it can continue importing.
+the importing process waits (`sleep()`) until it can continue importing.
## Importing multiple projects
@@ -35,8 +35,8 @@ bundle exec rake "import:github[access_token,root,foo/bar]" RAILS_ENV=production
```
In this case, `access_token` is your GitHub personal access token, `root`
-is your GitLab username, and `foo/bar` is the new GitLab namespace/project that
-will get created from your GitHub project. Subgroups are also possible: `foo/foo/bar`.
+is your GitLab username, and `foo/bar` is the new GitLab namespace/project
+created from your GitHub project. Subgroups are also possible: `foo/foo/bar`.
## Importing a single project
diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md
index b93442be0a1..5fc95fcb1ae 100644
--- a/doc/administration/raketasks/maintenance.md
+++ b/doc/administration/raketasks/maintenance.md
@@ -107,8 +107,8 @@ The `gitlab:check` Rake task runs the following Rake tasks:
- `gitlab:sidekiq:check`
- `gitlab:app:check`
-It will check that each component was set up according to the installation guide and suggest fixes
-for issues found. This command must be run from your application server and will not work correctly on
+It checks that each component was set up according to the installation guide and suggest fixes
+for issues found. This command must be run from your application server and doesn't work correctly on
component servers like [Gitaly](../gitaly/index.md#run-gitaly-on-its-own-server).
You may also have a look at our troubleshooting guides for:
@@ -300,7 +300,7 @@ To check the status of specific migrations, you can use the following Rake task:
sudo gitlab-rake db:migrate:status
```
-This will output a table with a `Status` of `up` or `down` for
+This outputs a table with a `Status` of `up` or `down` for
each Migration ID.
```shell
@@ -313,7 +313,7 @@ database: gitlabhq_production
## Run incomplete database migrations
-Database migrations can be stuck in an incomplete state. That is, they'll have a `down`
+Database migrations can be stuck in an incomplete state, with a `down`
status in the output of the `sudo gitlab-rake db:migrate:status` command.
To complete these migrations, use the following Rake task:
diff --git a/doc/administration/raketasks/project_import_export.md b/doc/administration/raketasks/project_import_export.md
index d83ab6e5cee..976fcdc8091 100644
--- a/doc/administration/raketasks/project_import_export.md
+++ b/doc/administration/raketasks/project_import_export.md
@@ -36,7 +36,7 @@ sudo gitlab-rake gitlab:import_export:version
bundle exec rake gitlab:import_export:version RAILS_ENV=production
```
-The current list of DB tables that will be exported can be listed by using the following command:
+The current list of DB tables to export can be listed by using the following command:
```shell
# Omnibus installations
diff --git a/doc/administration/raketasks/uploads/migrate.md b/doc/administration/raketasks/uploads/migrate.md
index 075b27fb70d..552a81a765d 100644
--- a/doc/administration/raketasks/uploads/migrate.md
+++ b/doc/administration/raketasks/uploads/migrate.md
@@ -16,7 +16,7 @@ There is a Rake task for migrating uploads between different storage types.
After [configuring the object storage](../../uploads.md#using-object-storage) for GitLab's
uploads, use this task to migrate existing uploads from the local storage to the remote storage.
-All of the processing will be done in a background worker and requires **no downtime**.
+All of the processing is done in a background worker and requires **no downtime**.
Read more about using [object storage with GitLab](../../object_storage.md).
@@ -133,7 +133,7 @@ migrate your data out of object storage and back into your local storage.
CAUTION: **Warning:**
**Extended downtime is required** so no new files are created in object storage during
-the migration. A configuration setting will be added soon to allow migrating
+the migration. A configuration setting is planned to allow migrating
from object storage to local files with only a brief moment of downtime for configuration changes.
To follow progress, see the [relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/30979).
diff --git a/doc/administration/raketasks/uploads/sanitize.md b/doc/administration/raketasks/uploads/sanitize.md
index 4f7c99babd8..2ab2136ad2f 100644
--- a/doc/administration/raketasks/uploads/sanitize.md
+++ b/doc/administration/raketasks/uploads/sanitize.md
@@ -41,8 +41,8 @@ The Rake task accepts following parameters.
| Parameter | Type | Description |
|:-------------|:--------|:----------------------------------------------------------------------------------------------------------------------------|
-| `start_id` | integer | Only uploads with equal or greater ID will be processed |
-| `stop_id` | integer | Only uploads with equal or smaller ID will be processed |
+| `start_id` | integer | Only uploads with equal or greater ID are processed |
+| `stop_id` | integer | Only uploads with equal or smaller ID are processed |
| `dry_run` | boolean | Do not remove EXIF data, only check if EXIF data are present or not. Defaults to `true` |
| `sleep_time` | float | Pause for number of seconds after processing each image. Defaults to 0.3 seconds |
| `uploader` | string | Run sanitization only for uploads of the given uploader: `FileUploader`, `PersonalFileUploader`, or `NamespaceFileUploader` |
@@ -66,7 +66,7 @@ To remove EXIF data on uploads with an ID between 100 and 5000 and pause for 0.1
sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:uploads:sanitize:remove_exif[100,5000,false,0.1] 2>&1 | tee exif.log
```
-The output is written into an `exif.log` file because it will probably be long.
+The output is written into an `exif.log` file because it is often long.
If sanitization fails for an upload, an error message should be in the output of the Rake task.
Typical reasons include that the file is missing in the storage or it's not a valid image.
diff --git a/doc/api/avatar.md b/doc/api/avatar.md
index aec1ba67d45..6af00641a41 100644
--- a/doc/api/avatar.md
+++ b/doc/api/avatar.md
@@ -16,7 +16,7 @@ If:
- No user with the given public email address is found, results from external avatar services are
returned.
-- Public visibility is restricted, response will be `403 Forbidden` when unauthenticated.
+- Public visibility is restricted, response is `403 Forbidden` when unauthenticated.
NOTE: **Note:**
This endpoint can be accessed without authentication.
diff --git a/doc/api/custom_attributes.md b/doc/api/custom_attributes.md
index 76c8474ee95..2b0c06ad681 100644
--- a/doc/api/custom_attributes.md
+++ b/doc/api/custom_attributes.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Every API call to custom attributes must be authenticated as administrator.
Custom attributes are currently available on users, groups, and projects,
-which will be referred to as "resource" in this documentation.
+which is referred to as "resource" in this documentation.
## List custom attributes
@@ -74,7 +74,7 @@ Example response:
## Set custom attribute
-Set a custom attribute on a resource. The attribute will be updated if it already exists,
+Set a custom attribute on a resource. The attribute is updated if it already exists,
or newly created otherwise.
```plaintext
diff --git a/doc/api/graphql/getting_started.md b/doc/api/graphql/getting_started.md
index 8501e76b5aa..b44b7d290a2 100644
--- a/doc/api/graphql/getting_started.md
+++ b/doc/api/graphql/getting_started.md
@@ -41,11 +41,11 @@ The examples below:
- Can be run directly against GitLab 11.0 or later, though some of the types and fields
may not be supported in older versions.
-- Will work against GitLab.com without any further setup. Make sure you are signed in and
+- Works against GitLab.com without any further setup. Make sure you are signed in and
navigate to the [GraphiQL Explorer](https://gitlab.com/-/graphql-explorer).
If you want to run the queries locally, or on a self-managed instance,
-you will need to either:
+you must either:
- Create the `gitlab-org` group with a project called `graphql-sandbox` under it. Create
several issues within the project.
@@ -133,7 +133,7 @@ More about queries:
### Authorization
Authorization uses the same engine as the GitLab application (and GitLab.com). So if you've signed in to GitLab
-and use GraphiQL, all queries will be performed as you, the signed in user. For more information, see the
+and use GraphiQL, all queries are performed as you, the signed in user. For more information, see the
[GitLab API documentation](../README.md#authentication).
### Mutations
@@ -173,7 +173,7 @@ mutation {
```
Example: Add a comment to the issue (we're using the ID of the `GitLab.com` issue - but
-if you're using a local instance, you'll need to get the ID of an issue you can write to).
+if you're using a local instance, you must get the ID of an issue you can write to).
```graphql
mutation {
@@ -314,9 +314,9 @@ Pagination is a way of only asking for a subset of the records (say, the first 1
If we want more of them, we can make another request for the next 10 from the server
(in the form of something like "please give me the next 10 records").
-By default, GitLab's GraphQL API will return only the first 100 records of any collection.
+By default, GitLab's GraphQL API returns only the first 100 records of any collection.
This can be changed by using `first` or `last` arguments. Both arguments take a value,
-so `first: 10` will return the first 10 records, and `last: 10` the last 10 records.
+so `first: 10` returns the first 10 records, and `last: 10` the last 10 records.
Example: Retrieve only the first 2 issues (slicing). The `cursor` field gives us a position from which
we can retrieve further records relative to that one.
diff --git a/doc/api/group_badges.md b/doc/api/group_badges.md
index e13b9633da9..4ef6db89aac 100644
--- a/doc/api/group_badges.md
+++ b/doc/api/group_badges.md
@@ -10,15 +10,15 @@ info: To determine the technical writer assigned to the Stage/Group associated w
## Placeholder tokens
-Badges support placeholders that will be replaced in real time in both the link and image URL. The allowed placeholders are:
+Badges support placeholders that are replaced in real time in both the link and image URL. The allowed placeholders are:
-- **%{project_path}**: will be replaced by the project path.
-- **%{project_id}**: will be replaced by the project ID.
-- **%{default_branch}**: will be replaced by the project default branch.
-- **%{commit_sha}**: will be replaced by the last project's commit SHA.
+- **%{project_path}**: replaced by the project path.
+- **%{project_id}**: replaced by the project ID.
+- **%{default_branch}**: replaced by the project default branch.
+- **%{commit_sha}**: replaced by the last project's commit SHA.
-Because these endpoints aren't inside a project's context, the information used to replace the placeholders will be
-from the first group's project by creation date. If the group hasn't got any project the original URL with the placeholders will be returned.
+Because these endpoints aren't inside a project's context, the information used to replace the placeholders comes
+from the first group's project by creation date. If the group hasn't got any project the original URL with the placeholders is returned.
## List all badges of a group
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 0a584795d21..ce94eb455ce 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -339,7 +339,7 @@ Example response:
```
NOTE: **Note:**
-To distinguish between a project in the group and a project shared to the group, the `namespace` attribute can be used. When a project has been shared to the group, its `namespace` will be different from the group the request is being made for.
+To distinguish between a project in the group and a project shared to the group, the `namespace` attribute can be used. When a project has been shared to the group, its `namespace` differs from the group the request is being made for.
## List a group's shared projects
@@ -479,7 +479,7 @@ Example response:
## Details of a group
Get all details of a group. This endpoint can be accessed without authentication
-if the group is publicly accessible. In case the user that requests is admin of the group, it will return the `runners_token` for the group too.
+if the group is publicly accessible. In case the user that requests is admin of the group, it returns the `runners_token` for the group too.
```plaintext
GET /groups/:id
@@ -491,10 +491,10 @@ Parameters:
| ------------------------ | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user. |
| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only). |
-| `with_projects` | boolean | no | Include details from projects that belong to the specified group (defaults to `true`). (Deprecated, [will be removed in API v5](https://gitlab.com/gitlab-org/gitlab/-/issues/213797). To get the details of all projects within a group, use the [list a group's projects endpoint](#list-a-groups-projects).) |
+| `with_projects` | boolean | no | Include details from projects that belong to the specified group (defaults to `true`). (Deprecated, [scheduled for removal in API v5](https://gitlab.com/gitlab-org/gitlab/-/issues/213797). To get the details of all projects within a group, use the [list a group's projects endpoint](#list-a-groups-projects).) |
NOTE: **Note:**
-The `projects` and `shared_projects` attributes in the response are deprecated and will be [removed in API v5](https://gitlab.com/gitlab-org/gitlab/-/issues/213797).
+The `projects` and `shared_projects` attributes in the response are deprecated and [scheduled for removal in API v5](https://gitlab.com/gitlab-org/gitlab/-/issues/213797).
To get the details of all projects within a group, use either the [list a group's projects](#list-a-groups-projects) or the [list a group's shared projects](#list-a-groups-shared-projects) endpoint.
```shell
@@ -670,7 +670,7 @@ Example response:
}
```
-Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) also see
the `shared_runners_minutes_limit` and `extra_shared_runners_minutes_limit` parameters:
Additional response parameters:
@@ -685,7 +685,7 @@ Additional response parameters:
}
```
-Users on GitLab [Silver, Premium, or higher](https://about.gitlab.com/pricing/) will also see
+Users on GitLab [Silver, Premium, or higher](https://about.gitlab.com/pricing/) also see
the `marked_for_deletion_on` attribute:
```json
@@ -697,7 +697,7 @@ the `marked_for_deletion_on` attribute:
}
```
-When adding the parameter `with_projects=false`, projects will not be returned.
+When adding the parameter `with_projects=false`, projects aren't returned.
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/4?with_projects=false"
@@ -790,7 +790,7 @@ The `shared_runners_setting` attribute determines whether shared runners are ena
## New Subgroup
-This is similar to creating a [New group](#new-group). You'll need the `parent_id` from the [List groups](#list-groups) call. You can then enter the desired:
+This is similar to creating a [New group](#new-group). You need the `parent_id` from the [List groups](#list-groups) call. You can then enter the desired:
- `subgroup_path`
- `subgroup_name`
@@ -854,7 +854,7 @@ PUT /groups/:id
| `prevent_forking_outside_group` | boolean | no | **(PREMIUM)** When enabled, users can **not** fork projects from this group to external namespaces
NOTE: **Note:**
-The `projects` and `shared_projects` attributes in the response are deprecated and will be [removed in API v5](https://gitlab.com/gitlab-org/gitlab/-/issues/213797).
+The `projects` and `shared_projects` attributes in the response are deprecated and [scheduled for removal in API v5](https://gitlab.com/gitlab-org/gitlab/-/issues/213797).
To get the details of all projects within a group, use either the [list a group's projects](#list-a-groups-projects) or the [list a group's shared projects](#list-a-groups-shared-projects) endpoint.
```shell
@@ -948,7 +948,7 @@ Only available to group owners and administrators.
This endpoint either:
- Removes group, and queues a background job to delete all projects in the group as well.
-- Since [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/issues/33257), on [Premium or Silver](https://about.gitlab.com/pricing/) or higher tiers, marks a group for deletion. The deletion will happen 7 days later by default, but this can be changed in the [instance settings](../user/admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
+- Since [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/issues/33257), on [Premium or Silver](https://about.gitlab.com/pricing/) or higher tiers, marks a group for deletion. The deletion happens 7 days later by default, but this can be changed in the [instance settings](../user/admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
```plaintext
DELETE /groups/:id
@@ -960,7 +960,7 @@ Parameters:
| --------------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
-The response will be `202 Accepted` if the user has authorization.
+The response is `202 Accepted` if the user has authorization.
## Restore group marked for deletion **(PREMIUM)**
@@ -1074,7 +1074,7 @@ POST /groups/:id/hooks
| `deployment_events` | boolean | no | Trigger hook on deployment events |
| `releases_events` | boolean | no | Trigger hook on release events |
| `enable_ssl_verification` | boolean | no | Do SSL verification when triggering the hook |
-| `token` | string | no | Secret token to validate received payloads; this will not be returned in the response |
+| `token` | string | no | Secret token to validate received payloads; not returned in the response |
### Edit group hook
@@ -1102,7 +1102,7 @@ PUT /groups/:id/hooks/:hook_id
| `deployment_events` | boolean | no | Trigger hook on deployment events |
| `releases_events` | boolean | no | Trigger hook on release events |
| `enable_ssl_verification` | boolean | no | Do SSL verification when triggering the hook |
-| `token` | string | no | Secret token to validate received payloads; this will not be returned in the response |
+| `token` | string | no | Secret token to validate received payloads; not returned in the response |
### Delete group hook
@@ -1175,7 +1175,7 @@ To define the LDAP group link, provide either a `cn` or a `filter`, but not both
### Delete LDAP group link **(STARTER ONLY)**
-Deletes an LDAP group link. Deprecated. Will be removed in a future release.
+Deletes an LDAP group link. Deprecated. Scheduled for removal in a future release.
```plaintext
DELETE /groups/:id/ldap_group_links/:cn
@@ -1186,7 +1186,7 @@ DELETE /groups/:id/ldap_group_links/:cn
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `cn` | string | yes | The CN of an LDAP group |
-Deletes an LDAP group link for a specific LDAP provider. Deprecated. Will be removed in a future release.
+Deletes an LDAP group link for a specific LDAP provider. Deprecated. Scheduled for removal in a future release.
```plaintext
DELETE /groups/:id/ldap_group_links/:provider/:cn
@@ -1306,7 +1306,7 @@ GET /groups/:id/push_rule
}
```
-Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) will also see
+Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) also see
the `commit_committer_check` and `reject_unsigned_commits` parameters:
```json
@@ -1334,15 +1334,15 @@ POST /groups/:id/push_rule
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `deny_delete_tag` **(STARTER)** | boolean | no | Deny deleting a tag |
| `member_check` **(STARTER)** | boolean | no | Allows only GitLab users to author commits |
-| `prevent_secrets` **(STARTER)** | boolean | no | [Files that are likely to contain secrets](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/gitlab/checks/files_denylist.yml) will be rejected |
+| `prevent_secrets` **(STARTER)** | boolean | no | [Files that are likely to contain secrets](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/gitlab/checks/files_denylist.yml) are rejected |
| `commit_message_regex` **(STARTER)** | string | no | All commit messages must match the regular expression provided in this attribute, e.g. `Fixed \d+\..*` |
-| `commit_message_negative_regex` **(STARTER)** | string | no | Commit messages matching the regular expression provided in this attribute will not be allowed, e.g. `ssh\:\/\/` |
+| `commit_message_negative_regex` **(STARTER)** | string | no | Commit messages matching the regular expression provided in this attribute aren't allowed, e.g. `ssh\:\/\/` |
| `branch_name_regex` **(STARTER)** | string | no | All branch names must match the regular expression provided in this attribute, e.g. `(feature|hotfix)\/*` |
| `author_email_regex` **(STARTER)** | string | no | All commit author emails must match the regular expression provided in this attribute, e.g. `@my-company.com$` |
-| `file_name_regex` **(STARTER)** | string | no | Filenames matching the regular expression provided in this attribute will **not** be allowed, e.g. `(jar|exe)$` |
+| `file_name_regex` **(STARTER)** | string | no | Filenames matching the regular expression provided in this attribute are **not** allowed, e.g. `(jar|exe)$` |
| `max_file_size` **(STARTER)** | integer | no | Maximum file size (MB) allowed |
-| `commit_committer_check` **(PREMIUM)** | boolean | no | Only commits pushed using verified emails will be allowed |
-| `reject_unsigned_commits` **(PREMIUM)** | boolean | no | Only commits signed through GPG will be allowed |
+| `commit_committer_check` **(PREMIUM)** | boolean | no | Only commits pushed using verified emails are allowed |
+| `reject_unsigned_commits` **(PREMIUM)** | boolean | no | Only commits signed through GPG are allowed |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/19/push_rule"
@@ -1381,15 +1381,15 @@ PUT /groups/:id/push_rule
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `deny_delete_tag` **(STARTER)** | boolean | no | Deny deleting a tag |
| `member_check` **(STARTER)** | boolean | no | Restricts commits to be authored by existing GitLab users only |
-| `prevent_secrets` **(STARTER)** | boolean | no | [Files that are likely to contain secrets](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/gitlab/checks/files_denylist.yml) will be rejected |
+| `prevent_secrets` **(STARTER)** | boolean | no | [Files that are likely to contain secrets](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/gitlab/checks/files_denylist.yml) are rejected |
| `commit_message_regex` **(STARTER)** | string | no | All commit messages must match the regular expression provided in this attribute, e.g. `Fixed \d+\..*` |
-| `commit_message_negative_regex` **(STARTER)** | string | no | Commit messages matching the regular expression provided in this attribute will not be allowed, e.g. `ssh\:\/\/` |
+| `commit_message_negative_regex` **(STARTER)** | string | no | Commit messages matching the regular expression provided in this attribute aren't allowed, e.g. `ssh\:\/\/` |
| `branch_name_regex` **(STARTER)** | string | no | All branch names must match the regular expression provided in this attribute, e.g. `(feature|hotfix)\/*` |
| `author_email_regex` **(STARTER)** | string | no | All commit author emails must match the regular expression provided in this attribute, e.g. `@my-company.com$` |
-| `file_name_regex` **(STARTER)** | string | no | Filenames matching the regular expression provided in this attribute will **not** be allowed, e.g. `(jar|exe)$` |
+| `file_name_regex` **(STARTER)** | string | no | Filenames matching the regular expression provided in this attribute are **not** allowed, e.g. `(jar|exe)$` |
| `max_file_size` **(STARTER)** | integer | no | Maximum file size (MB) allowed |
-| `commit_committer_check` **(PREMIUM)** | boolean | no | Only commits pushed using verified emails will be allowed |
-| `reject_unsigned_commits` **(PREMIUM)** | boolean | no | Only commits signed through GPG will be allowed |
+| `commit_committer_check` **(PREMIUM)** | boolean | no | Only commits pushed using verified emails are allowed |
+| `reject_unsigned_commits` **(PREMIUM)** | boolean | no | Only commits signed through GPG are allowed |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/19/push_rule"
diff --git a/doc/api/import.md b/doc/api/import.md
index 27f5915b206..ff473c7ccf8 100644
--- a/doc/api/import.md
+++ b/doc/api/import.md
@@ -53,7 +53,7 @@ Import your projects from Bitbucket Server to GitLab via the API.
NOTE: **Note:**
The Bitbucket Project Key is only used for finding the repository in Bitbucket.
You must specify a `target_namespace` if you want to import the repository to a GitLab group.
-If you do not specify `target_namespace`, the project will import to your personal user namespace.
+If you do not specify `target_namespace`, the project imports to your personal user namespace.
```plaintext
POST /import/bitbucket_server
diff --git a/doc/api/issue_links.md b/doc/api/issue_links.md
index 41e2dd7c147..68d1ea49789 100644
--- a/doc/api/issue_links.md
+++ b/doc/api/issue_links.md
@@ -12,7 +12,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Get a list of a given issue's [related issues](../user/project/issues/related_issues.md),
sorted by the relationship creation datetime (ascending).
-Issues will be filtered according to the user authorizations.
+Issues are filtered according to the user authorizations.
```plaintext
GET /projects/:id/issues/:issue_iid/links
diff --git a/doc/api/issues_statistics.md b/doc/api/issues_statistics.md
index 3f0b22cca4c..df0f1d51134 100644
--- a/doc/api/issues_statistics.md
+++ b/doc/api/issues_statistics.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Every API call to issues_statistics must be authenticated.
If a user is not a member of a project and the project is private, a `GET`
-request on that project will result to a `404` status code.
+request on that project results in a `404` status code.
## Get issues statistics
@@ -40,7 +40,7 @@ GET /issues_statistics?confidential=true
| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. |
| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. |
-| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE `assignee_username` array should only contain a single value or an invalid parameter error will be returned otherwise. |
+| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE `assignee_username` array should only contain a single value or an invalid parameter error is returned otherwise. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
| `iids[]` | integer array | no | Return only the issues having the given `iid` |
| `search` | string | no | Search issues against their `title` and `description` |
@@ -98,7 +98,7 @@ GET /groups/:id/issues_statistics?confidential=true
| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. |
| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. |
-| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE `assignee_username` array should only contain a single value or an invalid parameter error will be returned otherwise. |
+| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE `assignee_username` array should only contain a single value or an invalid parameter error is returned otherwise. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
| `search` | string | no | Search group issues against their `title` and `description` |
| `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
@@ -154,7 +154,7 @@ GET /projects/:id/issues_statistics?confidential=true
| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. |
| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. |
-| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE `assignee_username` array should only contain a single value or an invalid parameter error will be returned otherwise. |
+| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE `assignee_username` array should only contain a single value or an invalid parameter error is returned otherwise. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
| `search` | string | no | Search project issues against their `title` and `description` |
| `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
diff --git a/doc/api/license.md b/doc/api/license.md
index 8c92a46a975..688ec075482 100644
--- a/doc/api/license.md
+++ b/doc/api/license.md
@@ -94,7 +94,7 @@ This is calculated differently depending on whether the license has expired or n
Returns:
-- `200 OK` with response containing the licenses in JSON format. This will be an empty JSON array if there are no licenses.
+- `200 OK` with response containing the licenses in JSON format. This is an empty JSON array if there are no licenses.
- `403 Forbidden` if the current user in not permitted to read the licenses.
## Add a new license
diff --git a/doc/api/members.md b/doc/api/members.md
index d616dfdd85c..6809eeb9187 100644
--- a/doc/api/members.md
+++ b/doc/api/members.md
@@ -19,7 +19,7 @@ The access levels are defined in the `Gitlab::Access` module. Currently, these l
CAUTION: **Caution:**
Due to [an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/219299),
-projects in personal namespaces will not show owner (`50`) permission
+projects in personal namespaces don't show owner (`50`) permission
for owner.
## Limitations
diff --git a/doc/api/namespaces.md b/doc/api/namespaces.md
index f61400dfddb..1434ed08693 100644
--- a/doc/api/namespaces.md
+++ b/doc/api/namespaces.md
@@ -93,12 +93,12 @@ the `plan` parameter associated with a namespace:
]
```
-Users on GitLab.com will also see `max_seats_used` and `seats_in_use` parameters.
+Users on GitLab.com also see `max_seats_used` and `seats_in_use` parameters.
`max_seats_used` is the highest number of users the group had. `seats_in_use` is
the number of license seats currently being used. Both values are updated
once a day.
-`max_seats_used` and `seats_in_use` will be non-zero only for namespaces on paid plans.
+`max_seats_used` and `seats_in_use` are non-zero only for namespaces on paid plans.
```json
[
diff --git a/doc/api/services.md b/doc/api/services.md
index a60eacef1d8..2a50d2c8a18 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -74,7 +74,7 @@ Asana - Teamwork without email
Set Asana service for a project.
-> This service adds commit messages as comments to Asana tasks. Once enabled, commit messages are checked for Asana task URLs (for example, `https://app.asana.com/0/123456/987654`) or task IDs starting with # (for example, `#987654`). Every task ID found will get the commit comment added to it. You can also close a task with a message containing: `fix #123456`. You can find your API Keys here: <https://developers.asana.com/docs/#authentication-basics>.
+> This service adds commit messages as comments to Asana tasks. Once enabled, commit messages are checked for Asana task URLs (for example, `https://app.asana.com/0/123456/987654`) or task IDs starting with # (for example, `#987654`). Every task ID found gets the commit comment added to it. You can also close a task with a message containing: `fix #123456`. You can find your API Keys here: <https://developers.asana.com/docs/#authentication-basics>.
```plaintext
PUT /projects/:id/services/asana
@@ -84,8 +84,8 @@ Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `api_key` | string | true | User API token. User must have access to task, all comments will be attributed to this user. |
-| `restrict_to_branch` | string | false | Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches. |
+| `api_key` | string | true | User API token. User must have access to task, all comments are attributed to this user. |
+| `restrict_to_branch` | string | false | Comma-separated list of branches which are automatically inspected. Leave blank to include all branches. |
| `push_events` | boolean | false | Enable notifications for push events |
### Delete Asana service
@@ -237,7 +237,7 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `token` | string | true | Buildkite project GitLab token |
| `project_url` | string | true | Pipeline URL. For example, `https://buildkite.com/example/pipeline` |
-| `enable_ssl_verification` | boolean | false | DEPRECATED: This parameter has no effect since SSL verification will always be enabled |
+| `enable_ssl_verification` | boolean | false | DEPRECATED: This parameter has no effect since SSL verification is always enabled |
| `push_events` | boolean | false | Enable notifications for push events |
### Delete Buildkite service
@@ -482,7 +482,7 @@ Parameters:
| `send_from_committer_email` | boolean | false | Send from committer |
| `push_events` | boolean | false | Enable notifications for push events |
| `tag_push_events` | boolean | false | Enable notifications for tag push events |
-| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are "all", "default", "protected", and "default_and_protected". Notifications will be always fired for tag pushes. The default value is "all" |
+| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are "all", "default", "protected", and "default_and_protected". Notifications are always fired for tag pushes. The default value is "all" |
### Delete Emails on push service
@@ -809,7 +809,7 @@ Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `url` | string | yes | The URL to the Jira project which is being linked to this GitLab project. For example, `https://jira.example.com`. |
-| `api_url` | string | no | The base URL to the Jira instance API. Web URL value will be used if not set. For example, `https://jira-api.example.com`. |
+| `api_url` | string | no | The base URL to the Jira instance API. Web URL value is used if not set. For example, `https://jira-api.example.com`. |
| `username` | string | yes | The username of the user created to be used with GitLab/Jira. |
| `password` | string | yes | The password of the user created to be used with GitLab/Jira. |
| `active` | boolean | no | Activates or deactivates the service. Defaults to false (deactivated). |
@@ -1015,7 +1015,7 @@ Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `token` | string | true | The PivotalTracker token |
-| `restrict_to_branch` | boolean | false | Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches. |
+| `restrict_to_branch` | boolean | false | Comma-separated list of branches to automatically inspect. Leave blank to include all branches. |
| `push_events` | boolean | false | Enable notifications for push events |
### Delete PivotalTracker service
@@ -1325,7 +1325,7 @@ A continuous integration and build server
Set JetBrains TeamCity CI service for a project.
-> The build configuration in TeamCity must use the build format number `%build.vcs.number%` you will also want to configure monitoring of all branches so merge requests build, that setting is in the VSC root advanced settings.
+> The build configuration in TeamCity must use the build format number `%build.vcs.number%`. Configure monitoring of all branches so merge requests build. That setting is in the VSC root advanced settings.
```plaintext
PUT /projects/:id/services/teamcity
@@ -1411,7 +1411,7 @@ Parameters:
- `project_url` (**required**) - Jenkins project URL like `http://jenkins.example.com/job/my-project/`
- `multiproject_enabled` (optional) - Multi-project mode is configured in Jenkins GitLab Hook plugin
-- `pass_unstable` (optional) - Unstable builds will be treated as passing
+- `pass_unstable` (optional) - Unstable builds are treated as passing
### Delete Jenkins CI (Deprecated) service
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 907256f3901..f3ca2726285 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -209,16 +209,16 @@ listed in the descriptions of the relevant settings.
| `allow_local_requests_from_hooks_and_services` | boolean | no | (Deprecated: Use `allow_local_requests_from_web_hooks_and_services` instead) Allow requests to the local network from hooks and services. |
| `allow_local_requests_from_system_hooks` | boolean | no | Allow requests to the local network from system hooks. |
| `allow_local_requests_from_web_hooks_and_services` | boolean | no | Allow requests to the local network from web hooks and services. |
-| `archive_builds_in_human_readable` | string | no | Set the duration for which the jobs will be considered as old and expired. Once that time passes, the jobs will be archived and no longer able to be retried. Make it empty to never expire jobs. It has to be no less than 1 day, for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>. |
+| `archive_builds_in_human_readable` | string | no | Set the duration for which the jobs are considered as old and expired. After that time passes, the jobs are archived and no longer able to be retried. Make it empty to never expire jobs. It has to be no less than 1 day, for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>. |
| `asset_proxy_enabled` | boolean | no | (**If enabled, requires:** `asset_proxy_url`) Enable proxying of assets. GitLab restart is required to apply changes. |
| `asset_proxy_secret_key` | string | no | Shared secret with the asset proxy server. GitLab restart is required to apply changes. |
| `asset_proxy_url` | string | no | URL of the asset proxy server. GitLab restart is required to apply changes. |
-| `asset_proxy_whitelist` | string or array of strings | no | Assets that match these domain(s) will NOT be proxied. Wildcards allowed. Your GitLab installation URL is automatically whitelisted. GitLab restart is required to apply changes. |
+| `asset_proxy_whitelist` | string or array of strings | no | Assets that match these domain(s) are **not** proxied. Wildcards allowed. Your GitLab installation URL is automatically allowlisted. GitLab restart is required to apply changes. |
| `authorized_keys_enabled` | boolean | no | By default, we write to the `authorized_keys` file to support Git over SSH without additional configuration. GitLab can be optimized to authenticate SSH keys via the database file. Only disable this if you have configured your OpenSSH server to use the AuthorizedKeysCommand. |
| `auto_devops_domain` | string | no | Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages. |
-| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for projects by default. It will automatically build, test, and deploy applications based on a predefined CI/CD configuration. |
+| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for projects by default. It automatically builds, tests, and deploys applications based on a predefined CI/CD configuration. |
| `automatic_purchased_storage_allocation` | boolean | no | Enabling this permits automatic allocation of purchased storage within a namespace. |
-| `check_namespace_plan` | boolean | no | **(PREMIUM)** Enabling this will make only licensed EE features available to projects if the project namespace's plan includes the feature or if the project is public. |
+| `check_namespace_plan` | boolean | no | **(PREMIUM)** Enabling this makes only licensed EE features available to projects if the project namespace's plan includes the feature or if the project is public. |
| `commit_email_hostname` | string | no | Custom hostname (for private commit emails). |
| `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes. |
| `default_artifacts_expire_in` | string | no | Set the default expiration time for each job's artifacts. |
@@ -234,7 +234,7 @@ listed in the descriptions of the relevant settings.
| `disabled_oauth_sign_in_sources` | array of strings | no | Disabled OAuth sign-in sources. |
| `dns_rebinding_protection_enabled` | boolean | no | Enforce DNS rebinding attack protection. |
| `domain_denylist_enabled` | boolean | no | (**If enabled, requires:** `domain_denylist`) Allows blocking sign-ups from emails from specific domains. |
-| `domain_denylist` | array of strings | no | Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: `domain.com`, `*.domain.com`. |
+| `domain_denylist` | array of strings | no | Users with e-mail addresses that match these domain(s) **cannot** sign up. Wildcards allowed. Use separate lines for multiple entries. Ex: `domain.com`, `*.domain.com`. |
| `domain_allowlist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is `null`, meaning there is no restriction. |
| `dsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded DSA key. Default is `0` (no restriction). `-1` disables DSA keys. |
| `ecdsa_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ECDSA key. Default is `0` (no restriction). `-1` disables ECDSA keys. |
@@ -247,8 +247,8 @@ listed in the descriptions of the relevant settings.
| `elasticsearch_aws_region` | string | no | **(PREMIUM)** The AWS region the Elasticsearch domain is configured |
| `elasticsearch_aws_secret_access_key` | string | no | **(PREMIUM)** AWS IAM secret access key |
| `elasticsearch_aws` | boolean | no | **(PREMIUM)** Enable the use of AWS hosted Elasticsearch |
-| `elasticsearch_indexed_field_length_limit` | integer | no | **(PREMIUM)** Maximum size of text fields that will be indexed by Elasticsearch. 0 value means no limit. This does not apply to repository and wiki indexing. |
-| `elasticsearch_indexed_file_size_limit_kb` | integer | no | **(PREMIUM)** Maximum size of repository and wiki files that will be indexed by Elasticsearch. |
+| `elasticsearch_indexed_field_length_limit` | integer | no | **(PREMIUM)** Maximum size of text fields to index by Elasticsearch. 0 value means no limit. This does not apply to repository and wiki indexing. |
+| `elasticsearch_indexed_file_size_limit_kb` | integer | no | **(PREMIUM)** Maximum size of repository and wiki files that are indexed by Elasticsearch. |
| `elasticsearch_indexing` | boolean | no | **(PREMIUM)** Enable Elasticsearch indexing |
| `elasticsearch_limit_indexing` | boolean | no | **(PREMIUM)** Limit Elasticsearch to index certain namespaces and projects |
| `elasticsearch_max_bulk_concurrency` | integer | no | **(PREMIUM)** Maximum concurrency of Elasticsearch bulk requests per indexing operation. This only applies to repository indexing operations. |
@@ -272,14 +272,14 @@ listed in the descriptions of the relevant settings.
| `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from |
| `first_day_of_week` | integer | no | Start day of the week for calendar views and date pickers. Valid values are `0` (default) for Sunday, `1` for Monday, and `6` for Saturday. |
| `geo_node_allowed_ips` | string | yes | **(PREMIUM)** Comma-separated list of IPs and CIDRs of allowed secondary nodes. For example, `1.1.1.1, 2.2.2.0/24`. |
-| `geo_status_timeout` | integer | no | **(PREMIUM)** The amount of seconds after which a request to get a secondary node status will time out. |
+| `geo_status_timeout` | integer | no | **(PREMIUM)** The amount of seconds after which a request to get a secondary node status times out. |
| `gitaly_timeout_default` | integer | no | Default Gitaly timeout, in seconds. This timeout is not enforced for Git fetch/push operations or Sidekiq jobs. Set to `0` to disable timeouts. |
| `gitaly_timeout_fast` | integer | no | Gitaly fast operation timeout, in seconds. Some Gitaly operations are expected to be fast. If they exceed this threshold, there may be a problem with a storage shard and 'failing fast' can help maintain the stability of the GitLab instance. Set to `0` to disable timeouts. |
| `gitaly_timeout_medium` | integer | no | Medium Gitaly timeout, in seconds. This should be a value between the Fast and the Default timeout. Set to `0` to disable timeouts. |
| `grafana_enabled` | boolean | no | Enable Grafana. |
| `grafana_url` | string | no | Grafana URL. |
| `gravatar_enabled` | boolean | no | Enable Gravatar. |
-| `hashed_storage_enabled` | boolean | no | Create new projects using hashed storage paths: Enable immutable, hash-based paths and repository names to store repositories on disk. This prevents repositories from having to be moved or renamed when the Project URL changes and may improve disk I/O performance. (Always enabled since 13.0, configuration will be removed in 14.0) |
+| `hashed_storage_enabled` | boolean | no | Create new projects using hashed storage paths: Enable immutable, hash-based paths and repository names to store repositories on disk. This prevents repositories from having to be moved or renamed when the Project URL changes and may improve disk I/O performance. (Always enabled since 13.0, configuration is scheduled for removal in 14.0) |
| `help_page_hide_commercial_content` | boolean | no | Hide marketing-related entries from help. |
| `help_page_support_url` | string | no | Alternate support URL for help page and help dropdown. |
| `help_page_text` | string | no | Custom text displayed on the help page. |
@@ -303,7 +303,7 @@ listed in the descriptions of the relevant settings.
| `max_pages_size` | integer | no | Maximum size of pages repositories in MB |
| `max_personal_access_token_lifetime` | integer | no | **(ULTIMATE ONLY)** Maximum allowable lifetime for personal access tokens in days |
| `metrics_method_call_threshold` | integer | no | A method call is only tracked when it takes longer than the given amount of milliseconds. |
-| `mirror_available` | boolean | no | Allow repository mirroring to configured by project Maintainers. If disabled, only Admins will be able to configure repository mirroring. |
+| `mirror_available` | boolean | no | Allow repository mirroring to configured by project Maintainers. If disabled, only Admins can configure repository mirroring. |
| `mirror_capacity_threshold` | integer | no | **(PREMIUM)** Minimum capacity to be available before scheduling more mirrors preemptively |
| `mirror_max_capacity` | integer | no | **(PREMIUM)** Maximum number of mirrors that can be synchronizing at the same time. |
| `mirror_max_delay` | integer | no | **(PREMIUM)** Maximum time (in minutes) between updates that a mirror can have when scheduled to synchronize. |
@@ -321,15 +321,15 @@ listed in the descriptions of the relevant settings.
| `project_export_enabled` | boolean | no | Enable project export. |
| `prometheus_metrics_enabled` | boolean | no | Enable Prometheus metrics. |
| `protected_ci_variables` | boolean | no | Environment variables are protected by default. |
-| `pseudonymizer_enabled` | boolean | no | **(PREMIUM)** When enabled, GitLab will run a background job that will produce pseudonymized CSVs of the GitLab database that will be uploaded to your configured object storage directory.
-| `push_event_activities_limit` | integer | no | Number of changes (branches or tags) in a single push to determine whether individual push events or bulk push events will be created. [Bulk push events will be created](../user/admin_area/settings/push_event_activities_limit.md) if it surpasses that value. |
-| `push_event_hooks_limit` | integer | no | Number of changes (branches or tags) in a single push to determine whether webhooks and services will be fired or not. Webhooks and services won't be submitted if it surpasses that value. |
+| `pseudonymizer_enabled` | boolean | no | **(PREMIUM)** When enabled, GitLab runs a background job that produces pseudonymized CSVs of the GitLab database to upload to your configured object storage directory.
+| `push_event_activities_limit` | integer | no | Number of changes (branches or tags) in a single push to determine whether individual push events or bulk push events are created. [Bulk push events are created](../user/admin_area/settings/push_event_activities_limit.md) if it surpasses that value. |
+| `push_event_hooks_limit` | integer | no | Number of changes (branches or tags) in a single push to determine whether webhooks and services fire or not. Webhooks and services aren't submitted if it surpasses that value. |
| `raw_blob_request_limit` | integer | no | Max number of requests per minute for each raw path. Default: 300. To disable throttling set to 0.|
| `recaptcha_enabled` | boolean | no | (**If enabled, requires:** `recaptcha_private_key` and `recaptcha_site_key`) Enable reCAPTCHA. |
| `recaptcha_private_key` | string | required by: `recaptcha_enabled` | Private key for reCAPTCHA. |
| `recaptcha_site_key` | string | required by: `recaptcha_enabled` | Site key for reCAPTCHA. |
| `receive_max_input_size` | integer | no | Maximum push size (MB). |
-| `repository_checks_enabled` | boolean | no | GitLab will periodically run `git fsck` in all project and wiki repositories to look for silent disk corruption issues. |
+| `repository_checks_enabled` | boolean | no | GitLab periodically runs `git fsck` in all project and wiki repositories to look for silent disk corruption issues. |
| `repository_size_limit` | integer | no | **(PREMIUM)** Size limit per repository (MB) |
| `repository_storages_weighted` | hash of strings to integers | no | (GitLab 13.1 and later) Hash of names of taken from `gitlab.yml` to [weights](../administration/repository_storage_paths.md#choose-where-new-repositories-are-stored). New projects are created in one of these stores, chosen by a weighted random selection. |
| `repository_storages` | array of strings | no | (GitLab 13.0 and earlier) List of names of enabled storage paths, taken from `gitlab.yml`. New projects are created in one of these stores, chosen at random. |
@@ -374,9 +374,9 @@ listed in the descriptions of the relevant settings.
| `two_factor_grace_period` | integer | required by: `require_two_factor_authentication` | Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication. |
| `unique_ips_limit_enabled` | boolean | no | (**If enabled, requires:** `unique_ips_limit_per_user` and `unique_ips_limit_time_window`) Limit sign in from multiple IPs. |
| `unique_ips_limit_per_user` | integer | required by: `unique_ips_limit_enabled` | Maximum number of IPs per user. |
-| `unique_ips_limit_time_window` | integer | required by: `unique_ips_limit_enabled` | How many seconds an IP will be counted towards the limit. |
-| `usage_ping_enabled` | boolean | no | Every week GitLab will report license usage back to GitLab, Inc. |
-| `user_default_external` | boolean | no | Newly registered users will be external by default. |
+| `unique_ips_limit_time_window` | integer | required by: `unique_ips_limit_enabled` | How many seconds an IP is counted towards the limit. |
+| `usage_ping_enabled` | boolean | no | Every week GitLab reports license usage back to GitLab, Inc. |
+| `user_default_external` | boolean | no | Newly registered users are external by default. |
| `user_default_internal_regex` | string | no | Specify an e-mail address regex pattern to identify default internal users. |
| `user_oauth_applications` | boolean | no | Allow users to register any application to use GitLab as an OAuth provider. |
| `user_show_add_ssh_key_message` | boolean | no | When set to `false` disable the "You won't be able to pull or push project code via SSH" warning shown to users with no uploaded SSH key. |
diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md
index 00cd88c88dd..bfe308a70f5 100644
--- a/doc/api/system_hooks.md
+++ b/doc/api/system_hooks.md
@@ -55,9 +55,9 @@ POST /hooks
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `url` | string | yes | The hook URL |
-| `token` | string | no | Secret token to validate received payloads; this will not be returned in the response |
-| `push_events` | boolean | no | When true, the hook will fire on push events |
-| `tag_push_events` | boolean | no | When true, the hook will fire on new tags being pushed |
+| `token` | string | no | Secret token to validate received payloads; this isn't returned in the response |
+| `push_events` | boolean | no | When true, the hook fires on push events |
+| `tag_push_events` | boolean | no | When true, the hook fires on new tags being pushed |
| `merge_requests_events` | boolean | no | Trigger hook on merge requests events |
| `repository_update_events` | boolean | no | Trigger hook on repository update events |
| `enable_ssl_verification` | boolean | no | Do SSL verification when triggering the hook |
diff --git a/doc/api/templates/licenses.md b/doc/api/templates/licenses.md
index d1044b23306..6733505405b 100644
--- a/doc/api/templates/licenses.md
+++ b/doc/api/templates/licenses.md
@@ -125,7 +125,7 @@ GET /templates/licenses/:key
NOTE: **Note:**
If you omit the `fullname` parameter but authenticate your request, the name of
-the authenticated user will be used to replace the copyright holder placeholder.
+the authenticated user replaces the copyright holder placeholder.
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/templates/licenses/mit?project=My+Cool+Project
diff --git a/doc/api/users.md b/doc/api/users.md
index e1fa97765df..0d837924507 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -170,7 +170,7 @@ GET /users
]
```
-Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see the `shared_runners_minutes_limit`, and `extra_shared_runners_minutes_limit` parameters.
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) also see the `shared_runners_minutes_limit`, and `extra_shared_runners_minutes_limit` parameters.
```json
[
@@ -184,7 +184,7 @@ Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/)
]
```
-Users on GitLab [Silver or higher](https://about.gitlab.com/pricing/) will also see
+Users on GitLab [Silver or higher](https://about.gitlab.com/pricing/) also see
the `group_saml` provider option:
```json
@@ -335,7 +335,7 @@ Example Responses:
NOTE: **Note:**
The `plan` and `trial` parameters are only available on GitLab Enterprise Edition.
-Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) also see
the `shared_runners_minutes_limit`, and `extra_shared_runners_minutes_limit` parameters.
```json
@@ -348,7 +348,7 @@ the `shared_runners_minutes_limit`, and `extra_shared_runners_minutes_limit` par
}
```
-Users on GitLab.com [Silver, or higher](https://about.gitlab.com/pricing/) will also
+Users on GitLab.com [Silver, or higher](https://about.gitlab.com/pricing/) also
see the `group_saml` option:
```json
@@ -385,10 +385,10 @@ over `password`. In addition, `reset_password` and
`force_random_password` can be used together.
NOTE: **Note:**
-From [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/29888/), `private_profile` will default to `false`.
+From [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/29888/), `private_profile` defaults to `false`.
NOTE: **Note:**
-From [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35604), `bio` will default to `""` instead of `null`.
+From [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35604), `bio` defaults to `""` instead of `null`.
```plaintext
POST /users
@@ -469,7 +469,7 @@ Parameters:
| `username` | No | Username |
| `website_url` | No | Website URL |
-On password update, user will be forced to change it upon next login.
+On password update, the user is forced to change it upon next login.
Note, at the moment this method does only return a `404` error,
even in cases where a `409` (Conflict) would be more appropriate.
For example, when renaming the email address to some existing one.
@@ -501,7 +501,7 @@ Parameters:
- `id` (required) - The ID of the user
- `hard_delete` (optional) - If true, contributions that would usually be
[moved to the ghost user](../user/profile/account/delete_account.md#associated-records)
- will be deleted instead, as well as groups owned solely by this user.
+ are deleted instead, as well as groups owned solely by this user.
## List current user (for normal users)
@@ -664,7 +664,7 @@ PUT /user/status
| `emoji` | string | no | The name of the emoji to use as status. If omitted `speech_balloon` is used. Emoji name can be one of the specified names in the [Gemojione index](https://github.com/bonusly/gemojione/blob/master/config/index.json). |
| `message` | string | no | The message to set as a status. It can also contain emoji codes. |
-When both parameters `emoji` and `message` are empty, the status will be cleared.
+When both parameters `emoji` and `message` are empty, the status is cleared.
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --data "emoji=coffee" --data "message=I crave coffee" "https://gitlab.example.com/api/v4/user/status"
@@ -792,7 +792,7 @@ Parameters:
}
```
-Will return created key with status `201 Created` on success. If an
+Returns a created key with status `201 Created` on success. If an
error occurs a `400 Bad Request` is returned with a message explaining the error:
```json
@@ -1147,7 +1147,7 @@ Parameters:
}
```
-Will return created email with status `201 Created` on success. If an
+Returns a created email with status `201 Created` on success. If an
error occurs a `400 Bad Request` is returned with a message explaining the error:
```json
@@ -1232,7 +1232,7 @@ Parameters:
- `id` (required) - ID of specified user
-Will return `201 OK` on success, `404 User Not Found` is user cannot be found or
+Returns `201 OK` on success, `404 User Not Found` is user cannot be found or
`403 Forbidden` when trying to unblock a user blocked by LDAP synchronization.
## Deactivate user
@@ -1379,11 +1379,11 @@ Example response:
## Create an impersonation token
> Requires admin permissions.
-> Token values are returned once. Make sure you save it - you won't be able to access it again.
+> Token values are returned once. Make sure you save it - you can't access it again.
It creates a new impersonation token. Note that only administrators can do this.
You are only able to create impersonation tokens to impersonate the user and perform
-both API calls and Git reads and writes. The user will not see these tokens in their profile
+both API calls and Git reads and writes. The user can't see these tokens in their profile
settings page.
```plaintext
@@ -1451,7 +1451,7 @@ CAUTION: **Warning:**
This feature might not be available to you. Check the **version history** note above for details.
> Requires admin permissions.
-> Token values are returned once. Make sure you save it - you won't be able to access it again.
+> Token values are returned once. Make sure you save it - you can't access it again.
It creates a new personal access token.
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index dabb18c1f75..49ada6d9a13 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -603,6 +603,32 @@ it "really connects to Prometheus", :permit_dns do
And if you need more specific control, the DNS blocking is implemented in
`spec/support/helpers/dns_helpers.rb` and these methods can be called elsewhere.
+#### Stubbing File methods
+
+In the situations where you need to
+[stub](https://relishapp.com/rspec/rspec-mocks/v/3-9/docs/basics/allowing-messages)
+methods such as `File.read`, make sure to:
+
+1. Stub `File.read` for only the filepath you are interested in.
+1. Call the original implementation for other filepaths.
+
+Otherwise `File.read` calls from other parts of the codebase get
+stubbed incorrectly. You should use the `stub_file_read`, and
+`expect_file_read` helper methods which does the stubbing for
+`File.read` correctly.
+
+```ruby
+# bad, all Files will read and return nothing
+allow(File).to receive(:read)
+
+# good
+stub_file_read(my_filepath)
+
+# also OK
+allow(File).to receive(:read).and_call_original
+allow(File).to receive(:read).with(my_filepath)
+```
+
#### Filesystem
Filesystem data can be roughly split into "repositories", and "everything else".
diff --git a/doc/downgrade_ee_to_ce/README.md b/doc/downgrade_ee_to_ce/README.md
index 2561ee875d2..dd8db80f849 100644
--- a/doc/downgrade_ee_to_ce/README.md
+++ b/doc/downgrade_ee_to_ce/README.md
@@ -24,8 +24,7 @@ alternative authentication methods to your users.
### Remove Service Integration entries from the database
The `JenkinsService` and `GithubService` classes are only available in the Enterprise Edition codebase,
-so if you downgrade to the Community Edition, you'll come across the following
-error:
+so if you downgrade to the Community Edition, the following error displays:
```plaintext
Completed 500 Internal Server Error in 497ms (ActiveRecord: 32.2ms)
diff --git a/doc/migrate_ci_to_ce/README.md b/doc/migrate_ci_to_ce/README.md
index 17f9db10767..c2eedb08823 100644
--- a/doc/migrate_ci_to_ce/README.md
+++ b/doc/migrate_ci_to_ce/README.md
@@ -11,7 +11,7 @@ Beginning with version 8.0 of GitLab Community Edition (CE) and Enterprise
Edition (EE), GitLab CI is no longer its own application, but is instead built
into the CE and EE applications.
-This guide will detail the process of migrating your CI installation and data
+This guide details the process of migrating your CI installation and data
into your GitLab CE or EE installation. **You can only migrate CI data from
GitLab CI 8.0 to GitLab 8.0; migrating between other versions (e.g.7.14 to 8.1)
is not possible.**
@@ -28,9 +28,9 @@ The migration consists of three parts: updating GitLab and GitLab CI, moving
data, and redirecting traffic.
Please note that CI builds triggered on your GitLab server in the time between
-updating to 8.0 and finishing the migration will be lost. Your GitLab server
+updating to 8.0 and finishing the migration are lost. Your GitLab server
can be online for most of the procedure; the only GitLab downtime (if any) is
-during the upgrade to 8.0. Your CI service will be offline from the moment you
+during the upgrade to 8.0. Your CI service remains offline from the moment you
upgrade to 8.0 until you finish the migration procedure.
## Before upgrading
@@ -47,8 +47,8 @@ If you want to migrate your existing data, continue reading.
### 0. Updating Omnibus from versions prior to 7.13
-If you are updating from older versions you should first update to 7.14 and then to 8.0.
-Otherwise it's pretty likely that you will encounter problems described in the [Troubleshooting](#troubleshooting).
+If you are updating from older versions you should first update to 7.14 and then to 8.0
+to avoid the problems described in the [Troubleshooting](#troubleshooting) section.
### 1. Verify that backups work
@@ -123,7 +123,7 @@ store build traces on the same storage as your Git repositories.
## I. Upgrading
-From this point on, GitLab CI will be unavailable for your end users.
+From this point on, GitLab CI is unavailable for your end users.
### 1. Upgrade GitLab to 8.0
@@ -169,10 +169,10 @@ sudo -u gitlab_ci -H bundle exec whenever --clear-crontab RAILS_ENV=production
### 1. Database encryption key
Move the database encryption key from your CI server to your GitLab
- server. The command below will show you what you need to copy-paste to your
-GitLab server. On Omnibus GitLab servers you will have to add a line to
-`/etc/gitlab/gitlab.rb`. On GitLab servers installed from source you will have
-to replace the contents of `/home/git/gitlab/config/secrets.yml`.
+ server. The command below shows you what you need to copy-paste to your
+GitLab server. On Omnibus GitLab servers you must add a line to
+`/etc/gitlab/gitlab.rb`. On GitLab servers installed from source you must
+replace the contents of `/home/git/gitlab/config/secrets.yml`.
```shell
# On your CI server:
@@ -188,8 +188,8 @@ sudo -u gitlab_ci -H bundle exec rake backup:show_secrets RAILS_ENV=production
Create your final CI data export. If you are converting from MySQL to
PostgreSQL, add `MYSQL_TO_POSTGRESQL=1` to the end of the Rake command. When
-the command finishes it will print the path to your data export archive; you
-will need this file later.
+the command finishes it prints the path to your data export archive; you
+need this file later.
```shell
# On your CI server:
@@ -208,7 +208,7 @@ If you were running GitLab and GitLab CI on the same server you can skip this
step.
Copy your CI data archive to your GitLab server. There are many ways to do
-this, below we use SSH agent forwarding and `scp`, which will be easy and fast
+this, below we use SSH agent forwarding and `scp`, which is easy and fast
for most setups. You can also copy the data archive first from the CI server to
your laptop and then from your laptop to the GitLab server.
@@ -235,7 +235,7 @@ sudo mv /path/to/12345_gitlab_ci_backup.tar /home/git/gitlab/tmp/backups/
### 5. Import the CI data into GitLab
-This step will delete any existing CI data on your GitLab server. There should
+This step deletes any existing CI data on your GitLab server. There should
be no CI data yet because you turned CI on the GitLab server off earlier.
```shell
@@ -274,8 +274,8 @@ so that existing links to your CI server keep working.
### 1. Update NGINX configuration
To ensure that your existing CI runners are able to communicate with the
-migrated installation, and that existing build triggers still work, you'll need
-to update your NGINX configuration to redirect requests for the old locations to
+migrated installation, and that existing build triggers still work, you must
+update your NGINX configuration to redirect requests for the old locations to
the new ones.
Edit `/etc/nginx/sites-available/gitlab_ci` and paste:
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index 1f9486dc324..51a9131ac5c 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -17,19 +17,19 @@ public access directory (`/public` under your GitLab instance), like at <https:/
Public projects can be cloned **without any** authentication over HTTPS.
-They will be listed in the public access directory (`/public`) for all users.
+They are listed in the public access directory (`/public`) for all users.
-**Any logged in user** will have [Guest permissions](../user/permissions.md)
+**Any logged in user** has [Guest permissions](../user/permissions.md)
on the repository.
### Internal projects
Internal projects can be cloned by any logged in user except [external users](../user/permissions.md#external-users).
-They will also be listed in the public access directory (`/public`), but only for logged
+They are also listed in the public access directory (`/public`), but only for logged
in users.
-Any logged in user except [external users](../user/permissions.md#external-users) will have [Guest permissions](../user/permissions.md)
+Any logged in users except [external users](../user/permissions.md#external-users) have [Guest permissions](../user/permissions.md)
on the repository.
NOTE: **Note:**
@@ -42,7 +42,7 @@ visibility setting keep this setting. You can read more about the change in the
Private projects can only be cloned and viewed by project members (except for guests).
-They will appear in the public access directory (`/public`) for project members only.
+They appear in the public access directory (`/public`) for project members only.
### How to change project visibility
@@ -59,7 +59,7 @@ In previous versions, a group's page was always visible to all users.
Like with projects, the visibility of a group can be set to dictate whether
anonymous users, all signed in users, or only explicit group members can view
it. The restriction for visibility levels on the application setting level also
-applies to groups, so if that's set to internal, the explore page will be empty
+applies to groups, so if that's set to internal, the explore page is empty
for anonymous users. The group page now has a visibility level icon.
Admin users cannot create subgroups or projects with higher visibility level than that of the immediate parent group.
@@ -96,7 +96,7 @@ For details, see [Restricted visibility levels](../user/admin_area/settings/visi
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33358) in GitLab 12.6.
-Reducing a project's visibility level will remove the fork relationship between the project and
+Reducing a project's visibility level removes the fork relationship between the project and
any forked project. This is a potentially destructive action which requires confirmation before
this can be saved.
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index 00a3e9196e2..71eca512463 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -18,7 +18,7 @@ have finished, which otherwise may lead to data loss.
When you remove LFS files from a repository's history, they become orphaned and continue to consume
disk space. With this Rake task, you can remove invalid references from the database, which
-will allow garbage collection of LFS files.
+allows garbage collection of LFS files.
For example:
@@ -44,7 +44,7 @@ By default, this task does not delete anything but shows how many file reference
delete. Run the command with `DRY_RUN=false` if you actually want to
delete the references. You can also use `LIMIT={number}` parameter to limit the number of deleted references.
-Note that this Rake task only removes the references to LFS files. Unreferenced LFS files will be garbage-collected
+Note that this Rake task only removes the references to LFS files. Unreferenced LFS files are garbage-collected
later (once a day). If you need to garbage collect them immediately, run
`rake gitlab:cleanup:orphan_lfs_files` described below.
@@ -149,7 +149,7 @@ I, [2018-08-02T10:26:47.764356 #45087] INFO -- : Moved to lost and found: @hash
> - [`ionice` support fixed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28023) in GitLab 12.10.
NOTE: **Note:**
-These commands will not work for artifacts stored on
+These commands don't work for artifacts stored on
[object storage](../administration/object_storage.md).
When you notice there are more job artifacts files and/or directories on disk than there
@@ -179,10 +179,10 @@ You can also limit the number of files to delete with `LIMIT`:
sudo gitlab-rake gitlab:cleanup:orphan_job_artifact_files LIMIT=100
```
-This will only delete up to 100 files from disk. You can use this to
-delete a small set for testing purposes.
+This deletes only up to 100 files from disk. You can use this to delete a small
+set for testing purposes.
-If you provide `DEBUG=1`, you'll see the full path of every file that
+Providing `DEBUG=1` displays the full path of every file that
is detected as being an orphan.
If `ionice` is installed, the tasks uses it to ensure the command is
diff --git a/doc/raketasks/features.md b/doc/raketasks/features.md
index ecdf6aee069..0bf0dd2b826 100644
--- a/doc/raketasks/features.md
+++ b/doc/raketasks/features.md
@@ -10,11 +10,11 @@ This Rake task enables [namespaces](../user/group/index.md#namespaces) for proje
## Enable usernames and namespaces for user projects
-This command will enable the namespaces feature introduced in GitLab 4.0. It will move every project in its namespace folder.
+This command enables the namespaces feature introduced in GitLab 4.0. It moves every project in its namespace folder.
Note:
-- The **repository location will change**, so you will need to **update all your Git URLs** to
+- The **repository location changes as part of this task**, so you must **update all your Git URLs** to
point to the new location.
- The username can be changed at **Profile > Account**.
diff --git a/doc/topics/application_development_platform/index.md b/doc/topics/application_development_platform/index.md
index c38b067f1f3..9882904a371 100644
--- a/doc/topics/application_development_platform/index.md
+++ b/doc/topics/application_development_platform/index.md
@@ -35,12 +35,12 @@ of newer, more efficient, more profitable, and less error-prone techniques for s
Because at GitLab we are [cloud-native first](https://about.gitlab.com/handbook/product/#cloud-native-first) our
Application Development Platform initially focuses on providing robust support for Kubernetes, with other platforms
-to follow. Teams can bring their own clusters and we will additionally make it easy to create new infrastructure
+to follow. Teams can bring their own clusters and we additionally make it easy to create new infrastructure
with various cloud providers.
### Build, test, deploy
-In order to provide modern DevOps workflows, our Application Development Platform will rely on
+In order to provide modern DevOps workflows, our Application Development Platform relies on
[Auto DevOps](../autodevops/index.md) to provide those workflows. Auto DevOps works with
any Kubernetes cluster; you're not limited to running on GitLab's infrastructure. Additionally, Auto DevOps offers
an incremental consumption path. Because it is [composable](../autodevops/customize.md#using-components-of-auto-devops),
diff --git a/doc/topics/git/lfs/migrate_to_git_lfs.md b/doc/topics/git/lfs/migrate_to_git_lfs.md
index 596b2cb400f..bf7c69eb9ba 100644
--- a/doc/topics/git/lfs/migrate_to_git_lfs.md
+++ b/doc/topics/git/lfs/migrate_to_git_lfs.md
@@ -10,9 +10,8 @@ description: "How to migrate an existing Git repository to Git LFS with BFG."
Using Git LFS can help you to reduce the size of your Git
repository and improve its performance.
-However, simply adding the
-large files that are already in your repository to Git LFS,
-will not actually reduce the size of your repository because
+However, simply adding the large files that are already in your repository to Git LFS
+doesn't actually reduce the size of your repository because
the files are still referenced by previous commits.
Through the method described on this document, first migrate
@@ -41,7 +40,7 @@ Before beginning, make sure:
Branches based on the repository before applying this method cannot be merged.
Branches based on the repo before applying this method cannot be merged.
-To follow this tutorial, you'll need:
+To follow this tutorial, you need:
- Maintainer permissions to the existing Git repository
you'd like to migrate to LFS with access through the command line.
@@ -74,7 +73,7 @@ Consider an example upstream project, `git@gitlab.com:gitlab-tests/test-git-lfs-
1. Clone `--mirror` the repository:
- Cloning with the mirror flag will create a bare repository.
+ Cloning with the mirror flag creates a bare repository.
This ensures you get all the branches within the repo.
It creates a directory called `<repo-name>.git`
@@ -150,7 +149,7 @@ Consider an example upstream project, `git@gitlab.com:gitlab-tests/test-git-lfs-
```
Now all existing the files you converted, as well as the new
- ones you add, will be properly tracked with LFS.
+ ones you add, are properly tracked with LFS.
1. [Re-protect the default branch](../../../user/project/protected_branches.md):
diff --git a/doc/topics/index.md b/doc/topics/index.md
index 91b1905f1b6..a5dcfa5fc57 100644
--- a/doc/topics/index.md
+++ b/doc/topics/index.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Welcome to Topics! We have organized our content resources into topics
to get you started on areas of your interest. Each topic page
-consists of an index listing all related content. It will guide
+consists of an index listing all related content. It guides
you through better understanding GitLab's concepts
through our regular docs, and, when available, through articles (guides,
tutorials, technical overviews, blog posts) and videos.
diff --git a/doc/topics/offline/quick_start_guide.md b/doc/topics/offline/quick_start_guide.md
index 92f8f9167b7..d4c1a9d72b9 100644
--- a/doc/topics/offline/quick_start_guide.md
+++ b/doc/topics/offline/quick_start_guide.md
@@ -18,12 +18,12 @@ server's name.
Follow the installation instructions [as outlined in the omnibus install
guide](https://about.gitlab.com/install/#ubuntu), but make sure to specify an `http`
-URL for the `EXTERNAL_URL` installation step. Once installed, we will manually
+URL for the `EXTERNAL_URL` installation step. Once installed, we can manually
configure the SSL ourselves.
It is strongly recommended to setup a domain for IP resolution rather than bind
to the server's IP address. This better ensures a stable target for our certs' CN
-and will make long-term resolution simpler.
+and makes long-term resolution simpler.
```shell
sudo EXTERNAL_URL="http://my-host.internal" install gitlab-ee
diff --git a/doc/user/admin_area/appearance.md b/doc/user/admin_area/appearance.md
index 23a6de38e17..d7f0dd935db 100644
--- a/doc/user/admin_area/appearance.md
+++ b/doc/user/admin_area/appearance.md
@@ -16,7 +16,7 @@ section.
By default, the navigation bar has the GitLab logo, but this can be customized with
any image desired. It is optimized for images 28px high (any width), but any image can be
-used (less than 1MB) and it will automatically be resized.
+used (less than 1MB) and it is automatically resized.
![Navigation bar header logo screenshot](img/appearance_header_logo_v12_3.png)
@@ -24,7 +24,7 @@ Once you select and upload an image, click **Update appearance settings** at the
of the page to activate it in the GitLab instance.
NOTE: **Note:**
-GitLab pipeline emails will also display the custom logo.
+GitLab pipeline emails also display the custom logo.
## Favicon
@@ -45,7 +45,7 @@ of the page to activate it in the GitLab instance.
> - [Added](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55057) to [GitLab Core](https://about.gitlab.com/pricing/) in 11.9.
You can add a small header message, a small footer message, or both, to the interface
-of your GitLab instance. These messages will appear on all projects and pages of the
+of your GitLab instance. These messages appear on all projects and pages of the
instance, including the sign in / sign up page. The default color is white text on
an orange background, but this can be customized by clicking on **Customize colors**.
@@ -69,7 +69,7 @@ and logo. You can make full use of [Markdown](../markdown.md) in the description
![sign in message screenshot](img/appearance_sign_in_v12_3.png)
The optimal size for the logo is 640x360px, but any image can be used (below 1MB)
-and it will be resized automatically. The logo image will appear between the title and
+and it is resized automatically. The logo image appears between the title and
the description, on the left of the sign-up page.
![sign in message preview screenshot](img/appearance_sign_in_preview_v12_3.png)
@@ -88,12 +88,12 @@ You can make full use of [Markdown](../markdown.md) in the description:
![new project message screenshot](img/appearance_new_project_v12_3.png)
-The message will be displayed below the **New Project** message, on the left side
+The message is displayed below the **New Project** message, on the left side
of the **New project page**.
After you add a message, click **Update appearance settings** at the bottom of the page
to activate it in the GitLab instance. You can also click on the **New project page**
-button, which will bring you to the new project page so you can review the change.
+button, which brings you to the new project page so you can review the change.
![new project message preview screenshot](img/appearance_new_project_preview_v12_3.png)
diff --git a/doc/user/admin_area/settings/external_authorization.md b/doc/user/admin_area/settings/external_authorization.md
index 80bca6f5b2c..6e32d15d8f4 100644
--- a/doc/user/admin_area/settings/external_authorization.md
+++ b/doc/user/admin_area/settings/external_authorization.md
@@ -17,26 +17,26 @@ authorization with your own defined service.
## Overview
-Once the external service is configured and enabled, when a project is accessed,
-a request is made to the external service with the user information and project
-classification label assigned to the project. When the service replies with a
-known response, the result is cached for 6 hours.
+After the external service is configured and enabled, when a project is
+accessed, a request is made to the external service with the user information
+and project classification label assigned to the project. When the service
+replies with a known response, the result is cached for six hours.
-If the external authorization is enabled, GitLab will further block pages and
+If the external authorization is enabled, GitLab further blocks pages and
functionality that render cross-project data. That includes:
- Most pages under Dashboard (Activity, Milestones, Snippets, Assigned merge
requests, Assigned issues, To-Do List).
- Under a specific group (Activity, Contribution analytics, Issues, Issue boards,
Labels, Milestones, Merge requests).
-- Global and Group search will be disabled.
+- Global and Group search are disabled.
This is to prevent performing to many requests at once to the external
authorization service.
Whenever access is granted or denied this is logged in a log file called
-`external-policy-access-control.log`.
-Read more about logs GitLab keeps in the [omnibus documentation](https://docs.gitlab.com/omnibus/settings/logs.html).
+`external-policy-access-control.log`. Read more about the logs GitLab keeps in
+the [Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/settings/logs.html).
## Configuration
@@ -48,7 +48,7 @@ The external authorization service can be enabled by an admin on the GitLab's
The available required properties are:
- **Service URL**: The URL to make authorization requests to. When leaving the
- URL blank, cross project features will remain available while still being able
+ URL blank, cross project features remain available while still being able
to specify classification labels for projects.
- **External authorization request timeout**: The timeout after which an
authorization request is aborted. When a request times out, access is denied
@@ -58,19 +58,21 @@ The available required properties are:
- **Client authentication key**: Private key for the certificate when
authentication is required for the external authorization service, this is
encrypted when stored.
-- **Client authentication key password**: Passphrase to use for the private key when authenticating with the external service this is encrypted when stored.
+- **Client authentication key password**: Passphrase to use for the private key
+ when authenticating with the external service this is encrypted when stored.
- **Default classification label**: The classification label to use when
requesting authorization if no specific label is defined on the project
When using TLS Authentication with a self signed certificate, the CA certificate
-needs to be trusted by the OpenSSL installation. When using GitLab installed using
-Omnibus, learn to install a custom CA in the
-[omnibus documentation](https://docs.gitlab.com/omnibus/settings/ssl.html). Alternatively learn where to install
-custom certificates using `openssl version -d`.
+needs to be trusted by the OpenSSL installation. When using GitLab installed
+using Omnibus, learn to install a custom CA in the
+[Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/settings/ssl.html).
+Alternatively, learn where to install custom certificates by using
+`openssl version -d`.
## How it works
-When GitLab requests access, it will send a JSON POST request to the external
+When GitLab requests access, it sends a JSON POST request to the external
service with this body:
```json
@@ -85,14 +87,17 @@ service with this body:
}
```
-The `user_ldap_dn` is optional and is only sent when the user is logged in
+The `user_ldap_dn` is optional and is only sent when the user is signed in
through LDAP.
-`identities` will contain the details of all the identities associated with the user. This will be an empty array if there are no identities associated with the user.
+`identities` contains the details of all the identities associated with the
+user. This is an empty array if there are no identities associated with the
+user.
When the external authorization service responds with a status code 200, the
user is granted access. When the external service responds with a status code
-401 or 403, the user is denied access. In any case, the request is cached for 6 hours.
+401 or 403, the user is denied access. In any case, the request is cached for
+six hours.
When denying access, a `reason` can be optionally specified in the JSON body:
@@ -102,20 +107,20 @@ When denying access, a `reason` can be optionally specified in the JSON body:
}
```
-Any other status code than 200, 401 or 403 will also deny access to the user, but the
-response will not be cached.
+Any other status code than 200, 401 or 403 also deny access to the user, but the
+response isn't cached.
If the service times out (after 500ms), a message "External Policy Server did
-not respond" will be displayed.
+not respond" is displayed.
## Classification labels
You can use your own classification label in the project's
**Settings > General > General project settings** page in the "Classification
label" box. When no classification label is specified on a project, the default
-label defined in the [global settings](#configuration) will be used.
+label defined in the [global settings](#configuration) is used.
-The label will be shown on all project pages in the upper right corner.
+The label is shown on all project pages in the upper right corner.
![classification label on project page](img/classification_label_on_project_page.png)
diff --git a/doc/user/admin_area/settings/index.md b/doc/user/admin_area/settings/index.md
index 21d495de5b7..e78a3319e2f 100644
--- a/doc/user/admin_area/settings/index.md
+++ b/doc/user/admin_area/settings/index.md
@@ -63,7 +63,7 @@ Access the default page for admin area settings by navigating to **Admin Area >
| Option | Description |
| ------ | ----------- |
| [Continuous Integration and Deployment](continuous_integration.md) | Auto DevOps, runners and job artifacts. |
-| [Required pipeline configuration](continuous_integration.md#required-pipeline-configuration) **(PREMIUM ONLY)** | Set an instance-wide auto included [pipeline configuration](../../../ci/yaml/README.md). This pipeline configuration will be run after the project's own configuration. |
+| [Required pipeline configuration](continuous_integration.md#required-pipeline-configuration) **(PREMIUM ONLY)** | Set an instance-wide auto included [pipeline configuration](../../../ci/yaml/README.md). This pipeline configuration is run after the project's own configuration. |
| [Package Registry](continuous_integration.md#package-registry-configuration) | Settings related to the use and experience of using GitLab's Package Registry. Note there are [risks involved](../../packages/container_registry/index.md#use-with-external-container-registries) in enabling some of these settings. |
## Reporting
@@ -98,7 +98,7 @@ Access the default page for admin area settings by navigating to **Admin Area >
| Option | Description |
| ------ | ----------- |
-| Geo | Geo allows you to replicate your GitLab instance to other geographical locations. Redirects to **Admin Area > Geo > Settings**, and will no longer be available at **Admin Area > Settings > Geo** in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/36896). |
+| Geo | Geo allows you to replicate your GitLab instance to other geographical locations. Redirects to **Admin Area > Geo > Settings** are no longer available at **Admin Area > Settings > Geo** in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/36896). |
## Preferences
diff --git a/doc/user/admin_area/settings/terms.md b/doc/user/admin_area/settings/terms.md
index 95c32af5716..e6b13d9b703 100644
--- a/doc/user/admin_area/settings/terms.md
+++ b/doc/user/admin_area/settings/terms.md
@@ -29,7 +29,7 @@ To enforce acceptance of a Terms of Service and Privacy Policy:
![Enable enforcing Terms of Service](img/enforce_terms.png)
For each update to the terms, a new version is stored. When a user accepts or declines the terms,
-GitLab will record which version they accepted or declined.
+GitLab records which version they accepted or declined.
## New users
@@ -37,28 +37,28 @@ When this feature is enabled, a checkbox is added to the sign-up form.
![Sign up form](img/sign_up_terms.png)
-This checkbox will be required during sign up.
+This checkbox is required during sign up.
Users can review the terms entered in the admin panel before
-accepting. The page will be opened in a new window so they can
+accepting. The page is opened in a new window so they can
continue their registration afterwards.
## Accepting terms
When this feature is enabled, the users that have not accepted the
-terms of service will be presented with a screen where they can either
+terms of service are presented with a screen where they can either
accept or decline the terms.
![Respond to terms](img/respond_to_terms.png)
-If the user accepts the terms, they will be directed to where they
-were going. After a sign-in or sign-up this will most likely be the
+If the user accepts the terms, they are directed to where they
+were going. After a sign-in or sign-up this is most likely the
dashboard.
If the user was already logged in when the feature was turned on,
-they will be asked to accept the terms on their next interaction.
+they are asked to accept the terms on their next interaction.
-If a user declines the terms, they will be signed out.
+If a user declines the terms, they are signed out.
<!-- ## Troubleshooting
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e96ceb193c7..e0de85acdec 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3093,6 +3093,9 @@ msgstr ""
msgid "An error occurred while generating a username. Please try again."
msgstr ""
+msgid "An error occurred while getting autocomplete data. Please refresh the page and try again."
+msgstr ""
+
msgid "An error occurred while getting files for - %{branchId}"
msgstr ""
diff --git a/package.json b/package.json
index cc1f4eb1bc8..76837471c69 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.5",
"@gitlab/svgs": "1.175.0",
- "@gitlab/ui": "23.9.0",
+ "@gitlab/ui": "23.12.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-3",
"@rails/ujs": "^6.0.3-2",
diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb
index 9ac42cbc3ec..6927df3b1c7 100644
--- a/spec/controllers/help_controller_spec.rb
+++ b/spec/controllers/help_controller_spec.rb
@@ -101,7 +101,8 @@ RSpec.describe HelpController do
context 'for Markdown formats' do
context 'when requested file exists' do
before do
- expect(File).to receive(:read).and_return(fixture_file('blockquote_fence_after.md'))
+ expect_file_read(File.join(Rails.root, 'doc/ssh/README.md'), content: fixture_file('blockquote_fence_after.md'))
+
get :show, params: { path: 'ssh/README' }, format: :md
end
@@ -213,6 +214,6 @@ RSpec.describe HelpController do
end
def stub_readme(content)
- expect(File).to receive(:read).and_return(content)
+ expect_file_read(Rails.root.join('doc', 'README.md'), content: content)
end
end
diff --git a/spec/features/projects/blobs/balsamiq_spec.rb b/spec/features/projects/blobs/balsamiq_spec.rb
new file mode 100644
index 00000000000..bce60856544
--- /dev/null
+++ b/spec/features/projects/blobs/balsamiq_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Balsamiq file blob', :js do
+ let(:project) { create(:project, :public, :repository) }
+
+ before do
+ visit project_blob_path(project, 'add-balsamiq-file/files/images/balsamiq.bmpr')
+
+ wait_for_requests
+ end
+
+ it 'displays Balsamiq file content' do
+ expect(page).to have_content("Mobile examples")
+ end
+end
diff --git a/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap b/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
index 5fad0d07f97..8948a9926bb 100644
--- a/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
+++ b/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
@@ -18,7 +18,9 @@ exports[`AddContextCommitsModal renders modal with 2 tabs 1`] = `
theme="indigo"
value="0"
>
- <gl-tab-stub>
+ <gl-tab-stub
+ titlelinkclass=""
+ >
<div
class="mt-2"
@@ -37,7 +39,9 @@ exports[`AddContextCommitsModal renders modal with 2 tabs 1`] = `
</div>
</gl-tab-stub>
- <gl-tab-stub>
+ <gl-tab-stub
+ titlelinkclass=""
+ >
<review-tab-container-stub
commits=""
diff --git a/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_new_spec.js.snap b/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_new_spec.js.snap
index e2ef7483316..98c79b406f2 100644
--- a/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_new_spec.js.snap
+++ b/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_new_spec.js.snap
@@ -28,7 +28,7 @@ exports[`AlertsSettingsFormNew with default values renders the initial template
<div id=\\"integration-webhook\\" role=\\"group\\" class=\\"form-group gl-form-group\\"><label id=\\"integration-webhook__BV_label_\\" for=\\"integration-webhook\\" class=\\"d-block col-form-label\\">3. Set up webhook</label>
<div class=\\"bv-no-focus-ring\\"><span>Utilize the URL and authorization key below to authorize an external service to send alerts to GitLab. Review your external service's documentation to learn where to add these details, and the <a rel=\\"noopener noreferrer\\" target=\\"_blank\\" href=\\"https://docs.gitlab.com/ee/operations/incident_management/alert_integrations.html\\" class=\\"gl-link gl-display-inline-block\\">GitLab documentation</a> to learn more about configuring your endpoint.</span> <label class=\\"gl-display-flex gl-flex-direction-column gl-mb-0 gl-w-max-content gl-my-4 gl-font-weight-normal\\">
<div class=\\"gl-toggle-wrapper\\"><span class=\\"gl-toggle-label\\">Active</span>
- <!----> <button aria-label=\\"Active\\" type=\\"button\\" class=\\"gl-toggle\\"><span class=\\"toggle-icon\\"><svg data-testid=\\"close-icon\\" class=\\"gl-icon s16\\"><use href=\\"#close\\"></use></svg></span></button></div>
+ <!----> <button aria-label=\\"Active\\" type=\\"button\\" class=\\"gl-toggle\\"><span class=\\"toggle-icon\\"><svg data-testid=\\"close-icon\\" aria-hidden=\\"true\\" class=\\"gl-icon s16\\"><use href=\\"#close\\"></use></svg></span></button></div>
<!---->
</label>
<!---->
@@ -40,7 +40,7 @@ exports[`AlertsSettingsFormNew with default values renders the initial template
<!---->
<!----> <input id=\\"url\\" type=\\"text\\" readonly=\\"readonly\\" class=\\"gl-form-input form-control\\">
<div class=\\"input-group-append\\"><button title=\\"Copy\\" data-clipboard-text=\\"\\" aria-label=\\"Copy this value\\" type=\\"button\\" class=\\"btn gl-m-0! btn-default btn-md gl-button btn-default-secondary btn-icon\\">
- <!----> <svg data-testid=\\"copy-to-clipboard-icon\\" class=\\"gl-button-icon gl-icon s16\\">
+ <!----> <svg data-testid=\\"copy-to-clipboard-icon\\" aria-hidden=\\"true\\" class=\\"gl-button-icon gl-icon s16\\">
<use href=\\"#copy-to-clipboard\\"></use>
</svg>
<!----></button></div>
@@ -56,7 +56,7 @@ exports[`AlertsSettingsFormNew with default values renders the initial template
<!---->
<!----> <input id=\\"authorization-key\\" type=\\"text\\" readonly=\\"readonly\\" class=\\"gl-form-input form-control\\">
<div class=\\"input-group-append\\"><button title=\\"Copy\\" data-clipboard-text=\\"\\" aria-label=\\"Copy this value\\" type=\\"button\\" class=\\"btn gl-m-0! btn-default btn-md gl-button btn-default-secondary btn-icon\\">
- <!----> <svg data-testid=\\"copy-to-clipboard-icon\\" class=\\"gl-button-icon gl-icon s16\\">
+ <!----> <svg data-testid=\\"copy-to-clipboard-icon\\" aria-hidden=\\"true\\" class=\\"gl-button-icon gl-icon s16\\">
<use href=\\"#copy-to-clipboard\\"></use>
</svg>
<!----></button></div>
diff --git a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
index de40e03b598..6f28573c808 100644
--- a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
+++ b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
@@ -53,6 +53,7 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
type="button"
>
<svg
+ aria-hidden="true"
class="gl-icon s16 gl-new-dropdown-item-check-icon"
data-testid="mobile-issue-close-icon"
>
@@ -107,6 +108,7 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
type="button"
>
<svg
+ aria-hidden="true"
class="gl-icon s16 gl-new-dropdown-item-check-icon gl-visibility-hidden"
data-testid="mobile-issue-close-icon"
>
diff --git a/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap b/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap
index 62e527a2c5f..b59d1597a12 100644
--- a/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap
+++ b/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap
@@ -17,6 +17,7 @@ exports[`Code navigation popover component renders popover 1`] = `
>
<gl-tab-stub
title="Definition"
+ titlelinkclass=""
>
<div
class="overflow-auto code-navigation-popover-container"
@@ -76,6 +77,7 @@ exports[`Code navigation popover component renders popover 1`] = `
<gl-tab-stub
class="py-2"
data-testid="references-tab"
+ titlelinkclass=""
>
<p
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
index 072e611b9a4..2b3c803be08 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
@@ -43,6 +43,7 @@ exports[`IncidentsSettingTabs should render the component 1`] = `
>
<gl-tab-stub
title="Alert integration"
+ titlelinkclass=""
>
<alertssettingsform-stub
class="gl-pt-3"
@@ -51,6 +52,7 @@ exports[`IncidentsSettingTabs should render the component 1`] = `
</gl-tab-stub>
<gl-tab-stub
title="PagerDuty integration"
+ titlelinkclass=""
>
<pagerdutysettingsform-stub
class="gl-pt-3"
diff --git a/spec/frontend/issuable/related_issues/components/issue_token_spec.js b/spec/frontend/issuable/related_issues/components/issue_token_spec.js
index 1b4c6b548e2..d5181d4a17a 100644
--- a/spec/frontend/issuable/related_issues/components/issue_token_spec.js
+++ b/spec/frontend/issuable/related_issues/components/issue_token_spec.js
@@ -100,7 +100,7 @@ describe('IssueToken', () => {
state,
});
- expect(findReferenceIcon().attributes('aria-label')).toBe(state);
+ expect(findReferenceIcon().props('ariaLabel')).toBe(state);
expect(findReference().text()).toBe(displayReference);
expect(findTitle().text()).toBe(title);
});
diff --git a/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap b/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap
index fe6d9a34078..c40b7c90c72 100644
--- a/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap
+++ b/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap
@@ -120,6 +120,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
class="gl-search-box-by-type"
>
<svg
+ aria-hidden="true"
class="gl-search-box-by-type-search-icon gl-icon s16"
data-testid="search-icon"
>
@@ -234,6 +235,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
class="gl-search-box-by-type"
>
<svg
+ aria-hidden="true"
class="gl-search-box-by-type-search-icon gl-icon s16"
data-testid="search-icon"
>
diff --git a/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap
index 19a649089e0..adb6c935f96 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap
@@ -11,6 +11,7 @@ exports[`Expand button on click when short text is provided renders button after
<!---->
<svg
+ aria-hidden="true"
class="gl-button-icon gl-icon s16"
data-testid="ellipsis_h-icon"
>
@@ -39,6 +40,7 @@ exports[`Expand button on click when short text is provided renders button after
<!---->
<svg
+ aria-hidden="true"
class="gl-button-icon gl-icon s16"
data-testid="ellipsis_h-icon"
>
@@ -62,6 +64,7 @@ exports[`Expand button when short text is provided renders button before text 1`
<!---->
<svg
+ aria-hidden="true"
class="gl-button-icon gl-icon s16"
data-testid="ellipsis_h-icon"
>
@@ -90,6 +93,7 @@ exports[`Expand button when short text is provided renders button before text 1`
<!---->
<svg
+ aria-hidden="true"
class="gl-button-icon gl-icon s16"
data-testid="ellipsis_h-icon"
>
diff --git a/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap b/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap
new file mode 100644
index 00000000000..d0fa2086fdc
--- /dev/null
+++ b/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap
@@ -0,0 +1,47 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`gfm_autocomplete/utils issues config shows the iid and title in the menu item within a project context 1`] = `"<small>123456</small> Project context issue title &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;"`;
+
+exports[`gfm_autocomplete/utils issues config shows the reference and title in the menu item within a group context 1`] = `"<small>gitlab#987654</small> Group context issue title &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;"`;
+
+exports[`gfm_autocomplete/utils labels config shows the title in the menu item 1`] = `
+"
+ <span class=\\"dropdown-label-box\\" style=\\"background: #123456;\\"></span>
+ bug &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;"
+`;
+
+exports[`gfm_autocomplete/utils members config shows an avatar character, name, parent name, and count in the menu item for a group 1`] = `
+"
+ <div class=\\"gl-display-flex gl-align-items-center\\">
+ <div class=\\"gl-avatar gl-avatar-s24 gl-flex-shrink-0 gl-rounded-small
+ gl-display-flex gl-align-items-center gl-justify-content-center\\" aria-hidden=\\"true\\">
+ G</div>
+ <div class=\\"gl-font-sm gl-line-height-normal gl-ml-3\\">
+ <div>1-1s &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt; (2)</div>
+ <div class=\\"gl-text-gray-700\\">GitLab Support Team</div>
+ </div>
+
+ </div>
+ "
+`;
+
+exports[`gfm_autocomplete/utils members config shows the avatar, name and username in the menu item for a user 1`] = `
+"
+ <div class=\\"gl-display-flex gl-align-items-center\\">
+ <img class=\\"gl-avatar gl-avatar-s24 gl-flex-shrink-0 gl-avatar-circle\\" src=\\"/uploads/-/system/user/avatar/123456/avatar.png\\" alt=\\"\\" />
+ <div class=\\"gl-font-sm gl-line-height-normal gl-ml-3\\">
+ <div>My Name &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;</div>
+ <div class=\\"gl-text-gray-700\\">@myusername</div>
+ </div>
+
+ </div>
+ "
+`;
+
+exports[`gfm_autocomplete/utils merge requests config shows the iid and title in the menu item within a project context 1`] = `"<small>123456</small> Project context merge request title &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;"`;
+
+exports[`gfm_autocomplete/utils merge requests config shows the reference and title in the menu item within a group context 1`] = `"<small>gitlab!456789</small> Group context merge request title &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;"`;
+
+exports[`gfm_autocomplete/utils milestones config shows the title in the menu item 1`] = `"13.2 &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;"`;
+
+exports[`gfm_autocomplete/utils snippets config shows the id and title in the menu item 1`] = `"<small>123456</small> Snippet title &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;"`;
diff --git a/spec/frontend/vue_shared/components/gl_mentions_spec.js b/spec/frontend/vue_shared/components/gfm_autocomplete/gfm_autocomplete_spec.js
index 32fc055a77d..d12faacca75 100644
--- a/spec/frontend/vue_shared/components/gl_mentions_spec.js
+++ b/spec/frontend/vue_shared/components/gfm_autocomplete/gfm_autocomplete_spec.js
@@ -1,15 +1,15 @@
import { shallowMount } from '@vue/test-utils';
import Tribute from 'tributejs';
-import GlMentions from '~/vue_shared/components/gl_mentions.vue';
+import GfmAutocomplete from '~/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue';
-describe('GlMentions', () => {
+describe('GfmAutocomplete', () => {
let wrapper;
- describe('Tribute', () => {
+ describe('tribute', () => {
const mentions = '/gitlab-org/gitlab-test/-/autocomplete_sources/members?type=Issue&type_id=1';
beforeEach(() => {
- wrapper = shallowMount(GlMentions, {
+ wrapper = shallowMount(GfmAutocomplete, {
propsData: {
dataSources: {
mentions,
diff --git a/spec/frontend/vue_shared/components/gfm_autocomplete/utils_spec.js b/spec/frontend/vue_shared/components/gfm_autocomplete/utils_spec.js
new file mode 100644
index 00000000000..647f8c6e000
--- /dev/null
+++ b/spec/frontend/vue_shared/components/gfm_autocomplete/utils_spec.js
@@ -0,0 +1,344 @@
+import { escape, last } from 'lodash';
+import { GfmAutocompleteType, tributeConfig } from '~/vue_shared/components/gfm_autocomplete/utils';
+
+describe('gfm_autocomplete/utils', () => {
+ describe('issues config', () => {
+ const issuesConfig = tributeConfig[GfmAutocompleteType.Issues].config;
+ const groupContextIssue = {
+ iid: 987654,
+ reference: 'gitlab#987654',
+ title: "Group context issue title <script>alert('hi')</script>",
+ };
+ const projectContextIssue = {
+ id: null,
+ iid: 123456,
+ time_estimate: 0,
+ title: "Project context issue title <script>alert('hi')</script>",
+ };
+
+ it('uses # as the trigger', () => {
+ expect(issuesConfig.trigger).toBe('#');
+ });
+
+ it('searches using both the iid and title', () => {
+ expect(issuesConfig.lookup(projectContextIssue)).toBe(
+ `${projectContextIssue.iid}${projectContextIssue.title}`,
+ );
+ });
+
+ it('shows the reference and title in the menu item within a group context', () => {
+ expect(issuesConfig.menuItemTemplate({ original: groupContextIssue })).toMatchSnapshot();
+ });
+
+ it('shows the iid and title in the menu item within a project context', () => {
+ expect(issuesConfig.menuItemTemplate({ original: projectContextIssue })).toMatchSnapshot();
+ });
+
+ it('inserts the reference on autocomplete selection within a group context', () => {
+ expect(issuesConfig.selectTemplate({ original: groupContextIssue })).toBe(
+ groupContextIssue.reference,
+ );
+ });
+
+ it('inserts the iid on autocomplete selection within a project context', () => {
+ expect(issuesConfig.selectTemplate({ original: projectContextIssue })).toBe(
+ `#${projectContextIssue.iid}`,
+ );
+ });
+ });
+
+ describe('labels config', () => {
+ const labelsConfig = tributeConfig[GfmAutocompleteType.Labels].config;
+ const labelsFilter = tributeConfig[GfmAutocompleteType.Labels].filterValues;
+ const label = {
+ color: '#123456',
+ textColor: '#FFFFFF',
+ title: `bug <script>alert('hi')</script>`,
+ type: 'GroupLabel',
+ };
+ const singleWordLabel = {
+ color: '#456789',
+ textColor: '#DDD',
+ title: `bug`,
+ type: 'GroupLabel',
+ };
+ const numericalLabel = {
+ color: '#abcdef',
+ textColor: '#AAA',
+ title: 123456,
+ type: 'ProjectLabel',
+ };
+
+ it('uses ~ as the trigger', () => {
+ expect(labelsConfig.trigger).toBe('~');
+ });
+
+ it('searches using `title`', () => {
+ expect(labelsConfig.lookup).toBe('title');
+ });
+
+ it('shows the title in the menu item', () => {
+ expect(labelsConfig.menuItemTemplate({ original: label })).toMatchSnapshot();
+ });
+
+ it('inserts the title on autocomplete selection', () => {
+ expect(labelsConfig.selectTemplate({ original: singleWordLabel })).toBe(
+ `~${escape(singleWordLabel.title)}`,
+ );
+ });
+
+ it('inserts the title enclosed with quotes on autocomplete selection when the title is numerical', () => {
+ expect(labelsConfig.selectTemplate({ original: numericalLabel })).toBe(
+ `~"${escape(numericalLabel.title)}"`,
+ );
+ });
+
+ it('inserts the title enclosed with quotes on autocomplete selection when the title contains multiple words', () => {
+ expect(labelsConfig.selectTemplate({ original: label })).toBe(`~"${escape(label.title)}"`);
+ });
+
+ describe('filter', () => {
+ const collection = [label, singleWordLabel, { ...numericalLabel, set: true }];
+
+ describe('/label quick action', () => {
+ describe('when the line starts with `/label`', () => {
+ it('shows labels that are not currently selected', () => {
+ const fullText = '/label ~';
+ const selectionStart = 8;
+
+ expect(labelsFilter({ collection, fullText, selectionStart })).toEqual([
+ collection[0],
+ collection[1],
+ ]);
+ });
+ });
+
+ describe('when the line does not start with `/label`', () => {
+ it('shows all labels', () => {
+ const fullText = '~';
+ const selectionStart = 1;
+
+ expect(labelsFilter({ collection, fullText, selectionStart })).toEqual(collection);
+ });
+ });
+ });
+
+ describe('/unlabel quick action', () => {
+ describe('when the line starts with `/unlabel`', () => {
+ it('shows labels that are currently selected', () => {
+ const fullText = '/unlabel ~';
+ const selectionStart = 10;
+
+ expect(labelsFilter({ collection, fullText, selectionStart })).toEqual([collection[2]]);
+ });
+ });
+
+ describe('when the line does not start with `/unlabel`', () => {
+ it('shows all labels', () => {
+ const fullText = '~';
+ const selectionStart = 1;
+
+ expect(labelsFilter({ collection, fullText, selectionStart })).toEqual(collection);
+ });
+ });
+ });
+ });
+ });
+
+ describe('members config', () => {
+ const membersConfig = tributeConfig[GfmAutocompleteType.Members].config;
+ const membersFilter = tributeConfig[GfmAutocompleteType.Members].filterValues;
+ const userMember = {
+ type: 'User',
+ username: 'myusername',
+ name: "My Name <script>alert('hi')</script>",
+ avatar_url: '/uploads/-/system/user/avatar/123456/avatar.png',
+ availability: null,
+ };
+ const groupMember = {
+ type: 'Group',
+ username: 'gitlab-com/support/1-1s',
+ name: "GitLab.com / GitLab Support Team / 1-1s <script>alert('hi')</script>",
+ avatar_url: null,
+ count: 2,
+ mentionsDisabled: null,
+ };
+
+ it('uses @ as the trigger', () => {
+ expect(membersConfig.trigger).toBe('@');
+ });
+
+ it('inserts the username on autocomplete selection', () => {
+ expect(membersConfig.fillAttr).toBe('username');
+ });
+
+ it('searches using both the name and username for a user', () => {
+ expect(membersConfig.lookup(userMember)).toBe(`${userMember.name}${userMember.username}`);
+ });
+
+ it('searches using only its own name and not its ancestors for a group', () => {
+ expect(membersConfig.lookup(groupMember)).toBe(last(groupMember.name.split(' / ')));
+ });
+
+ it('shows the avatar, name and username in the menu item for a user', () => {
+ expect(membersConfig.menuItemTemplate({ original: userMember })).toMatchSnapshot();
+ });
+
+ it('shows an avatar character, name, parent name, and count in the menu item for a group', () => {
+ expect(membersConfig.menuItemTemplate({ original: groupMember })).toMatchSnapshot();
+ });
+
+ describe('filter', () => {
+ const assignees = [userMember.username];
+ const collection = [userMember, groupMember];
+
+ describe('/assign quick action', () => {
+ describe('when the line starts with `/assign`', () => {
+ it('shows members that are not currently selected', () => {
+ const fullText = '/assign @';
+ const selectionStart = 9;
+
+ expect(membersFilter({ assignees, collection, fullText, selectionStart })).toEqual([
+ collection[1],
+ ]);
+ });
+ });
+
+ describe('when the line does not start with `/assign`', () => {
+ it('shows all labels', () => {
+ const fullText = '@';
+ const selectionStart = 1;
+
+ expect(membersFilter({ assignees, collection, fullText, selectionStart })).toEqual(
+ collection,
+ );
+ });
+ });
+ });
+
+ describe('/unassign quick action', () => {
+ describe('when the line starts with `/unassign`', () => {
+ it('shows members that are currently selected', () => {
+ const fullText = '/unassign @';
+ const selectionStart = 11;
+
+ expect(membersFilter({ assignees, collection, fullText, selectionStart })).toEqual([
+ collection[0],
+ ]);
+ });
+ });
+
+ describe('when the line does not start with `/unassign`', () => {
+ it('shows all members', () => {
+ const fullText = '@';
+ const selectionStart = 1;
+
+ expect(membersFilter({ assignees, collection, fullText, selectionStart })).toEqual(
+ collection,
+ );
+ });
+ });
+ });
+ });
+ });
+
+ describe('merge requests config', () => {
+ const mergeRequestsConfig = tributeConfig[GfmAutocompleteType.MergeRequests].config;
+ const groupContextMergeRequest = {
+ iid: 456789,
+ reference: 'gitlab!456789',
+ title: "Group context merge request title <script>alert('hi')</script>",
+ };
+ const projectContextMergeRequest = {
+ id: null,
+ iid: 123456,
+ time_estimate: 0,
+ title: "Project context merge request title <script>alert('hi')</script>",
+ };
+
+ it('uses ! as the trigger', () => {
+ expect(mergeRequestsConfig.trigger).toBe('!');
+ });
+
+ it('searches using both the iid and title', () => {
+ expect(mergeRequestsConfig.lookup(projectContextMergeRequest)).toBe(
+ `${projectContextMergeRequest.iid}${projectContextMergeRequest.title}`,
+ );
+ });
+
+ it('shows the reference and title in the menu item within a group context', () => {
+ expect(
+ mergeRequestsConfig.menuItemTemplate({ original: groupContextMergeRequest }),
+ ).toMatchSnapshot();
+ });
+
+ it('shows the iid and title in the menu item within a project context', () => {
+ expect(
+ mergeRequestsConfig.menuItemTemplate({ original: projectContextMergeRequest }),
+ ).toMatchSnapshot();
+ });
+
+ it('inserts the reference on autocomplete selection within a group context', () => {
+ expect(mergeRequestsConfig.selectTemplate({ original: groupContextMergeRequest })).toBe(
+ groupContextMergeRequest.reference,
+ );
+ });
+
+ it('inserts the iid on autocomplete selection within a project context', () => {
+ expect(mergeRequestsConfig.selectTemplate({ original: projectContextMergeRequest })).toBe(
+ `!${projectContextMergeRequest.iid}`,
+ );
+ });
+ });
+
+ describe('milestones config', () => {
+ const milestonesConfig = tributeConfig[GfmAutocompleteType.Milestones].config;
+ const milestone = {
+ id: null,
+ iid: 49,
+ title: "13.2 <script>alert('hi')</script>",
+ };
+
+ it('uses % as the trigger', () => {
+ expect(milestonesConfig.trigger).toBe('%');
+ });
+
+ it('searches using the title', () => {
+ expect(milestonesConfig.lookup).toBe('title');
+ });
+
+ it('shows the title in the menu item', () => {
+ expect(milestonesConfig.menuItemTemplate({ original: milestone })).toMatchSnapshot();
+ });
+
+ it('inserts the title on autocomplete selection', () => {
+ expect(milestonesConfig.selectTemplate({ original: milestone })).toBe(
+ `%"${escape(milestone.title)}"`,
+ );
+ });
+ });
+
+ describe('snippets config', () => {
+ const snippetsConfig = tributeConfig[GfmAutocompleteType.Snippets].config;
+ const snippet = {
+ id: 123456,
+ title: "Snippet title <script>alert('hi')</script>",
+ };
+
+ it('uses $ as the trigger', () => {
+ expect(snippetsConfig.trigger).toBe('$');
+ });
+
+ it('inserts the id on autocomplete selection', () => {
+ expect(snippetsConfig.fillAttr).toBe('id');
+ });
+
+ it('searches using both the id and title', () => {
+ expect(snippetsConfig.lookup(snippet)).toBe(`${snippet.id}${snippet.title}`);
+ });
+
+ it('shows the id and title in the menu item', () => {
+ expect(snippetsConfig.menuItemTemplate({ original: snippet })).toMatchSnapshot();
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap b/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
index ecea151fc8a..da49778f216 100644
--- a/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
+++ b/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
@@ -47,6 +47,7 @@ exports[`Package code instruction single line to match the default snapshot 1`]
<!---->
<svg
+ aria-hidden="true"
class="gl-button-icon gl-icon s16"
data-testid="copy-to-clipboard-icon"
>
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index c05b2b206cc..357ca0afe46 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -86,7 +86,7 @@ RSpec.describe IconsHelper do
it 'does not raise in production mode' do
stub_rails_env('production')
- expect(File).not_to receive(:read)
+ expect_file_not_to_read(Rails.root.join('node_modules/@gitlab/svgs/dist/icons.json'))
expect { sprite_icon(non_existing) }.not_to raise_error
end
diff --git a/spec/initializers/secret_token_spec.rb b/spec/initializers/secret_token_spec.rb
index 362371e0962..51a14aca4ad 100644
--- a/spec/initializers/secret_token_spec.rb
+++ b/spec/initializers/secret_token_spec.rb
@@ -11,10 +11,13 @@ RSpec.describe 'create_tokens' do
let(:rsa_key) { /\A-----BEGIN RSA PRIVATE KEY-----\n.+\n-----END RSA PRIVATE KEY-----\n\Z/m.freeze }
before do
- allow(File).to receive(:write)
- allow(File).to receive(:delete)
allow(Rails).to receive_message_chain(:application, :secrets).and_return(secrets)
allow(Rails).to receive_message_chain(:root, :join) { |string| string }
+
+ allow(File).to receive(:write).and_call_original
+ allow(File).to receive(:write).with(Rails.root.join('config/secrets.yml'))
+ allow(File).to receive(:delete).and_call_original
+ allow(File).to receive(:delete).with(Rails.root.join('.secret'))
allow(self).to receive(:warn)
allow(self).to receive(:exit)
end
@@ -105,7 +108,7 @@ RSpec.describe 'create_tokens' do
secrets.openid_connect_signing_key = 'openid_connect_signing_key'
allow(File).to receive(:exist?).with('.secret').and_return(true)
- allow(File).to receive(:read).with('.secret').and_return('file_key')
+ stub_file_read('.secret', content: 'file_key')
end
context 'when secret_key_base exists in the environment and secrets.yml' do
diff --git a/spec/javascripts/blob/balsamiq/balsamiq_viewer_browser_spec.js b/spec/javascripts/blob/balsamiq/balsamiq_viewer_browser_spec.js
deleted file mode 100644
index 4e06e5c12fc..00000000000
--- a/spec/javascripts/blob/balsamiq/balsamiq_viewer_browser_spec.js
+++ /dev/null
@@ -1,59 +0,0 @@
-// this file can't be migrated to jest because it relies on the browser to perform integration tests:
-// see: https://gitlab.com/gitlab-org/gitlab/-/issues/194207#note_301878738
-import { FIXTURES_PATH } from 'spec/test_constants';
-import BalsamiqViewer from '~/blob/balsamiq/balsamiq_viewer';
-
-const bmprPath = `${FIXTURES_PATH}/blob/balsamiq/test.bmpr`;
-
-describe('Balsamiq integration spec', () => {
- let container;
- let endpoint;
- let balsamiqViewer;
-
- preloadFixtures('static/balsamiq_viewer.html');
-
- beforeEach(() => {
- loadFixtures('static/balsamiq_viewer.html');
-
- container = document.getElementById('js-balsamiq-viewer');
- balsamiqViewer = new BalsamiqViewer(container);
- });
-
- describe('successful response', () => {
- beforeEach(done => {
- endpoint = bmprPath;
-
- balsamiqViewer
- .loadFile(endpoint)
- .then(done)
- .catch(done.fail);
- });
-
- it('does not show loading icon', () => {
- expect(document.querySelector('.loading')).toBeNull();
- });
-
- it('renders the balsamiq previews', () => {
- expect(document.querySelectorAll('.previews .preview').length).not.toEqual(0);
- });
- });
-
- describe('error getting file', () => {
- beforeEach(done => {
- endpoint = 'invalid/path/to/file.bmpr';
-
- balsamiqViewer
- .loadFile(endpoint)
- .then(done.fail, null)
- .catch(done);
- });
-
- it('does not show loading icon', () => {
- expect(document.querySelector('.loading')).toBeNull();
- });
-
- it('does not render the balsamiq previews', () => {
- expect(document.querySelectorAll('.previews .preview').length).toEqual(0);
- });
- });
-});
diff --git a/spec/lib/feature/definition_spec.rb b/spec/lib/feature/definition_spec.rb
index fa0207d829a..974310d8ea9 100644
--- a/spec/lib/feature/definition_spec.rb
+++ b/spec/lib/feature/definition_spec.rb
@@ -75,7 +75,7 @@ RSpec.describe Feature::Definition do
describe '.load_from_file' do
it 'properly loads a definition from file' do
- expect(File).to receive(:read).with(path) { yaml_content }
+ expect_file_read(path, content: yaml_content)
expect(described_class.send(:load_from_file, path).attributes)
.to eq(definition.attributes)
@@ -93,7 +93,7 @@ RSpec.describe Feature::Definition do
context 'for invalid definition' do
it 'raises exception' do
- expect(File).to receive(:read).with(path) { '{}' }
+ expect_file_read(path, content: '{}')
expect do
described_class.send(:load_from_file, path)
diff --git a/spec/lib/gitlab/email/smime/certificate_spec.rb b/spec/lib/gitlab/email/smime/certificate_spec.rb
index e4a085d971b..f7bb933e348 100644
--- a/spec/lib/gitlab/email/smime/certificate_spec.rb
+++ b/spec/lib/gitlab/email/smime/certificate_spec.rb
@@ -69,8 +69,8 @@ RSpec.describe Gitlab::Email::Smime::Certificate do
describe '.from_files' do
it 'parses correctly a certificate and key' do
- allow(File).to receive(:read).with('a_key').and_return(@cert[:key].to_s)
- allow(File).to receive(:read).with('a_cert').and_return(@cert[:cert].to_pem)
+ stub_file_read('a_key', content: @cert[:key].to_s)
+ stub_file_read('a_cert', content: @cert[:cert].to_pem)
parsed_cert = described_class.from_files('a_key', 'a_cert')
@@ -79,9 +79,9 @@ RSpec.describe Gitlab::Email::Smime::Certificate do
context 'with optional ca_certs' do
it 'parses correctly certificate, key and ca_certs' do
- allow(File).to receive(:read).with('a_key').and_return(@cert[:key].to_s)
- allow(File).to receive(:read).with('a_cert').and_return(@cert[:cert].to_pem)
- allow(File).to receive(:read).with('a_ca_cert').and_return(@intermediate_ca[:cert].to_pem)
+ stub_file_read('a_key', content: @cert[:key].to_s)
+ stub_file_read('a_cert', content: @cert[:cert].to_pem)
+ stub_file_read('a_ca_cert', content: @intermediate_ca[:cert].to_pem)
parsed_cert = described_class.from_files('a_key', 'a_cert', 'a_ca_cert')
@@ -94,8 +94,8 @@ RSpec.describe Gitlab::Email::Smime::Certificate do
it 'parses correctly a certificate and key' do
cert = generate_cert(signer_ca: @root_ca)
- allow(File).to receive(:read).with('a_key').and_return(cert[:key].to_s)
- allow(File).to receive(:read).with('a_cert').and_return(cert[:cert].to_pem)
+ stub_file_read('a_key', content: cert[:key].to_s)
+ stub_file_read('a_cert', content: cert[:cert].to_pem)
parsed_cert = described_class.from_files('a_key', 'a_cert')
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 16dd2bbee6d..7fcb11c4dfd 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -53,7 +53,7 @@ RSpec.describe Gitlab::GitalyClient do
describe '.filesystem_id_from_disk' do
it 'catches errors' do
[Errno::ENOENT, Errno::EACCES, JSON::ParserError].each do |error|
- allow(File).to receive(:read).with(described_class.storage_metadata_file_path('default')).and_raise(error)
+ stub_file_read(described_class.storage_metadata_file_path('default'), error: error)
expect(described_class.filesystem_id_from_disk('default')).to be_nil
end
diff --git a/spec/lib/gitlab/webpack/manifest_spec.rb b/spec/lib/gitlab/webpack/manifest_spec.rb
index 1427bdd7d4f..08b4774dd67 100644
--- a/spec/lib/gitlab/webpack/manifest_spec.rb
+++ b/spec/lib/gitlab/webpack/manifest_spec.rb
@@ -97,7 +97,7 @@ RSpec.describe Gitlab::Webpack::Manifest do
context "with dev server disabled" do
before do
allow(Gitlab.config.webpack.dev_server).to receive(:enabled).and_return(false)
- allow(File).to receive(:read).with(::Rails.root.join("manifest_output/my_manifest.json")).and_return(manifest)
+ stub_file_read(::Rails.root.join("manifest_output/my_manifest.json"), content: manifest)
end
describe ".asset_paths" do
@@ -105,7 +105,7 @@ RSpec.describe Gitlab::Webpack::Manifest do
it "errors if we can't find the manifest" do
allow(Gitlab.config.webpack).to receive(:manifest_filename).and_return('broken.json')
- allow(File).to receive(:read).with(::Rails.root.join("manifest_output/broken.json")).and_raise(Errno::ENOENT)
+ stub_file_read(::Rails.root.join("manifest_output/broken.json"), error: Errno::ENOENT)
expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.to raise_error(Gitlab::Webpack::Manifest::ManifestLoadError)
end
end
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index 7c2758bf27e..eaab39291b2 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -26,18 +26,17 @@ RSpec.describe Gitlab do
end
it 'returns the actual Git revision' do
- expect(File).to receive(:read)
- .with(described_class.root.join('REVISION'))
- .and_return("abc123\n")
+ expect_file_read(described_class.root.join('REVISION'), content: "abc123\n")
expect(described_class.revision).to eq('abc123')
end
it 'memoizes the revision' do
+ stub_file_read(described_class.root.join('REVISION'), content: "abc123\n")
+
expect(File).to receive(:read)
- .once
- .with(described_class.root.join('REVISION'))
- .and_return("abc123\n")
+ .once
+ .with(described_class.root.join('REVISION'))
2.times { described_class.revision }
end
diff --git a/spec/models/instance_configuration_spec.rb b/spec/models/instance_configuration_spec.rb
index 383e548c324..d3566ed04c2 100644
--- a/spec/models/instance_configuration_spec.rb
+++ b/spec/models/instance_configuration_spec.rb
@@ -10,31 +10,35 @@ RSpec.describe InstanceConfiguration do
let(:sha256) { 'SHA256:2KJDT7xf2i68mBgJ3TVsjISntg4droLbXYLfQj0VvSY' }
it 'does not return anything if file does not exist' do
- stub_pub_file(exist: false)
+ stub_pub_file(pub_file(exist: false))
expect(subject.settings[:ssh_algorithms_hashes]).to be_empty
end
it 'does not return anything if file is empty' do
- stub_pub_file
+ stub_pub_file(pub_file)
- allow(File).to receive(:read).and_return('')
+ stub_file_read(pub_file, content: '')
expect(subject.settings[:ssh_algorithms_hashes]).to be_empty
end
it 'returns the md5 and sha256 if file valid and exists' do
- stub_pub_file
+ stub_pub_file(pub_file)
result = subject.settings[:ssh_algorithms_hashes].select { |o| o[:md5] == md5 && o[:sha256] == sha256 }
expect(result.size).to eq(InstanceConfiguration::SSH_ALGORITHMS.size)
end
- def stub_pub_file(exist: true)
+ def pub_file(exist: true)
path = exist ? 'spec/fixtures/ssh_host_example_key.pub' : 'spec/fixtures/ssh_host_example_key.pub.random'
- allow(subject).to receive(:ssh_algorithm_file).and_return(Rails.root.join(path))
+ Rails.root.join(path)
+ end
+
+ def stub_pub_file(path)
+ allow(subject).to receive(:ssh_algorithm_file).and_return(path)
end
end
diff --git a/spec/models/namespace_onboarding_action_spec.rb b/spec/models/namespace_onboarding_action_spec.rb
new file mode 100644
index 00000000000..9dd82c05032
--- /dev/null
+++ b/spec/models/namespace_onboarding_action_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe NamespaceOnboardingAction do
+ it { is_expected.to belong_to :namespace }
+end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 85f9005052e..0130618d004 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -19,6 +19,7 @@ RSpec.describe Namespace do
it { is_expected.to have_one :aggregation_schedule }
it { is_expected.to have_one :namespace_settings }
it { is_expected.to have_many :custom_emoji }
+ it { is_expected.to have_many :namespace_onboarding_actions }
end
describe 'validations' do
diff --git a/spec/services/clusters/aws/fetch_credentials_service_spec.rb b/spec/services/clusters/aws/fetch_credentials_service_spec.rb
index 361a947f634..4b9458d277b 100644
--- a/spec/services/clusters/aws/fetch_credentials_service_spec.rb
+++ b/spec/services/clusters/aws/fetch_credentials_service_spec.rb
@@ -60,9 +60,7 @@ RSpec.describe Clusters::Aws::FetchCredentialsService do
subject { described_class.new(provision_role, provider: provider).execute }
before do
- allow(File).to receive(:read)
- .with(Rails.root.join('vendor', 'aws', 'iam', 'eks_cluster_read_only_policy.json'))
- .and_return(session_policy)
+ stub_file_read(Rails.root.join('vendor', 'aws', 'iam', 'eks_cluster_read_only_policy.json'), content: session_policy)
end
it { is_expected.to eq assumed_role_credentials }
diff --git a/spec/services/clusters/aws/provision_service_spec.rb b/spec/services/clusters/aws/provision_service_spec.rb
index 52612e5ac40..5efac29ec1e 100644
--- a/spec/services/clusters/aws/provision_service_spec.rb
+++ b/spec/services/clusters/aws/provision_service_spec.rb
@@ -42,9 +42,7 @@ RSpec.describe Clusters::Aws::ProvisionService do
allow(provider).to receive(:api_client)
.and_return(client)
- allow(File).to receive(:read)
- .with(Rails.root.join('vendor', 'aws', 'cloudformation', 'eks_cluster.yaml'))
- .and_return(cloudformation_template)
+ stub_file_read(Rails.root.join('vendor', 'aws', 'cloudformation', 'eks_cluster.yaml'), content: cloudformation_template)
end
it 'updates the provider status to :creating and configures the provider with credentials' do
diff --git a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb
index 728b343b801..b326fc1726d 100644
--- a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb
@@ -146,7 +146,7 @@ RSpec.describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memor
it 'extends dashboard template path to absolute url' do
allow(::Files::CreateService).to receive(:new).and_return(double(execute: { status: :success }))
- expect(File).to receive(:read).with(Rails.root.join('config/prometheus/common_metrics.yml')).and_return('')
+ expect_file_read(Rails.root.join('config/prometheus/common_metrics.yml'), content: '')
service_call
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 788c953b6f4..7051d975980 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -134,6 +134,7 @@ RSpec.configure do |config|
config.include NextFoundInstanceOf
config.include NextInstanceOf
config.include TestEnv
+ config.include FileReadHelpers
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::IntegrationHelpers, type: :feature
config.include LoginHelpers, type: :feature
diff --git a/spec/support/helpers/file_read_helpers.rb b/spec/support/helpers/file_read_helpers.rb
new file mode 100644
index 00000000000..c30a9e6466f
--- /dev/null
+++ b/spec/support/helpers/file_read_helpers.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module FileReadHelpers
+ def stub_file_read(file, content: nil, error: nil)
+ allow_original_file_read
+
+ expectation = allow(File).to receive(:read).with(file)
+
+ if error
+ expectation.and_raise(error)
+ elsif content
+ expectation.and_return(content)
+ else
+ expectation
+ end
+ end
+
+ def expect_file_read(file, content: nil, error: nil)
+ allow_original_file_read
+
+ expectation = expect(File).to receive(:read).with(file)
+
+ if error
+ expectation.and_raise(error)
+ elsif content
+ expectation.and_return(content)
+ else
+ expectation
+ end
+ end
+
+ def expect_file_not_to_read(file)
+ allow_original_file_read
+
+ expect(File).not_to receive(:read).with(file)
+ end
+
+ private
+
+ def allow_original_file_read
+ # Don't set this mock twice, otherwise subsequent calls will clobber
+ # previous mocks
+ return if @allow_original_file_read
+
+ @allow_original_file_read = true
+ allow(File).to receive(:read).and_call_original
+ end
+end
diff --git a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
index 1501a2a0f52..b6c33eac7b4 100644
--- a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
+++ b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
@@ -46,7 +46,7 @@ RSpec.shared_examples 'refreshes cache when dashboard_version is changed' do
allow(service).to receive(:dashboard_version).and_return('1', '2')
end
- expect(File).to receive(:read).twice.and_call_original
+ expect_file_read(Rails.root.join(described_class::DASHBOARD_PATH)).twice.and_call_original
service = described_class.new(*service_params)
diff --git a/spec/tasks/gitlab/db_rake_spec.rb b/spec/tasks/gitlab/db_rake_spec.rb
index 046e066a45f..313088599e9 100644
--- a/spec/tasks/gitlab/db_rake_spec.rb
+++ b/spec/tasks/gitlab/db_rake_spec.rb
@@ -129,7 +129,7 @@ RSpec.describe 'gitlab:db namespace rake task' do
let(:output) { StringIO.new }
before do
- allow(File).to receive(:read).with(structure_file).and_return(input)
+ stub_file_read(structure_file, content: input)
allow(File).to receive(:open).with(structure_file, any_args).and_yield(output)
end
diff --git a/spec/tooling/lib/tooling/test_map_generator_spec.rb b/spec/tooling/lib/tooling/test_map_generator_spec.rb
index 7f3b2807162..4c720ba62a2 100644
--- a/spec/tooling/lib/tooling/test_map_generator_spec.rb
+++ b/spec/tooling/lib/tooling/test_map_generator_spec.rb
@@ -1,8 +1,11 @@
# frozen_string_literal: true
require_relative '../../../../tooling/lib/tooling/test_map_generator'
+require_relative '../../../support/helpers/file_read_helpers'
RSpec.describe Tooling::TestMapGenerator do
+ include FileReadHelpers
+
subject { described_class.new }
describe '#parse' do
@@ -39,8 +42,8 @@ RSpec.describe Tooling::TestMapGenerator do
let(:pathname) { instance_double(Pathname) }
before do
- allow(File).to receive(:read).with('yaml1.yml').and_return(yaml1)
- allow(File).to receive(:read).with('yaml2.yml').and_return(yaml2)
+ stub_file_read('yaml1.yml', content: yaml1)
+ stub_file_read('yaml2.yml', content: yaml2)
end
context 'with single yaml' do
diff --git a/yarn.lock b/yarn.lock
index a2e89886d6d..cd425673458 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -866,10 +866,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.175.0.tgz#734f341784af1cd1d62d160a17bcdfb61ff7b04d"
integrity sha512-gXpc87TGSXIzfAr4QER1Qw1v3P47pBO6BXkma52blgwXVmcFNe3nhQzqsqt66wKNzrIrk3lAcB4GUyPHbPVXpg==
-"@gitlab/ui@23.9.0":
- version "23.9.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-23.9.0.tgz#e21966130b41e624dbe4505911a79afb731c2d6b"
- integrity sha512-IfaiIcRw6iKE9Fxx36LQ1Afa/fcdmvRQCJO9igc+wWD3MFZGU/ggsQw3SExkkYI6XYmDUr56CT/o+HYlCDjgZQ==
+"@gitlab/ui@23.12.0":
+ version "23.12.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-23.12.0.tgz#a71240b659bf37f5ea118fa0948d22d8c304d811"
+ integrity sha512-ibnvGx7PmMjVFcHJeGXInr5PZBHhzexyH1vrpjktlHhmQfi5gbcOwHOcXrBpLqmAW5o2F8jFx2aXBZeuGMpEkg==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"