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:
-rw-r--r--.rubocop.yml1
-rw-r--r--.rubocop_manual_todo.yml39
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/diffs/components/settings_dropdown.vue4
-rw-r--r--app/assets/javascripts/diffs/index.js4
-rw-r--r--app/assets/javascripts/diffs/store/actions.js8
-rw-r--r--app/assets/javascripts/members/components/action_buttons/remove_member_button.vue35
-rw-r--r--app/assets/javascripts/members/components/modals/remove_member_modal.vue (renamed from app/assets/javascripts/vue_shared/components/remove_member_modal.vue)72
-rw-r--r--app/assets/javascripts/members/components/table/members_table.vue3
-rw-r--r--app/assets/javascripts/members/store/actions.js8
-rw-r--r--app/assets/javascripts/members/store/mutation_types.js3
-rw-r--r--app/assets/javascripts/members/store/mutations.js7
-rw-r--r--app/assets/javascripts/members/store/state.js2
-rw-r--r--app/assets/javascripts/pages/admin/groups/show/index.js22
-rw-r--r--app/assets/javascripts/pages/admin/projects/index.js18
-rw-r--r--app/assets/javascripts/pages/groups/group_members/index.js17
-rw-r--r--app/assets/javascripts/pages/projects/project_members/index.js17
-rw-r--r--app/assets/javascripts/runner/components/runner_update_form.vue8
-rw-r--r--app/assets/javascripts/security_configuration/components/constants.js5
-rw-r--r--app/assets/javascripts/security_configuration/components/feature_card.vue7
-rw-r--r--app/controllers/projects/merge_requests/creations_controller.rb4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/graphql/resolvers/alert_management/alert_resolver.rb6
-rw-r--r--app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb4
-rw-r--r--app/graphql/resolvers/blobs_resolver.rb4
-rw-r--r--app/graphql/resolvers/ci/config_resolver.rb8
-rw-r--r--app/graphql/resolvers/ci/runner_setup_resolver.rb4
-rw-r--r--app/graphql/resolvers/ci/runners_resolver.rb4
-rw-r--r--app/graphql/resolvers/ci/template_resolver.rb2
-rw-r--r--app/graphql/resolvers/ci/test_suite_resolver.rb2
-rw-r--r--app/graphql/resolvers/concerns/group_issuable_resolver.rb2
-rw-r--r--app/graphql/resolvers/concerns/issue_resolver_arguments.rb18
-rw-r--r--app/graphql/resolvers/concerns/resolves_pipelines.rb4
-rw-r--r--app/graphql/resolvers/container_repositories_resolver.rb2
-rw-r--r--app/graphql/resolvers/design_management/design_resolver.rb2
-rw-r--r--app/graphql/resolvers/design_management/designs_resolver.rb2
-rw-r--r--app/graphql/resolvers/design_management/version/design_at_version_resolver.rb2
-rw-r--r--app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb2
-rw-r--r--app/graphql/resolvers/design_management/version_in_collection_resolver.rb2
-rw-r--r--app/graphql/resolvers/design_management/versions_resolver.rb2
-rw-r--r--app/graphql/resolvers/echo_resolver.rb4
-rw-r--r--app/graphql/resolvers/environments_resolver.rb6
-rw-r--r--app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb4
-rw-r--r--app/graphql/resolvers/full_path_resolver.rb2
-rw-r--r--app/graphql/resolvers/group_labels_resolver.rb4
-rw-r--r--app/graphql/resolvers/group_milestones_resolver.rb4
-rw-r--r--app/graphql/resolvers/labels_resolver.rb4
-rw-r--r--app/graphql/resolvers/members_resolver.rb2
-rw-r--r--app/graphql/resolvers/merge_request_resolver.rb2
-rw-r--r--app/graphql/resolvers/merge_requests_resolver.rb20
-rw-r--r--app/graphql/resolvers/metrics/dashboard_resolver.rb2
-rw-r--r--app/graphql/resolvers/milestones_resolver.rb6
-rw-r--r--app/graphql/resolvers/namespace_projects_resolver.rb6
-rw-r--r--app/graphql/resolvers/packages_base_resolver.rb4
-rw-r--r--app/graphql/resolvers/project_milestones_resolver.rb2
-rw-r--r--app/graphql/resolvers/project_pipeline_resolver.rb4
-rw-r--r--app/graphql/resolvers/projects/jira_projects_resolver.rb2
-rw-r--r--app/graphql/resolvers/projects/services_resolver.rb2
-rw-r--r--app/graphql/resolvers/projects_resolver.rb12
-rw-r--r--app/graphql/resolvers/release_resolver.rb2
-rw-r--r--app/graphql/resolvers/repository_branch_names_resolver.rb8
-rw-r--r--app/graphql/resolvers/snippets/blobs_resolver.rb2
-rw-r--r--app/graphql/resolvers/snippets_resolver.rb2
-rw-r--r--app/graphql/resolvers/terraform/states_resolver.rb2
-rw-r--r--app/graphql/resolvers/todo_resolver.rb6
-rw-r--r--app/graphql/resolvers/tree_resolver.rb6
-rw-r--r--app/graphql/resolvers/user_discussions_count_resolver.rb2
-rw-r--r--app/graphql/resolvers/user_merge_requests_resolver_base.rb2
-rw-r--r--app/graphql/resolvers/user_notes_count_resolver.rb2
-rw-r--r--app/graphql/resolvers/user_resolver.rb2
-rw-r--r--app/graphql/resolvers/user_starred_projects_resolver.rb2
-rw-r--r--app/graphql/resolvers/users/group_count_resolver.rb2
-rw-r--r--app/graphql/resolvers/users_resolver.rb8
-rw-r--r--app/helpers/application_helper.rb6
-rw-r--r--app/services/packages/debian/generate_distribution_key_service.rb61
-rw-r--r--app/services/packages/debian/sign_distribution_service.rb38
-rw-r--r--app/views/admin/dashboard/index.html.haml1
-rw-r--r--app/views/admin/groups/show.html.haml1
-rw-r--r--app/views/admin/projects/show.html.haml1
-rw-r--r--app/views/groups/group_members/index.html.haml1
-rw-r--r--app/views/groups/settings/_permissions.html.haml12
-rw-r--r--app/views/layouts/_head.html.haml7
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/projects/project_members/index.html.haml1
-rw-r--r--app/views/projects/settings/_general.html.haml2
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--app/views/shared/issuable/form/_metadata_issuable_reviewer.html.haml3
-rw-r--r--config/feature_flags/development/mr_collapsed_approval_rules.yml8
-rw-r--r--db/post_migrate/20190517153211_migrate_k8s_service_integration.rb2
-rw-r--r--doc/administration/geo/replication/troubleshooting.md26
-rw-r--r--doc/development/fe_guide/haml.md74
-rw-r--r--doc/development/fe_guide/index.md4
-rw-r--r--doc/development/sidekiq_style_guide.md18
-rw-r--r--doc/raketasks/backup_restore.md72
-rw-r--r--doc/user/infrastructure/iac/index.md139
-rw-r--r--doc/user/infrastructure/index.md137
-rw-r--r--doc/user/infrastructure/mr_integration.md2
-rw-r--r--lib/gitlab/ci/yaml_processor/dag.rb2
-rw-r--r--lib/gitlab/form_builders/gitlab_ui_form_builder.rb55
-rw-r--r--lib/gitlab/import_export/json/legacy_reader.rb2
-rw-r--r--lib/gitlab/import_export/json/ndjson_reader.rb4
-rw-r--r--lib/gitlab/import_export/lfs_restorer.rb2
-rw-r--r--lib/gitlab/json_cache.rb4
-rw-r--r--locale/gitlab.pot27
-rw-r--r--qa/qa/page/group/members.rb2
-rw-r--r--rubocop/cop/gitlab/json.rb2
-rw-r--r--spec/factories/packages/debian/distribution_key.rb4
-rw-r--r--spec/features/projects/import_export/export_file_spec.rb3
-rw-r--r--spec/fixtures/private_key.asc17
-rw-r--r--spec/fixtures/public_key.asc15
-rw-r--r--spec/frontend/diffs/components/settings_dropdown_spec.js8
-rw-r--r--spec/frontend/diffs/store/actions_spec.js4
-rw-r--r--spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js2
-rw-r--r--spec/frontend/members/components/action_buttons/remove_member_button_spec.js27
-rw-r--r--spec/frontend/members/components/modals/remove_member_modal_spec.js (renamed from spec/frontend/vue_shared/components/remove_member_modal_spec.js)87
-rw-r--r--spec/frontend/members/components/table/members_table_spec.js1
-rw-r--r--spec/frontend/members/mock_data.js9
-rw-r--r--spec/frontend/members/store/actions_spec.js32
-rw-r--r--spec/frontend/members/store/mutations_spec.js30
-rw-r--r--spec/frontend/security_configuration/components/feature_card_spec.js34
-rw-r--r--spec/graphql/resolvers/base_resolver_spec.rb38
-rw-r--r--spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb2
-rw-r--r--spec/graphql/resolvers/echo_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/namespace_projects_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/project_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/terraform/states_resolver_spec.rb3
-rw-r--r--spec/graphql/resolvers/user_discussions_count_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/user_notes_count_resolver_spec.rb2
-rw-r--r--spec/helpers/application_helper_spec.rb19
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb2
-rw-r--r--spec/lib/gitlab/form_builders/gitlab_ui_form_builder_spec.rb88
-rw-r--r--spec/lib/gitlab/import_export/group/legacy_tree_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/group/tree_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/import_test_coverage_spec.rb2
-rw-r--r--spec/lib/gitlab/json_cache_spec.rb6
-rw-r--r--spec/requests/git_http_spec.rb4
-rw-r--r--spec/rubocop/cop/gitlab/json_spec.rb15
-rw-r--r--spec/services/packages/debian/generate_distribution_key_service_spec.rb32
-rw-r--r--spec/services/packages/debian/sign_distribution_service_spec.rb61
-rw-r--r--spec/support/import_export/common_util.rb6
-rw-r--r--spec/views/admin/dashboard/index.html.haml_spec.rb8
143 files changed, 1156 insertions, 644 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index d34b133edee..19f0b0b294f 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -254,7 +254,6 @@ Gitlab/HTTParty:
Gitlab/Json:
Enabled: true
Exclude:
- - 'db/**/*'
- 'qa/**/*'
- 'scripts/**/*'
- 'tooling/rspec_flaky/**/*'
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index d52cf65a704..7fceb2eecaa 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -90,45 +90,6 @@ Graphql/OldTypes:
- 'app/graphql/mutations/snippets/create.rb'
- 'app/graphql/mutations/snippets/update.rb'
- 'app/graphql/mutations/user_callouts/create.rb'
- - 'app/graphql/resolvers/alert_management/alert_resolver.rb'
- - 'app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb'
- - 'app/graphql/resolvers/blobs_resolver.rb'
- - 'app/graphql/resolvers/ci/config_resolver.rb'
- - 'app/graphql/resolvers/ci/runners_resolver.rb'
- - 'app/graphql/resolvers/ci/template_resolver.rb'
- - 'app/graphql/resolvers/concerns/group_issuable_resolver.rb'
- - 'app/graphql/resolvers/concerns/issue_resolver_arguments.rb'
- - 'app/graphql/resolvers/concerns/resolves_pipelines.rb'
- - 'app/graphql/resolvers/container_repositories_resolver.rb'
- - 'app/graphql/resolvers/design_management/design_resolver.rb'
- - 'app/graphql/resolvers/design_management/version/design_at_version_resolver.rb'
- - 'app/graphql/resolvers/design_management/version_in_collection_resolver.rb'
- - 'app/graphql/resolvers/design_management/versions_resolver.rb'
- - 'app/graphql/resolvers/environments_resolver.rb'
- - 'app/graphql/resolvers/full_path_resolver.rb'
- - 'app/graphql/resolvers/group_labels_resolver.rb'
- - 'app/graphql/resolvers/group_milestones_resolver.rb'
- - 'app/graphql/resolvers/labels_resolver.rb'
- - 'app/graphql/resolvers/members_resolver.rb'
- - 'app/graphql/resolvers/merge_request_resolver.rb'
- - 'app/graphql/resolvers/merge_requests_resolver.rb'
- - 'app/graphql/resolvers/metrics/dashboard_resolver.rb'
- - 'app/graphql/resolvers/milestones_resolver.rb'
- - 'app/graphql/resolvers/namespace_projects_resolver.rb'
- - 'app/graphql/resolvers/packages_base_resolver.rb'
- - 'app/graphql/resolvers/project_milestones_resolver.rb'
- - 'app/graphql/resolvers/project_pipeline_resolver.rb'
- - 'app/graphql/resolvers/projects/jira_projects_resolver.rb'
- - 'app/graphql/resolvers/projects/services_resolver.rb'
- - 'app/graphql/resolvers/projects_resolver.rb'
- - 'app/graphql/resolvers/release_resolver.rb'
- - 'app/graphql/resolvers/repository_branch_names_resolver.rb'
- - 'app/graphql/resolvers/snippets_resolver.rb'
- - 'app/graphql/resolvers/terraform/states_resolver.rb'
- - 'app/graphql/resolvers/tree_resolver.rb'
- - 'app/graphql/resolvers/user_resolver.rb'
- - 'app/graphql/resolvers/user_starred_projects_resolver.rb'
- - 'app/graphql/resolvers/users_resolver.rb'
- 'app/graphql/types/access_level_type.rb'
- 'app/graphql/types/admin/analytics/usage_trends/measurement_type.rb'
- 'app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index eb5cb835516..fa3999e2a82 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-996a4adda765e8ced18c72eca0ebd27848afa3c9
+818f3d85a2c8e6596376f1d2276aa22660203a6c
diff --git a/app/assets/javascripts/diffs/components/settings_dropdown.vue b/app/assets/javascripts/diffs/components/settings_dropdown.vue
index 178f93b651e..2d9ac76b3e4 100644
--- a/app/assets/javascripts/diffs/components/settings_dropdown.vue
+++ b/app/assets/javascripts/diffs/components/settings_dropdown.vue
@@ -60,14 +60,14 @@ export default {
<gl-button
:class="{ selected: !renderTreeList }"
class="gl-w-half js-list-view"
- @click="setRenderTreeList(false)"
+ @click="setRenderTreeList({ renderTreeList: false })"
>
{{ __('List view') }}
</gl-button>
<gl-button
:class="{ selected: renderTreeList }"
class="gl-w-half js-tree-view"
- @click="setRenderTreeList(true)"
+ @click="setRenderTreeList({ renderTreeList: true })"
>
{{ __('Tree view') }}
</gl-button>
diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js
index ea83523008c..9d974c132b5 100644
--- a/app/assets/javascripts/diffs/index.js
+++ b/app/assets/javascripts/diffs/index.js
@@ -93,7 +93,7 @@ export default function initDiffsApp(store) {
const treeListStored = localStorage.getItem(TREE_LIST_STORAGE_KEY);
const renderTreeList = treeListStored !== null ? parseBoolean(treeListStored) : true;
- this.setRenderTreeList(renderTreeList);
+ this.setRenderTreeList({ renderTreeList, trackClick: false });
// NOTE: A "true" or "checked" value for `showWhitespace` is '0' not '1'.
// Check for cookie and save that setting for future use.
@@ -104,6 +104,7 @@ export default function initDiffsApp(store) {
this.setShowWhitespace({
url: this.endpointUpdateUser,
showWhitespace: hideWhitespace !== '1',
+ trackClick: false,
});
Cookies.remove(DIFF_WHITESPACE_COOKIE_NAME);
} else {
@@ -111,6 +112,7 @@ export default function initDiffsApp(store) {
this.setShowWhitespace({
showWhitespace: this.showWhitespaceDefault,
updateDatabase: false,
+ trackClick: false,
});
}
},
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 66510edf3db..f8cc39fc238 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -560,12 +560,12 @@ export const closeDiffFileCommentForm = ({ commit }, fileHash) => {
commit(types.CLOSE_DIFF_FILE_COMMENT_FORM, fileHash);
};
-export const setRenderTreeList = ({ commit }, renderTreeList) => {
+export const setRenderTreeList = ({ commit }, { renderTreeList, trackClick = true }) => {
commit(types.SET_RENDER_TREE_LIST, renderTreeList);
localStorage.setItem(TREE_LIST_STORAGE_KEY, renderTreeList);
- if (window.gon?.features?.diffSettingsUsageData) {
+ if (window.gon?.features?.diffSettingsUsageData && trackClick) {
api.trackRedisHllUserEvent(TRACKING_CLICK_FILE_BROWSER_SETTING);
if (renderTreeList) {
@@ -578,7 +578,7 @@ export const setRenderTreeList = ({ commit }, renderTreeList) => {
export const setShowWhitespace = async (
{ state, commit },
- { url, showWhitespace, updateDatabase = true },
+ { url, showWhitespace, updateDatabase = true, trackClick = true },
) => {
if (updateDatabase && Boolean(window.gon?.current_user_id)) {
await axios.put(url || state.endpointUpdateUser, { show_whitespace_in_diffs: showWhitespace });
@@ -587,7 +587,7 @@ export const setShowWhitespace = async (
commit(types.SET_SHOW_WHITESPACE, showWhitespace);
notesEventHub.$emit('refetchDiffData');
- if (window.gon?.features?.diffSettingsUsageData) {
+ if (window.gon?.features?.diffSettingsUsageData && trackClick) {
api.trackRedisHllUserEvent(TRACKING_CLICK_WHITESPACE_SETTING);
if (showWhitespace) {
diff --git a/app/assets/javascripts/members/components/action_buttons/remove_member_button.vue b/app/assets/javascripts/members/components/action_buttons/remove_member_button.vue
index a477aedd233..665e8ee69f7 100644
--- a/app/assets/javascripts/members/components/action_buttons/remove_member_button.vue
+++ b/app/assets/javascripts/members/components/action_buttons/remove_member_button.vue
@@ -1,6 +1,6 @@
<script>
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
-import { mapState } from 'vuex';
+import { mapActions, mapState } from 'vuex';
export default {
name: 'RemoveMemberButton',
@@ -45,7 +45,7 @@ export default {
oncallSchedules: {
type: Object,
required: false,
- default: () => {},
+ default: () => ({}),
},
},
computed: {
@@ -54,30 +54,35 @@ export default {
return state[this.namespace].memberPath;
},
}),
- computedMemberPath() {
- return this.memberPath.replace(':id', this.memberId);
- },
- stringifiedSchedules() {
- return JSON.stringify(this.oncallSchedules);
+ modalData() {
+ return {
+ isAccessRequest: this.isAccessRequest,
+ isInvite: this.isInvite,
+ memberPath: this.memberPath.replace(':id', this.memberId),
+ memberType: this.memberType,
+ message: this.message,
+ oncallSchedules: this.oncallSchedules,
+ };
},
},
+ methods: {
+ ...mapActions({
+ showRemoveMemberModal(dispatch, payload) {
+ return dispatch(`${this.namespace}/showRemoveMemberModal`, payload);
+ },
+ }),
+ },
};
</script>
<template>
<gl-button
- v-gl-tooltip.hover
- class="js-remove-member-button"
+ v-gl-tooltip
variant="danger"
:title="title"
:aria-label="title"
:icon="icon"
- :data-member-path="computedMemberPath"
- :data-member-type="memberType"
- :data-is-access-request="isAccessRequest"
- :data-is-invite="isInvite"
- :data-message="message"
- :data-oncall-schedules="stringifiedSchedules"
data-qa-selector="delete_member_button"
+ @click="showRemoveMemberModal(modalData)"
/>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/remove_member_modal.vue b/app/assets/javascripts/members/components/modals/remove_member_modal.vue
index 07272a5b8d6..00b6ebf9a73 100644
--- a/app/assets/javascripts/vue_shared/components/remove_member_modal.vue
+++ b/app/assets/javascripts/members/components/modals/remove_member_modal.vue
@@ -1,7 +1,6 @@
<script>
import { GlFormCheckbox, GlModal } from '@gitlab/ui';
-import * as Sentry from '@sentry/browser';
-import { parseBoolean } from '~/lib/utils/common_utils';
+import { mapActions, mapState } from 'vuex';
import csrf from '~/lib/utils/csrf';
import { s__, __ } from '~/locale';
import OncallSchedulesList from '~/vue_shared/components/oncall_schedules_list.vue';
@@ -16,20 +15,33 @@ export default {
GlModal,
OncallSchedulesList,
},
- data() {
- return {
- modalData: {},
- };
- },
+ inject: ['namespace'],
computed: {
- isAccessRequest() {
- return parseBoolean(this.modalData.isAccessRequest);
- },
- isInvite() {
- return parseBoolean(this.modalData.isInvite);
- },
+ ...mapState({
+ isAccessRequest(state) {
+ return state[this.namespace].removeMemberModalData.isAccessRequest;
+ },
+ isInvite(state) {
+ return state[this.namespace].removeMemberModalData.isInvite;
+ },
+ memberPath(state) {
+ return state[this.namespace].removeMemberModalData.memberPath;
+ },
+ memberType(state) {
+ return state[this.namespace].removeMemberModalData.memberType;
+ },
+ message(state) {
+ return state[this.namespace].removeMemberModalData.message;
+ },
+ oncallSchedules(state) {
+ return state[this.namespace].removeMemberModalData.oncallSchedules ?? {};
+ },
+ removeMemberModalVisible(state) {
+ return state[this.namespace].removeMemberModalVisible;
+ },
+ }),
isGroupMember() {
- return this.modalData.memberType === 'GroupMember';
+ return this.memberType === 'GroupMember';
},
actionText() {
if (this.isAccessRequest) {
@@ -54,29 +66,13 @@ export default {
isPartOfOncallSchedules() {
return !this.isAccessRequest && this.oncallSchedules.schedules?.length;
},
- oncallSchedules() {
- try {
- return JSON.parse(this.modalData.oncallSchedules);
- } catch (e) {
- Sentry.captureException(e);
- }
- return {};
- },
- },
- mounted() {
- document.addEventListener('click', this.handleClick);
- },
- beforeDestroy() {
- document.removeEventListener('click', this.handleClick);
},
methods: {
- handleClick(event) {
- const removeButton = event.target.closest('.js-remove-member-button');
- if (removeButton) {
- this.modalData = removeButton.dataset;
- this.$refs.modal.show();
- }
- },
+ ...mapActions({
+ hideRemoveMemberModal(dispatch) {
+ return dispatch(`${this.namespace}/hideRemoveMemberModal`);
+ },
+ }),
submitForm() {
this.$refs.form.submit();
},
@@ -91,11 +87,13 @@ export default {
:action-cancel="$options.actionCancel"
:action-primary="actionPrimary"
:title="actionText"
+ :visible="removeMemberModalVisible"
data-qa-selector="remove_member_modal_content"
@primary="submitForm"
+ @hide="hideRemoveMemberModal"
>
- <form ref="form" :action="modalData.memberPath" method="post">
- <p data-testid="modal-message">{{ modalData.message }}</p>
+ <form ref="form" :action="memberPath" method="post">
+ <p>{{ message }}</p>
<oncall-schedules-list
v-if="isPartOfOncallSchedules"
diff --git a/app/assets/javascripts/members/components/table/members_table.vue b/app/assets/javascripts/members/components/table/members_table.vue
index b9c80edbc49..debc3fc31f6 100644
--- a/app/assets/javascripts/members/components/table/members_table.vue
+++ b/app/assets/javascripts/members/components/table/members_table.vue
@@ -7,6 +7,7 @@ import { mergeUrlParams } from '~/lib/utils/url_utility';
import initUserPopovers from '~/user_popovers';
import { FIELDS, ACTIVE_TAB_QUERY_PARAM_NAME } from '../../constants';
import RemoveGroupLinkModal from '../modals/remove_group_link_modal.vue';
+import RemoveMemberModal from '../modals/remove_member_modal.vue';
import CreatedAt from './created_at.vue';
import ExpirationDatepicker from './expiration_datepicker.vue';
import ExpiresAt from './expires_at.vue';
@@ -29,6 +30,7 @@ export default {
MemberActionButtons,
RoleDropdown,
RemoveGroupLinkModal,
+ RemoveMemberModal,
ExpirationDatepicker,
LdapOverrideConfirmationModal: () =>
import('ee_component/members/components/ldap/ldap_override_confirmation_modal.vue'),
@@ -225,6 +227,7 @@ export default {
align="center"
/>
<remove-group-link-modal />
+ <remove-member-modal />
<ldap-override-confirmation-modal />
</div>
</template>
diff --git a/app/assets/javascripts/members/store/actions.js b/app/assets/javascripts/members/store/actions.js
index 7b191dd85d0..712f0d6caa7 100644
--- a/app/assets/javascripts/members/store/actions.js
+++ b/app/assets/javascripts/members/store/actions.js
@@ -25,6 +25,14 @@ export const hideRemoveGroupLinkModal = ({ commit }) => {
commit(types.HIDE_REMOVE_GROUP_LINK_MODAL);
};
+export const showRemoveMemberModal = ({ commit }, modalData) => {
+ commit(types.SHOW_REMOVE_MEMBER_MODAL, modalData);
+};
+
+export const hideRemoveMemberModal = ({ commit }) => {
+ commit(types.HIDE_REMOVE_MEMBER_MODAL);
+};
+
export const updateMemberExpiration = async ({ state, commit }, { memberId, expiresAt }) => {
try {
await axios.put(
diff --git a/app/assets/javascripts/members/store/mutation_types.js b/app/assets/javascripts/members/store/mutation_types.js
index 77307aa745b..5fa75725552 100644
--- a/app/assets/javascripts/members/store/mutation_types.js
+++ b/app/assets/javascripts/members/store/mutation_types.js
@@ -8,3 +8,6 @@ export const HIDE_ERROR = 'HIDE_ERROR';
export const SHOW_REMOVE_GROUP_LINK_MODAL = 'SHOW_REMOVE_GROUP_LINK_MODAL';
export const HIDE_REMOVE_GROUP_LINK_MODAL = 'HIDE_REMOVE_GROUP_LINK_MODAL';
+
+export const SHOW_REMOVE_MEMBER_MODAL = 'SHOW_REMOVE_MEMBER_MODAL';
+export const HIDE_REMOVE_MEMBER_MODAL = 'HIDE_REMOVE_MEMBER_MODAL';
diff --git a/app/assets/javascripts/members/store/mutations.js b/app/assets/javascripts/members/store/mutations.js
index f4aac1571d6..b4cf9f3480f 100644
--- a/app/assets/javascripts/members/store/mutations.js
+++ b/app/assets/javascripts/members/store/mutations.js
@@ -47,4 +47,11 @@ export default {
[types.HIDE_REMOVE_GROUP_LINK_MODAL](state) {
state.removeGroupLinkModalVisible = false;
},
+ [types.SHOW_REMOVE_MEMBER_MODAL](state, modalData) {
+ state.removeMemberModalData = modalData;
+ state.removeMemberModalVisible = true;
+ },
+ [types.HIDE_REMOVE_MEMBER_MODAL](state) {
+ state.removeMemberModalVisible = false;
+ },
};
diff --git a/app/assets/javascripts/members/store/state.js b/app/assets/javascripts/members/store/state.js
index 5415b1c5f25..c233a660840 100644
--- a/app/assets/javascripts/members/store/state.js
+++ b/app/assets/javascripts/members/store/state.js
@@ -20,4 +20,6 @@ export default ({
errorMessage: '',
removeGroupLinkModalVisible: false,
groupLinkToRemove: null,
+ removeMemberModalData: {},
+ removeMemberModalVisible: false,
});
diff --git a/app/assets/javascripts/pages/admin/groups/show/index.js b/app/assets/javascripts/pages/admin/groups/show/index.js
index 69d219d29f7..86b80a0ba5b 100644
--- a/app/assets/javascripts/pages/admin/groups/show/index.js
+++ b/app/assets/javascripts/pages/admin/groups/show/index.js
@@ -1,23 +1,3 @@
-import Vue from 'vue';
import UsersSelect from '~/users_select';
-import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue';
-function mountRemoveMemberModal() {
- const el = document.querySelector('.js-remove-member-modal');
- if (!el) {
- return false;
- }
-
- return new Vue({
- el,
- render(createComponent) {
- return createComponent(RemoveMemberModal);
- },
- });
-}
-
-document.addEventListener('DOMContentLoaded', () => {
- mountRemoveMemberModal();
-
- new UsersSelect(); // eslint-disable-line no-new
-});
+new UsersSelect(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/admin/projects/index.js b/app/assets/javascripts/pages/admin/projects/index.js
index 042ff7808f1..b07ca815f13 100644
--- a/app/assets/javascripts/pages/admin/projects/index.js
+++ b/app/assets/javascripts/pages/admin/projects/index.js
@@ -1,23 +1,5 @@
-import Vue from 'vue';
import NamespaceSelect from '~/namespace_select';
import ProjectsList from '~/projects_list';
-import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue';
-
-function mountRemoveMemberModal() {
- const el = document.querySelector('.js-remove-member-modal');
- if (!el) {
- return false;
- }
-
- return new Vue({
- el,
- render(createComponent) {
- return createComponent(RemoveMemberModal);
- },
- });
-}
-
-mountRemoveMemberModal();
new ProjectsList(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/groups/group_members/index.js b/app/assets/javascripts/pages/groups/group_members/index.js
index 13656ee9b16..0137ff87979 100644
--- a/app/assets/javascripts/pages/groups/group_members/index.js
+++ b/app/assets/javascripts/pages/groups/group_members/index.js
@@ -1,4 +1,3 @@
-import Vue from 'vue';
import { groupMemberRequestFormatter } from '~/groups/members/utils';
import groupsSelect from '~/groups_select';
import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
@@ -11,21 +10,6 @@ import { initMembersApp } from '~/members';
import { MEMBER_TYPES } from '~/members/constants';
import { groupLinkRequestFormatter } from '~/members/utils';
import UsersSelect from '~/users_select';
-import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue';
-
-function mountRemoveMemberModal() {
- const el = document.querySelector('.js-remove-member-modal');
- if (!el) {
- return false;
- }
-
- return new Vue({
- el,
- render(createComponent) {
- return createComponent(RemoveMemberModal);
- },
- });
-}
const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'];
@@ -71,7 +55,6 @@ initMembersApp(document.querySelector('.js-group-members-list-app'), {
groupsSelect();
memberExpirationDate();
memberExpirationDate('.js-access-expiration-date-groups');
-mountRemoveMemberModal();
initInviteMembersModal();
initInviteMembersTrigger();
initInviteGroupTrigger();
diff --git a/app/assets/javascripts/pages/projects/project_members/index.js b/app/assets/javascripts/pages/projects/project_members/index.js
index 177dc346c60..fb0be31834d 100644
--- a/app/assets/javascripts/pages/projects/project_members/index.js
+++ b/app/assets/javascripts/pages/projects/project_members/index.js
@@ -1,4 +1,3 @@
-import Vue from 'vue';
import groupsSelect from '~/groups_select';
import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
import initInviteMembersForm from '~/invite_members/init_invite_members_form';
@@ -11,26 +10,10 @@ import { MEMBER_TYPES } from '~/members/constants';
import { groupLinkRequestFormatter } from '~/members/utils';
import { projectMemberRequestFormatter } from '~/projects/members/utils';
import UsersSelect from '~/users_select';
-import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue';
-
-function mountRemoveMemberModal() {
- const el = document.querySelector('.js-remove-member-modal');
- if (!el) {
- return false;
- }
-
- return new Vue({
- el,
- render(createComponent) {
- return createComponent(RemoveMemberModal);
- },
- });
-}
groupsSelect();
memberExpirationDate();
memberExpirationDate('.js-access-expiration-date-groups');
-mountRemoveMemberModal();
initInviteMembersModal();
initInviteMembersTrigger();
initInviteGroupTrigger();
diff --git a/app/assets/javascripts/runner/components/runner_update_form.vue b/app/assets/javascripts/runner/components/runner_update_form.vue
index 85d14547efd..a5bc1680852 100644
--- a/app/assets/javascripts/runner/components/runner_update_form.vue
+++ b/app/assets/javascripts/runner/components/runner_update_form.vue
@@ -111,7 +111,7 @@ export default {
>
{{ __('Paused') }}
<template #help>
- {{ __("Paused runners don't accept new jobs") }}
+ {{ s__('Runners|Stop the runner from accepting new jobs.') }}
</template>
</gl-form-checkbox>
@@ -123,14 +123,14 @@ export default {
>
{{ __('Protected') }}
<template #help>
- {{ __('This runner will only run on pipelines triggered on protected branches') }}
+ {{ s__('Runners|Use the runner on pipelines for protected branches only.') }}
</template>
</gl-form-checkbox>
<gl-form-checkbox v-model="model.runUntagged" data-testid="runner-field-run-untagged">
{{ __('Run untagged jobs') }}
<template #help>
- {{ __('Indicates whether this runner can pick jobs without tags') }}
+ {{ s__('Runners|Use the runner for jobs without tags, in addition to tagged jobs.') }}
</template>
</gl-form-checkbox>
@@ -141,7 +141,7 @@ export default {
>
{{ __('Lock to current projects') }}
<template #help>
- {{ __('When a runner is locked, it cannot be assigned to other projects') }}
+ {{ s__('Runners|Use the runner for the currently assigned projects only.') }}
</template>
</gl-form-checkbox>
diff --git a/app/assets/javascripts/security_configuration/components/constants.js b/app/assets/javascripts/security_configuration/components/constants.js
index 5cb9277040d..d80c67da8b1 100644
--- a/app/assets/javascripts/security_configuration/components/constants.js
+++ b/app/assets/javascripts/security_configuration/components/constants.js
@@ -98,6 +98,10 @@ export const COVERAGE_FUZZING_DESCRIPTION = __(
export const COVERAGE_FUZZING_HELP_PATH = helpPagePath(
'user/application_security/coverage_fuzzing/index',
);
+export const COVERAGE_FUZZING_CONFIG_HELP_PATH = helpPagePath(
+ 'user/application_security/coverage_fuzzing/index',
+ { anchor: 'configuration' },
+);
export const API_FUZZING_NAME = __('API Fuzzing');
export const API_FUZZING_DESCRIPTION = __('Find bugs in your code with API fuzzing.');
@@ -262,6 +266,7 @@ export const securityFeatures = [
name: COVERAGE_FUZZING_NAME,
description: COVERAGE_FUZZING_DESCRIPTION,
helpPath: COVERAGE_FUZZING_HELP_PATH,
+ configurationHelpPath: COVERAGE_FUZZING_CONFIG_HELP_PATH,
type: REPORT_TYPE_COVERAGE_FUZZING,
},
];
diff --git a/app/assets/javascripts/security_configuration/components/feature_card.vue b/app/assets/javascripts/security_configuration/components/feature_card.vue
index 23cffde1f83..6ca96504982 100644
--- a/app/assets/javascripts/security_configuration/components/feature_card.vue
+++ b/app/assets/javascripts/security_configuration/components/feature_card.vue
@@ -125,7 +125,12 @@ export default {
class="gl-mt-5"
/>
- <gl-button v-else icon="external-link" :href="feature.configurationHelpPath" class="gl-mt-5">
+ <gl-button
+ v-else-if="feature.configurationHelpPath"
+ icon="external-link"
+ :href="feature.configurationHelpPath"
+ class="gl-mt-5"
+ >
{{ $options.i18n.configurationGuide }}
</gl-button>
</template>
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index 9f1e2d8236a..ecc5ad1f84e 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -10,10 +10,6 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
before_action :apply_diff_view_cookie!, only: [:diffs, :diff_for_path]
before_action :build_merge_request, except: [:create]
- before_action do
- push_frontend_feature_flag(:mr_collapsed_approval_rules, @project)
- end
-
def new
define_new_vars
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index cfa64bbc16d..8c69fe61b67 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -55,7 +55,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
before_action do
- push_frontend_feature_flag(:mr_collapsed_approval_rules, @project)
push_frontend_feature_flag(:show_relevant_approval_rule_approvers, @project, default_enabled: :yaml)
end
diff --git a/app/graphql/resolvers/alert_management/alert_resolver.rb b/app/graphql/resolvers/alert_management/alert_resolver.rb
index 62744e719da..899b90a94dd 100644
--- a/app/graphql/resolvers/alert_management/alert_resolver.rb
+++ b/app/graphql/resolvers/alert_management/alert_resolver.rb
@@ -5,7 +5,7 @@ module Resolvers
class AlertResolver < BaseResolver
include LooksAhead
- argument :iid, GraphQL::STRING_TYPE,
+ argument :iid, GraphQL::Types::String,
required: false,
description: 'IID of the alert. For example, "1".'
@@ -23,11 +23,11 @@ module Resolvers
required: true,
default_value: 'operations'
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
description: 'Search query for title, description, service, or monitoring_tool.',
required: false
- argument :assignee_username, GraphQL::STRING_TYPE,
+ argument :assignee_username, GraphQL::Types::String,
required: false,
description: 'Username of a user assigned to the issue.'
diff --git a/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb b/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb
index 410f72cff84..568d648a95e 100644
--- a/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb
+++ b/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb
@@ -5,11 +5,11 @@ module Resolvers
class AlertStatusCountsResolver < BaseResolver
type Types::AlertManagement::AlertStatusCountsType, null: true
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
description: 'Search query for title, description, service, or monitoring_tool.',
required: false
- argument :assignee_username, GraphQL::STRING_TYPE,
+ argument :assignee_username, GraphQL::Types::String,
required: false,
description: 'Username of a user assigned to the issue.'
diff --git a/app/graphql/resolvers/blobs_resolver.rb b/app/graphql/resolvers/blobs_resolver.rb
index d006769bd4b..4c35f6c342e 100644
--- a/app/graphql/resolvers/blobs_resolver.rb
+++ b/app/graphql/resolvers/blobs_resolver.rb
@@ -10,10 +10,10 @@ module Resolvers
alias_method :repository, :object
- argument :paths, [GraphQL::STRING_TYPE],
+ argument :paths, [GraphQL::Types::String],
required: true,
description: 'Array of desired blob paths.'
- argument :ref, GraphQL::STRING_TYPE,
+ argument :ref, GraphQL::Types::String,
required: false,
default_value: nil,
description: 'The commit ref to get the blobs from. Default value is HEAD.'
diff --git a/app/graphql/resolvers/ci/config_resolver.rb b/app/graphql/resolvers/ci/config_resolver.rb
index f2e33251b9c..eb331331c70 100644
--- a/app/graphql/resolvers/ci/config_resolver.rb
+++ b/app/graphql/resolvers/ci/config_resolver.rb
@@ -14,19 +14,19 @@ module Resolvers
authorize :read_pipeline
- argument :project_path, GraphQL::ID_TYPE,
+ argument :project_path, GraphQL::Types::ID,
required: true,
description: 'The project of the CI config.'
- argument :sha, GraphQL::STRING_TYPE,
+ argument :sha, GraphQL::Types::String,
required: false,
description: "Sha for the pipeline."
- argument :content, GraphQL::STRING_TYPE,
+ argument :content, GraphQL::Types::String,
required: true,
description: "Contents of `.gitlab-ci.yml`."
- argument :dry_run, GraphQL::BOOLEAN_TYPE,
+ argument :dry_run, GraphQL::Types::Boolean,
required: false,
description: 'Run pipeline creation simulation, or only do static check.'
diff --git a/app/graphql/resolvers/ci/runner_setup_resolver.rb b/app/graphql/resolvers/ci/runner_setup_resolver.rb
index 9166999b400..6b21f5c3ab4 100644
--- a/app/graphql/resolvers/ci/runner_setup_resolver.rb
+++ b/app/graphql/resolvers/ci/runner_setup_resolver.rb
@@ -9,12 +9,12 @@ module Resolvers
description 'Runner setup instructions.'
argument :platform,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
required: true,
description: 'Platform to generate the instructions for.'
argument :architecture,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
required: true,
description: 'Architecture to generate the instructions for.'
diff --git a/app/graphql/resolvers/ci/runners_resolver.rb b/app/graphql/resolvers/ci/runners_resolver.rb
index 5074a248e18..1957c4ec058 100644
--- a/app/graphql/resolvers/ci/runners_resolver.rb
+++ b/app/graphql/resolvers/ci/runners_resolver.rb
@@ -15,11 +15,11 @@ module Resolvers
required: false,
description: 'Filter runners by type.'
- argument :tag_list, [GraphQL::STRING_TYPE],
+ argument :tag_list, [GraphQL::Types::String],
required: false,
description: 'Filter by tags associated with the runner (comma-separated or array).'
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
required: false,
description: 'Filter by full token or partial text in description field.'
diff --git a/app/graphql/resolvers/ci/template_resolver.rb b/app/graphql/resolvers/ci/template_resolver.rb
index 7f5a1a486d7..17f2668df11 100644
--- a/app/graphql/resolvers/ci/template_resolver.rb
+++ b/app/graphql/resolvers/ci/template_resolver.rb
@@ -5,7 +5,7 @@ module Resolvers
class TemplateResolver < BaseResolver
type Types::Ci::TemplateType, null: true
- argument :name, GraphQL::STRING_TYPE, required: true,
+ argument :name, GraphQL::Types::String, required: true,
description: 'Name of the CI/CD template to search for. Template must be formatted as `Name.gitlab-ci.yml`.'
alias_method :project, :object
diff --git a/app/graphql/resolvers/ci/test_suite_resolver.rb b/app/graphql/resolvers/ci/test_suite_resolver.rb
index 90cc30b1281..5d61d9e986b 100644
--- a/app/graphql/resolvers/ci/test_suite_resolver.rb
+++ b/app/graphql/resolvers/ci/test_suite_resolver.rb
@@ -11,7 +11,7 @@ module Resolvers
alias_method :pipeline, :object
- argument :build_ids, [GraphQL::ID_TYPE],
+ argument :build_ids, [GraphQL::Types::ID],
required: true,
description: 'IDs of the builds used to run the test suite.'
diff --git a/app/graphql/resolvers/concerns/group_issuable_resolver.rb b/app/graphql/resolvers/concerns/group_issuable_resolver.rb
index 49a79683e9f..542ff5374ff 100644
--- a/app/graphql/resolvers/concerns/group_issuable_resolver.rb
+++ b/app/graphql/resolvers/concerns/group_issuable_resolver.rb
@@ -5,7 +5,7 @@ module GroupIssuableResolver
class_methods do
def include_subgroups(name_of_things)
- argument :include_subgroups, GraphQL::BOOLEAN_TYPE,
+ argument :include_subgroups, GraphQL::Types::Boolean,
required: false,
default_value: false,
description: "Include #{name_of_things} belonging to subgroups"
diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
index c24f4dedc0e..b91dca3fc47 100644
--- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
+++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
@@ -6,29 +6,29 @@ module IssueResolverArguments
prepended do
include LooksAhead
- argument :iid, GraphQL::STRING_TYPE,
+ argument :iid, GraphQL::Types::String,
required: false,
description: 'IID of the issue. For example, "1".'
- argument :iids, [GraphQL::STRING_TYPE],
+ argument :iids, [GraphQL::Types::String],
required: false,
description: 'List of IIDs of issues. For example, `["1", "2"]`.'
- argument :label_name, [GraphQL::STRING_TYPE, null: true],
+ argument :label_name, [GraphQL::Types::String, null: true],
required: false,
description: 'Labels applied to this issue.'
- argument :milestone_title, [GraphQL::STRING_TYPE, null: true],
+ argument :milestone_title, [GraphQL::Types::String, null: true],
required: false,
description: 'Milestone applied to this issue.'
- argument :author_username, GraphQL::STRING_TYPE,
+ argument :author_username, GraphQL::Types::String,
required: false,
description: 'Username of the author of the issue.'
- argument :assignee_username, GraphQL::STRING_TYPE,
+ argument :assignee_username, GraphQL::Types::String,
required: false,
description: 'Username of a user assigned to the issue.',
deprecated: { reason: 'Use `assigneeUsernames`', milestone: '13.11' }
- argument :assignee_usernames, [GraphQL::STRING_TYPE],
+ argument :assignee_usernames, [GraphQL::Types::String],
required: false,
description: 'Usernames of users assigned to the issue.'
- argument :assignee_id, GraphQL::STRING_TYPE,
+ argument :assignee_id, GraphQL::Types::String,
required: false,
description: 'ID of a user assigned to the issues, "none" and "any" values are supported.'
argument :created_before, Types::TimeType,
@@ -49,7 +49,7 @@ module IssueResolverArguments
argument :closed_after, Types::TimeType,
required: false,
description: 'Issues closed after this date.'
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
required: false,
description: 'Search query for issue title or description.'
argument :types, [Types::IssueTypeEnum],
diff --git a/app/graphql/resolvers/concerns/resolves_pipelines.rb b/app/graphql/resolvers/concerns/resolves_pipelines.rb
index bbf33c0b5eb..77f2105db7c 100644
--- a/app/graphql/resolvers/concerns/resolves_pipelines.rb
+++ b/app/graphql/resolvers/concerns/resolves_pipelines.rb
@@ -10,11 +10,11 @@ module ResolvesPipelines
required: false,
description: "Filter pipelines by their status."
argument :ref,
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
required: false,
description: "Filter pipelines by the ref they are run for."
argument :sha,
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
required: false,
description: "Filter pipelines by the sha of the commit they are run for."
end
diff --git a/app/graphql/resolvers/container_repositories_resolver.rb b/app/graphql/resolvers/container_repositories_resolver.rb
index 17af2a2f070..1e06d4e9094 100644
--- a/app/graphql/resolvers/container_repositories_resolver.rb
+++ b/app/graphql/resolvers/container_repositories_resolver.rb
@@ -6,7 +6,7 @@ module Resolvers
type Types::ContainerRepositoryType, null: true
- argument :name, GraphQL::STRING_TYPE,
+ argument :name, GraphQL::Types::String,
required: false,
description: 'Filter the container repositories by their name.'
diff --git a/app/graphql/resolvers/design_management/design_resolver.rb b/app/graphql/resolvers/design_management/design_resolver.rb
index e640f57f04a..d9e5203ef0e 100644
--- a/app/graphql/resolvers/design_management/design_resolver.rb
+++ b/app/graphql/resolvers/design_management/design_resolver.rb
@@ -11,7 +11,7 @@ module Resolvers
required: false,
description: 'Find a design by its ID.'
- argument :filename, GraphQL::STRING_TYPE,
+ argument :filename, GraphQL::Types::String,
required: false,
description: 'Find a design by its filename.'
diff --git a/app/graphql/resolvers/design_management/designs_resolver.rb b/app/graphql/resolvers/design_management/designs_resolver.rb
index c45e4d01f6e..dec778fac80 100644
--- a/app/graphql/resolvers/design_management/designs_resolver.rb
+++ b/app/graphql/resolvers/design_management/designs_resolver.rb
@@ -11,7 +11,7 @@ module Resolvers
argument :ids, [DesignID],
required: false,
description: 'Filters designs by their ID.'
- argument :filenames, [GraphQL::STRING_TYPE],
+ argument :filenames, [GraphQL::Types::String],
required: false,
description: 'Filters designs by their filename.'
argument :at_version, VersionID,
diff --git a/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb b/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
index fea74cbfb0b..3f872ebbc55 100644
--- a/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
+++ b/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
@@ -23,7 +23,7 @@ module Resolvers
argument :design_id, DesignID,
required: false,
description: 'The ID of a specific design.'
- argument :filename, GraphQL::STRING_TYPE,
+ argument :filename, GraphQL::Types::String,
required: false,
description: 'The filename of a specific design.'
diff --git a/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb b/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb
index 930b1b60d0e..254f1efa0a5 100644
--- a/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb
+++ b/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb
@@ -17,7 +17,7 @@ module Resolvers
required: false,
description: 'Filters designs by their ID.'
argument :filenames,
- [GraphQL::STRING_TYPE],
+ [GraphQL::Types::String],
required: false,
description: 'Filters designs by their filename.'
diff --git a/app/graphql/resolvers/design_management/version_in_collection_resolver.rb b/app/graphql/resolvers/design_management/version_in_collection_resolver.rb
index 593974beb04..10c3d4126d4 100644
--- a/app/graphql/resolvers/design_management/version_in_collection_resolver.rb
+++ b/app/graphql/resolvers/design_management/version_in_collection_resolver.rb
@@ -15,7 +15,7 @@ module Resolvers
VersionID = ::Types::GlobalIDType[::DesignManagement::Version]
- argument :sha, GraphQL::STRING_TYPE,
+ argument :sha, GraphQL::Types::String,
required: false,
description: "The SHA256 of a specific version."
argument :id, VersionID,
diff --git a/app/graphql/resolvers/design_management/versions_resolver.rb b/app/graphql/resolvers/design_management/versions_resolver.rb
index 08b29d884b0..71ab768c89e 100644
--- a/app/graphql/resolvers/design_management/versions_resolver.rb
+++ b/app/graphql/resolvers/design_management/versions_resolver.rb
@@ -11,7 +11,7 @@ module Resolvers
extras [:parent]
- argument :earlier_or_equal_to_sha, GraphQL::STRING_TYPE,
+ argument :earlier_or_equal_to_sha, GraphQL::Types::String,
as: :sha,
required: false,
description: 'The SHA256 of the most recent acceptable version.'
diff --git a/app/graphql/resolvers/echo_resolver.rb b/app/graphql/resolvers/echo_resolver.rb
index a09b0a1fd87..856e6873a65 100644
--- a/app/graphql/resolvers/echo_resolver.rb
+++ b/app/graphql/resolvers/echo_resolver.rb
@@ -2,11 +2,11 @@
module Resolvers
class EchoResolver < BaseResolver
- type ::GraphQL::STRING_TYPE, null: false
+ type ::GraphQL::Types::String, null: false
description 'Testing endpoint to validate the API with'
argument :text,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
required: true,
description: 'Text to echo back.'
diff --git a/app/graphql/resolvers/environments_resolver.rb b/app/graphql/resolvers/environments_resolver.rb
index ee604e7b307..1823eb65d44 100644
--- a/app/graphql/resolvers/environments_resolver.rb
+++ b/app/graphql/resolvers/environments_resolver.rb
@@ -2,15 +2,15 @@
module Resolvers
class EnvironmentsResolver < BaseResolver
- argument :name, GraphQL::STRING_TYPE,
+ argument :name, GraphQL::Types::String,
required: false,
description: 'Name of the environment.'
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
required: false,
description: 'Search query for environment name.'
- argument :states, [GraphQL::STRING_TYPE],
+ argument :states, [GraphQL::Types::String],
required: false,
description: 'States of environments that should be included in result.'
diff --git a/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb b/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb
index 4cd65daa655..793b73342ab 100644
--- a/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb
+++ b/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb
@@ -6,12 +6,12 @@ module Resolvers
type Types::ErrorTracking::SentryErrorType.connection_type, null: true
extension Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension
- argument :search_term, ::GraphQL::STRING_TYPE,
+ argument :search_term, ::GraphQL::Types::String,
description: 'Search query for the Sentry error details.',
required: false
# TODO: convert to Enum
- argument :sort, ::GraphQL::STRING_TYPE,
+ argument :sort, ::GraphQL::Types::String,
description: 'Attribute to sort on. Options are frequency, first_seen, last_seen. last_seen is default.',
required: false
diff --git a/app/graphql/resolvers/full_path_resolver.rb b/app/graphql/resolvers/full_path_resolver.rb
index b5e90da78b2..2dab55a1954 100644
--- a/app/graphql/resolvers/full_path_resolver.rb
+++ b/app/graphql/resolvers/full_path_resolver.rb
@@ -5,7 +5,7 @@ module Resolvers
extend ActiveSupport::Concern
prepended do
- argument :full_path, GraphQL::ID_TYPE,
+ argument :full_path, GraphQL::Types::ID,
required: true,
description: 'The full path of the project, group or namespace, e.g., `gitlab-org/gitlab-foss`.'
end
diff --git a/app/graphql/resolvers/group_labels_resolver.rb b/app/graphql/resolvers/group_labels_resolver.rb
index 5c2f950bbc0..a22fa9761d6 100644
--- a/app/graphql/resolvers/group_labels_resolver.rb
+++ b/app/graphql/resolvers/group_labels_resolver.rb
@@ -4,12 +4,12 @@ module Resolvers
class GroupLabelsResolver < LabelsResolver
type Types::LabelType.connection_type, null: true
- argument :include_descendant_groups, GraphQL::BOOLEAN_TYPE,
+ argument :include_descendant_groups, GraphQL::Types::Boolean,
required: false,
description: 'Include labels from descendant groups.',
default_value: false
- argument :only_group_labels, GraphQL::BOOLEAN_TYPE,
+ argument :only_group_labels, GraphQL::Types::Boolean,
required: false,
description: 'Include only group level labels.',
default_value: false
diff --git a/app/graphql/resolvers/group_milestones_resolver.rb b/app/graphql/resolvers/group_milestones_resolver.rb
index 31280b36278..44192b6f4bf 100644
--- a/app/graphql/resolvers/group_milestones_resolver.rb
+++ b/app/graphql/resolvers/group_milestones_resolver.rb
@@ -2,10 +2,10 @@
module Resolvers
class GroupMilestonesResolver < MilestonesResolver
- argument :include_descendants, GraphQL::BOOLEAN_TYPE,
+ argument :include_descendants, GraphQL::Types::Boolean,
required: false,
description: 'Include milestones from all subgroups and subprojects.'
- argument :include_ancestors, GraphQL::BOOLEAN_TYPE,
+ argument :include_ancestors, GraphQL::Types::Boolean,
required: false,
description: 'Include milestones from all parent groups.'
diff --git a/app/graphql/resolvers/labels_resolver.rb b/app/graphql/resolvers/labels_resolver.rb
index 1b523b8a240..505d1dff8d2 100644
--- a/app/graphql/resolvers/labels_resolver.rb
+++ b/app/graphql/resolvers/labels_resolver.rb
@@ -8,11 +8,11 @@ module Resolvers
type Types::LabelType.connection_type, null: true
- argument :search_term, GraphQL::STRING_TYPE,
+ argument :search_term, GraphQL::Types::String,
required: false,
description: 'A search term to find labels with.'
- argument :include_ancestor_groups, GraphQL::BOOLEAN_TYPE,
+ argument :include_ancestor_groups, GraphQL::Types::Boolean,
required: false,
description: 'Include labels from ancestor groups.',
default_value: false
diff --git a/app/graphql/resolvers/members_resolver.rb b/app/graphql/resolvers/members_resolver.rb
index 2b731d54cdd..827db54134a 100644
--- a/app/graphql/resolvers/members_resolver.rb
+++ b/app/graphql/resolvers/members_resolver.rb
@@ -7,7 +7,7 @@ module Resolvers
type Types::MemberInterface.connection_type, null: true
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
required: false,
description: 'Search query.'
diff --git a/app/graphql/resolvers/merge_request_resolver.rb b/app/graphql/resolvers/merge_request_resolver.rb
index c431d079beb..0f0f3ee3772 100644
--- a/app/graphql/resolvers/merge_request_resolver.rb
+++ b/app/graphql/resolvers/merge_request_resolver.rb
@@ -8,7 +8,7 @@ module Resolvers
type ::Types::MergeRequestType, null: true
- argument :iid, GraphQL::STRING_TYPE,
+ argument :iid, GraphQL::Types::String,
required: true,
as: :iids,
description: 'IID of the merge request, for example `1`.'
diff --git a/app/graphql/resolvers/merge_requests_resolver.rb b/app/graphql/resolvers/merge_requests_resolver.rb
index a9eea4ae4b8..8f2c7847a2e 100644
--- a/app/graphql/resolvers/merge_requests_resolver.rb
+++ b/app/graphql/resolvers/merge_requests_resolver.rb
@@ -10,28 +10,28 @@ module Resolvers
alias_method :project, :object
def self.accept_assignee
- argument :assignee_username, GraphQL::STRING_TYPE,
+ argument :assignee_username, GraphQL::Types::String,
required: false,
description: 'Username of the assignee.'
end
def self.accept_author
- argument :author_username, GraphQL::STRING_TYPE,
+ argument :author_username, GraphQL::Types::String,
required: false,
description: 'Username of the author.'
end
def self.accept_reviewer
- argument :reviewer_username, GraphQL::STRING_TYPE,
+ argument :reviewer_username, GraphQL::Types::String,
required: false,
description: 'Username of the reviewer.'
end
- argument :iids, [GraphQL::STRING_TYPE],
+ argument :iids, [GraphQL::Types::String],
required: false,
description: 'Array of IIDs of merge requests, for example `[1, 2]`.'
- argument :source_branches, [GraphQL::STRING_TYPE],
+ argument :source_branches, [GraphQL::Types::String],
required: false,
as: :source_branch,
description: <<~DESC
@@ -39,7 +39,7 @@ module Resolvers
All resolved merge requests will have one of these branches as their source.
DESC
- argument :target_branches, [GraphQL::STRING_TYPE],
+ argument :target_branches, [GraphQL::Types::String],
required: false,
as: :target_branch,
description: <<~DESC
@@ -51,7 +51,7 @@ module Resolvers
required: false,
description: 'A merge request state. If provided, all resolved merge requests will have this state.'
- argument :labels, [GraphQL::STRING_TYPE],
+ argument :labels, [GraphQL::Types::String],
required: false,
as: :label_name,
description: 'Array of label names. All resolved merge requests will have all of these labels.'
@@ -61,7 +61,7 @@ module Resolvers
argument :merged_before, Types::TimeType,
required: false,
description: 'Merge requests merged before this date.'
- argument :milestone_title, GraphQL::STRING_TYPE,
+ argument :milestone_title, GraphQL::Types::String,
required: false,
description: 'Title of the milestone.'
argument :sort, Types::MergeRequestSortEnum,
@@ -70,11 +70,11 @@ module Resolvers
default_value: :created_desc
negated do
- argument :labels, [GraphQL::STRING_TYPE],
+ argument :labels, [GraphQL::Types::String],
required: false,
as: :label_name,
description: 'Array of label names. All resolved merge requests will not have these labels.'
- argument :milestone_title, GraphQL::STRING_TYPE,
+ argument :milestone_title, GraphQL::Types::String,
required: false,
description: 'Title of the milestone.'
end
diff --git a/app/graphql/resolvers/metrics/dashboard_resolver.rb b/app/graphql/resolvers/metrics/dashboard_resolver.rb
index 0669fececd5..d2be9fcdd89 100644
--- a/app/graphql/resolvers/metrics/dashboard_resolver.rb
+++ b/app/graphql/resolvers/metrics/dashboard_resolver.rb
@@ -6,7 +6,7 @@ module Resolvers
type Types::Metrics::DashboardType, null: true
calls_gitaly!
- argument :path, GraphQL::STRING_TYPE,
+ argument :path, GraphQL::Types::String,
required: true,
description: <<~MD
Path to a file which defines a metrics dashboard eg: `"config/prometheus/common_metrics.yml"`.
diff --git a/app/graphql/resolvers/milestones_resolver.rb b/app/graphql/resolvers/milestones_resolver.rb
index 4fa4c939a23..84f7d66ec19 100644
--- a/app/graphql/resolvers/milestones_resolver.rb
+++ b/app/graphql/resolvers/milestones_resolver.rb
@@ -5,7 +5,7 @@ module Resolvers
include Gitlab::Graphql::Authorize::AuthorizeResource
include TimeFrameArguments
- argument :ids, [GraphQL::ID_TYPE],
+ argument :ids, [GraphQL::Types::ID],
required: false,
description: 'Array of global milestone IDs, e.g., `"gid://gitlab/Milestone/1"`.'
@@ -13,11 +13,11 @@ module Resolvers
required: false,
description: 'Filter milestones by state.'
- argument :title, GraphQL::STRING_TYPE,
+ argument :title, GraphQL::Types::String,
required: false,
description: 'The title of the milestone.'
- argument :search_title, GraphQL::STRING_TYPE,
+ argument :search_title, GraphQL::Types::String,
required: false,
description: 'A search string for the title.'
diff --git a/app/graphql/resolvers/namespace_projects_resolver.rb b/app/graphql/resolvers/namespace_projects_resolver.rb
index 86286a744bd..c3c61d31e8d 100644
--- a/app/graphql/resolvers/namespace_projects_resolver.rb
+++ b/app/graphql/resolvers/namespace_projects_resolver.rb
@@ -2,12 +2,12 @@
module Resolvers
class NamespaceProjectsResolver < BaseResolver
- argument :include_subgroups, GraphQL::BOOLEAN_TYPE,
+ argument :include_subgroups, GraphQL::Types::Boolean,
required: false,
default_value: false,
description: 'Include also subgroup projects.'
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
required: false,
default_value: nil,
description: 'Search project with most similar names or paths.'
@@ -17,7 +17,7 @@ module Resolvers
default_value: nil,
description: 'Sort projects by this criteria.'
- argument :ids, [GraphQL::ID_TYPE],
+ argument :ids, [GraphQL::Types::ID],
required: false,
default_value: nil,
description: 'Filter projects by IDs.'
diff --git a/app/graphql/resolvers/packages_base_resolver.rb b/app/graphql/resolvers/packages_base_resolver.rb
index 3378cc32c9f..7d153d16910 100644
--- a/app/graphql/resolvers/packages_base_resolver.rb
+++ b/app/graphql/resolvers/packages_base_resolver.rb
@@ -9,7 +9,7 @@ module Resolvers
required: false,
default_value: :created_desc
- argument :package_name, GraphQL::STRING_TYPE,
+ argument :package_name, GraphQL::Types::String,
description: 'Search a package by name.',
required: false,
default_value: nil
@@ -24,7 +24,7 @@ module Resolvers
required: false,
default_value: nil
- argument :include_versionless, GraphQL::BOOLEAN_TYPE,
+ argument :include_versionless, GraphQL::Types::Boolean,
description: 'Include versionless packages.',
required: false,
default_value: false
diff --git a/app/graphql/resolvers/project_milestones_resolver.rb b/app/graphql/resolvers/project_milestones_resolver.rb
index 4cd9cb53f56..567a55aa09b 100644
--- a/app/graphql/resolvers/project_milestones_resolver.rb
+++ b/app/graphql/resolvers/project_milestones_resolver.rb
@@ -3,7 +3,7 @@
module Resolvers
class ProjectMilestonesResolver < MilestonesResolver
- argument :include_ancestors, GraphQL::BOOLEAN_TYPE,
+ argument :include_ancestors, GraphQL::Types::Boolean,
required: false,
description: "Also return milestones in the project's parent group and its ancestors."
diff --git a/app/graphql/resolvers/project_pipeline_resolver.rb b/app/graphql/resolvers/project_pipeline_resolver.rb
index aa8808b15ac..ce4b6ac6b0c 100644
--- a/app/graphql/resolvers/project_pipeline_resolver.rb
+++ b/app/graphql/resolvers/project_pipeline_resolver.rb
@@ -6,11 +6,11 @@ module Resolvers
alias_method :project, :object
- argument :iid, GraphQL::ID_TYPE,
+ argument :iid, GraphQL::Types::ID,
required: false,
description: 'IID of the Pipeline. For example, "1".'
- argument :sha, GraphQL::STRING_TYPE,
+ argument :sha, GraphQL::Types::String,
required: false,
description: 'SHA of the Pipeline. For example, "dyd0f15ay83993f5ab66k927w28673882x99100b".'
diff --git a/app/graphql/resolvers/projects/jira_projects_resolver.rb b/app/graphql/resolvers/projects/jira_projects_resolver.rb
index 864acb6d759..56432585015 100644
--- a/app/graphql/resolvers/projects/jira_projects_resolver.rb
+++ b/app/graphql/resolvers/projects/jira_projects_resolver.rb
@@ -9,7 +9,7 @@ module Resolvers
authorize :admin_project
argument :name,
- GraphQL::STRING_TYPE,
+ GraphQL::Types::String,
required: false,
description: 'Project name or key.'
diff --git a/app/graphql/resolvers/projects/services_resolver.rb b/app/graphql/resolvers/projects/services_resolver.rb
index 3674aa97e1f..99de4df945c 100644
--- a/app/graphql/resolvers/projects/services_resolver.rb
+++ b/app/graphql/resolvers/projects/services_resolver.rb
@@ -10,7 +10,7 @@ module Resolvers
authorizes_object!
argument :active,
- GraphQL::BOOLEAN_TYPE,
+ GraphQL::Types::Boolean,
required: false,
description: 'Indicates if the integration is active.'
argument :type,
diff --git a/app/graphql/resolvers/projects_resolver.rb b/app/graphql/resolvers/projects_resolver.rb
index 665ec796cd3..b846248458f 100644
--- a/app/graphql/resolvers/projects_resolver.rb
+++ b/app/graphql/resolvers/projects_resolver.rb
@@ -4,27 +4,27 @@ module Resolvers
class ProjectsResolver < BaseResolver
type Types::ProjectType, null: true
- argument :membership, GraphQL::BOOLEAN_TYPE,
+ argument :membership, GraphQL::Types::Boolean,
required: false,
description: 'Limit projects that the current user is a member of.'
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
required: false,
description: 'Search query for project name, path, or description.'
- argument :ids, [GraphQL::ID_TYPE],
+ argument :ids, [GraphQL::Types::ID],
required: false,
description: 'Filter projects by IDs.'
- argument :search_namespaces, GraphQL::BOOLEAN_TYPE,
+ argument :search_namespaces, GraphQL::Types::Boolean,
required: false,
description: 'Include namespace in project search.'
- argument :sort, GraphQL::STRING_TYPE,
+ argument :sort, GraphQL::Types::String,
required: false,
description: 'Sort order of results.'
- argument :topics, type: [GraphQL::STRING_TYPE],
+ argument :topics, type: [GraphQL::Types::String],
required: false,
description: 'Filters projects by topics.'
diff --git a/app/graphql/resolvers/release_resolver.rb b/app/graphql/resolvers/release_resolver.rb
index 67ff5fed0bb..0374a1103de 100644
--- a/app/graphql/resolvers/release_resolver.rb
+++ b/app/graphql/resolvers/release_resolver.rb
@@ -4,7 +4,7 @@ module Resolvers
class ReleaseResolver < BaseResolver
type Types::ReleaseType, null: true
- argument :tag_name, GraphQL::STRING_TYPE,
+ argument :tag_name, GraphQL::Types::String,
required: true,
description: 'The name of the tag associated to the release.'
diff --git a/app/graphql/resolvers/repository_branch_names_resolver.rb b/app/graphql/resolvers/repository_branch_names_resolver.rb
index c0a5ea0366f..e9aacda2652 100644
--- a/app/graphql/resolvers/repository_branch_names_resolver.rb
+++ b/app/graphql/resolvers/repository_branch_names_resolver.rb
@@ -2,19 +2,19 @@
module Resolvers
class RepositoryBranchNamesResolver < BaseResolver
- type ::GraphQL::STRING_TYPE, null: false
+ type ::GraphQL::Types::String, null: false
calls_gitaly!
- argument :search_pattern, GraphQL::STRING_TYPE,
+ argument :search_pattern, GraphQL::Types::String,
required: true,
description: 'The pattern to search for branch names by.'
- argument :offset, GraphQL::INT_TYPE,
+ argument :offset, GraphQL::Types::Int,
required: true,
description: 'The number of branch names to skip.'
- argument :limit, GraphQL::INT_TYPE,
+ argument :limit, GraphQL::Types::Int,
required: true,
description: 'The number of branch names to return.'
diff --git a/app/graphql/resolvers/snippets/blobs_resolver.rb b/app/graphql/resolvers/snippets/blobs_resolver.rb
index 4328d38d485..00f41517422 100644
--- a/app/graphql/resolvers/snippets/blobs_resolver.rb
+++ b/app/graphql/resolvers/snippets/blobs_resolver.rb
@@ -12,7 +12,7 @@ module Resolvers
alias_method :snippet, :object
- argument :paths, [GraphQL::STRING_TYPE],
+ argument :paths, [GraphQL::Types::String],
required: false,
description: 'Paths of the blobs.'
diff --git a/app/graphql/resolvers/snippets_resolver.rb b/app/graphql/resolvers/snippets_resolver.rb
index 7153c919062..4e34185b189 100644
--- a/app/graphql/resolvers/snippets_resolver.rb
+++ b/app/graphql/resolvers/snippets_resolver.rb
@@ -22,7 +22,7 @@ module Resolvers
description: 'The type of snippet.'
argument :explore,
- GraphQL::BOOLEAN_TYPE,
+ GraphQL::Types::Boolean,
required: false,
description: 'Explore personal snippets.'
diff --git a/app/graphql/resolvers/terraform/states_resolver.rb b/app/graphql/resolvers/terraform/states_resolver.rb
index f543eb182e8..69785cfc794 100644
--- a/app/graphql/resolvers/terraform/states_resolver.rb
+++ b/app/graphql/resolvers/terraform/states_resolver.rb
@@ -8,7 +8,7 @@ module Resolvers
alias_method :project, :object
when_single do
- argument :name, GraphQL::STRING_TYPE,
+ argument :name, GraphQL::Types::String,
required: true,
description: 'Name of the Terraform state.'
end
diff --git a/app/graphql/resolvers/todo_resolver.rb b/app/graphql/resolvers/todo_resolver.rb
index 8966285fccc..9de61e95898 100644
--- a/app/graphql/resolvers/todo_resolver.rb
+++ b/app/graphql/resolvers/todo_resolver.rb
@@ -10,15 +10,15 @@ module Resolvers
required: false,
description: 'The action to be filtered.'
- argument :author_id, [GraphQL::ID_TYPE],
+ argument :author_id, [GraphQL::Types::ID],
required: false,
description: 'The ID of an author.'
- argument :project_id, [GraphQL::ID_TYPE],
+ argument :project_id, [GraphQL::Types::ID],
required: false,
description: 'The ID of a project.'
- argument :group_id, [GraphQL::ID_TYPE],
+ argument :group_id, [GraphQL::Types::ID],
required: false,
description: 'The ID of a group.'
diff --git a/app/graphql/resolvers/tree_resolver.rb b/app/graphql/resolvers/tree_resolver.rb
index c07d9187d4d..70b4d81845c 100644
--- a/app/graphql/resolvers/tree_resolver.rb
+++ b/app/graphql/resolvers/tree_resolver.rb
@@ -6,15 +6,15 @@ module Resolvers
calls_gitaly!
- argument :path, GraphQL::STRING_TYPE,
+ argument :path, GraphQL::Types::String,
required: false,
default_value: '',
description: 'The path to get the tree for. Default value is the root of the repository.'
- argument :ref, GraphQL::STRING_TYPE,
+ argument :ref, GraphQL::Types::String,
required: false,
default_value: :head,
description: 'The commit ref to get the tree for. Default value is HEAD.'
- argument :recursive, GraphQL::BOOLEAN_TYPE,
+ argument :recursive, GraphQL::Types::Boolean,
required: false,
default_value: false,
description: 'Used to get a recursive tree. Default is false.'
diff --git a/app/graphql/resolvers/user_discussions_count_resolver.rb b/app/graphql/resolvers/user_discussions_count_resolver.rb
index 115997ec666..0a04e8df0b8 100644
--- a/app/graphql/resolvers/user_discussions_count_resolver.rb
+++ b/app/graphql/resolvers/user_discussions_count_resolver.rb
@@ -4,7 +4,7 @@ module Resolvers
class UserDiscussionsCountResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
- type GraphQL::INT_TYPE, null: true
+ type GraphQL::Types::Int, null: true
def resolve
authorize!(object)
diff --git a/app/graphql/resolvers/user_merge_requests_resolver_base.rb b/app/graphql/resolvers/user_merge_requests_resolver_base.rb
index 221a43f691d..e0201e45664 100644
--- a/app/graphql/resolvers/user_merge_requests_resolver_base.rb
+++ b/app/graphql/resolvers/user_merge_requests_resolver_base.rb
@@ -5,7 +5,7 @@ module Resolvers
include ResolvesProject
argument :project_path,
- type: GraphQL::STRING_TYPE,
+ type: GraphQL::Types::String,
required: false,
description: <<~DESC
The full-path of the project the authored merge requests should be in.
diff --git a/app/graphql/resolvers/user_notes_count_resolver.rb b/app/graphql/resolvers/user_notes_count_resolver.rb
index 2cb61104c18..b91815c72f5 100644
--- a/app/graphql/resolvers/user_notes_count_resolver.rb
+++ b/app/graphql/resolvers/user_notes_count_resolver.rb
@@ -4,7 +4,7 @@ module Resolvers
class UserNotesCountResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
- type GraphQL::INT_TYPE, null: true
+ type GraphQL::Types::Int, null: true
def resolve
authorize!(object)
diff --git a/app/graphql/resolvers/user_resolver.rb b/app/graphql/resolvers/user_resolver.rb
index 84bc03091d9..99fd0d4927d 100644
--- a/app/graphql/resolvers/user_resolver.rb
+++ b/app/graphql/resolvers/user_resolver.rb
@@ -10,7 +10,7 @@ module Resolvers
required: false,
description: 'ID of the User.'
- argument :username, GraphQL::STRING_TYPE,
+ argument :username, GraphQL::Types::String,
required: false,
description: 'Username of the User.'
diff --git a/app/graphql/resolvers/user_starred_projects_resolver.rb b/app/graphql/resolvers/user_starred_projects_resolver.rb
index a8abe759f27..07c6611e41d 100644
--- a/app/graphql/resolvers/user_starred_projects_resolver.rb
+++ b/app/graphql/resolvers/user_starred_projects_resolver.rb
@@ -4,7 +4,7 @@ module Resolvers
class UserStarredProjectsResolver < BaseResolver
type Types::ProjectType.connection_type, null: true
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
required: false,
description: 'Search query.'
diff --git a/app/graphql/resolvers/users/group_count_resolver.rb b/app/graphql/resolvers/users/group_count_resolver.rb
index ebfe594d31d..592436ac546 100644
--- a/app/graphql/resolvers/users/group_count_resolver.rb
+++ b/app/graphql/resolvers/users/group_count_resolver.rb
@@ -3,7 +3,7 @@
module Resolvers
module Users
class GroupCountResolver < BaseResolver
- type GraphQL::INT_TYPE, null: true
+ type GraphQL::Types::Int, null: true
alias_method :user, :object
diff --git a/app/graphql/resolvers/users_resolver.rb b/app/graphql/resolvers/users_resolver.rb
index 95ced131504..c6de3dba41a 100644
--- a/app/graphql/resolvers/users_resolver.rb
+++ b/app/graphql/resolvers/users_resolver.rb
@@ -7,11 +7,11 @@ module Resolvers
type Types::UserType.connection_type, null: true
description 'Find Users'
- argument :ids, [GraphQL::ID_TYPE],
+ argument :ids, [GraphQL::Types::ID],
required: false,
description: 'List of user Global IDs.'
- argument :usernames, [GraphQL::STRING_TYPE], required: false,
+ argument :usernames, [GraphQL::Types::String], required: false,
description: 'List of usernames.'
argument :sort, Types::SortEnum,
@@ -19,11 +19,11 @@ module Resolvers
required: false,
default_value: :created_desc
- argument :search, GraphQL::STRING_TYPE,
+ argument :search, GraphQL::Types::String,
required: false,
description: "Query to search users by name, username, or primary email."
- argument :admins, GraphQL::BOOLEAN_TYPE,
+ argument :admins, GraphQL::Types::Boolean,
required: false,
default_value: false,
description: 'Return only admin users.'
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 1304bcb1c7e..58f933a7fe0 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -413,6 +413,12 @@ module ApplicationHelper
end
end
+ def gitlab_ui_form_for(record, *args, &block)
+ options = args.extract_options!
+
+ form_for(record, *(args << options.merge({ builder: ::Gitlab::FormBuilders::GitlabUiFormBuilder })), &block)
+ end
+
private
def appearance
diff --git a/app/services/packages/debian/generate_distribution_key_service.rb b/app/services/packages/debian/generate_distribution_key_service.rb
index 28c97c7681e..917965da58e 100644
--- a/app/services/packages/debian/generate_distribution_key_service.rb
+++ b/app/services/packages/debian/generate_distribution_key_service.rb
@@ -5,20 +5,42 @@ module Packages
class GenerateDistributionKeyService
include Gitlab::Utils::StrongMemoize
- def initialize(current_user:, params: {})
- @current_user = current_user
+ def initialize(params: {})
@params = params
end
def execute
- raise ArgumentError, 'Please provide a user' unless current_user.is_a?(User)
+ using_pinentry do |ctx|
+ # Generate key
+ ctx.generate_key generate_key_params
+
+ key = ctx.keys.first # rubocop:disable Gitlab/KeysFirstAndValuesFirst
+ fingerprint = key.fingerprint
+
+ # Export private key
+ data = GPGME::Data.new
+ ctx.export_keys fingerprint, data, GPGME::EXPORT_MODE_SECRET
+ data.seek 0
+ private_key = data.read
- generate_key
+ # Export public key
+ data = GPGME::Data.new
+ ctx.export_keys fingerprint, data
+ data.seek 0
+ public_key = data.read
+
+ {
+ private_key: private_key,
+ public_key: public_key,
+ passphrase: passphrase,
+ fingerprint: fingerprint
+ }
+ end
end
private
- attr_reader :current_user, :params
+ attr_reader :params
def passphrase
strong_memoize(:passphrase) do
@@ -72,35 +94,6 @@ module Packages
}.map { |k, v| "#{k}: #{v}\n" }.join +
'</GnupgKeyParms>'
end
-
- def generate_key
- using_pinentry do |ctx|
- # Generate key
- ctx.generate_key generate_key_params
-
- key = ctx.keys.first # rubocop:disable Gitlab/KeysFirstAndValuesFirst
- fingerprint = key.fingerprint
-
- # Export private key
- data = GPGME::Data.new
- ctx.export_keys fingerprint, data, GPGME::EXPORT_MODE_SECRET
- data.seek 0
- private_key = data.read
-
- # Export public key
- data = GPGME::Data.new
- ctx.export_keys fingerprint, data
- data.seek 0
- public_key = data.read
-
- {
- private_key: private_key,
- public_key: public_key,
- passphrase: passphrase,
- fingerprint: fingerprint
- }
- end
- end
end
end
end
diff --git a/app/services/packages/debian/sign_distribution_service.rb b/app/services/packages/debian/sign_distribution_service.rb
new file mode 100644
index 00000000000..643995dab67
--- /dev/null
+++ b/app/services/packages/debian/sign_distribution_service.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Packages
+ module Debian
+ class SignDistributionService
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(distribution, content, params: {})
+ @distribution = distribution
+ @content = content
+ @params = params
+ end
+
+ def execute
+ raise ArgumentError, 'distribution key is missing' unless @distribution.key
+
+ sig_mode = GPGME::GPGME_SIG_MODE_CLEAR
+
+ sig_mode = GPGME::GPGME_SIG_MODE_DETACH if @params[:detach]
+
+ Gitlab::Gpg.using_tmp_keychain do
+ GPGME::Ctx.new(
+ armor: true,
+ offline: true,
+ pinentry_mode: GPGME::PINENTRY_MODE_LOOPBACK,
+ password: @distribution.key.passphrase
+ ) do |ctx|
+ ctx.import(GPGME::Data.from_str(@distribution.key.public_key))
+ ctx.import(GPGME::Data.from_str(@distribution.key.private_key))
+ signature = GPGME::Data.new
+ ctx.sign(GPGME::Data.from_str(@content), signature, sig_mode)
+ signature.to_s
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index ec3daf6c494..7ae690b8fe0 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -118,6 +118,7 @@
- if Gitlab::CurrentSettings.version_check_enabled
.float-right
= version_status_badge
+ = link_to(sprite_icon('question'), "https://gitlab.com/gitlab-org/gitlab/-/blob/master/CHANGELOG.md", class: 'gl-ml-2', target: '_blank', rel: 'noopener noreferrer')
%p
= link_to _('GitLab'), general_admin_application_settings_path
%span.float-right
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 9b42e1b4967..ae809f01592 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -4,7 +4,6 @@
- page_title @group.name, _("Groups")
- current_user_is_group_owner = @group && @group.has_owner?(current_user)
-.js-remove-member-modal
%h3.page-title
= _('Group: %{group_name}') % { group_name: @group.full_name }
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 5c92cbf957e..1a87b21351c 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -5,7 +5,6 @@
- @content_class = "admin-projects"
- current_user_is_group_owner = @group && @group.has_owner?(current_user)
-.js-remove-member-modal
%h3.page-title
= _('Project: %{name}') % { name: @project.full_name }
= link_to edit_project_path(@project), class: "btn btn-default gl-button float-right" do
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index c5b8c5e25a3..2c0a519fbb8 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -2,7 +2,6 @@
- page_title _('Group members')
- groups_select_tag_data = group_select_data(@group).merge({ skip_groups: @skip_groups })
-.js-remove-member-modal
.row.gl-mt-3
.col-lg-12
.gl-display-flex.gl-flex-wrap
diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml
index d1f356ed665..9ef1e414872 100644
--- a/app/views/groups/settings/_permissions.html.haml
+++ b/app/views/groups/settings/_permissions.html.haml
@@ -1,4 +1,4 @@
-= form_for @group, html: { multipart: true, class: 'gl-show-field-errors js-general-permissions-form' }, authenticity_token: true do |f|
+= gitlab_ui_form_for @group, html: { multipart: true, class: 'gl-show-field-errors js-general-permissions-form' }, authenticity_token: true do |f|
%input{ type: 'hidden', name: 'update_section', value: 'js-permissions-settings' }
= form_errors(@group)
@@ -9,12 +9,10 @@
- if @group.root?
.form-group.gl-mb-3
- .gl-form-checkbox.custom-control.custom-checkbox
- = f.check_box :prevent_sharing_groups_outside_hierarchy, disabled: !can_change_prevent_sharing_groups_outside_hierarchy?(@group), class: 'custom-control-input'
- = f.label :prevent_sharing_groups_outside_hierarchy, class: 'custom-control-label' do
- %span
- = s_('GroupSettings|Prevent members from sending invitations to groups outside of %{group} and its subgroups.').html_safe % { group: link_to_group(@group) }
- %p.js-descr.help-text= prevent_sharing_groups_outside_hierarchy_help_text(@group)
+ = f.gitlab_ui_checkbox_component :prevent_sharing_groups_outside_hierarchy,
+ s_('GroupSettings|Prevent members from sending invitations to groups outside of %{group} and its subgroups.').html_safe % { group: link_to_group(@group) },
+ help_text: prevent_sharing_groups_outside_hierarchy_help_text(@group),
+ checkbox_options: { disabled: !can_change_prevent_sharing_groups_outside_hierarchy?(@group) }
.form-group.gl-mb-3
.gl-form-checkbox.custom-control.custom-checkbox
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 683d3a6ad1b..4fe1039b880 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -32,6 +32,7 @@
- if page_canonical_link
%link{ rel: 'canonical', href: page_canonical_link }
+ = preload_link_tag(path_to_stylesheet('application_utilities'))
= yield :prefetch_asset_tags
= favicon_link_tag favicon, id: 'favicon', data: { original_href: favicon }, type: 'image/png'
@@ -39,12 +40,10 @@
= render 'layouts/startup_css', { startup_filename: local_assigns.fetch(:startup_filename, nil) }
- if user_application_theme == 'gl-dark'
= stylesheet_link_tag_defer "application_dark"
- = yield :page_specific_styles
- = stylesheet_link_tag_defer "application_utilities_dark"
- else
= stylesheet_link_tag_defer "application"
- = yield :page_specific_styles
- = stylesheet_link_tag_defer "application_utilities"
+ = yield :page_specific_styles
+ = stylesheet_link_tag_defer 'application_utilities'
= stylesheet_link_tag "disable_animations", media: "all" if Rails.env.test? || Gitlab.config.gitlab['disable_animations']
= stylesheet_link_tag "test_environment", media: "all" if Rails.env.test?
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 187fe608a68..ce02c64623f 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -54,6 +54,8 @@
.settings-content
= render 'shared/badges/badge_settings'
+= render_if_exists 'compliance_management/compliance_framework/project_settings', expanded: expanded
+
= render_if_exists 'projects/settings/default_issue_template'
= render 'projects/service_desk_settings'
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
index d1b6db95392..18a5add9704 100644
--- a/app/views/projects/project_members/index.html.haml
+++ b/app/views/projects/project_members/index.html.haml
@@ -1,7 +1,6 @@
- add_page_specific_style 'page_bundles/members'
- page_title _("Members")
-.js-remove-member-modal
.row.gl-mt-3
.col-lg-12
- if can_invite_members_for_project?(@project) || can_invite_group_for_project?(@project)
diff --git a/app/views/projects/settings/_general.html.haml b/app/views/projects/settings/_general.html.haml
index 0891e3e0526..b185f45d129 100644
--- a/app/views/projects/settings/_general.html.haml
+++ b/app/views/projects/settings/_general.html.haml
@@ -19,8 +19,6 @@
= f.text_field :topics, value: @project.topic_list.join(', '), maxlength: 2000, class: "form-control gl-form-input"
%p.form-text.text-muted= _('Separate topics with commas.')
- = render_if_exists 'compliance_management/compliance_framework/project_settings', f: f
-
.row
.form-group.col-md-9
= f.label :description, _('Project description (optional)'), class: 'label-bold'
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 6aa80e6808d..dc93442d6cd 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -31,8 +31,6 @@
= render 'shared/issuable/form/metadata', issuable: issuable, form: form, project: project, presenter: presenter
-= render_if_exists 'shared/issuable/approvals', issuable: issuable, presenter: presenter, form: form
-
= render 'shared/issuable/form/merge_params', issuable: issuable, project: project
= render 'shared/issuable/form/contribution', issuable: issuable, form: form
diff --git a/app/views/shared/issuable/form/_metadata_issuable_reviewer.html.haml b/app/views/shared/issuable/form/_metadata_issuable_reviewer.html.haml
index a0df007f8ca..fad13c78e26 100644
--- a/app/views/shared/issuable/form/_metadata_issuable_reviewer.html.haml
+++ b/app/views/shared/issuable/form/_metadata_issuable_reviewer.html.haml
@@ -8,5 +8,4 @@
= hidden_field_tag "#{issuable.to_ability_name}[reviewer_ids][]", 0, id: nil, data: { meta: '' }
= dropdown_tag(users_dropdown_label(issuable.reviewers), options: reviewers_dropdown_options(issuable.to_ability_name, issuable.iid, issuable.target_branch))
- - if Feature.enabled?(:mr_collapsed_approval_rules, @project)
- = render_if_exists 'shared/issuable/approver_suggestion', issuable: issuable, presenter: presenter
+ = render_if_exists 'shared/issuable/approver_suggestion', issuable: issuable, presenter: presenter
diff --git a/config/feature_flags/development/mr_collapsed_approval_rules.yml b/config/feature_flags/development/mr_collapsed_approval_rules.yml
deleted file mode 100644
index 5fca48ddc3a..00000000000
--- a/config/feature_flags/development/mr_collapsed_approval_rules.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: mr_collapsed_approval_rules
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47475
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/284052
-milestone: '13.6'
-type: development
-group: group::source code
-default_enabled: false
diff --git a/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb b/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb
index 4bd04edb239..0b409cd2866 100644
--- a/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb
+++ b/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb
@@ -70,7 +70,7 @@ class MigrateK8sServiceIntegration < ActiveRecord::Migration[5.1]
private
def parsed_properties
- @parsed_properties ||= JSON.parse(self.properties)
+ @parsed_properties ||= JSON.parse(self.properties) # rubocop:disable Gitlab/Json
end
end
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index d63e927627a..7031f15d3a8 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -159,6 +159,27 @@ This machine's Geo node name matches a database record ... no
doc/administration/geo/replication/troubleshooting.md#can-geo-detect-the-current-node-correctly
```
+### Message: `WARNING: oldest xmin is far in the past` and `pg_wal` size growing
+
+If a replication slot is inactive,
+the `pg_wal` logs corresponding to the slot are reserved forever
+(or until the slot is active again). This causes continuous disk usage growth
+and the following messages appear repeatedly in the
+[PostgreSQL logs](../../logs.md#postgresql-logs):
+
+```plaintext
+WARNING: oldest xmin is far in the past
+HINT: Close open transactions soon to avoid wraparound problems.
+You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
+```
+
+To fix this, do the following:
+
+1. [Connect to the primary database](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database).
+1. Run `SELECT * FROM pg_replication_slots;`.
+1. Note the `slot_name` that reports `active` as `f` (false).
+1. Follow [all these steps to remove that Geo site](remove_geo_site.md).
+
## Fixing errors found when running the Geo check Rake task
When running this Rake task, you may see errors if the nodes are not properly configured:
@@ -325,7 +346,8 @@ log data to build up in `pg_xlog`. Removing the unused slots can reduce the amou
Slots where `active` is `f` are not active.
- When this slot should be active, because you have a **secondary** node configured using that slot,
- log in to that **secondary** node and check the PostgreSQL logs why the replication is not running.
+ log in to that **secondary** node and check the [PostgreSQL logs](../../logs.md#postgresql-logs)
+ to view why the replication is not running.
- If you are no longer using the slot (for example, you no longer have Geo enabled), you can remove it with in the
PostgreSQL console session:
@@ -521,7 +543,7 @@ to start again from scratch, there are a few steps that can help you:
gitlab-ctl stop geo-logcursor
```
- You can watch Sidekiq logs to know when Sidekiq jobs processing have finished:
+ You can watch the [Sidekiq logs](../../logs.md#sidekiq-logs) to know when Sidekiq jobs processing has finished:
```shell
gitlab-ctl tail sidekiq
diff --git a/doc/development/fe_guide/haml.md b/doc/development/fe_guide/haml.md
new file mode 100644
index 00000000000..eaf475a35b6
--- /dev/null
+++ b/doc/development/fe_guide/haml.md
@@ -0,0 +1,74 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+---
+
+# HAML
+
+[HAML](https://haml.info/) is the [Ruby on Rails](https://rubyonrails.org/) template language that GitLab uses.
+
+## GitLab UI form builder
+
+[GitLab UI](https://gitlab-org.gitlab.io/gitlab-ui/) is a Vue component library that conforms
+to the [Pajamas design system](https://design.gitlab.com/). Most of these components
+rely on JavaScript and therefore can only be used in Vue.
+
+However, some of the simpler components (checkboxes, radio buttons, form inputs) can be
+used in HAML by applying the correct CSS classes to the elements. A custom
+[Ruby on Rails form builder](https://gitlab.com/gitlab-org/gitlab/-/blob/7c108df101e86d8a27d69df2b5b1ff1fc24133c5/lib/gitlab/form_builders/gitlab_ui_form_builder.rb) exists to help use GitLab UI components in HAML.
+
+### Use the GitLab UI form builder
+
+To use the GitLab UI form builder:
+
+1. Change `form_for` to `gitlab_ui_form_for`.
+1. Change `f.check_box` to `f.gitlab_ui_checkbox_component`.
+1. Remove `f.label` and instead pass the label as the second argument in `f.gitlab_ui_checkbox_component`.
+
+For example:
+
+- Before:
+
+ ```haml
+ = gitlab_ui_form_for @group do |f|
+ .form-group.gl-mb-3
+ .gl-form-checkbox.custom-control.custom-checkbox
+ = f.check_box :prevent_sharing_groups_outside_hierarchy, disabled: !can_change_prevent_sharing_groups_outside_hierarchy?(@group), class: 'custom-control-input'
+ = f.label :prevent_sharing_groups_outside_hierarchy, class: 'custom-control-label' do
+ %span
+ = s_('GroupSettings|Prevent members from sending invitations to groups outside of %{group} and its subgroups.').html_safe % { group: link_to_group(@group) }
+ %p.help-text= prevent_sharing_groups_outside_hierarchy_help_text(@group)
+ ```
+
+- After:
+
+ ```haml
+ = gitlab_ui_form_for @group do |f|
+ .form-group.gl-mb-3
+ = f.gitlab_ui_checkbox_component :prevent_sharing_groups_outside_hierarchy,
+ s_('GroupSettings|Prevent members from sending invitations to groups outside of %{group} and its subgroups.').html_safe % { group: link_to_group(@group) },
+ help_text: prevent_sharing_groups_outside_hierarchy_help_text(@group),
+ checkbox_options: { disabled: !can_change_prevent_sharing_groups_outside_hierarchy?(@group) }
+ ```
+
+### Available components
+
+When using the GitLab UI form builder, the following components are available for use in HAML.
+
+NOTE:
+Currently only `gitlab_ui_checkbox_component` is available but more components are planned.
+
+#### gitlab_ui_checkbox_component
+
+[GitLab UI Docs](https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-form-form-checkbox--default)
+
+| Argument | Description | Type | Required (default value) |
+|---|---|---|---|
+| `method` | Attribute on the object passed to `gitlab_ui_form_for`. | `Symbol` | `true` |
+| `label` | Checkbox label. | `String` | `true` |
+| `help_text` | Help text displayed below the checkbox. | `String` | `false` (`nil`) |
+| `checkbox_options` | Options that are passed to [Rails `check_box` method](https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-check_box). | `Hash` | `false` (`{}`) |
+| `checked_value` | Value when checkbox is checked. | `String` | `false` (`'1'`) |
+| `unchecked_value` | Value when checkbox is unchecked. | `String` | `false` (`'0'`) |
+| `label_options` | Options that are passed to [Rails `label` method](https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-label). | `Hash` | `false` (`{}`) |
diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md
index 325310ad05c..517616e155c 100644
--- a/doc/development/fe_guide/index.md
+++ b/doc/development/fe_guide/index.md
@@ -81,6 +81,10 @@ Vue specific [design patterns and practices](vue.md).
How to use [GraphQL](graphql.md).
+## HAML
+
+How to use [HAML](haml.md).
+
## Icons and Illustrations
How we use SVG for our [Icons and Illustrations](icons.md).
diff --git a/doc/development/sidekiq_style_guide.md b/doc/development/sidekiq_style_guide.md
index a77c9908ef4..c1733a974e4 100644
--- a/doc/development/sidekiq_style_guide.md
+++ b/doc/development/sidekiq_style_guide.md
@@ -466,6 +466,24 @@ If we expect an increase of **less than 5%**, then no further action is needed.
Otherwise, please ping `@gitlab-org/scalability` on the merge request and ask
for a review.
+## Job size
+
+GitLab stores Sidekiq jobs and their arguments in Redis. To avoid
+excessive memory usage, we compress the arguments of Sidekiq jobs
+if their original size is bigger than 100KB.
+
+After compression, if their size still exceeds 5MB, it raises an
+[`ExceedLimitError`](https://gitlab.com/gitlab-org/gitlab/-/blob/f3dd89e5e510ea04b43ffdcb58587d8f78a8d77c/lib/gitlab/sidekiq_middleware/size_limiter/exceed_limit_error.rb#L8)
+error when scheduling the job.
+
+If this happens, rely on other means of making the data
+available in Sidekiq. There are possible workarounds such as:
+
+- Rebuild the data in Sidekiq with data loaded from the database or
+ elsewhere.
+- Store the data in [object storage](file_storage.md#object-storage)
+ before scheduling the job, and retrieve it inside the job.
+
## Job data consistency strategies
In GitLab 13.11 and earlier, Sidekiq workers would always send database queries to the primary
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 73360c3ee4b..b393be18910 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -1050,9 +1050,10 @@ is being discussed in [issue #17517](https://gitlab.com/gitlab-org/gitlab/-/issu
## Alternative backup strategies
-If your GitLab server contains a lot of Git repository data, you may find the
-GitLab backup script to be too slow. In this case you can consider using
-file system snapshots as part of your backup strategy.
+If your GitLab instance contains a lot of Git repository data, you may find the
+GitLab backup script to be too slow. If your GitLab instance has a lot of forked
+projects, the regular backup task also duplicates the Git data for all of them.
+In these cases, consider using file system snapshots as part of your backup strategy.
Example: Amazon EBS
@@ -1074,6 +1075,71 @@ VM snapshots of the entire GitLab server. It's not uncommon however for a VM
snapshot to require you to power down the server, which limits this solution's
practical use.
+### Back up repository data separately
+
+First, ensure you back up existing GitLab data while [skipping repositories](#excluding-specific-directories-from-the-backup):
+
+```shell
+# for Omnibus GitLab package installations
+sudo gitlab-backup create SKIP=repositories
+
+# for installations from source:
+sudo -u git -H bundle exec rake gitlab:backup:create SKIP=repositories RAILS_ENV=production
+```
+
+For manually backing up the Git repository data on disk, there are multiple possible strategies:
+
+- Use snapshots, such as the previous examples of Amazon EBS drive snapshots, or LVM snapshots + rsync.
+- Use [GitLab Geo](../administration/geo/index.md) and rely on the repository data on a Geo secondary site.
+- [Prevent writes and copy the Git repository data](#prevent-writes-and-copy-the-git-repository-data).
+- [Create an online backup by marking repositories as read-only (experimental)](#online-backup-through-marking-repositories-as-read-only-experimental).
+
+#### Prevent writes and copy the Git repository data
+
+Git repositories must be copied in a consistent way. They should not be copied during concurrent write
+operations, as this can lead to inconsistencies or corruption issues. For more details,
+[issue 270422](https://gitlab.com/gitlab-org/gitlab/-/issues/270422 "Provide documentation on preferred method of migrating Gitaly servers")
+has a longer discussion explaining the potential problems.
+
+To prevent writes to the Git repository data, there are two possible approaches:
+
+- Use [maintenance mode](../administration/maintenance_mode/index.md) to place GitLab in a read-only state.
+- Create explicit downtime by stopping all Gitaly services before backing up the repositories:
+
+ ```shell
+ sudo gitlab-ctl stop gitaly
+ # execute git data copy step
+ sudo gitlab-ctl start gitaly
+ ```
+
+You can copy Git repository data using any method, as long as writes are prevented on the data being copied
+(to prevent inconsistencies and corruption issues). In order of preference and safety, the recommended methods are:
+
+1. Use `rsync` with archive-mode, delete, and checksum options, for example:
+
+ ```shell
+ rsync -aR --delete --checksum source destination # be extra safe with the order as it will delete existing data if inverted
+ ```
+
+1. Use a [`tar` pipe to copy the entire repository's directory to another server or location](../administration/operations/moving_repositories.md#tar-pipe-to-another-server).
+
+1. Use `sftp`, `scp`, `cp`, or any other copying method.
+
+#### Online backup through marking repositories as read-only (experimental)
+
+One way of backing up repositories without requiring instance-wide downtime
+is to programmatically mark projects as read-only while copying the underlying data.
+
+There are a few possible downsides to this:
+
+- Repositories are read-only for a period of time that scales with the size of the repository.
+- Backups take a longer time to complete due to marking each project as read-only, potentially leading to inconsistencies. For example,
+ a possible date discrepancy between the last data available for the first project that gets backed up compared to
+ the last project that gets backed up.
+- Fork networks should be entirely read-only while the projects inside get backed up to prevent potential changes to the pool repository.
+
+There is an **experimental** script that attempts to automate this process in [Snippet 2149205](https://gitlab.com/-/snippets/2149205).
+
## Backup and restore for installations using PgBouncer
Do NOT backup or restore GitLab through a PgBouncer connection. These
diff --git a/doc/user/infrastructure/iac/index.md b/doc/user/infrastructure/iac/index.md
new file mode 100644
index 00000000000..53d8c9864a7
--- /dev/null
+++ b/doc/user/infrastructure/iac/index.md
@@ -0,0 +1,139 @@
+---
+stage: Configure
+group: Configure
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+---
+
+# Infrastructure as Code with Terraform and GitLab **(FREE)**
+
+## Motivation
+
+The Terraform integration features in GitLab enable your GitOps / Infrastructure-as-Code (IaC)
+workflows to tie into GitLab authentication and authorization. These features focus on
+lowering the barrier to entry for teams to adopt Terraform, collaborate effectively in
+GitLab, and support Terraform best practices.
+
+## Quick Start
+
+Use the following `.gitlab-ci.yml` to set up a basic Terraform project integration
+for GitLab versions 14.0 and later:
+
+```yaml
+include:
+ - template: Terraform.gitlab-ci.yml
+
+variables:
+ # If not using GitLab's HTTP backend, remove this line and specify TF_HTTP_* variables
+ TF_STATE_NAME: default
+ TF_CACHE_KEY: default
+ # If your terraform files are in a subdirectory, set TF_ROOT accordingly
+ # TF_ROOT: terraform/production
+```
+
+This template includes some opinionated decisions, which you can override:
+
+- Including the latest [GitLab Terraform Image](https://gitlab.com/gitlab-org/terraform-images).
+- Using the [GitLab managed Terraform State](#gitlab-managed-terraform-state) as
+ the Terraform state storage backend.
+- Creating [four pipeline stages](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform.gitlab-ci.yml):
+ `init`, `validate`, `build`, and `deploy`. These stages
+ [run the Terraform commands](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml)
+ `init`, `validate`, `plan`, `plan-json`, and `apply`. The `apply` command only runs on the default branch.
+
+This video from January 2021 walks you through all the GitLab Terraform integration features:
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=iGXjUrkkzDI">Terraform with GitLab</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube.com/embed/iGXjUrkkzDI" frameborder="0" allowfullscreen="true"> </iframe>
+</figure>
+
+## GitLab Managed Terraform state
+
+[Terraform remote backends](https://www.terraform.io/docs/language/settings/backends/index.html)
+enable you to store the state file in a remote, shared store. GitLab uses the
+[Terraform HTTP backend](https://www.terraform.io/docs/language/settings/backends/http.html)
+to securely store the state files in local storage (the default) or
+[the remote store of your choice](../../../administration/terraform_state.md).
+
+The GitLab managed Terraform state backend can store your Terraform state easily and
+securely. It spares you from setting up additional remote resources like
+Amazon S3 or Google Cloud Storage. Its features include:
+
+- Supporting encryption of the state file both in transit and at rest.
+- Locking and unlocking state.
+- Remote Terraform plan and apply execution.
+
+Read more on setting up and [using GitLab Managed Terraform states](../terraform_state.md)
+
+WARNING:
+Like any other job artifact, Terraform plan data is [viewable by anyone with Guest access](../../permissions.md) to the repository.
+Neither Terraform nor GitLab encrypts the plan file by default. If your Terraform plan
+includes sensitive data such as passwords, access tokens, or certificates, GitLab strongly
+recommends encrypting plan output or modifying the project visibility settings.
+
+## Terraform module registry
+
+GitLab can be used as a [Terraform module registry](../../packages/terraform_module_registry/index.md)
+to create and publish Terraform modules to a private registry specific to your
+top-level namespace.
+
+## Terraform integration in Merge Requests
+
+Collaborating around Infrastructure as Code (IaC) changes requires both code changes
+and expected infrastructure changes to be checked and approved. GitLab provides a
+solution to help collaboration around Terraform code changes and their expected
+effects using the Merge Request pages. This way users don't have to build custom
+tools or rely on 3rd party solutions to streamline their IaC workflows.
+
+Read more on setting up and [using the merge request integrations](../mr_integration.md).
+
+## The GitLab Terraform provider
+
+WARNING:
+The GitLab Terraform provider is released separately from GitLab.
+We are working on migrating the GitLab Terraform provider for GitLab.com.
+
+You can use the [GitLab Terraform provider](https://github.com/gitlabhq/terraform-provider-gitlab)
+to manage various aspects of GitLab using Terraform. The provider is an open source project,
+owned by GitLab, where everyone can contribute.
+
+The [documentation of the provider](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs)
+is available as part of the official Terraform provider documentations.
+
+## Create a new cluster through IaC
+
+Learn how to [create a new cluster on Google Kubernetes Engine (GKE)](../clusters/connect/new_gke_cluster.md).
+
+## Troubleshooting
+
+### `gitlab_group_share_group` resources not detected when subgroup state is refreshed
+
+The GitLab Terraform provider can fail to detect existing `gitlab_group_share_group` resources
+due to the issue ["User with permissions cannot retrieve `share_with_groups` from the API"](https://gitlab.com/gitlab-org/gitlab/-/issues/328428).
+This results in an error when running `terraform apply` because Terraform attempts to recreate an
+existing resource.
+
+For example, consider the following group/subgroup configuration:
+
+```plaintext
+parent-group
+├── subgroup-A
+└── subgroup-B
+```
+
+Where:
+
+- User `user-1` creates `parent-group`, `subgroup-A`, and `subgroup-B`.
+- `subgroup-A` is shared with `subgroup-B`.
+- User `terraform-user` is member of `parent-group` with inherited `owner` access to both subgroups.
+
+When the Terraform state is refreshed, the API query `GET /groups/:subgroup-A_id` issued by the provider does not return the
+details of `subgroup-B` in the `shared_with_groups` array. This leads to the error.
+
+To workaround this issue, make sure to apply one of the following conditions:
+
+1. The `terraform-user` creates all subgroup resources.
+1. Grant Maintainer or Owner role to the `terraform-user` user on `subgroup-B`.
+1. The `terraform-user` inherited access to `subgroup-B` and `subgroup-B` contains at least one project.
diff --git a/doc/user/infrastructure/index.md b/doc/user/infrastructure/index.md
index bdaae4b8225..7e334e93c4f 100644
--- a/doc/user/infrastructure/index.md
+++ b/doc/user/infrastructure/index.md
@@ -4,136 +4,11 @@ group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
-# Infrastructure as code with Terraform and GitLab **(FREE)**
+# Infrastructure management **(FREE)**
-## Motivation
+GitLab provides you with great solutions to help you manage your
+infrastrucure:
-The Terraform integration features in GitLab enable your GitOps / Infrastructure-as-Code (IaC)
-workflows to tie into GitLab authentication and authorization. These features focus on
-lowering the barrier to entry for teams to adopt Terraform, collaborate effectively in
-GitLab, and support Terraform best practices.
-
-## Quick Start
-
-Use the following `.gitlab-ci.yml` to set up a basic Terraform project integration
-for GitLab versions 14.0 and later:
-
-```yaml
-include:
- - template: Terraform.gitlab-ci.yml
-
-variables:
- # If not using GitLab's HTTP backend, remove this line and specify TF_HTTP_* variables
- TF_STATE_NAME: default
- TF_CACHE_KEY: default
- # If your terraform files are in a subdirectory, set TF_ROOT accordingly
- # TF_ROOT: terraform/production
-```
-
-This template includes some opinionated decisions, which you can override:
-
-- Including the latest [GitLab Terraform Image](https://gitlab.com/gitlab-org/terraform-images).
-- Using the [GitLab managed Terraform State](#gitlab-managed-terraform-state) as
- the Terraform state storage backend.
-- Creating [four pipeline stages](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform.gitlab-ci.yml):
- `init`, `validate`, `build`, and `deploy`. These stages
- [run the Terraform commands](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml)
- `init`, `validate`, `plan`, `plan-json`, and `apply`. The `apply` command only runs on the default branch.
-
-This video from January 2021 walks you through all the GitLab Terraform integration features:
-
-<div class="video-fallback">
- See the video: <a href="https://www.youtube.com/watch?v=iGXjUrkkzDI">Terraform with GitLab</a>.
-</div>
-<figure class="video-container">
- <iframe src="https://www.youtube.com/embed/iGXjUrkkzDI" frameborder="0" allowfullscreen="true"> </iframe>
-</figure>
-
-## GitLab Managed Terraform state
-
-[Terraform remote backends](https://www.terraform.io/docs/language/settings/backends/index.html)
-enable you to store the state file in a remote, shared store. GitLab uses the
-[Terraform HTTP backend](https://www.terraform.io/docs/language/settings/backends/http.html)
-to securely store the state files in local storage (the default) or
-[the remote store of your choice](../../administration/terraform_state.md).
-
-The GitLab managed Terraform state backend can store your Terraform state easily and
-securely. It spares you from setting up additional remote resources like
-Amazon S3 or Google Cloud Storage. Its features include:
-
-- Supporting encryption of the state file both in transit and at rest.
-- Locking and unlocking state.
-- Remote Terraform plan and apply execution.
-
-Read more on setting up and [using GitLab Managed Terraform states](terraform_state.md)
-
-WARNING:
-Like any other job artifact, Terraform plan data is [viewable by anyone with Guest access](../permissions.md) to the repository.
-Neither Terraform nor GitLab encrypts the plan file by default. If your Terraform plan
-includes sensitive data such as passwords, access tokens, or certificates, GitLab strongly
-recommends encrypting plan output or modifying the project visibility settings.
-
-## Terraform module registry
-
-GitLab can be used as a [Terraform module registry](../packages/terraform_module_registry/index.md)
-to create and publish Terraform modules to a private registry specific to your
-top-level namespace.
-
-## Terraform integration in Merge Requests
-
-Collaborating around Infrastructure as Code (IaC) changes requires both code changes
-and expected infrastructure changes to be checked and approved. GitLab provides a
-solution to help collaboration around Terraform code changes and their expected
-effects using the Merge Request pages. This way users don't have to build custom
-tools or rely on 3rd party solutions to streamline their IaC workflows.
-
-Read more on setting up and [using the merge request integrations](mr_integration.md).
-
-## The GitLab Terraform provider
-
-WARNING:
-The GitLab Terraform provider is released separately from GitLab.
-We are working on migrating the GitLab Terraform provider for GitLab.com.
-
-You can use the [GitLab Terraform provider](https://github.com/gitlabhq/terraform-provider-gitlab)
-to manage various aspects of GitLab using Terraform. The provider is an open source project,
-owned by GitLab, where everyone can contribute.
-
-The [documentation of the provider](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs)
-is available as part of the official Terraform provider documentations.
-
-## Create a new cluster through IaC
-
-Learn how to [create a new cluster on Google Kubernetes Engine (GKE)](clusters/connect/new_gke_cluster.md).
-
-## Troubleshooting
-
-### `gitlab_group_share_group` resources not detected when subgroup state is refreshed
-
-The GitLab Terraform provider can fail to detect existing `gitlab_group_share_group` resources
-due to the issue ["User with permissions cannot retrieve `share_with_groups` from the API"](https://gitlab.com/gitlab-org/gitlab/-/issues/328428).
-This results in an error when running `terraform apply` because Terraform attempts to recreate an
-existing resource.
-
-For example, consider the following group/subgroup configuration:
-
-```plaintext
-parent-group
-├── subgroup-A
-└── subgroup-B
-```
-
-Where:
-
-- User `user-1` creates `parent-group`, `subgroup-A`, and `subgroup-B`.
-- `subgroup-A` is shared with `subgroup-B`.
-- User `terraform-user` is member of `parent-group` with inherited `owner` access to both subgroups.
-
-When the Terraform state is refreshed, the API query `GET /groups/:subgroup-A_id` issued by the provider does not return the
-details of `subgroup-B` in the `shared_with_groups` array. This leads to the error.
-
-To workaround this issue, make sure to apply one of the following conditions:
-
-1. The `terraform-user` creates all subgroup resources.
-1. Grant Maintainer or Owner role to the `terraform-user` user on `subgroup-B`.
-1. The `terraform-user` inherited access to `subgroup-B` and `subgroup-B` contains at least one project.
+- [Infrastructure as Code and GitOps](iac/index.md)
+- [Kubernetes clusters](../project/clusters/index.md)
+- [Runbooks](../project/clusters/runbooks/index.md)
diff --git a/doc/user/infrastructure/mr_integration.md b/doc/user/infrastructure/mr_integration.md
index 66e00bab6ce..03b3d19cddb 100644
--- a/doc/user/infrastructure/mr_integration.md
+++ b/doc/user/infrastructure/mr_integration.md
@@ -18,7 +18,7 @@ modifies, or destroys.
## Setup
NOTE:
-GitLab ships with a [pre-built CI template](index.md#quick-start) that uses GitLab Managed Terraform state and integrates Terraform changes into merge requests. We recommend customizing the pre-built image and relying on the `gitlab-terraform` helper provided within for a quick setup.
+GitLab ships with a [pre-built CI template](iac/index.md#quick-start) that uses GitLab Managed Terraform state and integrates Terraform changes into merge requests. We recommend customizing the pre-built image and relying on the `gitlab-terraform` helper provided within for a quick setup.
To manually configure a GitLab Terraform Report artifact requires the following steps:
diff --git a/lib/gitlab/ci/yaml_processor/dag.rb b/lib/gitlab/ci/yaml_processor/dag.rb
index 0140218d9bc..8ab9573dd20 100644
--- a/lib/gitlab/ci/yaml_processor/dag.rb
+++ b/lib/gitlab/ci/yaml_processor/dag.rb
@@ -23,7 +23,7 @@ module Gitlab
new(nodes).tsort
rescue TSort::Cyclic
- raise ValidationError, 'The pipeline has circular dependencies.'
+ raise ValidationError, 'The pipeline has circular dependencies'
rescue MissingNodeError
end
diff --git a/lib/gitlab/form_builders/gitlab_ui_form_builder.rb b/lib/gitlab/form_builders/gitlab_ui_form_builder.rb
new file mode 100644
index 00000000000..a5290508e42
--- /dev/null
+++ b/lib/gitlab/form_builders/gitlab_ui_form_builder.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module FormBuilders
+ class GitlabUiFormBuilder < ActionView::Helpers::FormBuilder
+ def gitlab_ui_checkbox_component(
+ method,
+ label,
+ help_text: nil,
+ checkbox_options: {},
+ checked_value: '1',
+ unchecked_value: '0',
+ label_options: {}
+ )
+ @template.content_tag(
+ :div,
+ class: 'gl-form-checkbox custom-control custom-checkbox'
+ ) do
+ @template.check_box(
+ @object_name,
+ method,
+ format_options(checkbox_options, ['custom-control-input']),
+ checked_value,
+ unchecked_value
+ ) +
+ @template.label(
+ @object_name, method, format_options(label_options, ['custom-control-label'])
+ ) do
+ if help_text
+ @template.content_tag(
+ :span,
+ label
+ ) +
+ @template.content_tag(
+ :p,
+ help_text,
+ class: 'help-text'
+ )
+ else
+ label
+ end
+ end
+ end
+ end
+
+ private
+
+ def format_options(options, classes)
+ classes << options[:class]
+
+ objectify_options(options.merge({ class: classes.flatten.compact }))
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_export/json/legacy_reader.rb b/lib/gitlab/import_export/json/legacy_reader.rb
index 97b34088e3e..dc80c92f507 100644
--- a/lib/gitlab/import_export/json/legacy_reader.rb
+++ b/lib/gitlab/import_export/json/legacy_reader.rb
@@ -27,7 +27,7 @@ module Gitlab
end
def read_hash
- ActiveSupport::JSON.decode(IO.read(@path))
+ Gitlab::Json.parse(IO.read(@path))
rescue StandardError => e
Gitlab::ErrorTracking.log_exception(e)
raise Gitlab::ImportExport::Error, 'Incorrect JSON format'
diff --git a/lib/gitlab/import_export/json/ndjson_reader.rb b/lib/gitlab/import_export/json/ndjson_reader.rb
index 4899bd3b0ee..510da61d3ab 100644
--- a/lib/gitlab/import_export/json/ndjson_reader.rb
+++ b/lib/gitlab/import_export/json/ndjson_reader.rb
@@ -47,8 +47,8 @@ module Gitlab
private
def json_decode(string)
- ActiveSupport::JSON.decode(string)
- rescue ActiveSupport::JSON.parse_error => e
+ Gitlab::Json.parse(string)
+ rescue JSON::ParserError => e
Gitlab::ErrorTracking.log_exception(e)
raise Gitlab::ImportExport::Error, 'Incorrect JSON format'
end
diff --git a/lib/gitlab/import_export/lfs_restorer.rb b/lib/gitlab/import_export/lfs_restorer.rb
index d73ae1410a3..9931b09e9ca 100644
--- a/lib/gitlab/import_export/lfs_restorer.rb
+++ b/lib/gitlab/import_export/lfs_restorer.rb
@@ -72,7 +72,7 @@ module Gitlab
@lfs_json ||=
begin
json = IO.read(lfs_json_path)
- ActiveSupport::JSON.decode(json)
+ Gitlab::Json.parse(json)
rescue StandardError
raise Gitlab::ImportExport::Error, 'Incorrect JSON format'
end
diff --git a/lib/gitlab/json_cache.rb b/lib/gitlab/json_cache.rb
index 4314c131ada..41c18f82a4b 100644
--- a/lib/gitlab/json_cache.rb
+++ b/lib/gitlab/json_cache.rb
@@ -58,7 +58,7 @@ module Gitlab
private
def parse_value(raw, klass)
- value = ActiveSupport::JSON.decode(raw.to_s)
+ value = Gitlab::Json.parse(raw.to_s)
case value
when Hash then parse_entry(value, klass)
@@ -66,7 +66,7 @@ module Gitlab
else
value
end
- rescue ActiveSupport::JSON.parse_error
+ rescue JSON::ParserError
nil
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e70f1465b97..a7275a62559 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -16496,9 +16496,6 @@ msgstr ""
msgid "Image details"
msgstr ""
-msgid "ImageAltText|Sparkling golden tanuki logo"
-msgstr ""
-
msgid "ImageDiffViewer|2-up"
msgstr ""
@@ -28270,6 +28267,9 @@ msgstr ""
msgid "Runners|Something went wrong while fetching the tags suggestions"
msgstr ""
+msgid "Runners|Stop the runner from accepting new jobs."
+msgstr ""
+
msgid "Runners|Tags"
msgstr ""
@@ -28291,6 +28291,15 @@ msgstr ""
msgid "Runners|Use Group runners when you want all projects in a group to have access to a set of runners."
msgstr ""
+msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
+msgstr ""
+
+msgid "Runners|Use the runner for the currently assigned projects only."
+msgstr ""
+
+msgid "Runners|Use the runner on pipelines for protected branches only."
+msgstr ""
+
msgid "Runners|Value"
msgstr ""
@@ -29342,6 +29351,9 @@ msgstr ""
msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
msgstr ""
+msgid "Select a framework that applies to this project. %{linkStart}How are these added?%{linkEnd}"
+msgstr ""
+
msgid "Select a group to invite"
msgstr ""
@@ -34126,9 +34138,6 @@ msgstr ""
msgid "Tip: Hover over a job to see the jobs it depends on to run."
msgstr ""
-msgid "Tip: add a"
-msgstr ""
-
msgid "Tip: add a %{linkStart}CODEOWNERS%{linkEnd} to automatically add approvers based on file paths and file types."
msgstr ""
@@ -38955,9 +38964,6 @@ msgid_plural "merge requests"
msgstr[0] ""
msgstr[1] ""
-msgid "merge request approvals"
-msgstr ""
-
msgid "merged %{timeAgo}"
msgstr ""
@@ -39655,9 +39661,6 @@ msgstr ""
msgid "time summary"
msgstr ""
-msgid "to automatically add approvers based on file paths and file types."
-msgstr ""
-
msgid "to help your contributors communicate effectively!"
msgstr ""
diff --git a/qa/qa/page/group/members.rb b/qa/qa/page/group/members.rb
index b526a4488b2..ccc901932f4 100644
--- a/qa/qa/page/group/members.rb
+++ b/qa/qa/page/group/members.rb
@@ -7,7 +7,7 @@ module QA
include Page::Component::InviteMembersModal
include Page::Component::UsersSelect
- view 'app/assets/javascripts/vue_shared/components/remove_member_modal.vue' do
+ view 'app/assets/javascripts/members/components/modals/remove_member_modal.vue' do
element :remove_member_modal_content
end
diff --git a/rubocop/cop/gitlab/json.rb b/rubocop/cop/gitlab/json.rb
index 7cc719aca09..d2ba0012ca0 100644
--- a/rubocop/cop/gitlab/json.rb
+++ b/rubocop/cop/gitlab/json.rb
@@ -10,7 +10,7 @@ module RuboCop
EOL
def_node_matcher :json_node?, <<~PATTERN
- (send (const nil? :JSON)...)
+ (send (const {nil? | (const nil? :ActiveSupport)} :JSON)...)
PATTERN
def on_send(node)
diff --git a/spec/factories/packages/debian/distribution_key.rb b/spec/factories/packages/debian/distribution_key.rb
index 6bd457c50d0..94e041eb4a9 100644
--- a/spec/factories/packages/debian/distribution_key.rb
+++ b/spec/factories/packages/debian/distribution_key.rb
@@ -4,9 +4,9 @@ FactoryBot.define do
factory :debian_project_distribution_key, class: 'Packages::Debian::ProjectDistributionKey' do
distribution { association(:debian_project_distribution) }
- private_key { '-----BEGIN PGP PRIVATE KEY BLOCK-----' }
+ private_key { File.read(Rails.root.join('spec/fixtures/', 'private_key.asc')) }
passphrase { '12345' }
- public_key { '-----BEGIN PGP PUBLIC KEY BLOCK-----' }
+ public_key { File.read(Rails.root.join('spec/fixtures/', 'public_key.asc')) }
fingerprint { '12345' }
factory :debian_group_distribution_key, class: 'Packages::Debian::GroupDistributionKey' do
diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb
index 7f8ded4fa43..ccf3ccc6a96 100644
--- a/spec/features/projects/import_export/export_file_spec.rb
+++ b/spec/features/projects/import_export/export_file_spec.rb
@@ -82,8 +82,7 @@ RSpec.describe 'Import/Export - project export integration test', :js do
relations << Gitlab::Json.parse(IO.read(project_json_path))
Dir.glob(File.join(tmpdir, 'tree/project', '*.ndjson')) do |rb_filename|
File.foreach(rb_filename) do |line|
- json = ActiveSupport::JSON.decode(line)
- relations << json
+ relations << Gitlab::Json.parse(line)
end
end
diff --git a/spec/fixtures/private_key.asc b/spec/fixtures/private_key.asc
new file mode 100644
index 00000000000..d9252bafd62
--- /dev/null
+++ b/spec/fixtures/private_key.asc
@@ -0,0 +1,17 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Comment: Alice's OpenPGP Transferable Secret Key
+Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html
+
+lFgEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U
+b7O1u10AAP9XBeW6lzGOLx7zHH9AsUDUTb2pggYGMzd0P3ulJ2AfvQ4RtCZBbGlj
+ZSBMb3ZlbGFjZSA8YWxpY2VAb3BlbnBncC5leGFtcGxlPoiQBBMWCAA4AhsDBQsJ
+CAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE64W7X6M6deFelE5j8jFVDE9H444FAl2l
+nzoACgkQ8jFVDE9H447pKwD6A5xwUqIDprBzrHfahrImaYEZzncqb25vkLV2arYf
+a78A/R3AwtLQvjxwLDuzk4dUtUwvUYibL2sAHwj2kGaHnfICnF0EXEcE6RIKKwYB
+BAGXVQEFAQEHQEL/BiGtq0k84Km1wqQw2DIikVYrQrMttN8d7BPfnr4iAwEIBwAA
+/3/xFPG6U17rhTuq+07gmEvaFYKfxRB6sgAYiW6TMTpQEK6IeAQYFggAIBYhBOuF
+u1+jOnXhXpROY/IxVQxPR+OOBQJcRwTpAhsMAAoJEPIxVQxPR+OOWdABAMUdSzpM
+hzGs1O0RkWNQWbUzQ8nUOeD9wNbjE3zR+yfRAQDbYqvtWQKN4AQLTxVJN5X5AWyb
+Pnn+We1aTBhaGa86AQ==
+=n8OM
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/spec/fixtures/public_key.asc b/spec/fixtures/public_key.asc
new file mode 100644
index 00000000000..68fdb39324e
--- /dev/null
+++ b/spec/fixtures/public_key.asc
@@ -0,0 +1,15 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: Alice's OpenPGP certificate
+Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html
+
+mDMEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U
+b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE
+ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy
+MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO
+dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4
+OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s
+E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb
+DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn
+0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=
+=iIGO
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/spec/frontend/diffs/components/settings_dropdown_spec.js b/spec/frontend/diffs/components/settings_dropdown_spec.js
index 43b9c5871a6..2dd35519464 100644
--- a/spec/frontend/diffs/components/settings_dropdown_spec.js
+++ b/spec/frontend/diffs/components/settings_dropdown_spec.js
@@ -48,13 +48,17 @@ describe('Diff settings dropdown component', () => {
it('list view button dispatches setRenderTreeList with false', () => {
wrapper.find('.js-list-view').trigger('click');
- expect(store.dispatch).toHaveBeenCalledWith('diffs/setRenderTreeList', false);
+ expect(store.dispatch).toHaveBeenCalledWith('diffs/setRenderTreeList', {
+ renderTreeList: false,
+ });
});
it('tree view button dispatches setRenderTreeList with true', () => {
wrapper.find('.js-tree-view').trigger('click');
- expect(store.dispatch).toHaveBeenCalledWith('diffs/setRenderTreeList', true);
+ expect(store.dispatch).toHaveBeenCalledWith('diffs/setRenderTreeList', {
+ renderTreeList: true,
+ });
});
it('sets list button as selected when renderTreeList is false', () => {
diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js
index c2e5d07bcfd..4681b4f9d45 100644
--- a/spec/frontend/diffs/store/actions_spec.js
+++ b/spec/frontend/diffs/store/actions_spec.js
@@ -1000,7 +1000,7 @@ describe('DiffsStoreActions', () => {
it('commits SET_RENDER_TREE_LIST', (done) => {
testAction(
setRenderTreeList,
- true,
+ { renderTreeList: true },
{},
[{ type: types.SET_RENDER_TREE_LIST, payload: true }],
[],
@@ -1009,7 +1009,7 @@ describe('DiffsStoreActions', () => {
});
it('sets localStorage', () => {
- setRenderTreeList({ commit() {} }, true);
+ setRenderTreeList({ commit() {} }, { renderTreeList: true });
expect(localStorage.setItem).toHaveBeenCalledWith('mr_diff_tree_list', true);
});
diff --git a/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js b/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js
index e7a99a96da6..79252456f67 100644
--- a/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js
+++ b/spec/frontend/members/components/action_buttons/invite_action_buttons_spec.js
@@ -37,7 +37,7 @@ describe('InviteActionButtons', () => {
});
it('sets props correctly', () => {
- expect(findRemoveMemberButton().props()).toEqual({
+ expect(findRemoveMemberButton().props()).toMatchObject({
memberId: member.id,
memberType: null,
message: `Are you sure you want to revoke the invitation for ${member.invite.email} to join "${member.source.fullName}"`,
diff --git a/spec/frontend/members/components/action_buttons/remove_member_button_spec.js b/spec/frontend/members/components/action_buttons/remove_member_button_spec.js
index 4ff12f7fa97..d8453d453e7 100644
--- a/spec/frontend/members/components/action_buttons/remove_member_button_spec.js
+++ b/spec/frontend/members/components/action_buttons/remove_member_button_spec.js
@@ -1,6 +1,8 @@
+import { GlButton } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { modalData } from 'jest/members/mock_data';
import RemoveMemberButton from '~/members/components/action_buttons/remove_member_button.vue';
import { MEMBER_TYPES } from '~/members/constants';
@@ -10,6 +12,10 @@ localVue.use(Vuex);
describe('RemoveMemberButton', () => {
let wrapper;
+ const actions = {
+ showRemoveMemberModal: jest.fn(),
+ };
+
const createStore = (state = {}) => {
return new Vuex.Store({
modules: {
@@ -19,6 +25,7 @@ describe('RemoveMemberButton', () => {
memberPath: '/groups/foo-bar/-/group_members/:id',
...state,
},
+ actions,
},
},
});
@@ -47,20 +54,16 @@ describe('RemoveMemberButton', () => {
});
};
+ beforeEach(() => {
+ createComponent();
+ });
+
afterEach(() => {
wrapper.destroy();
});
it('sets attributes on button', () => {
- createComponent();
-
expect(wrapper.attributes()).toMatchObject({
- 'data-member-path': '/groups/foo-bar/-/group_members/1',
- 'data-member-type': 'GroupMember',
- 'data-message': 'Are you sure you want to remove John Smith?',
- 'data-is-access-request': 'true',
- 'data-is-invite': 'true',
- 'data-oncall-schedules': '{"name":"user","schedules":[]}',
'aria-label': 'Remove member',
title: 'Remove member',
icon: 'remove',
@@ -68,14 +71,12 @@ describe('RemoveMemberButton', () => {
});
it('displays `title` prop as a tooltip', () => {
- createComponent();
-
expect(getBinding(wrapper.element, 'gl-tooltip')).not.toBeUndefined();
});
- it('has CSS class used by `remove_member_modal.vue`', () => {
- createComponent();
+ it('calls Vuex action to show `remove member` modal when clicked', () => {
+ wrapper.findComponent(GlButton).vm.$emit('click');
- expect(wrapper.classes()).toContain('js-remove-member-button');
+ expect(actions.showRemoveMemberModal).toHaveBeenCalledWith(expect.any(Object), modalData);
});
});
diff --git a/spec/frontend/vue_shared/components/remove_member_modal_spec.js b/spec/frontend/members/components/modals/remove_member_modal_spec.js
index ce9de28d53c..1dc41582c12 100644
--- a/spec/frontend/vue_shared/components/remove_member_modal_spec.js
+++ b/spec/frontend/members/components/modals/remove_member_modal_spec.js
@@ -1,37 +1,61 @@
import { GlModal } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import Vuex from 'vuex';
+import RemoveMemberModal from '~/members/components/modals/remove_member_modal.vue';
+import { MEMBER_TYPES } from '~/members/constants';
import OncallSchedulesList from '~/vue_shared/components/oncall_schedules_list.vue';
-import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue';
-const mockSchedules = JSON.stringify({
- schedules: [
- {
- id: 1,
- name: 'Schedule 1',
- },
- ],
- name: 'User1',
-});
+Vue.use(Vuex);
describe('RemoveMemberModal', () => {
const memberPath = '/gitlab-org/gitlab-test/-/project_members/90';
+ const mockSchedules = {
+ name: 'User1',
+ schedules: [{ id: 1, name: 'Schedule 1' }],
+ };
let wrapper;
+ const actions = {
+ hideRemoveMemberModal: jest.fn(),
+ };
+
+ const createStore = (removeMemberModalData) =>
+ new Vuex.Store({
+ modules: {
+ [MEMBER_TYPES.user]: {
+ namespaced: true,
+ state: {
+ removeMemberModalData,
+ },
+ actions,
+ },
+ },
+ });
+
+ const createComponent = (state) => {
+ wrapper = shallowMount(RemoveMemberModal, {
+ store: createStore(state),
+ provide: {
+ namespace: MEMBER_TYPES.user,
+ },
+ });
+ };
+
const findForm = () => wrapper.find({ ref: 'form' });
const findGlModal = () => wrapper.findComponent(GlModal);
const findOnCallSchedulesList = () => wrapper.findComponent(OncallSchedulesList);
afterEach(() => {
wrapper.destroy();
- wrapper = null;
});
describe.each`
- state | memberType | isAccessRequest | isInvite | actionText | removeSubMembershipsCheckboxExpected | unassignIssuablesCheckboxExpected | message | onCallSchedules
- ${'removing a group member'} | ${'GroupMember'} | ${false} | ${'false'} | ${'Remove member'} | ${true} | ${true} | ${'Are you sure you want to remove Jane Doe from the Gitlab Org / Gitlab Test project?'} | ${`{}`}
- ${'removing a project member'} | ${'ProjectMember'} | ${false} | ${'false'} | ${'Remove member'} | ${false} | ${true} | ${'Are you sure you want to remove Jane Doe from the Gitlab Org / Gitlab Test project?'} | ${mockSchedules}
- ${'denying an access request'} | ${'ProjectMember'} | ${true} | ${'false'} | ${'Deny access request'} | ${false} | ${false} | ${"Are you sure you want to deny Jane Doe's request to join the Gitlab Org / Gitlab Test project?"} | ${`{}`}
- ${'revoking invite'} | ${'ProjectMember'} | ${false} | ${'true'} | ${'Revoke invite'} | ${false} | ${false} | ${'Are you sure you want to revoke the invitation for foo@bar.com to join the Gitlab Org / Gitlab Test project?'} | ${mockSchedules}
+ state | memberType | isAccessRequest | isInvite | actionText | removeSubMembershipsCheckboxExpected | unassignIssuablesCheckboxExpected | message | onCallSchedules
+ ${'removing a group member'} | ${'GroupMember'} | ${false} | ${false} | ${'Remove member'} | ${true} | ${true} | ${'Are you sure you want to remove Jane Doe from the Gitlab Org / Gitlab Test project?'} | ${{}}
+ ${'removing a project member'} | ${'ProjectMember'} | ${false} | ${false} | ${'Remove member'} | ${false} | ${true} | ${'Are you sure you want to remove Jane Doe from the Gitlab Org / Gitlab Test project?'} | ${mockSchedules}
+ ${'denying an access request'} | ${'ProjectMember'} | ${true} | ${false} | ${'Deny access request'} | ${false} | ${false} | ${"Are you sure you want to deny Jane Doe's request to join the Gitlab Org / Gitlab Test project?"} | ${{}}
+ ${'revoking invite'} | ${'ProjectMember'} | ${false} | ${true} | ${'Revoke invite'} | ${false} | ${false} | ${'Are you sure you want to revoke the invitation for foo@bar.com to join the Gitlab Org / Gitlab Test project?'} | ${mockSchedules}
`(
'when $state',
({
@@ -45,24 +69,17 @@ describe('RemoveMemberModal', () => {
onCallSchedules,
}) => {
beforeEach(() => {
- wrapper = shallowMount(RemoveMemberModal, {
- data() {
- return {
- modalData: {
- isAccessRequest,
- isInvite,
- message,
- memberPath,
- memberType,
- onCallSchedules,
- },
- };
- },
+ createComponent({
+ isAccessRequest,
+ isInvite,
+ message,
+ memberPath,
+ memberType,
+ onCallSchedules,
});
});
- const parsedSchedules = JSON.parse(onCallSchedules);
- const isPartOfOncallSchedules = Boolean(isAccessRequest && parsedSchedules.schedules?.length);
+ const isPartOfOncallSchedules = Boolean(isAccessRequest && onCallSchedules.schedules?.length);
it(`has the title ${actionText}`, () => {
expect(findGlModal().attributes('title')).toBe(actionText);
@@ -73,7 +90,7 @@ describe('RemoveMemberModal', () => {
});
it('displays a message to the user', () => {
- expect(wrapper.find('[data-testid=modal-message]').text()).toBe(message);
+ expect(wrapper.find('p').text()).toBe(message);
});
it(`shows ${
@@ -105,6 +122,12 @@ describe('RemoveMemberModal', () => {
spy.mockRestore();
});
+
+ it('calls Vuex action to hide the modal when `GlModal` emits `hide` event', () => {
+ findGlModal().vm.$emit('hide');
+
+ expect(actions.hideRemoveMemberModal).toHaveBeenCalled();
+ });
},
);
});
diff --git a/spec/frontend/members/components/table/members_table_spec.js b/spec/frontend/members/components/table/members_table_spec.js
index 3a17d78bd17..6e7d9bc6b6e 100644
--- a/spec/frontend/members/components/table/members_table_spec.js
+++ b/spec/frontend/members/components/table/members_table_spec.js
@@ -72,6 +72,7 @@ describe('MembersTable', () => {
'member-action-buttons',
'role-dropdown',
'remove-group-link-modal',
+ 'remove-member-modal',
'expiration-datepicker',
],
});
diff --git a/spec/frontend/members/mock_data.js b/spec/frontend/members/mock_data.js
index 4275db5fa9f..eb9f905fea2 100644
--- a/spec/frontend/members/mock_data.js
+++ b/spec/frontend/members/mock_data.js
@@ -57,6 +57,15 @@ export const group = {
validRoles: { Guest: 10, Reporter: 20, Developer: 30, Maintainer: 40, Owner: 50 },
};
+export const modalData = {
+ isAccessRequest: true,
+ isInvite: true,
+ memberPath: '/groups/foo-bar/-/group_members/1',
+ memberType: 'GroupMember',
+ message: 'Are you sure you want to remove John Smith?',
+ oncallSchedules: { name: 'user', schedules: [] },
+};
+
const { user, ...memberNoUser } = member;
export const invite = {
...memberNoUser,
diff --git a/spec/frontend/members/store/actions_spec.js b/spec/frontend/members/store/actions_spec.js
index d913c5c56df..d37e6871387 100644
--- a/spec/frontend/members/store/actions_spec.js
+++ b/spec/frontend/members/store/actions_spec.js
@@ -3,12 +3,14 @@ import MockAdapter from 'axios-mock-adapter';
import { noop } from 'lodash';
import { useFakeDate } from 'helpers/fake_date';
import testAction from 'helpers/vuex_action_helper';
-import { members, group } from 'jest/members/mock_data';
+import { members, group, modalData } from 'jest/members/mock_data';
import httpStatusCodes from '~/lib/utils/http_status';
import {
updateMemberRole,
showRemoveGroupLinkModal,
hideRemoveGroupLinkModal,
+ showRemoveMemberModal,
+ hideRemoveMemberModal,
updateMemberExpiration,
} from '~/members/store/actions';
import * as types from '~/members/store/mutation_types';
@@ -153,4 +155,32 @@ describe('Vuex members actions', () => {
});
});
});
+
+ describe('Remove member modal', () => {
+ const state = {
+ removeMemberModalVisible: false,
+ removeMemberModalData: {},
+ };
+
+ describe('showRemoveMemberModal', () => {
+ it(`commits ${types.SHOW_REMOVE_MEMBER_MODAL} mutation`, () => {
+ testAction(showRemoveMemberModal, modalData, state, [
+ {
+ type: types.SHOW_REMOVE_MEMBER_MODAL,
+ payload: modalData,
+ },
+ ]);
+ });
+ });
+
+ describe('hideRemoveMemberModal', () => {
+ it(`commits ${types.HIDE_REMOVE_MEMBER_MODAL} mutation`, () => {
+ testAction(hideRemoveMemberModal, undefined, state, [
+ {
+ type: types.HIDE_REMOVE_MEMBER_MODAL,
+ },
+ ]);
+ });
+ });
+ });
});
diff --git a/spec/frontend/members/store/mutations_spec.js b/spec/frontend/members/store/mutations_spec.js
index 7ad7034eb6d..72423c6b4d4 100644
--- a/spec/frontend/members/store/mutations_spec.js
+++ b/spec/frontend/members/store/mutations_spec.js
@@ -1,4 +1,4 @@
-import { members, group } from 'jest/members/mock_data';
+import { members, group, modalData } from 'jest/members/mock_data';
import * as types from '~/members/store/mutation_types';
import mutations from '~/members/store/mutations';
@@ -154,4 +154,32 @@ describe('Vuex members mutations', () => {
expect(state.removeGroupLinkModalVisible).toBe(false);
});
});
+
+ describe(types.SHOW_REMOVE_MEMBER_MODAL, () => {
+ it('sets `removeMemberModalVisible` and `removeMemberModalData`', () => {
+ const state = {
+ removeMemberModalVisible: false,
+ removeMemberModalData: {},
+ };
+
+ mutations[types.SHOW_REMOVE_MEMBER_MODAL](state, modalData);
+
+ expect(state).toEqual({
+ removeMemberModalVisible: true,
+ removeMemberModalData: modalData,
+ });
+ });
+ });
+
+ describe(types.HIDE_REMOVE_MEMBER_MODAL, () => {
+ it('sets `removeMemberModalVisible` to `false`', () => {
+ const state = {
+ removeMemberModalVisible: true,
+ };
+
+ mutations[types.HIDE_REMOVE_MEMBER_MODAL](state);
+
+ expect(state.removeMemberModalVisible).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/security_configuration/components/feature_card_spec.js b/spec/frontend/security_configuration/components/feature_card_spec.js
index 3658dbb5ef2..fdb1d2f86e3 100644
--- a/spec/frontend/security_configuration/components/feature_card_spec.js
+++ b/spec/frontend/security_configuration/components/feature_card_spec.js
@@ -127,25 +127,35 @@ describe('FeatureCard component', () => {
describe('actions', () => {
describe.each`
- context | type | available | configured | configurationPath | canEnableByMergeRequest | action
- ${'unavailable'} | ${REPORT_TYPE_SAST} | ${false} | ${false} | ${null} | ${false} | ${null}
- ${'available'} | ${REPORT_TYPE_SAST} | ${true} | ${false} | ${null} | ${false} | ${'guide'}
- ${'configured'} | ${REPORT_TYPE_SAST} | ${true} | ${true} | ${null} | ${false} | ${'guide'}
- ${'available, can enable by MR'} | ${REPORT_TYPE_SAST} | ${true} | ${false} | ${null} | ${true} | ${'create-mr'}
- ${'available, can enable by MR, unknown type'} | ${'foo'} | ${true} | ${false} | ${null} | ${true} | ${'guide'}
- ${'configured, can enable by MR'} | ${REPORT_TYPE_SAST} | ${true} | ${true} | ${null} | ${true} | ${'guide'}
- ${'available with config path'} | ${REPORT_TYPE_SAST} | ${true} | ${false} | ${'foo'} | ${false} | ${'enable'}
- ${'available with config path, can enable by MR'} | ${REPORT_TYPE_SAST} | ${true} | ${false} | ${'foo'} | ${true} | ${'enable'}
- ${'configured with config path'} | ${REPORT_TYPE_SAST} | ${true} | ${true} | ${'foo'} | ${false} | ${'configure'}
- ${'configured with config path, can enable by MR'} | ${REPORT_TYPE_SAST} | ${true} | ${true} | ${'foo'} | ${true} | ${'configure'}
+ context | type | available | configured | configurationHelpPath | configurationPath | canEnableByMergeRequest | action
+ ${'unavailable'} | ${REPORT_TYPE_SAST} | ${false} | ${false} | ${'/help'} | ${null} | ${false} | ${null}
+ ${'available, no configurationHelpPath'} | ${REPORT_TYPE_SAST} | ${true} | ${false} | ${null} | ${null} | ${false} | ${null}
+ ${'available'} | ${REPORT_TYPE_SAST} | ${true} | ${false} | ${'/help'} | ${null} | ${false} | ${'guide'}
+ ${'configured'} | ${REPORT_TYPE_SAST} | ${true} | ${true} | ${'/help'} | ${null} | ${false} | ${'guide'}
+ ${'available, can enable by MR'} | ${REPORT_TYPE_SAST} | ${true} | ${false} | ${'/help'} | ${null} | ${true} | ${'create-mr'}
+ ${'available, can enable by MR, unknown type'} | ${'foo'} | ${true} | ${false} | ${'/help'} | ${null} | ${true} | ${'guide'}
+ ${'configured, can enable by MR'} | ${REPORT_TYPE_SAST} | ${true} | ${true} | ${'/help'} | ${null} | ${true} | ${'guide'}
+ ${'available with config path'} | ${REPORT_TYPE_SAST} | ${true} | ${false} | ${'/help'} | ${'foo'} | ${false} | ${'enable'}
+ ${'available with config path, can enable by MR'} | ${REPORT_TYPE_SAST} | ${true} | ${false} | ${'/help'} | ${'foo'} | ${true} | ${'enable'}
+ ${'configured with config path'} | ${REPORT_TYPE_SAST} | ${true} | ${true} | ${'/help'} | ${'foo'} | ${false} | ${'configure'}
+ ${'configured with config path, can enable by MR'} | ${REPORT_TYPE_SAST} | ${true} | ${true} | ${'/help'} | ${'foo'} | ${true} | ${'configure'}
`(
'given $context feature',
- ({ type, available, configured, configurationPath, canEnableByMergeRequest, action }) => {
+ ({
+ type,
+ available,
+ configured,
+ configurationHelpPath,
+ configurationPath,
+ canEnableByMergeRequest,
+ action,
+ }) => {
beforeEach(() => {
feature = makeFeature({
type,
available,
configured,
+ configurationHelpPath,
configurationPath,
canEnableByMergeRequest,
});
diff --git a/spec/graphql/resolvers/base_resolver_spec.rb b/spec/graphql/resolvers/base_resolver_spec.rb
index 8d2ae238bfe..d77a0b6242e 100644
--- a/spec/graphql/resolvers/base_resolver_spec.rb
+++ b/spec/graphql/resolvers/base_resolver_spec.rb
@@ -7,8 +7,8 @@ RSpec.describe Resolvers::BaseResolver do
let(:resolver) do
Class.new(described_class) do
- argument :test, ::GraphQL::INT_TYPE, required: false
- type [::GraphQL::INT_TYPE], null: true
+ argument :test, ::GraphQL::Types::Int, required: false
+ type [::GraphQL::Types::Int], null: true
def resolve(test: 100)
process(object)
@@ -22,7 +22,7 @@ RSpec.describe Resolvers::BaseResolver do
let(:last_resolver) do
Class.new(described_class) do
- type [::GraphQL::INT_TYPE], null: true
+ type [::GraphQL::Types::Int], null: true
def resolve(**args)
[1, 2]
@@ -36,11 +36,11 @@ RSpec.describe Resolvers::BaseResolver do
context 'for a connection of scalars' do
let(:resolver) do
Class.new(described_class) do
- type ::GraphQL::INT_TYPE.connection_type, null: true
+ type ::GraphQL::Types::Int.connection_type, null: true
end
end
- it { is_expected.to eq(::GraphQL::INT_TYPE) }
+ it { is_expected.to eq(::GraphQL::Types::Int) }
end
context 'for a connection of objects' do
@@ -64,21 +64,21 @@ RSpec.describe Resolvers::BaseResolver do
context 'for a list type' do
let(:resolver) do
Class.new(described_class) do
- type [::GraphQL::STRING_TYPE], null: true
+ type [::GraphQL::Types::String], null: true
end
end
- it { is_expected.to eq(::GraphQL::STRING_TYPE) }
+ it { is_expected.to eq(::GraphQL::Types::String) }
end
context 'for a scalar type' do
let(:resolver) do
Class.new(described_class) do
- type ::GraphQL::BOOLEAN_TYPE, null: true
+ type ::GraphQL::Types::Boolean, null: true
end
end
- it { is_expected.to eq(::GraphQL::BOOLEAN_TYPE) }
+ it { is_expected.to eq(::GraphQL::Types::Boolean) }
end
end
@@ -88,7 +88,7 @@ RSpec.describe Resolvers::BaseResolver do
end
it 'has the correct (singular) type' do
- expect(resolver.single.type).to eq(::GraphQL::INT_TYPE)
+ expect(resolver.single.type).to eq(::GraphQL::Types::Int)
end
it 'returns the same subclass every time' do
@@ -105,10 +105,10 @@ RSpec.describe Resolvers::BaseResolver do
describe '.when_single' do
let(:resolver) do
Class.new(described_class) do
- type [::GraphQL::INT_TYPE], null: true
+ type [::GraphQL::Types::Int], null: true
when_single do
- argument :foo, ::GraphQL::INT_TYPE, required: true
+ argument :foo, ::GraphQL::Types::Int, required: true
end
def resolve(foo: 1)
@@ -138,14 +138,14 @@ RSpec.describe Resolvers::BaseResolver do
context 'multiple when_single blocks' do
let(:resolver) do
Class.new(described_class) do
- type [::GraphQL::INT_TYPE], null: true
+ type [::GraphQL::Types::Int], null: true
when_single do
- argument :foo, ::GraphQL::INT_TYPE, required: true
+ argument :foo, ::GraphQL::Types::Int, required: true
end
when_single do
- argument :bar, ::GraphQL::INT_TYPE, required: true
+ argument :bar, ::GraphQL::Types::Int, required: true
end
def resolve(foo: 1, bar: 2)
@@ -168,7 +168,7 @@ RSpec.describe Resolvers::BaseResolver do
let(:subclass) do
Class.new(resolver) do
when_single do
- argument :inc, ::GraphQL::INT_TYPE, required: true
+ argument :inc, ::GraphQL::Types::Int, required: true
end
def resolve(foo:, inc:)
@@ -194,7 +194,7 @@ RSpec.describe Resolvers::BaseResolver do
context 'when the resolver returns early' do
let(:resolver) do
Class.new(described_class) do
- type [::GraphQL::STRING_TYPE], null: true
+ type [::GraphQL::Types::String], null: true
def ready?(**args)
[false, %w[early return]]
@@ -237,14 +237,14 @@ RSpec.describe Resolvers::BaseResolver do
context 'when field is a connection' do
it 'increases complexity based on arguments' do
- field = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE.connection_type, resolver_class: described_class, null: false, max_page_size: 1)
+ field = Types::BaseField.new(name: 'test', type: GraphQL::Types::String.connection_type, resolver_class: described_class, null: false, max_page_size: 1)
expect(field.to_graphql.complexity.call({}, { sort: 'foo' }, 1)).to eq 3
expect(field.to_graphql.complexity.call({}, { search: 'foo' }, 1)).to eq 7
end
it 'does not increase complexity when filtering by iids' do
- field = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE.connection_type, resolver_class: described_class, null: false, max_page_size: 100)
+ field = Types::BaseField.new(name: 'test', type: GraphQL::Types::String.connection_type, resolver_class: described_class, null: false, max_page_size: 100)
expect(field.to_graphql.complexity.call({}, { sort: 'foo' }, 1)).to eq 6
expect(field.to_graphql.complexity.call({}, { sort: 'foo', iid: 1 }, 1)).to eq 3
diff --git a/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb b/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb
index 8d15d7eda1b..852aaf66201 100644
--- a/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb
+++ b/spec/graphql/resolvers/concerns/caching_array_resolver_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe ::CachingArrayResolver do
Class.new(::Resolvers::BaseResolver) do
include mod
type [::Types::UserType], null: true
- argument :is_admin, ::GraphQL::BOOLEAN_TYPE, required: false
+ argument :is_admin, ::GraphQL::Types::Boolean, required: false
def query_input(is_admin:)
is_admin
@@ -50,7 +50,7 @@ RSpec.describe ::CachingArrayResolver do
Class.new(::Resolvers::BaseResolver) do
include mod
type [::Types::UserType], null: true
- argument :username, ::GraphQL::STRING_TYPE, required: false
+ argument :username, ::GraphQL::Types::String, required: false
def query_input(username:)
username
diff --git a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb
index 3dffda75e08..6f6855c8f84 100644
--- a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb
+++ b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe ResolvesPipelines do
end
it 'increases field complexity based on arguments' do
- field = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE, resolver_class: resolver, null: false, max_page_size: 1)
+ field = Types::BaseField.new(name: 'test', type: GraphQL::Types::String, resolver_class: resolver, null: false, max_page_size: 1)
expect(field.to_graphql.complexity.call({}, {}, 1)).to eq 2
expect(field.to_graphql.complexity.call({}, { sha: 'foo' }, 1)).to eq 4
diff --git a/spec/graphql/resolvers/echo_resolver_spec.rb b/spec/graphql/resolvers/echo_resolver_spec.rb
index 4f48e5e0d7a..59a121ac7de 100644
--- a/spec/graphql/resolvers/echo_resolver_spec.rb
+++ b/spec/graphql/resolvers/echo_resolver_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Resolvers::EchoResolver do
let(:text) { 'Message test' }
specify do
- expect(described_class).to have_non_null_graphql_type(::GraphQL::STRING_TYPE)
+ expect(described_class).to have_non_null_graphql_type(::GraphQL::Types::String)
end
describe '#resolve' do
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index 9b329e961cc..89e4e803fa8 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -407,7 +407,7 @@ RSpec.describe Resolvers::IssuesResolver do
end
it 'increases field complexity based on arguments' do
- field = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE.connection_type, resolver_class: described_class, null: false, max_page_size: 100)
+ field = Types::BaseField.new(name: 'test', type: GraphQL::Types::String.connection_type, resolver_class: described_class, null: false, max_page_size: 100)
expect(field.to_graphql.complexity.call({}, {}, 1)).to eq 4
expect(field.to_graphql.complexity.call({}, { labelName: 'foo' }, 1)).to eq 8
diff --git a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb
index 618d012bd6d..b1f50a4a4a5 100644
--- a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb
@@ -145,7 +145,7 @@ RSpec.describe Resolvers::NamespaceProjectsResolver do
end
it 'has an high complexity regardless of arguments' do
- field = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE.connection_type, resolver_class: described_class, null: false, max_page_size: 100)
+ field = Types::BaseField.new(name: 'test', type: GraphQL::Types::String.connection_type, resolver_class: described_class, null: false, max_page_size: 100)
expect(field.to_graphql.complexity.call({}, {}, 1)).to eq 24
expect(field.to_graphql.complexity.call({}, { include_subgroups: true }, 1)).to eq 24
diff --git a/spec/graphql/resolvers/project_resolver_spec.rb b/spec/graphql/resolvers/project_resolver_spec.rb
index 72a01b1c574..d0661c27b95 100644
--- a/spec/graphql/resolvers/project_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_resolver_spec.rb
@@ -28,8 +28,8 @@ RSpec.describe Resolvers::ProjectResolver do
end
it 'does not increase complexity depending on number of load limits' do
- field1 = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE, resolver_class: described_class, null: false, max_page_size: 100)
- field2 = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE, resolver_class: described_class, null: false, max_page_size: 1)
+ field1 = Types::BaseField.new(name: 'test', type: GraphQL::Types::String, resolver_class: described_class, null: false, max_page_size: 100)
+ field2 = Types::BaseField.new(name: 'test', type: GraphQL::Types::String, resolver_class: described_class, null: false, max_page_size: 1)
expect(field1.to_graphql.complexity.call({}, {}, 1)).to eq 2
expect(field2.to_graphql.complexity.call({}, {}, 1)).to eq 2
diff --git a/spec/graphql/resolvers/terraform/states_resolver_spec.rb b/spec/graphql/resolvers/terraform/states_resolver_spec.rb
index 91d48cd782b..012c74ce398 100644
--- a/spec/graphql/resolvers/terraform/states_resolver_spec.rb
+++ b/spec/graphql/resolvers/terraform/states_resolver_spec.rb
@@ -43,7 +43,8 @@ RSpec.describe Resolvers::Terraform::StatesResolver.single do
it do
expect(subject).to be_present
- expect(subject.type.to_s).to eq('String!')
+ expect(subject.type).to be_kind_of GraphQL::Schema::NonNull
+ expect(subject.type.unwrap).to eq GraphQL::Types::String
expect(subject.description).to be_present
end
end
diff --git a/spec/graphql/resolvers/user_discussions_count_resolver_spec.rb b/spec/graphql/resolvers/user_discussions_count_resolver_spec.rb
index cc855bbcb53..70f06b58a65 100644
--- a/spec/graphql/resolvers/user_discussions_count_resolver_spec.rb
+++ b/spec/graphql/resolvers/user_discussions_count_resolver_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe Resolvers::UserDiscussionsCountResolver do
let_it_be(:private_discussion) { create_list(:discussion_note_on_issue, 3, noteable: private_issue, project: private_project) }
specify do
- expect(described_class).to have_nullable_graphql_type(GraphQL::INT_TYPE)
+ expect(described_class).to have_nullable_graphql_type(GraphQL::Types::Int)
end
context 'when counting discussions from a public issue' do
diff --git a/spec/graphql/resolvers/user_notes_count_resolver_spec.rb b/spec/graphql/resolvers/user_notes_count_resolver_spec.rb
index 6cf23a2f57f..bc173b2a166 100644
--- a/spec/graphql/resolvers/user_notes_count_resolver_spec.rb
+++ b/spec/graphql/resolvers/user_notes_count_resolver_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Resolvers::UserNotesCountResolver do
let_it_be(:private_project) { create(:project, :repository, :private) }
specify do
- expect(described_class).to have_nullable_graphql_type(GraphQL::INT_TYPE)
+ expect(described_class).to have_nullable_graphql_type(GraphQL::Types::Int)
end
context 'when counting notes from an issue' do
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index bf533ca7034..7e3f665a99c 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -472,4 +472,23 @@ RSpec.describe ApplicationHelper do
allow(helper.controller).to receive(method_name).and_return(value)
end
end
+
+ describe '#gitlab_ui_form_for' do
+ let_it_be(:user) { build(:user) }
+
+ before do
+ allow(helper).to receive(:users_path).and_return('/root')
+ allow(helper).to receive(:form_for).and_call_original
+ end
+
+ it 'adds custom form builder to options and calls `form_for`' do
+ options = { html: { class: 'foo-bar' } }
+ expected_options = options.merge({ builder: ::Gitlab::FormBuilders::GitlabUiFormBuilder, url: '/root' })
+
+ expect do |b|
+ helper.gitlab_ui_form_for(user, options, &b)
+ end.to yield_with_args(::Gitlab::FormBuilders::GitlabUiFormBuilder)
+ expect(helper).to have_received(:form_for).with(user, expected_options)
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 19c2e34a0f0..f5ed33ab114 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -2851,7 +2851,7 @@ module Gitlab
YAML
end
- it_behaves_like 'returns errors', 'The pipeline has circular dependencies.'
+ it_behaves_like 'returns errors', 'The pipeline has circular dependencies'
end
end
diff --git a/spec/lib/gitlab/form_builders/gitlab_ui_form_builder_spec.rb b/spec/lib/gitlab/form_builders/gitlab_ui_form_builder_spec.rb
new file mode 100644
index 00000000000..a46846e9820
--- /dev/null
+++ b/spec/lib/gitlab/form_builders/gitlab_ui_form_builder_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::FormBuilders::GitlabUiFormBuilder do
+ let_it_be(:user) { build(:user) }
+ let_it_be(:fake_template) do
+ Object.new.tap do |template|
+ template.extend ActionView::Helpers::FormHelper
+ template.extend ActionView::Helpers::FormOptionsHelper
+ template.extend ActionView::Helpers::TagHelper
+ template.extend ActionView::Context
+ end
+ end
+
+ let_it_be(:form_builder) { described_class.new(:user, user, fake_template, {}) }
+
+ describe '#gitlab_ui_checkbox_component' do
+ let(:optional_args) { {} }
+
+ subject(:checkbox_html) { form_builder.gitlab_ui_checkbox_component(:view_diffs_file_by_file, "Show one file at a time on merge request's Changes tab", **optional_args) }
+
+ context 'without optional arguments' do
+ it 'renders correct html' do
+ expected_html = <<~EOS
+ <div class="gl-form-checkbox custom-control custom-checkbox">
+ <input name="user[view_diffs_file_by_file]" type="hidden" value="0" />
+ <input class="custom-control-input" type="checkbox" value="1" name="user[view_diffs_file_by_file]" id="user_view_diffs_file_by_file" />
+ <label class="custom-control-label" for="user_view_diffs_file_by_file">
+ Show one file at a time on merge request&#39;s Changes tab
+ </label>
+ </div>
+ EOS
+
+ expect(checkbox_html).to eq(html_strip_whitespace(expected_html))
+ end
+ end
+
+ context 'with optional arguments' do
+ let(:optional_args) do
+ {
+ help_text: 'Instead of all the files changed, show only one file at a time.',
+ checkbox_options: { class: 'checkbox-foo-bar' },
+ label_options: { class: 'label-foo-bar' },
+ checked_value: '3',
+ unchecked_value: '1'
+ }
+ end
+
+ it 'renders help text' do
+ expected_html = <<~EOS
+ <div class="gl-form-checkbox custom-control custom-checkbox">
+ <input name="user[view_diffs_file_by_file]" type="hidden" value="1" />
+ <input class="custom-control-input checkbox-foo-bar" type="checkbox" value="3" name="user[view_diffs_file_by_file]" id="user_view_diffs_file_by_file" />
+ <label class="custom-control-label label-foo-bar" for="user_view_diffs_file_by_file">
+ <span>Show one file at a time on merge request&#39;s Changes tab</span>
+ <p class="help-text">Instead of all the files changed, show only one file at a time.</p>
+ </label>
+ </div>
+ EOS
+
+ expect(checkbox_html).to eq(html_strip_whitespace(expected_html))
+ end
+
+ it 'passes arguments to `check_box` method' do
+ allow(fake_template).to receive(:check_box).and_return('')
+
+ checkbox_html
+
+ expect(fake_template).to have_received(:check_box).with(:user, :view_diffs_file_by_file, { class: %w(custom-control-input checkbox-foo-bar), object: user }, '3', '1')
+ end
+
+ it 'passes arguments to `label` method' do
+ allow(fake_template).to receive(:label).and_return('')
+
+ checkbox_html
+
+ expect(fake_template).to have_received(:label).with(:user, :view_diffs_file_by_file, { class: %w(custom-control-label label-foo-bar), object: user })
+ end
+ end
+ end
+
+ private
+
+ def html_strip_whitespace(html)
+ html.lines.map(&:strip).join('')
+ end
+end
diff --git a/spec/lib/gitlab/import_export/group/legacy_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/group/legacy_tree_restorer_spec.rb
index bfcd4994995..dbd6cb243f6 100644
--- a/spec/lib/gitlab/import_export/group/legacy_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/group/legacy_tree_restorer_spec.rb
@@ -77,7 +77,7 @@ RSpec.describe Gitlab::ImportExport::Group::LegacyTreeRestorer do
let(:group) { create(:group) }
let(:shared) { Gitlab::ImportExport::Shared.new(group) }
let(:group_tree_restorer) { described_class.new(user: importer_user, shared: shared, group: group, group_hash: nil) }
- let(:group_json) { ActiveSupport::JSON.decode(IO.read(File.join(shared.export_path, 'group.json'))) }
+ let(:group_json) { Gitlab::Json.parse(IO.read(File.join(shared.export_path, 'group.json'))) }
shared_examples 'excluded attributes' do
excluded_attributes = %w[
diff --git a/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb
index d2153221e8f..b67d42d1b71 100644
--- a/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/group/tree_restorer_spec.rb
@@ -111,7 +111,7 @@ RSpec.describe Gitlab::ImportExport::Group::TreeRestorer do
let(:shared) { Gitlab::ImportExport::Shared.new(group) }
let(:group_tree_restorer) { described_class.new(user: importer_user, shared: shared, group: group) }
let(:exported_file) { File.join(shared.export_path, 'tree/groups/4352.json') }
- let(:group_json) { ActiveSupport::JSON.decode(IO.read(exported_file)) }
+ let(:group_json) { Gitlab::Json.parse(IO.read(exported_file)) }
shared_examples 'excluded attributes' do
excluded_attributes = %w[
diff --git a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
index 9c6d2708607..90966cb4915 100644
--- a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
+++ b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
@@ -86,7 +86,7 @@ RSpec.describe 'Test coverage of the Project Import' do
end
def relations_from_json(json_file)
- json = ActiveSupport::JSON.decode(IO.read(json_file))
+ json = Gitlab::Json.parse(IO.read(json_file))
[].tap {|res| gather_relations({ project: json }, res, [])}
.map {|relation_names| relation_names.join('.')}
diff --git a/spec/lib/gitlab/json_cache_spec.rb b/spec/lib/gitlab/json_cache_spec.rb
index 8265c3449bb..7899d01b475 100644
--- a/spec/lib/gitlab/json_cache_spec.rb
+++ b/spec/lib/gitlab/json_cache_spec.rb
@@ -130,7 +130,7 @@ RSpec.describe Gitlab::JsonCache do
.with(expanded_key)
.and_return(nil)
- expect(ActiveSupport::JSON).not_to receive(:decode)
+ expect(Gitlab::Json).not_to receive(:parse)
expect(cache.read(key)).to be_nil
end
@@ -140,7 +140,7 @@ RSpec.describe Gitlab::JsonCache do
.with(expanded_key)
.and_return(true)
- expect(ActiveSupport::JSON).to receive(:decode).with("true").and_call_original
+ expect(Gitlab::Json).to receive(:parse).with("true").and_call_original
expect(cache.read(key, BroadcastMessage)).to eq(true)
end
end
@@ -151,7 +151,7 @@ RSpec.describe Gitlab::JsonCache do
.with(expanded_key)
.and_return(false)
- expect(ActiveSupport::JSON).to receive(:decode).with("false").and_call_original
+ expect(Gitlab::Json).to receive(:parse).with("false").and_call_original
expect(cache.read(key, BroadcastMessage)).to eq(false)
end
end
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 3fb683ea0fa..2a91dae32b8 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -267,7 +267,7 @@ RSpec.describe 'Git HTTP requests' do
it "responds to pulls with the wiki's repo" do
download(path) do |response|
- json_body = ActiveSupport::JSON.decode(response.body)
+ json_body = Gitlab::Json.parse(response.body)
expect(json_body['Repository']['relative_path']).to eq(wiki.repository.relative_path)
end
@@ -1584,7 +1584,7 @@ RSpec.describe 'Git HTTP requests' do
it "responds to pulls with the wiki's repo" do
download(path) do |response|
- json_body = ActiveSupport::JSON.decode(response.body)
+ json_body = Gitlab::Json.parse(response.body)
expect(json_body['Repository']['relative_path']).to eq(wiki.repository.relative_path)
end
diff --git a/spec/rubocop/cop/gitlab/json_spec.rb b/spec/rubocop/cop/gitlab/json_spec.rb
index 66b2c675e80..7998f26da4e 100644
--- a/spec/rubocop/cop/gitlab/json_spec.rb
+++ b/spec/rubocop/cop/gitlab/json_spec.rb
@@ -6,7 +6,7 @@ require_relative '../../../../rubocop/cop/gitlab/json'
RSpec.describe RuboCop::Cop::Gitlab::Json do
subject(:cop) { described_class.new }
- context 'when JSON is called' do
+ context 'when ::JSON is called' do
it 'registers an offense' do
expect_offense(<<~RUBY)
class Foo
@@ -18,4 +18,17 @@ RSpec.describe RuboCop::Cop::Gitlab::Json do
RUBY
end
end
+
+ context 'when ActiveSupport::JSON is called' do
+ it 'registers an offense' do
+ expect_offense(<<~RUBY)
+ class Foo
+ def bar
+ ActiveSupport::JSON.parse('{ "foo": "bar" }')
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid calling `JSON` directly. [...]
+ end
+ end
+ RUBY
+ end
+ end
end
diff --git a/spec/services/packages/debian/generate_distribution_key_service_spec.rb b/spec/services/packages/debian/generate_distribution_key_service_spec.rb
index b31830c2d3b..f82d577f071 100644
--- a/spec/services/packages/debian/generate_distribution_key_service_spec.rb
+++ b/spec/services/packages/debian/generate_distribution_key_service_spec.rb
@@ -3,33 +3,21 @@
require 'spec_helper'
RSpec.describe Packages::Debian::GenerateDistributionKeyService do
- let_it_be(:user) { create(:user) }
-
let(:params) { {} }
- subject { described_class.new(current_user: user, params: params) }
+ subject { described_class.new(params: params) }
let(:response) { subject.execute }
- context 'with a user' do
- it 'returns an Hash', :aggregate_failures do
- expect(GPGME::Ctx).to receive(:new).with(armor: true, offline: true).and_call_original
- expect(User).to receive(:random_password).with(no_args).and_call_original
-
- expect(response).to be_a Hash
- expect(response.keys).to contain_exactly(:private_key, :public_key, :fingerprint, :passphrase)
- expect(response[:private_key]).to start_with('-----BEGIN PGP PRIVATE KEY BLOCK-----')
- expect(response[:public_key]).to start_with('-----BEGIN PGP PUBLIC KEY BLOCK-----')
- expect(response[:fingerprint].length).to eq(40)
- expect(response[:passphrase].length).to be > 10
- end
- end
-
- context 'without a user' do
- let(:user) { nil }
+ it 'returns an Hash', :aggregate_failures do
+ expect(GPGME::Ctx).to receive(:new).with(armor: true, offline: true).and_call_original
+ expect(User).to receive(:random_password).with(no_args).and_call_original
- it 'raises an ArgumentError' do
- expect { response }.to raise_error(ArgumentError, 'Please provide a user')
- end
+ expect(response).to be_a Hash
+ expect(response.keys).to contain_exactly(:private_key, :public_key, :fingerprint, :passphrase)
+ expect(response[:private_key]).to start_with('-----BEGIN PGP PRIVATE KEY BLOCK-----')
+ expect(response[:public_key]).to start_with('-----BEGIN PGP PUBLIC KEY BLOCK-----')
+ expect(response[:fingerprint].length).to eq(40)
+ expect(response[:passphrase].length).to be > 10
end
end
diff --git a/spec/services/packages/debian/sign_distribution_service_spec.rb b/spec/services/packages/debian/sign_distribution_service_spec.rb
new file mode 100644
index 00000000000..b1096ba235f
--- /dev/null
+++ b/spec/services/packages/debian/sign_distribution_service_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Debian::SignDistributionService do
+ let_it_be(:group) { create(:group, :public) }
+
+ let(:content) { FFaker::Lorem.paragraph }
+ let(:params) { {} }
+ let(:service) { described_class.new(distribution, content, params: params) }
+
+ shared_examples 'Sign Distribution' do |container_type, detach: false|
+ context "for #{container_type} detach=#{detach}" do
+ let(:params) { { detach: detach } }
+
+ if container_type == :group
+ let_it_be(:distribution) { create('debian_group_distribution', container: group) }
+ else
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:distribution) { create('debian_project_distribution', container: project) }
+ end
+
+ describe '#execute' do
+ subject { service.execute }
+
+ context 'without an existing key' do
+ it 'raises ArgumentError', :aggregate_failures do
+ expect { subject }
+ .to raise_error(ArgumentError, 'distribution key is missing')
+ end
+ end
+
+ context 'with an existing key' do
+ let!(:key) { create("debian_#{container_type}_distribution_key", distribution: distribution)}
+
+ it 'returns the content signed', :aggregate_failures do
+ expect(Packages::Debian::GenerateDistributionKeyService).not_to receive(:new)
+
+ key_class = "Packages::Debian::#{container_type.capitalize}DistributionKey".constantize
+
+ expect { subject }
+ .to not_change { key_class.count }
+
+ if detach
+ expect(subject).to start_with("-----BEGIN PGP SIGNATURE-----\n")
+ else
+ expect(subject).to start_with("-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA256\n\n#{content}\n-----BEGIN PGP SIGNATURE-----\n")
+ end
+
+ expect(subject).to end_with("\n-----END PGP SIGNATURE-----\n")
+ end
+ end
+ end
+ end
+ end
+
+ it_behaves_like 'Sign Distribution', :project
+ it_behaves_like 'Sign Distribution', :project, detach: true
+ it_behaves_like 'Sign Distribution', :group
+ it_behaves_like 'Sign Distribution', :group, detach: true
+end
diff --git a/spec/support/import_export/common_util.rb b/spec/support/import_export/common_util.rb
index 5fb6af99b79..1aa20dab6f8 100644
--- a/spec/support/import_export/common_util.rb
+++ b/spec/support/import_export/common_util.rb
@@ -83,7 +83,7 @@ module ImportExport
path = File.join(dir_path, "#{exportable_path}.json")
return unless File.exist?(path)
- ActiveSupport::JSON.decode(IO.read(path))
+ Gitlab::Json.parse(IO.read(path))
end
def consume_relations(dir_path, exportable_path, key)
@@ -93,7 +93,7 @@ module ImportExport
relations = []
File.foreach(path) do |line|
- json = ActiveSupport::JSON.decode(line)
+ json = Gitlab::Json.parse(line)
relations << json
end
@@ -101,7 +101,7 @@ module ImportExport
end
def project_json(filename)
- ActiveSupport::JSON.decode(IO.read(filename))
+ Gitlab::Json.parse(IO.read(filename))
end
end
end
diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb
index 43a6fcc2adc..9fa95613d1c 100644
--- a/spec/views/admin/dashboard/index.html.haml_spec.rb
+++ b/spec/views/admin/dashboard/index.html.haml_spec.rb
@@ -52,4 +52,12 @@ RSpec.describe 'admin/dashboard/index.html.haml' do
expect(rendered).not_to have_content "Maximum Users"
expect(rendered).not_to have_content "Users over License"
end
+
+ it 'links to the GitLab Changelog' do
+ stub_application_setting(version_check_enabled: true)
+
+ render
+
+ expect(rendered).to have_link(href: 'https://gitlab.com/gitlab-org/gitlab/-/blob/master/CHANGELOG.md')
+ end
end