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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-12-14 03:14:57 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-12-14 03:14:57 +0300
commit1d54f384d509d9581730e24a64561e94132e41c1 (patch)
treeb53346e16f2129de0872f9e1cc28bb468fffee04
parentf163fc8ce6d7661ccf0ff9aa4561f6e5a708b71b (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/qa.gitlab-ci.yml9
-rw-r--r--app/assets/javascripts/header_search/components/app.vue1
-rw-r--r--app/assets/javascripts/integrations/constants.js1
-rw-r--r--app/assets/javascripts/integrations/edit/components/integration_form.vue75
-rw-r--r--app/assets/javascripts/integrations/edit/store/actions.js1
-rw-r--r--app/assets/javascripts/integrations/edit/store/getters.js2
-rw-r--r--app/assets/javascripts/integrations/edit/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/integrations/edit/store/mutations.js3
-rw-r--r--app/assets/javascripts/integrations/edit/store/state.js1
-rw-r--r--app/assets/javascripts/integrations/integration_settings_form.js56
-rw-r--r--app/assets/javascripts/main.js30
-rw-r--r--app/assets/javascripts/snippets/components/edit.vue2
-rw-r--r--app/assets/javascripts/snippets/components/snippet_header.vue2
-rw-r--r--app/assets/stylesheets/framework/contextual_sidebar.scss12
-rw-r--r--app/assets/stylesheets/startup/startup-dark.scss57
-rw-r--r--app/assets/stylesheets/startup/startup-general.scss57
-rw-r--r--app/assets/stylesheets/utilities.scss12
-rw-r--r--app/services/issuable_base_service.rb19
-rw-r--r--app/services/issues/set_crm_contacts_service.rb3
-rw-r--r--app/views/groups/_invite_members_side_nav_link.html.haml1
-rw-r--r--app/views/layouts/header/_default.html.haml4
-rw-r--r--app/views/projects/_invite_members_side_nav_link.html.haml1
-rw-r--r--app/views/shared/nav/_scope_menu.html.haml2
-rw-r--r--app/views/shared/nav/_sidebar_hidden_menu_item.html.haml2
-rw-r--r--app/views/shared/nav/_sidebar_menu.html.haml2
-rw-r--r--app/views/shared/nav/_sidebar_menu_item.html.haml2
-rw-r--r--config/feature_flags/ops/database_async_index_creation.yml8
-rw-r--r--doc/administration/gitaly/recovery.md7
-rw-r--r--doc/user/group/saml_sso/scim_setup.md9
-rw-r--r--lib/gitlab/background_migration/add_merge_request_diff_commits_count.rb25
-rw-r--r--lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule.rb73
-rw-r--r--lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments.rb19
-rw-r--r--lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests.rb47
-rw-r--r--lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules.rb40
-rw-r--r--lib/gitlab/background_migration/backfill_namespace_settings.rb18
-rw-r--r--lib/gitlab/background_migration/backfill_project_settings.rb18
-rw-r--r--lib/gitlab/background_migration/backfill_push_rules_id_in_projects.rb27
-rw-r--r--lib/gitlab/background_migration/fix_promoted_epics_discussion_ids.rb22
-rw-r--r--lib/gitlab/background_migration/fix_user_namespace_names.rb68
-rw-r--r--lib/gitlab/background_migration/fix_user_project_route_names.rb38
-rw-r--r--lib/gitlab/background_migration/link_lfs_objects_projects.rb82
-rw-r--r--lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys.rb61
-rw-r--r--lib/gitlab/background_migration/migrate_pages_metadata.rb38
-rw-r--r--lib/gitlab/background_migration/migrate_security_scans.rb13
-rw-r--r--lib/gitlab/background_migration/migrate_to_hashed_storage.rb61
-rw-r--r--lib/gitlab/background_migration/move_epic_issues_after_epics.rb13
-rw-r--r--lib/gitlab/background_migration/populate_any_approval_rule_for_merge_requests.rb14
-rw-r--r--lib/gitlab/background_migration/populate_any_approval_rule_for_projects.rb14
-rw-r--r--lib/gitlab/background_migration/populate_canonical_emails.rb28
-rw-r--r--lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities.rb17
-rw-r--r--lib/gitlab/background_migration/populate_has_vulnerabilities.rb64
-rw-r--r--lib/gitlab/background_migration/populate_merge_request_assignees_table.rb44
-rw-r--r--lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information.rb89
-rw-r--r--lib/gitlab/background_migration/populate_personal_snippet_statistics.rb49
-rw-r--r--lib/gitlab/background_migration/populate_project_snippet_statistics.rb61
-rw-r--r--lib/gitlab/background_migration/populate_vulnerability_feedback_pipeline_id.rb13
-rw-r--r--lib/gitlab/background_migration/populate_vulnerability_historical_statistics.rb14
-rw-r--r--lib/gitlab/background_migration/prune_orphaned_geo_events.rb17
-rw-r--r--lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id.rb38
-rw-r--r--lib/gitlab/background_migration/remove_duplicate_cs_findings.rb13
-rw-r--r--lib/gitlab/background_migration/remove_duplicated_cs_findings_without_vulnerability_id.rb13
-rw-r--r--lib/gitlab/background_migration/remove_inaccessible_epic_todos.rb13
-rw-r--r--lib/gitlab/background_migration/remove_undefined_vulnerability_confidence_level.rb13
-rw-r--r--lib/gitlab/background_migration/replace_blocked_by_links.rb34
-rw-r--r--lib/gitlab/background_migration/reset_merge_status.rb17
-rw-r--r--lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects.rb30
-rw-r--r--lib/gitlab/background_migration/set_merge_request_diff_files_count.rb33
-rw-r--r--lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent.rb21
-rw-r--r--lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth.rb110
-rw-r--r--lib/gitlab/background_migration/update_location_fingerprint_for_container_scanning_findings.rb13
-rw-r--r--lib/gitlab/background_migration/update_vulnerabilities_from_dismissal_feedback.rb13
-rw-r--r--lib/gitlab/quick_actions/issue_actions.rb28
-rw-r--r--lib/sidebars/concerns/container_with_html_options.rb2
-rw-r--r--lib/sidebars/concerns/link_with_html_options.rb14
-rw-r--r--lib/sidebars/menu_item.rb2
-rw-r--r--spec/frontend/integrations/edit/components/integration_form_spec.js121
-rw-r--r--spec/frontend/integrations/edit/store/actions_spec.js7
-rw-r--r--spec/frontend/integrations/edit/store/getters_spec.js19
-rw-r--r--spec/frontend/integrations/edit/store/mutations_spec.js8
-rw-r--r--spec/frontend/integrations/edit/store/state_spec.js1
-rw-r--r--spec/frontend/integrations/integration_settings_form_spec.js90
-rw-r--r--spec/frontend/snippets/components/snippet_header_spec.js2
-rw-r--r--spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb66
-rw-r--r--spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb61
-rw-r--r--spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb44
-rw-r--r--spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb46
-rw-r--r--spec/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules_spec.rb53
-rw-r--r--spec/lib/gitlab/background_migration/backfill_namespace_settings_spec.rb23
-rw-r--r--spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb24
-rw-r--r--spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb32
-rw-r--r--spec/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids_spec.rb49
-rw-r--r--spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb104
-rw-r--r--spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb98
-rw-r--r--spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb113
-rw-r--r--spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb93
-rw-r--r--spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb36
-rw-r--r--spec/lib/gitlab/background_migration/migrate_to_hashed_storage_spec.rb43
-rw-r--r--spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb94
-rw-r--r--spec/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities_spec.rb44
-rw-r--r--spec/lib/gitlab/background_migration/populate_has_vulnerabilities_spec.rb63
-rw-r--r--spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb70
-rw-r--r--spec/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information_spec.rb65
-rw-r--r--spec/lib/gitlab/background_migration/populate_personal_snippet_statistics_spec.rb141
-rw-r--r--spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb224
-rw-r--r--spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb38
-rw-r--r--spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb42
-rw-r--r--spec/lib/gitlab/background_migration/reset_merge_status_spec.rb48
-rw-r--r--spec/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects_spec.rb35
-rw-r--r--spec/lib/gitlab/background_migration/set_merge_request_diff_files_count_spec.rb51
-rw-r--r--spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb46
-rw-r--r--spec/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth_spec.rb74
-rw-r--r--spec/lib/sidebars/concerns/link_with_html_options_spec.rb39
-rw-r--r--spec/services/issues/create_service_spec.rb15
-rw-r--r--spec/services/issues/update_service_spec.rb6
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb22
-rw-r--r--spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb2
116 files changed, 454 insertions, 3674 deletions
diff --git a/.gitlab/ci/qa.gitlab-ci.yml b/.gitlab/ci/qa.gitlab-ci.yml
index a7541a613f0..4fec223e66d 100644
--- a/.gitlab/ci/qa.gitlab-ci.yml
+++ b/.gitlab/ci/qa.gitlab-ci.yml
@@ -57,11 +57,12 @@ update-qa-cache:
- install_gitlab_gem
- tooling/bin/find_change_diffs ${CHANGES_DIFFS_DIR}
script:
+ - tooling/bin/qa/check_if_qa_only_spec_changes ${CHANGES_FILE} ${ONLY_QA_CHANGES_FILE}
+ - '[ -f $ONLY_QA_CHANGES_FILE ] && export QA_TESTS="`cat $ONLY_QA_CHANGES_FILE`"'
+ - 'echo "QA_TESTS: $QA_TESTS"'
+ - exit_code=0 && tooling/bin/qa/package_and_qa_check ${CHANGES_DIFFS_DIR} || exit_code=$?
+ - echo $exit_code
- |
- tooling/bin/qa/check_if_qa_only_spec_changes ${CHANGES_FILE} ${ONLY_QA_CHANGES_FILE}
- [ -f $ONLY_QA_CHANGES_FILE ] && export QA_TESTS="`cat $ONLY_QA_CHANGES_FILE`"
- echo "QA_TESTS: $QA_TESTS"
- tooling/bin/qa/package_and_qa_check ${CHANGES_DIFFS_DIR} && exit_code=$?
if [ $exit_code -eq 0 ]; then
./scripts/trigger-build omnibus
elif [ $exit_code -eq 1 ]; then
diff --git a/app/assets/javascripts/header_search/components/app.vue b/app/assets/javascripts/header_search/components/app.vue
index c22f532d7ac..edc6573a489 100644
--- a/app/assets/javascripts/header_search/components/app.vue
+++ b/app/assets/javascripts/header_search/components/app.vue
@@ -140,6 +140,7 @@ export default {
class="header-search gl-relative"
>
<gl-search-box-by-type
+ id="search"
v-model="searchText"
role="searchbox"
class="gl-z-index-1"
diff --git a/app/assets/javascripts/integrations/constants.js b/app/assets/javascripts/integrations/constants.js
index 74d99d02fc5..177e3d6f9cc 100644
--- a/app/assets/javascripts/integrations/constants.js
+++ b/app/assets/javascripts/integrations/constants.js
@@ -1,6 +1,5 @@
import { s__, __ } from '~/locale';
-export const TEST_INTEGRATION_EVENT = 'testIntegration';
export const SAVE_INTEGRATION_EVENT = 'saveIntegration';
export const VALIDATE_INTEGRATION_FORM_EVENT = 'validateIntegrationForm';
diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue
index a30c84bd4d2..60a6d13ce69 100644
--- a/app/assets/javascripts/integrations/edit/components/integration_form.vue
+++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue
@@ -1,14 +1,18 @@
<script>
import { GlButton, GlModalDirective, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
+import * as Sentry from '@sentry/browser';
import { mapState, mapActions, mapGetters } from 'vuex';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import {
- TEST_INTEGRATION_EVENT,
SAVE_INTEGRATION_EVENT,
+ VALIDATE_INTEGRATION_FORM_EVENT,
+ I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE,
+ I18N_DEFAULT_ERROR_MESSAGE,
+ I18N_SUCCESSFUL_CONNECTION_MESSAGE,
integrationLevels,
} from '~/integrations/constants';
import eventHub from '../event_hub';
-
+import { testIntegrationSettings } from '../api';
import ActiveCheckbox from './active_checkbox.vue';
import ConfirmationModal from './confirmation_modal.vue';
import DynamicField from './dynamic_field.vue';
@@ -50,18 +54,12 @@ export default {
data() {
return {
integrationActive: false,
+ testingLoading: false,
};
},
computed: {
...mapGetters(['currentKey', 'propsSource', 'isDisabled']),
- ...mapState([
- 'defaultState',
- 'customState',
- 'override',
- 'isSaving',
- 'isTesting',
- 'isResetting',
- ]),
+ ...mapState(['defaultState', 'customState', 'override', 'isSaving', 'isResetting']),
isEditable() {
return this.propsSource.editable;
},
@@ -74,9 +72,18 @@ export default {
this.customState.integrationLevel === integrationLevels.GROUP
);
},
- showReset() {
+ showResetButton() {
return this.isInstanceOrGroupLevel && this.propsSource.resetPath;
},
+ showTestButton() {
+ return this.propsSource.canTest;
+ },
+ disableSaveButton() {
+ return Boolean(this.isResetting || this.testingLoading);
+ },
+ disableResetButton() {
+ return Boolean(this.isSaving || this.testingLoading);
+ },
},
mounted() {
// this form element is defined in Haml
@@ -86,7 +93,6 @@ export default {
...mapActions([
'setOverride',
'setIsSaving',
- 'setIsTesting',
'setIsResetting',
'fetchResetIntegration',
'requestJiraIssueTypes',
@@ -98,17 +104,39 @@ export default {
eventHub.$emit(SAVE_INTEGRATION_EVENT, formValid);
},
onTestClick() {
- this.setIsTesting(true);
+ this.testingLoading = true;
- const formValid = this.form.checkValidity();
- eventHub.$emit(TEST_INTEGRATION_EVENT, formValid);
+ if (!this.form.checkValidity()) {
+ eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT);
+ return;
+ }
+
+ testIntegrationSettings(this.propsSource.testPath, this.getFormData())
+ .then(({ data: { error, message = I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE } }) => {
+ if (error) {
+ eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT);
+ this.$toast.show(message);
+ return;
+ }
+
+ this.$toast.show(I18N_SUCCESSFUL_CONNECTION_MESSAGE);
+ })
+ .catch((error) => {
+ this.$toast.show(I18N_DEFAULT_ERROR_MESSAGE);
+ Sentry.captureException(error);
+ })
+ .finally(() => {
+ this.testingLoading = false;
+ });
},
onResetClick() {
this.fetchResetIntegration();
},
onRequestJiraIssueTypes() {
- const formData = new FormData(this.form);
- this.requestJiraIssueTypes(formData);
+ this.requestJiraIssueTypes(this.getFormData());
+ },
+ getFormData() {
+ return new FormData(this.form);
},
onToggleIntegrationState(integrationActive) {
this.integrationActive = integrationActive;
@@ -183,7 +211,7 @@ export default {
category="primary"
variant="confirm"
:loading="isSaving"
- :disabled="isDisabled"
+ :disabled="disableSaveButton"
data-qa-selector="save_changes_button"
>
{{ __('Save changes') }}
@@ -196,7 +224,7 @@ export default {
variant="confirm"
type="submit"
:loading="isSaving"
- :disabled="isDisabled"
+ :disabled="disableSaveButton"
data-testid="save-button"
data-qa-selector="save_changes_button"
@click.prevent="onSaveClick"
@@ -205,25 +233,24 @@ export default {
</gl-button>
<gl-button
- v-if="propsSource.canTest"
+ v-if="showTestButton"
category="secondary"
variant="confirm"
- :loading="isTesting"
+ :loading="testingLoading"
:disabled="isDisabled"
- :href="propsSource.testPath"
data-testid="test-button"
@click.prevent="onTestClick"
>
{{ __('Test settings') }}
</gl-button>
- <template v-if="showReset">
+ <template v-if="showResetButton">
<gl-button
v-gl-modal.confirmResetIntegration
category="secondary"
variant="confirm"
:loading="isResetting"
- :disabled="isDisabled"
+ :disabled="disableResetButton"
data-testid="reset-button"
>
{{ __('Reset') }}
diff --git a/app/assets/javascripts/integrations/edit/store/actions.js b/app/assets/javascripts/integrations/edit/store/actions.js
index b81ae1b1cb6..6c1bfaa7858 100644
--- a/app/assets/javascripts/integrations/edit/store/actions.js
+++ b/app/assets/javascripts/integrations/edit/store/actions.js
@@ -11,7 +11,6 @@ import * as types from './mutation_types';
export const setOverride = ({ commit }, override) => commit(types.SET_OVERRIDE, override);
export const setIsSaving = ({ commit }, isSaving) => commit(types.SET_IS_SAVING, isSaving);
-export const setIsTesting = ({ commit }, isTesting) => commit(types.SET_IS_TESTING, isTesting);
export const setIsResetting = ({ commit }, isResetting) =>
commit(types.SET_IS_RESETTING, isResetting);
diff --git a/app/assets/javascripts/integrations/edit/store/getters.js b/app/assets/javascripts/integrations/edit/store/getters.js
index 39e14de2d0d..10d370de856 100644
--- a/app/assets/javascripts/integrations/edit/store/getters.js
+++ b/app/assets/javascripts/integrations/edit/store/getters.js
@@ -1,6 +1,6 @@
export const isInheriting = (state) => (state.defaultState === null ? false : !state.override);
-export const isDisabled = (state) => state.isSaving || state.isTesting || state.isResetting;
+export const isDisabled = (state) => state.isSaving || state.isResetting;
export const propsSource = (state, getters) =>
getters.isInheriting ? state.defaultState : state.customState;
diff --git a/app/assets/javascripts/integrations/edit/store/mutation_types.js b/app/assets/javascripts/integrations/edit/store/mutation_types.js
index c681056a515..dd4a79f6fe0 100644
--- a/app/assets/javascripts/integrations/edit/store/mutation_types.js
+++ b/app/assets/javascripts/integrations/edit/store/mutation_types.js
@@ -1,6 +1,5 @@
export const SET_OVERRIDE = 'SET_OVERRIDE';
export const SET_IS_SAVING = 'SET_IS_SAVING';
-export const SET_IS_TESTING = 'SET_IS_TESTING';
export const SET_IS_RESETTING = 'SET_IS_RESETTING';
export const SET_IS_LOADING_JIRA_ISSUE_TYPES = 'SET_IS_LOADING_JIRA_ISSUE_TYPES';
diff --git a/app/assets/javascripts/integrations/edit/store/mutations.js b/app/assets/javascripts/integrations/edit/store/mutations.js
index 279df1b9266..f76081e62f0 100644
--- a/app/assets/javascripts/integrations/edit/store/mutations.js
+++ b/app/assets/javascripts/integrations/edit/store/mutations.js
@@ -7,9 +7,6 @@ export default {
[types.SET_IS_SAVING](state, isSaving) {
state.isSaving = isSaving;
},
- [types.SET_IS_TESTING](state, isTesting) {
- state.isTesting = isTesting;
- },
[types.SET_IS_RESETTING](state, isResetting) {
state.isResetting = isResetting;
},
diff --git a/app/assets/javascripts/integrations/edit/store/state.js b/app/assets/javascripts/integrations/edit/store/state.js
index 1c0b274e4ef..3d40d1b90d5 100644
--- a/app/assets/javascripts/integrations/edit/store/state.js
+++ b/app/assets/javascripts/integrations/edit/store/state.js
@@ -6,7 +6,6 @@ export default ({ defaultState = null, customState = {} } = {}) => {
defaultState,
customState,
isSaving: false,
- isTesting: false,
isResetting: false,
isLoadingJiraIssueTypes: false,
loadingJiraIssueTypesErrorMessage: '',
diff --git a/app/assets/javascripts/integrations/integration_settings_form.js b/app/assets/javascripts/integrations/integration_settings_form.js
index d3c227df1ee..193bc1c4e9b 100644
--- a/app/assets/javascripts/integrations/integration_settings_form.js
+++ b/app/assets/javascripts/integrations/integration_settings_form.js
@@ -1,15 +1,7 @@
import { delay } from 'lodash';
-import toast from '~/vue_shared/plugins/global_toast';
import initForm from './edit';
import eventHub from './edit/event_hub';
-import {
- TEST_INTEGRATION_EVENT,
- SAVE_INTEGRATION_EVENT,
- VALIDATE_INTEGRATION_FORM_EVENT,
- I18N_DEFAULT_ERROR_MESSAGE,
- I18N_SUCCESSFUL_CONNECTION_MESSAGE,
-} from './constants';
-import { testIntegrationSettings } from './edit/api';
+import { SAVE_INTEGRATION_EVENT, VALIDATE_INTEGRATION_FORM_EVENT } from './constants';
export default class IntegrationSettingsForm {
constructor(formSelector) {
@@ -29,9 +21,6 @@ export default class IntegrationSettingsForm {
document.querySelector('.js-vue-default-integration-settings'),
this.formSelector,
);
- eventHub.$on(TEST_INTEGRATION_EVENT, (formValid) => {
- this.testIntegration(formValid);
- });
eventHub.$on(SAVE_INTEGRATION_EVENT, (formValid) => {
this.saveIntegration(formValid);
});
@@ -53,47 +42,4 @@ export default class IntegrationSettingsForm {
this.vue.$store.dispatch('setIsSaving', false);
}
}
-
- testIntegration(formValid) {
- // Service was marked active so now we check;
- // 1) If form contents are valid
- // 2) If this service can be tested
- // If both conditions are true, we override form submission
- // and test the service using provided configuration.
- if (formValid) {
- this.testSettings(new FormData(this.$form));
- } else {
- eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT);
- this.vue.$store.dispatch('setIsTesting', false);
- }
- }
-
- /**
- * Get a list of Jira issue types for the currently configured project
- *
- * @param {string} formData - URL encoded string containing the form data
- *
- * @return {Promise}
- */
-
- /**
- * Test Integration config
- */
- testSettings(formData) {
- return testIntegrationSettings(this.testEndPoint, formData)
- .then(({ data }) => {
- if (data.error) {
- toast(`${data.message} ${data.service_response}`);
- } else {
- this.vue.$store.dispatch('receiveJiraIssueTypesSuccess', data.issuetypes);
- toast(I18N_SUCCESSFUL_CONNECTION_MESSAGE);
- }
- })
- .catch(() => {
- toast(I18N_DEFAULT_ERROR_MESSAGE);
- })
- .finally(() => {
- this.vue.$store.dispatch('setIsTesting', false);
- });
- }
}
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 0d307d7744b..99e8058b57d 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -14,7 +14,6 @@ import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import { initRails } from '~/lib/utils/rails_ujs';
import * as popovers from '~/popovers';
import * as tooltips from '~/tooltips';
-import { initHeaderSearchApp } from '~/header_search';
import initAlertHandler from './alert_handler';
import { addDismissFlashClickListener } from './flash';
import initTodoToggle from './header';
@@ -100,24 +99,29 @@ function deferredInitialisation() {
initFeatureHighlight();
initCopyCodeButton();
- if (gon.features?.newHeaderSearch) {
- initHeaderSearchApp();
- } else {
- const search = document.querySelector('#search');
- if (search) {
- search.addEventListener(
- 'focus',
- () => {
+ const search = document.querySelector('#search');
+ if (search) {
+ search.addEventListener(
+ 'focus',
+ () => {
+ if (gon.features?.newHeaderSearch) {
+ import(/* webpackChunkName: 'globalSearch' */ '~/header_search')
+ .then(async ({ initHeaderSearchApp }) => {
+ await initHeaderSearchApp();
+ document.querySelector('#search').focus();
+ })
+ .catch(() => {});
+ } else {
import(/* webpackChunkName: 'globalSearch' */ './search_autocomplete')
.then(({ default: initSearchAutocomplete }) => {
const searchDropdown = initSearchAutocomplete();
searchDropdown.onSearchInputFocus();
})
.catch(() => {});
- },
- { once: true },
- );
- }
+ }
+ },
+ { once: true },
+ );
}
addSelectOnFocusBehaviour('.js-select-on-focus');
diff --git a/app/assets/javascripts/snippets/components/edit.vue b/app/assets/javascripts/snippets/components/edit.vue
index f07fb9d926a..e3aa29d5f89 100644
--- a/app/assets/javascripts/snippets/components/edit.vue
+++ b/app/assets/javascripts/snippets/components/edit.vue
@@ -230,7 +230,7 @@ export default {
<gl-button
category="primary"
type="submit"
- variant="success"
+ variant="confirm"
:disabled="updatePrevented"
data-qa-selector="submit_button"
data-testid="snippet-submit-btn"
diff --git a/app/assets/javascripts/snippets/components/snippet_header.vue b/app/assets/javascripts/snippets/components/snippet_header.vue
index a5c98a7ad90..9b24c8afe37 100644
--- a/app/assets/javascripts/snippets/components/snippet_header.vue
+++ b/app/assets/javascripts/snippets/components/snippet_header.vue
@@ -113,7 +113,7 @@ export default {
href: this.snippet.project
? joinPaths(this.snippet.project.webUrl, '-/snippets/new')
: joinPaths('/', gon.relative_url_root, '/-/snippets/new'),
- variant: 'success',
+ variant: 'confirm',
category: 'secondary',
},
{
diff --git a/app/assets/stylesheets/framework/contextual_sidebar.scss b/app/assets/stylesheets/framework/contextual_sidebar.scss
index 03dcbd2b8f9..345c180d164 100644
--- a/app/assets/stylesheets/framework/contextual_sidebar.scss
+++ b/app/assets/stylesheets/framework/contextual_sidebar.scss
@@ -376,6 +376,18 @@
}
}
}
+
+ li > a.gl-link {
+ // undo gl-link text items for things in the sidebar - including sub menus
+ // defined in https://gitlab.com/gitlab-org/gitlab-ui/-/blob/5431e0ca5149d4e02e3d5d617d194ac9609bb82d/src/components/base/link/link.scss
+ @include gl-text-body;
+
+ &:active,
+ &:focus,
+ &:focus:active {
+ @include gl-text-decoration-none;
+ }
+ }
}
.sidebar-sub-level-items {
diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss
index 9914e573247..63305bc592d 100644
--- a/app/assets/stylesheets/startup/startup-dark.scss
+++ b/app/assets/stylesheets/startup/startup-dark.scss
@@ -407,6 +407,34 @@ h1 {
.gl-form-input.form-control::placeholder {
color: #868686;
}
+.gl-icon {
+ fill: currentColor;
+}
+.gl-icon.s12 {
+ width: 12px;
+ height: 12px;
+}
+.gl-icon.s16 {
+ width: 16px;
+ height: 16px;
+}
+.gl-icon.s32 {
+ width: 32px;
+ height: 32px;
+}
+.gl-link {
+ font-size: 0.875rem;
+ color: #428fdc;
+}
+.gl-link:active {
+ color: #9dc7f1;
+}
+.gl-link:active {
+ text-decoration: underline;
+ box-shadow: 0 0 0 1px rgba(51, 51, 51, 0.4),
+ 0 0 0 4px rgba(66, 143, 220, 0.48);
+ outline: none;
+}
.gl-button {
display: inline-flex;
}
@@ -439,6 +467,29 @@ h1 {
outline: none;
background-color: #404040;
}
+.gl-button.gl-button.btn-default:active .gl-icon,
+.gl-button.gl-button.btn-default.active .gl-icon {
+ color: #fafafa;
+}
+.gl-button.gl-button.btn-default .gl-icon {
+ color: #999;
+}
+.gl-search-box-by-type-search-icon {
+ margin: 0.5rem;
+ color: #999;
+ width: 1rem;
+ position: absolute;
+}
+.gl-search-box-by-type {
+ display: flex;
+ position: relative;
+}
+.gl-search-box-by-type-input,
+.gl-search-box-by-type-input.gl-form-input {
+ height: 2rem;
+ padding-right: 2rem;
+ padding-left: 1.75rem;
+}
body,
.form-control,
.search form {
@@ -1334,6 +1385,12 @@ input {
font-weight: 400;
color: #9dc7f1;
}
+.sidebar-top-level-items li > a.gl-link {
+ color: #fafafa;
+}
+.sidebar-top-level-items li > a.gl-link:active {
+ text-decoration: none;
+}
.sidebar-sub-level-items {
padding-top: 0;
padding-bottom: 0;
diff --git a/app/assets/stylesheets/startup/startup-general.scss b/app/assets/stylesheets/startup/startup-general.scss
index e6d7185e29c..a57202515ad 100644
--- a/app/assets/stylesheets/startup/startup-general.scss
+++ b/app/assets/stylesheets/startup/startup-general.scss
@@ -388,6 +388,34 @@ h1 {
.gl-form-input.form-control::placeholder {
color: #868686;
}
+.gl-icon {
+ fill: currentColor;
+}
+.gl-icon.s12 {
+ width: 12px;
+ height: 12px;
+}
+.gl-icon.s16 {
+ width: 16px;
+ height: 16px;
+}
+.gl-icon.s32 {
+ width: 32px;
+ height: 32px;
+}
+.gl-link {
+ font-size: 0.875rem;
+ color: #1f75cb;
+}
+.gl-link:active {
+ color: #0b5cad;
+}
+.gl-link:active {
+ text-decoration: underline;
+ box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.4),
+ 0 0 0 4px rgba(31, 117, 203, 0.48);
+ outline: none;
+}
.gl-button {
display: inline-flex;
}
@@ -420,6 +448,29 @@ h1 {
outline: none;
background-color: #dbdbdb;
}
+.gl-button.gl-button.btn-default:active .gl-icon,
+.gl-button.gl-button.btn-default.active .gl-icon {
+ color: #303030;
+}
+.gl-button.gl-button.btn-default .gl-icon {
+ color: #666;
+}
+.gl-search-box-by-type-search-icon {
+ margin: 0.5rem;
+ color: #666;
+ width: 1rem;
+ position: absolute;
+}
+.gl-search-box-by-type {
+ display: flex;
+ position: relative;
+}
+.gl-search-box-by-type-input,
+.gl-search-box-by-type-input.gl-form-input {
+ height: 2rem;
+ padding-right: 2rem;
+ padding-left: 1.75rem;
+}
body,
.form-control,
.search form {
@@ -1315,6 +1366,12 @@ input {
font-weight: 400;
color: #0b5cad;
}
+.sidebar-top-level-items li > a.gl-link {
+ color: #303030;
+}
+.sidebar-top-level-items li > a.gl-link:active {
+ text-decoration: none;
+}
.sidebar-sub-level-items {
padding-top: 0;
padding-bottom: 0;
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index d2cc1f8640f..a8110d15d8e 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -291,18 +291,6 @@ $gl-line-height-42: px-to-rem(42px);
@include gl-focus($gl-border-size-1, $gray-900, true);
}
-// Will be moved to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2476
-.gl-md-max-w-50p {
- @include gl-media-breakpoint-up(md) {
- max-width: 50%;
- }
-}
-
-// Will be moved to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2497
-.gl-z-index-200 {
- z-index: 200;
-}
-
// Will be moved to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1637
.gl-lg-w-25p {
@include gl-media-breakpoint-up(lg) {
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 2daf098b94a..1d1d9b6bec7 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -56,6 +56,8 @@ class IssuableBaseService < ::BaseProjectService
# confidential attribute is a special type of metadata and needs to be allowed to be set
# by non-members on issues in public projects so that security issues can be reported as confidential.
params.delete(:confidential) unless can?(current_user, :set_confidentiality, issuable)
+ params.delete(:add_contacts) unless can?(current_user, :set_issue_crm_contacts, issuable)
+ params.delete(:remove_contacts) unless can?(current_user, :set_issue_crm_contacts, issuable)
filter_assignees(issuable)
filter_milestone
@@ -206,6 +208,9 @@ class IssuableBaseService < ::BaseProjectService
params[:assignee_ids] = process_assignee_ids(params, extra_assignee_ids: issuable.assignee_ids.to_a)
end
+ params.delete(:remove_contacts)
+ add_crm_contact_emails = params.delete(:add_contacts)
+
issuable.assign_attributes(allowed_create_params(params))
before_create(issuable)
@@ -219,6 +224,7 @@ class IssuableBaseService < ::BaseProjectService
handle_changes(issuable, { params: params })
after_create(issuable)
+ set_crm_contacts(issuable, add_crm_contact_emails)
execute_hooks(issuable)
users_to_invalidate = issuable.allows_reviewers? ? issuable.assignees | issuable.reviewers : issuable.assignees
@@ -229,6 +235,12 @@ class IssuableBaseService < ::BaseProjectService
issuable
end
+ def set_crm_contacts(issuable, add_crm_contact_emails, remove_crm_contact_emails = [])
+ return unless add_crm_contact_emails.present? || remove_crm_contact_emails.present?
+
+ ::Issues::SetCrmContactsService.new(project: project, current_user: current_user, params: { add_emails: add_crm_contact_emails, remove_emails: remove_crm_contact_emails }).execute(issuable)
+ end
+
def before_create(issuable)
# To be overridden by subclasses
end
@@ -254,6 +266,7 @@ class IssuableBaseService < ::BaseProjectService
assign_requested_labels(issuable)
assign_requested_assignees(issuable)
+ assign_requested_crm_contacts(issuable)
if issuable.changed? || params.present?
issuable.assign_attributes(allowed_update_params(params))
@@ -414,6 +427,12 @@ class IssuableBaseService < ::BaseProjectService
issuable.touch
end
+ def assign_requested_crm_contacts(issuable)
+ add_crm_contact_emails = params.delete(:add_contacts)
+ remove_crm_contact_emails = params.delete(:remove_contacts)
+ set_crm_contacts(issuable, add_crm_contact_emails, remove_crm_contact_emails)
+ end
+
def assign_requested_assignees(issuable)
return if issuable.is_a?(Epic)
diff --git a/app/services/issues/set_crm_contacts_service.rb b/app/services/issues/set_crm_contacts_service.rb
index f0d95934ea4..c435ab81b4d 100644
--- a/app/services/issues/set_crm_contacts_service.rb
+++ b/app/services/issues/set_crm_contacts_service.rb
@@ -12,7 +12,7 @@ module Issues
return error_no_permissions unless allowed?
return error_invalid_params unless valid_params?
- @existing_ids = issue.issue_customer_relations_contacts.map(&:contact_id)
+ @existing_ids = issue.customer_relations_contact_ids
determine_changes if params[:replace_ids].present?
return error_too_many if too_many?
@@ -24,6 +24,7 @@ module Issues
if issue.valid?
GraphqlTriggers.issue_crm_contacts_updated(issue)
+ issue.touch
ServiceResponse.success(payload: issue)
else
# The default error isn't very helpful: "Issue customer relations contacts is invalid"
diff --git a/app/views/groups/_invite_members_side_nav_link.html.haml b/app/views/groups/_invite_members_side_nav_link.html.haml
index bccfa9897da..3046669b53b 100644
--- a/app/views/groups/_invite_members_side_nav_link.html.haml
+++ b/app/views/groups/_invite_members_side_nav_link.html.haml
@@ -1,5 +1,4 @@
.js-invite-members-trigger{ data: { trigger_source: 'group-side-nav',
- classes: 'gl-text-decoration-none! gl-shadow-none! gl-text-body!',
icon: 'users',
display_text: title,
trigger_element: 'side-nav'} }
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 01dfecb585a..a7c08bafba6 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -36,7 +36,9 @@
'issues-path' => issues_dashboard_path,
'mr-path' => merge_requests_dashboard_path,
'autocomplete-path' => search_autocomplete_path } }
- %input{ type: "text", placeholder: _('Search or jump to...'), class: 'form-control gl-form-input' }
+ .gl-search-box-by-type
+ = sprite_icon('search', css_class: 'gl-search-box-by-type-search-icon gl-icon')
+ %input{ type: "text", placeholder: _('Search or jump to...'), class: 'form-control gl-form-input gl-search-box-by-type-input', id: 'search', autocomplete: 'off' }
- else
= render 'layouts/search'
%li.nav-item{ class: 'd-none d-sm-inline-block d-lg-none' }
diff --git a/app/views/projects/_invite_members_side_nav_link.html.haml b/app/views/projects/_invite_members_side_nav_link.html.haml
index ea6174d19f0..fae681b1a71 100644
--- a/app/views/projects/_invite_members_side_nav_link.html.haml
+++ b/app/views/projects/_invite_members_side_nav_link.html.haml
@@ -1,5 +1,4 @@
.js-invite-members-trigger{ data: { trigger_source: 'project-side-nav',
- classes: 'gl-text-decoration-none! gl-shadow-none! gl-text-body!',
icon: 'users',
display_text: title,
trigger_element: 'side-nav'} }
diff --git a/app/views/shared/nav/_scope_menu.html.haml b/app/views/shared/nav/_scope_menu.html.haml
index 1a7089fb570..4e570086bf8 100644
--- a/app/views/shared/nav/_scope_menu.html.haml
+++ b/app/views/shared/nav/_scope_menu.html.haml
@@ -1,5 +1,5 @@
= nav_link(**scope_menu.active_routes, html_options: scope_menu.nav_link_html_options) do
- = link_to scope_menu.link, **scope_menu.container_html_options, data: { qa_selector: 'sidebar_menu_link', qa_menu_item: scope_qa_menu_item(scope_menu.container) } do
+ = link_to scope_menu.link, **scope_menu.link_html_options, data: { qa_selector: 'sidebar_menu_link', qa_menu_item: scope_qa_menu_item(scope_menu.container) } do
%span{ class: scope_avatar_classes(scope_menu.container) }
= source_icon(scope_menu.container, alt: scope_menu.title, class: ['avatar', 'avatar-tile', 's32'], width: 32, height: 32)
%span.sidebar-context-title
diff --git a/app/views/shared/nav/_sidebar_hidden_menu_item.html.haml b/app/views/shared/nav/_sidebar_hidden_menu_item.html.haml
index 953f7a8ae60..d0ae5e99707 100644
--- a/app/views/shared/nav/_sidebar_hidden_menu_item.html.haml
+++ b/app/views/shared/nav/_sidebar_hidden_menu_item.html.haml
@@ -1,3 +1,3 @@
%li.hidden
- = link_to sidebar_hidden_menu_item.link, **sidebar_hidden_menu_item.container_html_options do
+ = link_to sidebar_hidden_menu_item.link, **sidebar_hidden_menu_item.link_html_options do
= sidebar_hidden_menu_item.title
diff --git a/app/views/shared/nav/_sidebar_menu.html.haml b/app/views/shared/nav/_sidebar_menu.html.haml
index 3f71368aff3..4c4ceb9ea70 100644
--- a/app/views/shared/nav/_sidebar_menu.html.haml
+++ b/app/views/shared/nav/_sidebar_menu.html.haml
@@ -2,7 +2,7 @@
- if sidebar_menu.menu_with_partial?
= render_if_exists sidebar_menu.menu_partial, **sidebar_menu.menu_partial_options
- else
- = link_to sidebar_menu.link, **sidebar_menu.container_html_options, data: { qa_selector: 'sidebar_menu_link', qa_menu_item: sidebar_menu.title } do
+ = link_to sidebar_menu.link, **sidebar_menu.link_html_options, data: { qa_selector: 'sidebar_menu_link', qa_menu_item: sidebar_menu.title } do
- if sidebar_menu.icon_or_image?
%span.nav-icon-container
- if sidebar_menu.image_path
diff --git a/app/views/shared/nav/_sidebar_menu_item.html.haml b/app/views/shared/nav/_sidebar_menu_item.html.haml
index 674ce593ee2..5452cd486da 100644
--- a/app/views/shared/nav/_sidebar_menu_item.html.haml
+++ b/app/views/shared/nav/_sidebar_menu_item.html.haml
@@ -1,5 +1,5 @@
= nav_link(**sidebar_menu_item.active_routes, html_options: sidebar_menu_item.nav_link_html_options) do
- = link_to sidebar_menu_item.link, **sidebar_menu_item.container_html_options, data: { qa_selector: 'sidebar_menu_item_link', qa_menu_item: sidebar_menu_item.title } do
+ = link_to sidebar_menu_item.link, **sidebar_menu_item.link_html_options, data: { qa_selector: 'sidebar_menu_item_link', qa_menu_item: sidebar_menu_item.title } do
%span
= sidebar_menu_item.title
- if sidebar_menu_item.sprite_icon
diff --git a/config/feature_flags/ops/database_async_index_creation.yml b/config/feature_flags/ops/database_async_index_creation.yml
new file mode 100644
index 00000000000..60d491b6073
--- /dev/null
+++ b/config/feature_flags/ops/database_async_index_creation.yml
@@ -0,0 +1,8 @@
+---
+name: database_async_index_creation
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66478
+rollout_issue_url:
+milestone: '14.2'
+type: ops
+group: group::database
+default_enabled: false
diff --git a/doc/administration/gitaly/recovery.md b/doc/administration/gitaly/recovery.md
index 31316693917..e1b9a73908d 100644
--- a/doc/administration/gitaly/recovery.md
+++ b/doc/administration/gitaly/recovery.md
@@ -371,12 +371,13 @@ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.t
### Manually track repositories
-> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5658) in GitLab 14.4.
+> - [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5658) in GitLab 14.4.
+> - [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5789) in GitLab 14.6, support for immediate replication.
The `track-repository` Praefect sub-command adds repositories on disk to the Praefect database to be tracked.
```shell
-sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml track-repository -virtual-storage <virtual-storage> -repository <repository>
+sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml track-repository -virtual-storage <virtual-storage> -repository <repository> -replicate-immediately
```
- `-virtual-storage` is the virtual storage the repository is located in. Virtual storages are configured in `/etc/gitlab/gitlab.rb` under `praefect['virtual_storages]` and looks like the following:
@@ -403,6 +404,8 @@ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.t
- `-authoritative-storage` is the storage we want Praefect to treat as the primary. Required if
[per-repository replication](praefect.md#configure-replication-factor) is set as the replication strategy.
+- `-replicate-immediately`, available in GitLab 14.6 and later, causes the command to replicate the repository to its secondaries immediately.
+ Otherwise, replication jobs are scheduled for execution in the database and are picked up by a Praefect background process.
The command outputs:
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index dd4558b4a3e..2b7d90be631 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -303,3 +303,12 @@ As a workaround, try an alternate mapping:
1. Follow the Azure mapping instructions from above.
1. Delete the `name.formatted` target attribute entry.
1. Change the `displayName` source attribute to have `name.formatted` target attribute.
+
+#### Failed to match an entry in the source and target systems Group 'Group-Name'
+
+Group provisioning in Azure can fail with the `Failed to match an entry in the source and target systems Group 'Group-Name'` error message,
+and the error response can include a HTML result of the GitLab URL `https://gitlab.com/users/sign_in`.
+
+This error is harmless and occurs because Group provisioning was turned on but GitLab SCIM integration does not support it nor require it. To
+remove the error, follow the instructions in the Azure configuration guide to disable the option
+[`Synchronize Azure Active Directory Groups to AppName`](#azure-configuration-steps).
diff --git a/lib/gitlab/background_migration/add_merge_request_diff_commits_count.rb b/lib/gitlab/background_migration/add_merge_request_diff_commits_count.rb
deleted file mode 100644
index 5b9ee8a0ee2..00000000000
--- a/lib/gitlab/background_migration/add_merge_request_diff_commits_count.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class AddMergeRequestDiffCommitsCount
- class MergeRequestDiff < ActiveRecord::Base
- self.table_name = 'merge_request_diffs'
- end
-
- def perform(start_id, stop_id)
- Gitlab::AppLogger.info("Setting commits_count for merge request diffs: #{start_id} - #{stop_id}")
-
- update = '
- commits_count = (
- SELECT count(*)
- FROM merge_request_diff_commits
- WHERE merge_request_diffs.id = merge_request_diff_commits.merge_request_diff_id
- )'.squish
-
- MergeRequestDiff.where(id: start_id..stop_id).where(commits_count: nil).update_all(update)
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule.rb b/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule.rb
deleted file mode 100644
index 2148e96f6b4..00000000000
--- a/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Compare all current rules to project rules
- class AddModifiedToApprovalMergeRequestRule
- # Stubbed class to access the Group table
- class Group < ActiveRecord::Base
- self.table_name = 'namespaces'
- self.inheritance_column = :_type_disabled
- end
-
- # Stubbed class to access the ApprovalMergeRequestRule table
- class ApprovalMergeRequestRule < ActiveRecord::Base
- self.table_name = 'approval_merge_request_rules'
-
- has_one :approval_merge_request_rule_source, class_name: 'AddModifiedToApprovalMergeRequestRule::ApprovalMergeRequestRuleSource'
- has_one :approval_project_rule, through: :approval_merge_request_rule_source
- has_and_belongs_to_many :groups,
- class_name: 'AddModifiedToApprovalMergeRequestRule::Group', join_table: "#{self.table_name}_groups"
- end
-
- # Stubbed class to access the ApprovalProjectRule table
- class ApprovalProjectRule < ActiveRecord::Base
- self.table_name = 'approval_project_rules'
-
- has_many :approval_merge_request_rule_sources, class_name: 'AddModifiedToApprovalMergeRequestRule::ApprovalMergeRequestRuleSource'
- has_and_belongs_to_many :groups,
- class_name: 'AddModifiedToApprovalMergeRequestRule::Group', join_table: "#{self.table_name}_groups"
- end
-
- # Stubbed class to access the ApprovalMergeRequestRuleSource table
- class ApprovalMergeRequestRuleSource < ActiveRecord::Base
- self.table_name = 'approval_merge_request_rule_sources'
-
- belongs_to :approval_merge_request_rule, class_name: 'AddModifiedToApprovalMergeRequestRule::ApprovalMergeRequestRule'
- belongs_to :approval_project_rule, class_name: 'AddModifiedToApprovalMergeRequestRule::ApprovalProjectRule'
- end
-
- def perform(start_id, stop_id)
- approval_merge_requests_rules = ApprovalMergeRequestRule
- .joins(:groups, :approval_merge_request_rule_source)
- .where(id: start_id..stop_id)
- .pluck(
- 'approval_merge_request_rule_sources.id as ars_id',
- 'approval_merge_request_rules_groups.id as amrg_id'
- )
-
- approval_project_rules = ApprovalProjectRule
- .joins(:groups, approval_merge_request_rule_sources: :approval_merge_request_rule)
- .where(approval_merge_request_rules: { id: start_id..stop_id })
- .pluck(
- 'approval_merge_request_rule_sources.id as ars_id',
- 'approval_project_rules_groups.id as apg_id'
- )
-
- different_names_or_approval_sources = ApprovalMergeRequestRule.joins(:approval_project_rule, :approval_merge_request_rule_source)
- .where(id: start_id..stop_id)
- .where('approval_merge_request_rules.name != approval_project_rules.name OR ' \
- 'approval_merge_request_rules.approvals_required != approval_project_rules.approvals_required')
- .pluck('approval_merge_request_rule_sources.id as ars_id')
-
- intersected_set = approval_merge_requests_rules.to_set ^ approval_project_rules.to_set
- source_ids = intersected_set.collect { |rule| rule[0] }.uniq
-
- rule_sources = ApprovalMergeRequestRuleSource.where(id: source_ids + different_names_or_approval_sources)
- changed_merge_request_rules = ApprovalMergeRequestRule.where(id: rule_sources.select(:approval_merge_request_rule_id))
-
- changed_merge_request_rules.update_all(modified_from_project_rule: true)
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments.rb b/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments.rb
deleted file mode 100644
index 9778f360e87..00000000000
--- a/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Backfill deployment_clusters for a range of deployments
- class BackfillDeploymentClustersFromDeployments
- def perform(start_id, end_id)
- ActiveRecord::Base.connection.execute <<~SQL
- INSERT INTO deployment_clusters (deployment_id, cluster_id)
- SELECT deployments.id, deployments.cluster_id
- FROM deployments
- WHERE deployments.cluster_id IS NOT NULL
- AND deployments.id BETWEEN #{start_id} AND #{end_id}
- ON CONFLICT DO NOTHING
- SQL
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests.rb b/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests.rb
deleted file mode 100644
index 4fd3b81fda3..00000000000
--- a/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # BackfillEnvironmentIdDeploymentMergeRequests deletes duplicates
- # from deployment_merge_requests table and backfills environment_id
- class BackfillEnvironmentIdDeploymentMergeRequests
- def perform(_start_mr_id, _stop_mr_id)
- # no-op
-
- # Background migration removed due to
- # https://gitlab.com/gitlab-org/gitlab/-/issues/217191
- end
-
- def backfill_range(start_mr_id, stop_mr_id)
- start_mr_id = Integer(start_mr_id)
- stop_mr_id = Integer(stop_mr_id)
-
- ActiveRecord::Base.connection.execute(<<~SQL)
- DELETE FROM deployment_merge_requests
- WHERE (deployment_id, merge_request_id) in (
- SELECT t.deployment_id, t.merge_request_id FROM (
- SELECT mrd.merge_request_id, mrd.deployment_id, ROW_NUMBER() OVER w AS rnum
- FROM deployment_merge_requests as mrd
- INNER JOIN "deployments" ON "deployments"."id" = "mrd"."deployment_id"
- WHERE mrd.merge_request_id BETWEEN #{start_mr_id} AND #{stop_mr_id}
- WINDOW w AS (
- PARTITION BY merge_request_id, deployments.environment_id
- ORDER BY deployments.id
- )
- ) t
- WHERE t.rnum > 1
- );
- SQL
-
- ActiveRecord::Base.connection.execute(<<~SQL)
- UPDATE deployment_merge_requests
- SET environment_id = deployments.environment_id
- FROM deployments
- WHERE deployments.id = "deployment_merge_requests".deployment_id
- AND "deployment_merge_requests".environment_id IS NULL
- AND "deployment_merge_requests".merge_request_id BETWEEN #{start_mr_id} AND #{stop_mr_id}
- SQL
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules.rb b/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules.rb
deleted file mode 100644
index 8a58cf9b302..00000000000
--- a/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Backfill merge request cleanup schedules of closed/merged merge requests
- # without any corresponding records.
- class BackfillMergeRequestCleanupSchedules
- # Model used for migration added in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46782.
- class MergeRequest < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'merge_requests'
-
- def self.eligible
- where('merge_requests.state_id IN (2, 3)')
- end
- end
-
- def perform(start_id, end_id)
- eligible_mrs = MergeRequest.eligible.where(id: start_id..end_id)
- scheduled_at_column = "COALESCE(metrics.merged_at, COALESCE(metrics.latest_closed_at, merge_requests.updated_at)) + interval '14 days'"
- query =
- eligible_mrs
- .select("merge_requests.id, #{scheduled_at_column}, NOW(), NOW()")
- .joins('LEFT JOIN merge_request_metrics metrics ON metrics.merge_request_id = merge_requests.id')
-
- result = ActiveRecord::Base.connection.execute <<~SQL
- INSERT INTO merge_request_cleanup_schedules (merge_request_id, scheduled_at, created_at, updated_at)
- #{query.to_sql}
- ON CONFLICT (merge_request_id) DO NOTHING;
- SQL
-
- ::Gitlab::BackgroundMigration::Logger.info(
- message: 'Backfilled merge_request_cleanup_schedules records',
- count: result.cmd_tuples
- )
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/backfill_namespace_settings.rb b/lib/gitlab/background_migration/backfill_namespace_settings.rb
deleted file mode 100644
index a391d5f4ebe..00000000000
--- a/lib/gitlab/background_migration/backfill_namespace_settings.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Backfillnamespace_settings for a range of namespaces
- class BackfillNamespaceSettings
- def perform(start_id, end_id)
- ActiveRecord::Base.connection.execute <<~SQL
- INSERT INTO namespace_settings (namespace_id, created_at, updated_at)
- SELECT namespaces.id, now(), now()
- FROM namespaces
- WHERE namespaces.id BETWEEN #{start_id} AND #{end_id}
- ON CONFLICT (namespace_id) DO NOTHING;
- SQL
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/backfill_project_settings.rb b/lib/gitlab/background_migration/backfill_project_settings.rb
deleted file mode 100644
index 7d7f19e1fda..00000000000
--- a/lib/gitlab/background_migration/backfill_project_settings.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Backfill project_settings for a range of projects
- class BackfillProjectSettings
- def perform(start_id, end_id)
- ActiveRecord::Base.connection.execute <<~SQL
- INSERT INTO project_settings (project_id, created_at, updated_at)
- SELECT projects.id, now(), now()
- FROM projects
- WHERE projects.id BETWEEN #{start_id} AND #{end_id}
- ON CONFLICT (project_id) DO NOTHING;
- SQL
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/backfill_push_rules_id_in_projects.rb b/lib/gitlab/background_migration/backfill_push_rules_id_in_projects.rb
deleted file mode 100644
index 9b9ef70424a..00000000000
--- a/lib/gitlab/background_migration/backfill_push_rules_id_in_projects.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Class that will insert record into project_push_rules
- # for each existing push_rule
- class BackfillPushRulesIdInProjects
- # Temporary AR table for push rules
- class ProjectSetting < ActiveRecord::Base
- self.table_name = 'project_settings'
- end
-
- def perform(start_id, stop_id)
- ProjectSetting.connection.execute(<<~SQL)
- UPDATE project_settings ps1
- SET push_rule_id = pr.id
- FROM project_settings ps2
- INNER JOIN push_rules pr
- ON ps2.project_id = pr.project_id
- WHERE pr.is_sample = false
- AND pr.id BETWEEN #{start_id} AND #{stop_id}
- AND ps1.project_id = ps2.project_id
- SQL
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids.rb b/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids.rb
deleted file mode 100644
index 1a80ccdee92..00000000000
--- a/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This migration updates discussion ids for epics that were promoted from issue so that the discussion id on epics
- # is different from discussion id on issue, which was causing problems when replying to epic discussions as it would
- # identify the discussion as related to an issue and complaint about missing project_id
- class FixPromotedEpicsDiscussionIds
- # notes model to iterate through the notes to be updated
- class Note < ActiveRecord::Base
- self.table_name = 'notes'
- self.inheritance_column = :_type_disabled
- end
-
- def perform(discussion_ids)
- Note.where(noteable_type: 'Epic')
- .where(discussion_id: discussion_ids)
- .update_all("discussion_id=MD5(discussion_id)||substring(discussion_id from 1 for 8)")
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/fix_user_namespace_names.rb b/lib/gitlab/background_migration/fix_user_namespace_names.rb
deleted file mode 100644
index cd5b4ab103d..00000000000
--- a/lib/gitlab/background_migration/fix_user_namespace_names.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This migration fixes the namespaces.name for all user-namespaces that have names
- # that aren't equal to the users name.
- # Then it uses the updated names of the namespaces to update the associated routes
- # For more info see https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/23272
- class FixUserNamespaceNames
- def perform(from_id, to_id)
- fix_namespace_names(from_id, to_id)
- fix_namespace_route_names(from_id, to_id)
- end
-
- def fix_namespace_names(from_id, to_id)
- ActiveRecord::Base.connection.execute <<~UPDATE_NAMESPACES
- WITH namespaces_to_update AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
- SELECT
- namespaces.id,
- users.name AS correct_name
- FROM
- namespaces
- INNER JOIN users ON namespaces.owner_id = users.id
- WHERE
- namespaces.type IS NULL
- AND namespaces.id BETWEEN #{from_id} AND #{to_id}
- AND namespaces.name != users.name
- )
- UPDATE
- namespaces
- SET
- name = correct_name
- FROM
- namespaces_to_update
- WHERE
- namespaces.id = namespaces_to_update.id
- UPDATE_NAMESPACES
- end
-
- def fix_namespace_route_names(from_id, to_id)
- ActiveRecord::Base.connection.execute <<~ROUTES_UPDATE
- WITH routes_to_update AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
- SELECT
- routes.id,
- users.name AS correct_name
- FROM
- routes
- INNER JOIN namespaces ON routes.source_id = namespaces.id
- INNER JOIN users ON namespaces.owner_id = users.id
- WHERE
- namespaces.type IS NULL
- AND routes.source_type = 'Namespace'
- AND namespaces.id BETWEEN #{from_id} AND #{to_id}
- AND (routes.name != users.name OR routes.name IS NULL)
- )
- UPDATE
- routes
- SET
- name = correct_name
- FROM
- routes_to_update
- WHERE
- routes_to_update.id = routes.id
- ROUTES_UPDATE
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/fix_user_project_route_names.rb b/lib/gitlab/background_migration/fix_user_project_route_names.rb
deleted file mode 100644
index e534f2449aa..00000000000
--- a/lib/gitlab/background_migration/fix_user_project_route_names.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This migration fixes the routes.name for all user-projects that have names
- # that don't start with the users name.
- # For more info see https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/23272
- class FixUserProjectRouteNames
- def perform(from_id, to_id)
- ActiveRecord::Base.connection.execute <<~ROUTES_UPDATE
- WITH routes_to_update AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
- SELECT
- routes.id,
- users.name || ' / ' || projects.name AS correct_name
- FROM
- routes
- INNER JOIN projects ON routes.source_id = projects.id
- INNER JOIN namespaces ON projects.namespace_id = namespaces.id
- INNER JOIN users ON namespaces.owner_id = users.id
- WHERE
- routes.source_type = 'Project'
- AND routes.id BETWEEN #{from_id} AND #{to_id}
- AND namespaces.type IS NULL
- AND (routes.name NOT LIKE users.name || '%' OR routes.name IS NULL)
- )
- UPDATE
- routes
- SET
- name = routes_to_update.correct_name
- FROM
- routes_to_update
- WHERE
- routes_to_update.id = routes.id
- ROUTES_UPDATE
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/link_lfs_objects_projects.rb b/lib/gitlab/background_migration/link_lfs_objects_projects.rb
deleted file mode 100644
index 983470c5121..00000000000
--- a/lib/gitlab/background_migration/link_lfs_objects_projects.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Create missing LfsObjectsProject records for forks
- class LinkLfsObjectsProjects
- # Model specifically used for migration.
- class LfsObjectsProject < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'lfs_objects_projects'
-
- def self.linkable
- where(
- <<~SQL
- lfs_objects_projects.project_id IN (
- SELECT fork_network_members.forked_from_project_id
- FROM fork_network_members
- WHERE fork_network_members.forked_from_project_id IS NOT NULL
- )
- SQL
- )
- end
- end
-
- # Model specifically used for migration.
- class ForkNetworkMember < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'fork_network_members'
-
- def self.without_lfs_object(lfs_object_id)
- where(
- <<~SQL
- fork_network_members.project_id NOT IN (
- SELECT lop.project_id
- FROM lfs_objects_projects lop
- WHERE lop.lfs_object_id = #{lfs_object_id}
- )
- SQL
- )
- end
- end
-
- BATCH_SIZE = 1000
-
- def perform(start_id, end_id)
- lfs_objects_projects =
- Gitlab::BackgroundMigration::LinkLfsObjectsProjects::LfsObjectsProject
- .linkable
- .where(id: start_id..end_id)
-
- return if lfs_objects_projects.empty?
-
- lfs_objects_projects.find_each do |lop|
- ForkNetworkMember
- .select("#{lop.lfs_object_id}, fork_network_members.project_id, NOW(), NOW()")
- .without_lfs_object(lop.lfs_object_id)
- .where(forked_from_project_id: lop.project_id)
- .each_batch(of: BATCH_SIZE) do |batch, index|
- execute <<~SQL
- INSERT INTO lfs_objects_projects (lfs_object_id, project_id, created_at, updated_at)
- #{batch.to_sql}
- SQL
-
- logger.info(message: "LinkLfsObjectsProjects: created missing LfsObjectsProject records for LfsObject #{lop.lfs_object_id}")
- end
- end
- end
-
- private
-
- def execute(sql)
- ::ActiveRecord::Base.connection.execute(sql)
- end
-
- def logger
- @logger ||= Gitlab::BackgroundMigration::Logger.build
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys.rb b/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys.rb
deleted file mode 100644
index 36a339c6b80..00000000000
--- a/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This class is responsible to update all sha256 fingerprints within the keys table
- class MigrateFingerprintSha256WithinKeys
- # Temporary AR table for keys
- class Key < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'keys'
- self.inheritance_column = :_type_disabled
- end
-
- TEMP_TABLE = 'tmp_fingerprint_sha256_migration'
-
- def perform(start_id, stop_id)
- ActiveRecord::Base.transaction do
- execute(<<~SQL)
- CREATE TEMPORARY TABLE #{TEMP_TABLE}
- (id bigint primary key, fingerprint_sha256 bytea not null)
- ON COMMIT DROP
- SQL
-
- fingerprints = []
- Key.where(id: start_id..stop_id, fingerprint_sha256: nil).find_each do |regular_key|
- if fingerprint = generate_ssh_public_key(regular_key.key)
- bytea = ActiveRecord::Base.connection.escape_bytea(Base64.decode64(fingerprint))
-
- fingerprints << {
- id: regular_key.id,
- fingerprint_sha256: bytea
- }
- end
- end
-
- ApplicationRecord.legacy_bulk_insert(TEMP_TABLE, fingerprints) # rubocop:disable Gitlab/BulkInsert
-
- execute("ANALYZE #{TEMP_TABLE}")
-
- execute(<<~SQL)
- UPDATE keys
- SET fingerprint_sha256 = t.fingerprint_sha256
- FROM #{TEMP_TABLE} t
- WHERE keys.id = t.id
- SQL
- end
- end
-
- private
-
- def generate_ssh_public_key(regular_key)
- Gitlab::SSHPublicKey.new(regular_key).fingerprint("SHA256")&.gsub("SHA256:", "")
- end
-
- def execute(query)
- ActiveRecord::Base.connection.execute(query)
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/migrate_pages_metadata.rb b/lib/gitlab/background_migration/migrate_pages_metadata.rb
deleted file mode 100644
index 68fd0c17d29..00000000000
--- a/lib/gitlab/background_migration/migrate_pages_metadata.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Class that will insert record into project_pages_metadata
- # for each existing project
- class MigratePagesMetadata
- def perform(start_id, stop_id)
- perform_on_relation(Project.where(id: start_id..stop_id))
- end
-
- def perform_on_relation(relation)
- successful_pages_deploy = <<~SQL
- SELECT TRUE
- FROM ci_builds
- WHERE ci_builds.type = 'GenericCommitStatus'
- AND ci_builds.status = 'success'
- AND ci_builds.stage = 'deploy'
- AND ci_builds.name = 'pages:deploy'
- AND ci_builds.project_id = projects.id
- LIMIT 1
- SQL
-
- select_from = relation
- .select("projects.id", "COALESCE((#{successful_pages_deploy}), FALSE)")
- .to_sql
-
- ActiveRecord::Base.connection_pool.with_connection do |connection|
- connection.execute <<~SQL
- INSERT INTO project_pages_metadata (project_id, deployed)
- #{select_from}
- ON CONFLICT (project_id) DO NOTHING
- SQL
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/migrate_security_scans.rb b/lib/gitlab/background_migration/migrate_security_scans.rb
deleted file mode 100644
index 0ae984f2dbc..00000000000
--- a/lib/gitlab/background_migration/migrate_security_scans.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # rubocop: disable Style/Documentation
- class MigrateSecurityScans
- def perform(start_id, stop_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::MigrateSecurityScans.prepend_mod_with('Gitlab::BackgroundMigration::MigrateSecurityScans')
diff --git a/lib/gitlab/background_migration/migrate_to_hashed_storage.rb b/lib/gitlab/background_migration/migrate_to_hashed_storage.rb
deleted file mode 100644
index 4054db4fb87..00000000000
--- a/lib/gitlab/background_migration/migrate_to_hashed_storage.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Background migration to move any legacy project to Hashed Storage
- class MigrateToHashedStorage
- def perform
- batch_size = helper.batch_size
- legacy_projects_count = Project.with_unmigrated_storage.count
-
- if storage_migrator.rollback_pending?
- logger.warn(
- migrator: 'MigrateToHashedStorage',
- message: 'Aborting an storage rollback operation currently in progress'
- )
-
- storage_migrator.abort_rollback!
- end
-
- if legacy_projects_count == 0
- logger.info(
- migrator: 'MigrateToHashedStorage',
- message: 'There are no projects requiring migration to Hashed Storage'
- )
-
- return
- end
-
- logger.info(
- migrator: 'MigrateToHashedStorage',
- message: "Enqueuing migration of #{legacy_projects_count} projects in batches of #{batch_size}"
- )
-
- helper.project_id_batches_migration do |start, finish|
- storage_migrator.bulk_schedule_migration(start: start, finish: finish)
-
- logger.info(
- migrator: 'MigrateToHashedStorage',
- message: "Enqueuing migration of projects in batches of #{batch_size} from ID=#{start} to ID=#{finish}",
- batch_from: start,
- batch_to: finish
- )
- end
- end
-
- private
-
- def helper
- Gitlab::HashedStorage::RakeHelper
- end
-
- def storage_migrator
- @storage_migrator ||= Gitlab::HashedStorage::Migrator.new
- end
-
- def logger
- @logger ||= ::Gitlab::BackgroundMigration::Logger.build
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/move_epic_issues_after_epics.rb b/lib/gitlab/background_migration/move_epic_issues_after_epics.rb
deleted file mode 100644
index 174994c7862..00000000000
--- a/lib/gitlab/background_migration/move_epic_issues_after_epics.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # rubocop: disable Style/Documentation
- class MoveEpicIssuesAfterEpics
- def perform(start_id, stop_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::MoveEpicIssuesAfterEpics.prepend_mod_with('Gitlab::BackgroundMigration::MoveEpicIssuesAfterEpics')
diff --git a/lib/gitlab/background_migration/populate_any_approval_rule_for_merge_requests.rb b/lib/gitlab/background_migration/populate_any_approval_rule_for_merge_requests.rb
deleted file mode 100644
index 890a43800c9..00000000000
--- a/lib/gitlab/background_migration/populate_any_approval_rule_for_merge_requests.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This background migration creates any approver rule records according
- # to the given merge request IDs range. A _single_ INSERT is issued for the given range.
- class PopulateAnyApprovalRuleForMergeRequests
- def perform(from_id, to_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::PopulateAnyApprovalRuleForMergeRequests.prepend_mod_with('Gitlab::BackgroundMigration::PopulateAnyApprovalRuleForMergeRequests')
diff --git a/lib/gitlab/background_migration/populate_any_approval_rule_for_projects.rb b/lib/gitlab/background_migration/populate_any_approval_rule_for_projects.rb
deleted file mode 100644
index ac7ed18ba14..00000000000
--- a/lib/gitlab/background_migration/populate_any_approval_rule_for_projects.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This background migration creates any approver rule records according
- # to the given project IDs range. A _single_ INSERT is issued for the given range.
- class PopulateAnyApprovalRuleForProjects
- def perform(from_id, to_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::PopulateAnyApprovalRuleForProjects.prepend_mod_with('Gitlab::BackgroundMigration::PopulateAnyApprovalRuleForProjects')
diff --git a/lib/gitlab/background_migration/populate_canonical_emails.rb b/lib/gitlab/background_migration/populate_canonical_emails.rb
deleted file mode 100644
index 052e75c5655..00000000000
--- a/lib/gitlab/background_migration/populate_canonical_emails.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Class to populate new rows of UserCanonicalEmail based on existing email addresses
- class PopulateCanonicalEmails
- def perform(start_id, stop_id)
- ActiveRecord::Base.connection.execute <<~SQL
- INSERT INTO
- user_canonical_emails (
- user_id,
- canonical_email,
- created_at,
- updated_at
- )
- SELECT users.id AS user_id,
- concat(translate(split_part(split_part(users.email, '@', 1), '+', 1), '.', ''), '@gmail.com') AS canonical_email,
- NOW() AS created_at,
- NOW() AS updated_at
- FROM users
- WHERE users.email ILIKE '%@gmail.com'
- AND users.id BETWEEN #{start_id} AND #{stop_id}
- ON CONFLICT DO NOTHING;
- SQL
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities.rb b/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities.rb
deleted file mode 100644
index 68c91650d93..00000000000
--- a/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This class updates vulnerabilities entities with state dismissed
- class PopulateDismissedStateForVulnerabilities
- class Vulnerability < ActiveRecord::Base # rubocop:disable Style/Documentation
- self.table_name = 'vulnerabilities'
- end
-
- def perform(*vulnerability_ids)
- Vulnerability.where(id: vulnerability_ids).update_all(state: 2)
- PopulateMissingVulnerabilityDismissalInformation.new.perform(*vulnerability_ids)
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/populate_has_vulnerabilities.rb b/lib/gitlab/background_migration/populate_has_vulnerabilities.rb
deleted file mode 100644
index 28ff2070209..00000000000
--- a/lib/gitlab/background_migration/populate_has_vulnerabilities.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This class populates missing dismissal information for
- # vulnerability entries.
- class PopulateHasVulnerabilities
- class ProjectSetting < ActiveRecord::Base # rubocop:disable Style/Documentation
- self.table_name = 'project_settings'
-
- def self.upsert_for(project_ids)
- connection.execute(upsert_sql % { project_ids: project_ids.join(', ') })
- end
-
- def self.upsert_sql
- <<~SQL
- WITH upsert_data (project_id, has_vulnerabilities, created_at, updated_at) AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
- SELECT projects.id, true, current_timestamp, current_timestamp FROM projects WHERE projects.id IN (%{project_ids})
- )
- INSERT INTO project_settings
- (project_id, has_vulnerabilities, created_at, updated_at)
- (SELECT * FROM upsert_data)
- ON CONFLICT (project_id)
- DO UPDATE SET
- has_vulnerabilities = true,
- updated_at = EXCLUDED.updated_at
- SQL
- end
- end
-
- class Vulnerability < ActiveRecord::Base # rubocop:disable Style/Documentation
- include EachBatch
-
- self.table_name = 'vulnerabilities'
- end
-
- def perform(*project_ids)
- ProjectSetting.upsert_for(project_ids)
- rescue StandardError => e
- log_error(e, project_ids)
- ensure
- log_info(project_ids)
- end
-
- private
-
- def log_error(error, project_ids)
- ::Gitlab::BackgroundMigration::Logger.error(
- migrator: self.class.name,
- message: error.message,
- project_ids: project_ids
- )
- end
-
- def log_info(project_ids)
- ::Gitlab::BackgroundMigration::Logger.info(
- migrator: self.class.name,
- message: 'Projects has been processed to populate `has_vulnerabilities` information',
- count: project_ids.length
- )
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/populate_merge_request_assignees_table.rb b/lib/gitlab/background_migration/populate_merge_request_assignees_table.rb
deleted file mode 100644
index 28cc4a5e3fa..00000000000
--- a/lib/gitlab/background_migration/populate_merge_request_assignees_table.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This background migration creates records on merge_request_assignees according
- # to the given merge request IDs range. A _single_ INSERT is issued for the given range.
- # This is required for supporting multiple assignees on merge requests.
- class PopulateMergeRequestAssigneesTable
- def perform(from_id, to_id)
- select_sql =
- MergeRequest
- .where(merge_request_assignees_not_exists_clause)
- .where(id: from_id..to_id)
- .where.not(assignee_id: nil)
- .select(:id, :assignee_id)
- .to_sql
-
- execute("INSERT INTO merge_request_assignees (merge_request_id, user_id) #{select_sql}")
- end
-
- def perform_all_sync(batch_size:)
- MergeRequest.each_batch(of: batch_size) do |batch|
- range = batch.pluck('MIN(id)', 'MAX(id)').first
-
- perform(*range)
- end
- end
-
- private
-
- def merge_request_assignees_not_exists_clause
- <<~SQL
- NOT EXISTS (SELECT 1 FROM merge_request_assignees
- WHERE merge_request_assignees.merge_request_id = merge_requests.id)
- SQL
- end
-
- def execute(sql)
- @connection ||= ActiveRecord::Base.connection
- @connection.execute(sql)
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information.rb b/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information.rb
deleted file mode 100644
index 04342fdabd4..00000000000
--- a/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This class populates missing dismissal information for
- # vulnerability entries.
- class PopulateMissingVulnerabilityDismissalInformation
- class Vulnerability < ActiveRecord::Base # rubocop:disable Style/Documentation
- include EachBatch
-
- self.table_name = 'vulnerabilities'
-
- has_one :finding, class_name: '::Gitlab::BackgroundMigration::PopulateMissingVulnerabilityDismissalInformation::Finding'
-
- scope :broken, -> { where('state = 2 AND (dismissed_at IS NULL OR dismissed_by_id IS NULL)') }
-
- def copy_dismissal_information
- return unless finding&.dismissal_feedback
-
- update_columns(
- dismissed_at: finding.dismissal_feedback.created_at,
- dismissed_by_id: finding.dismissal_feedback.author_id
- )
- end
- end
-
- class Finding < ActiveRecord::Base # rubocop:disable Style/Documentation
- include ShaAttribute
- include ::Gitlab::Utils::StrongMemoize
-
- self.table_name = 'vulnerability_occurrences'
-
- sha_attribute :project_fingerprint
-
- def dismissal_feedback
- strong_memoize(:dismissal_feedback) do
- Feedback.dismissal.where(category: report_type, project_fingerprint: project_fingerprint, project_id: project_id).first
- end
- end
- end
-
- class Feedback < ActiveRecord::Base # rubocop:disable Style/Documentation
- DISMISSAL_TYPE = 0
-
- self.table_name = 'vulnerability_feedback'
-
- scope :dismissal, -> { where(feedback_type: DISMISSAL_TYPE) }
- end
-
- def perform(*vulnerability_ids)
- Vulnerability.includes(:finding).where(id: vulnerability_ids).each { |vulnerability| populate_for(vulnerability) }
-
- log_info(vulnerability_ids)
- end
-
- private
-
- def populate_for(vulnerability)
- log_warning(vulnerability) unless vulnerability.copy_dismissal_information
- rescue StandardError => error
- log_error(error, vulnerability)
- end
-
- def log_info(vulnerability_ids)
- ::Gitlab::BackgroundMigration::Logger.info(
- migrator: self.class.name,
- message: 'Dismissal information has been copied',
- count: vulnerability_ids.length
- )
- end
-
- def log_warning(vulnerability)
- ::Gitlab::BackgroundMigration::Logger.warn(
- migrator: self.class.name,
- message: 'Could not update vulnerability!',
- vulnerability_id: vulnerability.id
- )
- end
-
- def log_error(error, vulnerability)
- ::Gitlab::BackgroundMigration::Logger.error(
- migrator: self.class.name,
- message: error.message,
- vulnerability_id: vulnerability.id
- )
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/populate_personal_snippet_statistics.rb b/lib/gitlab/background_migration/populate_personal_snippet_statistics.rb
deleted file mode 100644
index ed7ffce8018..00000000000
--- a/lib/gitlab/background_migration/populate_personal_snippet_statistics.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This class creates/updates those personal snippets statistics
- # that haven't been created nor initialized.
- # It also updates the related root storage namespace stats
- class PopulatePersonalSnippetStatistics
- def perform(snippet_ids)
- personal_snippets(snippet_ids).group_by(&:author).each do |author, author_snippets|
- upsert_snippet_statistics(author_snippets)
- update_namespace_statistics(author.namespace)
- end
- end
-
- private
-
- def personal_snippets(snippet_ids)
- PersonalSnippet
- .where(id: snippet_ids)
- .includes(author: :namespace)
- .includes(:statistics)
- .includes(snippet_repository: :shard)
- end
-
- def upsert_snippet_statistics(snippets)
- snippets.each do |snippet|
- response = Snippets::UpdateStatisticsService.new(snippet).execute
-
- error_message("#{response.message} snippet: #{snippet.id}") if response.error?
- end
- end
-
- def update_namespace_statistics(namespace)
- Namespaces::StatisticsRefresherService.new.execute(namespace)
- rescue StandardError => e
- error_message("Error updating statistics for namespace #{namespace.id}: #{e.message}")
- end
-
- def logger
- @logger ||= Gitlab::BackgroundMigration::Logger.build
- end
-
- def error_message(message)
- logger.error(message: "Snippet Statistics Migration: #{message}")
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/populate_project_snippet_statistics.rb b/lib/gitlab/background_migration/populate_project_snippet_statistics.rb
deleted file mode 100644
index 37af320f044..00000000000
--- a/lib/gitlab/background_migration/populate_project_snippet_statistics.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This class creates/updates those project snippets statistics
- # that haven't been created nor initialized.
- # It also updates the related project statistics and its root storage namespace stats
- class PopulateProjectSnippetStatistics
- def perform(snippet_ids)
- project_snippets(snippet_ids).group_by(&:namespace_id).each do |namespace_id, namespace_snippets|
- namespace_snippets.group_by(&:project).each do |project, snippets|
- upsert_snippet_statistics(snippets)
- update_project_statistics(project)
- rescue StandardError
- error_message("Error updating statistics for project #{project.id}")
- end
-
- update_namespace_statistics(namespace_snippets.first.project.root_namespace)
- rescue StandardError => e
- error_message("Error updating statistics for namespace #{namespace_id}: #{e.message}")
- end
- end
-
- private
-
- def project_snippets(snippet_ids)
- ProjectSnippet
- .select('snippets.*, projects.namespace_id')
- .where(id: snippet_ids)
- .joins(:project)
- .includes(:statistics)
- .includes(snippet_repository: :shard)
- .includes(project: [:route, :statistics, :namespace])
- end
-
- def upsert_snippet_statistics(snippets)
- snippets.each do |snippet|
- response = Snippets::UpdateStatisticsService.new(snippet).execute
-
- error_message("#{response.message} snippet: #{snippet.id}") if response.error?
- end
- end
-
- def logger
- @logger ||= Gitlab::BackgroundMigration::Logger.build
- end
-
- def error_message(message)
- logger.error(message: "Snippet Statistics Migration: #{message}")
- end
-
- def update_project_statistics(project)
- project.statistics&.refresh!(only: [:snippets_size])
- end
-
- def update_namespace_statistics(namespace)
- Namespaces::StatisticsRefresherService.new.execute(namespace)
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/populate_vulnerability_feedback_pipeline_id.rb b/lib/gitlab/background_migration/populate_vulnerability_feedback_pipeline_id.rb
deleted file mode 100644
index 8241fea66db..00000000000
--- a/lib/gitlab/background_migration/populate_vulnerability_feedback_pipeline_id.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This class updates vulnerability feedback entities with no pipeline id assigned.
- class PopulateVulnerabilityFeedbackPipelineId
- def perform(project_ids)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::PopulateVulnerabilityFeedbackPipelineId.prepend_mod_with('Gitlab::BackgroundMigration::PopulateVulnerabilityFeedbackPipelineId')
diff --git a/lib/gitlab/background_migration/populate_vulnerability_historical_statistics.rb b/lib/gitlab/background_migration/populate_vulnerability_historical_statistics.rb
deleted file mode 100644
index 9a9f23e29ea..00000000000
--- a/lib/gitlab/background_migration/populate_vulnerability_historical_statistics.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This class creates/updates those project historical vulnerability statistics
- # that haven't been created nor initialized. It should only be executed in EE.
- class PopulateVulnerabilityHistoricalStatistics
- def perform(project_ids, retention_period = 90)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::PopulateVulnerabilityHistoricalStatistics.prepend_mod_with('Gitlab::BackgroundMigration::PopulateVulnerabilityHistoricalStatistics')
diff --git a/lib/gitlab/background_migration/prune_orphaned_geo_events.rb b/lib/gitlab/background_migration/prune_orphaned_geo_events.rb
deleted file mode 100644
index 0efbe72775c..00000000000
--- a/lib/gitlab/background_migration/prune_orphaned_geo_events.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-#
-# rubocop:disable Style/Documentation
-
-# This job is added to fix https://gitlab.com/gitlab-org/gitlab/issues/30229
-# It's not used anywhere else.
-# Can be removed in GitLab 13.*
-module Gitlab
- module BackgroundMigration
- class PruneOrphanedGeoEvents
- def perform(table_name)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::PruneOrphanedGeoEvents.prepend_mod_with('Gitlab::BackgroundMigration::PruneOrphanedGeoEvents')
diff --git a/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id.rb b/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id.rb
deleted file mode 100644
index b66fdfd5c65..00000000000
--- a/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # rubocop:disable Style/Documentation
- class RecalculateProjectAuthorizationsWithMinMaxUserId
- def perform(min_user_id, max_user_id)
- User.where(id: min_user_id..max_user_id).find_each do |user|
- service = Users::RefreshAuthorizedProjectsService.new(
- user,
- incorrect_auth_found_callback:
- ->(project_id, access_level) do
- logger.info(message: 'Removing ProjectAuthorizations',
- user_id: user.id,
- project_id: project_id,
- access_level: access_level)
- end,
- missing_auth_found_callback:
- ->(project_id, access_level) do
- logger.info(message: 'Creating ProjectAuthorizations',
- user_id: user.id,
- project_id: project_id,
- access_level: access_level)
- end
- )
-
- service.execute
- end
- end
-
- private
-
- def logger
- @logger ||= Gitlab::BackgroundMigration::Logger.build
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/remove_duplicate_cs_findings.rb b/lib/gitlab/background_migration/remove_duplicate_cs_findings.rb
deleted file mode 100644
index 17ef6dec4c0..00000000000
--- a/lib/gitlab/background_migration/remove_duplicate_cs_findings.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class RemoveDuplicateCsFindings
- def perform(start_id, stop_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::RemoveDuplicateCsFindings.prepend_mod_with('Gitlab::BackgroundMigration::RemoveDuplicateCsFindings')
diff --git a/lib/gitlab/background_migration/remove_duplicated_cs_findings_without_vulnerability_id.rb b/lib/gitlab/background_migration/remove_duplicated_cs_findings_without_vulnerability_id.rb
deleted file mode 100644
index e5772fc7375..00000000000
--- a/lib/gitlab/background_migration/remove_duplicated_cs_findings_without_vulnerability_id.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class RemoveDuplicatedCsFindingsWithoutVulnerabilityId
- def perform(start_id, stop_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::RemoveDuplicatedCsFindingsWithoutVulnerabilityId.prepend_mod_with('Gitlab::BackgroundMigration::RemoveDuplicatedCsFindingsWithoutVulnerabilityId')
diff --git a/lib/gitlab/background_migration/remove_inaccessible_epic_todos.rb b/lib/gitlab/background_migration/remove_inaccessible_epic_todos.rb
deleted file mode 100644
index cb6a600a525..00000000000
--- a/lib/gitlab/background_migration/remove_inaccessible_epic_todos.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # rubocop:disable Style/Documentation
- class RemoveInaccessibleEpicTodos
- def perform(start_id, stop_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::RemoveInaccessibleEpicTodos.prepend_mod_with('Gitlab::BackgroundMigration::RemoveInaccessibleEpicTodos')
diff --git a/lib/gitlab/background_migration/remove_undefined_vulnerability_confidence_level.rb b/lib/gitlab/background_migration/remove_undefined_vulnerability_confidence_level.rb
deleted file mode 100644
index 4be61bfb689..00000000000
--- a/lib/gitlab/background_migration/remove_undefined_vulnerability_confidence_level.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class RemoveUndefinedVulnerabilityConfidenceLevel
- def perform(start_id, stop_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::RemoveUndefinedVulnerabilityConfidenceLevel.prepend_mod_with('Gitlab::BackgroundMigration::RemoveUndefinedVulnerabilityConfidenceLevel')
diff --git a/lib/gitlab/background_migration/replace_blocked_by_links.rb b/lib/gitlab/background_migration/replace_blocked_by_links.rb
deleted file mode 100644
index 0c29887bb00..00000000000
--- a/lib/gitlab/background_migration/replace_blocked_by_links.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class ReplaceBlockedByLinks
- class IssueLink < ActiveRecord::Base
- self.table_name = 'issue_links'
- end
-
- def perform(start_id, stop_id)
- blocked_by_links = IssueLink.where(id: start_id..stop_id).where(link_type: 2)
-
- ActiveRecord::Base.transaction do
- # There could be two edge cases:
- # 1) issue1 is blocked by issue2 AND issue2 blocks issue1 (type 1)
- # 2) issue1 is blocked by issue2 AND issue2 is related to issue1 (type 0)
- # In both cases cases we couldn't convert blocked by relation to
- # `issue2 blocks issue` because there is already a link with the same
- # source/target id. To avoid these conflicts, we first delete any
- # "opposite" links before we update `blocked by` relation. This
- # should be rare as we have a pre-create check which checks if issues
- # are already linked
- opposite_ids = blocked_by_links
- .select('opposite_links.id')
- .joins('INNER JOIN issue_links as opposite_links ON issue_links.source_id = opposite_links.target_id AND issue_links.target_id = opposite_links.source_id')
- IssueLink.where(id: opposite_ids).delete_all
-
- blocked_by_links.update_all('source_id=target_id,target_id=source_id,link_type=1')
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/reset_merge_status.rb b/lib/gitlab/background_migration/reset_merge_status.rb
deleted file mode 100644
index d040b4931be..00000000000
--- a/lib/gitlab/background_migration/reset_merge_status.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Updates the range of given MRs to merge_status "unchecked", if they're opened
- # and mergeable.
- class ResetMergeStatus
- def perform(from_id, to_id)
- relation = MergeRequest.where(id: from_id..to_id,
- state_id: 1, # opened
- merge_status: 'can_be_merged')
-
- relation.update_all(merge_status: 'unchecked')
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects.rb b/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects.rb
deleted file mode 100644
index 0053cafb4ac..00000000000
--- a/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Resets inconsistent state of shared_runners_enabled for projects that have been transferred
- class ResetSharedRunnersForTransferredProjects
- # Model specifically used for migration.
- class Namespace < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'namespaces'
- end
-
- # Model specifically used for migration.
- class Project < ActiveRecord::Base
- self.table_name = 'projects'
- end
-
- def perform(start_id, stop_id)
- Project.reset_column_information
-
- Namespace.where(id: start_id..stop_id).each_batch(of: 1_000) do |relation|
- ids = relation.where(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: false).select(:id)
-
- Project.where(namespace_id: ids).update_all(shared_runners_enabled: false)
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/set_merge_request_diff_files_count.rb b/lib/gitlab/background_migration/set_merge_request_diff_files_count.rb
deleted file mode 100644
index 527dd2a0a83..00000000000
--- a/lib/gitlab/background_migration/set_merge_request_diff_files_count.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Sets the MergeRequestDiff#files_count value for old rows
- class SetMergeRequestDiffFilesCount
- # Some historic data has a *lot* of files. Apply a sentinel to these cases
- FILES_COUNT_SENTINEL = 2**15 - 1
-
- def self.count_subquery
- <<~SQL
- files_count = (
- SELECT LEAST(#{FILES_COUNT_SENTINEL}, count(*))
- FROM merge_request_diff_files
- WHERE merge_request_diff_files.merge_request_diff_id = merge_request_diffs.id
- )
- SQL
- end
-
- class MergeRequestDiff < ActiveRecord::Base # rubocop:disable Style/Documentation
- include EachBatch
-
- self.table_name = 'merge_request_diffs'
- end
-
- def perform(start_id, end_id)
- MergeRequestDiff.where(id: start_id..end_id).each_batch do |relation|
- relation.update_all(self.class.count_subquery)
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent.rb b/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent.rb
deleted file mode 100644
index 9e330f7c008..00000000000
--- a/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This background migration updates children of group to match visibility of a parent
- class UpdateExistingSubgroupToMatchVisibilityLevelOfParent
- def perform(parents_groups_ids, level)
- groups_ids = Gitlab::ObjectHierarchy.new(Group.where(id: parents_groups_ids))
- .base_and_descendants
- .where("visibility_level > ?", level)
- .select(:id)
-
- return if groups_ids.empty?
-
- Group
- .where(id: groups_ids)
- .update_all(visibility_level: level)
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth.rb b/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth.rb
deleted file mode 100644
index d97765cd398..00000000000
--- a/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class UpdateExistingUsersThatRequireTwoFactorAuth # rubocop:disable Metrics/ClassLength
- def perform(start_id, stop_id)
- ActiveRecord::Base.connection.execute <<~SQL
- UPDATE
- users
- SET
- require_two_factor_authentication_from_group = FALSE
- WHERE
- users.id BETWEEN #{start_id}
- AND #{stop_id}
- AND users.require_two_factor_authentication_from_group = TRUE
- AND users.id NOT IN ( SELECT DISTINCT
- users_groups_query.user_id
- FROM (
- SELECT
- users.id AS user_id,
- members.source_id AS group_ids
- FROM
- users
- LEFT JOIN members ON members.source_type = 'Namespace'
- AND members.requested_at IS NULL
- AND members.user_id = users.id
- AND members.type = 'GroupMember'
- WHERE
- users.require_two_factor_authentication_from_group = TRUE
- AND users.id BETWEEN #{start_id}
- AND #{stop_id}) AS users_groups_query
- INNER JOIN LATERAL ( WITH RECURSIVE "base_and_ancestors" AS (
- (
- SELECT
- "namespaces"."type",
- "namespaces"."id",
- "namespaces"."parent_id",
- "namespaces"."require_two_factor_authentication"
- FROM
- "namespaces"
- WHERE
- "namespaces"."type" = 'Group'
- AND "namespaces"."id" = users_groups_query.group_ids)
- UNION (
- SELECT
- "namespaces"."type",
- "namespaces"."id",
- "namespaces"."parent_id",
- "namespaces"."require_two_factor_authentication"
- FROM
- "namespaces",
- "base_and_ancestors"
- WHERE
- "namespaces"."type" = 'Group'
- AND "namespaces"."id" = "base_and_ancestors"."parent_id")),
- "base_and_descendants" AS (
- (
- SELECT
- "namespaces"."type",
- "namespaces"."id",
- "namespaces"."parent_id",
- "namespaces"."require_two_factor_authentication"
- FROM
- "namespaces"
- WHERE
- "namespaces"."type" = 'Group'
- AND "namespaces"."id" = users_groups_query.group_ids)
- UNION (
- SELECT
- "namespaces"."type",
- "namespaces"."id",
- "namespaces"."parent_id",
- "namespaces"."require_two_factor_authentication"
- FROM
- "namespaces",
- "base_and_descendants"
- WHERE
- "namespaces"."type" = 'Group'
- AND "namespaces"."parent_id" = "base_and_descendants"."id"))
- SELECT
- "namespaces".*
- FROM ((
- SELECT
- "namespaces"."type",
- "namespaces"."id",
- "namespaces"."parent_id",
- "namespaces"."require_two_factor_authentication"
- FROM
- "base_and_ancestors" AS "namespaces"
- WHERE
- "namespaces"."type" = 'Group')
- UNION (
- SELECT
- "namespaces"."type",
- "namespaces"."id",
- "namespaces"."parent_id",
- "namespaces"."require_two_factor_authentication"
- FROM
- "base_and_descendants" AS "namespaces"
- WHERE
- "namespaces"."type" = 'Group')) namespaces
- WHERE
- "namespaces"."type" = 'Group'
- AND "namespaces"."require_two_factor_authentication" = TRUE) AS hierarchy_tree ON TRUE);
- SQL
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/update_location_fingerprint_for_container_scanning_findings.rb b/lib/gitlab/background_migration/update_location_fingerprint_for_container_scanning_findings.rb
deleted file mode 100644
index 054b918dade..00000000000
--- a/lib/gitlab/background_migration/update_location_fingerprint_for_container_scanning_findings.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class UpdateLocationFingerprintForContainerScanningFindings
- def perform(start_id, stop_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::UpdateLocationFingerprintForContainerScanningFindings.prepend_mod_with('Gitlab::BackgroundMigration::UpdateLocationFingerprintForContainerScanningFindings')
diff --git a/lib/gitlab/background_migration/update_vulnerabilities_from_dismissal_feedback.rb b/lib/gitlab/background_migration/update_vulnerabilities_from_dismissal_feedback.rb
deleted file mode 100644
index 1cc03f061fb..00000000000
--- a/lib/gitlab/background_migration/update_vulnerabilities_from_dismissal_feedback.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # rubocop: disable Style/Documentation
- class UpdateVulnerabilitiesFromDismissalFeedback
- def perform(project_id)
- end
- end
- end
-end
-
-Gitlab::BackgroundMigration::UpdateVulnerabilitiesFromDismissalFeedback.prepend_mod_with('Gitlab::BackgroundMigration::UpdateVulnerabilitiesFromDismissalFeedback')
diff --git a/lib/gitlab/quick_actions/issue_actions.rb b/lib/gitlab/quick_actions/issue_actions.rb
index 5afcb386152..5fd422db722 100644
--- a/lib/gitlab/quick_actions/issue_actions.rb
+++ b/lib/gitlab/quick_actions/issue_actions.rb
@@ -292,17 +292,11 @@ module Gitlab
condition do
current_user.can?(:set_issue_crm_contacts, quick_action_target)
end
+ execution_message do
+ _('One or more contacts were successfully added.')
+ end
command :add_contacts do |contact_emails|
- result = ::Issues::SetCrmContactsService
- .new(project: project, current_user: current_user, params: { add_emails: contact_emails.split(' ') })
- .execute(quick_action_target)
-
- @execution_message[:add_contacts] =
- if result.success?
- _('One or more contacts were successfully added.')
- else
- result.message
- end
+ @updates[:add_contacts] = contact_emails.split(' ')
end
desc _('Remove customer relation contacts')
@@ -312,17 +306,11 @@ module Gitlab
condition do
current_user.can?(:set_issue_crm_contacts, quick_action_target)
end
+ execution_message do
+ _('One or more contacts were successfully removed.')
+ end
command :remove_contacts do |contact_emails|
- result = ::Issues::SetCrmContactsService
- .new(project: project, current_user: current_user, params: { remove_emails: contact_emails.split(' ') })
- .execute(quick_action_target)
-
- @execution_message[:remove_contacts] =
- if result.success?
- _('One or more contacts were successfully removed.')
- else
- result.message
- end
+ @updates[:remove_contacts] = contact_emails.split(' ')
end
private
diff --git a/lib/sidebars/concerns/container_with_html_options.rb b/lib/sidebars/concerns/container_with_html_options.rb
index 79dddd309b5..796b7cbe275 100644
--- a/lib/sidebars/concerns/container_with_html_options.rb
+++ b/lib/sidebars/concerns/container_with_html_options.rb
@@ -3,6 +3,8 @@
module Sidebars
module Concerns
module ContainerWithHtmlOptions
+ include LinkWithHtmlOptions
+
# The attributes returned from this method
# will be applied to helper methods like
# `link_to` or the div containing the container.
diff --git a/lib/sidebars/concerns/link_with_html_options.rb b/lib/sidebars/concerns/link_with_html_options.rb
new file mode 100644
index 00000000000..4ca748e0a71
--- /dev/null
+++ b/lib/sidebars/concerns/link_with_html_options.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Concerns
+ module LinkWithHtmlOptions
+ # add on specific items as the pertain to `link_to` objects specifically
+ def link_html_options
+ container_html_options.tap do |html_options|
+ html_options[:class] = [*html_options[:class], 'gl-link'].join(' ')
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/menu_item.rb b/lib/sidebars/menu_item.rb
index 1375f9fffca..7ed3e47ae34 100644
--- a/lib/sidebars/menu_item.rb
+++ b/lib/sidebars/menu_item.rb
@@ -2,6 +2,8 @@
module Sidebars
class MenuItem
+ include ::Sidebars::Concerns::LinkWithHtmlOptions
+
attr_reader :title, :link, :active_routes, :item_id, :container_html_options, :sprite_icon, :sprite_icon_html_options, :hint_html_options
def initialize(title:, link:, active_routes:, item_id: nil, container_html_options: {}, sprite_icon: nil, sprite_icon_html_options: {}, hint_html_options: {})
diff --git a/spec/frontend/integrations/edit/components/integration_form_spec.js b/spec/frontend/integrations/edit/components/integration_form_spec.js
index 3e5822778a5..9622cdf0cfe 100644
--- a/spec/frontend/integrations/edit/components/integration_form_spec.js
+++ b/spec/frontend/integrations/edit/components/integration_form_spec.js
@@ -1,6 +1,8 @@
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
+import * as Sentry from '@sentry/browser';
import { setHTMLFixture } from 'helpers/fixtures';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-
import { mockIntegrationProps } from 'jest/integrations/edit/mock_data';
import ActiveCheckbox from '~/integrations/edit/components/active_checkbox.vue';
import ConfirmationModal from '~/integrations/edit/components/confirmation_modal.vue';
@@ -11,19 +13,27 @@ import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_field
import OverrideDropdown from '~/integrations/edit/components/override_dropdown.vue';
import ResetConfirmationModal from '~/integrations/edit/components/reset_confirmation_modal.vue';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
+import waitForPromises from 'helpers/wait_for_promises';
import {
integrationLevels,
- TEST_INTEGRATION_EVENT,
+ I18N_SUCCESSFUL_CONNECTION_MESSAGE,
+ VALIDATE_INTEGRATION_FORM_EVENT,
SAVE_INTEGRATION_EVENT,
+ I18N_DEFAULT_ERROR_MESSAGE,
} from '~/integrations/constants';
import { createStore } from '~/integrations/edit/store';
import eventHub from '~/integrations/edit/event_hub';
+import httpStatus from '~/lib/utils/http_status';
jest.mock('~/integrations/edit/event_hub');
+jest.mock('@sentry/browser');
describe('IntegrationForm', () => {
+ const mockToastShow = jest.fn();
+
let wrapper;
let dispatch;
+ let mockAxios;
const createComponent = ({
customStateProps = {},
@@ -39,6 +49,9 @@ describe('IntegrationForm', () => {
wrapper = shallowMountExtended(IntegrationForm, {
propsData: { ...props, formSelector: '.test' },
+ provide: {
+ glFeatures: featureFlags,
+ },
store,
stubs: {
OverrideDropdown,
@@ -47,15 +60,21 @@ describe('IntegrationForm', () => {
JiraTriggerFields,
TriggerFields,
},
- provide: {
- glFeatures: featureFlags,
+ mocks: {
+ $toast: {
+ show: mockToastShow,
+ },
},
});
};
- afterEach(() => {
- wrapper.destroy();
- });
+ const createForm = ({ isValid = true } = {}) => {
+ const mockForm = document.createElement('form');
+ jest.spyOn(document, 'querySelector').mockReturnValue(mockForm);
+ jest.spyOn(mockForm, 'checkValidity').mockReturnValue(isValid);
+
+ return mockForm;
+ };
const findOverrideDropdown = () => wrapper.findComponent(OverrideDropdown);
const findActiveCheckbox = () => wrapper.findComponent(ActiveCheckbox);
@@ -68,6 +87,15 @@ describe('IntegrationForm', () => {
const findJiraIssuesFields = () => wrapper.findComponent(JiraIssuesFields);
const findTriggerFields = () => wrapper.findComponent(TriggerFields);
+ beforeEach(() => {
+ mockAxios = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ mockAxios.restore();
+ });
+
describe('template', () => {
describe('integrationLevel is instance', () => {
it('renders ConfirmationModal', () => {
@@ -399,18 +427,9 @@ describe('IntegrationForm', () => {
});
describe('when `test` button is clicked', () => {
- let mockForm;
-
- describe.each`
- formValid
- ${true}
- ${false}
- `('when form checkValidity returns $formValid', ({ formValid }) => {
- beforeEach(() => {
- mockForm = document.createElement('form');
- jest.spyOn(document, 'querySelector').mockReturnValue(mockForm);
- jest.spyOn(mockForm, 'checkValidity').mockReturnValue(formValid);
-
+ describe('when form is invalid', () => {
+ it('emits `VALIDATE_INTEGRATION_FORM_EVENT` event to the event hub', () => {
+ createForm({ isValid: false });
createComponent({
customStateProps: {
showActive: true,
@@ -419,14 +438,70 @@ describe('IntegrationForm', () => {
});
findTestButton().vm.$emit('click', new Event('click'));
+
+ expect(eventHub.$emit).toHaveBeenCalledWith(VALIDATE_INTEGRATION_FORM_EVENT);
});
+ });
+
+ describe('when form is valid', () => {
+ const mockTestPath = '/test';
- it('dispatches setIsTesting action', () => {
- expect(dispatch).toHaveBeenCalledWith('setIsTesting', true);
+ beforeEach(() => {
+ createForm({ isValid: true });
+ createComponent({
+ customStateProps: {
+ showActive: true,
+ canTest: true,
+ testPath: mockTestPath,
+ },
+ });
});
- it(`emits \`TEST_INTEGRATION_EVENT\` event with payload \`${formValid}\``, () => {
- expect(eventHub.$emit).toHaveBeenCalledWith(TEST_INTEGRATION_EVENT, formValid);
+ describe('buttons', () => {
+ beforeEach(async () => {
+ await findTestButton().vm.$emit('click', new Event('click'));
+ });
+
+ it('sets test button `loading` prop to `true`', () => {
+ expect(findTestButton().props('loading')).toBe(true);
+ });
+
+ it('sets save button `disabled` prop to `true`', () => {
+ expect(findSaveButton().props('disabled')).toBe(true);
+ });
+ });
+
+ describe.each`
+ scenario | replyStatus | errorMessage | expectToast | expectSentry
+ ${'when "test settings" request fails'} | ${httpStatus.INTERNAL_SERVER_ERROR} | ${undefined} | ${I18N_DEFAULT_ERROR_MESSAGE} | ${true}
+ ${'when "test settings" returns an error'} | ${httpStatus.OK} | ${'an error'} | ${'an error'} | ${false}
+ ${'when "test settings" succeeds'} | ${httpStatus.OK} | ${undefined} | ${I18N_SUCCESSFUL_CONNECTION_MESSAGE} | ${false}
+ `('$scenario', ({ replyStatus, errorMessage, expectToast, expectSentry }) => {
+ beforeEach(async () => {
+ mockAxios.onPut(mockTestPath).replyOnce(replyStatus, {
+ error: Boolean(errorMessage),
+ message: errorMessage,
+ });
+
+ await findTestButton().vm.$emit('click', new Event('click'));
+ await waitForPromises();
+ });
+
+ it(`calls toast with '${expectToast}'`, () => {
+ expect(mockToastShow).toHaveBeenCalledWith(expectToast);
+ });
+
+ it('sets `loading` prop of test button to `false`', () => {
+ expect(findTestButton().props('loading')).toBe(false);
+ });
+
+ it('sets save button `disabled` prop to `false`', () => {
+ expect(findSaveButton().props('disabled')).toBe(false);
+ });
+
+ it(`${expectSentry ? 'does' : 'does not'} capture exception in Sentry`, () => {
+ expect(Sentry.captureException).toHaveBeenCalledTimes(expectSentry ? 1 : 0);
+ });
});
});
});
diff --git a/spec/frontend/integrations/edit/store/actions_spec.js b/spec/frontend/integrations/edit/store/actions_spec.js
index 3cf69c65126..dff435578a7 100644
--- a/spec/frontend/integrations/edit/store/actions_spec.js
+++ b/spec/frontend/integrations/edit/store/actions_spec.js
@@ -5,7 +5,6 @@ import { I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE } from '~/integrations/c
import {
setOverride,
setIsSaving,
- setIsTesting,
setIsResetting,
requestResetIntegration,
receiveResetIntegrationSuccess,
@@ -46,12 +45,6 @@ describe('Integration form store actions', () => {
});
});
- describe('setIsTesting', () => {
- it('should commit isTesting mutation', () => {
- return testAction(setIsTesting, true, state, [{ type: types.SET_IS_TESTING, payload: true }]);
- });
- });
-
describe('setIsResetting', () => {
it('should commit isResetting mutation', () => {
return testAction(setIsResetting, true, state, [
diff --git a/spec/frontend/integrations/edit/store/getters_spec.js b/spec/frontend/integrations/edit/store/getters_spec.js
index ad7a887dff2..037629d22a6 100644
--- a/spec/frontend/integrations/edit/store/getters_spec.js
+++ b/spec/frontend/integrations/edit/store/getters_spec.js
@@ -54,20 +54,15 @@ describe('Integration form store getters', () => {
describe('isDisabled', () => {
it.each`
- isSaving | isTesting | isResetting | expected
- ${false} | ${false} | ${false} | ${false}
- ${true} | ${false} | ${false} | ${true}
- ${false} | ${true} | ${false} | ${true}
- ${false} | ${false} | ${true} | ${true}
- ${false} | ${true} | ${true} | ${true}
- ${true} | ${false} | ${true} | ${true}
- ${true} | ${true} | ${false} | ${true}
- ${true} | ${true} | ${true} | ${true}
+ isSaving | isResetting | expected
+ ${false} | ${false} | ${false}
+ ${true} | ${false} | ${true}
+ ${false} | ${true} | ${true}
+ ${true} | ${true} | ${true}
`(
- 'when isSaving = $isSaving, isTesting = $isTesting, isResetting = $isResetting then isDisabled = $expected',
- ({ isSaving, isTesting, isResetting, expected }) => {
+ 'when isSaving = $isSaving, isResetting = $isResetting then isDisabled = $expected',
+ ({ isSaving, isResetting, expected }) => {
mutations[types.SET_IS_SAVING](state, isSaving);
- mutations[types.SET_IS_TESTING](state, isTesting);
mutations[types.SET_IS_RESETTING](state, isResetting);
expect(isDisabled(state)).toBe(expected);
diff --git a/spec/frontend/integrations/edit/store/mutations_spec.js b/spec/frontend/integrations/edit/store/mutations_spec.js
index 18faa2f6bba..9f27a7ed6be 100644
--- a/spec/frontend/integrations/edit/store/mutations_spec.js
+++ b/spec/frontend/integrations/edit/store/mutations_spec.js
@@ -25,14 +25,6 @@ describe('Integration form store mutations', () => {
});
});
- describe(`${types.SET_IS_TESTING}`, () => {
- it('sets isTesting', () => {
- mutations[types.SET_IS_TESTING](state, true);
-
- expect(state.isTesting).toBe(true);
- });
- });
-
describe(`${types.SET_IS_RESETTING}`, () => {
it('sets isResetting', () => {
mutations[types.SET_IS_RESETTING](state, true);
diff --git a/spec/frontend/integrations/edit/store/state_spec.js b/spec/frontend/integrations/edit/store/state_spec.js
index 6cd84836395..5582be7fd3c 100644
--- a/spec/frontend/integrations/edit/store/state_spec.js
+++ b/spec/frontend/integrations/edit/store/state_spec.js
@@ -6,7 +6,6 @@ describe('Integration form state factory', () => {
defaultState: null,
customState: {},
isSaving: false,
- isTesting: false,
isResetting: false,
override: false,
isLoadingJiraIssueTypes: false,
diff --git a/spec/frontend/integrations/integration_settings_form_spec.js b/spec/frontend/integrations/integration_settings_form_spec.js
index a71fe9dd0c4..344d4799889 100644
--- a/spec/frontend/integrations/integration_settings_form_spec.js
+++ b/spec/frontend/integrations/integration_settings_form_spec.js
@@ -2,13 +2,7 @@ import MockAdaptor from 'axios-mock-adapter';
import IntegrationSettingsForm from '~/integrations/integration_settings_form';
import eventHub from '~/integrations/edit/event_hub';
import axios from '~/lib/utils/axios_utils';
-import toast from '~/vue_shared/plugins/global_toast';
-import {
- I18N_SUCCESSFUL_CONNECTION_MESSAGE,
- I18N_DEFAULT_ERROR_MESSAGE,
- TEST_INTEGRATION_EVENT,
- SAVE_INTEGRATION_EVENT,
-} from '~/integrations/constants';
+import { SAVE_INTEGRATION_EVENT } from '~/integrations/constants';
import waitForPromises from 'helpers/wait_for_promises';
jest.mock('~/vue_shared/plugins/global_toast');
@@ -29,6 +23,10 @@ describe('IntegrationSettingsForm', () => {
integrationSettingsForm.init();
});
+ afterEach(() => {
+ eventHub.dispose(); // clear event hub handlers
+ });
+
describe('constructor', () => {
it('should initialize form element refs on class object', () => {
expect(integrationSettingsForm.$form).toBeDefined();
@@ -47,88 +45,11 @@ describe('IntegrationSettingsForm', () => {
beforeEach(() => {
mockAxios = new MockAdaptor(axios);
jest.spyOn(axios, 'put');
- jest.spyOn(integrationSettingsForm, 'testSettings');
jest.spyOn(integrationSettingsForm.$form, 'submit');
});
afterEach(() => {
mockAxios.restore();
- eventHub.dispose(); // clear event hub handlers
- });
-
- describe('when event hub receives `TEST_INTEGRATION_EVENT`', () => {
- describe('when form is valid', () => {
- it('should make an ajax request with provided `formData`', async () => {
- eventHub.$emit(TEST_INTEGRATION_EVENT, true);
- await waitForPromises();
-
- expect(axios.put).toHaveBeenCalledWith(
- integrationSettingsForm.testEndPoint,
- new FormData(integrationSettingsForm.$form),
- );
- });
-
- it('should show success message if test is successful', async () => {
- jest.spyOn(integrationSettingsForm.$form, 'submit').mockImplementation(() => {});
-
- mockAxios.onPut(integrationSettingsForm.testEndPoint).reply(200, {
- error: false,
- });
-
- eventHub.$emit(TEST_INTEGRATION_EVENT, true);
- await waitForPromises();
-
- expect(toast).toHaveBeenCalledWith(I18N_SUCCESSFUL_CONNECTION_MESSAGE);
- });
-
- it('should show error message if ajax request responds with test error', async () => {
- const errorMessage = 'Test failed.';
- const serviceResponse = 'some error';
-
- mockAxios.onPut(integrationSettingsForm.testEndPoint).reply(200, {
- error: true,
- message: errorMessage,
- service_response: serviceResponse,
- test_failed: false,
- });
-
- eventHub.$emit(TEST_INTEGRATION_EVENT, true);
- await waitForPromises();
-
- expect(toast).toHaveBeenCalledWith(`${errorMessage} ${serviceResponse}`);
- });
-
- it('should show error message if ajax request failed', async () => {
- mockAxios.onPut(integrationSettingsForm.testEndPoint).networkError();
-
- eventHub.$emit(TEST_INTEGRATION_EVENT, true);
- await waitForPromises();
-
- expect(toast).toHaveBeenCalledWith(I18N_DEFAULT_ERROR_MESSAGE);
- });
-
- it('should always dispatch `setIsTesting` with `false` once request is completed', async () => {
- const dispatchSpy = mockStoreDispatch();
- mockAxios.onPut(integrationSettingsForm.testEndPoint).networkError();
-
- eventHub.$emit(TEST_INTEGRATION_EVENT, true);
- await waitForPromises();
-
- expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false);
- });
- });
-
- describe('when form is invalid', () => {
- it('should dispatch `setIsTesting` with `false` and not call `testSettings`', async () => {
- const dispatchSpy = mockStoreDispatch();
-
- eventHub.$emit(TEST_INTEGRATION_EVENT, false);
- await waitForPromises();
-
- expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false);
- expect(integrationSettingsForm.testSettings).not.toHaveBeenCalled();
- });
- });
});
describe('when event hub receives `SAVE_INTEGRATION_EVENT`', () => {
@@ -137,7 +58,6 @@ describe('IntegrationSettingsForm', () => {
eventHub.$emit(SAVE_INTEGRATION_EVENT, true);
await waitForPromises();
- expect(integrationSettingsForm.$form.submit).toHaveBeenCalled();
expect(integrationSettingsForm.$form.submit).toHaveBeenCalledTimes(1);
});
});
diff --git a/spec/frontend/snippets/components/snippet_header_spec.js b/spec/frontend/snippets/components/snippet_header_spec.js
index 552a1c6fcde..2d5e0cfd615 100644
--- a/spec/frontend/snippets/components/snippet_header_spec.js
+++ b/spec/frontend/snippets/components/snippet_header_spec.js
@@ -252,7 +252,7 @@ describe('Snippet header component', () => {
disabled: false,
href: `/foo/-/snippets/new`,
text: 'New snippet',
- variant: 'success',
+ variant: 'confirm',
},
]),
);
diff --git a/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb b/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb
deleted file mode 100644
index 1e72b249c19..00000000000
--- a/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::AddMergeRequestDiffCommitsCount do
- let(:namespaces_table) { table(:namespaces) }
- let(:projects_table) { table(:projects) }
- let(:merge_requests_table) { table(:merge_requests) }
- let(:merge_request_diffs_table) { table(:merge_request_diffs) }
- let(:merge_request_diff_commits_table) { table(:merge_request_diff_commits) }
-
- let(:namespace) { namespaces_table.create!(name: 'gitlab-org', path: 'gitlab-org') }
- let(:project) { projects_table.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce', namespace_id: namespace.id) }
- let(:merge_request) do
- merge_requests_table.create!(target_project_id: project.id,
- target_branch: 'master',
- source_project_id: project.id,
- source_branch: 'mr name',
- title: 'mr name')
- end
-
- def create_diff!(name, commits: 0)
- mr_diff = merge_request_diffs_table.create!(
- merge_request_id: merge_request.id)
-
- commits.times do |i|
- merge_request_diff_commits_table.create!(
- merge_request_diff_id: mr_diff.id,
- relative_order: i, sha: i)
- end
-
- mr_diff
- end
-
- describe '#perform' do
- it 'migrates diffs that have no commits' do
- diff = create_diff!('with_multiple_commits', commits: 0)
-
- subject.perform(diff.id, diff.id)
-
- expect(diff.reload.commits_count).to eq(0)
- end
-
- it 'skips diffs that have commits_count already set' do
- timestamp = 2.days.ago
- diff = merge_request_diffs_table.create!(
- merge_request_id: merge_request.id,
- commits_count: 0,
- updated_at: timestamp)
-
- subject.perform(diff.id, diff.id)
-
- expect(diff.reload.updated_at).to be_within(1.second).of(timestamp)
- end
-
- it 'migrates multiple diffs to the correct values' do
- diffs = Array.new(3).map.with_index { |_, i| create_diff!(i, commits: 3) }
-
- subject.perform(diffs.first.id, diffs.last.id)
-
- diffs.each do |diff|
- expect(diff.reload.commits_count).to eq(3)
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb b/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb
deleted file mode 100644
index 0b29163671c..00000000000
--- a/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::AddModifiedToApprovalMergeRequestRule, schema: 20181228175414 do
- let(:determine_if_rules_are_modified) { described_class.new }
-
- let(:namespace) { table(:namespaces).create!(name: 'gitlab', path: 'gitlab') }
- let(:projects) { table(:projects) }
- let(:normal_project) { projects.create!(namespace_id: namespace.id) }
- let(:overridden_project) { projects.create!(namespace_id: namespace.id) }
- let(:rules) { table(:approval_merge_request_rules) }
- let(:project_rules) { table(:approval_project_rules) }
- let(:sources) { table(:approval_merge_request_rule_sources) }
- let(:merge_requests) { table(:merge_requests) }
- let(:groups) { table(:namespaces) }
- let(:mr_groups) { table(:approval_merge_request_rules_groups) }
- let(:project_groups) { table(:approval_project_rules_groups) }
-
- before do
- project_rule = project_rules.create!(project_id: normal_project.id, approvals_required: 3, name: 'test rule')
- overridden_project_rule = project_rules.create!(project_id: overridden_project.id, approvals_required: 5, name: 'other test rule')
- overridden_project_rule_two = project_rules.create!(project_id: overridden_project.id, approvals_required: 7, name: 'super cool rule')
-
- merge_request = merge_requests.create!(target_branch: 'feature', source_branch: 'default', source_project_id: normal_project.id, target_project_id: normal_project.id)
- overridden_merge_request = merge_requests.create!(target_branch: 'feature-2', source_branch: 'default', source_project_id: overridden_project.id, target_project_id: overridden_project.id)
-
- merge_rule = rules.create!(merge_request_id: merge_request.id, approvals_required: 3, name: 'test rule')
- overridden_merge_rule = rules.create!(merge_request_id: overridden_merge_request.id, approvals_required: 6, name: 'other test rule')
- overridden_merge_rule_two = rules.create!(merge_request_id: overridden_merge_request.id, approvals_required: 7, name: 'super cool rule')
-
- sources.create!(approval_project_rule_id: project_rule.id, approval_merge_request_rule_id: merge_rule.id)
- sources.create!(approval_project_rule_id: overridden_project_rule.id, approval_merge_request_rule_id: overridden_merge_rule.id)
- sources.create!(approval_project_rule_id: overridden_project_rule_two.id, approval_merge_request_rule_id: overridden_merge_rule_two.id)
-
- group1 = groups.create!(name: "group1", path: "test_group1", type: 'Group')
- group2 = groups.create!(name: "group2", path: "test_group2", type: 'Group')
- group3 = groups.create!(name: "group3", path: "test_group3", type: 'Group')
-
- project_groups.create!(approval_project_rule_id: overridden_project_rule_two.id, group_id: group1.id)
- project_groups.create!(approval_project_rule_id: overridden_project_rule_two.id, group_id: group2.id)
- project_groups.create!(approval_project_rule_id: overridden_project_rule_two.id, group_id: group3.id)
-
- mr_groups.create!(approval_merge_request_rule_id: overridden_merge_rule.id, group_id: group1.id)
- mr_groups.create!(approval_merge_request_rule_id: overridden_merge_rule_two.id, group_id: group2.id)
- end
-
- describe '#perform' do
- it 'changes the correct rules' do
- original_count = rules.all.count
-
- determine_if_rules_are_modified.perform(rules.minimum(:id), rules.maximum(:id))
-
- results = rules.where(modified_from_project_rule: true)
-
- expect(results.count).to eq 2
- expect(results.collect(&:name)).to eq(['other test rule', 'super cool rule'])
- expect(rules.count).to eq original_count
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb b/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb
deleted file mode 100644
index 1404ada3647..00000000000
--- a/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::BackfillDeploymentClustersFromDeployments, :migration, schema: 20181228175414 do
- subject { described_class.new }
-
- describe '#perform' do
- it 'backfills deployment_cluster for all deployments in the given range with a non-null cluster_id' do
- deployment_clusters = table(:deployment_clusters)
-
- namespace = table(:namespaces).create!(name: 'the-namespace', path: 'the-path')
- project = table(:projects).create!(name: 'the-project', namespace_id: namespace.id)
- environment = table(:environments).create!(name: 'the-environment', project_id: project.id, slug: 'slug')
- cluster = table(:clusters).create!(name: 'the-cluster')
-
- deployment_data = { cluster_id: cluster.id, project_id: project.id, environment_id: environment.id, ref: 'abc', tag: false, sha: 'sha', status: 1 }
- expected_deployment_1 = create_deployment(**deployment_data)
- create_deployment(**deployment_data, cluster_id: nil) # no cluster_id
- expected_deployment_2 = create_deployment(**deployment_data)
- out_of_range_deployment = create_deployment(**deployment_data, cluster_id: cluster.id) # expected to be out of range
-
- # to test "ON CONFLICT DO NOTHING"
- existing_record_for_deployment_2 = deployment_clusters.create!(
- deployment_id: expected_deployment_2.id,
- cluster_id: expected_deployment_2.cluster_id,
- kubernetes_namespace: 'production'
- )
-
- subject.perform(expected_deployment_1.id, out_of_range_deployment.id - 1)
-
- expect(deployment_clusters.all.pluck(:deployment_id, :cluster_id, :kubernetes_namespace)).to contain_exactly(
- [expected_deployment_1.id, cluster.id, nil],
- [expected_deployment_2.id, cluster.id, existing_record_for_deployment_2.kubernetes_namespace]
- )
- end
-
- def create_deployment(**data)
- @iid ||= 0
- @iid += 1
- table(:deployments).create!(iid: @iid, **data)
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb b/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb
deleted file mode 100644
index 9194525e713..00000000000
--- a/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::BackfillEnvironmentIdDeploymentMergeRequests, schema: 20181228175414 do
- let(:environments) { table(:environments) }
- let(:merge_requests) { table(:merge_requests) }
- let(:deployments) { table(:deployments) }
- let(:deployment_merge_requests) { table(:deployment_merge_requests) }
- let(:namespaces) { table(:namespaces) }
- let(:projects) { table(:projects) }
-
- subject(:migration) { described_class.new }
-
- it 'correctly backfills environment_id column' do
- namespace = namespaces.create!(name: 'foo', path: 'foo')
- project = projects.create!(namespace_id: namespace.id)
-
- production = environments.create!(project_id: project.id, name: 'production', slug: 'production')
- staging = environments.create!(project_id: project.id, name: 'staging', slug: 'staging')
-
- mr = merge_requests.create!(source_branch: 'x', target_branch: 'master', target_project_id: project.id)
-
- deployment1 = deployments.create!(environment_id: staging.id, iid: 1, project_id: project.id, ref: 'master', tag: false, sha: '123abcdef', status: 1)
- deployment2 = deployments.create!(environment_id: production.id, iid: 2, project_id: project.id, ref: 'master', tag: false, sha: '123abcdef', status: 1)
- deployment3 = deployments.create!(environment_id: production.id, iid: 3, project_id: project.id, ref: 'master', tag: false, sha: '123abcdef', status: 1)
-
- # mr is tracked twice in production through deployment2 and deployment3
- deployment_merge_requests.create!(deployment_id: deployment1.id, merge_request_id: mr.id)
- deployment_merge_requests.create!(deployment_id: deployment2.id, merge_request_id: mr.id)
- deployment_merge_requests.create!(deployment_id: deployment3.id, merge_request_id: mr.id)
-
- expect(deployment_merge_requests.where(environment_id: nil).count).to eq(3)
-
- migration.backfill_range(1, mr.id)
-
- expect(deployment_merge_requests.where(environment_id: nil).count).to be_zero
- expect(deployment_merge_requests.count).to eq(2)
-
- production_deployments = deployment_merge_requests.where(environment_id: production.id)
- expect(production_deployments.count).to eq(1)
- expect(production_deployments.first.deployment_id).to eq(deployment2.id)
-
- expect(deployment_merge_requests.where(environment_id: staging.id).count).to eq(1)
- end
-end
diff --git a/spec/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules_spec.rb b/spec/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules_spec.rb
deleted file mode 100644
index d33f52514da..00000000000
--- a/spec/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::BackfillMergeRequestCleanupSchedules, schema: 20181228175414 do
- let(:merge_requests) { table(:merge_requests) }
- let(:cleanup_schedules) { table(:merge_request_cleanup_schedules) }
- let(:metrics) { table(:merge_request_metrics) }
-
- let(:namespace) { table(:namespaces).create!(name: 'name', path: 'path') }
- let(:project) { table(:projects).create!(namespace_id: namespace.id) }
-
- subject { described_class.new }
-
- describe '#perform' do
- let!(:open_mr) { merge_requests.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'master') }
-
- let!(:closed_mr_1) { merge_requests.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'master', state_id: 2) }
- let!(:closed_mr_2) { merge_requests.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'master', state_id: 2) }
- let!(:closed_mr_1_metrics) { metrics.create!(merge_request_id: closed_mr_1.id, target_project_id: project.id, latest_closed_at: Time.current, created_at: Time.current, updated_at: Time.current) }
- let!(:closed_mr_2_metrics) { metrics.create!(merge_request_id: closed_mr_2.id, target_project_id: project.id, latest_closed_at: Time.current, created_at: Time.current, updated_at: Time.current) }
- let!(:closed_mr_2_cleanup_schedule) { cleanup_schedules.create!(merge_request_id: closed_mr_2.id, scheduled_at: Time.current) }
-
- let!(:merged_mr_1) { merge_requests.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'master', state_id: 3) }
- let!(:merged_mr_2) { merge_requests.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'master', state_id: 3, updated_at: Time.current) }
- let!(:merged_mr_1_metrics) { metrics.create!(merge_request_id: merged_mr_1.id, target_project_id: project.id, merged_at: Time.current, created_at: Time.current, updated_at: Time.current) }
-
- let!(:closed_mr_3) { merge_requests.create!(target_project_id: project.id, source_branch: 'master', target_branch: 'master', state_id: 2) }
- let!(:closed_mr_3_metrics) { metrics.create!(merge_request_id: closed_mr_3.id, target_project_id: project.id, latest_closed_at: Time.current, created_at: Time.current, updated_at: Time.current) }
-
- it 'creates records for all closed and merged merge requests in range' do
- expect(Gitlab::BackgroundMigration::Logger).to receive(:info).with(
- message: 'Backfilled merge_request_cleanup_schedules records',
- count: 3
- )
-
- subject.perform(open_mr.id, merged_mr_2.id)
-
- aggregate_failures do
- expect(cleanup_schedules.all.pluck(:merge_request_id))
- .to contain_exactly(closed_mr_1.id, closed_mr_2.id, merged_mr_1.id, merged_mr_2.id)
- expect(cleanup_schedules.find_by(merge_request_id: closed_mr_1.id).scheduled_at.to_s)
- .to eq((closed_mr_1_metrics.latest_closed_at + 14.days).to_s)
- expect(cleanup_schedules.find_by(merge_request_id: closed_mr_2.id).scheduled_at.to_s)
- .to eq(closed_mr_2_cleanup_schedule.scheduled_at.to_s)
- expect(cleanup_schedules.find_by(merge_request_id: merged_mr_1.id).scheduled_at.to_s)
- .to eq((merged_mr_1_metrics.merged_at + 14.days).to_s)
- expect(cleanup_schedules.find_by(merge_request_id: merged_mr_2.id).scheduled_at.to_s)
- .to eq((merged_mr_2.updated_at + 14.days).to_s)
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/backfill_namespace_settings_spec.rb b/spec/lib/gitlab/background_migration/backfill_namespace_settings_spec.rb
deleted file mode 100644
index 0f8adca2ca4..00000000000
--- a/spec/lib/gitlab/background_migration/backfill_namespace_settings_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::BackfillNamespaceSettings, schema: 20181228175414 do
- let(:namespaces) { table(:namespaces) }
- let(:namespace_settings) { table(:namespace_settings) }
- let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') }
-
- subject { described_class.new }
-
- describe '#perform' do
- it 'creates settings for all projects in range' do
- namespaces.create!(id: 5, name: 'test1', path: 'test1')
- namespaces.create!(id: 7, name: 'test2', path: 'test2')
- namespaces.create!(id: 8, name: 'test3', path: 'test3')
-
- subject.perform(5, 7)
-
- expect(namespace_settings.all.pluck(:namespace_id)).to contain_exactly(5, 7)
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb
deleted file mode 100644
index e6b0db2ab73..00000000000
--- a/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::BackfillProjectSettings, schema: 20181228175414 do
- let(:projects) { table(:projects) }
- let(:project_settings) { table(:project_settings) }
- let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') }
- let(:project) { projects.create!(namespace_id: namespace.id) }
-
- subject { described_class.new }
-
- describe '#perform' do
- it 'creates settings for all projects in range' do
- projects.create!(id: 5, namespace_id: namespace.id)
- projects.create!(id: 7, namespace_id: namespace.id)
- projects.create!(id: 8, namespace_id: namespace.id)
-
- subject.perform(5, 7)
-
- expect(project_settings.all.pluck(:project_id)).to contain_exactly(5, 7)
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb b/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb
deleted file mode 100644
index 3468df3dccd..00000000000
--- a/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::BackfillPushRulesIdInProjects, :migration, schema: 20181228175414 do
- let(:push_rules) { table(:push_rules) }
- let(:projects) { table(:projects) }
- let(:project_settings) { table(:project_settings) }
- let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') }
-
- subject { described_class.new }
-
- describe '#perform' do
- it 'creates new project push_rules for all push rules in the range' do
- project_1 = projects.create!(id: 1, namespace_id: namespace.id)
- project_2 = projects.create!(id: 2, namespace_id: namespace.id)
- project_3 = projects.create!(id: 3, namespace_id: namespace.id)
- project_settings_1 = project_settings.create!(project_id: project_1.id)
- project_settings_2 = project_settings.create!(project_id: project_2.id)
- project_settings_3 = project_settings.create!(project_id: project_3.id)
- push_rule_1 = push_rules.create!(id: 5, is_sample: false, project_id: project_1.id)
- push_rule_2 = push_rules.create!(id: 6, is_sample: false, project_id: project_2.id)
- push_rules.create!(id: 8, is_sample: false, project_id: 3)
-
- subject.perform(5, 7)
-
- expect(project_settings_1.reload.push_rule_id).to eq(push_rule_1.id)
- expect(project_settings_2.reload.push_rule_id).to eq(push_rule_2.id)
- expect(project_settings_3.reload.push_rule_id).to be_nil
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids_spec.rb b/spec/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids_spec.rb
deleted file mode 100644
index 35ec8be691a..00000000000
--- a/spec/lib/gitlab/background_migration/fix_promoted_epics_discussion_ids_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::FixPromotedEpicsDiscussionIds, schema: 20181228175414 do
- let(:namespaces) { table(:namespaces) }
- let(:users) { table(:users) }
- let(:epics) { table(:epics) }
- let(:notes) { table(:notes) }
-
- let(:user) { users.create!(email: 'test@example.com', projects_limit: 100, username: 'test') }
- let(:namespace) { namespaces.create!(name: 'gitlab', path: 'gitlab-org') }
- let(:epic1) { epics.create!(id: 1, author_id: user.id, iid: 1, group_id: namespace.id, title: 'Epic with discussion', title_html: 'Epic with discussion') }
-
- def create_note(discussion_id)
- notes.create!(note: 'note comment',
- noteable_id: epic1.id,
- noteable_type: 'Epic',
- discussion_id: discussion_id)
- end
-
- def expect_valid_discussion_id(id)
- expect(id).to match(/\A\h{40}\z/)
- end
-
- describe '#perform with batch of discussion ids' do
- it 'updates discussion ids' do
- note1 = create_note('00000000')
- note2 = create_note('00000000')
- note3 = create_note('10000000')
-
- subject.perform(%w(00000000 10000000))
-
- expect_valid_discussion_id(note1.reload.discussion_id)
- expect_valid_discussion_id(note2.reload.discussion_id)
- expect_valid_discussion_id(note3.reload.discussion_id)
- expect(note1.discussion_id).to eq(note2.discussion_id)
- expect(note1.discussion_id).not_to eq(note3.discussion_id)
- end
-
- it 'skips notes with discussion id not in range' do
- note4 = create_note('20000000')
-
- subject.perform(%w(00000000 10000000))
-
- expect(note4.reload.discussion_id).to eq('20000000')
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb b/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb
deleted file mode 100644
index 95509f9b897..00000000000
--- a/spec/lib/gitlab/background_migration/fix_user_namespace_names_spec.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::FixUserNamespaceNames, schema: 20181228175414 do
- let(:namespaces) { table(:namespaces) }
- let(:users) { table(:users) }
- let(:user) { users.create!(name: "The user's full name", projects_limit: 10, username: 'not-null', email: '1') }
-
- context 'updating the namespace names' do
- it 'updates a user namespace within range' do
- user2 = users.create!(name: "Other user's full name", projects_limit: 10, username: 'also-not-null', email: '2')
- user_namespace1 = namespaces.create!(
- id: 2,
- owner_id: user.id,
- name: "Should be the user's name",
- path: user.username
- )
- user_namespace2 = namespaces.create!(
- id: 3,
- owner_id: user2.id,
- name: "Should also be the user's name",
- path: user.username
- )
-
- described_class.new.perform(1, 5)
-
- expect(user_namespace1.reload.name).to eq("The user's full name")
- expect(user_namespace2.reload.name).to eq("Other user's full name")
- end
-
- it 'does not update namespaces out of range' do
- user_namespace = namespaces.create!(
- id: 6,
- owner_id: user.id,
- name: "Should be the user's name",
- path: user.username
- )
-
- expect { described_class.new.perform(1, 5) }
- .not_to change { user_namespace.reload.name }
- end
-
- it 'does not update groups owned by the users' do
- user_group = namespaces.create!(
- id: 2,
- owner_id: user.id,
- name: 'A group name',
- path: 'the-path',
- type: 'Group'
- )
-
- expect { described_class.new.perform(1, 5) }
- .not_to change { user_group.reload.name }
- end
- end
-
- context 'namespace route names' do
- let(:routes) { table(:routes) }
- let(:namespace) do
- namespaces.create!(
- id: 2,
- owner_id: user.id,
- name: "Will be updated to the user's name",
- path: user.username
- )
- end
-
- it "updates the route name if it didn't match the namespace" do
- route = routes.create!(path: namespace.path, name: 'Incorrect name', source_type: 'Namespace', source_id: namespace.id)
-
- described_class.new.perform(1, 5)
-
- expect(route.reload.name).to eq("The user's full name")
- end
-
- it 'updates the route name if it was nil match the namespace' do
- route = routes.create!(path: namespace.path, name: nil, source_type: 'Namespace', source_id: namespace.id)
-
- described_class.new.perform(1, 5)
-
- expect(route.reload.name).to eq("The user's full name")
- end
-
- it "doesn't update group routes" do
- route = routes.create!(path: 'group-path', name: 'Group name', source_type: 'Group', source_id: namespace.id)
-
- expect { described_class.new.perform(1, 5) }
- .not_to change { route.reload.name }
- end
-
- it "doesn't touch routes for namespaces out of range" do
- user_namespace = namespaces.create!(
- id: 6,
- owner_id: user.id,
- name: "Should be the user's name",
- path: user.username
- )
-
- expect { described_class.new.perform(1, 5) }
- .not_to change { user_namespace.reload.name }
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb b/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb
deleted file mode 100644
index b4444df674e..00000000000
--- a/spec/lib/gitlab/background_migration/fix_user_project_route_names_spec.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::FixUserProjectRouteNames, schema: 20181228175414 do
- let(:namespaces) { table(:namespaces) }
- let(:users) { table(:users) }
- let(:routes) { table(:routes) }
- let(:projects) { table(:projects) }
-
- let(:user) { users.create!(name: "The user's full name", projects_limit: 10, username: 'not-null', email: '1') }
-
- let(:namespace) do
- namespaces.create!(
- owner_id: user.id,
- name: "Should eventually be the user's name",
- path: user.username
- )
- end
-
- let(:project) do
- projects.create!(namespace_id: namespace.id, name: 'Project Name')
- end
-
- it "updates the route for a project if it did not match the user's name" do
- route = routes.create!(
- id: 1,
- path: "#{user.username}/#{project.path}",
- source_id: project.id,
- source_type: 'Project',
- name: 'Completely wrong'
- )
-
- described_class.new.perform(1, 5)
-
- expect(route.reload.name).to eq("The user's full name / Project Name")
- end
-
- it 'updates the route for a project if the name was nil' do
- route = routes.create!(
- id: 1,
- path: "#{user.username}/#{project.path}",
- source_id: project.id,
- source_type: 'Project',
- name: nil
- )
-
- described_class.new.perform(1, 5)
-
- expect(route.reload.name).to eq("The user's full name / Project Name")
- end
-
- it 'does not update routes that were are out of the range' do
- route = routes.create!(
- id: 6,
- path: "#{user.username}/#{project.path}",
- source_id: project.id,
- source_type: 'Project',
- name: 'Completely wrong'
- )
-
- expect { described_class.new.perform(1, 5) }
- .not_to change { route.reload.name }
- end
-
- it 'does not update routes for projects in groups owned by the user' do
- group = namespaces.create!(
- owner_id: user.id,
- name: 'A group',
- path: 'a-path',
- type: ''
- )
- project = projects.create!(namespace_id: group.id, name: 'Project Name')
- route = routes.create!(
- id: 1,
- path: "#{group.path}/#{project.path}",
- source_id: project.id,
- source_type: 'Project',
- name: 'Completely wrong'
- )
-
- expect { described_class.new.perform(1, 5) }
- .not_to change { route.reload.name }
- end
-
- it 'does not update routes for namespaces' do
- route = routes.create!(
- id: 1,
- path: namespace.path,
- source_id: namespace.id,
- source_type: 'Namespace',
- name: 'Completely wrong'
- )
-
- expect { described_class.new.perform(1, 5) }
- .not_to change { route.reload.name }
- end
-end
diff --git a/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb b/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb
deleted file mode 100644
index 64e8afedf52..00000000000
--- a/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::LinkLfsObjectsProjects, :migration, schema: 20181228175414 do
- let(:namespaces) { table(:namespaces) }
- let(:projects) { table(:projects) }
- let(:fork_networks) { table(:fork_networks) }
- let(:fork_network_members) { table(:fork_network_members) }
- let(:lfs_objects) { table(:lfs_objects) }
- let(:lfs_objects_projects) { table(:lfs_objects_projects) }
-
- let(:namespace) { namespaces.create!(name: 'GitLab', path: 'gitlab') }
-
- let(:fork_network) { fork_networks.create!(root_project_id: source_project.id) }
- let(:another_fork_network) { fork_networks.create!(root_project_id: another_source_project.id) }
-
- let(:source_project) { projects.create!(namespace_id: namespace.id) }
- let(:another_source_project) { projects.create!(namespace_id: namespace.id) }
- let(:project) { projects.create!(namespace_id: namespace.id) }
- let(:another_project) { projects.create!(namespace_id: namespace.id) }
- let(:partially_linked_project) { projects.create!(namespace_id: namespace.id) }
- let(:fully_linked_project) { projects.create!(namespace_id: namespace.id) }
-
- let(:lfs_object) { lfs_objects.create!(oid: 'abc123', size: 100) }
- let(:another_lfs_object) { lfs_objects.create!(oid: 'def456', size: 200) }
-
- let!(:source_project_lop_1) do
- lfs_objects_projects.create!(
- lfs_object_id: lfs_object.id,
- project_id: source_project.id
- )
- end
-
- let!(:source_project_lop_2) do
- lfs_objects_projects.create!(
- lfs_object_id: another_lfs_object.id,
- project_id: source_project.id
- )
- end
-
- let!(:another_source_project_lop_1) do
- lfs_objects_projects.create!(
- lfs_object_id: lfs_object.id,
- project_id: another_source_project.id
- )
- end
-
- let!(:another_source_project_lop_2) do
- lfs_objects_projects.create!(
- lfs_object_id: another_lfs_object.id,
- project_id: another_source_project.id
- )
- end
-
- before do
- stub_const("#{described_class}::BATCH_SIZE", 2)
-
- # Create links between projects
- fork_network_members.create!(fork_network_id: fork_network.id, project_id: source_project.id, forked_from_project_id: nil)
-
- [project, partially_linked_project, fully_linked_project].each do |p|
- fork_network_members.create!(
- fork_network_id: fork_network.id,
- project_id: p.id,
- forked_from_project_id: fork_network.root_project_id
- )
- end
-
- fork_network_members.create!(fork_network_id: another_fork_network.id, project_id: another_source_project.id, forked_from_project_id: nil)
- fork_network_members.create!(fork_network_id: another_fork_network.id, project_id: another_project.id, forked_from_project_id: another_fork_network.root_project_id)
-
- # Links LFS objects to some projects
- lfs_objects_projects.create!(lfs_object_id: lfs_object.id, project_id: fully_linked_project.id)
- lfs_objects_projects.create!(lfs_object_id: another_lfs_object.id, project_id: fully_linked_project.id)
- lfs_objects_projects.create!(lfs_object_id: lfs_object.id, project_id: partially_linked_project.id)
- end
-
- context 'when there are LFS objects to be linked' do
- it 'creates LfsObjectsProject records for forks based on the specified range of LfsObjectProject id' do
- expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |logger|
- expect(logger).to receive(:info).exactly(4).times
- end
-
- expect { subject.perform(source_project_lop_1.id, another_source_project_lop_2.id) }.to change { lfs_objects_projects.count }.by(5)
-
- expect(lfs_object_ids_for(project)).to match_array(lfs_object_ids_for(source_project))
- expect(lfs_object_ids_for(another_project)).to match_array(lfs_object_ids_for(another_source_project))
- expect(lfs_object_ids_for(partially_linked_project)).to match_array(lfs_object_ids_for(source_project))
-
- expect { subject.perform(source_project_lop_1.id, another_source_project_lop_2.id) }.not_to change { lfs_objects_projects.count }
- end
- end
-
- context 'when there are no LFS objects to be linked' do
- before do
- # Links LFS objects to all projects
- projects.all.each do |p|
- lfs_objects_projects.create!(lfs_object_id: lfs_object.id, project_id: p.id)
- lfs_objects_projects.create!(lfs_object_id: another_lfs_object.id, project_id: p.id)
- end
- end
-
- it 'does not create LfsObjectProject records' do
- expect { subject.perform(source_project_lop_1.id, another_source_project_lop_2.id) }
- .not_to change { lfs_objects_projects.count }
- end
- end
-
- def lfs_object_ids_for(project)
- lfs_objects_projects.where(project_id: project.id).pluck(:lfs_object_id)
- end
-end
diff --git a/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb b/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb
deleted file mode 100644
index 4287d6723cf..00000000000
--- a/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::MigrateFingerprintSha256WithinKeys, schema: 20181228175414 do
- subject(:fingerprint_migrator) { described_class.new }
-
- let(:key_table) { table(:keys) }
-
- before do
- generate_fingerprints!
- end
-
- it 'correctly creates a sha256 fingerprint for a key' do
- key_1 = Key.find(1017)
- key_2 = Key.find(1027)
-
- expect(key_1.fingerprint_md5).to eq('ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1')
- expect(key_1.fingerprint_sha256).to eq(nil)
-
- expect(key_2.fingerprint_md5).to eq('39:e3:64:a6:24:ea:45:a2:8c:55:2a:e9:4d:4f:1f:b4')
- expect(key_2.fingerprint_sha256).to eq(nil)
-
- query_count = ActiveRecord::QueryRecorder.new do
- fingerprint_migrator.perform(1, 10000)
- end.count
-
- expect(query_count).to eq(8)
-
- key_1.reload
- key_2.reload
-
- expect(key_1.fingerprint_md5).to eq('ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1')
- expect(key_1.fingerprint_sha256).to eq('nUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo/lCg')
-
- expect(key_2.fingerprint_md5).to eq('39:e3:64:a6:24:ea:45:a2:8c:55:2a:e9:4d:4f:1f:b4')
- expect(key_2.fingerprint_sha256).to eq('zMNbLekgdjtcgDv8VSC0z5lpdACMG3Q4PUoIz5+H2jM')
- end
-
- context 'with invalid keys' do
- before do
- key = Key.find(1017)
- # double space after "ssh-rsa" leads to a
- # OpenSSL::PKey::PKeyError in Net::SSH::KeyFactory.load_data_public_key
- key.update_column(:key, key.key.gsub('ssh-rsa ', 'ssh-rsa '))
- end
-
- it 'ignores errors and does not set the fingerprint' do
- fingerprint_migrator.perform(1, 10000)
-
- key_1 = Key.find(1017)
- key_2 = Key.find(1027)
-
- expect(key_1.fingerprint_sha256).to be_nil
- expect(key_2.fingerprint_sha256).not_to be_nil
- end
- end
-
- it 'migrates all keys' do
- expect(Key.where(fingerprint_sha256: nil).count).to eq(Key.all.count)
-
- fingerprint_migrator.perform(1, 10000)
-
- expect(Key.where(fingerprint_sha256: nil).count).to eq(0)
- end
-
- def generate_fingerprints!
- values = ""
- (1000..2000).to_a.each do |record|
- key = base_key_for(record)
- fingerprint = fingerprint_for(key)
-
- values += "(#{record}, #{record}, 'test-#{record}', '#{key}', '#{fingerprint}'),"
- end
-
- update_query = <<~SQL
- INSERT INTO keys ( id, user_id, title, key, fingerprint )
- VALUES
- #{values.chomp(",")};
- SQL
-
- ActiveRecord::Base.connection.execute(update_query)
- end
-
- def base_key_for(record)
- 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt0000k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0='
- .gsub("0000", "%04d" % (record - 1)) # generate arbitrary keys with placeholder 0000 within the key above
- end
-
- def fingerprint_for(key)
- Gitlab::SSHPublicKey.new(key).fingerprint("md5")
- end
-end
diff --git a/spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb b/spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb
deleted file mode 100644
index b6d93b9ff54..00000000000
--- a/spec/lib/gitlab/background_migration/migrate_pages_metadata_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::MigratePagesMetadata, schema: 20181228175414 do
- let(:projects) { table(:projects) }
-
- subject(:migrate_pages_metadata) { described_class.new }
-
- describe '#perform' do
- let(:namespaces) { table(:namespaces) }
- let(:builds) { table(:ci_builds) }
- let(:pages_metadata) { table(:project_pages_metadata) }
-
- it 'marks specified projects with successful pages deployment' do
- namespace = namespaces.create!(name: 'gitlab', path: 'gitlab-org')
- not_migrated_with_pages = projects.create!(namespace_id: namespace.id, name: 'Not Migrated With Pages')
- builds.create!(project_id: not_migrated_with_pages.id, type: 'GenericCommitStatus', status: 'success', stage: 'deploy', name: 'pages:deploy')
-
- migrated = projects.create!(namespace_id: namespace.id, name: 'Migrated')
- pages_metadata.create!(project_id: migrated.id, deployed: true)
-
- not_migrated_no_pages = projects.create!(namespace_id: namespace.id, name: 'Not Migrated No Pages')
- project_not_in_relation_scope = projects.create!(namespace_id: namespace.id, name: 'Other')
-
- ids = [not_migrated_no_pages.id, not_migrated_with_pages.id, migrated.id]
-
- migrate_pages_metadata.perform(ids.min, ids.max)
-
- expect(pages_metadata.find_by_project_id(not_migrated_with_pages.id).deployed).to eq(true)
- expect(pages_metadata.find_by_project_id(not_migrated_no_pages.id).deployed).to eq(false)
- expect(pages_metadata.find_by_project_id(migrated.id).deployed).to eq(true)
- expect(pages_metadata.find_by_project_id(project_not_in_relation_scope.id)).to be_nil
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/migrate_to_hashed_storage_spec.rb b/spec/lib/gitlab/background_migration/migrate_to_hashed_storage_spec.rb
deleted file mode 100644
index 0f7bb06e830..00000000000
--- a/spec/lib/gitlab/background_migration/migrate_to_hashed_storage_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-# rubocop:disable RSpec/FactoriesInMigrationSpecs
-RSpec.describe Gitlab::BackgroundMigration::MigrateToHashedStorage, :sidekiq, :redis do
- let(:migrator) { Gitlab::HashedStorage::Migrator.new }
-
- subject(:background_migration) { described_class.new }
-
- describe '#perform' do
- let!(:project) { create(:project, :empty_repo, :legacy_storage) }
-
- context 'with pending rollback' do
- it 'aborts rollback operation' do
- Sidekiq::Testing.disable! do
- Sidekiq::Client.push(
- 'queue' => ::HashedStorage::ProjectRollbackWorker.queue,
- 'class' => ::HashedStorage::ProjectRollbackWorker,
- 'args' => [project.id]
- )
-
- expect { background_migration.perform }.to change { migrator.rollback_pending? }.from(true).to(false)
- end
- end
- end
-
- it 'enqueues legacy projects to be migrated' do
- Sidekiq::Testing.fake! do
- expect { background_migration.perform }.to change { Sidekiq::Queues[::HashedStorage::MigratorWorker.queue].size }.by(1)
- end
- end
-
- context 'when executing all jobs' do
- it 'migrates legacy projects' do
- Sidekiq::Testing.inline! do
- expect { background_migration.perform }.to change { project.reload.legacy_storage? }.from(true).to(false)
- end
- end
- end
- end
-end
-# rubocop:enable RSpec/FactoriesInMigrationSpecs
diff --git a/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb b/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb
deleted file mode 100644
index 944ee98ed4a..00000000000
--- a/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::PopulateCanonicalEmails, :migration, schema: 20181228175414 do
- let(:migration) { described_class.new }
-
- let_it_be(:users_table) { table(:users) }
- let_it_be(:user_canonical_emails_table) { table(:user_canonical_emails) }
-
- let_it_be(:users) { users_table.all }
- let_it_be(:user_canonical_emails) { user_canonical_emails_table.all }
-
- subject { migration.perform(1, 1) }
-
- describe 'gmail users' do
- using RSpec::Parameterized::TableSyntax
-
- where(:original_email, :expected_result) do
- 'legitimateuser@gmail.com' | 'legitimateuser@gmail.com'
- 'userwithplus+somestuff@gmail.com' | 'userwithplus@gmail.com'
- 'user.with.periods@gmail.com' | 'userwithperiods@gmail.com'
- 'user.with.periods.and.plus+someotherstuff@gmail.com' | 'userwithperiodsandplus@gmail.com'
- end
-
- with_them do
- it 'generates the correct canonical email' do
- create_user(email: original_email, id: 1)
-
- subject
-
- result = canonical_emails
- expect(result.count).to eq 1
- expect(result.first).to match({
- 'user_id' => 1,
- 'canonical_email' => expected_result
- })
- end
- end
- end
-
- describe 'non gmail.com domain users' do
- %w[
- legitimateuser@somedomain.com
- userwithplus+somestuff@other.com
- user.with.periods@gmail.org
- user.with.periods.and.plus+someotherstuff@orangmail.com
- ].each do |non_gmail_address|
- it 'does not generate a canonical email' do
- create_user(email: non_gmail_address, id: 1)
-
- subject
-
- expect(canonical_emails(user_id: 1).count).to eq 0
- end
- end
- end
-
- describe 'gracefully handles missing records' do
- specify { expect { subject }.not_to raise_error }
- end
-
- describe 'gracefully handles existing records, some of which may have an already-existing identical canonical_email field' do
- let_it_be(:user_one) { create_user(email: "example.user@gmail.com", id: 1) }
- let_it_be(:user_two) { create_user(email: "exampleuser@gmail.com", id: 2) }
- let_it_be(:user_email_one) { user_canonical_emails.create!(canonical_email: "exampleuser@gmail.com", user_id: user_one.id) }
-
- subject { migration.perform(1, 2) }
-
- it 'only creates one record' do
- subject
-
- expect(canonical_emails.count).not_to be_nil
- end
- end
-
- def create_user(attributes)
- default_attributes = {
- projects_limit: 0
- }
-
- users.create!(default_attributes.merge!(attributes))
- end
-
- def canonical_emails(user_id: nil)
- filter_by_id = user_id ? "WHERE user_id = #{user_id}" : ""
-
- ApplicationRecord.connection.execute <<~SQL
- SELECT canonical_email, user_id
- FROM user_canonical_emails
- #{filter_by_id};
- SQL
- end
-end
diff --git a/spec/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities_spec.rb b/spec/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities_spec.rb
deleted file mode 100644
index dc8c8c75b83..00000000000
--- a/spec/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ::Gitlab::BackgroundMigration::PopulateDismissedStateForVulnerabilities, schema: 20181228175414 do
- let(:users) { table(:users) }
- let(:namespaces) { table(:namespaces) }
- let(:projects) { table(:projects) }
- let(:vulnerabilities) { table(:vulnerabilities) }
-
- let!(:namespace) { namespaces.create!(name: "foo", path: "bar") }
- let!(:user) { users.create!(name: 'John Doe', email: 'test@example.com', projects_limit: 5) }
- let!(:project) { projects.create!(namespace_id: namespace.id) }
- let!(:vulnerability_params) do
- {
- project_id: project.id,
- author_id: user.id,
- title: 'Vulnerability',
- severity: 5,
- confidence: 5,
- report_type: 5
- }
- end
-
- let!(:vulnerability_1) { vulnerabilities.create!(vulnerability_params.merge(state: 1)) }
- let!(:vulnerability_2) { vulnerabilities.create!(vulnerability_params.merge(state: 3)) }
-
- describe '#perform' do
- it 'changes state of vulnerability to dismissed' do
- subject.perform(vulnerability_1.id, vulnerability_2.id)
-
- expect(vulnerability_1.reload.state).to eq(2)
- expect(vulnerability_2.reload.state).to eq(2)
- end
-
- it 'populates missing dismissal information' do
- expect_next_instance_of(::Gitlab::BackgroundMigration::PopulateMissingVulnerabilityDismissalInformation) do |migration|
- expect(migration).to receive(:perform).with(vulnerability_1.id, vulnerability_2.id)
- end
-
- subject.perform(vulnerability_1.id, vulnerability_2.id)
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/populate_has_vulnerabilities_spec.rb b/spec/lib/gitlab/background_migration/populate_has_vulnerabilities_spec.rb
deleted file mode 100644
index 6722321d5f7..00000000000
--- a/spec/lib/gitlab/background_migration/populate_has_vulnerabilities_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::PopulateHasVulnerabilities, schema: 20181228175414 do
- let(:users) { table(:users) }
- let(:namespaces) { table(:namespaces) }
- let(:projects) { table(:projects) }
- let(:project_settings) { table(:project_settings) }
- let(:vulnerabilities) { table(:vulnerabilities) }
-
- let(:user) { users.create!(name: 'test', email: 'test@example.com', projects_limit: 5) }
- let(:namespace) { namespaces.create!(name: 'gitlab', path: 'gitlab-org') }
- let(:vulnerability_base_params) { { title: 'title', state: 2, severity: 0, confidence: 5, report_type: 2, author_id: user.id } }
-
- let!(:project_1) { projects.create!(namespace_id: namespace.id, name: 'foo_1') }
- let!(:project_2) { projects.create!(namespace_id: namespace.id, name: 'foo_2') }
- let!(:project_3) { projects.create!(namespace_id: namespace.id, name: 'foo_3') }
-
- before do
- project_settings.create!(project_id: project_1.id)
- vulnerabilities.create!(vulnerability_base_params.merge(project_id: project_1.id))
- vulnerabilities.create!(vulnerability_base_params.merge(project_id: project_3.id))
-
- allow(::Gitlab::BackgroundMigration::Logger).to receive_messages(info: true, error: true)
- end
-
- describe '#perform' do
- it 'sets `has_vulnerabilities` attribute of project_settings' do
- expect { subject.perform(project_1.id, project_3.id) }.to change { project_settings.count }.from(1).to(2)
- .and change { project_settings.where(has_vulnerabilities: true).count }.from(0).to(2)
- end
-
- it 'writes info log message' do
- subject.perform(project_1.id, project_3.id)
-
- expect(::Gitlab::BackgroundMigration::Logger).to have_received(:info).with(migrator: described_class.name,
- message: 'Projects has been processed to populate `has_vulnerabilities` information',
- count: 2)
- end
-
- context 'when non-existing project_id is given' do
- it 'populates only for the existing projects' do
- expect { subject.perform(project_1.id, 0, project_3.id) }.to change { project_settings.count }.from(1).to(2)
- .and change { project_settings.where(has_vulnerabilities: true).count }.from(0).to(2)
- end
- end
-
- context 'when an error happens' do
- before do
- allow(described_class::ProjectSetting).to receive(:upsert_for).and_raise('foo')
- end
-
- it 'writes error log message' do
- subject.perform(project_1.id, project_3.id)
-
- expect(::Gitlab::BackgroundMigration::Logger).to have_received(:error).with(migrator: described_class.name,
- message: 'foo',
- project_ids: [project_1.id, project_3.id])
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
deleted file mode 100644
index 1d8eed53553..00000000000
--- a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::PopulateMergeRequestAssigneesTable, schema: 20181228175414 do
- let(:namespaces) { table(:namespaces) }
- let(:projects) { table(:projects) }
- let(:users) { table(:users) }
-
- let(:user) { users.create!(email: 'test@example.com', projects_limit: 100, username: 'test') }
- let(:user_2) { users.create!(email: 'test2@example.com', projects_limit: 100, username: 'test') }
- let(:user_3) { users.create!(email: 'test3@example.com', projects_limit: 100, username: 'test') }
-
- let(:namespace) { namespaces.create!(name: 'gitlab', path: 'gitlab-org') }
- let(:project) { projects.create!(namespace_id: namespace.id, name: 'foo') }
- let(:merge_requests) { table(:merge_requests) }
- let(:merge_request_assignees) { table(:merge_request_assignees) }
-
- def create_merge_request(id, params = {})
- params.merge!(id: id,
- target_project_id: project.id,
- target_branch: 'master',
- source_project_id: project.id,
- source_branch: 'mr name',
- title: "mr name#{id}")
-
- merge_requests.create!(params)
- end
-
- before do
- create_merge_request(2, assignee_id: user.id)
- create_merge_request(3, assignee_id: user_2.id)
- create_merge_request(4, assignee_id: user_3.id)
-
- # Test filtering MRs without assignees
- create_merge_request(5, assignee_id: nil)
- # Test filtering already migrated row
- merge_request_assignees.create!(merge_request_id: 2, user_id: user_3.id)
- end
-
- describe '#perform' do
- it 'creates merge_request_assignees rows according to merge_requests' do
- subject.perform(1, 4)
-
- rows = merge_request_assignees.order(:id).map { |row| row.attributes.slice('merge_request_id', 'user_id') }
- existing_rows = [
- { 'merge_request_id' => 2, 'user_id' => user_3.id }
- ]
- created_rows = [
- { 'merge_request_id' => 3, 'user_id' => user_2.id },
- { 'merge_request_id' => 4, 'user_id' => user_3.id }
- ]
- expected_rows = existing_rows + created_rows
-
- expect(rows.size).to eq(expected_rows.size)
- expected_rows.each do |expected_row|
- expect(rows).to include(expected_row)
- end
- end
- end
-
- describe '#perform_all_sync' do
- it 'executes peform for all merge requests in batches' do
- expect(subject).to receive(:perform).with(2, 4).ordered
- expect(subject).to receive(:perform).with(5, 5).ordered
-
- subject.perform_all_sync(batch_size: 3)
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information_spec.rb b/spec/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information_spec.rb
deleted file mode 100644
index 1c987d3876f..00000000000
--- a/spec/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::PopulateMissingVulnerabilityDismissalInformation, schema: 20181228175414 do
- let(:users) { table(:users) }
- let(:namespaces) { table(:namespaces) }
- let(:projects) { table(:projects) }
- let(:vulnerabilities) { table(:vulnerabilities) }
- let(:findings) { table(:vulnerability_occurrences) }
- let(:scanners) { table(:vulnerability_scanners) }
- let(:identifiers) { table(:vulnerability_identifiers) }
- let(:feedback) { table(:vulnerability_feedback) }
-
- let(:user) { users.create!(name: 'test', email: 'test@example.com', projects_limit: 5) }
- let(:namespace) { namespaces.create!(name: 'gitlab', path: 'gitlab-org') }
- let(:project) { projects.create!(namespace_id: namespace.id, name: 'foo') }
- let(:vulnerability_1) { vulnerabilities.create!(title: 'title', state: 2, severity: 0, confidence: 5, report_type: 2, project_id: project.id, author_id: user.id) }
- let(:vulnerability_2) { vulnerabilities.create!(title: 'title', state: 2, severity: 0, confidence: 5, report_type: 2, project_id: project.id, author_id: user.id) }
- let(:scanner) { scanners.create!(project_id: project.id, external_id: 'foo', name: 'bar') }
- let(:identifier) { identifiers.create!(project_id: project.id, fingerprint: 'foo', external_type: 'bar', external_id: 'zoo', name: 'identifier') }
-
- before do
- feedback.create!(feedback_type: 0,
- category: 'sast',
- project_fingerprint: '418291a26024a1445b23fe64de9380cdcdfd1fa8',
- project_id: project.id,
- author_id: user.id,
- created_at: Time.current)
-
- findings.create!(name: 'Finding',
- report_type: 'sast',
- project_fingerprint: Gitlab::Database::ShaAttribute.new.serialize('418291a26024a1445b23fe64de9380cdcdfd1fa8'),
- location_fingerprint: 'bar',
- severity: 1,
- confidence: 1,
- metadata_version: 1,
- raw_metadata: '',
- uuid: SecureRandom.uuid,
- project_id: project.id,
- vulnerability_id: vulnerability_1.id,
- scanner_id: scanner.id,
- primary_identifier_id: identifier.id)
-
- allow(::Gitlab::BackgroundMigration::Logger).to receive_messages(info: true, warn: true, error: true)
- end
-
- describe '#perform' do
- it 'updates the missing dismissal information of the vulnerability' do
- expect { subject.perform(vulnerability_1.id, vulnerability_2.id) }.to change { vulnerability_1.reload.dismissed_at }.from(nil)
- .and change { vulnerability_1.reload.dismissed_by_id }.from(nil).to(user.id)
- end
-
- it 'writes log messages' do
- subject.perform(vulnerability_1.id, vulnerability_2.id)
-
- expect(::Gitlab::BackgroundMigration::Logger).to have_received(:info).with(migrator: described_class.name,
- message: 'Dismissal information has been copied',
- count: 2)
- expect(::Gitlab::BackgroundMigration::Logger).to have_received(:warn).with(migrator: described_class.name,
- message: 'Could not update vulnerability!',
- vulnerability_id: vulnerability_2.id)
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/populate_personal_snippet_statistics_spec.rb b/spec/lib/gitlab/background_migration/populate_personal_snippet_statistics_spec.rb
deleted file mode 100644
index f9628849dbf..00000000000
--- a/spec/lib/gitlab/background_migration/populate_personal_snippet_statistics_spec.rb
+++ /dev/null
@@ -1,141 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::PopulatePersonalSnippetStatistics do
- let(:file_name) { 'file_name.rb' }
- let(:content) { 'content' }
- let(:snippets) { table(:snippets) }
- let(:snippet_repositories) { table(:snippet_repositories) }
- let(:users) { table(:users) }
- let(:namespaces) { table(:namespaces) }
- let(:snippet_statistics) { table(:snippet_statistics) }
- let(:namespace_statistics) { table(:namespace_root_storage_statistics) }
- let(:routes) { table(:routes) }
- let(:repo_size) { 123456 }
- let(:expected_repo_size) { repo_size.megabytes }
-
- let(:user1) { users.create!(id: 1, email: 'test@example.com', projects_limit: 100, username: 'test1') }
- let(:user2) { users.create!(id: 2, email: 'test2@example.com', projects_limit: 100, username: 'test2') }
- let!(:user1_namespace) { namespaces.create!(id: 1, name: 'user1', path: 'user1', owner_id: user1.id) }
- let!(:user2_namespace) { namespaces.create!(id: 2, name: 'user2', path: 'user2', owner_id: user2.id) }
- let(:user1_namespace_statistics) { namespace_statistics.find_by(namespace_id: user1_namespace.id) }
- let(:user2_namespace_statistics) { namespace_statistics.find_by(namespace_id: user2_namespace.id) }
-
- let(:ids) { snippets.pluck(:id) }
- let(:migration) { described_class.new }
-
- subject do
- migration.perform(ids)
- end
-
- before do
- allow_any_instance_of(Repository).to receive(:size).and_return(repo_size)
- end
-
- after do
- snippets.all.each { |s| raw_repository(s).remove }
- end
-
- context 'with existing personal snippets' do
- let!(:snippet1) { create_snippet(1, user1) }
- let!(:snippet2) { create_snippet(2, user1) }
- let!(:snippet3) { create_snippet(3, user2) }
- let!(:snippet4) { create_snippet(4, user2) }
-
- before do
- create_snippet_statistics(2, 0)
- create_snippet_statistics(4, 123)
- end
-
- it 'creates/updates all snippet_statistics' do
- expect { subject }.to change { snippet_statistics.count }.from(2).to(4)
-
- expect(snippet_statistics.pluck(:repository_size)).to be_all(expected_repo_size)
- end
-
- it 'creates/updates the associated namespace statistics' do
- expect(migration).to receive(:update_namespace_statistics).twice.and_call_original
-
- subject
-
- stats = snippet_statistics.where(snippet_id: [snippet1, snippet2]).sum(:repository_size)
- expect(user1_namespace_statistics.snippets_size).to eq stats
-
- stats = snippet_statistics.where(snippet_id: [snippet3, snippet4]).sum(:repository_size)
- expect(user2_namespace_statistics.snippets_size).to eq stats
- end
-
- context 'when an error is raised when updating a namespace statistics' do
- it 'logs the error and continue execution' do
- expect_next_instance_of(Namespaces::StatisticsRefresherService) do |instance|
- expect(instance).to receive(:execute).with(Namespace.find(user1_namespace.id)).and_raise('Error')
- end
-
- expect_next_instance_of(Namespaces::StatisticsRefresherService) do |instance|
- expect(instance).to receive(:execute).and_call_original
- end
-
- expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |instance|
- expect(instance).to receive(:error).with(message: /Error updating statistics for namespace/).once
- end
-
- subject
-
- expect(user1_namespace_statistics).to be_nil
-
- stats = snippet_statistics.where(snippet_id: [snippet3, snippet4]).sum(:repository_size)
- expect(user2_namespace_statistics.snippets_size).to eq stats
- end
- end
- end
-
- context 'when a snippet repository is empty' do
- let!(:snippet1) { create_snippet(1, user1, with_repo: false) }
- let!(:snippet2) { create_snippet(2, user1) }
-
- it 'logs error and continues execution' do
- expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |instance|
- expect(instance).to receive(:error).with(message: /Invalid snippet repository/).once
- end
-
- subject
-
- expect(snippet_statistics.find_by(snippet_id: snippet1.id)).to be_nil
- expect(user1_namespace_statistics.snippets_size).to eq expected_repo_size
- end
- end
-
- def create_snippet(id, author, with_repo: true)
- snippets.create!(id: id, type: 'PersonalSnippet', author_id: author.id, file_name: file_name, content: content).tap do |snippet|
- if with_repo
- allow(snippet).to receive(:disk_path).and_return(disk_path(snippet))
-
- raw_repository(snippet).create_repository
-
- TestEnv.copy_repo(snippet,
- bare_repo: TestEnv.factory_repo_path_bare,
- refs: TestEnv::BRANCH_SHA)
- end
- end
- end
-
- def create_snippet_statistics(snippet_id, repository_size = 0)
- snippet_statistics.create!(snippet_id: snippet_id, repository_size: repository_size)
- end
-
- def raw_repository(snippet)
- Gitlab::Git::Repository.new('default',
- "#{disk_path(snippet)}.git",
- Gitlab::GlRepository::SNIPPET.identifier_for_container(snippet),
- "@snippets/#{snippet.id}")
- end
-
- def hashed_repository(snippet)
- Storage::Hashed.new(snippet, prefix: '@snippets')
- end
-
- def disk_path(snippet)
- hashed_repository(snippet).disk_path
- end
-end
diff --git a/spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb b/spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb
deleted file mode 100644
index 7884e0d97c0..00000000000
--- a/spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::PopulateProjectSnippetStatistics do
- let(:file_name) { 'file_name.rb' }
- let(:content) { 'content' }
- let(:snippets) { table(:snippets) }
- let(:snippet_repositories) { table(:snippet_repositories) }
- let(:users) { table(:users) }
- let(:namespaces) { table(:namespaces) }
- let(:snippet_statistics) { table(:snippet_statistics) }
- let(:project_statistics) { table(:project_statistics) }
- let(:projects) { table(:projects) }
- let(:namespace_statistics) { table(:namespace_root_storage_statistics) }
- let(:routes) { table(:routes) }
- let(:repo_size) { 123456 }
- let(:expected_repo_size) { repo_size.megabytes }
-
- let(:user) { users.create!(id: 1, email: 'test@example.com', projects_limit: 100, username: 'test') }
- let(:group) { namespaces.create!(id: 10, type: 'Group', name: 'group1', path: 'group1') }
- let(:user_namespace) { namespaces.create!(id: 20, name: 'user', path: 'user', owner_id: user.id) }
-
- let(:project1) { create_project(1, 'test', group) }
- let(:project2) { create_project(2, 'test1', user_namespace) }
- let(:project3) { create_project(3, 'test2', group) }
-
- let!(:project_stats1) { create_project_statistics(project1) }
- let!(:project_stats2) { create_project_statistics(project2) }
- let!(:project_stats3) { create_project_statistics(project3) }
-
- let(:ids) { snippets.pluck(:id) }
- let(:migration) { described_class.new }
-
- subject do
- migration.perform(ids)
-
- project_stats1.reload if project_stats1.persisted?
- project_stats2.reload if project_stats2.persisted?
- project_stats3.reload if project_stats3.persisted?
- end
-
- before do
- allow_any_instance_of(Repository).to receive(:size).and_return(repo_size)
- end
-
- after do
- snippets.all.each { |s| raw_repository(s).remove }
- end
-
- context 'with existing user and group snippets' do
- let!(:snippet1) { create_snippet(1, project1) }
- let!(:snippet2) { create_snippet(2, project1) }
- let!(:snippet3) { create_snippet(3, project2) }
- let!(:snippet4) { create_snippet(4, project2) }
- let!(:snippet5) { create_snippet(5, project3) }
-
- before do
- create_snippet_statistics(2, 0)
- create_snippet_statistics(4, 123)
- end
-
- it 'creates/updates all snippet_statistics' do
- expect(snippet_statistics.count).to eq 2
-
- subject
-
- expect(snippet_statistics.count).to eq 5
-
- snippet_statistics.all.each do |stat|
- expect(stat.repository_size).to eq expected_repo_size
- end
- end
-
- it 'updates associated snippet project statistics' do
- expect(project_stats1.snippets_size).to be_nil
- expect(project_stats2.snippets_size).to be_nil
-
- subject
-
- snippets_size = snippet_statistics.where(snippet_id: [snippet1.id, snippet2.id]).sum(:repository_size)
- expect(project_stats1.snippets_size).to eq snippets_size
-
- snippets_size = snippet_statistics.where(snippet_id: [snippet3.id, snippet4.id]).sum(:repository_size)
- expect(project_stats2.snippets_size).to eq snippets_size
-
- snippets_size = snippet_statistics.where(snippet_id: snippet5.id).sum(:repository_size)
- expect(project_stats3.snippets_size).to eq snippets_size
- end
-
- it 'forces the project statistics refresh' do
- expect(migration).to receive(:update_project_statistics).exactly(3).times
-
- subject
- end
-
- it 'creates/updates the associated namespace statistics' do
- expect(migration).to receive(:update_namespace_statistics).twice.and_call_original
-
- subject
-
- expect(namespace_statistics.find_by(namespace_id: group.id).snippets_size).to eq project_stats1.snippets_size + project_stats3.snippets_size
- expect(namespace_statistics.find_by(namespace_id: user_namespace.id).snippets_size).to eq project_stats2.snippets_size
- end
-
- context 'when the project statistics does not exists' do
- it 'does not raise any error' do
- project_stats3.delete
-
- subject
-
- expect(namespace_statistics.find_by(namespace_id: group.id).snippets_size).to eq project_stats1.snippets_size
- expect(namespace_statistics.find_by(namespace_id: user_namespace.id).snippets_size).to eq project_stats2.snippets_size
- end
- end
-
- context 'when an error is raised when updating a project statistics' do
- it 'logs the error and continue execution' do
- expect(migration).to receive(:update_project_statistics).with(Project.find(project1.id)).and_raise('Error')
- expect(migration).to receive(:update_project_statistics).with(Project.find(project2.id)).and_call_original
- expect(migration).to receive(:update_project_statistics).with(Project.find(project3.id)).and_call_original
-
- expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |instance|
- expect(instance).to receive(:error).with(message: /Error updating statistics for project #{project1.id}/).once
- end
-
- subject
-
- expect(project_stats2.snippets_size).not_to be_nil
- expect(project_stats3.snippets_size).not_to be_nil
- end
- end
-
- context 'when an error is raised when updating a namespace statistics' do
- it 'logs the error and continue execution' do
- expect(migration).to receive(:update_namespace_statistics).with(Group.find(group.id)).and_raise('Error')
- expect(migration).to receive(:update_namespace_statistics).with(Namespace.find(user_namespace.id)).and_call_original
-
- expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |instance|
- expect(instance).to receive(:error).with(message: /Error updating statistics for namespace/).once
- end
-
- subject
-
- expect(namespace_statistics.find_by(namespace_id: user_namespace.id).snippets_size).to eq project_stats2.snippets_size
- end
- end
- end
-
- context 'when project snippet is in a subgroup' do
- let(:subgroup) { namespaces.create!(id: 30, type: 'Group', name: 'subgroup', path: 'subgroup', parent_id: group.id) }
- let(:project1) { create_project(1, 'test', subgroup, "#{group.path}/#{subgroup.path}/test") }
- let!(:snippet1) { create_snippet(1, project1) }
-
- it 'updates the root namespace statistics' do
- subject
-
- expect(snippet_statistics.count).to eq 1
- expect(project_stats1.snippets_size).to eq snippet_statistics.first.repository_size
- expect(namespace_statistics.find_by(namespace_id: subgroup.id)).to be_nil
- expect(namespace_statistics.find_by(namespace_id: group.id).snippets_size).to eq project_stats1.snippets_size
- end
- end
-
- context 'when a snippet repository is empty' do
- let!(:snippet1) { create_snippet(1, project1, with_repo: false) }
- let!(:snippet2) { create_snippet(2, project1) }
-
- it 'logs error and continues execution' do
- expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |instance|
- expect(instance).to receive(:error).with(message: /Invalid snippet repository/).once
- end
-
- subject
-
- expect(snippet_statistics.find_by(snippet_id: snippet1.id)).to be_nil
- expect(project_stats1.snippets_size).to eq snippet_statistics.find(snippet2.id).repository_size
- end
- end
-
- def create_snippet(id, project, with_repo: true)
- snippets.create!(id: id, type: 'ProjectSnippet', project_id: project.id, author_id: user.id, file_name: file_name, content: content).tap do |snippet|
- if with_repo
- allow(snippet).to receive(:disk_path).and_return(disk_path(snippet))
-
- raw_repository(snippet).create_repository
-
- TestEnv.copy_repo(snippet,
- bare_repo: TestEnv.factory_repo_path_bare,
- refs: TestEnv::BRANCH_SHA)
- end
- end
- end
-
- def create_project(id, name, namespace, path = nil)
- projects.create!(id: id, name: name, path: name.downcase.gsub(/\s/, '_'), namespace_id: namespace.id).tap do |project|
- path ||= "#{namespace.path}/#{project.path}"
- routes.create!(id: id, source_type: 'Project', source_id: project.id, path: path)
- end
- end
-
- def create_snippet_statistics(snippet_id, repository_size = 0)
- snippet_statistics.create!(snippet_id: snippet_id, repository_size: repository_size)
- end
-
- def create_project_statistics(project, snippets_size = nil)
- project_statistics.create!(id: project.id, project_id: project.id, namespace_id: project.namespace_id, snippets_size: snippets_size)
- end
-
- def raw_repository(snippet)
- Gitlab::Git::Repository.new('default',
- "#{disk_path(snippet)}.git",
- Gitlab::GlRepository::SNIPPET.identifier_for_container(snippet),
- "@snippets/#{snippet.id}")
- end
-
- def hashed_repository(snippet)
- Storage::Hashed.new(snippet, prefix: '@snippets')
- end
-
- def disk_path(snippet)
- hashed_repository(snippet).disk_path
- end
-end
diff --git a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb
deleted file mode 100644
index 1830a7fc099..00000000000
--- a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizationsWithMinMaxUserId, schema: 20181228175414 do
- let(:users_table) { table(:users) }
- let(:min) { 1 }
- let(:max) { 5 }
-
- before do
- min.upto(max) do |i|
- users_table.create!(id: i, email: "user#{i}@example.com", projects_limit: 10)
- end
- end
-
- describe '#perform' do
- it 'initializes Users::RefreshAuthorizedProjectsService with correct users' do
- min.upto(max) do |i|
- user = User.find(i)
- expect(Users::RefreshAuthorizedProjectsService).to(
- receive(:new).with(user, any_args).and_call_original)
- end
-
- described_class.new.perform(min, max)
- end
-
- it 'executes Users::RefreshAuthorizedProjectsService' do
- expected_call_counts = max - min + 1
-
- service = instance_double(Users::RefreshAuthorizedProjectsService)
- expect(Users::RefreshAuthorizedProjectsService).to(
- receive(:new).exactly(expected_call_counts).times.and_return(service))
- expect(service).to receive(:execute).exactly(expected_call_counts).times
-
- described_class.new.perform(min, max)
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb b/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb
deleted file mode 100644
index 6cfdbb5a14e..00000000000
--- a/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::ReplaceBlockedByLinks, schema: 20181228175414 do
- let(:namespace) { table(:namespaces).create!(name: 'gitlab', path: 'gitlab-org') }
- let(:project) { table(:projects).create!(namespace_id: namespace.id, name: 'gitlab') }
- let(:issue1) { table(:issues).create!(project_id: project.id, title: 'a') }
- let(:issue2) { table(:issues).create!(project_id: project.id, title: 'b') }
- let(:issue3) { table(:issues).create!(project_id: project.id, title: 'c') }
- let(:issue_links) { table(:issue_links) }
- let!(:blocked_link1) { issue_links.create!(source_id: issue2.id, target_id: issue1.id, link_type: 2) }
- let!(:opposite_link1) { issue_links.create!(source_id: issue1.id, target_id: issue2.id, link_type: 1) }
- let!(:blocked_link2) { issue_links.create!(source_id: issue1.id, target_id: issue3.id, link_type: 2) }
- let!(:opposite_link2) { issue_links.create!(source_id: issue3.id, target_id: issue1.id, link_type: 0) }
- let!(:nochange_link) { issue_links.create!(source_id: issue2.id, target_id: issue3.id, link_type: 1) }
-
- subject { described_class.new.perform(issue_links.minimum(:id), issue_links.maximum(:id)) }
-
- it 'deletes any opposite relations' do
- subject
-
- expect(issue_links.ids).to match_array([nochange_link.id, blocked_link1.id, blocked_link2.id])
- end
-
- it 'ignores issue links other than blocked_by' do
- subject
-
- expect(nochange_link.reload.link_type).to eq(1)
- end
-
- it 'updates blocked_by issue links' do
- subject
-
- expect(blocked_link1.reload.link_type).to eq(1)
- expect(blocked_link1.source_id).to eq(issue1.id)
- expect(blocked_link1.target_id).to eq(issue2.id)
- expect(blocked_link2.reload.link_type).to eq(1)
- expect(blocked_link2.source_id).to eq(issue3.id)
- expect(blocked_link2.target_id).to eq(issue1.id)
- end
-end
diff --git a/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb b/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb
deleted file mode 100644
index 2f5074649c4..00000000000
--- a/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::ResetMergeStatus do
- let(:namespaces) { table(:namespaces) }
- let(:projects) { table(:projects) }
- let(:namespace) { namespaces.create!(name: 'gitlab', path: 'gitlab-org') }
- let(:project) { projects.create!(namespace_id: namespace.id, name: 'foo') }
- let(:merge_requests) { table(:merge_requests) }
-
- def create_merge_request(id, extra_params = {})
- params = {
- id: id,
- target_project_id: project.id,
- target_branch: 'master',
- source_project_id: project.id,
- source_branch: 'mr name',
- title: "mr name#{id}"
- }.merge(extra_params)
-
- merge_requests.create!(params)
- end
-
- it 'correctly updates opened mergeable MRs to unchecked' do
- create_merge_request(1, state_id: MergeRequest.available_states[:opened], merge_status: 'can_be_merged')
- create_merge_request(2, state_id: MergeRequest.available_states[:opened], merge_status: 'can_be_merged')
- create_merge_request(3, state_id: MergeRequest.available_states[:opened], merge_status: 'can_be_merged')
- create_merge_request(4, state_id: MergeRequest.available_states[:merged], merge_status: 'can_be_merged')
- create_merge_request(5, state_id: MergeRequest.available_states[:opened], merge_status: 'cannot_be_merged')
-
- subject.perform(1, 5)
-
- expected_rows = [
- { id: 1, state_id: MergeRequest.available_states[:opened], merge_status: 'unchecked' },
- { id: 2, state_id: MergeRequest.available_states[:opened], merge_status: 'unchecked' },
- { id: 3, state_id: MergeRequest.available_states[:opened], merge_status: 'unchecked' },
- { id: 4, state_id: MergeRequest.available_states[:merged], merge_status: 'can_be_merged' },
- { id: 5, state_id: MergeRequest.available_states[:opened], merge_status: 'cannot_be_merged' }
- ]
-
- rows = merge_requests.order(:id).map do |row|
- row.attributes.slice('id', 'state_id', 'merge_status').symbolize_keys
- end
-
- expect(rows).to eq(expected_rows)
- end
-end
diff --git a/spec/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects_spec.rb b/spec/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects_spec.rb
deleted file mode 100644
index ef90b5674f0..00000000000
--- a/spec/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::ResetSharedRunnersForTransferredProjects, schema: 20181228175414 do
- let(:namespaces) { table(:namespaces) }
- let(:projects) { table(:projects) }
-
- let(:namespace_1) { namespaces.create!(name: 'foo', path: 'foo', shared_runners_enabled: true, allow_descendants_override_disabled_shared_runners: false ) }
- let(:namespace_2) { namespaces.create!(name: 'foo', path: 'foo', shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: false ) }
- let(:namespace_3) { namespaces.create!(name: 'bar', path: 'bar', shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: true ) }
- let(:project_1_1) { projects.create!(namespace_id: namespace_1.id, shared_runners_enabled: true) }
- let(:project_1_2) { projects.create!(namespace_id: namespace_1.id, shared_runners_enabled: false) }
- let(:project_2_1) { projects.create!(namespace_id: namespace_2.id, shared_runners_enabled: true) }
- let(:project_2_2) { projects.create!(namespace_id: namespace_2.id, shared_runners_enabled: false) }
- let(:project_3_1) { projects.create!(namespace_id: namespace_3.id, shared_runners_enabled: true) }
- let(:project_3_2) { projects.create!(namespace_id: namespace_3.id, shared_runners_enabled: false) }
-
- it 'corrects each project shared_runners_enabled column' do
- expect do
- described_class.new.perform(namespace_1.id, namespace_3.id)
- project_1_1.reload
- project_1_2.reload
- project_2_1.reload
- project_2_2.reload
- project_3_1.reload
- project_3_2.reload
- end.to not_change(project_1_1, :shared_runners_enabled).from(true)
- .and not_change(project_1_2, :shared_runners_enabled).from(false)
- .and change(project_2_1, :shared_runners_enabled).from(true).to(false)
- .and not_change(project_2_2, :shared_runners_enabled).from(false)
- .and not_change(project_3_1, :shared_runners_enabled).from(true)
- .and not_change(project_3_2, :shared_runners_enabled).from(false)
- end
-end
diff --git a/spec/lib/gitlab/background_migration/set_merge_request_diff_files_count_spec.rb b/spec/lib/gitlab/background_migration/set_merge_request_diff_files_count_spec.rb
deleted file mode 100644
index 1fdbdf25706..00000000000
--- a/spec/lib/gitlab/background_migration/set_merge_request_diff_files_count_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::SetMergeRequestDiffFilesCount, schema: 20181228175414 do
- let(:merge_request_diff_files) { table(:merge_request_diff_files) }
- let(:merge_request_diffs) { table(:merge_request_diffs) }
- let(:merge_requests) { table(:merge_requests) }
- let(:namespaces) { table(:namespaces) }
- let(:projects) { table(:projects) }
-
- let(:namespace) { namespaces.create!(name: 'foo', path: 'foo') }
- let(:project) { projects.create!(namespace_id: namespace.id) }
- let(:merge_request) { merge_requests.create!(source_branch: 'x', target_branch: 'master', target_project_id: project.id) }
-
- let!(:empty_diff) { merge_request_diffs.create!(merge_request_id: merge_request.id) }
- let!(:filled_diff) { merge_request_diffs.create!(merge_request_id: merge_request.id) }
-
- let!(:filled_diff_files) do
- 1.upto(3).map do |n|
- merge_request_diff_files.create!(
- merge_request_diff_id: filled_diff.id,
- relative_order: n,
- new_file: false,
- renamed_file: false,
- deleted_file: false,
- too_large: false,
- a_mode: '',
- b_mode: '',
- old_path: '',
- new_path: ''
- )
- end
- end
-
- it 'fills the files_count column' do
- described_class.new.perform(empty_diff.id, filled_diff.id)
-
- expect(empty_diff.reload.files_count).to eq(0)
- expect(filled_diff.reload.files_count).to eq(3)
- end
-
- it 'uses the sentinel value if the actual count is too high' do
- stub_const("#{described_class}::FILES_COUNT_SENTINEL", filled_diff_files.size - 1)
-
- described_class.new.perform(empty_diff.id, filled_diff.id)
-
- expect(empty_diff.reload.files_count).to eq(0)
- expect(filled_diff.reload.files_count).to eq(described_class::FILES_COUNT_SENTINEL)
- end
-end
diff --git a/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb b/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb
deleted file mode 100644
index de9799c3642..00000000000
--- a/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::UpdateExistingSubgroupToMatchVisibilityLevelOfParent, schema: 20181228175414 do
- include MigrationHelpers::NamespacesHelpers
-
- context 'private visibility level' do
- it 'updates the project visibility' do
- parent = create_namespace('parent', Gitlab::VisibilityLevel::PRIVATE)
- child = create_namespace('child', Gitlab::VisibilityLevel::PUBLIC, parent_id: parent.id)
-
- expect { subject.perform([parent.id], Gitlab::VisibilityLevel::PRIVATE) }.to change { child.reload.visibility_level }.to(Gitlab::VisibilityLevel::PRIVATE)
- end
-
- it 'updates sub-sub groups' do
- parent = create_namespace('parent', Gitlab::VisibilityLevel::PRIVATE)
- middle_group = create_namespace('middle', Gitlab::VisibilityLevel::PRIVATE, parent_id: parent.id)
- child = create_namespace('child', Gitlab::VisibilityLevel::PUBLIC, parent_id: middle_group.id)
-
- subject.perform([parent.id, middle_group.id], Gitlab::VisibilityLevel::PRIVATE)
-
- expect(child.reload.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
- end
-
- it 'updates all sub groups' do
- parent = create_namespace('parent', Gitlab::VisibilityLevel::PRIVATE)
- middle_group = create_namespace('middle', Gitlab::VisibilityLevel::PUBLIC, parent_id: parent.id)
- child = create_namespace('child', Gitlab::VisibilityLevel::PUBLIC, parent_id: middle_group.id)
-
- subject.perform([parent.id], Gitlab::VisibilityLevel::PRIVATE)
-
- expect(child.reload.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
- expect(middle_group.reload.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
- end
- end
-
- context 'internal visibility level' do
- it 'updates the project visibility' do
- parent = create_namespace('parent', Gitlab::VisibilityLevel::INTERNAL)
- child = create_namespace('child', Gitlab::VisibilityLevel::PUBLIC, parent_id: parent.id)
-
- expect { subject.perform([parent.id], Gitlab::VisibilityLevel::INTERNAL) }.to change { child.reload.visibility_level }.to(Gitlab::VisibilityLevel::INTERNAL)
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth_spec.rb b/spec/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth_spec.rb
deleted file mode 100644
index 33f5e38100e..00000000000
--- a/spec/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth_spec.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::UpdateExistingUsersThatRequireTwoFactorAuth, schema: 20181228175414 do
- include MigrationHelpers::NamespacesHelpers
-
- let(:group_with_2fa_parent) { create_namespace('parent', Gitlab::VisibilityLevel::PRIVATE) }
- let(:group_with_2fa_child) { create_namespace('child', Gitlab::VisibilityLevel::PRIVATE, parent_id: group_with_2fa_parent.id) }
- let(:members_table) { table(:members) }
- let(:users_table) { table(:users) }
-
- subject { described_class.new }
-
- describe '#perform' do
- context 'with group members' do
- let(:user_1) { create_user('user@example.com') }
- let!(:member) { create_group_member(user_1, group_with_2fa_parent) }
- let!(:user_without_group) { create_user('user_without@example.com') }
- let(:user_other) { create_user('user_other@example.com') }
- let!(:member_other) { create_group_member(user_other, group_with_2fa_parent) }
-
- it 'updates user when user should not be required to establish two factor authentication' do
- subject.perform(user_1.id, user_without_group.id)
-
- expect(user_1.reload.require_two_factor_authentication_from_group).to eq(false)
- end
-
- it 'does not update user when user is member of group that requires two factor authentication' do
- group = create_namespace('other', Gitlab::VisibilityLevel::PRIVATE, require_two_factor_authentication: true)
- create_group_member(user_1, group)
-
- subject.perform(user_1.id, user_without_group.id)
-
- expect(user_1.reload.require_two_factor_authentication_from_group).to eq(true)
- end
-
- it 'does not update user who is not in current batch' do
- subject.perform(user_1.id, user_without_group.id)
-
- expect(user_other.reload.require_two_factor_authentication_from_group).to eq(true)
- end
-
- it 'updates all users in current batch' do
- subject.perform(user_1.id, user_other.id)
-
- expect(user_other.reload.require_two_factor_authentication_from_group).to eq(false)
- end
-
- it 'does not update user when user is member of group which parent group requires two factor authentication' do
- group_with_2fa_parent.update!(require_two_factor_authentication: true)
- subject.perform(user_1.id, user_other.id)
-
- expect(user_1.reload.require_two_factor_authentication_from_group).to eq(true)
- end
-
- it 'does not update user when user is member of group which has subgroup that requires two factor authentication' do
- create_namespace('subgroup', Gitlab::VisibilityLevel::PRIVATE, require_two_factor_authentication: true, parent_id: group_with_2fa_child.id)
-
- subject.perform(user_1.id, user_other.id)
-
- expect(user_1.reload.require_two_factor_authentication_from_group).to eq(true)
- end
- end
- end
-
- def create_user(email, require_2fa: true)
- users_table.create!(email: email, projects_limit: 10, require_two_factor_authentication_from_group: require_2fa)
- end
-
- def create_group_member(user, group)
- members_table.create!(user_id: user.id, source_id: group.id, access_level: GroupMember::MAINTAINER, source_type: "Namespace", type: "GroupMember", notification_level: 3)
- end
-end
diff --git a/spec/lib/sidebars/concerns/link_with_html_options_spec.rb b/spec/lib/sidebars/concerns/link_with_html_options_spec.rb
new file mode 100644
index 00000000000..1e890bffad1
--- /dev/null
+++ b/spec/lib/sidebars/concerns/link_with_html_options_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Concerns::LinkWithHtmlOptions do
+ let(:options) { {} }
+
+ subject { Class.new { include Sidebars::Concerns::LinkWithHtmlOptions }.new }
+
+ before do
+ allow(subject).to receive(:container_html_options).and_return(options)
+ end
+
+ describe '#link_html_options' do
+ context 'with existing classes' do
+ let(:options) do
+ {
+ class: '_class1_ _class2_',
+ aria: { label: '_label_' }
+ }
+ end
+
+ it 'includes class and default aria-label attribute' do
+ result = {
+ class: '_class1_ _class2_ gl-link',
+ aria: { label: '_label_' }
+ }
+
+ expect(subject.link_html_options).to eq(result)
+ end
+ end
+
+ context 'without existing classes' do
+ it 'includes gl-link class' do
+ expect(subject.link_html_options).to eq(class: 'gl-link')
+ end
+ end
+ end
+end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index a519bdab0c7..441cd7067e5 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -5,7 +5,8 @@ require 'spec_helper'
RSpec.describe Issues::CreateService do
include AfterNextHelpers
- let_it_be_with_reload(:project) { create(:project) }
+ let_it_be(:group) { create(:group) }
+ let_it_be_with_reload(:project) { create(:project, group: group) }
let_it_be(:user) { create(:user) }
let(:spam_params) { double }
@@ -430,25 +431,29 @@ RSpec.describe Issues::CreateService do
end
context 'Quick actions' do
- context 'with assignee and milestone in params and command' do
+ context 'with assignee, milestone, and contact in params and command' do
+ let_it_be(:contact) { create(:contact, group: group) }
+
let(:opts) do
{
assignee_ids: [create(:user).id],
milestone_id: 1,
title: 'Title',
- description: %(/assign @#{assignee.username}\n/milestone %"#{milestone.name}")
+ description: %(/assign @#{assignee.username}\n/milestone %"#{milestone.name}"),
+ add_contacts: [contact.email]
}
end
before_all do
- project.add_maintainer(user)
+ group.add_maintainer(user)
project.add_maintainer(assignee)
end
- it 'assigns and sets milestone to issuable from command' do
+ it 'assigns, sets milestone, and sets contact to issuable from command' do
expect(issue).to be_persisted
expect(issue.assignees).to eq([assignee])
expect(issue.milestone).to eq(milestone)
+ expect(issue.issue_customer_relations_contacts.last.contact).to eq(contact)
end
end
end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index b5246505558..4739b7e0f28 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -29,6 +29,8 @@ RSpec.describe Issues::UpdateService, :mailer do
end
describe 'execute' do
+ let_it_be(:contact) { create(:contact, group: group) }
+
def find_note(starting_with)
issue.notes.find do |note|
note && note.note.start_with?(starting_with)
@@ -57,7 +59,8 @@ RSpec.describe Issues::UpdateService, :mailer do
due_date: Date.tomorrow,
discussion_locked: true,
severity: 'low',
- milestone_id: milestone.id
+ milestone_id: milestone.id,
+ add_contacts: [contact.email]
}
end
@@ -76,6 +79,7 @@ RSpec.describe Issues::UpdateService, :mailer do
expect(issue.discussion_locked).to be_truthy
expect(issue.confidential).to be_falsey
expect(issue.milestone).to eq milestone
+ expect(issue.issue_customer_relations_contacts.last.contact).to eq contact
end
it 'updates issue milestone when passing `milestone` param' do
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 2bdc29a09a0..77d263f4b70 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -2253,35 +2253,29 @@ RSpec.describe QuickActions::InterpretService do
end
it 'add_contacts command does not add the contact' do
- add_command
+ _, updates, _ = add_command
- expect(issue.reload.customer_relations_contacts).to match_array([existing_contact])
+ expect(updates).to be_empty
end
it 'remove_contacts command does not remove the contact' do
- remove_command
+ _, updates, _ = remove_command
- expect(issue.reload.customer_relations_contacts).to match_array([existing_contact])
+ expect(updates).to be_empty
end
end
it 'add_contacts command adds the contact' do
- _, _, message = add_command
+ _, updates, message = add_command
- expect(issue.reload.customer_relations_contacts).to match_array([existing_contact, new_contact])
+ expect(updates).to eq(add_contacts: [new_contact.email])
expect(message).to eq('One or more contacts were successfully added.')
end
- it 'add_contacts command returns the correct error when something goes wrong' do
- _, _, message = service.execute("/add_contacts #{new_contact.email} #{new_contact.email} #{new_contact.email} #{new_contact.email} #{new_contact.email} #{new_contact.email} #{new_contact.email}", issue)
-
- expect(message).to eq('You can only add up to 6 contacts at one time')
- end
-
it 'remove_contacts command removes the contact' do
- _, _, message = remove_command
+ _, updates, message = remove_command
- expect(issue.reload.customer_relations_contacts).to be_empty
+ expect(updates).to eq(remove_contacts: [existing_contact.email])
expect(message).to eq('One or more contacts were successfully removed.')
end
end
diff --git a/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb
index 07012914a4d..6414a4d1eb3 100644
--- a/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb
+++ b/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb
@@ -28,7 +28,7 @@ RSpec.shared_context 'project service activation' do
end
def click_test_integration
- click_link('Test settings')
+ click_button('Test settings')
end
def click_test_then_save_integration(expect_test_to_fail: true)