Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
6aa5c04c74
commit
dd240e5cc4
|
|
@ -1 +1 @@
|
|||
be4a37406e949983d483a4aabb7af0c0768e60af
|
||||
61dcdf969231954c06f16a6222a7540460f4b4f0
|
||||
|
|
|
|||
114
Gemfile.lock
114
Gemfile.lock
|
|
@ -6,59 +6,59 @@ GEM
|
|||
ace-rails-ap (4.1.2)
|
||||
acme-client (2.0.6)
|
||||
faraday (>= 0.17, < 2.0.0)
|
||||
actioncable (6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
actioncable (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
activejob (= 6.0.3.1)
|
||||
activerecord (= 6.0.3.1)
|
||||
activestorage (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
actionmailbox (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
activejob (= 6.0.3.3)
|
||||
activerecord (= 6.0.3.3)
|
||||
activestorage (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
actionview (= 6.0.3.1)
|
||||
activejob (= 6.0.3.1)
|
||||
actionmailer (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
actionview (= 6.0.3.3)
|
||||
activejob (= 6.0.3.3)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.0.3.1)
|
||||
actionview (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
actionpack (6.0.3.3)
|
||||
actionview (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
rack (~> 2.0, >= 2.0.8)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
activerecord (= 6.0.3.1)
|
||||
activestorage (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
actiontext (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
activerecord (= 6.0.3.3)
|
||||
activestorage (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
actionview (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
activejob (6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
activejob (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
activerecord (6.0.3.1)
|
||||
activemodel (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
activemodel (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
activerecord (6.0.3.3)
|
||||
activemodel (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
activerecord-explain-analyze (0.1.0)
|
||||
activerecord (>= 4)
|
||||
pg
|
||||
activestorage (6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
activejob (= 6.0.3.1)
|
||||
activerecord (= 6.0.3.1)
|
||||
activestorage (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
activejob (= 6.0.3.3)
|
||||
activerecord (= 6.0.3.3)
|
||||
marcel (~> 0.3.1)
|
||||
activesupport (6.0.3.1)
|
||||
activesupport (6.0.3.3)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
|
|
@ -183,7 +183,7 @@ GEM
|
|||
concord (0.1.5)
|
||||
adamantium (~> 0.2.0)
|
||||
equalizer (~> 0.0.9)
|
||||
concurrent-ruby (1.1.6)
|
||||
concurrent-ruby (1.1.7)
|
||||
connection_pool (2.2.2)
|
||||
contracts (0.11.0)
|
||||
cork (0.3.0)
|
||||
|
|
@ -577,7 +577,7 @@ GEM
|
|||
mime-types (~> 3.0)
|
||||
multi_xml (>= 0.5.2)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.8.3)
|
||||
i18n (1.8.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
i18n_data (0.8.0)
|
||||
icalendar (2.4.1)
|
||||
|
|
@ -662,7 +662,7 @@ GEM
|
|||
activesupport (>= 4)
|
||||
railties (>= 4)
|
||||
request_store (~> 1.0)
|
||||
loofah (2.5.0)
|
||||
loofah (2.7.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
lru_redux (1.1.0)
|
||||
|
|
@ -713,7 +713,7 @@ GEM
|
|||
net-ntp (2.1.3)
|
||||
net-ssh (6.0.0)
|
||||
netrc (0.11.0)
|
||||
nio4r (2.5.2)
|
||||
nio4r (2.5.4)
|
||||
no_proxy_fix (0.1.2)
|
||||
nokogiri (1.10.10)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
|
|
@ -870,20 +870,20 @@ GEM
|
|||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-timeout (0.5.2)
|
||||
rails (6.0.3.1)
|
||||
actioncable (= 6.0.3.1)
|
||||
actionmailbox (= 6.0.3.1)
|
||||
actionmailer (= 6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
actiontext (= 6.0.3.1)
|
||||
actionview (= 6.0.3.1)
|
||||
activejob (= 6.0.3.1)
|
||||
activemodel (= 6.0.3.1)
|
||||
activerecord (= 6.0.3.1)
|
||||
activestorage (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
rails (6.0.3.3)
|
||||
actioncable (= 6.0.3.3)
|
||||
actionmailbox (= 6.0.3.3)
|
||||
actionmailer (= 6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
actiontext (= 6.0.3.3)
|
||||
actionview (= 6.0.3.3)
|
||||
activejob (= 6.0.3.3)
|
||||
activemodel (= 6.0.3.3)
|
||||
activerecord (= 6.0.3.3)
|
||||
activestorage (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
bundler (>= 1.3.0)
|
||||
railties (= 6.0.3.1)
|
||||
railties (= 6.0.3.3)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
|
|
@ -897,9 +897,9 @@ GEM
|
|||
rails-i18n (6.0.0)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 7)
|
||||
railties (6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
railties (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.20.3, < 2.0)
|
||||
|
|
@ -1106,7 +1106,7 @@ GEM
|
|||
sprockets (3.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.2.1)
|
||||
sprockets-rails (3.2.2)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
|
|
@ -1218,7 +1218,7 @@ GEM
|
|||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
websocket-driver (0.7.1)
|
||||
websocket-driver (0.7.3)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
wikicloth (0.8.1)
|
||||
|
|
@ -1230,7 +1230,7 @@ GEM
|
|||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
yajl-ruby (1.4.1)
|
||||
zeitwerk (2.3.0)
|
||||
zeitwerk (2.4.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
|
|
|||
|
|
@ -81,15 +81,12 @@ export default {
|
|||
default: '',
|
||||
},
|
||||
alertId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
projectId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
projectIssuesPath: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ export default {
|
|||
default: '',
|
||||
},
|
||||
projectId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.',
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
import initConfirmModal from '~/confirm_modal';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initConfirmModal();
|
||||
});
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import initConfirmModal from '~/confirm_modal';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initConfirmModal();
|
||||
});
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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}`);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(() => {});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -253,10 +253,6 @@
|
|||
content: '\f081';
|
||||
}
|
||||
|
||||
.fa-unlink::before {
|
||||
content: '\f127';
|
||||
}
|
||||
|
||||
.fa-file-pdf-o::before {
|
||||
content: '\f1c1';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -28,10 +28,6 @@
|
|||
text-decoration: none;
|
||||
color: $black;
|
||||
border-bottom: 2px solid $gray-darkest;
|
||||
|
||||
.badge.badge-pill {
|
||||
color: $black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -439,10 +439,6 @@
|
|||
content: '\f0c6';
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.no-attachment-icon {
|
||||
&::before {
|
||||
display: none;
|
||||
|
|
|
|||
|
|
@ -29,11 +29,6 @@
|
|||
|
||||
.ref-name {
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
color: $gl-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,10 +70,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $gray-normal;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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:)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 update_shared_runners_setting!(state)
|
||||
raise ArgumentError unless SHARED_RUNNERS_SETTINGS.include?(state)
|
||||
|
||||
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?
|
||||
|
||||
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')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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" } }<
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix displaying a message when design copying is in progress
|
||||
merge_request: 43749
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Updated the admin and user SSH key delete confirmation to use GlModal
|
||||
merge_request: 42824
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Limit postgres_indexes to owned schemas
|
||||
merge_request: 43834
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Change transfer, update and create services for groups and projects to take in consideration shared runners settings
|
||||
merge_request: 36080
|
||||
author: Arthur de Lapertosa Lisboa
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Migrate button in fluentd_output_settings.vue
|
||||
merge_request: 43724
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Set performance cookie to last for a year
|
||||
merge_request: 43692
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: api_commits_without_count
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43159
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/254994
|
||||
type: development
|
||||
group: team::Scalability
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: disable_shared_runners_on_group
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36080
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258991
|
||||
type: development
|
||||
group: group::runner
|
||||
default_enabled: true
|
||||
|
|
@ -21,12 +21,12 @@ if app.config.public_file_server.enabled
|
|||
settings = {
|
||||
enabled: true,
|
||||
host: dev_server.host,
|
||||
manifest_host: dev_server.host,
|
||||
manifest_port: dev_server.port,
|
||||
port: dev_server.port
|
||||
}
|
||||
|
||||
if Rails.env.development?
|
||||
# /assets are proxied through a Rails middlware to the Webpack
|
||||
# server, so we have to use the local Rails settings.
|
||||
settings.merge!(
|
||||
host: Gitlab.config.gitlab.host,
|
||||
port: Gitlab.config.gitlab.port,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UpdatePostgresIndexesView < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
execute(<<~SQL)
|
||||
CREATE OR REPLACE VIEW postgres_indexes AS
|
||||
SELECT
|
||||
pg_namespace.nspname || '.' || pg_class.relname as identifier,
|
||||
pg_index.indexrelid,
|
||||
pg_namespace.nspname as schema,
|
||||
pg_class.relname as name,
|
||||
pg_index.indisunique as unique,
|
||||
pg_index.indisvalid as valid_index,
|
||||
pg_class.relispartition as partitioned,
|
||||
pg_index.indisexclusion as exclusion,
|
||||
pg_indexes.indexdef as definition,
|
||||
pg_relation_size(pg_class.oid) as ondisk_size_bytes
|
||||
FROM pg_index
|
||||
INNER JOIN pg_class ON pg_class.oid = pg_index.indexrelid
|
||||
INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
|
||||
INNER JOIN pg_indexes ON pg_class.relname = pg_indexes.indexname
|
||||
WHERE pg_namespace.nspname <> 'pg_catalog'
|
||||
AND pg_namespace.nspname IN (
|
||||
current_schema(),
|
||||
'gitlab_partitions_dynamic',
|
||||
'gitlab_partitions_static'
|
||||
)
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
execute(<<~SQL)
|
||||
CREATE OR REPLACE VIEW postgres_indexes AS
|
||||
SELECT
|
||||
pg_namespace.nspname || '.' || pg_class.relname as identifier,
|
||||
pg_index.indexrelid,
|
||||
pg_namespace.nspname as schema,
|
||||
pg_class.relname as name,
|
||||
pg_index.indisunique as unique,
|
||||
pg_index.indisvalid as valid_index,
|
||||
pg_class.relispartition as partitioned,
|
||||
pg_index.indisexclusion as exclusion,
|
||||
pg_indexes.indexdef as definition,
|
||||
pg_relation_size(pg_class.oid) as ondisk_size_bytes
|
||||
FROM pg_index
|
||||
INNER JOIN pg_class ON pg_class.oid = pg_index.indexrelid
|
||||
INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
|
||||
INNER JOIN pg_indexes ON pg_class.relname = pg_indexes.indexname
|
||||
WHERE pg_namespace.nspname <> 'pg_catalog'
|
||||
SQL
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
b92b48a17bfd350a70017bfee99bcfb3dbc5ae9e33c8f23ab593666e5c3900aa
|
||||
|
|
@ -14447,7 +14447,7 @@ CREATE VIEW postgres_indexes AS
|
|||
JOIN pg_class ON ((pg_class.oid = pg_index.indexrelid)))
|
||||
JOIN pg_namespace ON ((pg_class.relnamespace = pg_namespace.oid)))
|
||||
JOIN pg_indexes ON ((pg_class.relname = pg_indexes.indexname)))
|
||||
WHERE (pg_namespace.nspname <> 'pg_catalog'::name);
|
||||
WHERE ((pg_namespace.nspname <> 'pg_catalog'::name) AND (pg_namespace.nspname = ANY (ARRAY["current_schema"(), 'gitlab_partitions_dynamic'::name, 'gitlab_partitions_static'::name])));
|
||||
|
||||
CREATE TABLE postgres_reindex_actions (
|
||||
id bigint NOT NULL,
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ type: howto
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20912) in GitLab 12.6.
|
||||
|
||||
## Overview
|
||||
|
||||
GitLab administrators are responsible for the overall security of their instance. To assist, GitLab provides a Credentials inventory to keep track of all the credentials that can be used to access their self-managed instance.
|
||||
|
||||
Using Credentials inventory, you can see all the personal access tokens (PAT) and SSH keys that exist in your GitLab instance. In addition, you can [revoke them](#revoke-a-users-personal-access-token) and see:
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
> - Introduced in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3090) for subgroups in GitLab 12.2.
|
||||
|
||||
## Overview
|
||||
|
||||
With Contribution Analytics you can get an overview of the following activity in your
|
||||
group:
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ Furthermore, the bot user can not be added to any other project.
|
|||
- The username is set to `project_{project_id}_bot` for the first access token, such as `project_123_bot`.
|
||||
- The username is set to `project_{project_id}_bot{bot_count}` for further access tokens, such as `project_123_bot1`.
|
||||
|
||||
After the project access token is [revoked](#revoking-a-project-access-token), the bot user is removed from the project and blocked. All associated records are moved to a system-wide user named "Ghost User". For more information, see [Associated Records](../../profile/account/delete_account.md#associated-records).
|
||||
When the project access token is [revoked](#revoking-a-project-access-token) the bot user is then deleted and all records are moved to a system-wide user with the username "Ghost User". For more information, see [Associated Records](../../profile/account/delete_account.md#associated-records).
|
||||
|
||||
Project bot users are a [GitLab-created service account](../../../subscriptions/self_managed/index.md#choose-the-number-of-users), but count as a licensed seat.
|
||||
These users will not count against your licensed seat in the future when [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/223695) is resolved.
|
||||
|
|
|
|||
|
|
@ -62,19 +62,29 @@ module API
|
|||
first_parent: first_parent,
|
||||
order: order)
|
||||
|
||||
commit_count =
|
||||
if all || path || before || after || first_parent
|
||||
user_project.repository.count_commits(ref: ref, path: path, before: before, after: after, all: all, first_parent: first_parent)
|
||||
else
|
||||
# Cacheable commit count.
|
||||
user_project.repository.commit_count_for_ref(ref)
|
||||
end
|
||||
|
||||
paginated_commits = Kaminari.paginate_array(commits, total_count: commit_count)
|
||||
|
||||
serializer = with_stats ? Entities::CommitWithStats : Entities::Commit
|
||||
|
||||
present paginate(paginated_commits), with: serializer
|
||||
if Feature.enabled?(:api_commits_without_count, user_project)
|
||||
# This tells kaminari that there is 1 more commit after the one we've
|
||||
# loaded, meaning there will be a next page, if the currently loaded set
|
||||
# of commits is equal to the requested page size.
|
||||
commit_count = offset + commits.size + 1
|
||||
paginated_commits = Kaminari.paginate_array(commits, total_count: commit_count)
|
||||
|
||||
present paginate(paginated_commits, exclude_total_headers: true), with: serializer
|
||||
else
|
||||
commit_count =
|
||||
if all || path || before || after || first_parent
|
||||
user_project.repository.count_commits(ref: ref, path: path, before: before, after: after, all: all, first_parent: first_parent)
|
||||
else
|
||||
# Cacheable commit count.
|
||||
user_project.repository.commit_count_for_ref(ref)
|
||||
end
|
||||
|
||||
paginated_commits = Kaminari.paginate_array(commits, total_count: commit_count)
|
||||
|
||||
present paginate(paginated_commits), with: serializer
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Commit multiple file changes as one commit' do
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
module API
|
||||
module Helpers
|
||||
module Pagination
|
||||
def paginate(relation)
|
||||
Gitlab::Pagination::OffsetPagination.new(self).paginate(relation)
|
||||
def paginate(*args)
|
||||
Gitlab::Pagination::OffsetPagination.new(self).paginate(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def all
|
||||
counts.values.sum # rubocop:disable CodeReuse/ActiveRecord
|
||||
counts.values.sum
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -46,13 +46,11 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop:disable CodeReuse/ActiveRecord
|
||||
def number_of_generated_jobs
|
||||
value.sum do |config|
|
||||
config.values.reduce(1) { |acc, values| acc * values.size }
|
||||
end
|
||||
end
|
||||
# rubocop:enable CodeReuse/ActiveRecord
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -57,11 +57,11 @@ module Gitlab
|
|||
end
|
||||
|
||||
def duration
|
||||
Time.current - @started
|
||||
(Time.current - @started).ceil
|
||||
end
|
||||
|
||||
def slot
|
||||
return 0 if duration <= 1
|
||||
return 0 if duration < 2
|
||||
|
||||
Math.log(duration, 2).floor - 1
|
||||
end
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ module Gitlab
|
|||
|
||||
next unless line_too_long?(line)
|
||||
|
||||
url_size = line.scan(%r((https?://\S+))).sum { |(url)| url.length } # rubocop:disable CodeReuse/ActiveRecord
|
||||
url_size = line.scan(%r((https?://\S+))).sum { |(url)| url.length }
|
||||
|
||||
# If the line includes a URL, we'll allow it to exceed MAX_LINE_LENGTH characters, but
|
||||
# only if the line _without_ the URL does not exceed this limit.
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ module Gitlab
|
|||
},
|
||||
invitation_reminders: {
|
||||
tracking_category: 'Growth::Acquisition::Experiment::InvitationReminders'
|
||||
},
|
||||
group_only_trials: {
|
||||
tracking_category: 'Growth::Conversion::Experiment::GroupOnlyTrials'
|
||||
}
|
||||
}.freeze
|
||||
|
||||
|
|
@ -105,7 +108,7 @@ module Gitlab
|
|||
|
||||
def track_experiment_event(experiment_key, action, value = nil)
|
||||
track_experiment_event_for(experiment_key, action, value) do |tracking_data|
|
||||
::Gitlab::Tracking.event(tracking_data.delete(:category), tracking_data.delete(:action), tracking_data)
|
||||
::Gitlab::Tracking.event(tracking_data.delete(:category), tracking_data.delete(:action), **tracking_data)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -504,7 +504,7 @@ module Gitlab
|
|||
changes_size = 0
|
||||
|
||||
changes_list.each do |change|
|
||||
changes_size += repository.new_blobs(change[:newrev]).sum(&:size) # rubocop: disable CodeReuse/ActiveRecord
|
||||
changes_size += repository.new_blobs(change[:newrev]).sum(&:size)
|
||||
|
||||
check_size_against_limit(changes_size)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module Gitlab
|
|||
def check
|
||||
return unless http_servers
|
||||
|
||||
http_servers.sum(&:worker_processes) # rubocop: disable CodeReuse/ActiveRecord
|
||||
http_servers.sum(&:worker_processes)
|
||||
end
|
||||
|
||||
# Traversal of ObjectSpace is expensive, on fully loaded application
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ module Gitlab
|
|||
|
||||
%i[get_request_count query_time read_bytes write_bytes].each do |method|
|
||||
define_method method do
|
||||
STORAGES.sum(&method) # rubocop:disable CodeReuse/ActiveRecord
|
||||
STORAGES.sum(&method)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ module Gitlab
|
|||
links&.each do |link|
|
||||
next unless link.is_a? Hash
|
||||
|
||||
Gitlab::UrlBlocker.validate!(link[:url], blocker_args)
|
||||
Gitlab::UrlBlocker.validate!(link[:url], **blocker_args)
|
||||
rescue Gitlab::UrlBlocker::BlockedUrlError
|
||||
link[:url] = ''
|
||||
end
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def unicorn_workers_count
|
||||
http_servers.sum(&:worker_processes) # rubocop: disable CodeReuse/ActiveRecord
|
||||
http_servers.sum(&:worker_processes)
|
||||
end
|
||||
|
||||
# Traversal of ObjectSpace is expensive, on fully loaded application
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ module Gitlab
|
|||
@request_context = request_context
|
||||
end
|
||||
|
||||
def paginate(relation)
|
||||
def paginate(relation, exclude_total_headers: false)
|
||||
paginate_with_limit_optimization(add_default_order(relation)).tap do |data|
|
||||
add_pagination_headers(data)
|
||||
add_pagination_headers(data, exclude_total_headers)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -47,14 +47,14 @@ module Gitlab
|
|||
relation
|
||||
end
|
||||
|
||||
def add_pagination_headers(paginated_data)
|
||||
def add_pagination_headers(paginated_data, exclude_total_headers)
|
||||
header 'X-Per-Page', paginated_data.limit_value.to_s
|
||||
header 'X-Page', paginated_data.current_page.to_s
|
||||
header 'X-Next-Page', paginated_data.next_page.to_s
|
||||
header 'X-Prev-Page', paginated_data.prev_page.to_s
|
||||
header 'Link', pagination_links(paginated_data)
|
||||
|
||||
return if data_without_counts?(paginated_data)
|
||||
return if exclude_total_headers || data_without_counts?(paginated_data)
|
||||
|
||||
header 'X-Total', paginated_data.total_count.to_s
|
||||
header 'X-Total-Pages', total_pages(paginated_data).to_s
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ module Gitlab
|
|||
|
||||
def rss_increase_by_jobs
|
||||
Gitlab::SidekiqDaemon::Monitor.instance.jobs_mutex.synchronize do
|
||||
Gitlab::SidekiqDaemon::Monitor.instance.jobs.sum do |job| # rubocop:disable CodeReuse/ActiveRecord
|
||||
Gitlab::SidekiqDaemon::Monitor.instance.jobs.sum do |job|
|
||||
rss_increase_by_job(job)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def sum(relation, column, *rest)
|
||||
relation.select(relation.all.table[column].sum).to_sql # rubocop:disable CodeReuse/ActiveRecord
|
||||
relation.select(relation.all.table[column].sum).to_sql
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -88,10 +88,9 @@ module Gitlab
|
|||
end
|
||||
|
||||
def load_dev_server_manifest
|
||||
host = ::Rails.configuration.webpack.dev_server.host
|
||||
port = ::Rails.configuration.webpack.dev_server.port
|
||||
scheme = ::Rails.configuration.webpack.dev_server.https ? 'https' : 'http'
|
||||
uri = Addressable::URI.new(scheme: scheme, host: host, port: port, path: dev_server_path)
|
||||
host = ::Rails.configuration.webpack.dev_server.manifest_host
|
||||
port = ::Rails.configuration.webpack.dev_server.manifest_port
|
||||
uri = Addressable::URI.new(scheme: 'http', host: host, port: port, path: dev_server_path)
|
||||
|
||||
# localhost could be blocked via Gitlab::HTTP
|
||||
response = HTTParty.get(uri.to_s, verify: false) # rubocop:disable Gitlab/HTTParty
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module Peek
|
|||
private
|
||||
|
||||
def duration
|
||||
detail_store.map { |entry| entry[:duration] }.sum * 1000 # rubocop:disable CodeReuse/ActiveRecord
|
||||
detail_store.map { |entry| entry[:duration] }.sum * 1000
|
||||
end
|
||||
|
||||
def calls
|
||||
|
|
|
|||
|
|
@ -3345,6 +3345,9 @@ msgstr ""
|
|||
msgid "Are you sure you want to delete this %{typeOfComment}?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure you want to delete this SSH key?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure you want to delete this board?"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -4548,6 +4551,9 @@ msgstr ""
|
|||
msgid "Cannot create the abuse report. This user has been blocked."
|
||||
msgstr ""
|
||||
|
||||
msgid "Cannot enable shared runners because parent group does not allow it"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cannot have multiple Jira imports running at the same time"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -26024,6 +26030,9 @@ msgstr ""
|
|||
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
|
||||
msgstr ""
|
||||
|
||||
msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
|
||||
msgstr ""
|
||||
|
||||
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -29951,6 +29960,15 @@ msgstr ""
|
|||
msgid "cannot be changed if a personal project has container registry tags."
|
||||
msgstr ""
|
||||
|
||||
msgid "cannot be changed if shared runners are enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "cannot be enabled because parent group does not allow it"
|
||||
msgstr ""
|
||||
|
||||
msgid "cannot be enabled because parent group has shared Runners disabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "cannot be enabled unless all domains have TLS certificates"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
"@gitlab/svgs": "1.168.0",
|
||||
"@gitlab/ui": "21.9.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "^6.0.3-1",
|
||||
"@rails/actioncable": "^6.0.3-3",
|
||||
"@rails/ujs": "^6.0.3-2",
|
||||
"@sentry/browser": "^5.22.3",
|
||||
"@sourcegraph/code-host-integration": "0.0.50",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'gitlab-qa'
|
||||
gem 'activesupport', '~> 6.0.3.1' # This should stay in sync with the root's Gemfile
|
||||
gem 'activesupport', '~> 6.0.3.3' # This should stay in sync with the root's Gemfile
|
||||
gem 'capybara', '~> 3.29.0'
|
||||
gem 'capybara-screenshot', '~> 1.0.23'
|
||||
gem 'rake', '~> 12.3.3'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ GEM
|
|||
remote: https://rubygems.org/
|
||||
specs:
|
||||
abstract_type (0.0.7)
|
||||
activesupport (6.0.3.1)
|
||||
activesupport (6.0.3.3)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
|
|
@ -38,7 +38,7 @@ GEM
|
|||
concord (0.1.5)
|
||||
adamantium (~> 0.2.0)
|
||||
equalizer (~> 0.0.9)
|
||||
concurrent-ruby (1.1.6)
|
||||
concurrent-ruby (1.1.7)
|
||||
debase (0.2.4.1)
|
||||
debase-ruby_core_source (>= 0.10.2)
|
||||
debase-ruby_core_source (0.10.6)
|
||||
|
|
@ -52,7 +52,7 @@ GEM
|
|||
http-accept (1.7.0)
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
i18n (1.8.2)
|
||||
i18n (1.8.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
ice_nine (0.11.2)
|
||||
knapsack (1.17.1)
|
||||
|
|
@ -67,11 +67,11 @@ GEM
|
|||
mime-types-data (3.2020.0425)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.14.1)
|
||||
minitest (5.14.2)
|
||||
netrc (0.11.0)
|
||||
nokogiri (1.10.9)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
parallel (1.17.0)
|
||||
parallel (1.19.2)
|
||||
parallel_tests (2.29.0)
|
||||
parallel
|
||||
parser (2.7.1.4)
|
||||
|
|
@ -145,13 +145,13 @@ GEM
|
|||
procto (~> 0.0.2)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.3.0)
|
||||
zeitwerk (2.4.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
activesupport (~> 6.0.3.1)
|
||||
activesupport (~> 6.0.3.3)
|
||||
airborne (~> 0.3.4)
|
||||
capybara (~> 3.29.0)
|
||||
capybara-screenshot (~> 1.0.23)
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ module QA
|
|||
element :add_key_button
|
||||
end
|
||||
|
||||
view 'app/views/profiles/keys/_key_details.html.haml' do
|
||||
element :delete_key_button
|
||||
view 'app/helpers/profiles_helper.rb' do
|
||||
element :delete_ssh_key_button
|
||||
element :ssh_key_delete_modal
|
||||
end
|
||||
|
||||
view 'app/views/profiles/keys/_key_table.html.haml' do
|
||||
|
|
@ -38,10 +39,13 @@ module QA
|
|||
def remove_key(title)
|
||||
click_link(title)
|
||||
|
||||
click_element(:delete_ssh_key_button)
|
||||
|
||||
# Retrying due to https://gitlab.com/gitlab-org/gitlab/-/issues/255287
|
||||
retry_on_exception do
|
||||
accept_alert do
|
||||
click_element(:delete_key_button)
|
||||
wait_for_animated_element(:ssh_key_delete_modal)
|
||||
within_element(:ssh_key_delete_modal) do
|
||||
click_button('Delete')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,20 +5,20 @@ require_relative '../../code_reuse_helpers'
|
|||
module RuboCop
|
||||
module Cop
|
||||
module CodeReuse
|
||||
# Cop that blacklists the use of ActiveRecord methods outside of models.
|
||||
# Cop that denies the use of ActiveRecord methods outside of models.
|
||||
class ActiveRecord < RuboCop::Cop::Cop
|
||||
include CodeReuseHelpers
|
||||
|
||||
MSG = 'This method can only be used inside an ActiveRecord model: ' \
|
||||
'https://gitlab.com/gitlab-org/gitlab-foss/issues/49653'
|
||||
|
||||
# Various methods from ActiveRecord::Querying that are blacklisted. We
|
||||
# Various methods from ActiveRecord::Querying that are denied. We
|
||||
# exclude some generic ones such as `any?` and `first`, as these may
|
||||
# lead to too many false positives, since `Array` also supports these
|
||||
# methods.
|
||||
#
|
||||
# The keys of this Hash are the blacklisted method names. The values are
|
||||
# booleans that indicate if the method should only be blacklisted if any
|
||||
# The keys of this Hash are the denied method names. The values are
|
||||
# booleans that indicate if the method should only be denied if any
|
||||
# arguments are provided.
|
||||
NOT_ALLOWED = {
|
||||
average: true,
|
||||
|
|
@ -57,7 +57,6 @@ module RuboCop
|
|||
references: true,
|
||||
reorder: true,
|
||||
rewhere: true,
|
||||
sum: false,
|
||||
take: false,
|
||||
take!: false,
|
||||
unscope: false,
|
||||
|
|
@ -65,9 +64,9 @@ module RuboCop
|
|||
with: true
|
||||
}.freeze
|
||||
|
||||
# Directories that allow the use of the blacklisted methods. These
|
||||
# Directories that allow the use of the denied methods. These
|
||||
# directories are checked relative to both . and ee/
|
||||
WHITELISTED_DIRECTORIES = %w[
|
||||
ALLOWED_DIRECTORIES = %w[
|
||||
app/models
|
||||
config
|
||||
danger
|
||||
|
|
@ -88,7 +87,7 @@ module RuboCop
|
|||
].freeze
|
||||
|
||||
def on_send(node)
|
||||
return if in_whitelisted_directory?(node)
|
||||
return if in_allowed_directory?(node)
|
||||
|
||||
receiver = node.children[0]
|
||||
send_name = node.children[1]
|
||||
|
|
@ -105,12 +104,12 @@ module RuboCop
|
|||
end
|
||||
end
|
||||
|
||||
# Returns true if the node resides in one of the whitelisted
|
||||
# Returns true if the node resides in one of the allowed
|
||||
# directories.
|
||||
def in_whitelisted_directory?(node)
|
||||
def in_allowed_directory?(node)
|
||||
path = file_path_for_node(node)
|
||||
|
||||
WHITELISTED_DIRECTORIES.any? do |directory|
|
||||
ALLOWED_DIRECTORIES.any? do |directory|
|
||||
path.start_with?(
|
||||
File.join(rails_root, directory),
|
||||
File.join(rails_root, 'ee', directory)
|
||||
|
|
@ -119,12 +118,12 @@ module RuboCop
|
|||
end
|
||||
|
||||
# We can not auto correct code like this, as it requires manual
|
||||
# refactoring. Instead, we'll just whitelist the surrounding scope.
|
||||
# refactoring. Instead, we'll just allow the surrounding scope.
|
||||
#
|
||||
# Despite this method's presence, you should not use it. This method
|
||||
# exists to make it possible to whitelist large chunks of offenses we
|
||||
# exists to make it possible to allow large chunks of offenses we
|
||||
# can't fix in the short term. If you are writing new code, follow the
|
||||
# code reuse guidelines, instead of whitelisting any new offenses.
|
||||
# code reuse guidelines, instead of allowing any new offenses.
|
||||
def autocorrect(node)
|
||||
scope = surrounding_scope_of(node)
|
||||
indent = indentation_of(scope)
|
||||
|
|
@ -132,7 +131,7 @@ module RuboCop
|
|||
lambda do |corrector|
|
||||
# This prevents us from inserting the same enable/disable comment
|
||||
# for a method or block that has multiple offenses.
|
||||
next if whitelisted_scopes.include?(scope)
|
||||
next if allowed_scopes.include?(scope)
|
||||
|
||||
corrector.insert_before(
|
||||
scope.source_range,
|
||||
|
|
@ -144,7 +143,7 @@ module RuboCop
|
|||
"\n#{indent}# rubocop: enable #{cop_name}"
|
||||
)
|
||||
|
||||
whitelisted_scopes << scope
|
||||
allowed_scopes << scope
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -160,8 +159,8 @@ module RuboCop
|
|||
end
|
||||
end
|
||||
|
||||
def whitelisted_scopes
|
||||
@whitelisted_scopes ||= Set.new
|
||||
def allowed_scopes
|
||||
@allowed_scopes ||= Set.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -73,4 +73,45 @@ RSpec.describe Projects::RunnersController do
|
|||
expect(runner.active).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#toggle_shared_runners' do
|
||||
let(:group) { create(:group) }
|
||||
let(:project) { create(:project, group: group) }
|
||||
|
||||
it 'toggles shared_runners_enabled when the group allows shared runners' do
|
||||
project.update!(shared_runners_enabled: true)
|
||||
|
||||
post :toggle_shared_runners, params: params
|
||||
|
||||
project.reload
|
||||
|
||||
expect(response).to have_gitlab_http_status(:found)
|
||||
expect(project.shared_runners_enabled).to eq(false)
|
||||
end
|
||||
|
||||
it 'toggles shared_runners_enabled when the group disallows shared runners but allows overrides' do
|
||||
group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: true)
|
||||
project.update!(shared_runners_enabled: false)
|
||||
|
||||
post :toggle_shared_runners, params: params
|
||||
|
||||
project.reload
|
||||
|
||||
expect(response).to have_gitlab_http_status(:found)
|
||||
expect(project.shared_runners_enabled).to eq(true)
|
||||
end
|
||||
|
||||
it 'does not enable if the group disallows shared runners' do
|
||||
group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: false)
|
||||
project.update!(shared_runners_enabled: false)
|
||||
|
||||
post :toggle_shared_runners, params: params
|
||||
|
||||
project.reload
|
||||
|
||||
expect(response).to have_gitlab_http_status(:found)
|
||||
expect(project.shared_runners_enabled).to eq(false)
|
||||
expect(flash[:alert]).to eq("Cannot enable shared runners because parent group does not allow it")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -63,5 +63,13 @@ FactoryBot.define do
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
trait :shared_runners_disabled do
|
||||
shared_runners_enabled { false }
|
||||
end
|
||||
|
||||
trait :allow_descendants_override_disabled_shared_runners do
|
||||
allow_descendants_override_disabled_shared_runners { true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -620,7 +620,7 @@ RSpec.describe "Admin::Users" do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'show user keys' do
|
||||
describe 'show user keys', :js do
|
||||
let!(:key1) do
|
||||
create(:key, user: user, title: "ssh-rsa Key1", key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4FIEBXGi4bPU8kzxMefudPIJ08/gNprdNTaO9BR/ndy3+58s2HCTw2xCHcsuBmq+TsAqgEidVq4skpqoTMB+Uot5Uzp9z4764rc48dZiI661izoREoKnuRQSsRqUTHg5wrLzwxlQbl1MVfRWQpqiz/5KjBC7yLEb9AbusjnWBk8wvC1bQPQ1uLAauEA7d836tgaIsym9BrLsMVnR4P1boWD3Xp1B1T/ImJwAGHvRmP/ycIqmKdSpMdJXwxcb40efWVj0Ibbe7ii9eeoLdHACqevUZi6fwfbymdow+FeqlkPoHyGg3Cu4vD/D8+8cRc7mE/zGCWcQ15Var83Tczour Key1")
|
||||
end
|
||||
|
|
@ -643,7 +643,11 @@ RSpec.describe "Admin::Users" do
|
|||
expect(page).to have_content(key2.title)
|
||||
expect(page).to have_content(key2.key)
|
||||
|
||||
click_link 'Remove'
|
||||
click_button 'Delete'
|
||||
|
||||
page.within('.modal') do
|
||||
page.click_button('Delete')
|
||||
end
|
||||
|
||||
expect(page).not_to have_content(key2.title)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -71,21 +71,35 @@ RSpec.describe 'Profile > SSH Keys' do
|
|||
expect(page).to have_content(key.title)
|
||||
end
|
||||
|
||||
it 'User removes a key via the key index' do
|
||||
create(:key, user: user)
|
||||
visit profile_keys_path
|
||||
describe 'User removes a key', :js do
|
||||
shared_examples 'removes key' do
|
||||
it 'removes key' do
|
||||
visit path
|
||||
click_button('Delete')
|
||||
|
||||
click_link('Remove')
|
||||
page.within('.modal') do
|
||||
page.click_button('Delete')
|
||||
end
|
||||
|
||||
expect(page).to have_content('Your SSH keys (0)')
|
||||
end
|
||||
expect(page).to have_content('Your SSH keys (0)')
|
||||
end
|
||||
end
|
||||
|
||||
it 'User removes a key via its details page' do
|
||||
key = create(:key, user: user)
|
||||
visit profile_key_path(key)
|
||||
context 'via the key index' do
|
||||
before do
|
||||
create(:key, user: user)
|
||||
end
|
||||
|
||||
click_link('Remove')
|
||||
let(:path) { profile_keys_path }
|
||||
|
||||
expect(page).to have_content('Your SSH keys (0)')
|
||||
it_behaves_like 'removes key'
|
||||
end
|
||||
|
||||
context 'via its details page' do
|
||||
let(:key) { create(:key, user: user) }
|
||||
let(:path) { profile_keys_path(key) }
|
||||
|
||||
it_behaves_like 'removes key'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -264,10 +264,10 @@ describe('Design management index page', () => {
|
|||
|
||||
describe('handling design collection copy state', () => {
|
||||
it.each`
|
||||
copyState | isRendered | description
|
||||
${'COPYING'} | ${true} | ${'renders'}
|
||||
${'READY'} | ${false} | ${'does not render'}
|
||||
${'ERROR'} | ${false} | ${'does not render'}
|
||||
copyState | isRendered | description
|
||||
${'IN_PROGRESS'} | ${true} | ${'renders'}
|
||||
${'READY'} | ${false} | ${'does not render'}
|
||||
${'ERROR'} | ${false} | ${'does not render'}
|
||||
`(
|
||||
'$description the copying message if design collection copyState is $copyState',
|
||||
({ copyState, isRendered }) => {
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ export const mockProjectId = '21';
|
|||
|
||||
export const mockPostParams = {
|
||||
ref: 'tag-1',
|
||||
variables: [
|
||||
{ key: 'test_var', value: 'test_var_val', variable_type: 'env_var' },
|
||||
{ key: 'test_file', value: 'test_file_val', variable_type: 'file' },
|
||||
variables_attributes: [
|
||||
{ key: 'test_var', secret_value: 'test_var_val', variable_type: 'env_var' },
|
||||
{ key: 'test_file', secret_value: 'test_file_val', variable_type: 'file' },
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import initSnippet from '~/snippet/snippet_bundle';
|
|||
|
||||
jest.mock('~/snippet/snippet_bundle');
|
||||
jest.mock('~/snippets');
|
||||
jest.mock('~/gl_form');
|
||||
|
||||
describe('Snippet edit form initialization', () => {
|
||||
const setFF = flag => {
|
||||
|
|
|
|||
|
|
@ -15,14 +15,36 @@ RSpec.describe Gitlab::Ci::Runner::Backoff do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns an integer value' do
|
||||
freeze_time do
|
||||
described_class.new(5.seconds.ago).then do |backoff|
|
||||
expect(backoff.duration).to be 5
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns the smallest number greater than or equal to duration' do
|
||||
freeze_time do
|
||||
described_class.new(0.5.seconds.ago).then do |backoff|
|
||||
expect(backoff.duration).to be 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#slot' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:started, :slot) do
|
||||
0 | 0
|
||||
0.1 | 0
|
||||
0.9 | 0
|
||||
1 | 0
|
||||
1.1 | 0
|
||||
1.9 | 0
|
||||
2 | 0
|
||||
2.9 | 0
|
||||
3 | 0
|
||||
4 | 1
|
||||
5 | 1
|
||||
|
|
@ -30,6 +52,7 @@ RSpec.describe Gitlab::Ci::Runner::Backoff do
|
|||
7 | 1
|
||||
8 | 2
|
||||
9 | 2
|
||||
9.9 | 2
|
||||
10 | 2
|
||||
15 | 2
|
||||
16 | 3
|
||||
|
|
@ -59,15 +82,22 @@ RSpec.describe Gitlab::Ci::Runner::Backoff do
|
|||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:started, :backoff) do
|
||||
0 | 1
|
||||
0.1 | 1
|
||||
0.9 | 1
|
||||
1 | 1
|
||||
1.1 | 1
|
||||
1.9 | 1
|
||||
2 | 1
|
||||
3 | 1
|
||||
4 | 2
|
||||
5 | 2
|
||||
6 | 2
|
||||
6.5 | 2
|
||||
7 | 2
|
||||
8 | 4
|
||||
9 | 4
|
||||
9.9 | 4
|
||||
10 | 4
|
||||
15 | 4
|
||||
16 | 8
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ RSpec.describe Gitlab::Pagination::OffsetPagination do
|
|||
|
||||
let(:request_context) { double("request_context") }
|
||||
|
||||
subject do
|
||||
subject(:paginator) do
|
||||
described_class.new(request_context)
|
||||
end
|
||||
|
||||
|
|
@ -119,6 +119,34 @@ RSpec.describe Gitlab::Pagination::OffsetPagination do
|
|||
subject.paginate(resource)
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not return the total headers when excluding them' do
|
||||
expect_no_header('X-Total')
|
||||
expect_no_header('X-Total-Pages')
|
||||
expect_header('X-Per-Page', '2')
|
||||
expect_header('X-Page', '1')
|
||||
|
||||
paginator.paginate(resource, exclude_total_headers: true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when resource is a paginatable array' do
|
||||
let(:resource) { Kaminari.paginate_array(Project.all.to_a) }
|
||||
|
||||
it_behaves_like 'response with pagination headers'
|
||||
|
||||
it 'only returns the requested resources' do
|
||||
expect(paginator.paginate(resource).count).to eq(2)
|
||||
end
|
||||
|
||||
it 'does not return total headers when excluding them' do
|
||||
expect_no_header('X-Total')
|
||||
expect_no_header('X-Total-Pages')
|
||||
expect_header('X-Per-Page', '2')
|
||||
expect_header('X-Page', '1')
|
||||
|
||||
paginator.paginate(resource, exclude_total_headers: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Gitlab::Prometheus::QueryVariables do
|
||||
describe '.call' do
|
||||
let_it_be_with_refind(:environment) { create(:environment) }
|
||||
let(:project) { environment.project }
|
||||
let(:environment) { create(:environment) }
|
||||
let(:slug) { environment.slug }
|
||||
let(:params) { {} }
|
||||
|
||||
subject { described_class.call(environment, params) }
|
||||
subject { described_class.call(environment, **params) }
|
||||
|
||||
it { is_expected.to include(ci_environment_slug: slug) }
|
||||
it { is_expected.to include(ci_project_name: project.name) }
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ RSpec.describe Gitlab::Webpack::Manifest do
|
|||
before do
|
||||
# Test that config variables work while we're here
|
||||
::Rails.configuration.webpack.dev_server.host = 'hostname'
|
||||
::Rails.configuration.webpack.dev_server.port = 2000
|
||||
::Rails.configuration.webpack.dev_server.port = 1999
|
||||
::Rails.configuration.webpack.dev_server.manifest_host = 'hostname'
|
||||
::Rails.configuration.webpack.dev_server.manifest_port = 2000
|
||||
::Rails.configuration.webpack.manifest_filename = "my_manifest.json"
|
||||
::Rails.configuration.webpack.public_path = "public_path"
|
||||
::Rails.configuration.webpack.output_dir = "manifest_output"
|
||||
|
|
|
|||
|
|
@ -1344,229 +1344,134 @@ RSpec.describe Group do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#shared_runners_allowed?' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:shared_runners_enabled, :allow_descendants_override, :expected_shared_runners_allowed) do
|
||||
true | false | true
|
||||
true | true | true
|
||||
false | false | false
|
||||
false | true | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
let!(:group) { create(:group, shared_runners_enabled: shared_runners_enabled, allow_descendants_override_disabled_shared_runners: allow_descendants_override) }
|
||||
|
||||
it 'returns the expected result' do
|
||||
expect(group.shared_runners_allowed?).to eq(expected_shared_runners_allowed)
|
||||
end
|
||||
end
|
||||
def subject_and_reload(*models)
|
||||
subject
|
||||
models.map(&:reload)
|
||||
end
|
||||
|
||||
describe '#parent_allows_shared_runners?' do
|
||||
context 'when parent group is present' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
describe '#update_shared_runners_setting!' do
|
||||
context 'enabled' do
|
||||
subject { group.update_shared_runners_setting!('enabled') }
|
||||
|
||||
where(:shared_runners_enabled, :allow_descendants_override, :expected_shared_runners_allowed) do
|
||||
true | false | true
|
||||
true | true | true
|
||||
false | false | false
|
||||
false | true | true
|
||||
context 'group that its ancestors have shared runners disabled' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
|
||||
|
||||
it 'raises error and does not enable shared Runners' do
|
||||
expect { subject_and_reload(parent, group, project) }
|
||||
.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Shared runners enabled cannot be enabled because parent group has shared Runners disabled')
|
||||
.and not_change { parent.shared_runners_enabled }
|
||||
.and not_change { group.shared_runners_enabled }
|
||||
.and not_change { project.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
|
||||
with_them do
|
||||
let!(:parent_group) { create(:group, shared_runners_enabled: shared_runners_enabled, allow_descendants_override_disabled_shared_runners: allow_descendants_override) }
|
||||
let!(:group) { create(:group, parent: parent_group) }
|
||||
context 'root group with shared runners disabled' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
|
||||
|
||||
it 'returns the expected result' do
|
||||
expect(group.parent_allows_shared_runners?).to eq(expected_shared_runners_allowed)
|
||||
it 'enables shared Runners only for itself' do
|
||||
expect { subject_and_reload(group, sub_group, project) }
|
||||
.to change { group.shared_runners_enabled }.from(false).to(true)
|
||||
.and not_change { sub_group.shared_runners_enabled }
|
||||
.and not_change { project.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parent group is missing' do
|
||||
let!(:group) { create(:group) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(group.parent_allows_shared_runners?).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parent_enabled_shared_runners?' do
|
||||
subject { group.parent_enabled_shared_runners? }
|
||||
|
||||
context 'when parent group is present' do
|
||||
context 'When shared Runners are disabled' do
|
||||
let!(:parent_group) { create(:group, :shared_runners_disabled) }
|
||||
let!(:group) { create(:group, parent: parent_group) }
|
||||
|
||||
it { is_expected.to be_falsy }
|
||||
end
|
||||
|
||||
context 'When shared Runners are enabled' do
|
||||
let!(:parent_group) { create(:group) }
|
||||
let!(:group) { create(:group, parent: parent_group) }
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parent group is missing' do
|
||||
let!(:group) { create(:group) }
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#enable_shared_runners!' do
|
||||
subject { group.enable_shared_runners! }
|
||||
|
||||
context 'group that its ancestors have shared runners disabled' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
|
||||
|
||||
it 'raises error and does not enable shared Runners' do
|
||||
expect { subject }
|
||||
.to raise_error(described_class::UpdateSharedRunnersError, 'Shared Runners disabled for the parent group')
|
||||
.and not_change { parent.reload.shared_runners_enabled }
|
||||
.and not_change { group.reload.shared_runners_enabled }
|
||||
.and not_change { project.reload.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
|
||||
context 'root group with shared runners disabled' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
|
||||
|
||||
it 'enables shared Runners only for itself' do
|
||||
expect { subject }
|
||||
.to change { group.reload.shared_runners_enabled }.from(false).to(true)
|
||||
.and not_change { sub_group.reload.shared_runners_enabled }
|
||||
.and not_change { project.reload.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#disable_shared_runners!' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent: group) }
|
||||
let_it_be(:sub_group_2) { create(:group, parent: group) }
|
||||
let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) }
|
||||
let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) }
|
||||
|
||||
subject { group.disable_shared_runners! }
|
||||
|
||||
it 'disables shared Runners for all descendant groups and projects' do
|
||||
expect { subject }
|
||||
.to change { group.reload.shared_runners_enabled }.from(true).to(false)
|
||||
.and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { sub_group.reload.shared_runners_enabled }
|
||||
.and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and change { sub_group_2.reload.shared_runners_enabled }.from(true).to(false)
|
||||
.and not_change { sub_group_2.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and change { project.reload.shared_runners_enabled }.from(true).to(false)
|
||||
.and change { project_2.reload.shared_runners_enabled }.from(true).to(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#allow_descendants_override_disabled_shared_runners!' do
|
||||
subject { group.allow_descendants_override_disabled_shared_runners! }
|
||||
|
||||
context 'top level group' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
|
||||
|
||||
it 'enables allow descendants to override only for itself' do
|
||||
expect { subject }
|
||||
.to change { group.reload.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
|
||||
.and not_change { group.reload.shared_runners_enabled }
|
||||
.and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { sub_group.reload.shared_runners_enabled }
|
||||
.and not_change { project.reload.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
|
||||
context 'group that its ancestors have shared Runners disabled but allows to override' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
|
||||
|
||||
it 'enables allow descendants to override' do
|
||||
expect { subject }
|
||||
.to not_change { parent.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { parent.reload.shared_runners_enabled }
|
||||
.and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
|
||||
.and not_change { group.reload.shared_runners_enabled }
|
||||
.and not_change { project.reload.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parent does not allow' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false ) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
|
||||
|
||||
it 'raises error and does not allow descendants to override' do
|
||||
expect { subject }
|
||||
.to raise_error(described_class::UpdateSharedRunnersError, 'Group level shared Runners not allowed')
|
||||
.and not_change { parent.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { parent.reload.shared_runners_enabled }
|
||||
.and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { group.reload.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
|
||||
context 'top level group that has shared Runners enabled' do
|
||||
let_it_be(:group) { create(:group, shared_runners_enabled: true) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
|
||||
|
||||
it 'raises error and does not change config' do
|
||||
expect { subject }
|
||||
.to raise_error(described_class::UpdateSharedRunnersError, 'Shared Runners enabled')
|
||||
.and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { group.reload.shared_runners_enabled }
|
||||
.and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { sub_group.reload.shared_runners_enabled }
|
||||
.and not_change { project.reload.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#disallow_descendants_override_disabled_shared_runners!' do
|
||||
subject { group.disallow_descendants_override_disabled_shared_runners! }
|
||||
|
||||
context 'top level group' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners ) }
|
||||
context 'disabled_and_unoverridable' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent: group) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: true, group: sub_group) }
|
||||
let_it_be(:sub_group_2) { create(:group, parent: group) }
|
||||
let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) }
|
||||
let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) }
|
||||
|
||||
it 'disables allow project to override for descendants and disables project shared Runners' do
|
||||
expect { subject }
|
||||
.to not_change { group.reload.shared_runners_enabled }
|
||||
.and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
|
||||
.and not_change { sub_group.reload.shared_runners_enabled }
|
||||
.and change { sub_group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
|
||||
.and change { project.reload.shared_runners_enabled }.from(true).to(false)
|
||||
subject { group.update_shared_runners_setting!('disabled_and_unoverridable') }
|
||||
|
||||
it 'disables shared Runners for all descendant groups and projects' do
|
||||
expect { subject_and_reload(group, sub_group, sub_group_2, project, project_2) }
|
||||
.to change { group.shared_runners_enabled }.from(true).to(false)
|
||||
.and not_change { group.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { sub_group.shared_runners_enabled }
|
||||
.and change { sub_group.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
|
||||
.and change { sub_group_2.shared_runners_enabled }.from(true).to(false)
|
||||
.and not_change { sub_group_2.allow_descendants_override_disabled_shared_runners }
|
||||
.and change { project.shared_runners_enabled }.from(true).to(false)
|
||||
.and change { project_2.shared_runners_enabled }.from(true).to(false)
|
||||
end
|
||||
|
||||
context 'with override on self' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
|
||||
|
||||
it 'disables it' do
|
||||
expect { subject_and_reload(group) }
|
||||
.to not_change { group.shared_runners_enabled }
|
||||
.and change { group.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'top level group that has shared Runners enabled' do
|
||||
let_it_be(:group) { create(:group, shared_runners_enabled: true) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
|
||||
context 'disabled_with_override' do
|
||||
subject { group.update_shared_runners_setting!('disabled_with_override') }
|
||||
|
||||
it 'results error and does not change config' do
|
||||
expect { subject }
|
||||
.to raise_error(described_class::UpdateSharedRunnersError, 'Shared Runners enabled')
|
||||
.and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { group.reload.shared_runners_enabled }
|
||||
.and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { sub_group.reload.shared_runners_enabled }
|
||||
.and not_change { project.reload.shared_runners_enabled }
|
||||
context 'top level group' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
|
||||
|
||||
it 'enables allow descendants to override only for itself' do
|
||||
expect { subject_and_reload(group, sub_group, project) }
|
||||
.to change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
|
||||
.and not_change { group.shared_runners_enabled }
|
||||
.and not_change { sub_group.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { sub_group.shared_runners_enabled }
|
||||
.and not_change { project.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
|
||||
context 'group that its ancestors have shared Runners disabled but allows to override' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
|
||||
|
||||
it 'enables allow descendants to override' do
|
||||
expect { subject_and_reload(parent, group, project) }
|
||||
.to not_change { parent.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { parent.shared_runners_enabled }
|
||||
.and change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
|
||||
.and not_change { group.shared_runners_enabled }
|
||||
.and not_change { project.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parent does not allow' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false ) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
|
||||
|
||||
it 'raises error and does not allow descendants to override' do
|
||||
expect { subject_and_reload(parent, group) }
|
||||
.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Allow descendants override disabled shared runners cannot be enabled because parent group does not allow it')
|
||||
.and not_change { parent.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { parent.shared_runners_enabled }
|
||||
.and not_change { group.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { group.shared_runners_enabled }
|
||||
end
|
||||
end
|
||||
|
||||
context 'top level group that has shared Runners enabled' do
|
||||
let_it_be(:group) { create(:group, shared_runners_enabled: true) }
|
||||
let_it_be(:sub_group) { create(:group, shared_runners_enabled: true, parent: group) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: true, group: sub_group) }
|
||||
|
||||
it 'enables allow descendants to override & disables shared runners everywhere' do
|
||||
expect { subject_and_reload(group, sub_group, project) }
|
||||
.to change { group.shared_runners_enabled }.from(true).to(false)
|
||||
.and change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
|
||||
.and change { sub_group.shared_runners_enabled }.from(true).to(false)
|
||||
.and change { project.shared_runners_enabled }.from(true).to(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1320,4 +1320,140 @@ RSpec.describe Namespace do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#shared_runners_setting' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:shared_runners_enabled, :allow_descendants_override_disabled_shared_runners, :shared_runners_setting) do
|
||||
true | true | 'enabled'
|
||||
true | false | 'enabled'
|
||||
false | true | 'disabled_with_override'
|
||||
false | false | 'disabled_and_unoverridable'
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:namespace) { build(:namespace, shared_runners_enabled: shared_runners_enabled, allow_descendants_override_disabled_shared_runners: allow_descendants_override_disabled_shared_runners)}
|
||||
|
||||
it 'returns the result' do
|
||||
expect(namespace.shared_runners_setting).to eq(shared_runners_setting)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#shared_runners_setting_higher_than?' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:shared_runners_enabled, :allow_descendants_override_disabled_shared_runners, :other_setting, :result) do
|
||||
true | true | 'enabled' | false
|
||||
true | true | 'disabled_with_override' | true
|
||||
true | true | 'disabled_and_unoverridable' | true
|
||||
false | true | 'enabled' | false
|
||||
false | true | 'disabled_with_override' | false
|
||||
false | true | 'disabled_and_unoverridable' | true
|
||||
false | false | 'enabled' | false
|
||||
false | false | 'disabled_with_override' | false
|
||||
false | false | 'disabled_and_unoverridable' | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:namespace) { build(:namespace, shared_runners_enabled: shared_runners_enabled, allow_descendants_override_disabled_shared_runners: allow_descendants_override_disabled_shared_runners)}
|
||||
|
||||
it 'returns the result' do
|
||||
expect(namespace.shared_runners_setting_higher_than?(other_setting)).to eq(result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validation #changing_shared_runners_enabled_is_allowed' do
|
||||
context 'without a parent' do
|
||||
let(:namespace) { build(:namespace, shared_runners_enabled: true) }
|
||||
|
||||
it 'is valid' do
|
||||
expect(namespace).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a parent' do
|
||||
context 'when parent has shared runners disabled' do
|
||||
let(:parent) { create(:namespace, :shared_runners_disabled) }
|
||||
let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) }
|
||||
|
||||
it 'is invalid' do
|
||||
expect(sub_namespace).to be_invalid
|
||||
expect(sub_namespace.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group has shared Runners disabled')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parent has shared runners disabled but allows override' do
|
||||
let(:parent) { create(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
|
||||
let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) }
|
||||
|
||||
it 'is valid' do
|
||||
expect(sub_namespace).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parent has shared runners enabled' do
|
||||
let(:parent) { create(:namespace, shared_runners_enabled: true) }
|
||||
let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) }
|
||||
|
||||
it 'is valid' do
|
||||
expect(sub_namespace).to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validation #changing_allow_descendants_override_disabled_shared_runners_is_allowed' do
|
||||
context 'without a parent' do
|
||||
context 'with shared runners disabled' do
|
||||
let(:namespace) { build(:namespace, :allow_descendants_override_disabled_shared_runners, :shared_runners_disabled) }
|
||||
|
||||
it 'is valid' do
|
||||
expect(namespace).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'with shared runners enabled' do
|
||||
let(:namespace) { create(:namespace) }
|
||||
|
||||
it 'is invalid' do
|
||||
namespace.allow_descendants_override_disabled_shared_runners = true
|
||||
|
||||
expect(namespace).to be_invalid
|
||||
expect(namespace.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be changed if shared runners are enabled')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a parent' do
|
||||
context 'when parent does not allow shared runners' do
|
||||
let(:parent) { create(:namespace, :shared_runners_disabled) }
|
||||
let(:sub_namespace) { build(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
|
||||
|
||||
it 'is invalid' do
|
||||
expect(sub_namespace).to be_invalid
|
||||
expect(sub_namespace.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be enabled because parent group does not allow it')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parent allows shared runners and setting to true' do
|
||||
let(:parent) { create(:namespace, shared_runners_enabled: true) }
|
||||
let(:sub_namespace) { build(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
|
||||
|
||||
it 'is valid' do
|
||||
expect(sub_namespace).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parent allows shared runners and setting to false' do
|
||||
let(:parent) { create(:namespace, shared_runners_enabled: true) }
|
||||
let(:sub_namespace) { build(:namespace, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent_id: parent.id) }
|
||||
|
||||
it 'is valid' do
|
||||
expect(sub_namespace).to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5813,6 +5813,38 @@ RSpec.describe Project do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'validation #changing_shared_runners_enabled_is_allowed' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:shared_runners_setting, :project_shared_runners_enabled, :valid_record) do
|
||||
'enabled' | true | true
|
||||
'enabled' | false | true
|
||||
'disabled_with_override' | true | true
|
||||
'disabled_with_override' | false | true
|
||||
'disabled_and_unoverridable' | true | false
|
||||
'disabled_and_unoverridable' | false | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:group) { create(:group) }
|
||||
let(:project) { build(:project, namespace: group, shared_runners_enabled: project_shared_runners_enabled) }
|
||||
|
||||
before do
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:shared_runners_setting).and_return(shared_runners_setting)
|
||||
end
|
||||
end
|
||||
|
||||
it 'validates the configuration' do
|
||||
expect(project.valid?).to eq(valid_record)
|
||||
|
||||
unless valid_record
|
||||
expect(project.errors[:shared_runners_enabled]).to contain_exactly('cannot be enabled because parent group does not allow it')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#mark_pages_as_deployed' do
|
||||
let(:project) { create(:project) }
|
||||
let(:artifacts_archive) { create(:ci_job_artifact, project: project) }
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@ RSpec.describe API::Commits do
|
|||
end
|
||||
|
||||
it 'include correct pagination headers' do
|
||||
get api(route, current_user)
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
end
|
||||
|
||||
it 'includes the total headers when the count is not disabled' do
|
||||
stub_feature_flags(api_commits_without_count: false)
|
||||
commit_count = project.repository.count_commits(ref: 'master').to_s
|
||||
|
||||
get api(route, current_user)
|
||||
|
|
@ -79,12 +86,10 @@ RSpec.describe API::Commits do
|
|||
it 'include correct pagination headers' do
|
||||
commits = project.repository.commits("master", limit: 2)
|
||||
after = commits.second.created_at
|
||||
commit_count = project.repository.count_commits(ref: 'master', after: after).to_s
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user)
|
||||
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response.headers['X-Total']).to eq(commit_count)
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
|
@ -109,12 +114,10 @@ RSpec.describe API::Commits do
|
|||
it 'include correct pagination headers' do
|
||||
commits = project.repository.commits("master", limit: 2)
|
||||
before = commits.second.created_at
|
||||
commit_count = project.repository.count_commits(ref: 'master', before: before).to_s
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user)
|
||||
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response.headers['X-Total']).to eq(commit_count)
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
|
@ -137,49 +140,49 @@ RSpec.describe API::Commits do
|
|||
context "path optional parameter" do
|
||||
it "returns project commits matching provided path parameter" do
|
||||
path = 'files/ruby/popen.rb'
|
||||
commit_count = project.repository.count_commits(ref: 'master', path: path).to_s
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?path=#{path}", user)
|
||||
|
||||
expect(json_response.size).to eq(3)
|
||||
expect(json_response.first["id"]).to eq("570e7b2abdd848b95f2f578043fc23bd6f6fd24d")
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response.headers['X-Total']).to eq(commit_count)
|
||||
expect(response).to include_limited_pagination_headers
|
||||
end
|
||||
|
||||
it 'include correct pagination headers' do
|
||||
path = 'files/ruby/popen.rb'
|
||||
commit_count = project.repository.count_commits(ref: 'master', path: path).to_s
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?path=#{path}", user)
|
||||
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response.headers['X-Total']).to eq(commit_count)
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'all optional parameter' do
|
||||
it 'returns all project commits' do
|
||||
commit_count = project.repository.count_commits(all: true)
|
||||
expected_commit_ids = project.repository.commits(nil, all: true, limit: 50).map(&:id)
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits?all=true", user)
|
||||
get api("/projects/#{project_id}/repository/commits?all=true&per_page=50", user)
|
||||
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response.headers['X-Total']).to eq(commit_count.to_s)
|
||||
commit_ids = json_response.map { |c| c['id'] }
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(commit_ids).to eq(expected_commit_ids)
|
||||
expect(response.headers['X-Page']).to eql('1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'first_parent optional parameter' do
|
||||
it 'returns all first_parent commits' do
|
||||
commit_count = project.repository.count_commits(ref: SeedRepo::Commit::ID, first_parent: true)
|
||||
expected_commit_ids = project.repository.commits(SeedRepo::Commit::ID, limit: 50, first_parent: true).map(&:id)
|
||||
|
||||
get api("/projects/#{project_id}/repository/commits", user), params: { ref_name: SeedRepo::Commit::ID, first_parent: 'true' }
|
||||
get api("/projects/#{project_id}/repository/commits?per_page=50", user), params: { ref_name: SeedRepo::Commit::ID, first_parent: 'true' }
|
||||
|
||||
expect(response).to include_pagination_headers
|
||||
expect(commit_count).to eq(12)
|
||||
expect(response.headers['X-Total']).to eq(commit_count.to_s)
|
||||
commit_ids = json_response.map { |c| c['id'] }
|
||||
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(expected_commit_ids.size).to eq(12)
|
||||
expect(commit_ids).to eq(expected_commit_ids)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -209,11 +212,7 @@ RSpec.describe API::Commits do
|
|||
end
|
||||
|
||||
it 'returns correct headers' do
|
||||
commit_count = project.repository.count_commits(ref: ref_name).to_s
|
||||
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response.headers['X-Total']).to eq(commit_count)
|
||||
expect(response.headers['X-Page']).to eq('1')
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(response.headers['Link']).to match(/page=1&per_page=5/)
|
||||
expect(response.headers['Link']).to match(/page=2&per_page=5/)
|
||||
end
|
||||
|
|
@ -972,7 +971,7 @@ RSpec.describe API::Commits do
|
|||
refs.concat(project.repository.tag_names_contains(commit_id).map {|name| ['tag', name]})
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.map { |r| [r['type'], r['name']] }.compact).to eq(refs)
|
||||
end
|
||||
|
|
@ -1262,7 +1261,7 @@ RSpec.describe API::Commits do
|
|||
get api(route, current_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(json_response.size).to be >= 1
|
||||
expect(json_response.first.keys).to include 'diff'
|
||||
end
|
||||
|
|
@ -1276,7 +1275,7 @@ RSpec.describe API::Commits do
|
|||
get api(route, current_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(json_response.size).to be <= 1
|
||||
end
|
||||
end
|
||||
|
|
@ -1914,7 +1913,7 @@ RSpec.describe API::Commits do
|
|||
get api("/projects/#{project.id}/repository/commits/#{commit.id}/merge_requests", user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to include_pagination_headers
|
||||
expect(response).to include_limited_pagination_headers
|
||||
expect(json_response.length).to eq(1)
|
||||
expect(json_response[0]['id']).to eq(merged_mr.id)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ RSpec.describe RuboCop::Cop::CodeReuse::ActiveRecord, type: :rubocop do
|
|||
SOURCE
|
||||
end
|
||||
|
||||
it 'autocorrects offenses in instance methods by whitelisting them' do
|
||||
it 'autocorrects offenses in instance methods by allowing them' do
|
||||
corrected = autocorrect_source(<<~SOURCE)
|
||||
def foo
|
||||
User.where
|
||||
|
|
@ -100,7 +100,7 @@ RSpec.describe RuboCop::Cop::CodeReuse::ActiveRecord, type: :rubocop do
|
|||
SOURCE
|
||||
end
|
||||
|
||||
it 'autocorrects offenses in class methods by whitelisting them' do
|
||||
it 'autocorrects offenses in class methods by allowing them' do
|
||||
corrected = autocorrect_source(<<~SOURCE)
|
||||
def self.foo
|
||||
User.where
|
||||
|
|
@ -116,7 +116,7 @@ RSpec.describe RuboCop::Cop::CodeReuse::ActiveRecord, type: :rubocop do
|
|||
SOURCE
|
||||
end
|
||||
|
||||
it 'autocorrects offenses in blocks by whitelisting them' do
|
||||
it 'autocorrects offenses in blocks by allowing them' do
|
||||
corrected = autocorrect_source(<<~SOURCE)
|
||||
get '/' do
|
||||
User.where
|
||||
|
|
|
|||
|
|
@ -185,4 +185,44 @@ RSpec.describe Groups::CreateService, '#execute' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'shared runners configuration' do
|
||||
context 'parent group present' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:shared_runners_config, :descendants_override_disabled_shared_runners_config) do
|
||||
true | false
|
||||
false | false
|
||||
# true | true # invalid at the group level, leaving as comment to make explicit
|
||||
false | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
let!(:group) { create(:group, shared_runners_enabled: shared_runners_config, allow_descendants_override_disabled_shared_runners: descendants_override_disabled_shared_runners_config) }
|
||||
let!(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'creates group following the parent config' do
|
||||
new_group = service.execute
|
||||
|
||||
expect(new_group.shared_runners_enabled).to eq(shared_runners_config)
|
||||
expect(new_group.allow_descendants_override_disabled_shared_runners).to eq(descendants_override_disabled_shared_runners_config)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'root group' do
|
||||
let!(:service) { described_class.new(user) }
|
||||
|
||||
it 'follows default config' do
|
||||
new_group = service.execute
|
||||
|
||||
expect(new_group.shared_runners_enabled).to eq(true)
|
||||
expect(new_group.allow_descendants_override_disabled_shared_runners).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -285,6 +285,44 @@ RSpec.describe Groups::TransferService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'shared runners configuration' do
|
||||
before do
|
||||
create(:group_member, :owner, group: new_parent_group, user: user)
|
||||
end
|
||||
|
||||
context 'if parent group has disabled shared runners but allows overrides' do
|
||||
let(:new_parent_group) { create(:group, shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: true) }
|
||||
|
||||
it 'calls update service' do
|
||||
expect(Groups::UpdateSharedRunnersService).to receive(:new).with(group, user, { shared_runners_setting: 'disabled_with_override' }).and_call_original
|
||||
|
||||
transfer_service.execute(new_parent_group)
|
||||
end
|
||||
end
|
||||
|
||||
context 'if parent group does not allow shared runners' do
|
||||
let(:new_parent_group) { create(:group, shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: false) }
|
||||
|
||||
it 'calls update service' do
|
||||
expect(Groups::UpdateSharedRunnersService).to receive(:new).with(group, user, { shared_runners_setting: 'disabled_and_unoverridable' }).and_call_original
|
||||
|
||||
transfer_service.execute(new_parent_group)
|
||||
end
|
||||
end
|
||||
|
||||
context 'if parent group allows shared runners' do
|
||||
let(:group) { create(:group, :public, :nested, shared_runners_enabled: false) }
|
||||
let(:new_parent_group) { create(:group, shared_runners_enabled: true) }
|
||||
|
||||
it 'does not call update service and keeps them disabled on the group' do
|
||||
expect(Groups::UpdateSharedRunnersService).not_to receive(:new)
|
||||
|
||||
transfer_service.execute(new_parent_group)
|
||||
expect(group.reload.shared_runners_enabled).to be_falsy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a group is transferred to its subgroup' do
|
||||
let(:new_parent_group) { create(:group, parent: group) }
|
||||
|
||||
|
|
|
|||
|
|
@ -283,6 +283,31 @@ RSpec.describe Groups::UpdateService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'change shared Runners config' do
|
||||
let(:group) { create(:group) }
|
||||
let(:project) { create(:project, shared_runners_enabled: true, group: group) }
|
||||
|
||||
subject { described_class.new(group, user, shared_runners_setting: 'disabled_and_unoverridable').execute }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'calls the shared runners update service' do
|
||||
expect_any_instance_of(::Groups::UpdateSharedRunnersService).to receive(:execute).and_return({ status: :success })
|
||||
|
||||
expect(subject).to be_truthy
|
||||
end
|
||||
|
||||
it 'handles errors in the shared runners update service' do
|
||||
expect_any_instance_of(::Groups::UpdateSharedRunnersService).to receive(:execute).and_return({ status: :error, message: 'something happened' })
|
||||
|
||||
expect(subject).to be_falsy
|
||||
|
||||
expect(group.errors[:update_shared_runners].first).to eq('something happened')
|
||||
end
|
||||
end
|
||||
|
||||
def update_group(group, user, opts)
|
||||
Groups::UpdateService.new(group, user, opts).execute
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,17 +13,14 @@ RSpec.describe Groups::UpdateSharedRunnersService do
|
|||
context 'when current_user is not the group owner' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
let(:params) { { shared_runners_enabled: '0' } }
|
||||
let(:params) { { shared_runners_setting: 'enabled' } }
|
||||
|
||||
before do
|
||||
group.add_maintainer(user)
|
||||
end
|
||||
|
||||
it 'results error and does not call any method' do
|
||||
expect(group).not_to receive(:enable_shared_runners!)
|
||||
expect(group).not_to receive(:disable_shared_runners!)
|
||||
expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!)
|
||||
expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!)
|
||||
expect(group).not_to receive(:update_shared_runners_setting!)
|
||||
|
||||
expect(subject[:status]).to eq(:error)
|
||||
expect(subject[:message]).to eq('Operation not allowed')
|
||||
|
|
@ -37,191 +34,60 @@ RSpec.describe Groups::UpdateSharedRunnersService do
|
|||
end
|
||||
|
||||
context 'enable shared Runners' do
|
||||
where(:desired_params) do
|
||||
['1', true]
|
||||
end
|
||||
let(:params) { { shared_runners_setting: 'enabled' } }
|
||||
|
||||
with_them do
|
||||
let(:params) { { shared_runners_enabled: desired_params } }
|
||||
context 'group that its ancestors have shared runners disabled' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
|
||||
|
||||
context 'group that its ancestors have shared runners disabled' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
|
||||
|
||||
it 'results error' do
|
||||
expect(subject[:status]).to eq(:error)
|
||||
expect(subject[:message]).to eq('Shared Runners disabled for the parent group')
|
||||
end
|
||||
end
|
||||
|
||||
context 'root group with shared runners disabled' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled) }
|
||||
|
||||
it 'receives correct method and succeeds' do
|
||||
expect(group).to receive(:enable_shared_runners!)
|
||||
expect(group).not_to receive(:disable_shared_runners!)
|
||||
expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!)
|
||||
expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!)
|
||||
|
||||
expect(subject[:status]).to eq(:success)
|
||||
end
|
||||
it 'results error' do
|
||||
expect(subject[:status]).to eq(:error)
|
||||
expect(subject[:message]).to eq('Validation failed: Shared runners enabled cannot be enabled because parent group has shared Runners disabled')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'disable shared Runners' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
where(:desired_params) do
|
||||
['0', false]
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:params) { { shared_runners_enabled: desired_params } }
|
||||
context 'root group with shared runners disabled' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled) }
|
||||
|
||||
it 'receives correct method and succeeds' do
|
||||
expect(group).to receive(:disable_shared_runners!)
|
||||
expect(group).not_to receive(:enable_shared_runners!)
|
||||
expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!)
|
||||
expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!)
|
||||
expect(group).to receive(:update_shared_runners_setting!).with('enabled')
|
||||
|
||||
expect(subject[:status]).to eq(:success)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'disable shared Runners' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let(:params) { { shared_runners_setting: 'disabled_and_unoverridable' } }
|
||||
|
||||
it 'receives correct method and succeeds' do
|
||||
expect(group).to receive(:update_shared_runners_setting!).with('disabled_and_unoverridable')
|
||||
|
||||
expect(subject[:status]).to eq(:success)
|
||||
end
|
||||
end
|
||||
|
||||
context 'allow descendants to override' do
|
||||
where(:desired_params) do
|
||||
['1', true]
|
||||
end
|
||||
let(:params) { { shared_runners_setting: 'disabled_with_override' } }
|
||||
|
||||
with_them do
|
||||
let(:params) { { allow_descendants_override_disabled_shared_runners: desired_params } }
|
||||
|
||||
context 'top level group' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled) }
|
||||
|
||||
it 'receives correct method and succeeds' do
|
||||
expect(group).to receive(:allow_descendants_override_disabled_shared_runners!)
|
||||
expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!)
|
||||
expect(group).not_to receive(:enable_shared_runners!)
|
||||
expect(group).not_to receive(:disable_shared_runners!)
|
||||
|
||||
expect(subject[:status]).to eq(:success)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when parent does not allow' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false ) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
|
||||
|
||||
it 'results error' do
|
||||
expect(subject[:status]).to eq(:error)
|
||||
expect(subject[:message]).to eq('Group level shared Runners not allowed')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'disallow descendants to override' do
|
||||
where(:desired_params) do
|
||||
['0', false]
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:params) { { allow_descendants_override_disabled_shared_runners: desired_params } }
|
||||
|
||||
context 'top level group' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners ) }
|
||||
|
||||
it 'receives correct method and succeeds' do
|
||||
expect(group).to receive(:disallow_descendants_override_disabled_shared_runners!)
|
||||
expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!)
|
||||
expect(group).not_to receive(:enable_shared_runners!)
|
||||
expect(group).not_to receive(:disable_shared_runners!)
|
||||
|
||||
expect(subject[:status]).to eq(:success)
|
||||
end
|
||||
end
|
||||
|
||||
context 'top level group that has shared Runners enabled' do
|
||||
let_it_be(:group) { create(:group, shared_runners_enabled: true) }
|
||||
|
||||
it 'results error' do
|
||||
expect(subject[:status]).to eq(:error)
|
||||
expect(subject[:message]).to eq('Shared Runners enabled')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'both params are present' do
|
||||
context 'shared_runners_enabled: 1 and allow_descendants_override_disabled_shared_runners' do
|
||||
context 'top level group' do
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
|
||||
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
|
||||
|
||||
where(:allow_descendants_override) do
|
||||
['1', true, '0', false]
|
||||
end
|
||||
it 'receives correct method and succeeds' do
|
||||
expect(group).to receive(:update_shared_runners_setting!).with('disabled_with_override')
|
||||
|
||||
with_them do
|
||||
let(:params) { { shared_runners_enabled: '1', allow_descendants_override_disabled_shared_runners: allow_descendants_override } }
|
||||
|
||||
it 'results in an error because shared Runners are enabled' do
|
||||
expect { subject }
|
||||
.to not_change { group.reload.shared_runners_enabled }
|
||||
.and not_change { sub_group.reload.shared_runners_enabled }
|
||||
.and not_change { project.reload.shared_runners_enabled }
|
||||
.and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
expect(subject[:status]).to eq(:error)
|
||||
expect(subject[:message]).to eq('Cannot set shared_runners_enabled to true and allow_descendants_override_disabled_shared_runners')
|
||||
end
|
||||
expect(subject[:status]).to eq(:success)
|
||||
end
|
||||
end
|
||||
|
||||
context 'shared_runners_enabled: 0 and allow_descendants_override_disabled_shared_runners: 0' do
|
||||
let_it_be(:group) { create(:group, :allow_descendants_override_disabled_shared_runners) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent: group) }
|
||||
let_it_be(:sub_group_2) { create(:group, parent: group) }
|
||||
let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) }
|
||||
let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) }
|
||||
context 'when parent does not allow' do
|
||||
let_it_be(:parent) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false ) }
|
||||
let_it_be(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
|
||||
|
||||
let(:params) { { shared_runners_enabled: '0', allow_descendants_override_disabled_shared_runners: '0' } }
|
||||
|
||||
it 'disables shared Runners and disable allow_descendants_override_disabled_shared_runners' do
|
||||
expect { subject }
|
||||
.to change { group.reload.shared_runners_enabled }.from(true).to(false)
|
||||
.and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
|
||||
.and not_change { sub_group.reload.shared_runners_enabled }
|
||||
.and change { sub_group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
|
||||
.and change { sub_group_2.reload.shared_runners_enabled }.from(true).to(false)
|
||||
.and not_change { sub_group_2.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and change { project.reload.shared_runners_enabled }.from(true).to(false)
|
||||
.and change { project_2.reload.shared_runners_enabled }.from(true).to(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'shared_runners_enabled: 0 and allow_descendants_override_disabled_shared_runners: 1' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
|
||||
let_it_be(:sub_group_2) { create(:group, parent: group) }
|
||||
let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) }
|
||||
let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) }
|
||||
|
||||
let(:params) { { shared_runners_enabled: '0', allow_descendants_override_disabled_shared_runners: '1' } }
|
||||
|
||||
it 'disables shared Runners and enable allow_descendants_override_disabled_shared_runners only for itself' do
|
||||
expect { subject }
|
||||
.to change { group.reload.shared_runners_enabled }.from(true).to(false)
|
||||
.and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
|
||||
.and not_change { sub_group.reload.shared_runners_enabled }
|
||||
.and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and change { sub_group_2.reload.shared_runners_enabled }.from(true).to(false)
|
||||
.and not_change { sub_group_2.reload.allow_descendants_override_disabled_shared_runners }
|
||||
.and change { project.reload.shared_runners_enabled }.from(true).to(false)
|
||||
.and change { project_2.reload.shared_runners_enabled }.from(true).to(false)
|
||||
it 'results error' do
|
||||
expect(subject[:status]).to eq(:error)
|
||||
expect(subject[:message]).to eq('Validation failed: Allow descendants override disabled shared runners cannot be enabled because parent group does not allow it')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -782,4 +782,100 @@ RSpec.describe Projects::CreateService, '#execute' do
|
|||
def create_project(user, opts)
|
||||
Projects::CreateService.new(user, opts).execute
|
||||
end
|
||||
|
||||
context 'shared Runners config' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:user) { create :user }
|
||||
|
||||
context 'when parent group is present' do
|
||||
let_it_be(:group) do
|
||||
create(:group) do |group|
|
||||
group.add_owner(user)
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:shared_runners_setting).and_return(shared_runners_setting)
|
||||
end
|
||||
|
||||
user.refresh_authorized_projects # Ensure cache is warm
|
||||
end
|
||||
|
||||
context 'default value based on parent group setting' do
|
||||
where(:shared_runners_setting, :desired_config_for_new_project, :expected_result_for_project) do
|
||||
'enabled' | nil | true
|
||||
'disabled_with_override' | nil | false
|
||||
'disabled_and_unoverridable' | nil | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'creates project following the parent config' do
|
||||
params = opts.merge(namespace_id: group.id)
|
||||
params = params.merge(shared_runners_enabled: desired_config_for_new_project) unless desired_config_for_new_project.nil?
|
||||
project = create_project(user, params)
|
||||
|
||||
expect(project).to be_valid
|
||||
expect(project.shared_runners_enabled).to eq(expected_result_for_project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'parent group is present and allows desired config' do
|
||||
where(:shared_runners_setting, :desired_config_for_new_project, :expected_result_for_project) do
|
||||
'enabled' | true | true
|
||||
'enabled' | false | false
|
||||
'disabled_with_override' | false | false
|
||||
'disabled_with_override' | true | true
|
||||
'disabled_and_unoverridable' | false | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'creates project following the parent config' do
|
||||
params = opts.merge(namespace_id: group.id, shared_runners_enabled: desired_config_for_new_project)
|
||||
project = create_project(user, params)
|
||||
|
||||
expect(project).to be_valid
|
||||
expect(project.shared_runners_enabled).to eq(expected_result_for_project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'parent group is present and disallows desired config' do
|
||||
where(:shared_runners_setting, :desired_config_for_new_project) do
|
||||
'disabled_and_unoverridable' | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'does not create project' do
|
||||
params = opts.merge(namespace_id: group.id, shared_runners_enabled: desired_config_for_new_project)
|
||||
project = create_project(user, params)
|
||||
|
||||
expect(project.persisted?).to eq(false)
|
||||
expect(project).to be_invalid
|
||||
expect(project.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group does not allow it')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'parent group is not present' do
|
||||
where(:desired_config, :expected_result) do
|
||||
true | true
|
||||
false | false
|
||||
nil | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'follows desired config' do
|
||||
opts[:shared_runners_enabled] = desired_config unless desired_config.nil?
|
||||
project = create_project(user, opts)
|
||||
|
||||
expect(project).to be_valid
|
||||
expect(project.shared_runners_enabled).to eq(expected_result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -314,6 +314,37 @@ RSpec.describe Projects::TransferService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'shared Runners group level configurations' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:project_shared_runners_enabled, :shared_runners_setting, :expected_shared_runners_enabled) do
|
||||
true | 'disabled_and_unoverridable' | false
|
||||
false | 'disabled_and_unoverridable' | false
|
||||
true | 'disabled_with_override' | true
|
||||
false | 'disabled_with_override' | false
|
||||
true | 'enabled' | true
|
||||
false | 'enabled' | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:project) { create(:project, :public, :repository, namespace: user.namespace, shared_runners_enabled: project_shared_runners_enabled) }
|
||||
let(:group) { create(:group) }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
expect_next_found_instance_of(Group) do |group|
|
||||
expect(group).to receive(:shared_runners_setting).and_return(shared_runners_setting)
|
||||
end
|
||||
|
||||
execute_transfer
|
||||
end
|
||||
|
||||
it 'updates shared runners based on the parent group' do
|
||||
expect(project.shared_runners_enabled).to eq(expected_shared_runners_enabled)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'missing group labels applied to issues or merge requests' do
|
||||
it 'delegates transfer to Labels::TransferService' do
|
||||
group.add_owner(user)
|
||||
|
|
|
|||
|
|
@ -151,6 +151,32 @@ RSpec.describe Projects::UpdateService do
|
|||
expect(project.reload).to be_internal
|
||||
end
|
||||
end
|
||||
|
||||
context 'when updating shared runners' do
|
||||
context 'can enable shared runners' do
|
||||
let(:group) { create(:group, shared_runners_enabled: true) }
|
||||
let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
|
||||
|
||||
it 'enables shared runners' do
|
||||
result = update_project(project, user, shared_runners_enabled: true)
|
||||
|
||||
expect(result).to eq({ status: :success })
|
||||
expect(project.reload.shared_runners_enabled).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'cannot enable shared runners' do
|
||||
let(:group) { create(:group, :shared_runners_disabled) }
|
||||
let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
|
||||
|
||||
it 'does not enable shared runners' do
|
||||
result = update_project(project, user, shared_runners_enabled: true)
|
||||
|
||||
expect(result).to eq({ status: :error, message: 'Shared runners enabled cannot be enabled because parent group does not allow it' })
|
||||
expect(project.reload.shared_runners_enabled).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when updating project that has forks' do
|
||||
|
|
|
|||
|
|
@ -34,6 +34,26 @@ RSpec.shared_examples 'reviewer_ids filter' do
|
|||
it 'contains reviewers who can read the merge_request' do
|
||||
expect(execute.reviewers).to contain_exactly(reviewer1, reviewer2)
|
||||
end
|
||||
|
||||
context 'with multiple_merge_request_reviewers feature on' do
|
||||
before do
|
||||
stub_licensed_features(multiple_merge_request_reviewers: true)
|
||||
end
|
||||
|
||||
it 'allows multiple reviewers' do
|
||||
expect(execute.reviewers).to contain_exactly(reviewer1, reviewer2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple_merge_request_reviewers feature off' do
|
||||
before do
|
||||
stub_licensed_features(multiple_merge_request_reviewers: false)
|
||||
end
|
||||
|
||||
it 'only allows one reviewer' do
|
||||
expect(execute.reviewers).to contain_exactly(reviewer1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue