Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-07-08 15:11:55 +00:00
parent b092843664
commit 7c1d6f125e
108 changed files with 1360 additions and 1138 deletions

View File

@ -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'

View File

@ -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'

View File

@ -1 +1 @@
403b947e4d6bcaa170535e7972a536a2ab21b5d4
09aa77d55b90fa51939ea12867eb2aaf43c61ee2

View File

@ -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"

View File

@ -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')">

View File

@ -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,
},
});
},
});
};

View File

@ -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>

View File

@ -120,6 +120,7 @@ export default {
return;
}
this.$emit('onGetNewRunnerId', runner.id);
this.$emit('next');
// destroy the alert
createAlert({ message: null }).dismiss();

View File

@ -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>

View File

@ -170,6 +170,7 @@
"EpicIssue",
"Issue",
"MergeRequest",
"ProjectComplianceViolation",
"Snippet",
"Vulnerability",
"WikiPage"

View File

@ -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>

View File

@ -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"

View File

@ -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 }">

View File

@ -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) {

View File

@ -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">

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 } }

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
5be772a7c7dadbeb607eed18fa48e4f8d0a65a143dc529ed9720b713bc57923d

View File

@ -0,0 +1 @@
bcfd87720663d2f53b52311657ff2c3b138f183af2991c59d30871109e17e9f4

View File

@ -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;

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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 \

View File

@ -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.
-->

View File

@ -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 \

View File

@ -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

View File

@ -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). |

View File

@ -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`

View File

@ -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. |

View File

@ -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. |

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -8,6 +8,8 @@ module Gitlab
NotImplementedError = Class.new(StandardError)
NoteableNotFound = Class.new(StandardError)
InvalidURLError = Class.new(StandardError)
end
end
end

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);
});
});
});

View File

@ -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

View File

@ -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');

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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 }

View File

@ -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