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
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-30 18:09:46 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-30 18:09:46 +0300
commitdd240e5cc4e0abc4eef8b97962c247dab43e3777 (patch)
treebc0752959bc0713afb555e358bb43d65cf04f48e /app
parent6aa5c04c74d2d70ee7d19ef3a155b2def9dd46de (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/alert_management/components/alert_details.vue3
-rw-r--r--app/assets/javascripts/alert_management/components/alert_sidebar.vue1
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js4
-rw-r--r--app/assets/javascripts/clusters/components/fluentd_output_settings.vue17
-rw-r--r--app/assets/javascripts/design_management/pages/index.vue8
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue2
-rw-r--r--app/assets/javascripts/pages/admin/keys/index.js5
-rw-r--r--app/assets/javascripts/pages/admin/users/keys/index.js5
-rw-r--r--app/assets/javascripts/pages/profiles/keys/index.js3
-rw-r--r--app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue7
-rw-r--r--app/assets/javascripts/snippet/snippet_show.js48
-rw-r--r--app/assets/javascripts/snippets/index.js14
-rw-r--r--app/assets/stylesheets/fontawesome_custom.scss4
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss18
-rw-r--r--app/assets/stylesheets/framework/secondary_navigation_elements.scss4
-rw-r--r--app/assets/stylesheets/framework/typography.scss4
-rw-r--r--app/assets/stylesheets/framework/wells.scss5
-rw-r--r--app/assets/stylesheets/pages/diff.scss4
-rw-r--r--app/controllers/projects/runners_controller.rb4
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/create.rb2
-rw-r--r--app/helpers/profiles_helper.rb15
-rw-r--r--app/models/group.rb94
-rw-r--r--app/models/merge_request.rb4
-rw-r--r--app/models/namespace.rb50
-rw-r--r--app/models/project.rb10
-rw-r--r--app/services/groups/create_service.rb9
-rw-r--r--app/services/groups/transfer_service.rb14
-rw-r--r--app/services/groups/update_service.rb13
-rw-r--r--app/services/groups/update_shared_runners_service.rb32
-rw-r--r--app/services/merge_requests/base_service.rb4
-rw-r--r--app/services/projects/create_service.rb4
-rw-r--r--app/services/projects/transfer_service.rb4
-rw-r--r--app/views/profiles/keys/_key.html.haml11
-rw-r--r--app/views/profiles/keys/_key_details.html.haml2
-rw-r--r--app/views/projects/diffs/_stats.html.haml4
36 files changed, 266 insertions, 170 deletions
diff --git a/app/assets/javascripts/alert_management/components/alert_details.vue b/app/assets/javascripts/alert_management/components/alert_details.vue
index beb636ee8fa..072ed2fa663 100644
--- a/app/assets/javascripts/alert_management/components/alert_details.vue
+++ b/app/assets/javascripts/alert_management/components/alert_details.vue
@@ -81,15 +81,12 @@ export default {
default: '',
},
alertId: {
- type: String,
default: '',
},
projectId: {
- type: String,
default: '',
},
projectIssuesPath: {
- type: String,
default: '',
},
},
diff --git a/app/assets/javascripts/alert_management/components/alert_sidebar.vue b/app/assets/javascripts/alert_management/components/alert_sidebar.vue
index 64e4089c85a..41d77716592 100644
--- a/app/assets/javascripts/alert_management/components/alert_sidebar.vue
+++ b/app/assets/javascripts/alert_management/components/alert_sidebar.vue
@@ -18,7 +18,6 @@ export default {
default: '',
},
projectId: {
- type: String,
default: '',
},
},
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index 8a8b61a57cd..3cb2d6719c8 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -117,9 +117,9 @@ export default class Shortcuts {
e.preventDefault();
const performanceBarCookieName = 'perf_bar_enabled';
if (parseBoolean(Cookies.get(performanceBarCookieName))) {
- Cookies.set(performanceBarCookieName, 'false', { path: '/' });
+ Cookies.set(performanceBarCookieName, 'false', { expires: 365, path: '/' });
} else {
- Cookies.set(performanceBarCookieName, 'true', { path: '/' });
+ Cookies.set(performanceBarCookieName, 'true', { expires: 365, path: '/' });
}
refreshCurrentPage();
}
diff --git a/app/assets/javascripts/clusters/components/fluentd_output_settings.vue b/app/assets/javascripts/clusters/components/fluentd_output_settings.vue
index e6001b11296..7b55efaaccd 100644
--- a/app/assets/javascripts/clusters/components/fluentd_output_settings.vue
+++ b/app/assets/javascripts/clusters/components/fluentd_output_settings.vue
@@ -1,7 +1,7 @@
<script>
import {
GlAlert,
- GlDeprecatedButton,
+ GlButton,
GlDeprecatedDropdown,
GlDeprecatedDropdownItem,
GlFormCheckbox,
@@ -16,7 +16,7 @@ const { UPDATING, UNINSTALLING, INSTALLING, INSTALLED, UPDATED } = APPLICATION_S
export default {
components: {
GlAlert,
- GlDeprecatedButton,
+ GlButton,
GlDeprecatedDropdown,
GlDeprecatedDropdownItem,
GlFormCheckbox,
@@ -221,20 +221,21 @@ export default {
<strong>{{ s__('ClusterIntegration|Send Container Network Policies Logs') }}</strong>
</gl-form-checkbox>
</div>
- <div v-if="showButtons" class="mt-3">
- <gl-deprecated-button
+ <div v-if="showButtons" class="gl-mt-5 gl-display-flex">
+ <gl-button
ref="saveBtn"
- class="mr-1"
+ class="gl-mr-3"
variant="success"
+ category="primary"
:loading="isSaving"
:disabled="saveButtonDisabled"
@click="updateApplication"
>
{{ saveButtonLabel }}
- </gl-deprecated-button>
- <gl-deprecated-button ref="cancelBtn" :disabled="saveButtonDisabled" @click="resetStatus">
+ </gl-button>
+ <gl-button ref="cancelBtn" :disabled="saveButtonDisabled" @click="resetStatus">
{{ __('Cancel') }}
- </gl-deprecated-button>
+ </gl-button>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/design_management/pages/index.vue b/app/assets/javascripts/design_management/pages/index.vue
index 7bf9454240b..fb6a91abcdc 100644
--- a/app/assets/javascripts/design_management/pages/index.vue
+++ b/app/assets/javascripts/design_management/pages/index.vue
@@ -113,9 +113,7 @@ export default {
return !this.isSaving && !this.hasDesigns;
},
isDesignCollectionCopying() {
- return (
- this.designCollection && ['PENDING', 'COPYING'].includes(this.designCollection.copyState)
- );
+ return this.designCollection && this.designCollection.copyState === 'IN_PROGRESS';
},
designDropzoneWrapperClass() {
return this.isDesignListEmpty
@@ -370,11 +368,11 @@ export default {
</gl-alert>
<header
v-else-if="isDesignCollectionCopying"
- class="card gl-p-3"
+ class="card"
data-testid="design-collection-is-copying"
>
<div class="card-header design-card-header border-bottom-0">
- <div class="card-title gl-my-0 gl-h-7">
+ <div class="card-title gl-display-flex gl-align-items-center gl-my-0 gl-h-7">
{{
s__(
'DesignManagement|Your designs are being copied and are on their way… Please refresh to update.',
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index 6205d113e5e..e403fc1f432 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -224,7 +224,7 @@ export default {
<a
ref="titleWrapper"
:v-once="!viewDiffsFileByFile"
- class="gl-mr-2"
+ class="gl-mr-2 gl-text-decoration-none!"
:href="titleLink"
@click="handleFileNameClick"
>
diff --git a/app/assets/javascripts/pages/admin/keys/index.js b/app/assets/javascripts/pages/admin/keys/index.js
new file mode 100644
index 00000000000..45b83ffcd67
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/keys/index.js
@@ -0,0 +1,5 @@
+import initConfirmModal from '~/confirm_modal';
+
+document.addEventListener('DOMContentLoaded', () => {
+ initConfirmModal();
+});
diff --git a/app/assets/javascripts/pages/admin/users/keys/index.js b/app/assets/javascripts/pages/admin/users/keys/index.js
new file mode 100644
index 00000000000..45b83ffcd67
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/users/keys/index.js
@@ -0,0 +1,5 @@
+import initConfirmModal from '~/confirm_modal';
+
+document.addEventListener('DOMContentLoaded', () => {
+ initConfirmModal();
+});
diff --git a/app/assets/javascripts/pages/profiles/keys/index.js b/app/assets/javascripts/pages/profiles/keys/index.js
index d3dcd21f456..4214d5bffb2 100644
--- a/app/assets/javascripts/pages/profiles/keys/index.js
+++ b/app/assets/javascripts/pages/profiles/keys/index.js
@@ -1,6 +1,9 @@
+import initConfirmModal from '~/confirm_modal';
import AddSshKeyValidation from '~/profile/add_ssh_key_validation';
document.addEventListener('DOMContentLoaded', () => {
+ initConfirmModal();
+
const input = document.querySelector('.js-add-ssh-key-validation-input');
if (!input) return;
diff --git a/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue b/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue
index c74258d102a..1cec08b93bd 100644
--- a/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue
+++ b/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue
@@ -170,13 +170,13 @@ export default {
.map(({ variable_type, key, value }) => ({
variable_type,
key,
- value,
+ secret_value: value,
}));
return axios
.post(this.pipelinesPath, {
ref: this.refValue,
- variables: filteredVariables,
+ variables_attributes: filteredVariables,
})
.then(({ data }) => {
redirectTo(`${this.pipelinesPath}/${data.id}`);
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue b/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
index 7d13ee582c6..8de18aef639 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
@@ -1,12 +1,11 @@
<script>
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import '~/lib/utils/datetime_utility';
-import tooltip from '~/vue_shared/directives/tooltip';
import timeagoMixin from '~/vue_shared/mixins/timeago';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: { GlIcon },
mixins: [timeagoMixin],
@@ -63,7 +62,7 @@ export default {
<gl-icon name="calendar" class="gl-vertical-align-baseline!" aria-hidden="true" />
<time
- v-tooltip
+ v-gl-tooltip
:title="tooltipTitle(finishedTime)"
data-placement="top"
data-container="body"
diff --git a/app/assets/javascripts/snippet/snippet_show.js b/app/assets/javascripts/snippet/snippet_show.js
index bbddfc579c5..1899ff91f87 100644
--- a/app/assets/javascripts/snippet/snippet_show.js
+++ b/app/assets/javascripts/snippet/snippet_show.js
@@ -1,21 +1,33 @@
-import LineHighlighter from '~/line_highlighter';
-import BlobViewer from '~/blob/viewer';
-import ZenMode from '~/zen_mode';
import initNotes from '~/init_notes';
-import snippetEmbed from '~/snippet/snippet_embed';
-import { SnippetShowInit } from '~/snippets';
import loadAwardsHandler from '~/awards_handler';
-document.addEventListener('DOMContentLoaded', () => {
- if (!gon.features.snippetsVue) {
- new LineHighlighter(); // eslint-disable-line no-new
- new BlobViewer(); // eslint-disable-line no-new
- initNotes();
- new ZenMode(); // eslint-disable-line no-new
- snippetEmbed();
- } else {
- SnippetShowInit();
- initNotes();
- }
- loadAwardsHandler();
-});
+if (!gon.features.snippetsVue) {
+ const LineHighlighterModule = import('~/line_highlighter');
+ const BlobViewerModule = import('~/blob/viewer');
+ const ZenModeModule = import('~/zen_mode');
+ const SnippetEmbedModule = import('~/snippet/snippet_embed');
+
+ Promise.all([LineHighlighterModule, BlobViewerModule, ZenModeModule, SnippetEmbedModule])
+ .then(
+ ([
+ { default: LineHighlighter },
+ { default: BlobViewer },
+ { default: ZenMode },
+ { default: SnippetEmbed },
+ ]) => {
+ new LineHighlighter(); // eslint-disable-line no-new
+ new BlobViewer(); // eslint-disable-line no-new
+ new ZenMode(); // eslint-disable-line no-new
+ SnippetEmbed();
+ },
+ )
+ .catch(() => {});
+} else {
+ import('~/snippets')
+ .then(({ SnippetShowInit }) => {
+ SnippetShowInit();
+ })
+ .catch(() => {});
+}
+initNotes();
+loadAwardsHandler();
diff --git a/app/assets/javascripts/snippets/index.js b/app/assets/javascripts/snippets/index.js
index 16635a081a2..d3caec42ce7 100644
--- a/app/assets/javascripts/snippets/index.js
+++ b/app/assets/javascripts/snippets/index.js
@@ -3,8 +3,6 @@ import VueApollo from 'vue-apollo';
import Translate from '~/vue_shared/translate';
import createDefaultClient from '~/lib/graphql';
-import SnippetsShow from './components/show.vue';
-import SnippetsEdit from './components/edit.vue';
import { SNIPPET_LEVELS_MAP, SNIPPET_VISIBILITY_PRIVATE } from '~/snippets/constants';
Vue.use(VueApollo);
@@ -48,9 +46,17 @@ function appFactory(el, Component) {
}
export const SnippetShowInit = () => {
- appFactory(document.getElementById('js-snippet-view'), SnippetsShow);
+ import('./components/show.vue')
+ .then(({ default: SnippetsShow }) => {
+ appFactory(document.getElementById('js-snippet-view'), SnippetsShow);
+ })
+ .catch(() => {});
};
export const SnippetEditInit = () => {
- appFactory(document.getElementById('js-snippet-edit'), SnippetsEdit);
+ import('./components/edit.vue')
+ .then(({ default: SnippetsEdit }) => {
+ appFactory(document.getElementById('js-snippet-edit'), SnippetsEdit);
+ })
+ .catch(() => {});
};
diff --git a/app/assets/stylesheets/fontawesome_custom.scss b/app/assets/stylesheets/fontawesome_custom.scss
index b884a6ea9fb..7ea03c4127b 100644
--- a/app/assets/stylesheets/fontawesome_custom.scss
+++ b/app/assets/stylesheets/fontawesome_custom.scss
@@ -253,10 +253,6 @@
content: '\f081';
}
-.fa-unlink::before {
- content: '\f127';
-}
-
.fa-file-pdf-o::before {
content: '\f1c1';
}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 7baaa26fbec..e8d37fcf40b 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -189,15 +189,6 @@
background-color: $gray-darker;
color: $gl-text-color;
outline: 0;
-
- // make sure the text color is not overridden
- &.text-danger {
- color: $brand-danger;
- }
-
- .avatar {
- border-color: $white;
- }
}
@mixin dropdown-link {
@@ -216,11 +207,6 @@
text-align: left;
width: 100%;
- // make sure the text color is not overridden
- &.text-danger {
- color: $brand-danger;
- }
-
&.disable-hover {
text-decoration: none;
}
@@ -232,10 +218,6 @@
@include dropdown-item-hover;
text-decoration: none;
-
- .badge.badge-pill {
- background-color: darken($blue-50, 5%);
- }
}
&.dropdown-menu-user-link {
diff --git a/app/assets/stylesheets/framework/secondary_navigation_elements.scss b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
index 292d57f132c..bbfe65e6eda 100644
--- a/app/assets/stylesheets/framework/secondary_navigation_elements.scss
+++ b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
@@ -28,10 +28,6 @@
text-decoration: none;
color: $black;
border-bottom: 2px solid $gray-darkest;
-
- .badge.badge-pill {
- color: $black;
- }
}
}
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 8b5fa6c1b6c..c15d46d43b2 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -439,10 +439,6 @@
content: '\f0c6';
}
- &:hover::before {
- text-decoration: none;
- }
-
&.no-attachment-icon {
&::before {
display: none;
diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss
index 55996a074c6..774ba5d9964 100644
--- a/app/assets/stylesheets/framework/wells.scss
+++ b/app/assets/stylesheets/framework/wells.scss
@@ -29,11 +29,6 @@
.ref-name {
font-size: 12px;
-
- &:hover {
- text-decoration: underline;
- color: $gl-text-color;
- }
}
}
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index fb13e776e13..ef2ee8d57c2 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -70,10 +70,6 @@
}
}
- a:hover {
- text-decoration: none;
- }
-
&:hover {
background-color: $gray-normal;
}
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index ca62f54813b..fb00156d320 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -50,6 +50,10 @@ class Projects::RunnersController < Projects::ApplicationController
end
def toggle_shared_runners
+ if Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true) && !project.shared_runners_enabled && project.group && project.group.shared_runners_setting == 'disabled_and_unoverridable'
+ return redirect_to project_runners_path(@project), alert: _("Cannot enable shared runners because parent group does not allow it")
+ end
+
project.toggle!(:shared_runners_enabled)
redirect_to project_settings_ci_cd_path(@project, anchor: 'js-runners-settings')
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/create.rb b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
index f99688aeac6..6f316e76e2a 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
@@ -80,7 +80,7 @@ module Mutations
raise Gitlab::Graphql::Errors::ArgumentError, ANNOTATION_SOURCE_ARGUMENT_ERROR
end
- super(args)
+ super(**args)
end
def find_object(id:)
diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb
index 5a42e581867..44d869fbd8f 100644
--- a/app/helpers/profiles_helper.rb
+++ b/app/helpers/profiles_helper.rb
@@ -29,4 +29,19 @@ module ProfilesHelper
def user_profile?
params[:controller] == 'users'
end
+
+ def ssh_key_delete_modal_data(key, is_admin)
+ {
+ path: path_to_key(key, is_admin),
+ method: 'delete',
+ qa_selector: 'delete_ssh_key_button',
+ modal_attributes: {
+ 'data-qa-selector': 'ssh_key_delete_modal',
+ title: _('Are you sure you want to delete this SSH key?'),
+ message: _('This action cannot be undone, and will permanently delete the %{key} SSH key') % { key: key.title },
+ okVariant: 'danger',
+ okTitle: _('Delete')
+ }
+ }
+ end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index abb3f6c96c4..4ecd096b2b4 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -19,8 +19,6 @@ class Group < Namespace
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10
- UpdateSharedRunnersError = Class.new(StandardError)
-
has_many :all_group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent
has_many :group_members, -> { where(requested_at: nil).where.not(members: { access_level: Gitlab::Access::MINIMAL_ACCESS }) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
alias_method :members, :group_members
@@ -538,53 +536,14 @@ class Group < Namespace
preloader.preload(self, shared_with_group_links: [shared_with_group: :route])
end
- def shared_runners_allowed?
- shared_runners_enabled? || allow_descendants_override_disabled_shared_runners?
- end
-
- def parent_allows_shared_runners?
- return true unless has_parent?
-
- parent.shared_runners_allowed?
- end
-
- def parent_enabled_shared_runners?
- return true unless has_parent?
-
- parent.shared_runners_enabled?
- end
-
- def enable_shared_runners!
- raise UpdateSharedRunnersError, 'Shared Runners disabled for the parent group' unless parent_enabled_shared_runners?
-
- update_column(:shared_runners_enabled, true)
- end
-
- def disable_shared_runners!
- group_ids = self_and_descendants
- return if group_ids.empty?
-
- Group.by_id(group_ids).update_all(shared_runners_enabled: false)
-
- all_projects.update_all(shared_runners_enabled: false)
- end
-
- def allow_descendants_override_disabled_shared_runners!
- raise UpdateSharedRunnersError, 'Shared Runners enabled' if shared_runners_enabled?
- raise UpdateSharedRunnersError, 'Group level shared Runners not allowed' unless parent_allows_shared_runners?
-
- update_column(:allow_descendants_override_disabled_shared_runners, true)
- end
-
- def disallow_descendants_override_disabled_shared_runners!
- raise UpdateSharedRunnersError, 'Shared Runners enabled' if shared_runners_enabled?
+ def update_shared_runners_setting!(state)
+ raise ArgumentError unless SHARED_RUNNERS_SETTINGS.include?(state)
- group_ids = self_and_descendants
- return if group_ids.empty?
-
- Group.by_id(group_ids).update_all(allow_descendants_override_disabled_shared_runners: false)
-
- all_projects.update_all(shared_runners_enabled: false)
+ case state
+ when 'disabled_and_unoverridable' then disable_shared_runners! # also disallows override
+ when 'disabled_with_override' then disable_shared_runners_and_allow_override!
+ when 'enabled' then enable_shared_runners! # set both to true
+ end
end
def default_owner
@@ -668,6 +627,45 @@ class Group < Namespace
.new(Group.where(id: group_ids))
.base_and_descendants
end
+
+ def disable_shared_runners!
+ update!(
+ shared_runners_enabled: false,
+ allow_descendants_override_disabled_shared_runners: false)
+
+ group_ids = descendants
+ unless group_ids.empty?
+ Group.by_id(group_ids).update_all(
+ shared_runners_enabled: false,
+ allow_descendants_override_disabled_shared_runners: false)
+ end
+
+ all_projects.update_all(shared_runners_enabled: false)
+ end
+
+ def disable_shared_runners_and_allow_override!
+ # enabled -> disabled_with_override
+ if shared_runners_enabled?
+ update!(
+ shared_runners_enabled: false,
+ allow_descendants_override_disabled_shared_runners: true)
+
+ group_ids = descendants
+ unless group_ids.empty?
+ Group.by_id(group_ids).update_all(shared_runners_enabled: false)
+ end
+
+ all_projects.update_all(shared_runners_enabled: false)
+
+ # disabled_and_unoverridable -> disabled_with_override
+ else
+ update!(allow_descendants_override_disabled_shared_runners: true)
+ end
+ end
+
+ def enable_shared_runners!
+ update!(shared_runners_enabled: true)
+ end
end
Group.prepend_if_ee('EE::Group')
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 1965c5dacc7..6a732410cb1 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1690,6 +1690,10 @@ class MergeRequest < ApplicationRecord
Feature.enabled?(:merge_request_reviewers, project)
end
+ def allows_multiple_reviewers?
+ false
+ end
+
private
def with_rebase_lock
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 527fa9d52d0..f0550713d01 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -18,6 +18,8 @@ class Namespace < ApplicationRecord
# Android repo (15) + some extra backup.
NUMBER_OF_ANCESTORS_ALLOWED = 20
+ SHARED_RUNNERS_SETTINGS = %w[disabled_and_unoverridable disabled_with_override enabled].freeze
+
cache_markdown_field :description, pipeline: :description
has_many :projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -59,6 +61,8 @@ class Namespace < ApplicationRecord
validates :max_artifacts_size, numericality: { only_integer: true, greater_than: 0, allow_nil: true }
validate :nesting_level_allowed
+ validate :changing_shared_runners_enabled_is_allowed
+ validate :changing_allow_descendants_override_disabled_shared_runners_is_allowed
validates_associated :runners
@@ -378,6 +382,52 @@ class Namespace < ApplicationRecord
actual_plan.name
end
+ def changing_shared_runners_enabled_is_allowed
+ return unless Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true)
+ return unless new_record? || changes.has_key?(:shared_runners_enabled)
+
+ if shared_runners_enabled && has_parent? && parent.shared_runners_setting == 'disabled_and_unoverridable'
+ errors.add(:shared_runners_enabled, _('cannot be enabled because parent group has shared Runners disabled'))
+ end
+ end
+
+ def changing_allow_descendants_override_disabled_shared_runners_is_allowed
+ return unless Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true)
+ return unless new_record? || changes.has_key?(:allow_descendants_override_disabled_shared_runners)
+
+ if shared_runners_enabled && !new_record?
+ errors.add(:allow_descendants_override_disabled_shared_runners, _('cannot be changed if shared runners are enabled'))
+ end
+
+ if allow_descendants_override_disabled_shared_runners && has_parent? && parent.shared_runners_setting == 'disabled_and_unoverridable'
+ errors.add(:allow_descendants_override_disabled_shared_runners, _('cannot be enabled because parent group does not allow it'))
+ end
+ end
+
+ def shared_runners_setting
+ if shared_runners_enabled
+ 'enabled'
+ else
+ if allow_descendants_override_disabled_shared_runners
+ 'disabled_with_override'
+ else
+ 'disabled_and_unoverridable'
+ end
+ end
+ end
+
+ def shared_runners_setting_higher_than?(other_setting)
+ if other_setting == 'enabled'
+ false
+ elsif other_setting == 'disabled_with_override'
+ shared_runners_setting == 'enabled'
+ elsif other_setting == 'disabled_and_unoverridable'
+ shared_runners_setting == 'enabled' || shared_runners_setting == 'disabled_with_override'
+ else
+ raise ArgumentError
+ end
+ end
+
private
def all_projects_with_pages
diff --git a/app/models/project.rb b/app/models/project.rb
index ca3729e277a..d726b9aece6 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -435,6 +435,7 @@ class Project < ApplicationRecord
validate :visibility_level_allowed_by_group, if: :should_validate_visibility_level?
validate :visibility_level_allowed_as_fork, if: :should_validate_visibility_level?
validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) }
+ validate :changing_shared_runners_enabled_is_allowed
validates :repository_storage,
presence: true,
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
@@ -1189,6 +1190,15 @@ class Project < ApplicationRecord
end
end
+ def changing_shared_runners_enabled_is_allowed
+ return unless Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true)
+ return unless new_record? || changes.has_key?(:shared_runners_enabled)
+
+ if shared_runners_enabled && group && group.shared_runners_setting == 'disabled_and_unoverridable'
+ errors.add(:shared_runners_enabled, _('cannot be enabled because parent group does not allow it'))
+ end
+ end
+
def to_param
if persisted? && errors.include?(:path)
path_was
diff --git a/app/services/groups/create_service.rb b/app/services/groups/create_service.rb
index 51dca43fa4a..4747e1d5ac5 100644
--- a/app/services/groups/create_service.rb
+++ b/app/services/groups/create_service.rb
@@ -15,6 +15,8 @@ module Groups
after_build_hook(@group, params)
+ inherit_group_shared_runners_settings
+
unless can_use_visibility_level? && can_create_group?
return @group
end
@@ -86,6 +88,13 @@ module Groups
params[:visibility_level] = Gitlab::CurrentSettings.current_application_settings.default_group_visibility
end
+
+ def inherit_group_shared_runners_settings
+ return unless @group.parent
+
+ @group.shared_runners_enabled = @group.parent.shared_runners_enabled
+ @group.allow_descendants_override_disabled_shared_runners = @group.parent.allow_descendants_override_disabled_shared_runners
+ end
end
end
diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb
index 2bd571f60af..70f5c7e2ea7 100644
--- a/app/services/groups/transfer_service.rb
+++ b/app/services/groups/transfer_service.rb
@@ -103,6 +103,9 @@ module Groups
@group.parent = @new_parent_group
@group.clear_memoization(:self_and_ancestors_ids)
+
+ inherit_group_shared_runners_settings
+
@group.save!
end
@@ -161,6 +164,17 @@ module Groups
group_contains_npm_packages: s_('TransferGroup|Group contains projects with NPM packages.')
}.freeze
end
+
+ def inherit_group_shared_runners_settings
+ parent_setting = @group.parent&.shared_runners_setting
+ return unless parent_setting
+
+ if @group.shared_runners_setting_higher_than?(parent_setting)
+ result = Groups::UpdateSharedRunnersService.new(@group, current_user, shared_runners_setting: parent_setting).execute
+
+ raise TransferError, result[:message] unless result[:status] == :success
+ end
+ end
end
end
diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb
index 81393681dc0..382a3dbf0f7 100644
--- a/app/services/groups/update_service.rb
+++ b/app/services/groups/update_service.rb
@@ -19,6 +19,8 @@ module Groups
return false unless valid_path_change_with_npm_packages?
+ return false unless update_shared_runners
+
before_assignment_hook(group, params)
group.assign_attributes(params)
@@ -98,6 +100,17 @@ module Groups
params[:share_with_group_lock] != group.share_with_group_lock
end
+
+ def update_shared_runners
+ return true if params[:shared_runners_setting].nil?
+
+ result = Groups::UpdateSharedRunnersService.new(group, current_user, shared_runners_setting: params.delete(:shared_runners_setting)).execute
+
+ return true if result[:status] == :success
+
+ group.errors.add(:update_shared_runners, result[:message])
+ false
+ end
end
end
diff --git a/app/services/groups/update_shared_runners_service.rb b/app/services/groups/update_shared_runners_service.rb
index 63f57104510..639c5bf6ae0 100644
--- a/app/services/groups/update_shared_runners_service.rb
+++ b/app/services/groups/update_shared_runners_service.rb
@@ -7,44 +7,24 @@ module Groups
validate_params
- enable_or_disable_shared_runners!
- allow_or_disallow_descendants_override_disabled_shared_runners!
+ update_shared_runners
success
- rescue Group::UpdateSharedRunnersError => error
+ rescue ActiveRecord::RecordInvalid, ArgumentError => error
error(error.message)
end
private
def validate_params
- if Gitlab::Utils.to_boolean(params[:shared_runners_enabled]) && !params[:allow_descendants_override_disabled_shared_runners].nil?
- raise Group::UpdateSharedRunnersError, 'Cannot set shared_runners_enabled to true and allow_descendants_override_disabled_shared_runners'
+ unless Namespace::SHARED_RUNNERS_SETTINGS.include?(params[:shared_runners_setting])
+ raise ArgumentError, "state must be one of: #{Namespace::SHARED_RUNNERS_SETTINGS.join(', ')}"
end
end
- def enable_or_disable_shared_runners!
- return if params[:shared_runners_enabled].nil?
-
- if Gitlab::Utils.to_boolean(params[:shared_runners_enabled])
- group.enable_shared_runners!
- else
- group.disable_shared_runners!
- end
- end
-
- def allow_or_disallow_descendants_override_disabled_shared_runners!
- return if params[:allow_descendants_override_disabled_shared_runners].nil?
-
- # Needs to reset group because if both params are present could result in error
- group.reset
-
- if Gitlab::Utils.to_boolean(params[:allow_descendants_override_disabled_shared_runners])
- group.allow_descendants_override_disabled_shared_runners!
- else
- group.disallow_descendants_override_disabled_shared_runners!
- end
+ def update_shared_runners
+ group.update_shared_runners_setting!(params[:shared_runners_setting])
end
end
end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 40a39be2fa5..aa591312c6a 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -110,6 +110,10 @@ module MergeRequests
return
end
+ unless merge_request.allows_multiple_reviewers?
+ params[:reviewer_ids] = params[:reviewer_ids].first(1)
+ end
+
reviewer_ids = params[:reviewer_ids].select { |reviewer_id| user_can_read?(merge_request, reviewer_id) }
if params[:reviewer_ids].map(&:to_s) == [IssuableFinder::Params::NONE]
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 9943dc46731..6fc8e8f8935 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -19,6 +19,10 @@ module Projects
@project = Project.new(params)
+ # If a project is newly created it should have shared runners settings
+ # based on its group having it enabled. This is like the "default value"
+ @project.shared_runners_enabled = false if !params.key?(:shared_runners_enabled) && @project.group && @project.group.shared_runners_setting != 'enabled'
+
# Make sure that the user is allowed to use the specified visibility level
if project_visibility.restricted?
deny_visibility_level(@project, project_visibility.visibility_level)
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index dba5177718d..013861631a1 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -88,6 +88,10 @@ module Projects
# Move uploads
move_project_uploads(project)
+ # If a project is being transferred to another group it means it can already
+ # have shared runners enabled but we need to check whether the new group allows that.
+ project.shared_runners_enabled = false if project.group && project.group.shared_runners_setting == 'disabled_and_unoverridable'
+
project.old_path_with_namespace = @old_path
update_repository_configuration(@new_path)
diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml
index 02b45853aa0..3f0c1596396 100644
--- a/app/views/profiles/keys/_key.html.haml
+++ b/app/views/profiles/keys/_key.html.haml
@@ -23,9 +23,10 @@
%span.expires.gl-mr-3
= s_('Profiles|Expires:')
= key.expires_at ? key.expires_at.to_date : _('Never')
- %span.key-created-at
- = s_('Profiles|Created %{time_ago}'.html_safe) % { time_ago:time_ago_with_tooltip(key.created_at)}
+ %span.key-created-at.gl-display-flex.gl-align-items-center
+ = s_('Profiles|Created%{time_ago}'.html_safe) % { time_ago: time_ago_with_tooltip(key.created_at, html_class: 'gl-ml-2')}
- if key.can_delete?
- = link_to path_to_key(key, is_admin), data: { confirm: _('Are you sure?')}, method: :delete, class: "btn btn-transparent gl-ml-3 align-baseline" do
- %span.sr-only= _('Remove')
- = sprite_icon('remove')
+ .gl-ml-3
+ = button_to '#', class: "btn btn-default gl-button btn-default-tertiary js-confirm-modal-button", data: ssh_key_delete_modal_data(key, is_admin) do
+ %span.sr-only= _('Delete')
+ = sprite_icon('remove')
diff --git a/app/views/profiles/keys/_key_details.html.haml b/app/views/profiles/keys/_key_details.html.haml
index 59d953678e7..2bc7e9eccb8 100644
--- a/app/views/profiles/keys/_key_details.html.haml
+++ b/app/views/profiles/keys/_key_details.html.haml
@@ -38,4 +38,4 @@
.col-md-12
.float-right
- if @key.can_delete?
- = link_to _('Remove'), path_to_key(@key, is_admin), data: {confirm: _('Are you sure?')}, method: :delete, class: "btn btn-remove delete-key qa-delete-key-button"
+ = button_to _('Delete'), '#', class: "btn btn-danger gl-button delete-key js-confirm-modal-button", data: ssh_key_delete_modal_data(@key, is_admin)
diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml
index b438fbbf446..cee479aab0a 100644
--- a/app/views/projects/diffs/_stats.html.haml
+++ b/app/views/projects/diffs/_stats.html.haml
@@ -1,5 +1,5 @@
-- sum_added_lines = diff_files.sum(&:added_lines) # rubocop: disable CodeReuse/ActiveRecord
-- sum_removed_lines = diff_files.sum(&:removed_lines) # rubocop: disable CodeReuse/ActiveRecord
+- sum_added_lines = diff_files.sum(&:added_lines)
+- sum_removed_lines = diff_files.sum(&:removed_lines)
.commit-stat-summary.dropdown
Showing
%button.diff-stats-summary-toggler.js-diff-stats-dropdown{ type: "button", data: { toggle: "dropdown", display: "static" } }<