Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b092843664
commit
7c1d6f125e
|
|
@ -526,7 +526,6 @@ Gitlab/StrongMemoizeAttr:
|
|||
- 'lib/gitlab/kubernetes/rollout_instances.rb'
|
||||
- 'lib/gitlab/language_data.rb'
|
||||
- 'lib/gitlab/lets_encrypt/client.rb'
|
||||
- 'lib/gitlab/metrics/prometheus.rb'
|
||||
- 'lib/gitlab/prometheus_client.rb'
|
||||
- 'lib/gitlab/rack_attack/request.rb'
|
||||
- 'lib/gitlab/redis/multi_store.rb'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
# Cop supports --autocorrect.
|
||||
Layout/LineContinuationSpacing:
|
||||
Exclude:
|
||||
- 'app/helpers/projects_helper.rb'
|
||||
- 'app/helpers/tags_helper.rb'
|
||||
- 'app/helpers/tree_helper.rb'
|
||||
- 'app/models/concerns/spammable.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
403b947e4d6bcaa170535e7972a536a2ab21b5d4
|
||||
09aa77d55b90fa51939ea12867eb2aaf43c61ee2
|
||||
|
|
|
|||
|
|
@ -213,6 +213,9 @@ export default {
|
|||
filters: this.filterParams,
|
||||
};
|
||||
},
|
||||
showStatusIcon() {
|
||||
return this.listType === 'status' && (!this.isSwimlanesHeader || !this.list.collapsed);
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
// eslint-disable-next-line @gitlab/vue-no-undef-apollo-properties
|
||||
|
|
@ -387,7 +390,7 @@ export default {
|
|||
/>
|
||||
</a>
|
||||
<gl-icon
|
||||
v-if="listType === 'status'"
|
||||
v-if="showStatusIcon"
|
||||
data-testid="status-icon"
|
||||
:name="listStatusIconName"
|
||||
:size="12"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ export default {
|
|||
PageHeading,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
runnersPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onSaved(runner) {
|
||||
saveAlertToLocalStorage({
|
||||
|
|
@ -38,6 +44,7 @@ export default {
|
|||
<runner-create-wizard
|
||||
v-if="glFeatures.runnerCreateWizardAdmin"
|
||||
:runner-type="$options.INSTANCE_TYPE"
|
||||
:runners-path="runnersPath"
|
||||
/>
|
||||
<div v-else>
|
||||
<page-heading :heading="s__('Runners|Create instance runner')">
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ export const initAdminNewRunner = (selector = '#js-admin-new-runner') => {
|
|||
return null;
|
||||
}
|
||||
|
||||
const { runnersPath } = el.dataset;
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(),
|
||||
});
|
||||
|
|
@ -20,7 +22,11 @@ export const initAdminNewRunner = (selector = '#js-admin-new-runner') => {
|
|||
el,
|
||||
apolloProvider,
|
||||
render(h) {
|
||||
return h(AdminNewRunnerApp);
|
||||
return h(AdminNewRunnerApp, {
|
||||
props: {
|
||||
runnersPath,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,12 +17,17 @@ export default {
|
|||
required: true,
|
||||
validator: (t) => RUNNER_TYPES.includes(t),
|
||||
},
|
||||
runnersPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentStep: 1,
|
||||
tags: '',
|
||||
runUntagged: false,
|
||||
newRunnerId: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -36,6 +41,9 @@ export default {
|
|||
this.tags = requiredFields.tags;
|
||||
this.runUntagged = requiredFields.runUntagged;
|
||||
},
|
||||
onGetNewRunnerId(runnerId) {
|
||||
this.newRunnerId = runnerId;
|
||||
},
|
||||
},
|
||||
stepsTotal: 3,
|
||||
};
|
||||
|
|
@ -59,10 +67,13 @@ export default {
|
|||
:runner-type="runnerType"
|
||||
@next="onNext"
|
||||
@back="onBack"
|
||||
@onGetNewRunnerId="onGetNewRunnerId"
|
||||
/>
|
||||
<runner-registration
|
||||
v-else-if="currentStep === 3"
|
||||
:current-step="currentStep"
|
||||
:steps-total="$options.stepsTotal"
|
||||
:runner-id="newRunnerId"
|
||||
:runners-path="runnersPath"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ export default {
|
|||
return;
|
||||
}
|
||||
|
||||
this.$emit('onGetNewRunnerId', runner.id);
|
||||
this.$emit('next');
|
||||
// destroy the alert
|
||||
createAlert({ message: null }).dismiss();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,31 @@
|
|||
<script>
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import {
|
||||
GlFormGroup,
|
||||
GlFormInputGroup,
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
GlAlert,
|
||||
GlLoadingIcon,
|
||||
} from '@gitlab/ui';
|
||||
import { createAlert } from '~/alert';
|
||||
import MultiStepFormTemplate from '~/vue_shared/components/multi_step_form_template.vue';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import { TYPENAME_CI_RUNNER } from '~/graphql_shared/constants';
|
||||
import runnerForRegistrationQuery from '../graphql/register/runner_for_registration.query.graphql';
|
||||
import { I18N_FETCH_ERROR } from '../constants';
|
||||
import { captureException } from '../sentry_utils';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlFormGroup,
|
||||
GlFormInputGroup,
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
GlAlert,
|
||||
GlLoadingIcon,
|
||||
MultiStepFormTemplate,
|
||||
ClipboardButton,
|
||||
},
|
||||
props: {
|
||||
currentStep: {
|
||||
|
|
@ -16,6 +36,50 @@ export default {
|
|||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
runnerId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
runnersPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
runner: null,
|
||||
token: null,
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
runner: {
|
||||
query: runnerForRegistrationQuery,
|
||||
variables() {
|
||||
return {
|
||||
id: convertToGraphQLId(TYPENAME_CI_RUNNER, this.runnerId),
|
||||
};
|
||||
},
|
||||
manual: true,
|
||||
result({ data }) {
|
||||
if (data?.runner) {
|
||||
const { ephemeralAuthenticationToken, ...runner } = data.runner;
|
||||
this.runner = runner;
|
||||
|
||||
// The token is available in the API for a limited amount of time
|
||||
// preserve its original value if it is missing after polling.
|
||||
this.token = ephemeralAuthenticationToken || this.token;
|
||||
}
|
||||
},
|
||||
error(error) {
|
||||
createAlert({ message: I18N_FETCH_ERROR });
|
||||
captureException({ error, component: this.$options.name });
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
loading() {
|
||||
return this.$apollo.queries.runner.loading;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -26,10 +90,79 @@ export default {
|
|||
:steps-total="stepsTotal"
|
||||
>
|
||||
<template #form>
|
||||
<!-- Content will be added in https://gitlab.com/gitlab-org/gitlab/-/issues/396544 -->
|
||||
<template v-if="loading">
|
||||
<div class="gl-text-center gl-text-base" data-testid="loading-icon-wrapper">
|
||||
<gl-loading-icon
|
||||
:label="s__('Runners|Loading')"
|
||||
size="md"
|
||||
variant="spinner"
|
||||
:inline="false"
|
||||
class="gl-mb-2"
|
||||
/>
|
||||
{{ s__('Runners|Loading') }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<gl-form-group
|
||||
v-if="token"
|
||||
:label="s__('Runners|Runner authentication token')"
|
||||
label-for="token"
|
||||
class="gl-mb-7"
|
||||
>
|
||||
<template #description>
|
||||
<gl-sprintf
|
||||
:message="
|
||||
s__(
|
||||
'Runners|The runner authentication token displays here %{boldStart}for a short time only%{boldEnd}. After you register the runner, this token is stored in the %{codeStart}config.toml%{codeEnd} and cannot be accessed again from the UI.',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #bold="{ content }">
|
||||
<b>{{ content }}</b>
|
||||
</template>
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
<gl-form-input-group
|
||||
id="token"
|
||||
readonly
|
||||
:value="token"
|
||||
class="gl-mb-3"
|
||||
data-testid="token-input"
|
||||
>
|
||||
<template #append>
|
||||
<clipboard-button
|
||||
:text="token"
|
||||
:title="__('Copy to clipboard')"
|
||||
data-testid="copy-token-to-clipboard"
|
||||
/>
|
||||
</template>
|
||||
</gl-form-input-group>
|
||||
</gl-form-group>
|
||||
<gl-alert v-else variant="warning" :dismissible="false" class="gl-mb-7">
|
||||
<gl-sprintf
|
||||
:message="
|
||||
s__(
|
||||
'Runners|The %{boldStart}runner authentication token%{boldEnd} is no longer visible, it is stored in the %{codeStart}config.toml%{codeEnd} if you have registered the runner.',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #bold="{ content }">
|
||||
<b>{{ content }}</b>
|
||||
</template>
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</gl-alert>
|
||||
|
||||
<!-- instructions will be added in https://gitlab.com/gitlab-org/gitlab/-/issues/396544 -->
|
||||
</template>
|
||||
</template>
|
||||
<template #back>
|
||||
<gl-button category="primary" variant="default" :disabled="true">
|
||||
<template v-if="!loading" #next>
|
||||
<gl-button category="primary" variant="default" :href="runnersPath">
|
||||
{{ s__('Runners|View runners') }}
|
||||
</gl-button>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@
|
|||
"EpicIssue",
|
||||
"Issue",
|
||||
"MergeRequest",
|
||||
"ProjectComplianceViolation",
|
||||
"Snippet",
|
||||
"Vulnerability",
|
||||
"WikiPage"
|
||||
|
|
|
|||
|
|
@ -33,42 +33,25 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<li class="!gl-mr-0 gl-contents">
|
||||
<ul class="gl-contents gl-list-none">
|
||||
<li v-if="upvotes">
|
||||
<span
|
||||
v-gl-tooltip
|
||||
class="gl-hidden sm:gl-block"
|
||||
:title="__('Upvotes')"
|
||||
data-testid="issuable-upvotes"
|
||||
>
|
||||
<gl-icon name="thumb-up" />
|
||||
{{ upvotes }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="downvotes">
|
||||
<span
|
||||
v-gl-tooltip
|
||||
class="gl-hidden sm:gl-block"
|
||||
:title="__('Downvotes')"
|
||||
data-testid="issuable-downvotes"
|
||||
>
|
||||
<gl-icon name="thumb-down" />
|
||||
{{ downvotes }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="closingMergeRequestsCount">
|
||||
<span
|
||||
v-gl-tooltip
|
||||
class="gl-hidden sm:gl-block"
|
||||
:title="__('Related merge requests')"
|
||||
data-testid="merge-requests"
|
||||
>
|
||||
<gl-icon name="merge-request" />
|
||||
{{ closingMergeRequestsCount }}
|
||||
</span>
|
||||
</li>
|
||||
<slot></slot>
|
||||
</ul>
|
||||
</li>
|
||||
<ul class="gl-contents gl-list-none">
|
||||
<li v-if="upvotes" class="gl-hidden sm:gl-mr-2 sm:gl-inline-block">
|
||||
<span v-gl-tooltip :title="__('Upvotes')" data-testid="issuable-upvotes">
|
||||
<gl-icon name="thumb-up" />
|
||||
{{ upvotes }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="downvotes" class="gl-hidden sm:gl-mr-2 sm:gl-inline-block">
|
||||
<span v-gl-tooltip :title="__('Downvotes')" data-testid="issuable-downvotes">
|
||||
<gl-icon name="thumb-down" />
|
||||
{{ downvotes }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="closingMergeRequestsCount" class="gl-hidden sm:gl-mr-2 sm:gl-inline-block">
|
||||
<span v-gl-tooltip :title="__('Related merge requests')" data-testid="merge-requests">
|
||||
<gl-icon name="merge-request" />
|
||||
{{ closingMergeRequestsCount }}
|
||||
</span>
|
||||
</li>
|
||||
<slot></slot>
|
||||
</ul>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -419,13 +419,13 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-flex gl-items-start gl-gap-3">
|
||||
<div class="gl-w-28">
|
||||
<div class="gl-flex gl-flex-wrap gl-items-start gl-gap-3">
|
||||
<div class="gl-w-full xl:gl-w-28">
|
||||
<gl-collapsible-listbox
|
||||
ref="userSelect"
|
||||
block
|
||||
is-check-centered
|
||||
toggle-class="!gl-w-28"
|
||||
toggle-class="!gl-w-full !xl:gl-w-28"
|
||||
:class="{ 'is-invalid': userSelectInvalid || sourceUser.reassignmentError }"
|
||||
:header-text="s__('UserMapping|Reassign to')"
|
||||
:toggle-text="toggleText"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
import {
|
||||
GlAvatarLabeled,
|
||||
GlBadge,
|
||||
GlIcon,
|
||||
GlKeysetPagination,
|
||||
GlLoadingIcon,
|
||||
GlTable,
|
||||
|
|
@ -34,7 +33,6 @@ export default {
|
|||
components: {
|
||||
GlAvatarLabeled,
|
||||
GlBadge,
|
||||
GlIcon,
|
||||
GlKeysetPagination,
|
||||
GlLoadingIcon,
|
||||
GlTable,
|
||||
|
|
@ -206,7 +204,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<gl-table :items="nodes" :fields="fields" :busy="isLoading" show-empty>
|
||||
<gl-table :items="nodes" :fields="fields" :busy="isLoading" show-empty stacked="md">
|
||||
<template #table-busy>
|
||||
<gl-loading-icon size="lg" class="gl-my-5" />
|
||||
</template>
|
||||
|
|
@ -231,40 +229,35 @@ export default {
|
|||
</template>
|
||||
|
||||
<template #cell(source)="{ item }">
|
||||
<div class="gl-flex gl-gap-1">
|
||||
<gl-icon name="location" />
|
||||
<span>{{ item.sourceHostname }}</span>
|
||||
</div>
|
||||
<div class="gl-mt-2">{{ item.sourceName }}</div>
|
||||
<div class="gl-mt-2 gl-flex gl-gap-1">
|
||||
<span v-if="item.sourceUsername">@{{ item.sourceUsername }}</span>
|
||||
<template v-else>
|
||||
<help-popover
|
||||
:aria-label="s__('UserMapping|Full user details missing')"
|
||||
class="gl-inline-flex"
|
||||
<p class="gl-mb-2">{{ item.sourceHostname }}</p>
|
||||
<p class="gl-mb-2">{{ item.sourceName }}</p>
|
||||
<p v-if="item.sourceUsername" class="gl-mb-2">@{{ item.sourceUsername }}</p>
|
||||
<template v-else>
|
||||
<help-popover
|
||||
:aria-label="s__('UserMapping|Full user details missing')"
|
||||
class="gl-relative gl-top-[-2px]"
|
||||
>
|
||||
<gl-sprintf
|
||||
:message="
|
||||
s__(
|
||||
'UserMapping|Full user details could not be fetched from source instance. %{linkStart}Why are placeholder users created%{linkEnd}?',
|
||||
)
|
||||
"
|
||||
>
|
||||
<gl-sprintf
|
||||
:message="
|
||||
s__(
|
||||
'UserMapping|Full user details could not be fetched from source instance. %{linkStart}Why are placeholder users created%{linkEnd}?',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #link="{ content }">
|
||||
<gl-link
|
||||
class="gl-text-sm"
|
||||
:href="$options.placeholderUsersHelpPath"
|
||||
target="_blank"
|
||||
>{{ content }}</gl-link
|
||||
>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</help-popover>
|
||||
<span class="gl-font-subtle gl-italic"
|
||||
>{{ s__('UserMapping|User ID') }}: {{ item.sourceUserIdentifier }}</span
|
||||
>
|
||||
</template>
|
||||
</div>
|
||||
<template #link="{ content }">
|
||||
<gl-link
|
||||
class="gl-text-sm"
|
||||
:href="$options.placeholderUsersHelpPath"
|
||||
target="_blank"
|
||||
>{{ content }}</gl-link
|
||||
>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</help-popover>
|
||||
<span class="gl-font-subtle gl-italic"
|
||||
>{{ s__('UserMapping|User ID') }}: {{ item.sourceUserIdentifier }}</span
|
||||
>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template #head(createdAt)="{ label }">
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ export function isExpanded(sectionArg) {
|
|||
export function expandSection(sectionArg) {
|
||||
const $section = $(sectionArg);
|
||||
const title = $section.find('.js-settings-toggle-trigger-only').text();
|
||||
const chevron = $section.find('.js-settings-icon');
|
||||
|
||||
$section
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only) .gl-button-text')
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only) .gl-sr-only')
|
||||
.text(__('Collapse'));
|
||||
$section
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)')
|
||||
|
|
@ -32,6 +33,7 @@ export function expandSection(sectionArg) {
|
|||
.addClass('animating')
|
||||
.one('animationend.animateSection', () => $section.removeClass('animating'));
|
||||
}
|
||||
chevron.addClass('gl-animated-icon-on').removeClass('gl-animated-icon-off');
|
||||
|
||||
InternalEvents.trackEvent('click_expand_panel_on_settings', {
|
||||
label: $section.find('[data-settings-block-title]').text(),
|
||||
|
|
@ -41,9 +43,10 @@ export function expandSection(sectionArg) {
|
|||
export function closeSection(sectionArg) {
|
||||
const $section = $(sectionArg);
|
||||
const title = $section.find('.js-settings-toggle-trigger-only').text();
|
||||
const chevron = $section.find('.js-settings-icon');
|
||||
|
||||
$section
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only) .gl-button-text')
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only) .gl-sr-only')
|
||||
.text(__('Expand'));
|
||||
$section
|
||||
.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)')
|
||||
|
|
@ -55,6 +58,7 @@ export function closeSection(sectionArg) {
|
|||
.addClass('animating')
|
||||
.one('animationend.animateSection', () => $section.removeClass('animating'));
|
||||
}
|
||||
chevron.addClass('gl-animated-icon-off').removeClass('gl-animated-icon-on');
|
||||
}
|
||||
|
||||
export function toggleSection($section) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<script>
|
||||
import { GlButton, GlCollapse } from '@gitlab/ui';
|
||||
import { GlButton, GlCollapse, GlAnimatedChevronLgRightDownIcon } from '@gitlab/ui';
|
||||
import { uniqueId } from 'lodash';
|
||||
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
components: { GlButton, GlCollapse },
|
||||
components: { GlButton, GlCollapse, GlAnimatedChevronLgRightDownIcon },
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
|
|
@ -45,6 +45,9 @@ export default {
|
|||
collapseId() {
|
||||
return this.id || uniqueId('settings-block-');
|
||||
},
|
||||
isChevronUp() {
|
||||
return this.expanded;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
expanded(newValue) {
|
||||
|
|
@ -73,16 +76,15 @@ export default {
|
|||
<gl-button
|
||||
category="tertiary"
|
||||
size="small"
|
||||
class="settings-toggle gl-shrink-0 !gl-pl-2 !gl-pr-0"
|
||||
icon="chevron-lg-right"
|
||||
button-text-classes="gl-sr-only"
|
||||
class="settings-toggle gl-shrink-0 !gl-px-0"
|
||||
:aria-label="toggleButtonAriaLabel"
|
||||
:aria-expanded="ariaExpanded"
|
||||
:aria-controls="collapseId"
|
||||
data-testid="settings-block-toggle"
|
||||
@click="toggleExpanded"
|
||||
>
|
||||
{{ toggleButtonText }}
|
||||
<gl-animated-chevron-lg-right-down-icon variant="default" :is-on="isChevronUp" />
|
||||
<div class="gl-sr-only">{{ toggleButtonText }}</div>
|
||||
</gl-button>
|
||||
</div>
|
||||
<div class="gl-grow">
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ export default {
|
|||
:full-path="fullPath"
|
||||
:is-group="isGroup"
|
||||
:selected-labels-ids="addLabelIds"
|
||||
data-testid="bulk-edit-add-labels"
|
||||
@select="addLabelIds = $event"
|
||||
/>
|
||||
<work-item-bulk-edit-labels
|
||||
|
|
@ -229,6 +230,7 @@ export default {
|
|||
:full-path="fullPath"
|
||||
:is-group="isGroup"
|
||||
:selected-labels-ids="removeLabelIds"
|
||||
data-testid="bulk-edit-remove-labels"
|
||||
@select="removeLabelIds = $event"
|
||||
/>
|
||||
<work-item-bulk-edit-dropdown
|
||||
|
|
|
|||
|
|
@ -42,15 +42,6 @@
|
|||
&.animating {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.settings-toggle svg {
|
||||
@include gl-prefers-reduced-motion-transition;
|
||||
@apply gl-transition;
|
||||
}
|
||||
|
||||
&.expanded .settings-toggle svg {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.vue-settings-block {
|
||||
|
|
@ -150,6 +141,7 @@
|
|||
.instance-runners-info {
|
||||
// stylelint-disable-next-line gitlab/no-gl-class
|
||||
.gl-alert-body {
|
||||
// selector-max-compound-selectors
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,12 @@
|
|||
= callout
|
||||
.gl-flex.gl-justify-between.gl-items-start.gl-gap-x-3.gl-pt-5
|
||||
.gl-shrink-0.gl-px-2.gl-py-0.-gl-mr-3.sm:gl-p-2.sm:gl-mr-0
|
||||
= render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'chevron-lg-right', icon_classes: '!-gl-mx-2', button_text_classes: 'gl-sr-only', button_options: @button_options.merge(class: 'settings-toggle js-settings-toggle', 'aria-label': aria_label)) do
|
||||
= button_text
|
||||
= render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, button_options: @button_options.merge(class: 'btn-icon settings-toggle js-settings-toggle', 'aria-label': aria_label)) do
|
||||
.gl-sr-only = button_text
|
||||
= render Pajamas::AnimatedIconComponent.new(icon: :chevron_lg_right_down,
|
||||
variant: :current,
|
||||
is_on: @expanded,
|
||||
icon_options: { class: 'js-settings-icon' })
|
||||
.gl-grow
|
||||
%h2{ class: title_classes, data: { 'settings-block-title': '' } }
|
||||
= heading || @heading
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ module ProjectsHelper
|
|||
.external_authorization_service_default_label
|
||||
|
||||
s_(
|
||||
"ExternalAuthorizationService|When no classification label is set the "\
|
||||
"ExternalAuthorizationService|When no classification label is set the " \
|
||||
"default label `%{default_label}` will be used."
|
||||
) % { default_label: default_label }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -351,6 +351,10 @@ class Note < ApplicationRecord
|
|||
noteable_type == "Vulnerability"
|
||||
end
|
||||
|
||||
def for_compliance_violation?
|
||||
noteable_type == 'ComplianceManagement::Projects::ComplianceViolation'
|
||||
end
|
||||
|
||||
def for_project_snippet?
|
||||
noteable.is_a?(ProjectSnippet)
|
||||
end
|
||||
|
|
@ -485,6 +489,8 @@ class Note < ApplicationRecord
|
|||
'security_resource'
|
||||
elsif for_wiki_page?
|
||||
'wiki_page'
|
||||
elsif for_compliance_violation?
|
||||
'compliance_violations_report'
|
||||
else
|
||||
noteable_type.demodulize.underscore
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module MergeRequests
|
|||
def execute(merge_request)
|
||||
return cannot_create_pipeline_error unless can_create_pipeline_for?(merge_request)
|
||||
|
||||
create_detached_merge_request_pipeline(merge_request)
|
||||
create_merge_request_pipeline(merge_request)
|
||||
end
|
||||
|
||||
def execute_async(merge_request)
|
||||
|
|
@ -21,8 +21,8 @@ module MergeRequests
|
|||
)
|
||||
end
|
||||
|
||||
def create_detached_merge_request_pipeline(merge_request)
|
||||
project, ref = detached_pipeline_project_and_ref(merge_request)
|
||||
def create_merge_request_pipeline(merge_request)
|
||||
project, ref = pipeline_project_and_ref(merge_request)
|
||||
|
||||
Ci::CreatePipelineService.new(project,
|
||||
current_user,
|
||||
|
|
@ -48,7 +48,7 @@ module MergeRequests
|
|||
|
||||
private
|
||||
|
||||
def detached_pipeline_project_and_ref(merge_request)
|
||||
def pipeline_project_and_ref(merge_request)
|
||||
if can_create_pipeline_in_target_project?(merge_request)
|
||||
[merge_request.target_project, merge_request.ref_path]
|
||||
else
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
_('Enable GitLab Prometheus metrics endpoint'),
|
||||
help_text: s_('AdminSettings|Enable collection of application metrics. Restart required. %{link_start}Learn how to export metrics to Prometheus%{link_end}.').html_safe % { link_start: prometheus_help_link_start, link_end: '</a>'.html_safe }
|
||||
.form-text.gl-text-subtle.gl-pl-6
|
||||
- unless Gitlab::Metrics.metrics_folder_present?
|
||||
- unless Gitlab::Metrics.prometheus_metrics_enabled?
|
||||
- icon_link = link_to sprite_icon('question-o'), help_page_path('administration/monitoring/prometheus/gitlab_metrics.md', anchor: 'metrics-shared-directory'), target: '_blank', rel: 'noopener noreferrer'
|
||||
= s_('AdminSettings|%{strongStart}WARNING:%{strongEnd} Environment variable %{environment_variable} does not exist or is not pointing to a valid directory. %{icon_link}').html_safe % { strongStart: '<strong class="gl-text-danger">'.html_safe, strongEnd: '</strong>'.html_safe, environment_variable: '<code>prometheus_multiproc_dir</code>'.html_safe, icon_link: icon_link }
|
||||
.form-group
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
- breadcrumb_title s_('Runners|Create')
|
||||
- page_title s_('Runners|Create an instance runner')
|
||||
|
||||
#js-admin-new-runner
|
||||
#js-admin-new-runner{ data: { runners_path: admin_runners_path } }
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
%li.gl-justify-between{ class: "md:!gl-flex !gl-items-start !gl-px-5", data: { testid: 'tag-row' } }
|
||||
.row-main-content
|
||||
= sprite_icon('tag', css_class: "gl-fill-icon-subtle")
|
||||
= link_to tag.name, project_tag_path(@project, tag.name), class: 'gl-font-bold'
|
||||
%h2.gl-inline.gl-m-0.gl-font-bold.gl-text-size-h2
|
||||
= sprite_icon('tag', css_class: "gl-fill-icon-subtle")
|
||||
= link_to tag.name, project_tag_path(@project, tag.name)
|
||||
|
||||
- if protected_tag?(@project, tag)
|
||||
= gl_badge_tag s_('TagsPage|protected'), variant: :neutral, class: 'gl-ml-2'
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: bitbucket_import_resumable_worker
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/466231
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/156797
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/471309
|
||||
milestone: '17.3'
|
||||
group: group::import and integrate
|
||||
type: beta
|
||||
default_enabled: true
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# This file was prefixed with zz_ because we want to load it the last!
|
||||
# See: https://gitlab.com/gitlab-org/gitlab-foss/issues/55611
|
||||
if Gitlab::Metrics.enabled? && Gitlab::Runtime.application?
|
||||
if Gitlab::Metrics.prometheus_metrics_enabled? && Gitlab::Runtime.application?
|
||||
require 'pathname'
|
||||
require 'connection_pool'
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class AddDefaultUserAddOnAssignmentToUserPreferences < Gitlab::Database::Migration[2.3]
|
||||
disable_ddl_transaction!
|
||||
milestone '18.2'
|
||||
INDEX_NAME = 'add_default_user_assignment_to_user_preferences'
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
add_column :user_preferences, :default_duo_add_on_assignment_id, :bigint, null: true, if_not_exists: true
|
||||
end
|
||||
|
||||
add_concurrent_index :user_preferences, :default_duo_add_on_assignment_id, unique: true, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_column :user_preferences, :default_duo_add_on_assignment_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class AddFkDefaultUserAddOnAssignmentToUserPreferences < Gitlab::Database::Migration[2.3]
|
||||
disable_ddl_transaction!
|
||||
milestone '18.2'
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key :user_preferences, :subscription_user_add_on_assignments,
|
||||
column: :default_duo_add_on_assignment_id, on_delete: :nullify
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists :user_preferences, column: :default_duo_add_on_assignment_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
5be772a7c7dadbeb607eed18fa48e4f8d0a65a143dc529ed9720b713bc57923d
|
||||
|
|
@ -0,0 +1 @@
|
|||
bcfd87720663d2f53b52311657ff2c3b138f183af2991c59d30871109e17e9f4
|
||||
|
|
@ -24932,6 +24932,7 @@ CREATE TABLE user_preferences (
|
|||
extensions_marketplace_opt_in_url text,
|
||||
dark_color_scheme_id smallint,
|
||||
work_items_display_settings jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
default_duo_add_on_assignment_id bigint,
|
||||
CONSTRAINT check_1d670edc68 CHECK ((time_display_relative IS NOT NULL)),
|
||||
CONSTRAINT check_89bf269f41 CHECK ((char_length(diffs_deletion_color) <= 7)),
|
||||
CONSTRAINT check_9b50d9f942 CHECK ((char_length(extensions_marketplace_opt_in_url) <= 512)),
|
||||
|
|
@ -33411,6 +33412,8 @@ CREATE INDEX achievement_uploads_uploaded_by_user_id_idx ON achievement_uploads
|
|||
|
||||
CREATE INDEX achievement_uploads_uploader_path_idx ON achievement_uploads USING btree (uploader, path);
|
||||
|
||||
CREATE UNIQUE INDEX add_default_user_assignment_to_user_preferences ON user_preferences USING btree (default_duo_add_on_assignment_id);
|
||||
|
||||
CREATE INDEX ai_vectorizable_file_uploads_checksum_idx ON ai_vectorizable_file_uploads USING btree (checksum);
|
||||
|
||||
CREATE INDEX ai_vectorizable_file_uploads_model_id_model_type_uploader_c_idx ON ai_vectorizable_file_uploads USING btree (model_id, model_type, uploader, created_at);
|
||||
|
|
@ -43197,6 +43200,9 @@ ALTER TABLE ONLY status_check_responses
|
|||
ALTER TABLE ONLY merge_request_metrics
|
||||
ADD CONSTRAINT fk_56067dcb44 FOREIGN KEY (target_project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY user_preferences
|
||||
ADD CONSTRAINT fk_561e98d37c FOREIGN KEY (default_duo_add_on_assignment_id) REFERENCES subscription_user_add_on_assignments(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY protected_branch_unprotect_access_levels
|
||||
ADD CONSTRAINT fk_5632201009 FOREIGN KEY (protected_branch_namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -465,9 +465,9 @@ The following IPs will be used as an example:
|
|||
To configure Consul:
|
||||
|
||||
1. SSH in to the server that will host Consul.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -575,11 +575,10 @@ The following IPs will be used as an example:
|
|||
- `10.6.0.22`: PostgreSQL secondary 1
|
||||
- `10.6.0.23`: PostgreSQL secondary 2
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package **on each node**. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux GitLab package **on each node**. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
#### PostgreSQL nodes
|
||||
|
||||
|
|
@ -900,9 +899,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the primary Redis Cache node
|
||||
|
||||
1. SSH in to the **Primary** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -973,9 +972,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the replica Redis Cache nodes
|
||||
|
||||
1. SSH in to the **replica** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add same contents as the primary node in the previous section replacing `redis_master_node` with `redis_replica_node`:
|
||||
|
||||
|
|
@ -1065,9 +1064,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the primary Redis Persistent node
|
||||
|
||||
1. SSH in to the **Primary** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -1128,9 +1127,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the replica Redis Persistent nodes
|
||||
|
||||
1. SSH in to the **replica** Redis Persistent server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -1248,11 +1247,10 @@ The following IPs will be used as an example:
|
|||
|
||||
- `10.6.0.141`: Praefect PostgreSQL
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package in the Praefect PostgreSQL node. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux package on the Praefect PostgreSQL node. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
1. SSH in to the Praefect PostgreSQL node.
|
||||
1. Create a strong password to be used for the Praefect PostgreSQL user. Take note of this password as `<praefect_postgresql_password>`.
|
||||
|
|
@ -1419,9 +1417,9 @@ The following IPs will be used as an example:
|
|||
To configure the Praefect nodes, on each one:
|
||||
|
||||
1. SSH in to the Praefect server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux package
|
||||
of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux package
|
||||
of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Edit the `/etc/gitlab/gitlab.rb` file to configure Praefect:
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
|
@ -1580,9 +1578,9 @@ The following IPs will be used as an example:
|
|||
|
||||
On each node:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and do not provide the `EXTERNAL_URL` value.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system, but do **not** provide the `EXTERNAL_URL` value.
|
||||
1. Edit the Gitaly server node's `/etc/gitlab/gitlab.rb` file to configure
|
||||
storage paths, enable the network listener, and to configure the token:
|
||||
|
||||
|
|
@ -1831,9 +1829,9 @@ To configure the Sidekiq nodes, on each one:
|
|||
telnet <GitLab host> 6379 # Redis
|
||||
```
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration:
|
||||
|
||||
```ruby
|
||||
|
|
@ -1982,9 +1980,9 @@ The following IPs will be used as an example:
|
|||
|
||||
On each node perform the following:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and use the following configuration.
|
||||
To maintain uniformity of links across nodes, the `external_url`
|
||||
|
|
@ -2177,9 +2175,9 @@ The following IP will be used as an example:
|
|||
To configure the Monitoring node:
|
||||
|
||||
1. SSH in to the Monitoring node.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
|
|||
|
|
@ -469,9 +469,9 @@ The following IPs will be used as an example:
|
|||
To configure Consul:
|
||||
|
||||
1. SSH in to the server that will host Consul.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to both follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -579,11 +579,10 @@ The following IPs are used as an example:
|
|||
- `10.6.0.22`: PostgreSQL secondary 1
|
||||
- `10.6.0.23`: PostgreSQL secondary 2
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package **on each node**. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux package **on each node**. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
#### PostgreSQL nodes
|
||||
|
||||
|
|
@ -906,9 +905,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the primary Redis Cache node
|
||||
|
||||
1. SSH in to the **Primary** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -978,9 +977,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the replica Redis Cache nodes
|
||||
|
||||
1. SSH in to the **replica** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to both follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the same contents as the primary node in the previous section replacing `redis_master_node` with `redis_replica_node`:
|
||||
|
||||
|
|
@ -1069,9 +1068,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the primary Redis Persistent node
|
||||
|
||||
1. SSH in to the **Primary** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to both follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -1132,9 +1131,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the replica Redis Persistent nodes
|
||||
|
||||
1. SSH in to the **replica** Redis Persistent server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to both follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -1256,11 +1255,10 @@ The following IPs will be used as an example:
|
|||
|
||||
- `10.6.0.141`: Praefect PostgreSQL
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package in the Praefect PostgreSQL node. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux package on the Praefect PostgreSQL node. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
1. SSH in to the Praefect PostgreSQL node.
|
||||
1. Create a strong password to be used for the Praefect PostgreSQL user. Take note of this password as `<praefect_postgresql_password>`.
|
||||
|
|
@ -1427,9 +1425,9 @@ The following IPs will be used as an example:
|
|||
To configure the Praefect nodes, on each one:
|
||||
|
||||
1. SSH in to the Praefect server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux package
|
||||
of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux package
|
||||
of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Edit the `/etc/gitlab/gitlab.rb` file to configure Praefect:
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
|
@ -1588,9 +1586,10 @@ The following IPs will be used as an example:
|
|||
|
||||
On each node:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux package
|
||||
of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and do not provide the `EXTERNAL_URL` value.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux package
|
||||
of your choice. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
1. Edit the Gitaly server node's `/etc/gitlab/gitlab.rb` file to configure
|
||||
storage paths, enable the network listener, and to configure the token:
|
||||
|
||||
|
|
@ -1839,9 +1838,9 @@ To configure the Sidekiq nodes, on each one:
|
|||
telnet <GitLab host> 6379 # Redis
|
||||
```
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration:
|
||||
|
||||
```ruby
|
||||
|
|
@ -1992,9 +1991,9 @@ The following IPs will be used as an example:
|
|||
|
||||
On each node perform the following:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and use the following configuration.
|
||||
To maintain uniformity of links across nodes, the `external_url`
|
||||
|
|
@ -2187,9 +2186,9 @@ The following IP will be used as an example:
|
|||
To configure the Monitoring node:
|
||||
|
||||
1. SSH in to the Monitoring node.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
|
|||
|
|
@ -303,9 +303,9 @@ If you use a third party external service:
|
|||
### Standalone PostgreSQL using the Linux package
|
||||
|
||||
1. SSH in to the PostgreSQL server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Generate a password hash for PostgreSQL. This assumes you will use the default
|
||||
username of `gitlab` (recommended). The command will request a password
|
||||
and confirmation. Use the value that is output by this command in the next
|
||||
|
|
@ -393,9 +393,9 @@ The steps below are the minimum necessary to configure a Redis server with
|
|||
the Linux package:
|
||||
|
||||
1. SSH in to the Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
```ruby
|
||||
|
|
@ -478,9 +478,10 @@ installation has two repository storages: `default` and `storage1`.
|
|||
|
||||
To configure the Gitaly server, on the server node you want to use for Gitaly:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux package
|
||||
of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and do not provide the `EXTERNAL_URL` value.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux package
|
||||
of your choice. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
1. Edit the Gitaly server node's `/etc/gitlab/gitlab.rb` file to configure
|
||||
storage paths, enable the network listener, and to configure the token:
|
||||
|
||||
|
|
@ -669,9 +670,9 @@ To configure the Sidekiq server, on the server node you want to use for Sidekiq:
|
|||
telnet <GitLab host> 6379 # Redis
|
||||
```
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration:
|
||||
|
||||
```ruby
|
||||
|
|
@ -795,9 +796,9 @@ but this is dependent on workload.
|
|||
|
||||
On each node perform the following:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration.
|
||||
To maintain uniformity of links across nodes, the `external_url`
|
||||
on the application server should point to the external URL that users will use
|
||||
|
|
@ -970,9 +971,9 @@ The Linux package can be used to configure a standalone Monitoring node
|
|||
running [Prometheus](../monitoring/prometheus/_index.md):
|
||||
|
||||
1. SSH in to the Monitoring node.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
```ruby
|
||||
|
|
|
|||
|
|
@ -452,9 +452,9 @@ The following IPs will be used as an example:
|
|||
To configure Consul:
|
||||
|
||||
1. SSH in to the server that will host Consul.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -562,11 +562,10 @@ The following IPs are used as an example:
|
|||
- `10.6.0.22`: PostgreSQL secondary 1
|
||||
- `10.6.0.23`: PostgreSQL secondary 2
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package **on each node**. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux GitLab package **on each node**. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
#### PostgreSQL nodes
|
||||
|
||||
|
|
@ -901,9 +900,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the primary Redis node
|
||||
|
||||
1. SSH in to the **Primary** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -964,9 +963,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the replica Redis nodes
|
||||
|
||||
1. SSH in to the **replica** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -1084,11 +1083,10 @@ The following IPs will be used as an example:
|
|||
|
||||
- `10.6.0.141`: Praefect PostgreSQL
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package in the Praefect PostgreSQL node. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux package on the Praefect PostgreSQL node. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
1. SSH in to the Praefect PostgreSQL node.
|
||||
1. Create a strong password to be used for the Praefect PostgreSQL user. Take note of this password as `<praefect_postgresql_password>`.
|
||||
|
|
@ -1253,9 +1251,9 @@ The following IPs will be used as an example:
|
|||
To configure the Praefect nodes, on each one:
|
||||
|
||||
1. SSH in to the Praefect server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Edit the `/etc/gitlab/gitlab.rb` file to configure Praefect:
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
|
@ -1414,9 +1412,10 @@ The following IPs will be used as an example:
|
|||
|
||||
On each node:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux package
|
||||
of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and do not provide the `EXTERNAL_URL` value.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux package
|
||||
of your choice. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
1. Edit the Gitaly server node's `/etc/gitlab/gitlab.rb` file to configure
|
||||
storage paths, enable the network listener, and to configure the token:
|
||||
|
||||
|
|
@ -1669,9 +1668,9 @@ To configure the Sidekiq nodes, on each one:
|
|||
telnet <GitLab host> 6379 # Redis
|
||||
```
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration:
|
||||
|
||||
```ruby
|
||||
|
|
@ -1822,9 +1821,9 @@ examples include the Object storage configuration.
|
|||
|
||||
On each node perform the following:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration.
|
||||
To maintain uniformity of links across nodes, the `external_url`
|
||||
on the application server should point to the external URL that users will use
|
||||
|
|
@ -2035,9 +2034,9 @@ The Linux package can be used to configure a standalone Monitoring node
|
|||
running [Prometheus](../monitoring/prometheus/_index.md):
|
||||
|
||||
1. SSH in to the Monitoring node.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
```ruby
|
||||
|
|
|
|||
|
|
@ -473,9 +473,9 @@ The following IPs will be used as an example:
|
|||
To configure Consul:
|
||||
|
||||
1. SSH in to the server that will host Consul.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -583,11 +583,10 @@ The following IPs will be used as an example:
|
|||
- `10.6.0.22`: PostgreSQL secondary 1
|
||||
- `10.6.0.23`: PostgreSQL secondary 2
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package **on each node**. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux package **on each node**. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
#### PostgreSQL nodes
|
||||
|
||||
|
|
@ -912,9 +911,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the primary Redis Cache node
|
||||
|
||||
1. SSH in to the **Primary** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to both follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -985,9 +984,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the replica Redis Cache nodes
|
||||
|
||||
1. SSH in to the **replica** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to both follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the same contents as the primary node in the previous section by replacing `redis_master_node` with `redis_replica_node`:
|
||||
|
||||
|
|
@ -1080,9 +1079,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the primary Redis Persistent node
|
||||
|
||||
1. SSH in to the **Primary** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to both follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -1143,9 +1142,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the replica Redis Persistent nodes
|
||||
|
||||
1. SSH in to the **replica** Redis Persistent server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to both follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -1263,11 +1262,10 @@ The following IPs will be used as an example:
|
|||
|
||||
- `10.6.0.141`: Praefect PostgreSQL
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package in the Praefect PostgreSQL node. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux package on the Praefect PostgreSQL node. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
1. SSH in to the Praefect PostgreSQL node.
|
||||
1. Create a strong password to be used for the Praefect PostgreSQL user. Take note of this password as `<praefect_postgresql_password>`.
|
||||
|
|
@ -1432,9 +1430,9 @@ The following IPs will be used as an example:
|
|||
To configure the Praefect nodes, on each one:
|
||||
|
||||
1. SSH in to the Praefect server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Edit the `/etc/gitlab/gitlab.rb` file to configure Praefect:
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
|
@ -1593,9 +1591,10 @@ The following IPs will be used as an example:
|
|||
|
||||
On each node:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and do not provide the `EXTERNAL_URL` value.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
1. Edit the Gitaly server node's `/etc/gitlab/gitlab.rb` file to configure
|
||||
storage paths, enable the network listener, and to configure the token:
|
||||
|
||||
|
|
@ -1845,9 +1844,9 @@ To configure the Sidekiq nodes, on each one:
|
|||
telnet <GitLab host> 6379 # Redis
|
||||
```
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration:
|
||||
|
||||
```ruby
|
||||
|
|
@ -2008,9 +2007,9 @@ The following IPs will be used as an example:
|
|||
|
||||
On each node perform the following:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and use the following configuration.
|
||||
To maintain uniformity of links across nodes, the `external_url`
|
||||
|
|
@ -2200,9 +2199,9 @@ The following IP will be used as an example:
|
|||
To configure the Monitoring node:
|
||||
|
||||
1. SSH in to the Monitoring node.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
|
|||
|
|
@ -455,9 +455,9 @@ The following IPs will be used as an example:
|
|||
To configure Consul:
|
||||
|
||||
1. SSH in to the server that will host Consul.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -565,11 +565,10 @@ The following IPs are used as an example:
|
|||
- `10.6.0.22`: PostgreSQL secondary 1
|
||||
- `10.6.0.23`: PostgreSQL secondary 2
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package **on each node**. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux package **on each node**. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
#### PostgreSQL nodes
|
||||
|
||||
|
|
@ -904,9 +903,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the primary Redis node
|
||||
|
||||
1. SSH in to the **Primary** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -967,9 +966,9 @@ a node and change its status from primary to replica (and vice versa).
|
|||
#### Configure the replica Redis nodes
|
||||
|
||||
1. SSH in to the **replica** Redis server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and to select the correct Linux package, with the same version
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system. Select the same version
|
||||
and type (Community or Enterprise editions) as your current install.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
|
|
@ -1087,11 +1086,10 @@ The following IPs are used as an example:
|
|||
|
||||
- `10.6.0.141`: Praefect PostgreSQL
|
||||
|
||||
First, make sure to [install](https://about.gitlab.com/install/)
|
||||
the Linux GitLab package in the Praefect PostgreSQL node. Following the steps,
|
||||
install the necessary dependencies from step 1, and add the
|
||||
GitLab package repository from step 2. When installing GitLab
|
||||
in the second step, do not supply the `EXTERNAL_URL` value.
|
||||
First, make sure to [install](../../install/package/_index.md#supported-platforms)
|
||||
the Linux package on the Praefect PostgreSQL node. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
|
||||
1. SSH in to the Praefect PostgreSQL node.
|
||||
1. Create a strong password to be used for the Praefect PostgreSQL user. Take note of this password as `<praefect_postgresql_password>`.
|
||||
|
|
@ -1258,9 +1256,9 @@ The following IPs are used as an example:
|
|||
To configure the Praefect nodes, on each one:
|
||||
|
||||
1. SSH in to the Praefect server.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Edit the `/etc/gitlab/gitlab.rb` file to configure Praefect:
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
|
@ -1419,9 +1417,10 @@ The following IPs are used as an example:
|
|||
|
||||
On each node:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page, and do not provide the `EXTERNAL_URL` value.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab
|
||||
package repository and install GitLab for your chosen operating system,
|
||||
but do **not** provide the `EXTERNAL_URL` value.
|
||||
1. Edit the Gitaly server node's `/etc/gitlab/gitlab.rb` file to configure
|
||||
storage paths, enable the network listener, and to configure the token:
|
||||
|
||||
|
|
@ -1669,9 +1668,9 @@ To configure the Sidekiq nodes, on each one:
|
|||
telnet <GitLab host> 6379 # Redis
|
||||
```
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux package
|
||||
of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux package
|
||||
of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration:
|
||||
|
||||
```ruby
|
||||
|
|
@ -1823,9 +1822,9 @@ examples include the Object storage configuration.
|
|||
|
||||
On each node perform the following:
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration.
|
||||
To maintain uniformity of links across nodes, the `external_url`
|
||||
on the application server should point to the external URL that users use
|
||||
|
|
@ -2039,9 +2038,9 @@ The Linux package can be used to configure a standalone Monitoring node
|
|||
running [Prometheus](../monitoring/prometheus/_index.md):
|
||||
|
||||
1. SSH in to the Monitoring node.
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Linux
|
||||
package of your choice. Be sure to follow only installation steps 1 and 2
|
||||
on the page.
|
||||
1. [Download and install](../../install/package/_index.md#supported-platforms) the Linux
|
||||
package of your choice. Be sure to only add the GitLab package repository and install GitLab
|
||||
for your chosen operating system.
|
||||
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
|
||||
|
||||
```ruby
|
||||
|
|
|
|||
|
|
@ -38949,12 +38949,32 @@ Compliance violation for a project.
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="projectcomplianceviolationauditevent"></a>`auditEvent` | [`AuditEvent!`](#auditevent) | Audit event related to the violation. |
|
||||
| <a id="projectcomplianceviolationcommenters"></a>`commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) |
|
||||
| <a id="projectcomplianceviolationcompliancecontrol"></a>`complianceControl` | [`ComplianceRequirementsControl!`](#compliancerequirementscontrol) | Compliance control of the violation. |
|
||||
| <a id="projectcomplianceviolationcreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp when the violation was detected. |
|
||||
| <a id="projectcomplianceviolationdiscussions"></a>`discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) |
|
||||
| <a id="projectcomplianceviolationid"></a>`id` | [`ID!`](#id) | Compliance violation ID. |
|
||||
| <a id="projectcomplianceviolationproject"></a>`project` | [`Project!`](#project) | Project of the compliance violation. |
|
||||
| <a id="projectcomplianceviolationstatus"></a>`status` | [`ComplianceViolationStatus!`](#complianceviolationstatus) | Compliance violation status of the project. |
|
||||
|
||||
#### Fields with arguments
|
||||
|
||||
##### `ProjectComplianceViolation.notes`
|
||||
|
||||
All notes on this noteable.
|
||||
|
||||
Returns [`NoteConnection!`](#noteconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, and `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="projectcomplianceviolationnotesfilter"></a>`filter` | [`NotesFilterType`](#notesfiltertype) | Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY. |
|
||||
|
||||
### `ProjectDataTransfer`
|
||||
|
||||
#### Fields
|
||||
|
|
@ -50262,6 +50282,7 @@ Implementations:
|
|||
- [`EpicIssue`](#epicissue)
|
||||
- [`Issue`](#issue)
|
||||
- [`MergeRequest`](#mergerequest)
|
||||
- [`ProjectComplianceViolation`](#projectcomplianceviolation)
|
||||
- [`Snippet`](#snippet)
|
||||
- [`Vulnerability`](#vulnerability)
|
||||
- [`WikiPage`](#wikipage)
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ curl --request GET \
|
|||
|
||||
## Get details on a group access token
|
||||
|
||||
Gets details on a group access token. You can reference a specific group access token, or use the keyword `self` to return details on the authenticating group access token.
|
||||
Gets details on a group access token.
|
||||
|
||||
```plaintext
|
||||
GET /groups/:id/access_tokens/:token_id
|
||||
|
|
@ -95,7 +95,7 @@ GET /groups/:id/access_tokens/:token_id
|
|||
| Attribute | Type | required | Description |
|
||||
| ---------- | ----------------- | -------- | ----------- |
|
||||
| `id` | integer or string | yes | ID or [URL-encoded path](rest/_index.md#namespaced-paths) of a group. |
|
||||
| `token_id` | integer or string | yes | ID of a group access token or the keyword `self`. |
|
||||
| `token_id` | integer or string | yes | ID |
|
||||
|
||||
```shell
|
||||
curl --request GET \
|
||||
|
|
|
|||
|
|
@ -2133,7 +2133,6 @@ Example response:
|
|||
]
|
||||
```
|
||||
|
||||
<!--
|
||||
### Credentials inventory management
|
||||
|
||||
{{< details >}}
|
||||
|
|
@ -2464,4 +2463,3 @@ Other possible responses:
|
|||
- You do not have access to the specified token.
|
||||
- `403: Forbidden` if the token is not allowed to rotate itself or token is not a bot user token.
|
||||
- `404: Not Found` if the user is a group owner but the token does not exist.
|
||||
-->
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ curl --request GET \
|
|||
|
||||
## Get details on a project access token
|
||||
|
||||
Gets details on a project access token. You can either reference a specific project access token, or use the keyword `self` to return details on the authenticating project access token.
|
||||
Gets details on a project access token.
|
||||
|
||||
```plaintext
|
||||
GET projects/:id/access_tokens/:token_id
|
||||
|
|
@ -95,7 +95,7 @@ GET projects/:id/access_tokens/:token_id
|
|||
| Attribute | Type | required | Description |
|
||||
| ---------- | ----------------- | -------- | ----------- |
|
||||
| `id` | integer or string | yes | ID or [URL-encoded path](rest/_index.md#namespaced-paths) of a project. |
|
||||
| `token_id` | integer or string | yes | ID of a project access token or the keyword `self`. |
|
||||
| `token_id` | integer or string | yes | ID |
|
||||
|
||||
```shell
|
||||
curl --request GET \
|
||||
|
|
|
|||
|
|
@ -360,6 +360,33 @@ job:
|
|||
- .yarn-cache/
|
||||
```
|
||||
|
||||
### Cache C/C++ compilation using Ccache
|
||||
|
||||
If you are compiling C/C++ projects, you can use [Ccache](https://ccache.dev/) to
|
||||
speed up your build times. Ccache speeds up recompilation by caching previous compilations
|
||||
and detecting when the same compilation is being done again. When building big projects like the Linux kernel,
|
||||
you can expect significantly faster compilations.
|
||||
|
||||
Use `cache` to reuse the created cache between jobs, for example:
|
||||
|
||||
```yaml
|
||||
job:
|
||||
cache:
|
||||
paths:
|
||||
- ccache
|
||||
before_script:
|
||||
- export PATH="/usr/lib/ccache:$PATH" # Override compiler path with ccache (this example is for Debian)
|
||||
- export CCACHE_DIR="${CI_PROJECT_DIR}/ccache"
|
||||
- export CCACHE_BASEDIR="${CI_PROJECT_DIR}"
|
||||
- export CCACHE_COMPILERCHECK=content # Compiler mtime might change in the container, use checksums instead
|
||||
script:
|
||||
- ccache --zero-stats || true
|
||||
- time make # Actually build your code while measuring time and cache efficiency.
|
||||
- ccache --show-stats || true
|
||||
```
|
||||
|
||||
If you have multiple projects in a single repository you do not need a separate `CCACHE_BASEDIR` for each of them.
|
||||
|
||||
### Cache PHP dependencies
|
||||
|
||||
If your project uses [Composer](https://getcomposer.org/) to install
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ Predefined variables become available at three different phases of pipeline exec
|
|||
| `CI_PIPELINE_SOURCE` | Pre-pipeline | How the pipeline was triggered. The value can be one of the [pipeline sources](../jobs/job_rules.md#ci_pipeline_source-predefined-variable). |
|
||||
| `CI_PIPELINE_TRIGGERED` | Pipeline | `true` if the job was [triggered](../triggers/_index.md). |
|
||||
| `CI_PIPELINE_URL` | Job-only | The URL for the pipeline details. |
|
||||
| `CI_PIPELINE_CREATED_AT` | Pre-pipeline | The date and time when the pipeline was created, in [ISO 8601](https://www.rfc-editor.org/rfc/rfc3339#appendix-A) format. For example, `2022-01-31T16:47:55Z`. [UTC by default](../../administration/timezone.md). |
|
||||
| `CI_PIPELINE_CREATED_AT` | Job-only | The date and time when the pipeline was created, in [ISO 8601](https://www.rfc-editor.org/rfc/rfc3339#appendix-A) format. For example, `2022-01-31T16:47:55Z`. [UTC by default](../../administration/timezone.md). |
|
||||
| `CI_PIPELINE_NAME` | Pre-pipeline | The pipeline name defined in [`workflow:name`](../yaml/_index.md#workflowname). Introduced in GitLab 16.3. |
|
||||
| `CI_PIPELINE_SCHEDULE_DESCRIPTION` | Pre-pipeline | The description of the pipeline schedule. Only available in scheduled pipelines. Introduced in GitLab 17.8. |
|
||||
| `CI_PROJECT_DIR` | Job-only | The full path the repository is cloned to, and where the job runs from. If the GitLab Runner `builds_dir` parameter is set, this variable is set relative to the value of `builds_dir`. For more information, see the [Advanced GitLab Runner configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section). |
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ Job-level persisted variables:
|
|||
- `CI_JOB_STARTED_AT`
|
||||
- `CI_JOB_TOKEN`
|
||||
- `CI_JOB_URL`
|
||||
- `CI_PIPELINE_CREATED_AT`
|
||||
- `CI_REGISTRY_PASSWORD`
|
||||
- `CI_REGISTRY_USER`
|
||||
- `CI_REPOSITORY_URL`
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ Each event is defined in a separate YAML file consisting of the following fields
|
|||
| `action` | yes | A unique name for the event. Only lowercase, numbers, and underscores are allowed. Use the format `<operation>_<target_of_operation>_<where/when>`. <br/><br/> For example: `publish_go_module_to_the_registry_from_pipeline` <br/>`<operation> = publish`<br/>`<target> = go_module`<br/>`<when/where> = to_the_registry_from_pipeline`. |
|
||||
| `identifiers` | no | A list of identifiers sent with the event. Can be set to one or more of `project`, `user`, `namespace` or `feature_enabled_by_namespace_ids` |
|
||||
| `product_group` | yes | The [group](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) that owns the event. |
|
||||
| `product_categories`| false | A list of the [feature categories](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/feature_categories.yml) that the event represents usage of. Some events may correspond to multiple categories or no category. |
|
||||
|
||||
| `milestone` | no | The milestone when the event is introduced. |
|
||||
| `status` | no | The status of the event. Can be set to one of `active`, `removed`, or `null`. |
|
||||
| `milestone_removed` | no | The milestone when the event is removed. |
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ Each metric is defined in a YAML file consisting of a number of fields:
|
|||
| `key_path` | yes | JSON key path for the metric, location in Service Ping payload. |
|
||||
| `description` | yes | |
|
||||
| `product_group` | yes | The [group](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) that owns the metric. |
|
||||
| `product_categories` | no | `array`; The [feature categories](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/feature_categories.yml) that the metric represents usage of. Some metrics may correspond to multiple categories or no category. |
|
||||
| `value_type` | yes | `string`; one of [`string`, `number`, `boolean`, `object`](https://json-schema.org/understanding-json-schema/reference/type). |
|
||||
| `status` | yes | `string`; [status](#metric-statuses) of the metric, may be set to `active`, `removed`, `broken`. |
|
||||
| `time_frame` | yes | `string` or `array`; may be set to `7d`, `28d`, `all`, `none` or an array including any of these values except for `none`. |
|
||||
|
|
@ -49,8 +50,7 @@ Each metric is defined in a YAML file consisting of a number of fields:
|
|||
| `data_category` | yes | `string`; [categories](#data-category) of the metric, may be set to `operational`, `optional`, `subscription`, `standard`. The default value is `optional`. |
|
||||
| `instrumentation_class` | no | `string`; used for metrics with `data_source` other than `internal_events`. See [the class that implements the metric](metrics_instrumentation.md). |
|
||||
| `performance_indicator_type` | no | `array`; may be set to one of [`gmau`, `smau`, `paid_gmau`, `umau`, `customer_health_score`, `devops_report`, `lighthouse`, or `leading_indicator`](https://handbook.gitlab.com/handbook/business-technology/data-team/data-catalog/). |
|
||||
| `tier` | yes | `array`; may contain one or a combination of `free`, `premium` or `ultimate`. The [tier](https://handbook.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/tiers/#definitions) where the tracked feature is available. This should be verbose and contain all tiers where a metric is available. |
|
||||
| `tiers` | no | `array`; may contain one or a combination of `free`, `premium` or `ultimate`. The [tiers](https://handbook.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/tiers/#definitions) where the tracked feature is available. This should be verbose and contain all tiers where a metric is available. |
|
||||
| `tiers` | yes | `array`; may contain one or a combination of `free`, `premium` or `ultimate`. The [tiers](https://handbook.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/tiers/#definitions) where the tracked feature is available. This should be verbose and contain all tiers where a metric is available. |
|
||||
| `milestone` | yes | The milestone when the metric is introduced and when it's available to GitLab Self-Managed instances with the official GitLab release. |
|
||||
| `milestone_removed` | no | The milestone when the metric is removed. Required for removed metrics. |
|
||||
| `introduced_by_url` | yes | The URL to the merge request that introduced the metric to be available for GitLab Self-Managed instances. |
|
||||
|
|
|
|||
|
|
@ -64,6 +64,15 @@ Validity checks supports the following secret types:
|
|||
|
||||
- GitLab personal access tokens
|
||||
- Routable GitLab personal access tokens
|
||||
- GitLab deploy tokens
|
||||
- GitLab Runner authentication tokens
|
||||
- Routable GitLab Runner authentication tokens
|
||||
- GitLab Kubernetes agent tokens
|
||||
- GitLab SCIM OAuth tokens
|
||||
- GitLab CI/CD job tokens
|
||||
- GitLab incoming email tokens
|
||||
- GitLab feed tokens (v2)
|
||||
- GitLab pipeline trigger tokens
|
||||
|
||||
## Secret status
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ Replace the placeholders in the URL with your specific values:
|
|||
- `:id`: Your project ID or URL-encoded path
|
||||
- `:package_name`: Name of your package
|
||||
- `:package_version`: Version of your package
|
||||
- `:file_name`: Name of the file you're uploading
|
||||
- `:file_name`: Name of the file you're uploading. See [valid package filename format](#valid-package-filename-format) below.
|
||||
|
||||
For example:
|
||||
|
||||
|
|
@ -529,6 +529,20 @@ The [Write CI-CD Variables in Pipeline](https://gitlab.com/guided-explorations/c
|
|||
|
||||
It also demonstrates how to manage a semantic version for the generic package: storing it in a CI/CD variable, retrieving it, incrementing it, and writing it back to the CI/CD variable when tests for the download work correctly.
|
||||
|
||||
## Valid package filename format
|
||||
|
||||
Valid package filenames can include:
|
||||
|
||||
- Letters: A-Z, a-z
|
||||
- Numbers: 0-9
|
||||
- Special characters: . (dot), _ (underscore), - (hyphen), + (plus), ~ (tilde), @ (at sign), / (forward slash)
|
||||
|
||||
The package filename cannot:
|
||||
|
||||
- Start with a tilde (~) or the at sign (@)
|
||||
- End with a tilde (~) or the at sign (@)
|
||||
- Include spaces
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### HTTP 403 errors
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ module API
|
|||
content_type :binary, 'application/octet-stream'
|
||||
content_type :yaml, 'text/yaml'
|
||||
|
||||
formatter :yaml, ->(object, _) { object.serializable_hash.stringify_keys.to_yaml }
|
||||
formatter :yaml, ->(object, _) do
|
||||
yaml_content = object.serializable_hash.stringify_keys.to_yaml
|
||||
|
||||
yaml_content.gsub(Gitlab::Regex.helm_index_app_version_quote_regex, '\1"\2"')
|
||||
end
|
||||
|
||||
authenticate_with do |accept|
|
||||
accept.token_types(:personal_access_token, :deploy_token, :job_token)
|
||||
|
|
@ -50,12 +54,13 @@ module API
|
|||
end
|
||||
|
||||
get ":channel/index.yaml" do
|
||||
env['api.format'] = :yaml
|
||||
|
||||
project = authorized_user_project(action: :read_package)
|
||||
authorize_read_package!(project)
|
||||
|
||||
packages = Packages::Helm::PackagesFinder.new(project, params[:channel]).execute
|
||||
|
||||
env['api.format'] = :yaml
|
||||
present ::Packages::Helm::IndexPresenter.new(params[:id], params[:channel], packages),
|
||||
with: ::API::Entities::Helm::Index
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,19 +11,6 @@ module Gitlab
|
|||
|
||||
log_info(import_stage: 'import_issues', message: 'importing issues')
|
||||
|
||||
bitbucket_import_resumable_worker =
|
||||
project.import_data&.data&.dig('bitbucket_import_resumable_worker')
|
||||
|
||||
if bitbucket_import_resumable_worker
|
||||
resumable_execute
|
||||
else
|
||||
non_resumable_execute
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def resumable_execute
|
||||
labels = build_labels_hash
|
||||
|
||||
is_first = true
|
||||
|
|
@ -42,31 +29,7 @@ module Gitlab
|
|||
job_waiter
|
||||
end
|
||||
|
||||
def non_resumable_execute
|
||||
issues = client.issues(project.import_source)
|
||||
|
||||
labels = build_labels_hash
|
||||
|
||||
issues.each_with_index do |issue, index|
|
||||
job_waiter.jobs_remaining += 1
|
||||
|
||||
next if already_enqueued?(issue)
|
||||
|
||||
allocate_issues_internal_id! if index == 0
|
||||
|
||||
job_delay = calculate_job_delay(job_waiter.jobs_remaining)
|
||||
|
||||
issue_hash = issue.to_hash.merge({ issue_type_id: default_issue_type_id, label_id: labels[issue.kind] })
|
||||
sidekiq_worker_class.perform_in(job_delay, project.id, issue_hash, job_waiter.key)
|
||||
|
||||
mark_as_enqueued(issue)
|
||||
end
|
||||
|
||||
job_waiter
|
||||
rescue StandardError => e
|
||||
track_import_failure!(project, exception: e)
|
||||
job_waiter
|
||||
end
|
||||
private
|
||||
|
||||
def sidekiq_worker_class
|
||||
ImportIssueWorker
|
||||
|
|
@ -85,13 +48,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def id_for_already_enqueued_cache(object)
|
||||
if object.is_a?(Hash)
|
||||
# used for `resumable_execute`
|
||||
object[:iid]
|
||||
else
|
||||
# used for `non_resumable_execute`
|
||||
object.iid
|
||||
end
|
||||
object[:iid]
|
||||
end
|
||||
|
||||
def default_issue_type_id
|
||||
|
|
|
|||
|
|
@ -7,19 +7,6 @@ module Gitlab
|
|||
include ParallelScheduling
|
||||
|
||||
def execute
|
||||
bitbucket_import_resumable_worker =
|
||||
project.import_data&.data&.dig('bitbucket_import_resumable_worker')
|
||||
|
||||
if bitbucket_import_resumable_worker
|
||||
resumable_execute
|
||||
else
|
||||
non_resumable_execute
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def resumable_execute
|
||||
log_info(import_stage: 'import_pull_requests', message: 'importing pull requests')
|
||||
|
||||
each_object_to_import do |object|
|
||||
|
|
@ -31,28 +18,7 @@ module Gitlab
|
|||
job_waiter
|
||||
end
|
||||
|
||||
def non_resumable_execute
|
||||
log_info(import_stage: 'import_pull_requests', message: 'importing pull requests')
|
||||
|
||||
pull_requests = client.pull_requests(project.import_source)
|
||||
|
||||
pull_requests.each do |pull_request|
|
||||
job_waiter.jobs_remaining += 1
|
||||
|
||||
next if already_enqueued?(pull_request)
|
||||
|
||||
job_delay = calculate_job_delay(job_waiter.jobs_remaining)
|
||||
|
||||
sidekiq_worker_class.perform_in(job_delay, project.id, pull_request.to_hash, job_waiter.key)
|
||||
|
||||
mark_as_enqueued(pull_request)
|
||||
end
|
||||
|
||||
job_waiter
|
||||
rescue StandardError => e
|
||||
track_import_failure!(project, exception: e)
|
||||
job_waiter
|
||||
end
|
||||
private
|
||||
|
||||
def sidekiq_worker_class
|
||||
ImportPullRequestWorker
|
||||
|
|
@ -71,13 +37,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def id_for_already_enqueued_cache(object)
|
||||
if object.is_a?(Hash)
|
||||
# used for `resumable_execute`
|
||||
object[:iid]
|
||||
else
|
||||
# used for `non_resumable_execute`
|
||||
object.iid
|
||||
end
|
||||
object[:iid]
|
||||
end
|
||||
|
||||
# To avoid overloading Gitaly, we use a smaller limit for pull requests than the one defined in the
|
||||
|
|
|
|||
|
|
@ -14,9 +14,6 @@ module Gitlab
|
|||
end
|
||||
|
||||
def execute
|
||||
bitbucket_import_resumable_worker =
|
||||
Feature.enabled?(:bitbucket_import_resumable_worker, current_user)
|
||||
|
||||
::Projects::CreateService.new(
|
||||
current_user,
|
||||
name: name,
|
||||
|
|
@ -28,12 +25,7 @@ module Gitlab
|
|||
import_type: 'bitbucket',
|
||||
import_source: repo.full_name,
|
||||
import_url: clone_url,
|
||||
import_data: {
|
||||
credentials: credentials,
|
||||
data: {
|
||||
bitbucket_import_resumable_worker: bitbucket_import_resumable_worker
|
||||
}
|
||||
},
|
||||
import_data: { credentials: credentials },
|
||||
skip_wiki: skip_wiki
|
||||
).execute
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,23 +44,6 @@ module Gitlab
|
|||
connection.execute(alter_new_sequences_range_trigger)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sequences
|
||||
if sequence_names.present?
|
||||
Gitlab::Database::PostgresSequence.where(seq_name: sequence_names)
|
||||
else
|
||||
Gitlab::Database::PostgresSequence.all
|
||||
end
|
||||
end
|
||||
|
||||
def with_lock_retries(&)
|
||||
Gitlab::Database::WithLockRetries.new(
|
||||
connection: connection,
|
||||
logger: logger
|
||||
).run(raise_on_exhaustion: false, &)
|
||||
end
|
||||
|
||||
def alter_new_sequences_range_function
|
||||
<<~SQL
|
||||
CREATE OR REPLACE FUNCTION alter_new_sequences_range()
|
||||
|
|
@ -80,7 +63,9 @@ module Gitlab
|
|||
SELECT min_value, max_value INTO current_minval, current_maxval FROM pg_sequences
|
||||
WHERE sequencename = sequence_name;
|
||||
|
||||
IF current_minval != #{minval} OR current_maxval != #{maxval} THEN
|
||||
-- On bumping sequence ranges using gitlab:db:increase_sequences_range, new ranges will always be
|
||||
-- greater than the existing ones. The below check catches the default minval (1) and updates accordingly.
|
||||
IF current_minval < #{minval} OR current_maxval < #{maxval} THEN
|
||||
RAISE NOTICE 'Altering sequence "%" with range [%, %]', sequence_name, #{minval}, #{maxval};
|
||||
|
||||
EXECUTE FORMAT('ALTER SEQUENCE %I START %s RESTART %s MINVALUE %s MAXVALUE %s',
|
||||
|
|
@ -107,6 +92,23 @@ module Gitlab
|
|||
EXECUTE FUNCTION alter_new_sequences_range();
|
||||
SQL
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sequences
|
||||
if sequence_names.present?
|
||||
Gitlab::Database::PostgresSequence.where(seq_name: sequence_names)
|
||||
else
|
||||
Gitlab::Database::PostgresSequence.all
|
||||
end
|
||||
end
|
||||
|
||||
def with_lock_retries(&)
|
||||
Gitlab::Database::WithLockRetries.new(
|
||||
connection: connection,
|
||||
logger: logger
|
||||
).run(raise_on_exhaustion: false, &)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -39,17 +39,12 @@ module Gitlab
|
|||
end
|
||||
|
||||
def fetch_gists_to_import
|
||||
page_counter = Gitlab::Import::PageCounter.new(user, :gists, 'github-gists-importer')
|
||||
collection = []
|
||||
|
||||
client.each_page(:gists, nil, page: page_counter.current) do |page|
|
||||
next unless page_counter.set(page.number)
|
||||
|
||||
client.each_page(:gists, nil, nil) do |page|
|
||||
collection += gists_from(page)
|
||||
end
|
||||
|
||||
page_counter.expire!
|
||||
|
||||
collection
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ module Gitlab
|
|||
DEFAULT_PER_PAGE = 100
|
||||
CLIENT_CONNECTION_ERROR = ::Faraday::ConnectionFailed # used/set in sawyer agent which octokit uses
|
||||
|
||||
# A single page of data and the corresponding page number.
|
||||
Page = Struct.new(:objects, :number)
|
||||
# A single page of data and the corresponding URL.
|
||||
Page = Struct.new(:objects, :url)
|
||||
|
||||
# The minimum number of requests we want to keep available.
|
||||
#
|
||||
|
|
@ -130,30 +130,37 @@ module Gitlab
|
|||
# Fetches data from the GitHub API and yields a Page object for every page
|
||||
# of data, without loading all of them into memory.
|
||||
#
|
||||
# method - The Octokit method to use for getting the data.
|
||||
# args - Arguments to pass to the Octokit method.
|
||||
# @param method [Symbol] The Octokit method to use for getting the data
|
||||
# @param resume_url [String, nil] The GitHub link header URL to resume pagination.
|
||||
# When nil, the method will be invoked from the first page
|
||||
# @param args [Array] Arguments to pass to the Octokit method
|
||||
# @yield [Page] Each page of data from the API
|
||||
# @return [Enumerator] When no block is given
|
||||
#
|
||||
# rubocop: disable GitlabSecurity/PublicSend
|
||||
def each_page(method, *args, &block)
|
||||
return to_enum(__method__, method, *args) unless block
|
||||
def each_page(method, resume_url, *args, &block)
|
||||
return to_enum(__method__, method, resume_url, *args) unless block
|
||||
|
||||
page =
|
||||
if args.last.is_a?(Hash) && args.last[:page]
|
||||
args.last[:page]
|
||||
collection = with_rate_limit do
|
||||
if resume_url.present?
|
||||
octokit.get(resume_url)
|
||||
else
|
||||
1
|
||||
octokit.public_send(method, *args)
|
||||
end
|
||||
end
|
||||
|
||||
collection = with_rate_limit { octokit.public_send(method, *args) }
|
||||
next_url = octokit.last_response.rels[:next]
|
||||
yield Page.new(collection, resume_url)
|
||||
|
||||
yield Page.new(collection, page)
|
||||
next_page = octokit.last_response.rels[:next]
|
||||
|
||||
while next_url
|
||||
response = with_rate_limit { next_url.get }
|
||||
next_url = response.rels[:next]
|
||||
while next_page
|
||||
raise Exceptions::InvalidURLError, 'Invalid pagination URL' unless valid_next_url?(next_page.href)
|
||||
|
||||
yield Page.new(response.data, page += 1)
|
||||
response = with_rate_limit { next_page.get }
|
||||
|
||||
yield Page.new(response.data, next_page.href)
|
||||
|
||||
next_page = response.rels[:next]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -164,7 +171,7 @@ module Gitlab
|
|||
def each_object(method, *args, &block)
|
||||
return to_enum(__method__, method, *args) unless block
|
||||
|
||||
each_page(method, *args) do |page|
|
||||
each_page(method, nil, *args) do |page|
|
||||
page.objects.each do |object|
|
||||
yield object.to_h
|
||||
end
|
||||
|
|
@ -285,6 +292,18 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def api_endpoint_host
|
||||
strong_memoize(:api_endpoint_host) do
|
||||
URI.parse(api_endpoint).host
|
||||
end
|
||||
end
|
||||
|
||||
def valid_next_url?(next_url)
|
||||
next_url_host = URI.parse(next_url).host
|
||||
|
||||
next_url_host == api_endpoint_host
|
||||
end
|
||||
|
||||
def with_retry
|
||||
Retriable.retriable(on: CLIENT_CONNECTION_ERROR, on_retry: on_retry) do
|
||||
yield
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ module Gitlab
|
|||
NotImplementedError = Class.new(StandardError)
|
||||
|
||||
NoteableNotFound = Class.new(StandardError)
|
||||
|
||||
InvalidURLError = Class.new(StandardError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ module Gitlab
|
|||
project.merge_requests.where.not(iid: already_imported_parents) # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
||||
def page_counter_id(merge_request)
|
||||
def page_keyset_id(merge_request)
|
||||
"merge_request/#{merge_request.id}/#{collection_method}"
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ module Gitlab
|
|||
"github-importer/issues/#{collection_method}/already-imported/#{project.id}"
|
||||
end
|
||||
|
||||
def page_counter_id(issuable)
|
||||
def page_keyset_id(issuable)
|
||||
PROCESSED_PAGE_CACHE_KEY % { issuable_iid: issuable.iid, collection: collection_method }
|
||||
end
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def collection_options
|
||||
{ state: 'all', sort: 'created', direction: 'asc' }
|
||||
{}
|
||||
end
|
||||
|
||||
# Cross-referenced events on Github doesn't have id.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module Gitlab
|
|||
module ParallelScheduling
|
||||
include JobDelayCalculator
|
||||
|
||||
attr_reader :project, :client, :page_counter, :already_imported_cache_key,
|
||||
attr_reader :project, :client, :page_keyset, :already_imported_cache_key,
|
||||
:job_waiter_cache_key, :job_waiter_remaining_cache_key
|
||||
|
||||
attr_accessor :job_started_at, :enqueued_job_counter
|
||||
|
|
@ -27,7 +27,7 @@ module Gitlab
|
|||
@project = project
|
||||
@client = client
|
||||
@parallel = parallel
|
||||
@page_counter = Gitlab::Import::PageCounter.new(project, collection_method)
|
||||
@page_keyset = Gitlab::Import::PageKeyset.new(project, collection_method, ::Import::SOURCE_GITHUB)
|
||||
@already_imported_cache_key = format(ALREADY_IMPORTED_CACHE_KEY, project: project.id,
|
||||
collection: collection_method)
|
||||
@job_waiter_cache_key = format(JOB_WAITER_CACHE_KEY, project: project.id, collection: collection_method)
|
||||
|
|
@ -114,21 +114,10 @@ module Gitlab
|
|||
def each_object_to_import
|
||||
repo = project.import_source
|
||||
|
||||
# We inject the page number here to make sure that all importers always
|
||||
# start where they left off. Simply starting over wouldn't work for
|
||||
# repositories with a lot of data (e.g. tens of thousands of comments).
|
||||
options = collection_options.merge(page: page_counter.current)
|
||||
|
||||
client.each_page(collection_method, repo, options) do |page|
|
||||
# Technically it's possible that the same work is performed multiple
|
||||
# times, as Sidekiq doesn't guarantee there will ever only be one
|
||||
# instance of a job. In such a scenario it's possible for one job to
|
||||
# have a lower page number (e.g. 5) compared to another (e.g. 10). In
|
||||
# this case we skip over all the objects until we have caught up,
|
||||
# reducing the number of duplicate jobs scheduled by the provided
|
||||
# block.
|
||||
next unless page_counter.set(page.number)
|
||||
# URL to resume the pagination from in case the job is interrupted.
|
||||
resume_url = page_keyset.current
|
||||
|
||||
client.each_page(collection_method, resume_url, repo, collection_options) do |page|
|
||||
page.objects.each do |object|
|
||||
object = object.to_h
|
||||
|
||||
|
|
@ -144,6 +133,8 @@ module Gitlab
|
|||
# scheduling it multiple times.
|
||||
mark_as_imported(object)
|
||||
end
|
||||
|
||||
page_keyset.set(page.url)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ module Gitlab
|
|||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def page_counter_id(parent)
|
||||
def page_keyset_id(parent)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
|
|
@ -71,16 +71,16 @@ module Gitlab
|
|||
|
||||
def process_batch(batch)
|
||||
batch.each do |parent_record|
|
||||
# The page counter needs to be scoped by parent_record to avoid skipping
|
||||
# The page keyset needs to be scoped by parent_record to avoid skipping
|
||||
# pages of notes from already imported parent_record.
|
||||
page_counter = Gitlab::Import::PageCounter.new(project, page_counter_id(parent_record))
|
||||
page_keyset = Gitlab::Import::PageKeyset.new(project, page_keyset_id(parent_record), ::Import::SOURCE_GITHUB)
|
||||
repo = project.import_source
|
||||
options = collection_options.merge(page: page_counter.current)
|
||||
|
||||
client.each_page(collection_method, repo, parent_record.iid, options) do |page|
|
||||
next unless page_counter.set(page.number)
|
||||
resume_url = page_keyset.current
|
||||
|
||||
client.each_page(collection_method, resume_url, repo, parent_record.iid, collection_options) do |page|
|
||||
yield parent_record, page
|
||||
|
||||
page_keyset.set(page.url)
|
||||
end
|
||||
|
||||
after_batch_processed(parent_record)
|
||||
|
|
|
|||
|
|
@ -2,20 +2,10 @@
|
|||
|
||||
module Gitlab
|
||||
module Metrics
|
||||
# TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
|
||||
# https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
|
||||
if ENV["LABKIT_METRICS_ENABLED"] == "true"
|
||||
include ::Gitlab::Metrics::Labkit
|
||||
else
|
||||
include ::Gitlab::Metrics::Prometheus
|
||||
end
|
||||
include ::Gitlab::Metrics::Labkit
|
||||
|
||||
EXECUTION_MEASUREMENT_BUCKETS = [0.001, 0.01, 0.1, 1].freeze
|
||||
|
||||
def self.enabled?
|
||||
prometheus_metrics_enabled?
|
||||
end
|
||||
|
||||
def self.record_duration_for_status?(status)
|
||||
status.to_i.between?(200, 499)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'webrick'
|
||||
require 'labkit/metrics/rack_exporter'
|
||||
|
||||
module Gitlab
|
||||
module Metrics
|
||||
module Exporter
|
||||
class BaseExporter < Daemon
|
||||
CERT_REGEX = /-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE-----/
|
||||
RACK_EXPORTER =
|
||||
if ENV["LABKIT_METRICS_ENABLED"] == "true"
|
||||
require 'labkit/metrics/rack_exporter'
|
||||
::Labkit::Metrics::RackExporter
|
||||
else
|
||||
require 'prometheus/client/rack/exporter'
|
||||
::Prometheus::Client::Rack::Exporter
|
||||
end
|
||||
|
||||
attr_reader :server
|
||||
|
||||
|
|
@ -90,7 +83,7 @@ module Gitlab
|
|||
use Rack::Deflater
|
||||
use Gitlab::Metrics::Exporter::MetricsMiddleware, pid
|
||||
use Gitlab::Metrics::Exporter::GcRequestMiddleware if gc_requests
|
||||
use RACK_EXPORTER if ::Gitlab::Metrics.enabled?
|
||||
use ::Labkit::Metrics::RackExporter if ::Gitlab::Metrics.prometheus_metrics_enabled?
|
||||
|
||||
run ->(env) { [404, {}, ['']] }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,81 +9,57 @@ module Gitlab
|
|||
def client
|
||||
::Labkit::Metrics::Client
|
||||
end
|
||||
alias_method :registry, :client
|
||||
|
||||
def null_metric
|
||||
::Labkit::Metrics::Null.instance
|
||||
end
|
||||
|
||||
def error?
|
||||
!client.enabled?
|
||||
end
|
||||
|
||||
# TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
|
||||
# https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160.
|
||||
#
|
||||
# This method is kept here for compatibility with the old implementation only:
|
||||
# lib/gitlab/metrics/prometheus.rb. This is a implementation detail supposed
|
||||
# to be hidden within Labkit::Metrics::Client.enabled?/disabled? methods.
|
||||
def metrics_folder_present?
|
||||
client.enabled?
|
||||
end
|
||||
|
||||
# Used only in specs to reset the error state
|
||||
#
|
||||
# TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
|
||||
# https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
|
||||
def reset_registry!
|
||||
@prometheus_metrics_enabled = nil
|
||||
client.reset!
|
||||
end
|
||||
|
||||
def counter(name, docstring, base_labels = {})
|
||||
safe_provide_metric(:counter, name, docstring, base_labels)
|
||||
when_metrics_enabled do
|
||||
client.counter(name, docstring, base_labels)
|
||||
end
|
||||
end
|
||||
|
||||
def summary(name, docstring, base_labels = {})
|
||||
safe_provide_metric(:summary, name, docstring, base_labels)
|
||||
when_metrics_enabled do
|
||||
client.summary(name, docstring, base_labels)
|
||||
end
|
||||
end
|
||||
|
||||
def gauge(name, docstring, base_labels = {}, multiprocess_mode = :all)
|
||||
safe_provide_metric(:gauge, name, docstring, base_labels, multiprocess_mode)
|
||||
when_metrics_enabled do
|
||||
client.gauge(name, docstring, base_labels, multiprocess_mode)
|
||||
end
|
||||
end
|
||||
|
||||
def histogram(name, docstring, base_labels = {}, buckets = ::Prometheus::Client::Histogram::DEFAULT_BUCKETS)
|
||||
safe_provide_metric(:histogram, name, docstring, base_labels, buckets)
|
||||
when_metrics_enabled do
|
||||
client.histogram(name, docstring, base_labels, buckets)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
|
||||
# https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
|
||||
def error_detected!
|
||||
@prometheus_metrics_enabled = nil
|
||||
|
||||
client.disable!
|
||||
end
|
||||
|
||||
# Used only in specs to reset the error state
|
||||
#
|
||||
# TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
|
||||
# https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
|
||||
def clear_errors!
|
||||
@prometheus_metrics_enabled = nil
|
||||
|
||||
client.enable!
|
||||
end
|
||||
|
||||
def prometheus_metrics_enabled?
|
||||
prometheus_metrics_enabled_memoized
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# TODO: remove when we move away from Prometheus::Client to Labkit::Metrics::Client completely
|
||||
# https://gitlab.com/gitlab-com/gl-infra/observability/team/-/issues/4160
|
||||
def safe_provide_metric(metric_type, metric_name, *args)
|
||||
return null_metric unless prometheus_metrics_enabled?
|
||||
|
||||
client.send(metric_type, metric_name, *args) # rubocop:disable GitlabSecurity/PublicSend -- temporary workaround, see issue link
|
||||
def when_metrics_enabled
|
||||
if prometheus_metrics_enabled?
|
||||
yield
|
||||
else
|
||||
null_metric
|
||||
end
|
||||
end
|
||||
|
||||
def prometheus_metrics_enabled_memoized
|
||||
|
|
|
|||
|
|
@ -1,119 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Metrics
|
||||
module Prometheus
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
REGISTRY_MUTEX = Mutex.new
|
||||
PROVIDER_MUTEX = Mutex.new
|
||||
|
||||
class_methods do
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
@error = false
|
||||
|
||||
def error?
|
||||
@error
|
||||
end
|
||||
|
||||
def client
|
||||
::Prometheus::Client
|
||||
end
|
||||
|
||||
def null_metric
|
||||
NullMetric.instance
|
||||
end
|
||||
|
||||
def metrics_folder_present?
|
||||
multiprocess_files_dir = client.configuration.multiprocess_files_dir
|
||||
|
||||
multiprocess_files_dir &&
|
||||
::Dir.exist?(multiprocess_files_dir) &&
|
||||
::File.writable?(multiprocess_files_dir)
|
||||
end
|
||||
|
||||
def prometheus_metrics_enabled?
|
||||
strong_memoize(:prometheus_metrics_enabled) do
|
||||
prometheus_metrics_enabled_unmemoized
|
||||
end
|
||||
end
|
||||
|
||||
def reset_registry!
|
||||
clear_memoization(:registry)
|
||||
clear_memoization(:prometheus_metrics_enabled)
|
||||
|
||||
REGISTRY_MUTEX.synchronize do
|
||||
client.cleanup!
|
||||
client.reset!
|
||||
end
|
||||
end
|
||||
|
||||
def registry
|
||||
strong_memoize(:registry) do
|
||||
REGISTRY_MUTEX.synchronize do
|
||||
strong_memoize(:registry) do
|
||||
client.registry
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def counter(name, docstring, base_labels = {})
|
||||
safe_provide_metric(:counter, name, docstring, base_labels)
|
||||
end
|
||||
|
||||
def summary(name, docstring, base_labels = {})
|
||||
safe_provide_metric(:summary, name, docstring, base_labels)
|
||||
end
|
||||
|
||||
def gauge(name, docstring, base_labels = {}, multiprocess_mode = :all)
|
||||
safe_provide_metric(:gauge, name, docstring, base_labels, multiprocess_mode)
|
||||
end
|
||||
|
||||
def histogram(name, docstring, base_labels = {}, buckets = client::Histogram::DEFAULT_BUCKETS)
|
||||
safe_provide_metric(:histogram, name, docstring, base_labels, buckets)
|
||||
end
|
||||
|
||||
def error_detected!
|
||||
set_error!(true)
|
||||
end
|
||||
|
||||
def clear_errors!
|
||||
set_error!(false)
|
||||
end
|
||||
|
||||
def set_error!(status)
|
||||
clear_memoization(:prometheus_metrics_enabled)
|
||||
|
||||
PROVIDER_MUTEX.synchronize do
|
||||
@error = status
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def safe_provide_metric(metric_type, name, *args)
|
||||
metric = provide_metric(name)
|
||||
return metric if metric
|
||||
|
||||
PROVIDER_MUTEX.synchronize do
|
||||
provide_metric(name) || registry.method(metric_type).call(name, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def provide_metric(metric_name)
|
||||
if prometheus_metrics_enabled?
|
||||
registry.get(metric_name)
|
||||
else
|
||||
null_metric
|
||||
end
|
||||
end
|
||||
|
||||
def prometheus_metrics_enabled_unmemoized
|
||||
(!error? && metrics_folder_present? && Gitlab::CurrentSettings.prometheus_metrics_enabled) || false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -30,7 +30,7 @@ module Gitlab
|
|||
|
||||
return unless project&.pages_deployed?
|
||||
|
||||
::Pages::VirtualDomain.new(projects: [project])
|
||||
::Pages::VirtualDomain.new(projects: [project], namespace: project.namespace)
|
||||
end
|
||||
|
||||
def by_namespace_domain(name)
|
||||
|
|
@ -51,7 +51,11 @@ module Gitlab
|
|||
return unless domain&.enabled?
|
||||
return unless domain&.pages_deployed?
|
||||
|
||||
::Pages::VirtualDomain.new(projects: [domain.project], domain: domain)
|
||||
::Pages::VirtualDomain.new(
|
||||
projects: [domain.project],
|
||||
domain: domain,
|
||||
namespace: domain.project.namespace
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def generic_package_file_name_regex
|
||||
@generic_package_file_name_regex ||= /\A(?!~)[A-Za-z0-9\.\_\-\+~]+(?<!~)\z/
|
||||
@generic_package_file_name_regex ||= /\A(?!~)(?!@)[A-Za-z0-9\.\_\-\+~@]+(?<!~)(?<!@)\z/
|
||||
end
|
||||
|
||||
def sha256_regex
|
||||
|
|
@ -279,6 +279,10 @@ module Gitlab
|
|||
@slack_link_regex ||= Gitlab::UntrustedRegexp.new('<([^|<>]*[|][^|<>]*)>')
|
||||
end
|
||||
|
||||
def helm_index_app_version_quote_regex
|
||||
@helm_index_app_version_quote_regex ||= /^(\s*appVersion:\s+)(?!["'])([^\n\r]+)$/m
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def conan_name_regex
|
||||
|
|
|
|||
|
|
@ -5838,6 +5838,9 @@ msgstr ""
|
|||
msgid "Agent not found for provided id."
|
||||
msgstr ""
|
||||
|
||||
msgid "Agent sessions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Agents"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -17035,9 +17038,15 @@ msgstr ""
|
|||
msgid "ComplianceViolation|Dismissed"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceViolation|Fix suggestion generated for this failed control"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceViolation|Framework"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceViolation|Go to project settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "ComplianceViolation|In review"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23552,10 +23561,13 @@ msgstr ""
|
|||
msgid "DuoAgenticChat|GitLab Duo Agentic Chat"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Agent flow"
|
||||
msgid "DuoAgentsPlatform|Agent session"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Agents"
|
||||
msgid "DuoAgentsPlatform|Agent sessions"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Automate"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Convert Jenkins to CI"
|
||||
|
|
@ -23582,13 +23594,13 @@ msgstr ""
|
|||
msgid "DuoAgentsPlatform|New"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|New Agent Flow"
|
||||
msgid "DuoAgentsPlatform|New agent sessions will appear here."
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|New Agent runs will appear here."
|
||||
msgid "DuoAgentsPlatform|New session"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|No Agent runs yet"
|
||||
msgid "DuoAgentsPlatform|No agent sessions yet"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|No logs available yet."
|
||||
|
|
@ -23603,16 +23615,16 @@ msgstr ""
|
|||
msgid "DuoAgentsPlatform|Prompt"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Run an Agent Flow"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Select Agent Flow"
|
||||
msgid "DuoAgentsPlatform|Select a flow"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Something went wrong while fetching Agent Flows"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Start Agent Flow"
|
||||
msgid "DuoAgentsPlatform|Start agent session"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Start an agent session"
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoAgentsPlatform|Status"
|
||||
|
|
@ -53279,6 +53291,9 @@ msgstr ""
|
|||
msgid "Runners|Learn more in the %{linkStart}Google Cloud documentation%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Loading"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Machine type"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -53577,6 +53592,9 @@ msgstr ""
|
|||
msgid "Runners|Runner assigned to project."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Runner authentication token"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Runner authentication token expiration"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -53760,6 +53778,9 @@ msgstr ""
|
|||
msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|The runner authentication token displays here %{boldStart}for a short time only%{boldEnd}. After you register the runner, this token is stored in the %{codeStart}config.toml%{codeEnd} and cannot be accessed again from the UI."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|The runner authentication token is invalid"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -54006,9 +54027,6 @@ msgstr ""
|
|||
msgid "Running"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runs"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -9,14 +9,8 @@ require 'active_support/inflector'
|
|||
require 'active_support/core_ext/numeric/bytes'
|
||||
|
||||
require 'gitlab/utils/all'
|
||||
|
||||
if ENV["LABKIT_METRICS_ENABLED"] == "true"
|
||||
require 'gitlab-labkit'
|
||||
require_relative '../lib/gitlab/metrics/labkit'
|
||||
else
|
||||
require 'prometheus/client'
|
||||
require_relative '../lib/gitlab/metrics/prometheus'
|
||||
end
|
||||
require 'gitlab-labkit'
|
||||
require_relative '../lib/gitlab/metrics/labkit'
|
||||
|
||||
require 'rack'
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module QA
|
|||
within_element(element_name) do
|
||||
# Because it is possible to click the button before the JS toggle code is bound
|
||||
wait_until(reload: false, message: "Waiting until content is expanded") do
|
||||
click_button 'Expand' unless has_css?('button', text: 'Collapse', wait: 1)
|
||||
click_button class: 'settings-toggle' unless has_css?('button', text: 'Collapse', wait: 1)
|
||||
|
||||
has_content?('Collapse')
|
||||
end
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ RSpec.describe OmniauthCallbacksController, :with_current_organization, type: :c
|
|||
it 'increments Prometheus counter' do
|
||||
expect { post(provider) }.to(
|
||||
change do
|
||||
Gitlab::Metrics.registry
|
||||
Gitlab::Metrics.client
|
||||
.get(:gitlab_omniauth_login_total)
|
||||
&.get(omniauth_provider: 'github', status: 'succeeded')
|
||||
.to_f
|
||||
|
|
@ -198,7 +198,7 @@ RSpec.describe OmniauthCallbacksController, :with_current_organization, type: :c
|
|||
it 'increments Prometheus counter' do
|
||||
expect { post(provider) }.to(
|
||||
change do
|
||||
Gitlab::Metrics.registry
|
||||
Gitlab::Metrics.client
|
||||
.get(:gitlab_omniauth_login_total)
|
||||
&.get(omniauth_provider: 'github', status: 'succeeded')
|
||||
.to_f
|
||||
|
|
@ -312,7 +312,7 @@ RSpec.describe OmniauthCallbacksController, :with_current_organization, type: :c
|
|||
ForgeryProtection.with_forgery_protection do
|
||||
expect { post :failure }.to(
|
||||
change do
|
||||
Gitlab::Metrics.registry
|
||||
Gitlab::Metrics.client
|
||||
.get(:gitlab_omniauth_login_total)
|
||||
&.get(omniauth_provider: 'saml', status: 'failed')
|
||||
.to_f
|
||||
|
|
|
|||
|
|
@ -338,6 +338,30 @@ RSpec.describe 'Edit group settings', feature_category: :groups_and_projects do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'update pages access control' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:project) { create(:project, :pages_published, namespace: group, pages_access_level: ProjectFeature::PUBLIC) }
|
||||
|
||||
before do
|
||||
stub_pages_setting(access_control: true, enabled: true)
|
||||
allow(::Gitlab::Pages).to receive(:access_control_is_forced?).and_return(false)
|
||||
end
|
||||
|
||||
context 'when group owner changes forced access control settings' do
|
||||
context 'when group access control is being enabled' do
|
||||
it 'project access control should be enforced' do
|
||||
visit edit_group_path(group)
|
||||
|
||||
check 'group_force_pages_access_control'
|
||||
|
||||
expect { save_permissions_group }.to change {
|
||||
project.private_pages?
|
||||
}.from(false).to(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_path(new_group_path)
|
||||
visit edit_group_path(group)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,32 +1,88 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import MultiStepFormTemplate from '~/vue_shared/components/multi_step_form_template.vue';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import RunnerCreateWizardRegistration from '~/ci/runner/components/runner_create_wizard_registration.vue';
|
||||
import runnerForRegistrationQuery from '~/ci/runner/graphql/register/runner_for_registration.query.graphql';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
describe('Create New Runner Registration', () => {
|
||||
let wrapper;
|
||||
|
||||
const createComponent = () => {
|
||||
const defaultHandler = [
|
||||
runnerForRegistrationQuery,
|
||||
jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
runner: {
|
||||
id: 1,
|
||||
description: 'test runner',
|
||||
ephemeralAuthenticationToken: 'mock-registration-token',
|
||||
creationState: 'FINISHED',
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const createComponent = (props = {}) => {
|
||||
wrapper = shallowMountExtended(RunnerCreateWizardRegistration, {
|
||||
apolloProvider: createMockApollo([defaultHandler]),
|
||||
propsData: {
|
||||
currentStep: 2,
|
||||
currentStep: 3,
|
||||
stepsTotal: 3,
|
||||
runnerId: 'gid://gitlab/Ci::Runner/1',
|
||||
runnersPath: '/admin/runners',
|
||||
...props,
|
||||
},
|
||||
});
|
||||
|
||||
return waitForPromises();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
const findMultiStepFormTemplate = () => wrapper.findComponent(MultiStepFormTemplate);
|
||||
const findToken = () => wrapper.findByTestId('token-input');
|
||||
const findCopyTokenButton = () => wrapper.findByTestId('copy-token-to-clipboard');
|
||||
const findLoadingIcon = () => wrapper.findByTestId('loading-icon-wrapper');
|
||||
|
||||
describe('form', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('passes the correct props to MultiStepFormTemplate', () => {
|
||||
expect(findMultiStepFormTemplate().props()).toMatchObject({
|
||||
title: 'Register your new runner',
|
||||
currentStep: 2,
|
||||
currentStep: 3,
|
||||
stepsTotal: 3,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders runner token', async () => {
|
||||
await waitForPromises();
|
||||
|
||||
expect(findToken().exists()).toBe(true);
|
||||
expect(findToken().props('value')).toBe('mock-registration-token');
|
||||
});
|
||||
|
||||
it('renders copy token to clipboard button', async () => {
|
||||
await waitForPromises();
|
||||
|
||||
expect(findCopyTokenButton().exists()).toBe(true);
|
||||
expect(findCopyTokenButton().props('text')).toBe('mock-registration-token');
|
||||
});
|
||||
});
|
||||
|
||||
describe('loading state', () => {
|
||||
it('shows the loading icon when data is not yet available', () => {
|
||||
createComponent();
|
||||
expect(findLoadingIcon().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('removes the loading icon when data is available', async () => {
|
||||
await createComponent();
|
||||
expect(findLoadingIcon().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ RSpec.describe Admin::ApplicationSettingsController, '(JavaScript fixtures)', ty
|
|||
|
||||
before do
|
||||
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
|
||||
allow(Gitlab::Metrics).to receive(:metrics_folder_present?).and_return(true)
|
||||
Labkit::Metrics::Client.enable!
|
||||
sign_in(admin)
|
||||
enable_admin_mode!(admin)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { GlCollapse } from '@gitlab/ui';
|
||||
import { GlCollapse, GlAnimatedChevronLgRightDownIcon } from '@gitlab/ui';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
|
||||
import setWindowLocation from 'helpers/set_window_location_helper';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
|
||||
describe('Settings Block', () => {
|
||||
let wrapper;
|
||||
|
|
@ -21,6 +22,7 @@ describe('Settings Block', () => {
|
|||
const findTitle = () => wrapper.findByTestId('settings-block-title');
|
||||
const findToggleButton = () => wrapper.findByTestId('settings-block-toggle');
|
||||
const findDescriptionSlot = () => wrapper.findByTestId('description-slot');
|
||||
const findChevronIcon = () => wrapper.findComponent(GlAnimatedChevronLgRightDownIcon);
|
||||
|
||||
it('has a default slot', () => {
|
||||
mountComponent();
|
||||
|
|
@ -75,6 +77,13 @@ describe('Settings Block', () => {
|
|||
expect(findToggleButton().attributes('aria-label')).toContain('Expand');
|
||||
});
|
||||
|
||||
it('animates chevron', () => {
|
||||
// Vue compat doesn't know about component props if it extends other component
|
||||
expect(
|
||||
findChevronIcon().props('isOn') ?? parseBoolean(findChevronIcon().attributes('is-on')),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
describe('when `Expand` button is clicked', () => {
|
||||
beforeEach(async () => {
|
||||
await findToggleButton().trigger('click');
|
||||
|
|
@ -119,6 +128,13 @@ describe('Settings Block', () => {
|
|||
expect(findToggleButton().attributes('aria-label')).toContain('Collapse');
|
||||
});
|
||||
|
||||
it('animates chevron', () => {
|
||||
// Vue compat doesn't know about component props if it extends other component
|
||||
expect(
|
||||
findChevronIcon().props('isOn') ?? parseBoolean(findChevronIcon().attributes('is-on')),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
describe('when `Collapse` button is clicked', () => {
|
||||
beforeEach(async () => {
|
||||
await findToggleButton().trigger('click');
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ RSpec.describe Gitlab::Auth::OAuth::BeforeRequestPhaseOauthLoginCounterIncrement
|
|||
end
|
||||
|
||||
def gitlab_metric_omniauth_login_total_for(omniauth_provider, status)
|
||||
Gitlab::Metrics.registry.get(:gitlab_omniauth_login_total)
|
||||
Gitlab::Metrics.client.get(:gitlab_omniauth_login_total)
|
||||
&.get(omniauth_provider: omniauth_provider, status: status)
|
||||
.to_f
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,20 +5,33 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::BitbucketImport::Importers::IssuesImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
subject(:importer) { described_class.new(project) }
|
||||
|
||||
shared_examples 'import bitbucket IssuesImporter' do |params|
|
||||
describe '#execute' do
|
||||
let(:client) { Bitbucket::Client.new(project.import_data.credentials) }
|
||||
let_it_be(:project) do
|
||||
create(:project, :import_started,
|
||||
import_data_attributes: {
|
||||
data: {
|
||||
'project_key' => 'key',
|
||||
'repo_slug' => 'slug',
|
||||
'bitbucket_import_resumable_worker' => params[:resumable]
|
||||
'repo_slug' => 'slug'
|
||||
},
|
||||
credentials: { 'base_uri' => 'http://bitbucket.org/', 'user' => 'bitbucket', 'password' => 'password' }
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(Bitbucket::Client).to receive(:new).and_return(client)
|
||||
allow(client).to receive(:repo).and_return(Bitbucket::Representation::Repo.new({ 'has_issues' => true }))
|
||||
allow(client).to receive(:last_issue).and_return(Bitbucket::Representation::Issue.new({ 'id' => 2 }))
|
||||
page = instance_double('Bitbucket::Page', attrs: [], items: [
|
||||
Bitbucket::Representation::Issue.new({ 'id' => 1 }),
|
||||
Bitbucket::Representation::Issue.new({ 'id' => 2 })
|
||||
])
|
||||
allow(client).to receive(:each_page).and_yield(page)
|
||||
allow(page).to receive(:next?).and_return(true)
|
||||
allow(page).to receive(:next).and_return('https://example.com/next')
|
||||
end
|
||||
|
||||
context 'when the repo does not have issue tracking enabled' do
|
||||
before do
|
||||
allow(client).to receive(:repo).and_return(Bitbucket::Representation::Repo.new({ 'has_issues' => false }))
|
||||
|
|
@ -62,72 +75,18 @@ RSpec.describe Gitlab::BitbucketImport::Importers::IssuesImporter, :clean_gitlab
|
|||
expect(waiter.jobs_remaining).to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#resumable_execute' do
|
||||
let(:client) { Bitbucket::Client.new(project.import_data.credentials) }
|
||||
context 'when the client raises an error' do
|
||||
let(:exception) { StandardError.new('error fetching issues') }
|
||||
|
||||
before do
|
||||
allow(Bitbucket::Client).to receive(:new).and_return(client)
|
||||
allow(client).to receive(:repo).and_return(Bitbucket::Representation::Repo.new({ 'has_issues' => true }))
|
||||
allow(client).to receive(:last_issue).and_return(Bitbucket::Representation::Issue.new({ 'id' => 2 }))
|
||||
page = instance_double('Bitbucket::Page', attrs: [], items: [
|
||||
Bitbucket::Representation::Issue.new({ 'id' => 1 }),
|
||||
Bitbucket::Representation::Issue.new({ 'id' => 2 })
|
||||
])
|
||||
allow(client).to receive(:each_page).and_yield(page)
|
||||
allow(page).to receive(:next?).and_return(true)
|
||||
allow(page).to receive(:next).and_return('https://example.com/next')
|
||||
end
|
||||
|
||||
it_behaves_like 'import bitbucket IssuesImporter', { resumable: true } do
|
||||
context 'when the client raises an error' do
|
||||
let(:exception) { StandardError.new('error fetching issues') }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(Bitbucket::Client) do |client|
|
||||
allow(client).to receive(:repo).and_raise(exception)
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises the error' do
|
||||
expect { importer.execute }.to raise_error(StandardError, 'error fetching issues')
|
||||
before do
|
||||
allow_next_instance_of(Bitbucket::Client) do |client|
|
||||
allow(client).to receive(:repo).and_raise(exception)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#non_resumable_execute' do
|
||||
let(:client) { Bitbucket::Client.new(project.import_data.credentials) }
|
||||
|
||||
before do
|
||||
allow(Bitbucket::Client).to receive(:new).and_return(client)
|
||||
allow(client).to receive(:repo).and_return(Bitbucket::Representation::Repo.new({ 'has_issues' => true }))
|
||||
allow(client).to receive(:last_issue).and_return(Bitbucket::Representation::Issue.new({ 'id' => 2 }))
|
||||
allow(client).to receive(:issues).and_return(
|
||||
[
|
||||
Bitbucket::Representation::Issue.new({ 'id' => 1 }),
|
||||
Bitbucket::Representation::Issue.new({ 'id' => 2 })
|
||||
],
|
||||
[]
|
||||
)
|
||||
end
|
||||
|
||||
it_behaves_like 'import bitbucket IssuesImporter', { resumable: false } do
|
||||
context 'when the client raises an error' do
|
||||
let(:exception) { StandardError.new('error fetching issues') }
|
||||
|
||||
before do
|
||||
allow(client).to receive(:issues).and_raise(exception)
|
||||
end
|
||||
|
||||
it 'tracks the failure and does not fail' do
|
||||
expect(Gitlab::Import::ImportFailureService).to receive(:track)
|
||||
.once
|
||||
.with(a_hash_including(exception: exception))
|
||||
|
||||
expect(importer.execute).to be_a(Gitlab::JobWaiter)
|
||||
end
|
||||
it 'raises the error' do
|
||||
expect { importer.execute }.to raise_error(StandardError, 'error fetching issues')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,20 +5,33 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsImporter, :clean_gitlab_redis_shared_state, feature_category: :importers do
|
||||
subject(:importer) { described_class.new(project) }
|
||||
|
||||
shared_examples 'import bitbucket PullRequestsImporter' do |params|
|
||||
describe '#execute' do
|
||||
let_it_be(:project) do
|
||||
create(:project, :import_started,
|
||||
import_data_attributes: {
|
||||
data: {
|
||||
'project_key' => 'key',
|
||||
'repo_slug' => 'slug',
|
||||
'bitbucket_import_resumable_worker' => params[:resumable]
|
||||
'repo_slug' => 'slug'
|
||||
},
|
||||
credentials: { 'base_uri' => 'http://bitbucket.org/', 'user' => 'bitbucket', 'password' => 'password' }
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow_next_instance_of(Bitbucket::Client) do |client|
|
||||
page = instance_double('Bitbucket::Page', attrs: [], items: [
|
||||
Bitbucket::Representation::PullRequest.new({ 'id' => 1, 'state' => 'OPENED' }),
|
||||
Bitbucket::Representation::PullRequest.new({ 'id' => 2, 'state' => 'DECLINED' }),
|
||||
Bitbucket::Representation::PullRequest.new({ 'id' => 3, 'state' => 'MERGED' })
|
||||
])
|
||||
|
||||
allow(client).to receive(:each_page).and_yield(page)
|
||||
allow(page).to receive(:next?).and_return(true)
|
||||
allow(page).to receive(:next).and_return('https://example.com/next')
|
||||
end
|
||||
end
|
||||
|
||||
it 'imports each pull request in parallel' do
|
||||
expect(Gitlab::BitbucketImport::ImportPullRequestWorker).to receive(:perform_in).exactly(3).times
|
||||
|
||||
|
|
@ -44,69 +57,16 @@ RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsImporter, :clean_
|
|||
expect(waiter.jobs_remaining).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#resumable_execute' do
|
||||
before do
|
||||
allow_next_instance_of(Bitbucket::Client) do |client|
|
||||
page = instance_double('Bitbucket::Page', attrs: [], items: [
|
||||
Bitbucket::Representation::PullRequest.new({ 'id' => 1, 'state' => 'OPENED' }),
|
||||
Bitbucket::Representation::PullRequest.new({ 'id' => 2, 'state' => 'DECLINED' }),
|
||||
Bitbucket::Representation::PullRequest.new({ 'id' => 3, 'state' => 'MERGED' })
|
||||
])
|
||||
|
||||
allow(client).to receive(:each_page).and_yield(page)
|
||||
allow(page).to receive(:next?).and_return(true)
|
||||
allow(page).to receive(:next).and_return('https://example.com/next')
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'import bitbucket PullRequestsImporter', { resumable: true } do
|
||||
context 'when the client raises an error' do
|
||||
before do
|
||||
allow_next_instance_of(Bitbucket::Client) do |client|
|
||||
allow(client).to receive(:pull_requests).and_raise(StandardError.new('error fetching PRs'))
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises the error' do
|
||||
expect { importer.execute }.to raise_error(StandardError, 'error fetching PRs')
|
||||
context 'when the client raises an error' do
|
||||
before do
|
||||
allow_next_instance_of(Bitbucket::Client) do |client|
|
||||
allow(client).to receive(:pull_requests).and_raise(StandardError.new('error fetching PRs'))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#non_resumable_execute' do
|
||||
before do
|
||||
allow_next_instance_of(Bitbucket::Client) do |client|
|
||||
allow(client).to receive(:pull_requests).and_return(
|
||||
[
|
||||
Bitbucket::Representation::PullRequest.new({ 'id' => 1, 'state' => 'OPENED' }),
|
||||
Bitbucket::Representation::PullRequest.new({ 'id' => 2, 'state' => 'DECLINED' }),
|
||||
Bitbucket::Representation::PullRequest.new({ 'id' => 3, 'state' => 'MERGED' })
|
||||
],
|
||||
[]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'import bitbucket PullRequestsImporter', { resumable: false } do
|
||||
context 'when the client raises an error' do
|
||||
let(:exception) { StandardError.new('error fetching PRs') }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(Bitbucket::Client) do |client|
|
||||
allow(client).to receive(:pull_requests).and_raise(exception)
|
||||
end
|
||||
end
|
||||
|
||||
it 'tracks the failure and does not fail' do
|
||||
expect(Gitlab::Import::ImportFailureService).to receive(:track)
|
||||
.once
|
||||
.with(a_hash_including(exception: exception))
|
||||
|
||||
expect(importer.execute).to be_a(Gitlab::JobWaiter)
|
||||
end
|
||||
it 'raises the error' do
|
||||
expect { importer.execute }.to raise_error(StandardError, 'error fetching PRs')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ RSpec.describe Gitlab::Ci::Parsers::Instrumentation do
|
|||
|
||||
expect(result).to eq('parse hello world')
|
||||
|
||||
metrics = Gitlab::Metrics.registry.get(:ci_report_parser_duration_seconds).get({ parser: parser_class.name })
|
||||
metrics = Gitlab::Metrics.client.get(:ci_report_parser_duration_seconds).get({ parser: parser_class.name })
|
||||
|
||||
expect(metrics.keys).to match_array(described_class::BUCKETS)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ RSpec.describe Gitlab::Database::ConsistencyChecker, feature_category: :cell do
|
|||
let(:batch_size) { 10 }
|
||||
let(:max_batches) { 4 }
|
||||
let(:max_runtime) { described_class::MAX_RUNTIME }
|
||||
let(:metrics_counter) { Gitlab::Metrics.registry.get(:consistency_checks) }
|
||||
let(:metrics_counter) { Gitlab::Metrics.client.get(:consistency_checks) }
|
||||
|
||||
subject(:consistency_checker) do
|
||||
described_class.new(
|
||||
|
|
|
|||
|
|
@ -136,6 +136,6 @@ RSpec.describe Gitlab::Database::LoadBalancing::HostList do
|
|||
end
|
||||
|
||||
def expect_metrics(hosts)
|
||||
expect(Gitlab::Metrics.registry.get(:db_load_balancing_hosts).get({})).to eq(hosts)
|
||||
expect(Gitlab::Metrics.client.get(:db_load_balancing_hosts).get({})).to eq(hosts)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,19 +25,19 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionMonitoring, feature_cate
|
|||
it 'reports number of present partitions' do
|
||||
subject
|
||||
|
||||
expect(Gitlab::Metrics.registry.get(:db_partitions_present).get({ table: table })).to eq(current_partitions.size)
|
||||
expect(Gitlab::Metrics.client.get(:db_partitions_present).get({ table: table })).to eq(current_partitions.size)
|
||||
end
|
||||
|
||||
it 'reports number of missing partitions' do
|
||||
subject
|
||||
|
||||
expect(Gitlab::Metrics.registry.get(:db_partitions_missing).get({ table: table })).to eq(missing_partitions.size)
|
||||
expect(Gitlab::Metrics.client.get(:db_partitions_missing).get({ table: table })).to eq(missing_partitions.size)
|
||||
end
|
||||
|
||||
it 'reports number of extra partitions' do
|
||||
subject
|
||||
|
||||
expect(Gitlab::Metrics.registry.get(:db_partitions_extra).get({ table: table })).to eq(extra_partitions.size)
|
||||
expect(Gitlab::Metrics.client.get(:db_partitions_extra).get({ table: table })).to eq(extra_partitions.size)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ RSpec.describe Gitlab::DependencyLinker do
|
|||
|
||||
described_class.link('Gemfile', nil, nil, used_on: :diff)
|
||||
|
||||
dependency_linker_usage_counter = Gitlab::Metrics.registry.get(:dependency_linker_usage)
|
||||
dependency_linker_usage_counter = Gitlab::Metrics.client.get(:dependency_linker_usage)
|
||||
|
||||
expect(dependency_linker_usage_counter.get(used_on: :diff)).to eq(1)
|
||||
expect(dependency_linker_usage_counter.get(used_on: :blob)).to eq(0)
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ RSpec.describe Gitlab::Git::KeepAround, feature_category: :gitaly do
|
|||
let(:metric_labels) { { source: 'keeparound_spec' } }
|
||||
|
||||
def expect_metrics_change(requested, created, &block)
|
||||
requested_metric = Gitlab::Metrics.registry.get(:gitlab_keeparound_refs_requested_total)
|
||||
created_metric = Gitlab::Metrics.registry.get(:gitlab_keeparound_refs_created_total)
|
||||
requested_metric = Gitlab::Metrics.client.get(:gitlab_keeparound_refs_requested_total)
|
||||
created_metric = Gitlab::Metrics.client.get(:gitlab_keeparound_refs_created_total)
|
||||
|
||||
expect(&block).to change { requested_metric.get(metric_labels) }.by(requested)
|
||||
.and change { created_metric.get(metric_labels) }.by(created)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RSpec.describe Gitlab::GithubGistsImport::Importer::GistsImporter, feature_categ
|
|||
let(:client) { instance_double('Gitlab::GithubImport::Client', rate_limit_resets_in: 5) }
|
||||
let(:token) { 'token' }
|
||||
let(:page_counter) { instance_double('Gitlab::Import::PageCounter', current: 1, set: true, expire!: true) }
|
||||
let(:page) { instance_double('Gitlab::GithubImport::Client::Page', objects: [gist], number: 1) }
|
||||
let(:page) { instance_double('Gitlab::GithubImport::Client::Page', objects: [gist], url: nil) }
|
||||
let(:url) { 'https://gist.github.com/foo/bar.git' }
|
||||
let(:waiter) { Gitlab::JobWaiter.new(0, 'some-job-key') }
|
||||
|
||||
|
|
@ -62,14 +62,9 @@ RSpec.describe Gitlab::GithubGistsImport::Importer::GistsImporter, feature_categ
|
|||
.with(token, parallel: true)
|
||||
.and_return(client)
|
||||
|
||||
allow(Gitlab::Import::PageCounter)
|
||||
.to receive(:new)
|
||||
.with(user, :gists, 'github-gists-importer')
|
||||
.and_return(page_counter)
|
||||
|
||||
allow(client)
|
||||
.to receive(:each_page)
|
||||
.with(:gists, nil, { page: 1 })
|
||||
.with(:gists, nil, nil)
|
||||
.and_yield(page)
|
||||
|
||||
allow(Gitlab::GithubGistsImport::Representation::Gist)
|
||||
|
|
|
|||
|
|
@ -186,45 +186,69 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
|
|||
end
|
||||
|
||||
describe '#each_page' do
|
||||
let(:object1) { double(:object1) }
|
||||
let(:object2) { double(:object2) }
|
||||
let(:resume_url) { nil }
|
||||
|
||||
before do
|
||||
allow(client)
|
||||
.to receive(:with_rate_limit)
|
||||
.and_yield
|
||||
|
||||
allow(client.octokit)
|
||||
.to receive(:public_send)
|
||||
.and_return([object1])
|
||||
stub_request(:get, 'https://api.github.com/repos/foo/bar/issues?per_page=100')
|
||||
.to_return(
|
||||
status: 200,
|
||||
body: [{ title: 'Issue 1' }].to_json,
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
link: '<https://api.github.com/repositories/1/issues?page=2&per_page=100>; rel="next"'
|
||||
}
|
||||
)
|
||||
|
||||
response = double(:response, data: [object2], rels: { next: nil })
|
||||
next_page = double(:next_page, get: response)
|
||||
stub_request(:get, 'https://api.github.com/repositories/1/issues?page=2&per_page=100')
|
||||
.to_return(
|
||||
status: 200,
|
||||
body: [{ title: 'Issue 2' }].to_json,
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
link: '<https://api.github.com/repositories/1/issues?page=3&per_page=100>; rel="next", ' \
|
||||
'<https://api.github.com/repositories/1/issues?page=2&per_page=100>; rel="prev"'
|
||||
}
|
||||
)
|
||||
|
||||
allow(client.octokit)
|
||||
.to receive(:last_response)
|
||||
.and_return(double(:last_response, rels: { next: next_page }))
|
||||
stub_request(:get, 'https://api.github.com/repositories/1/issues?page=3&per_page=100')
|
||||
.to_return(
|
||||
status: 200,
|
||||
body: [{ title: 'Issue 3' }].to_json,
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
link: '<https://api.github.com/repositories/1/issues?page=2&per_page=100>; rel="prev"'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
context 'without a block' do
|
||||
it 'returns an Enumerator' do
|
||||
expect(client.each_page(:foo)).to be_an_instance_of(Enumerator)
|
||||
expect(client.each_page(:issues, resume_url, 'foo/bar')).to be_an_instance_of(Enumerator)
|
||||
end
|
||||
|
||||
it 'the returned Enumerator returns Page objects' do
|
||||
enum = client.each_page(:foo)
|
||||
enum = client.each_page(:issues, resume_url, 'foo/bar')
|
||||
|
||||
page1 = enum.next
|
||||
page2 = enum.next
|
||||
page3 = enum.next
|
||||
|
||||
expect(page1).to be_an_instance_of(described_class::Page)
|
||||
expect(page2).to be_an_instance_of(described_class::Page)
|
||||
expect(page3).to be_an_instance_of(described_class::Page)
|
||||
|
||||
expect(page1.objects).to eq([object1])
|
||||
expect(page1.number).to eq(1)
|
||||
expect(page1.objects.map(&:to_h)).to eq([{ title: 'Issue 1' }])
|
||||
expect(page1.url).to eq(nil)
|
||||
|
||||
expect(page2.objects).to eq([object2])
|
||||
expect(page2.number).to eq(2)
|
||||
expect(page2.objects.map(&:to_h)).to eq([{ title: 'Issue 2' }])
|
||||
expect(page2.url).to eq('https://api.github.com/repositories/1/issues?page=2&per_page=100')
|
||||
|
||||
expect(page3.objects.map(&:to_h)).to eq([{ title: 'Issue 3' }])
|
||||
expect(page3.url).to eq('https://api.github.com/repositories/1/issues?page=3&per_page=100')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -232,25 +256,75 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
|
|||
it 'yields every retrieved page to the supplied block' do
|
||||
pages = []
|
||||
|
||||
client.each_page(:foo) { |page| pages << page }
|
||||
client.each_page(:issues, resume_url, 'foo/bar') { |page| pages << page }
|
||||
|
||||
expect(pages.size).to eq(3)
|
||||
|
||||
expect(pages[0]).to be_an_instance_of(described_class::Page)
|
||||
expect(pages[1]).to be_an_instance_of(described_class::Page)
|
||||
expect(pages[2]).to be_an_instance_of(described_class::Page)
|
||||
|
||||
expect(pages[0].objects.map(&:to_h)).to eq([{ title: 'Issue 1' }])
|
||||
expect(pages[0].url).to eq(nil)
|
||||
|
||||
expect(pages[1].objects.map(&:to_h)).to eq([{ title: 'Issue 2' }])
|
||||
expect(pages[1].url).to eq('https://api.github.com/repositories/1/issues?page=2&per_page=100')
|
||||
|
||||
expect(pages[2].objects.map(&:to_h)).to eq([{ title: 'Issue 3' }])
|
||||
expect(pages[2].url).to eq('https://api.github.com/repositories/1/issues?page=3&per_page=100')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a resume URL is passed' do
|
||||
let(:resume_url) { 'https://api.github.com/repositories/1/issues?page=2&per_page=100' }
|
||||
|
||||
it 'resumes the pagination from the provided URL' do
|
||||
pages = []
|
||||
|
||||
client.each_page(:issues, resume_url, 'foo/bar') { |page| pages << page }
|
||||
|
||||
expect(pages.size).to eq(2)
|
||||
|
||||
expect(pages[0]).to be_an_instance_of(described_class::Page)
|
||||
expect(pages[1]).to be_an_instance_of(described_class::Page)
|
||||
|
||||
expect(pages[0].objects).to eq([object1])
|
||||
expect(pages[0].number).to eq(1)
|
||||
expect(pages[0].objects.map(&:to_h)).to eq([{ title: 'Issue 2' }])
|
||||
expect(pages[0].url).to eq('https://api.github.com/repositories/1/issues?page=2&per_page=100')
|
||||
|
||||
expect(pages[1].objects).to eq([object2])
|
||||
expect(pages[1].number).to eq(2)
|
||||
expect(pages[1].objects.map(&:to_h)).to eq([{ title: 'Issue 3' }])
|
||||
expect(pages[1].url).to eq('https://api.github.com/repositories/1/issues?page=3&per_page=100')
|
||||
end
|
||||
end
|
||||
|
||||
it 'starts at the given page' do
|
||||
context 'when resume URL is an empty string' do
|
||||
let(:resume_url) { '' }
|
||||
|
||||
it 'does not resume the pagination' do
|
||||
pages = []
|
||||
|
||||
client.each_page(:foo, page: 2) { |page| pages << page }
|
||||
client.each_page(:issues, resume_url, 'foo/bar') { |page| pages << page }
|
||||
|
||||
expect(pages[0].number).to eq(2)
|
||||
expect(pages[1].number).to eq(3)
|
||||
expect(pages.size).to eq(3)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when next URL host does not match API URL host' do
|
||||
it 'raises InvalidURLError' do
|
||||
stub_request(:get, 'https://api.github.com/repos/foo/bar/issues?per_page=100')
|
||||
.to_return(
|
||||
status: 200,
|
||||
body: [{ title: 'Issue 1' }].to_json,
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
link: '<https://another.host.com>; rel="next"'
|
||||
}
|
||||
)
|
||||
|
||||
enum = client.each_page(:issues, nil, 'foo/bar')
|
||||
|
||||
enum.next
|
||||
|
||||
expect { enum.next }.to raise_error(Gitlab::GithubImport::Exceptions::InvalidURLError, 'Invalid pagination URL')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -113,14 +113,15 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter, feature_cat
|
|||
|
||||
describe '#each_object_to_import', :clean_gitlab_redis_shared_state do
|
||||
before do
|
||||
page = double(:page, objects: [pull_request], number: 1)
|
||||
page = instance_double(Gitlab::GithubImport::Client::Page, objects: [pull_request], url: nil)
|
||||
|
||||
expect(client)
|
||||
.to receive(:each_page)
|
||||
.with(
|
||||
:pull_requests,
|
||||
nil,
|
||||
'foo/bar',
|
||||
{ state: 'all', sort: 'created', direction: 'asc', page: 1 }
|
||||
{ state: 'all', sort: 'created', direction: 'asc' }
|
||||
)
|
||||
.and_yield(page)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointDiffNotesImporter,
|
|||
end
|
||||
|
||||
let(:note) { { id: 1 } }
|
||||
let(:page) { double(objects: [note], number: 1) }
|
||||
let(:page) { instance_double(Gitlab::GithubImport::Client::Page, objects: [note], url: nil) }
|
||||
|
||||
it 'fetches data' do
|
||||
expect(client)
|
||||
.to receive(:each_page)
|
||||
.exactly(:once) # ensure to be cached on the second call
|
||||
.with(:pull_request_comments, 'github/repo', merge_request.iid, { page: 1 })
|
||||
.with(:pull_request_comments, nil, 'github/repo', merge_request.iid, {})
|
||||
.and_yield(page)
|
||||
|
||||
expect { |b| subject.each_object_to_import(&b) }.to yield_with_args(note)
|
||||
|
|
@ -48,15 +48,17 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointDiffNotesImporter,
|
|||
).to eq(true)
|
||||
end
|
||||
|
||||
it 'skips cached pages' do
|
||||
Gitlab::Import::PageCounter
|
||||
.new(project, "merge_request/#{merge_request.id}/pull_request_comments")
|
||||
.set(2)
|
||||
it 'resumes from the last processed URL' do
|
||||
resume_url = 'https://api.github.com/repositories/1/pulls/999/comments?page=2'
|
||||
|
||||
Gitlab::Import::PageKeyset
|
||||
.new(project, "merge_request/#{merge_request.id}/pull_request_comments", ::Import::SOURCE_GITHUB)
|
||||
.set(resume_url)
|
||||
|
||||
expect(client)
|
||||
.to receive(:each_page)
|
||||
.exactly(:once) # ensure to be cached on the second call
|
||||
.with(:pull_request_comments, 'github/repo', merge_request.iid, { page: 2 })
|
||||
.with(:pull_request_comments, resume_url, 'github/repo', merge_request.iid, {})
|
||||
|
||||
subject.each_object_to_import {}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
it { expect(subject.collection_method).to eq(:issue_timeline) }
|
||||
end
|
||||
|
||||
describe '#page_counter_id' do
|
||||
it { expect(subject.page_counter_id(issuable)).to eq("issues/#{issuable.iid}/issue_timeline") }
|
||||
describe '#page_keyset_id' do
|
||||
it { expect(subject.page_keyset_id(issuable)).to eq("issues/#{issuable.iid}/issue_timeline") }
|
||||
end
|
||||
|
||||
describe '#id_for_already_imported_cache' do
|
||||
|
|
@ -47,8 +47,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
|
||||
describe '#collection_options' do
|
||||
it do
|
||||
expect(subject.collection_options)
|
||||
.to eq({ state: 'all', sort: 'created', direction: 'asc' })
|
||||
expect(subject.collection_options).to eq({})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -86,28 +85,48 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
end
|
||||
|
||||
describe '#each_object_to_import', :clean_gitlab_redis_shared_state do
|
||||
let(:issue_event) do
|
||||
struct = Struct.new(:id, :event, :created_at, :issue, keyword_init: true)
|
||||
struct.new(id: 1, event: event_name, created_at: '2022-04-26 18:30:53 UTC')
|
||||
end
|
||||
|
||||
let(:event_name) { 'closed' }
|
||||
|
||||
let(:page_events) { [issue_event] }
|
||||
|
||||
let(:page) do
|
||||
instance_double(
|
||||
Gitlab::GithubImport::Client::Page,
|
||||
number: 1, objects: page_events
|
||||
)
|
||||
let(:event_1) do
|
||||
{
|
||||
id: 1,
|
||||
event: event_name,
|
||||
created_at: '2022-04-26 18:30:53 UTC'
|
||||
}
|
||||
end
|
||||
|
||||
let(:page_counter) { instance_double(Gitlab::Import::PageCounter) }
|
||||
let(:event_2) do
|
||||
{
|
||||
id: 2,
|
||||
event: event_name,
|
||||
created_at: '2022-04-26 18:30:53 UTC'
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
allow(client).to receive(:each_page).once.with(:issue_timeline,
|
||||
project.import_source, issuable.iid, { state: 'all', sort: 'created', direction: 'asc', page: 1 }
|
||||
).and_yield(page)
|
||||
allow(client)
|
||||
.to receive(:with_rate_limit)
|
||||
.and_yield
|
||||
|
||||
stub_request(:get,
|
||||
"https://api.github.com/repos/foo/bar/issues/1/timeline?per_page=100")
|
||||
.to_return(
|
||||
status: 200,
|
||||
body: [event_1].to_json,
|
||||
headers: {
|
||||
'Content-Type' => 'application/json',
|
||||
'Link' => '<https://api.github.com/repositories/1/issues/1/timelint?per_page=100&page=2>; rel="next"'
|
||||
}
|
||||
)
|
||||
|
||||
stub_request(:get,
|
||||
"https://api.github.com/repositories/1/issues/1/timelint?per_page=100&page=2")
|
||||
.to_return(
|
||||
status: 200,
|
||||
body: [event_2].to_json,
|
||||
headers: {
|
||||
'Content-Type' => 'application/json'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
context 'with issues' do
|
||||
|
|
@ -116,9 +135,61 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
subject.each_object_to_import do |object|
|
||||
expect(object).to eq(
|
||||
{
|
||||
id: 1,
|
||||
event: 'closed',
|
||||
created_at: '2022-04-26 18:30:53 UTC',
|
||||
id: counter + 1,
|
||||
event: event_name,
|
||||
created_at: '2022-04-26 18:30:53.000000000 +0000',
|
||||
issue: {
|
||||
number: issuable.iid,
|
||||
pull_request: false
|
||||
}
|
||||
}
|
||||
)
|
||||
counter += 1
|
||||
end
|
||||
expect(counter).to eq 2
|
||||
end
|
||||
end
|
||||
|
||||
context 'with merge requests' do
|
||||
let!(:issuable) { create(:merge_request, source_project: project, target_project: project) }
|
||||
|
||||
it 'imports each merge request event page by page' do
|
||||
counter = 0
|
||||
subject.each_object_to_import do |object|
|
||||
expect(object).to eq(
|
||||
{
|
||||
id: counter + 1,
|
||||
event: event_name,
|
||||
created_at: '2022-04-26 18:30:53.000000000 +0000',
|
||||
issue: {
|
||||
number: issuable.iid,
|
||||
pull_request: true
|
||||
}
|
||||
}
|
||||
)
|
||||
counter += 1
|
||||
end
|
||||
expect(counter).to eq 2
|
||||
end
|
||||
end
|
||||
|
||||
context 'when page key set stores an URL' do
|
||||
before do
|
||||
allow_next_instance_of(Gitlab::Import::PageKeyset) do |page_keyset|
|
||||
allow(page_keyset).to receive(:current).and_return(
|
||||
"https://api.github.com/repositories/1/issues/1/timelint?per_page=100&page=2"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it 'resumes from the stored URL' do
|
||||
counter = 0
|
||||
subject.each_object_to_import do |object|
|
||||
expect(object).to eq(
|
||||
{
|
||||
id: event_2[:id],
|
||||
event: event_name,
|
||||
created_at: '2022-04-26 18:30:53.000000000 +0000',
|
||||
issue: {
|
||||
number: issuable.iid,
|
||||
pull_request: false
|
||||
|
|
@ -131,20 +202,20 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
end
|
||||
end
|
||||
|
||||
context 'with merge requests' do
|
||||
let!(:issuable) { create(:merge_request, source_project: project, target_project: project) }
|
||||
context 'when event is already processed' do
|
||||
it "doesn't process the event" do
|
||||
subject.mark_as_imported(event_1)
|
||||
|
||||
it 'imports each merge request event page by page' do
|
||||
counter = 0
|
||||
subject.each_object_to_import do |object|
|
||||
expect(object).to eq(
|
||||
{
|
||||
id: 1,
|
||||
event: 'closed',
|
||||
created_at: '2022-04-26 18:30:53 UTC',
|
||||
id: event_2[:id],
|
||||
event: event_name,
|
||||
created_at: '2022-04-26 18:30:53.000000000 +0000',
|
||||
issue: {
|
||||
number: issuable.iid,
|
||||
pull_request: true
|
||||
pull_request: false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
@ -154,48 +225,10 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
end
|
||||
end
|
||||
|
||||
it 'triggers page number increment' do
|
||||
expect(Gitlab::Import::PageCounter)
|
||||
.to receive(:new).with(project, 'issues/1/issue_timeline')
|
||||
.and_return(page_counter)
|
||||
expect(page_counter).to receive(:current).and_return(1)
|
||||
expect(page_counter)
|
||||
.to receive(:set).with(page.number).and_return(true)
|
||||
|
||||
counter = 0
|
||||
subject.each_object_to_import { counter += 1 }
|
||||
expect(counter).to eq 1
|
||||
end
|
||||
|
||||
context 'when page is already processed' do
|
||||
before do
|
||||
page_counter = Gitlab::Import::PageCounter.new(
|
||||
project, subject.page_counter_id(issuable)
|
||||
)
|
||||
page_counter.set(page.number)
|
||||
end
|
||||
|
||||
it "doesn't process this page" do
|
||||
counter = 0
|
||||
subject.each_object_to_import { counter += 1 }
|
||||
expect(counter).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'when event is already processed' do
|
||||
it "doesn't process this event" do
|
||||
subject.mark_as_imported(issue_event)
|
||||
|
||||
counter = 0
|
||||
subject.each_object_to_import { counter += 1 }
|
||||
expect(counter).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'when event is not supported' do
|
||||
let(:event_name) { 'not_supported_event' }
|
||||
|
||||
it "doesn't process this event" do
|
||||
it "doesn't process the event" do
|
||||
counter = 0
|
||||
subject.each_object_to_import { counter += 1 }
|
||||
expect(counter).to eq 0
|
||||
|
|
@ -204,7 +237,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
|
||||
describe 'increment object counter' do
|
||||
it 'increments counter' do
|
||||
expect(Gitlab::GithubImport::ObjectCounter).to receive(:increment).with(project, :issue_event, :fetched)
|
||||
expect(Gitlab::GithubImport::ObjectCounter).to receive(:increment).with(project, :issue_event, :fetched).twice
|
||||
|
||||
subject.each_object_to_import { |event| event }
|
||||
end
|
||||
|
|
@ -217,7 +250,8 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
end
|
||||
|
||||
it 'increments the mapped fetched counter' do
|
||||
expect(Gitlab::GithubImport::ObjectCounter).to receive(:increment).with(project, 'custom_type', :fetched)
|
||||
expect(Gitlab::GithubImport::ObjectCounter).to receive(:increment).with(project, 'custom_type',
|
||||
:fetched).twice
|
||||
|
||||
subject.each_object_to_import { |event| event }
|
||||
end
|
||||
|
|
@ -227,14 +261,17 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
describe 'save events' do
|
||||
shared_examples 'saves event' do
|
||||
it 'saves event' do
|
||||
expect(Gitlab::GithubImport::Representation::IssueEvent).to receive(:from_api_response).with(issue_event.to_h)
|
||||
.and_call_original
|
||||
expect(Gitlab::GithubImport::Representation::IssueEvent).to receive(:from_api_response).with(
|
||||
a_hash_including(id: event_1[:id])).and_call_original
|
||||
|
||||
expect(Gitlab::GithubImport::Representation::IssueEvent).to receive(:from_api_response).with(
|
||||
a_hash_including(id: event_2[:id])).and_call_original
|
||||
|
||||
expect_next_instance_of(Gitlab::GithubImport::EventsCache) do |events_cache|
|
||||
expect(events_cache).to receive(:add).with(
|
||||
issuable,
|
||||
an_instance_of(Gitlab::GithubImport::Representation::IssueEvent)
|
||||
)
|
||||
).twice
|
||||
end
|
||||
|
||||
subject.each_object_to_import { |event| event }
|
||||
|
|
@ -313,10 +350,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
|
|||
}
|
||||
]
|
||||
|
||||
endpoint = 'https://api.github.com/repos/foo/bar/issues/1/timeline' \
|
||||
'?direction=asc&page=1&per_page=100&sort=created&state=all'
|
||||
|
||||
stub_request(:get, endpoint)
|
||||
stub_request(:get, 'https://api.github.com/repos/foo/bar/issues/1/timeline?per_page=100')
|
||||
.to_return(status: 200, body: events.to_json, headers: { 'Content-Type' => 'application/json' })
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -360,7 +360,7 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling, feature_category: :impo
|
|||
end
|
||||
end
|
||||
|
||||
describe '#each_object_to_import' do
|
||||
describe '#each_object_to_import', :clean_gitlab_redis_shared_state do
|
||||
let(:importer) { importer_class.new(project, client) }
|
||||
let(:object) { {} }
|
||||
let(:object_counter_class) { Gitlab::GithubImport::ObjectCounter }
|
||||
|
|
@ -372,17 +372,16 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling, feature_category: :impo
|
|||
end
|
||||
|
||||
it 'yields every object to import' do
|
||||
page = double(:page, objects: [object], number: 1)
|
||||
page = instance_double(Gitlab::GithubImport::Client::Page, objects: [object], url: nil)
|
||||
|
||||
expect(client)
|
||||
.to receive(:each_page)
|
||||
.with(:issues, 'foo/bar', { state: 'all', page: 1 })
|
||||
.with(:issues, nil, 'foo/bar', { state: 'all' })
|
||||
.and_yield(page)
|
||||
|
||||
expect(importer.page_counter)
|
||||
expect(importer.page_keyset)
|
||||
.to receive(:set)
|
||||
.with(1)
|
||||
.and_return(true)
|
||||
.with(nil)
|
||||
|
||||
expect(importer)
|
||||
.to receive(:already_imported?)
|
||||
|
|
@ -400,22 +399,27 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling, feature_category: :impo
|
|||
.to yield_with_args(object)
|
||||
end
|
||||
|
||||
it 'resumes from the last page' do
|
||||
page = double(:page, objects: [object], number: 2)
|
||||
it 'resumes from the last processed page URL' do
|
||||
last_processed_url = 'https://api.github.com/repositories/1/issues?page=2'
|
||||
|
||||
expect(importer.page_counter)
|
||||
page = instance_double(
|
||||
Gitlab::GithubImport::Client::Page,
|
||||
objects: [object],
|
||||
url: last_processed_url
|
||||
)
|
||||
|
||||
expect(importer.page_keyset)
|
||||
.to receive(:current)
|
||||
.and_return(2)
|
||||
.and_return(last_processed_url)
|
||||
|
||||
expect(client)
|
||||
.to receive(:each_page)
|
||||
.with(:issues, 'foo/bar', { state: 'all', page: 2 })
|
||||
.with(:issues, last_processed_url, 'foo/bar', { state: 'all' })
|
||||
.and_yield(page)
|
||||
|
||||
expect(importer.page_counter)
|
||||
expect(importer.page_keyset)
|
||||
.to receive(:set)
|
||||
.with(2)
|
||||
.and_return(true)
|
||||
.with(last_processed_url)
|
||||
|
||||
expect(importer)
|
||||
.to receive(:already_imported?)
|
||||
|
|
@ -433,36 +437,14 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling, feature_category: :impo
|
|||
.to yield_with_args(object)
|
||||
end
|
||||
|
||||
it 'does not yield any objects if the page number was not set' do
|
||||
page = double(:page, objects: [object], number: 1)
|
||||
|
||||
expect(client)
|
||||
.to receive(:each_page)
|
||||
.with(:issues, 'foo/bar', { state: 'all', page: 1 })
|
||||
.and_yield(page)
|
||||
|
||||
expect(importer.page_counter)
|
||||
.to receive(:set)
|
||||
.with(1)
|
||||
.and_return(false)
|
||||
|
||||
expect { |b| importer.each_object_to_import(&b) }
|
||||
.not_to yield_control
|
||||
end
|
||||
|
||||
it 'does not yield the object if it was already imported' do
|
||||
page = double(:page, objects: [object], number: 1)
|
||||
page = instance_double(Gitlab::GithubImport::Client::Page, objects: [object], url: nil)
|
||||
|
||||
expect(client)
|
||||
.to receive(:each_page)
|
||||
.with(:issues, 'foo/bar', { state: 'all', page: 1 })
|
||||
.with(:issues, nil, 'foo/bar', { state: 'all' })
|
||||
.and_yield(page)
|
||||
|
||||
expect(importer.page_counter)
|
||||
.to receive(:set)
|
||||
.with(1)
|
||||
.and_return(true)
|
||||
|
||||
expect(importer)
|
||||
.to receive(:already_imported?)
|
||||
.with(object)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ RSpec.describe Gitlab::GithubImport::SingleEndpointNotesImporting, feature_categ
|
|||
it { expect { importer_instance.parent_imported_cache_key }.to raise_error(NotImplementedError) }
|
||||
end
|
||||
|
||||
describe '#page_counter_id' do
|
||||
it { expect { importer_instance.page_counter_id(build(:merge_request)) }.to raise_error(NotImplementedError) }
|
||||
describe '#page_keyset_id' do
|
||||
it { expect { importer_instance.page_keyset_id(build(:merge_request)) }.to raise_error(NotImplementedError) }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ RSpec.describe Gitlab::Highlight do
|
|||
it 'increments usage counter', :prometheus do
|
||||
described_class.highlight(file_name, content)
|
||||
|
||||
gitlab_highlight_usage_counter = Gitlab::Metrics.registry.get(:gitlab_highlight_usage)
|
||||
gitlab_highlight_usage_counter = Gitlab::Metrics.client.get(:gitlab_highlight_usage)
|
||||
|
||||
expect(gitlab_highlight_usage_counter.get(used_on: :blob)).to eq(1)
|
||||
expect(gitlab_highlight_usage_counter.get(used_on: :diff)).to eq(0)
|
||||
|
|
@ -154,7 +154,7 @@ RSpec.describe Gitlab::Highlight do
|
|||
it 'increments usage counter', :prometheus do
|
||||
described_class.highlight(file_name, content, used_on: :diff)
|
||||
|
||||
gitlab_highlight_usage_counter = Gitlab::Metrics.registry.get(:gitlab_highlight_usage)
|
||||
gitlab_highlight_usage_counter = Gitlab::Metrics.client.get(:gitlab_highlight_usage)
|
||||
|
||||
expect(gitlab_highlight_usage_counter.get(used_on: :diff)).to eq(1)
|
||||
expect(gitlab_highlight_usage_counter.get(used_on: :blob)).to eq(0)
|
||||
|
|
|
|||
|
|
@ -11,10 +11,6 @@ RSpec.describe ::Gitlab::Metrics::Labkit, :prometheus, feature_category: :scalab
|
|||
|
||||
let(:client) { all_metrics.client }
|
||||
|
||||
after do
|
||||
all_metrics.clear_errors!
|
||||
end
|
||||
|
||||
describe '#reset_registry!' do
|
||||
it 'clears existing metrics' do
|
||||
counter = client.counter(:test, 'test metric')
|
||||
|
|
@ -29,16 +25,20 @@ RSpec.describe ::Gitlab::Metrics::Labkit, :prometheus, feature_category: :scalab
|
|||
end
|
||||
|
||||
describe '#error_detected!' do
|
||||
after do
|
||||
Labkit::Metrics::Client.enable!
|
||||
end
|
||||
|
||||
it 'disables Prometheus metrics' do
|
||||
stub_application_setting(prometheus_metrics_enabled: true)
|
||||
|
||||
expect(all_metrics.error?).to be_falsey
|
||||
expect(client.enabled?).to be_truthy
|
||||
expect(all_metrics.prometheus_metrics_enabled?).to be_truthy
|
||||
|
||||
all_metrics.error_detected!
|
||||
|
||||
expect(client.enabled?).to be_falsey
|
||||
expect(all_metrics.prometheus_metrics_enabled?).to be_falsey
|
||||
expect(all_metrics.error?).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ::Gitlab::Metrics::Prometheus, :prometheus, feature_category: :scalability do
|
||||
let(:all_metrics) do
|
||||
Class.new do
|
||||
include ::Gitlab::Metrics::Prometheus
|
||||
end
|
||||
end
|
||||
|
||||
let(:registry) { all_metrics.registry }
|
||||
|
||||
after do
|
||||
all_metrics.clear_errors!
|
||||
end
|
||||
|
||||
describe '#reset_registry!' do
|
||||
it 'clears existing metrics' do
|
||||
registry.counter(:test, 'test metric')
|
||||
|
||||
expect(registry.metrics.count).to eq(1)
|
||||
|
||||
all_metrics.reset_registry!
|
||||
|
||||
expect(all_metrics.registry.metrics.count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#error_detected!' do
|
||||
before do
|
||||
allow(all_metrics).to receive(:metrics_folder_present?).and_return(true)
|
||||
stub_application_setting(prometheus_metrics_enabled: true)
|
||||
end
|
||||
|
||||
it 'disables Prometheus metrics' do
|
||||
expect(all_metrics.error?).to be_falsey
|
||||
expect(all_metrics.prometheus_metrics_enabled?).to be_truthy
|
||||
|
||||
all_metrics.error_detected!
|
||||
|
||||
expect(all_metrics.prometheus_metrics_enabled?).to be_falsey
|
||||
expect(all_metrics.error?).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -11,12 +11,6 @@ RSpec.describe Gitlab::Metrics, :prometheus, feature_category: :scalability do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.enabled?' do
|
||||
it 'returns a boolean' do
|
||||
expect(described_class.enabled?).to be_in([true, false])
|
||||
end
|
||||
end
|
||||
|
||||
describe '.prometheus_metrics_enabled?' do
|
||||
subject { described_class.prometheus_metrics_enabled? }
|
||||
|
||||
|
|
@ -25,7 +19,6 @@ RSpec.describe Gitlab::Metrics, :prometheus, feature_category: :scalability do
|
|||
context 'when Gitlab::CurrentSettings.prometheus_metrics_enabled is enabled' do
|
||||
before do
|
||||
allow(Gitlab::CurrentSettings).to receive(:prometheus_metrics_enabled).and_return(true)
|
||||
allow(described_class).to receive(:metrics_folder_present?).and_return(true)
|
||||
Labkit::Metrics::Client.enable!
|
||||
end
|
||||
|
||||
|
|
@ -35,7 +28,6 @@ RSpec.describe Gitlab::Metrics, :prometheus, feature_category: :scalability do
|
|||
context 'when Gitlab::CurrentSettings.prometheus_metrics_enabled is false' do
|
||||
before do
|
||||
allow(Gitlab::CurrentSettings).to receive(:prometheus_metrics_enabled).and_return(false)
|
||||
allow(described_class).to receive(:metrics_folder_present?).and_return(true)
|
||||
Labkit::Metrics::Client.enable!
|
||||
end
|
||||
|
||||
|
|
@ -45,7 +37,6 @@ RSpec.describe Gitlab::Metrics, :prometheus, feature_category: :scalability do
|
|||
context 'when metrics are disabled' do
|
||||
before do
|
||||
allow(Gitlab::CurrentSettings).to receive(:prometheus_metrics_enabled).and_return(true)
|
||||
allow(described_class).to receive(:metrics_folder_present?).and_return(false)
|
||||
Labkit::Metrics::Client.disable!
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:project) { create(:project, namespace: group) }
|
||||
|
||||
before do
|
||||
stub_pages_setting(host: 'example.com')
|
||||
|
|
@ -30,6 +31,16 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
|
|||
create(:pages_deployment, project: project)
|
||||
end
|
||||
|
||||
it 'passes the correct data to the virtual domain' do
|
||||
expect(::Pages::VirtualDomain).to receive(:new).with(
|
||||
projects: [project],
|
||||
namespace: project.namespace,
|
||||
domain: pages_domain
|
||||
).and_call_original
|
||||
|
||||
expect { virtual_domain }.not_to raise_error
|
||||
end
|
||||
|
||||
it 'returns the virtual domain' do
|
||||
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
|
||||
expect(virtual_domain.lookup_paths.length).to eq(1)
|
||||
|
|
@ -47,18 +58,24 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
|
|||
end
|
||||
|
||||
context 'when host is a namespace domain' do
|
||||
context 'when there are no pages deployed for the project' do
|
||||
it 'returns no result if the provided host is not subdomain of the Pages host' do
|
||||
virtual_domain = described_class.new("#{project.namespace.path}.something.io").execute
|
||||
subject(:virtual_domain) { described_class.new(domain).execute }
|
||||
|
||||
expect(virtual_domain).to eq(nil)
|
||||
context 'when there are no pages deployed for the project' do
|
||||
context 'if the provided host is not subdomain of the Pages host' do
|
||||
let(:domain) { "#{project.namespace.path}.something.io" }
|
||||
|
||||
it 'returns no result' do
|
||||
expect(virtual_domain).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns the virual domain with no lookup_paths' do
|
||||
virtual_domain = described_class.new("#{project.namespace.path}.example.com").execute
|
||||
context 'if the provided host is subdomain of the Pages host' do
|
||||
let(:domain) { "#{project.namespace.path}.example.com" }
|
||||
|
||||
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
|
||||
expect(virtual_domain.lookup_paths.length).to eq(0)
|
||||
it 'returns the virtual domain with no lookup_paths' do
|
||||
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
|
||||
expect(virtual_domain.lookup_paths.length).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -68,26 +85,42 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
|
|||
project.namespace.update!(path: 'topNAMEspace')
|
||||
end
|
||||
|
||||
it 'returns no result if the provided host is not subdomain of the Pages host' do
|
||||
virtual_domain = described_class.new("#{project.namespace.path}.something.io").execute
|
||||
context 'if the provided host is not subdomain of the Pages host' do
|
||||
let(:domain) { "#{project.namespace.path}.something.io" }
|
||||
|
||||
expect(virtual_domain).to eq(nil)
|
||||
it 'returns no result' do
|
||||
expect(virtual_domain).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns the virual domain when there are pages deployed for the project' do
|
||||
virtual_domain = described_class.new("#{project.namespace.path}.example.com").execute
|
||||
context 'if the provided host is subdomain of the Pages host' do
|
||||
let(:domain) { "#{project.namespace.path}.example.com" }
|
||||
|
||||
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
|
||||
expect(virtual_domain.lookup_paths.length).to eq(1)
|
||||
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
|
||||
it 'passes the correct data to the virtual domain' do
|
||||
expect(::Pages::VirtualDomain).to receive(:new).with(
|
||||
projects: [project],
|
||||
namespace: project.namespace,
|
||||
trim_prefix: project.namespace.path
|
||||
).and_call_original
|
||||
|
||||
expect { virtual_domain }.not_to raise_error
|
||||
end
|
||||
|
||||
it 'returns the virtual domain when there are pages deployed for the project' do
|
||||
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
|
||||
expect(virtual_domain.lookup_paths.length).to eq(1)
|
||||
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
|
||||
end
|
||||
end
|
||||
|
||||
it 'finds domain with case-insensitive' do
|
||||
virtual_domain = described_class.new("#{project.namespace.path}.Example.com").execute
|
||||
context 'if the provided host contains capitals' do
|
||||
let(:domain) { "#{project.namespace.path}.Example.com" }
|
||||
|
||||
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
|
||||
expect(virtual_domain.lookup_paths.length).to eq(1)
|
||||
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
|
||||
it 'finds domain case-insensitive' do
|
||||
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
|
||||
expect(virtual_domain.lookup_paths.length).to eq(1)
|
||||
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -115,7 +148,16 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
|
|||
create(:pages_deployment, project: project)
|
||||
end
|
||||
|
||||
it 'returns the virual domain when there are pages deployed for the project' do
|
||||
it 'passes the correct data to the virtual domain' do
|
||||
expect(::Pages::VirtualDomain).to receive(:new).with(
|
||||
projects: [project],
|
||||
namespace: project.namespace
|
||||
).and_call_original
|
||||
|
||||
expect { virtual_domain }.not_to raise_error
|
||||
end
|
||||
|
||||
it 'returns the virtual domain when there are pages deployed for the project' do
|
||||
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
|
||||
expect(virtual_domain.lookup_paths.length).to eq(1)
|
||||
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
|
||||
|
|
|
|||
|
|
@ -783,6 +783,7 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
|
|||
it { is_expected.not_to match('my package name') }
|
||||
it { is_expected.not_to match('foo.bar.baz-2.0-20190901~47283-1') }
|
||||
it { is_expected.not_to match('!!()()') }
|
||||
it { is_expected.not_to match('myfile@1.1.tar.gz') }
|
||||
end
|
||||
|
||||
describe '.generic_package_file_name_regex' do
|
||||
|
|
@ -792,6 +793,7 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
|
|||
it { is_expected.to match('foo') }
|
||||
it { is_expected.to match('foo.bar.baz-2.0-20190901.47283-1.jar') }
|
||||
it { is_expected.to match('foo.bar.baz-2.0-20190901~47283-1') }
|
||||
it { is_expected.to match('myfile@1.1.tar.gz') }
|
||||
it { is_expected.not_to match('../../foo') }
|
||||
it { is_expected.not_to match('..\..\foo') }
|
||||
it { is_expected.not_to match('%2f%2e%2e%2f%2essh%2fauthorized_keys') }
|
||||
|
|
@ -800,6 +802,8 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
|
|||
it { is_expected.not_to match('!!()()') }
|
||||
it { is_expected.not_to match('~/../../filename') }
|
||||
it { is_expected.not_to match('filename~') }
|
||||
it { is_expected.not_to match('@filename') }
|
||||
it { is_expected.not_to match('filename@') }
|
||||
end
|
||||
|
||||
describe '.prefixed_semver_regex' do
|
||||
|
|
@ -1158,4 +1162,15 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
|
|||
it { is_expected.to match('1.0-SNAPSHOT_v1_snapshot edited') }
|
||||
it { is_expected.not_to match('!!()()') }
|
||||
end
|
||||
|
||||
describe '.helm_index_app_version_quote_regex' do
|
||||
subject { described_class.helm_index_app_version_quote_regex }
|
||||
|
||||
it { is_expected.to match('appVersion: master') }
|
||||
it { is_expected.to match('appVersion: 4852e000') }
|
||||
it { is_expected.to match('appVersion: v1.0.0') }
|
||||
it { is_expected.not_to match('apiVersion: master') }
|
||||
it { is_expected.not_to match('apiVersion: "4852e000"') }
|
||||
it { is_expected.not_to match('apiVersion: \'v1.0.0\'') }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ RSpec.describe LooseForeignKeys::ModificationTracker, feature_category: :databas
|
|||
|
||||
describe '#add_deletions' do
|
||||
it 'increments a Prometheus counter' do
|
||||
counter = Gitlab::Metrics.registry.get(:loose_foreign_key_deletions)
|
||||
counter = Gitlab::Metrics.client.get(:loose_foreign_key_deletions)
|
||||
|
||||
subject.add_deletions(:users, 4)
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ RSpec.describe LooseForeignKeys::ModificationTracker, feature_category: :databas
|
|||
|
||||
describe '#add_updates' do
|
||||
it 'increments a Prometheus counter' do
|
||||
counter = Gitlab::Metrics.registry.get(:loose_foreign_key_updates)
|
||||
counter = Gitlab::Metrics.client.get(:loose_foreign_key_updates)
|
||||
|
||||
subject.add_updates(:users, 4)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ RSpec.describe Packages::Generic::Package, type: :model, feature_category: :pack
|
|||
it { is_expected.not_to allow_value('my file name').for(:name) }
|
||||
it { is_expected.not_to allow_value('!!().for(:name)().for(:name)').for(:name) }
|
||||
it { is_expected.not_to allow_value('test-packagename~with-tildes').for(:name) }
|
||||
it { is_expected.not_to allow_value('package-name-with-at@1.0.tar.gz').for(:name) }
|
||||
end
|
||||
|
||||
describe '#version' do
|
||||
|
|
|
|||
|
|
@ -517,21 +517,52 @@ RSpec.describe API::GenericPackages, feature_category: :package_registry do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when there is + sign is in filename' do
|
||||
it 'creates a package and package file with filename' do
|
||||
headers = workhorse_headers.merge(auth_header)
|
||||
context 'with special characters in filename' do
|
||||
where(:symbol, :file_name) do
|
||||
[
|
||||
['+', 'my+file.tar.gz'],
|
||||
['~', 'my~file.tar.gz'],
|
||||
['@', 'myfile@1.1.tar.gz']
|
||||
]
|
||||
end
|
||||
|
||||
upload_file(params, headers, file_name: 'my+file.tar.gz')
|
||||
with_them do
|
||||
it "creates package with #{params[:symbol]} in the filename", :aggregate_failures do
|
||||
headers = workhorse_headers.merge(auth_header)
|
||||
|
||||
expect do
|
||||
upload_file(params, headers, file_name:)
|
||||
end.to change { ::Packages::Generic::Package.for_projects(project).count }.by(1)
|
||||
|
||||
aggregate_failures do
|
||||
package = ::Packages::Generic::Package.for_projects(project).last
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(package.package_files.last.file_name).to eq('my+file.tar.gz')
|
||||
expect(project.package_files.find_by(file_name:)).not_to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when filename contains @ or ~ symbol at beginning or end' do
|
||||
where(:symbol, :file_name, :description) do
|
||||
[
|
||||
['@', 'myfile1.1.tar.gz@', 'at the end'],
|
||||
['@', '@myfile1.1.tar.gz', 'at the beginning'],
|
||||
['~', 'myfile.tar.gz~', 'at the end'],
|
||||
['~', '~myfile.tar.gz', 'at the beginning']
|
||||
]
|
||||
end
|
||||
|
||||
with_them do
|
||||
it "returns a bad request when #{params[:symbol]} is #{params[:description]} of filename",
|
||||
:aggregate_failures do
|
||||
headers = workhorse_headers.merge(personal_access_token_header)
|
||||
|
||||
upload_file(params, headers, file_name: file_name)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when valid personal access token is used' do
|
||||
it_behaves_like 'creates a package and package file' do
|
||||
let(:auth_header) { personal_access_token_header }
|
||||
|
|
|
|||
|
|
@ -52,6 +52,36 @@ RSpec.describe API::HelmPackages, feature_category: :package_registry do
|
|||
|
||||
it_behaves_like 'returning response status', :success
|
||||
end
|
||||
|
||||
context 'when helm metadata has appVersion' do
|
||||
subject(:api_request) { get api(url) }
|
||||
|
||||
where(:app_version, :expected_app_version) do
|
||||
'4852e000' | "\"4852e000\""
|
||||
'1.0.0' | "\"1.0.0\""
|
||||
'v1.0.0' | "\"v1.0.0\""
|
||||
'master' | "\"master\""
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
Packages::Helm::FileMetadatum.where(project_id: project_id).update_all(
|
||||
metadata: {
|
||||
'name' => 'Package Name',
|
||||
'version' => '1.0.0',
|
||||
'apiVersion' => 'v2',
|
||||
'appVersion' => app_version
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns yaml content with quoted appVersion' do
|
||||
api_request
|
||||
|
||||
expect(response.body).to include("appVersion: #{expected_app_version}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v4/projects/:id/packages/helm/:channel/charts/:file_name.tgz' do
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue