summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/alert_management/components/alert_details.vue37
-rw-r--r--app/assets/javascripts/alert_management/details.js3
-rw-r--r--app/assets/javascripts/alert_management/router.js13
-rw-r--r--app/assets/javascripts/import_projects/components/imported_project_table_row.vue3
-rw-r--r--app/assets/javascripts/import_projects/components/incompatible_repo_table_row.vue4
-rw-r--r--app/assets/javascripts/import_projects/components/provider_repo_table_row.vue3
-rw-r--r--app/assets/javascripts/lib/graphql.js2
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard_actions_menu.vue45
-rw-r--r--app/assets/javascripts/registry/explorer/pages/details.vue2
-rw-r--r--app/assets/javascripts/registry/explorer/pages/index.vue4
-rw-r--r--app/assets/javascripts/registry/explorer/pages/list.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue71
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/constants.js1
-rw-r--r--app/assets/stylesheets/fontawesome_custom.scss4
-rw-r--r--app/controllers/projects/environments_controller.rb1
-rw-r--r--app/controllers/projects/metrics/dashboards/builder_controller.rb5
-rw-r--r--app/controllers/projects/metrics_dashboard_controller.rb5
-rw-r--r--app/models/project_repository_storage_move.rb13
-rw-r--r--app/services/projects/update_repository_storage_service.rb65
-rw-r--r--app/views/projects/_merge_request_settings.html.haml2
20 files changed, 172 insertions, 113 deletions
diff --git a/app/assets/javascripts/alert_management/components/alert_details.vue b/app/assets/javascripts/alert_management/components/alert_details.vue
index f9795a18774..8c3ec527ef6 100644
--- a/app/assets/javascripts/alert_management/components/alert_details.vue
+++ b/app/assets/javascripts/alert_management/components/alert_details.vue
@@ -35,13 +35,24 @@ export default {
errorMsg: s__(
'AlertManagement|There was an error displaying the alert. Please refresh the page to try again.',
),
- fullAlertDetailsTitle: s__('AlertManagement|Alert details'),
- overviewTitle: s__('AlertManagement|Overview'),
- metricsTitle: s__('AlertManagement|Metrics'),
reportedAt: s__('AlertManagement|Reported %{when}'),
reportedAtWithTool: s__('AlertManagement|Reported %{when} by %{tool}'),
},
severityLabels: ALERTS_SEVERITY_LABELS,
+ tabsConfig: [
+ {
+ id: 'overview',
+ title: s__('AlertManagement|Overview'),
+ },
+ {
+ id: 'fullDetails',
+ title: s__('AlertManagement|Alert details'),
+ },
+ {
+ id: 'metrics',
+ title: s__('AlertManagement|Metrics'),
+ },
+ ],
components: {
GlBadge,
GlAlert,
@@ -119,6 +130,18 @@ export default {
showErrorMsg() {
return this.errored && !this.isErrorDismissed;
},
+ activeTab() {
+ return this.$route.params.tabId || this.$options.tabsConfig[0].id;
+ },
+ currentTabIndex: {
+ get() {
+ return this.$options.tabsConfig.findIndex(tab => tab.id === this.activeTab);
+ },
+ set(tabIdx) {
+ const tabId = this.$options.tabsConfig[tabIdx].id;
+ this.$router.replace({ name: 'tab', params: { tabId } });
+ },
+ },
},
mounted() {
this.trackPageViews();
@@ -257,8 +280,8 @@ export default {
>
<h2 data-testid="title">{{ alert.title }}</h2>
</div>
- <gl-tabs v-if="alert" data-testid="alertDetailsTabs">
- <gl-tab data-testid="overviewTab" :title="$options.i18n.overviewTitle">
+ <gl-tabs v-if="alert" v-model="currentTabIndex" data-testid="alertDetailsTabs">
+ <gl-tab :data-testid="$options.tabsConfig[0].id" :title="$options.tabsConfig[0].title">
<div v-if="alert.severity" class="gl-mt-3 gl-mb-5 gl-display-flex">
<div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3">
{{ s__('AlertManagement|Severity') }}:
@@ -309,7 +332,7 @@ export default {
</div>
</template>
</gl-tab>
- <gl-tab data-testid="fullDetailsTab" :title="$options.i18n.fullAlertDetailsTitle">
+ <gl-tab :data-testid="$options.tabsConfig[1].id" :title="$options.tabsConfig[1].title">
<gl-table
class="alert-management-details-table"
:items="[{ key: 'Value', ...alert }]"
@@ -325,7 +348,7 @@ export default {
</template>
</gl-table>
</gl-tab>
- <gl-tab data-testId="metricsTab" :title="$options.i18n.metricsTitle">
+ <gl-tab :data-testid="$options.tabsConfig[2].id" :title="$options.tabsConfig[2].title">
<alert-metrics :dashboard-url="alert.metricsDashboardUrl" />
</gl-tab>
</gl-tabs>
diff --git a/app/assets/javascripts/alert_management/details.js b/app/assets/javascripts/alert_management/details.js
index 2820bcb9665..5133b1b84ce 100644
--- a/app/assets/javascripts/alert_management/details.js
+++ b/app/assets/javascripts/alert_management/details.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
+import createRouter from './router';
import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
import AlertDetails from './components/alert_details.vue';
import sidebarStatusQuery from './graphql/queries/sidebar_status.query.graphql';
@@ -10,6 +11,7 @@ Vue.use(VueApollo);
export default selector => {
const domEl = document.querySelector(selector);
const { alertId, projectPath, projectIssuesPath, projectId } = domEl.dataset;
+ const router = createRouter();
const resolvers = {
Mutation: {
@@ -54,6 +56,7 @@ export default selector => {
components: {
AlertDetails,
},
+ router,
render(createElement) {
return createElement('alert-details', {});
},
diff --git a/app/assets/javascripts/alert_management/router.js b/app/assets/javascripts/alert_management/router.js
new file mode 100644
index 00000000000..5687fe4e0f5
--- /dev/null
+++ b/app/assets/javascripts/alert_management/router.js
@@ -0,0 +1,13 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import { joinPaths } from '~/lib/utils/url_utility';
+
+Vue.use(VueRouter);
+
+export default function createRouter(base) {
+ return new VueRouter({
+ mode: 'hash',
+ base: joinPaths(gon.relative_url_root || '', base),
+ routes: [{ path: '/:tabId', name: 'tab' }],
+ });
+}
diff --git a/app/assets/javascripts/import_projects/components/imported_project_table_row.vue b/app/assets/javascripts/import_projects/components/imported_project_table_row.vue
index ab2bd87ee9f..a1c54b11276 100644
--- a/app/assets/javascripts/import_projects/components/imported_project_table_row.vue
+++ b/app/assets/javascripts/import_projects/components/imported_project_table_row.vue
@@ -1,4 +1,5 @@
<script>
+import { GlIcon } from '@gitlab/ui';
import ImportStatus from './import_status.vue';
import { STATUSES } from '../constants';
@@ -6,6 +7,7 @@ export default {
name: 'ImportedProjectTableRow',
components: {
ImportStatus,
+ GlIcon,
},
props: {
project: {
@@ -36,6 +38,7 @@ export default {
class="js-provider-link"
>
{{ project.importSource }}
+ <gl-icon v-if="project.providerLink" name="external-link" />
</a>
</td>
<td class="js-full-path">{{ displayFullPath }}</td>
diff --git a/app/assets/javascripts/import_projects/components/incompatible_repo_table_row.vue b/app/assets/javascripts/import_projects/components/incompatible_repo_table_row.vue
index fa2fb439eac..d44c155a84e 100644
--- a/app/assets/javascripts/import_projects/components/incompatible_repo_table_row.vue
+++ b/app/assets/javascripts/import_projects/components/incompatible_repo_table_row.vue
@@ -1,9 +1,10 @@
<script>
-import { GlBadge } from '@gitlab/ui';
+import { GlIcon, GlBadge } from '@gitlab/ui';
export default {
components: {
GlBadge,
+ GlIcon,
},
props: {
repo: {
@@ -19,6 +20,7 @@ export default {
<td>
<a :href="repo.providerLink" rel="noreferrer noopener" target="_blank">
{{ repo.fullName }}
+ <gl-icon v-if="repo.providerLink" name="external-link" />
</a>
</td>
<td></td>
diff --git a/app/assets/javascripts/import_projects/components/provider_repo_table_row.vue b/app/assets/javascripts/import_projects/components/provider_repo_table_row.vue
index 63524d61146..a03e3d50135 100644
--- a/app/assets/javascripts/import_projects/components/provider_repo_table_row.vue
+++ b/app/assets/javascripts/import_projects/components/provider_repo_table_row.vue
@@ -1,5 +1,6 @@
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
+import { GlIcon } from '@gitlab/ui';
import Select2Select from '~/vue_shared/components/select2_select.vue';
import { __ } from '~/locale';
import eventHub from '../event_hub';
@@ -11,6 +12,7 @@ export default {
components: {
Select2Select,
ImportStatus,
+ GlIcon,
},
props: {
repo: {
@@ -84,6 +86,7 @@ export default {
class="js-provider-link"
>
{{ repo.fullName }}
+ <gl-icon v-if="repo.providerLink" name="external-link" />
</a>
</td>
<td class="d-flex flex-wrap flex-lg-nowrap">
diff --git a/app/assets/javascripts/lib/graphql.js b/app/assets/javascripts/lib/graphql.js
index b6c41ffa7ab..4fed121779e 100644
--- a/app/assets/javascripts/lib/graphql.js
+++ b/app/assets/javascripts/lib/graphql.js
@@ -14,7 +14,7 @@ export const fetchPolicies = {
};
export default (resolvers = {}, config = {}) => {
- let uri = `${gon.relative_url_root}/api/graphql`;
+ let uri = `${gon.relative_url_root || ''}/api/graphql`;
if (config.baseUrl) {
// Prepend baseUrl and ensure that `///` are replaced with `/`
diff --git a/app/assets/javascripts/monitoring/components/dashboard_actions_menu.vue b/app/assets/javascripts/monitoring/components/dashboard_actions_menu.vue
index d82b8e0992e..943cee9b504 100644
--- a/app/assets/javascripts/monitoring/components/dashboard_actions_menu.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard_actions_menu.vue
@@ -11,7 +11,6 @@ import {
GlTooltipDirective,
} from '@gitlab/ui';
import CustomMetricsFormFields from '~/custom_metrics/components/custom_metrics_form_fields.vue';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { PANEL_NEW_PAGE } from '../router/constants';
import DuplicateDashboardModal from './duplicate_dashboard_modal.vue';
import CreateDashboardModal from './create_dashboard_modal.vue';
@@ -38,7 +37,6 @@ export default {
GlTooltip: GlTooltipDirective,
TrackEvent: TrackEventDirective,
},
- mixins: [glFeatureFlagsMixin()],
props: {
addingMetricsAvailable: {
type: Boolean,
@@ -86,7 +84,6 @@ export default {
},
isMenuItemShown() {
return {
- addPanel: this.glFeatures.metricsDashboardNewPanelPage,
duplicateDashboard: this.isOutOfTheBoxDashboard,
};
},
@@ -192,31 +189,29 @@ export default {
</gl-modal>
</template>
- <template v-if="isMenuItemShown.addPanel">
+ <gl-new-dropdown-item
+ v-if="isMenuItemEnabled.addPanel"
+ data-testid="add-panel-item-enabled"
+ :to="newPanelPageLocation"
+ >
+ {{ $options.i18n.addPanel }}
+ </gl-new-dropdown-item>
+
+ <!--
+ wrapper for tooltip as button can be `disabled`
+ https://bootstrap-vue.org/docs/components/tooltip#disabled-elements
+ -->
+ <div v-else v-gl-tooltip :title="$options.i18n.addPanelInfo">
<gl-new-dropdown-item
- v-if="isMenuItemEnabled.addPanel"
- data-testid="add-panel-item-enabled"
+ :alt="$options.i18n.addPanelInfo"
:to="newPanelPageLocation"
+ data-testid="add-panel-item-disabled"
+ disabled
+ class="gl-cursor-not-allowed"
>
- {{ $options.i18n.addPanel }}
+ <span class="gl-text-gray-400">{{ $options.i18n.addPanel }}</span>
</gl-new-dropdown-item>
-
- <!--
- wrapper for tooltip as button can be `disabled`
- https://bootstrap-vue.org/docs/components/tooltip#disabled-elements
- -->
- <div v-else v-gl-tooltip :title="$options.i18n.addPanelInfo">
- <gl-new-dropdown-item
- :alt="$options.i18n.addPanelInfo"
- :to="newPanelPageLocation"
- data-testid="add-panel-item-disabled"
- disabled
- class="gl-cursor-not-allowed"
- >
- <span class="gl-text-gray-400">{{ $options.i18n.addPanel }}</span>
- </gl-new-dropdown-item>
- </div>
- </template>
+ </div>
<gl-new-dropdown-item
v-if="isMenuItemEnabled.editDashboard"
@@ -230,7 +225,7 @@ export default {
<!--
wrapper for tooltip as button can be `disabled`
https://bootstrap-vue.org/docs/components/tooltip#disabled-elements
- -->
+ -->
<div v-else v-gl-tooltip :title="$options.i18n.editDashboardInfo">
<gl-new-dropdown-item
:alt="$options.i18n.editDashboardInfo"
diff --git a/app/assets/javascripts/registry/explorer/pages/details.vue b/app/assets/javascripts/registry/explorer/pages/details.vue
index cf811156704..b697bca6259 100644
--- a/app/assets/javascripts/registry/explorer/pages/details.vue
+++ b/app/assets/javascripts/registry/explorer/pages/details.vue
@@ -112,7 +112,7 @@ export default {
</script>
<template>
- <div v-gl-resize-observer="handleResize" class="gl-my-3 gl-w-full slide-enter-to-element">
+ <div v-gl-resize-observer="handleResize" class="gl-my-3">
<delete-alert
v-model="deleteAlertType"
:garbage-collection-help-page-path="config.garbageCollectionHelpPagePath"
diff --git a/app/assets/javascripts/registry/explorer/pages/index.vue b/app/assets/javascripts/registry/explorer/pages/index.vue
index 709a163d56d..4ac0bca84c1 100644
--- a/app/assets/javascripts/registry/explorer/pages/index.vue
+++ b/app/assets/javascripts/registry/explorer/pages/index.vue
@@ -4,8 +4,6 @@ export default {};
<template>
<div>
- <transition name="slide">
- <router-view ref="router-view" />
- </transition>
+ <router-view ref="router-view" />
</div>
</template>
diff --git a/app/assets/javascripts/registry/explorer/pages/list.vue b/app/assets/javascripts/registry/explorer/pages/list.vue
index 1d353651c38..81e47073fe9 100644
--- a/app/assets/javascripts/registry/explorer/pages/list.vue
+++ b/app/assets/javascripts/registry/explorer/pages/list.vue
@@ -130,7 +130,7 @@ export default {
</script>
<template>
- <div class="w-100 slide-enter-from-element">
+ <div>
<gl-alert
v-if="showDeleteAlert"
:variant="deleteAlertType"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
index cc43135f50a..3d7fde2b4c8 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
@@ -15,7 +15,16 @@ import SquashBeforeMerge from './squash_before_merge.vue';
import CommitsHeader from './commits_header.vue';
import CommitEdit from './commit_edit.vue';
import CommitMessageDropdown from './commit_message_dropdown.vue';
-import { AUTO_MERGE_STRATEGIES } from '../../constants';
+import { AUTO_MERGE_STRATEGIES, DANGER, INFO, WARNING } from '../../constants';
+
+const PIPELINE_RUNNING_STATE = 'running';
+const PIPELINE_FAILED_STATE = 'failed';
+const PIPELINE_PENDING_STATE = 'pending';
+const PIPELINE_SUCCESS_STATE = 'success';
+
+const MERGE_FAILED_STATUS = 'failed';
+const MERGE_SUCCESS_STATUS = 'success';
+const MERGE_HOOK_VALIDATION_ERROR_STATUS = 'hook_validation_error';
export default {
name: 'ReadyToMerge',
@@ -29,6 +38,8 @@ export default {
GlSprintf,
GlLink,
GlDeprecatedButton,
+ MergeTrainHelperText: () =>
+ import('ee_component/vue_merge_request_widget/components/merge_train_helper_text.vue'),
MergeImmediatelyConfirmationDialog: () =>
import(
'ee_component/vue_merge_request_widget/components/merge_immediately_confirmation_dialog.vue'
@@ -60,35 +71,45 @@ export default {
const { pipeline, isPipelineFailed, hasCI, ciStatus } = this.mr;
if ((hasCI && !ciStatus) || this.hasPipelineMustSucceedConflict) {
- return 'failed';
- } else if (this.isAutoMergeAvailable) {
- return 'pending';
- } else if (!pipeline) {
- return 'success';
- } else if (isPipelineFailed) {
- return 'failed';
+ return PIPELINE_FAILED_STATE;
+ }
+
+ if (this.isAutoMergeAvailable) {
+ return PIPELINE_PENDING_STATE;
+ }
+
+ if (pipeline && isPipelineFailed) {
+ return PIPELINE_FAILED_STATE;
}
- return 'success';
+ return PIPELINE_SUCCESS_STATE;
},
mergeButtonVariant() {
- if (this.status === 'failed') {
- return 'danger';
- } else if (this.status === 'pending') {
- return 'info';
+ if (this.status === PIPELINE_FAILED_STATE) {
+ return DANGER;
}
- return 'success';
+
+ if (this.status === PIPELINE_PENDING_STATE) {
+ return INFO;
+ }
+
+ return PIPELINE_SUCCESS_STATE;
},
iconClass() {
+ if (this.shouldRenderMergeTrainHelperText && !this.mr.preventMerge) {
+ return PIPELINE_RUNNING_STATE;
+ }
+
if (
- this.status === 'failed' ||
+ this.status === PIPELINE_FAILED_STATE ||
!this.commitMessage.length ||
!this.mr.isMergeAllowed ||
this.mr.preventMerge
) {
- return 'warning';
+ return WARNING;
}
- return 'success';
+
+ return PIPELINE_SUCCESS_STATE;
},
mergeButtonText() {
if (this.isMergingImmediately) {
@@ -167,11 +188,13 @@ export default {
.merge(options)
.then(res => res.data)
.then(data => {
- const hasError = data.status === 'failed' || data.status === 'hook_validation_error';
+ const hasError =
+ data.status === MERGE_FAILED_STATUS ||
+ data.status === MERGE_HOOK_VALIDATION_ERROR_STATUS;
if (AUTO_MERGE_STRATEGIES.includes(data.status)) {
eventHub.$emit('MRWidgetUpdateRequested');
- } else if (data.status === 'success') {
+ } else if (data.status === MERGE_SUCCESS_STATUS) {
this.initiateMergePolling();
} else if (hasError) {
eventHub.$emit('FailedToMerge', data.merge_error);
@@ -269,7 +292,7 @@ export default {
<template>
<div>
- <div class="mr-widget-body media">
+ <div class="mr-widget-body media" :class="{ 'gl-pb-3': shouldRenderMergeTrainHelperText }">
<status-icon :status="iconClass" />
<div class="media-body">
<div class="mr-widget-body-controls media space-children">
@@ -358,6 +381,7 @@ export default {
<div
v-if="hasPipelineMustSucceedConflict"
class="gl-display-flex gl-align-items-center"
+ data-testid="pipeline-succeed-conflict"
>
<gl-sprintf :message="pipelineMustSucceedConflictText" />
<gl-link
@@ -379,6 +403,13 @@ export default {
</div>
</div>
</div>
+ <merge-train-helper-text
+ v-if="shouldRenderMergeTrainHelperText"
+ :pipeline-id="mr.pipeline.id"
+ :pipeline-link="mr.pipeline.path"
+ :merge-train-length="mr.mergeTrainsCount"
+ :merge-train-when-pipeline-succeeds-docs-path="mr.mergeTrainWhenPipelineSucceedsDocsPath"
+ />
<template v-if="shouldShowMergeControls">
<div v-if="mr.ffOnlyEnabled" class="mr-fast-forward-message">
{{ __('Fast-forward merge without a merge commit') }}
diff --git a/app/assets/javascripts/vue_merge_request_widget/constants.js b/app/assets/javascripts/vue_merge_request_widget/constants.js
index 1c43db23832..77dfbf9d385 100644
--- a/app/assets/javascripts/vue_merge_request_widget/constants.js
+++ b/app/assets/javascripts/vue_merge_request_widget/constants.js
@@ -3,6 +3,7 @@ import { s__ } from '~/locale';
export const SUCCESS = 'success';
export const WARNING = 'warning';
export const DANGER = 'danger';
+export const INFO = 'info';
export const WARNING_MESSAGE_CLASS = 'warning_message';
export const DANGER_MESSAGE_CLASS = 'danger_message';
diff --git a/app/assets/stylesheets/fontawesome_custom.scss b/app/assets/stylesheets/fontawesome_custom.scss
index 9b490491ee4..a96a002b879 100644
--- a/app/assets/stylesheets/fontawesome_custom.scss
+++ b/app/assets/stylesheets/fontawesome_custom.scss
@@ -243,10 +243,6 @@
content: '\f187';
}
-.fa-sign-out::before {
- content: '\f08b';
-}
-
.fa-thumb-tack::before {
content: '\f08d';
}
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 2e7de058e3a..71195fdb892 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -14,7 +14,6 @@ class Projects::EnvironmentsController < Projects::ApplicationController
push_frontend_feature_flag(:prometheus_computed_alerts)
push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate)
- push_frontend_feature_flag(:metrics_dashboard_new_panel_page)
end
before_action :authorize_read_environment!, except: [:metrics, :additional_metrics, :metrics_dashboard, :metrics_redirect]
before_action :authorize_create_environment!, only: [:new, :create]
diff --git a/app/controllers/projects/metrics/dashboards/builder_controller.rb b/app/controllers/projects/metrics/dashboards/builder_controller.rb
index a7832aa363e..2ab574d7d10 100644
--- a/app/controllers/projects/metrics/dashboards/builder_controller.rb
+++ b/app/controllers/projects/metrics/dashboards/builder_controller.rb
@@ -4,7 +4,6 @@ module Projects
module Metrics
module Dashboards
class BuilderController < Projects::ApplicationController
- before_action :ensure_feature_flags
before_action :authorize_metrics_dashboard!
def panel_preview
@@ -21,10 +20,6 @@ module Projects
private
- def ensure_feature_flags
- render_404 unless Feature.enabled?(:metrics_dashboard_new_panel_page, project)
- end
-
def rendered_panel
@panel_preview ||= ::Metrics::Dashboard::PanelPreviewService.new(project, panel_yaml, environment).execute
end
diff --git a/app/controllers/projects/metrics_dashboard_controller.rb b/app/controllers/projects/metrics_dashboard_controller.rb
index 7c964dc44f0..51307c3665c 100644
--- a/app/controllers/projects/metrics_dashboard_controller.rb
+++ b/app/controllers/projects/metrics_dashboard_controller.rb
@@ -10,14 +10,9 @@ module Projects
before_action do
push_frontend_feature_flag(:prometheus_computed_alerts)
push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate)
- push_frontend_feature_flag(:metrics_dashboard_new_panel_page)
end
def show
- if params[:page].present? && !Feature.enabled?(:metrics_dashboard_new_panel_page, project)
- return render_404
- end
-
if environment
render 'projects/environments/metrics'
else
diff --git a/app/models/project_repository_storage_move.rb b/app/models/project_repository_storage_move.rb
index b18d9765a57..2b74d9ccd88 100644
--- a/app/models/project_repository_storage_move.rb
+++ b/app/models/project_repository_storage_move.rb
@@ -29,12 +29,17 @@ class ProjectRepositoryStorageMove < ApplicationRecord
transition scheduled: :started
end
- event :finish do
- transition started: :finished
+ event :finish_replication do
+ transition started: :replicated
+ end
+
+ event :finish_cleanup do
+ transition replicated: :finished
end
event :do_fail do
transition [:initial, :scheduled, :started] => :failed
+ transition replicated: :cleanup_failed
end
after_transition initial: :scheduled do |storage_move|
@@ -49,7 +54,7 @@ class ProjectRepositoryStorageMove < ApplicationRecord
end
end
- after_transition started: :finished do |storage_move|
+ after_transition started: :replicated do |storage_move|
storage_move.project.update_columns(
repository_read_only: false,
repository_storage: storage_move.destination_storage_name
@@ -65,6 +70,8 @@ class ProjectRepositoryStorageMove < ApplicationRecord
state :started, value: 3
state :finished, value: 4
state :failed, value: 5
+ state :replicated, value: 6
+ state :cleanup_failed, value: 7
end
scope :order_created_at_desc, -> { order(created_at: :desc) }
diff --git a/app/services/projects/update_repository_storage_service.rb b/app/services/projects/update_repository_storage_service.rb
index 7b346c09635..a479d53a43a 100644
--- a/app/services/projects/update_repository_storage_service.rb
+++ b/app/services/projects/update_repository_storage_service.rb
@@ -6,8 +6,7 @@ module Projects
SameFilesystemError = Class.new(Error)
attr_reader :repository_storage_move
- delegate :project, :destination_storage_name, to: :repository_storage_move
- delegate :repository, to: :project
+ delegate :project, :source_storage_name, :destination_storage_name, to: :repository_storage_move
def initialize(repository_storage_move)
@repository_storage_move = repository_storage_move
@@ -20,21 +19,22 @@ module Projects
repository_storage_move.start!
end
- raise SameFilesystemError if same_filesystem?(repository.storage, destination_storage_name)
+ raise SameFilesystemError if same_filesystem?(source_storage_name, destination_storage_name)
mirror_repositories
- project.transaction do
- mark_old_paths_for_archive
-
- repository_storage_move.finish!
+ repository_storage_move.transaction do
+ repository_storage_move.finish_replication!
project.leave_pool_repository
project.track_project_repository
end
+ remove_old_paths
enqueue_housekeeping
+ repository_storage_move.finish_cleanup!
+
ServiceResponse.success
rescue StandardError => e
@@ -91,36 +91,31 @@ module Projects
end
end
- def mark_old_paths_for_archive
- old_repository_storage = project.repository_storage
- new_project_path = moved_path(project.disk_path)
-
- # Notice that the block passed to `run_after_commit` will run with `repository_storage_move`
- # as its context
- repository_storage_move.run_after_commit do
- GitlabShellWorker.perform_async(:mv_repository,
- old_repository_storage,
- project.disk_path,
- new_project_path)
-
- if project.wiki.repository_exists?
- GitlabShellWorker.perform_async(:mv_repository,
- old_repository_storage,
- project.wiki.disk_path,
- "#{new_project_path}.wiki")
- end
-
- if project.design_repository.exists?
- GitlabShellWorker.perform_async(:mv_repository,
- old_repository_storage,
- project.design_repository.disk_path,
- "#{new_project_path}.design")
- end
+ def remove_old_paths
+ Gitlab::Git::Repository.new(
+ source_storage_name,
+ "#{project.disk_path}.git",
+ nil,
+ nil
+ ).remove
+
+ if project.wiki.repository_exists?
+ Gitlab::Git::Repository.new(
+ source_storage_name,
+ "#{project.wiki.disk_path}.git",
+ nil,
+ nil
+ ).remove
end
- end
- def moved_path(path)
- "#{path}+#{project.id}+moved+#{Time.current.to_i}"
+ if project.design_repository.exists?
+ Gitlab::Git::Repository.new(
+ source_storage_name,
+ "#{project.design_repository.disk_path}.git",
+ nil,
+ nil
+ ).remove
+ end
end
# The underlying FetchInternalRemote call uses a `git fetch` to move data
diff --git a/app/views/projects/_merge_request_settings.html.haml b/app/views/projects/_merge_request_settings.html.haml
index 5ffdeef3558..e69972e8163 100644
--- a/app/views/projects/_merge_request_settings.html.haml
+++ b/app/views/projects/_merge_request_settings.html.haml
@@ -4,7 +4,7 @@
= render 'projects/merge_request_merge_options_settings', project: @project, form: form
-- if Feature.enabled?(:squash_options, @project)
+- if Feature.enabled?(:squash_options, @project, default_enabled: true)
= render 'projects/merge_request_squash_options_settings', form: form
= render 'projects/merge_request_merge_checks_settings', project: @project, form: form