Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
274a42ccfa
commit
0847321aee
|
|
@ -27,4 +27,8 @@ Please refer to the [Resolution guidance](https://about.gitlab.com/handbook/engi
|
|||
|
||||
Once the flaky failure has been fixed on the default branch, open merge requests to cherry-pick the fix to the active stable branches.
|
||||
|
||||
### Logs
|
||||
|
||||
<!-- Add here failing job logs -->
|
||||
|
||||
/label ~"type::maintenance" ~"failure::flaky-test" ~"priority::3" ~"severity::3"
|
||||
|
|
|
|||
|
|
@ -21,4 +21,8 @@ Please read the below documentations for a workflow of triaging and resolving br
|
|||
|
||||
Please refer to the [Resolution guidance](https://about.gitlab.com/handbook/engineering/workflow/#resolution-of-broken-master) to learn more about resolution of broken master.
|
||||
|
||||
### Logs
|
||||
|
||||
<!-- Add here failing job logs -->
|
||||
|
||||
/label ~"master:broken" ~"Engineering Productivity" ~"priority::1" ~"severity::1" ~"type::maintenance" ~"maintenance::pipelines"
|
||||
|
|
|
|||
|
|
@ -1025,3 +1025,10 @@ RSpec/FactoryBot/LocalStaticAssignment:
|
|||
|
||||
Rails/TransactionExitStatement:
|
||||
Enabled: true
|
||||
|
||||
Search/AvoidCheckingFinishedOnDeprecatedMigrations:
|
||||
Include:
|
||||
- 'ee/app/models/**/*.rb'
|
||||
- 'ee/lib/elastic/**/*.rb'
|
||||
- 'ee/lib/gitlab/elastic/**/*.rb'
|
||||
- 'ee/spec/support/helpers/elasticsearch_helpers.rb'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
Search/AvoidCheckingFinishedOnDeprecatedMigrations:
|
||||
Details: grace period
|
||||
|
|
@ -16,7 +16,7 @@ import {
|
|||
import * as Sentry from '@sentry/browser';
|
||||
import { isEqual, isEmpty, omit } from 'lodash';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
|
||||
import { PROMO_URL, DOCS_URL_IN_EE_DIR } from 'jh_else_ce/lib/utils/url_utility';
|
||||
import {
|
||||
integrationTypes,
|
||||
integrationSteps,
|
||||
|
|
@ -38,6 +38,7 @@ export default {
|
|||
placeholders: {
|
||||
prometheus: targetPrometheusUrlPlaceholder,
|
||||
},
|
||||
incidentManagementDocsLink: `${DOCS_URL_IN_EE_DIR}/operations/incident_management/integrations.html#configuration`,
|
||||
JSON_VALIDATE_DELAY,
|
||||
typeSet,
|
||||
integrationSteps,
|
||||
|
|
@ -617,7 +618,7 @@ export default {
|
|||
>
|
||||
<alert-settings-form-help-block
|
||||
:message="viewCredentialsHelpMsg"
|
||||
link="https://docs.gitlab.com/ee/operations/incident_management/integrations.html#configuration"
|
||||
:link="$options.incidentManagementDocsLink"
|
||||
/>
|
||||
|
||||
<gl-form-group id="integration-webhook">
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import Tracking from '~/tracking';
|
||||
import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
|
||||
import { pipelineEditorTrackingOptions } from '../../../constants';
|
||||
|
||||
export default {
|
||||
|
|
@ -34,7 +35,7 @@ export default {
|
|||
this.track(actions.helpDrawerLinks.runners, { label });
|
||||
},
|
||||
},
|
||||
RUNNER_HELP_URL: 'https://docs.gitlab.com/runner/register/index.html',
|
||||
RUNNER_HELP_URL: `${DOCS_URL}/runner/register/index.html`,
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ export default {
|
|||
pipelinesPath: {
|
||||
default: '',
|
||||
},
|
||||
newSchedulePath: {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
schedules: {
|
||||
|
|
@ -289,7 +292,12 @@ export default {
|
|||
</gl-tab>
|
||||
|
||||
<template #tabs-end>
|
||||
<gl-button variant="confirm" class="gl-ml-auto" data-testid="new-schedule-button">
|
||||
<gl-button
|
||||
:href="newSchedulePath"
|
||||
variant="confirm"
|
||||
class="gl-ml-auto"
|
||||
data-testid="new-schedule-button"
|
||||
>
|
||||
{{ $options.i18n.newSchedule }}
|
||||
</gl-button>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@ export default {
|
|||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
inject: {
|
||||
newSchedulePath: {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
schedulesHelpPath() {
|
||||
return helpPagePath('ci/pipelines/schedules');
|
||||
|
|
@ -37,7 +42,7 @@ export default {
|
|||
<gl-empty-state
|
||||
:svg-path="$options.SCHEDULE_MD_SVG_URL"
|
||||
:primary-button-text="$options.i18n.createNew"
|
||||
primary-button-link="#"
|
||||
:primary-button-link="newSchedulePath"
|
||||
>
|
||||
<template #title>
|
||||
<h3>
|
||||
|
|
|
|||
|
|
@ -8,16 +8,15 @@ import {
|
|||
GlFormGroup,
|
||||
GlFormInput,
|
||||
GlFormTextarea,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
} from '@gitlab/ui';
|
||||
import { uniqueId } from 'lodash';
|
||||
import Vue from 'vue';
|
||||
import { __, s__ } from '~/locale';
|
||||
import { createAlert } from '~/alert';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { REF_TYPE_BRANCHES, REF_TYPE_TAGS } from '~/ref/constants';
|
||||
import RefSelector from '~/ref/components/ref_selector.vue';
|
||||
import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown/timezone_dropdown.vue';
|
||||
import IntervalPatternInput from '~/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue';
|
||||
import createPipelineScheduleMutation from '../graphql/mutations/create_pipeline_schedule.mutation.graphql';
|
||||
import { VARIABLE_TYPE, FILE_TYPE } from '../constants';
|
||||
|
||||
export default {
|
||||
|
|
@ -30,8 +29,6 @@ export default {
|
|||
GlFormGroup,
|
||||
GlFormInput,
|
||||
GlFormTextarea,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
RefSelector,
|
||||
TimezoneDropdown,
|
||||
IntervalPatternInput,
|
||||
|
|
@ -44,6 +41,7 @@ export default {
|
|||
'cronTimezone',
|
||||
'dailyLimit',
|
||||
'settingsLink',
|
||||
'schedulesPath',
|
||||
],
|
||||
props: {
|
||||
timezoneData: {
|
||||
|
|
@ -55,24 +53,19 @@ export default {
|
|||
required: false,
|
||||
default: '',
|
||||
},
|
||||
editing: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
refValue: {
|
||||
shortName: this.refParam,
|
||||
// this is needed until we add support for ref type in url query strings
|
||||
// ensure default branch is called with full ref on load
|
||||
// https://gitlab.com/gitlab-org/gitlab/-/issues/287815
|
||||
fullName: this.refParam === this.defaultBranch ? `refs/heads/${this.refParam}` : undefined,
|
||||
},
|
||||
cronValue: this.cron,
|
||||
description: '',
|
||||
scheduleRef: this.defaultBranch,
|
||||
activated: true,
|
||||
timezone: this.cronTimezone,
|
||||
formCiVariables: {},
|
||||
// TODO: Add the GraphQL query to help populate the predefined variables
|
||||
// app/assets/javascripts/ci/pipeline_new/components/pipeline_new_form.vue#131
|
||||
predefinedValueOptions: {},
|
||||
variables: [],
|
||||
};
|
||||
},
|
||||
i18n: {
|
||||
|
|
@ -91,6 +84,9 @@ export default {
|
|||
),
|
||||
removeVariableLabel: s__('CiVariables|Remove variable'),
|
||||
variables: s__('Pipeline|Variables'),
|
||||
scheduleCreateError: s__(
|
||||
'PipelineSchedules|An error occurred while creating the pipeline schedule.',
|
||||
),
|
||||
},
|
||||
typeOptions: {
|
||||
[VARIABLE_TYPE]: __('Variable'),
|
||||
|
|
@ -103,15 +99,6 @@ export default {
|
|||
dropdownHeader: this.$options.i18n.targetBranchTag,
|
||||
};
|
||||
},
|
||||
refFullName() {
|
||||
return this.refValue.fullName;
|
||||
},
|
||||
variables() {
|
||||
return this.formCiVariables[this.refFullName]?.variables ?? [];
|
||||
},
|
||||
descriptions() {
|
||||
return this.formCiVariables[this.refFullName]?.descriptions ?? {};
|
||||
},
|
||||
typeOptionsListbox() {
|
||||
return [
|
||||
{
|
||||
|
|
@ -127,51 +114,84 @@ export default {
|
|||
getEnabledRefTypes() {
|
||||
return [REF_TYPE_BRANCHES, REF_TYPE_TAGS];
|
||||
},
|
||||
preparedVariables() {
|
||||
return this.variables.filter((variable) => variable.key !== '');
|
||||
},
|
||||
},
|
||||
created() {
|
||||
Vue.set(this.formCiVariables, this.refFullName, {
|
||||
variables: [],
|
||||
descriptions: {},
|
||||
});
|
||||
|
||||
this.addEmptyVariable(this.refFullName);
|
||||
this.addEmptyVariable();
|
||||
},
|
||||
methods: {
|
||||
addEmptyVariable(refValue) {
|
||||
const { variables } = this.formCiVariables[refValue];
|
||||
addEmptyVariable() {
|
||||
const lastVar = this.variables[this.variables.length - 1];
|
||||
|
||||
const lastVar = variables[variables.length - 1];
|
||||
if (lastVar?.key === '' && lastVar?.value === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
variables.push({
|
||||
uniqueId: uniqueId(`var-${refValue}`),
|
||||
variable_type: VARIABLE_TYPE,
|
||||
this.variables.push({
|
||||
variableType: VARIABLE_TYPE,
|
||||
key: '',
|
||||
value: '',
|
||||
});
|
||||
},
|
||||
setVariableAttribute(key, attribute, value) {
|
||||
const { variables } = this.formCiVariables[this.refFullName];
|
||||
const variable = variables.find((v) => v.key === key);
|
||||
const variable = this.variables.find((v) => v.key === key);
|
||||
variable[attribute] = value;
|
||||
},
|
||||
shouldShowValuesDropdown(key) {
|
||||
return this.predefinedValueOptions[key]?.length > 1;
|
||||
},
|
||||
removeVariable(index) {
|
||||
this.variables.splice(index, 1);
|
||||
},
|
||||
canRemove(index) {
|
||||
return index < this.variables.length - 1;
|
||||
},
|
||||
scheduleHandler() {
|
||||
if (!this.editing) {
|
||||
this.createPipelineSchedule();
|
||||
}
|
||||
},
|
||||
async createPipelineSchedule() {
|
||||
try {
|
||||
const {
|
||||
data: {
|
||||
pipelineScheduleCreate: { errors },
|
||||
},
|
||||
} = await this.$apollo.mutate({
|
||||
mutation: createPipelineScheduleMutation,
|
||||
variables: {
|
||||
input: {
|
||||
description: this.description,
|
||||
cron: this.cronValue,
|
||||
cronTimezone: this.timezone,
|
||||
ref: this.scheduleRef,
|
||||
variables: this.preparedVariables,
|
||||
active: this.activated,
|
||||
projectPath: this.fullPath,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (errors.length > 0) {
|
||||
createAlert({ message: errors[0] });
|
||||
} else {
|
||||
visitUrl(this.schedulesPath);
|
||||
}
|
||||
} catch {
|
||||
createAlert({ message: this.$options.i18n.scheduleCreateError });
|
||||
}
|
||||
},
|
||||
setCronValue(cron) {
|
||||
this.cronValue = cron;
|
||||
},
|
||||
setTimezone(timezone) {
|
||||
this.timezone = timezone.identifier || '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="col-lg-8">
|
||||
<div class="col-lg-8 gl-pl-0">
|
||||
<gl-form>
|
||||
<!--Description-->
|
||||
<gl-form-group :label="$options.i18n.description" label-for="schedule-description">
|
||||
|
|
@ -181,6 +201,7 @@ export default {
|
|||
type="text"
|
||||
:placeholder="$options.i18n.shortDescriptionPipeline"
|
||||
data-testid="schedule-description"
|
||||
required
|
||||
/>
|
||||
</gl-form-group>
|
||||
<!--Interval Pattern-->
|
||||
|
|
@ -190,6 +211,7 @@ export default {
|
|||
:initial-cron-interval="cron"
|
||||
:daily-limit="dailyLimit"
|
||||
:send-native-errors="false"
|
||||
@cronValue="setCronValue"
|
||||
/>
|
||||
</gl-form-group>
|
||||
<!--Timezone-->
|
||||
|
|
@ -199,12 +221,14 @@ export default {
|
|||
:value="timezone"
|
||||
:timezone-data="timezoneData"
|
||||
name="schedule-timezone"
|
||||
@input="setTimezone"
|
||||
/>
|
||||
</gl-form-group>
|
||||
<!--Branch/Tag Selector-->
|
||||
<gl-form-group :label="$options.i18n.targetBranchTag" label-for="schedule-target-branch-tag">
|
||||
<ref-selector
|
||||
id="schedule-target-branch-tag"
|
||||
v-model="scheduleRef"
|
||||
:enabled-ref-types="getEnabledRefTypes"
|
||||
:project-id="projectId"
|
||||
:value="scheduleRef"
|
||||
|
|
@ -217,7 +241,7 @@ export default {
|
|||
<gl-form-group :label="$options.i18n.variables">
|
||||
<div
|
||||
v-for="(variable, index) in variables"
|
||||
:key="variable.uniqueId"
|
||||
:key="`var-${index}`"
|
||||
class="gl-mb-3 gl-pb-2"
|
||||
data-testid="ci-variable-row"
|
||||
data-qa-selector="ci_variable_row_container"
|
||||
|
|
@ -226,14 +250,14 @@ export default {
|
|||
class="gl-display-flex gl-align-items-stretch gl-flex-direction-column gl-md-flex-direction-row"
|
||||
>
|
||||
<gl-dropdown
|
||||
:text="$options.typeOptions[variable.variable_type]"
|
||||
:text="$options.typeOptions[variable.variableType]"
|
||||
:class="$options.formElementClasses"
|
||||
data-testid="pipeline-form-ci-variable-type"
|
||||
>
|
||||
<gl-dropdown-item
|
||||
v-for="type in Object.keys($options.typeOptions)"
|
||||
:key="type"
|
||||
@click="setVariableAttribute(variable.key, 'variable_type', type)"
|
||||
@click="setVariableAttribute(variable.key, 'variableType', type)"
|
||||
>
|
||||
{{ $options.typeOptions[type] }}
|
||||
</gl-dropdown-item>
|
||||
|
|
@ -244,26 +268,10 @@ export default {
|
|||
:class="$options.formElementClasses"
|
||||
data-testid="pipeline-form-ci-variable-key"
|
||||
data-qa-selector="ci_variable_key_field"
|
||||
@change="addEmptyVariable(refFullName)"
|
||||
@change="addEmptyVariable()"
|
||||
/>
|
||||
<gl-dropdown
|
||||
v-if="shouldShowValuesDropdown(variable.key)"
|
||||
:text="variable.value"
|
||||
:class="$options.formElementClasses"
|
||||
class="gl-flex-grow-1 gl-mr-0!"
|
||||
data-testid="pipeline-form-ci-variable-value-dropdown"
|
||||
>
|
||||
<gl-dropdown-item
|
||||
v-for="value in predefinedValueOptions[variable.key]"
|
||||
:key="value"
|
||||
data-testid="pipeline-form-ci-variable-value-dropdown-items"
|
||||
@click="setVariableAttribute(variable.key, 'value', value)"
|
||||
>
|
||||
{{ value }}
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
|
||||
<gl-form-textarea
|
||||
v-else
|
||||
v-model="variable.value"
|
||||
:placeholder="s__('CiVariables|Input variable value')"
|
||||
class="gl-mb-3 gl-h-7!"
|
||||
|
|
@ -292,30 +300,19 @@ export default {
|
|||
/>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="descriptions[variable.key]" class="gl-text-gray-500 gl-mb-3">
|
||||
{{ descriptions[variable.key] }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #description
|
||||
><gl-sprintf :message="$options.i18n.variablesDescription">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="settingsLink">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf></template
|
||||
>
|
||||
</gl-form-group>
|
||||
<!--Activated-->
|
||||
<gl-form-checkbox id="schedule-active" v-model="activated" class="gl-mb-3">{{
|
||||
$options.i18n.activated
|
||||
}}</gl-form-checkbox>
|
||||
<gl-form-checkbox id="schedule-active" v-model="activated" class="gl-mb-3">
|
||||
{{ $options.i18n.activated }}
|
||||
</gl-form-checkbox>
|
||||
|
||||
<gl-button type="submit" variant="confirm" data-testid="schedule-submit-button">{{
|
||||
$options.i18n.savePipelineSchedule
|
||||
}}</gl-button>
|
||||
<gl-button type="reset" data-testid="schedule-cancel-button">{{
|
||||
$options.i18n.cancel
|
||||
}}</gl-button>
|
||||
<gl-button variant="confirm" data-testid="schedule-submit-button" @click="scheduleHandler">
|
||||
{{ $options.i18n.savePipelineSchedule }}
|
||||
</gl-button>
|
||||
<gl-button :href="schedulesPath" data-testid="schedule-cancel-button">
|
||||
{{ $options.i18n.cancel }}
|
||||
</gl-button>
|
||||
</gl-form>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlButton, GlButtonGroup, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
|
||||
export const i18n = {
|
||||
playTooltip: s__('PipelineSchedules|Run pipeline schedule'),
|
||||
|
|
@ -44,6 +45,11 @@ export default {
|
|||
canRemove() {
|
||||
return this.schedule.userPermissions.adminPipelineSchedule;
|
||||
},
|
||||
editPathWithIdParam() {
|
||||
const id = getIdFromGraphQLId(this.schedule.id);
|
||||
|
||||
return `${this.schedule.editPath}?id=${id}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -67,7 +73,14 @@ export default {
|
|||
data-testid="take-ownership-pipeline-schedule-btn"
|
||||
@click="$emit('showTakeOwnershipModal', schedule.id)"
|
||||
/>
|
||||
<gl-button v-if="canUpdate" v-gl-tooltip :title="$options.i18n.editTooltip" icon="pencil" />
|
||||
<gl-button
|
||||
v-if="canUpdate"
|
||||
v-gl-tooltip
|
||||
:href="editPathWithIdParam"
|
||||
:title="$options.i18n.editTooltip"
|
||||
icon="pencil"
|
||||
data-testid="edit-pipeline-schedule-btn"
|
||||
/>
|
||||
<gl-button
|
||||
v-if="canRemove"
|
||||
v-gl-tooltip
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
export const VARIABLE_TYPE = 'env_var';
|
||||
export const FILE_TYPE = 'file';
|
||||
export const VARIABLE_TYPE = 'ENV_VAR';
|
||||
export const FILE_TYPE = 'FILE';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
mutation createPipelineSchedule($input: PipelineScheduleCreateInput!) {
|
||||
pipelineScheduleCreate(input: $input) {
|
||||
clientMutationId
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ query getPipelineSchedulesQuery($projectPath: ID!, $status: PipelineScheduleStat
|
|||
id
|
||||
description
|
||||
forTag
|
||||
editPath
|
||||
refPath
|
||||
refForDisplay
|
||||
lastPipeline {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default () => {
|
|||
return false;
|
||||
}
|
||||
|
||||
const { fullPath, pipelinesPath } = containerEl.dataset;
|
||||
const { fullPath, pipelinesPath, newSchedulePath, schedulesPath } = containerEl.dataset;
|
||||
|
||||
return new Vue({
|
||||
el: containerEl,
|
||||
|
|
@ -27,6 +27,8 @@ export default () => {
|
|||
provide: {
|
||||
fullPath,
|
||||
pipelinesPath,
|
||||
newSchedulePath,
|
||||
schedulesPath,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(PipelineSchedules);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const apolloProvider = new VueApollo({
|
|||
defaultClient: createDefaultClient(),
|
||||
});
|
||||
|
||||
export default (selector) => {
|
||||
export default (selector, editing = false) => {
|
||||
const containerEl = document.querySelector(selector);
|
||||
|
||||
if (!containerEl) {
|
||||
|
|
@ -25,6 +25,7 @@ export default (selector) => {
|
|||
projectId,
|
||||
defaultBranch,
|
||||
settingsLink,
|
||||
schedulesPath,
|
||||
} = containerEl.dataset;
|
||||
|
||||
return new Vue({
|
||||
|
|
@ -39,12 +40,14 @@ export default (selector) => {
|
|||
cronTimezone: cronTimezone ?? '',
|
||||
cron: cron ?? '',
|
||||
settingsLink,
|
||||
schedulesPath,
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(PipelineSchedulesForm, {
|
||||
props: {
|
||||
timezoneData: JSON.parse(timezoneData),
|
||||
refParam: defaultBranch,
|
||||
editing,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { __, s__ } from '~/locale';
|
||||
import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
|
||||
|
||||
export const RUNNER_TYPENAME = 'CiRunner'; // __typename
|
||||
|
||||
|
|
@ -268,12 +269,10 @@ export const DEFAULT_PLATFORM = LINUX_PLATFORM;
|
|||
|
||||
// Runner docs are in a separate repository and are not shipped with GitLab
|
||||
// they are rendered as external URLs.
|
||||
export const INSTALL_HELP_URL = 'https://docs.gitlab.com/runner/install';
|
||||
export const EXECUTORS_HELP_URL = 'https://docs.gitlab.com/runner/executors/';
|
||||
export const SERVICE_COMMANDS_HELP_URL =
|
||||
'https://docs.gitlab.com/runner/commands/#service-related-commands';
|
||||
export const CHANGELOG_URL = 'https://gitlab.com/gitlab-org/gitlab-runner/blob/main/CHANGELOG.md';
|
||||
export const DOCKER_HELP_URL = 'https://docs.gitlab.com/runner/install/docker.html';
|
||||
export const KUBERNETES_HELP_URL = 'https://docs.gitlab.com/runner/install/kubernetes.html';
|
||||
export const RUNNER_MANAGERS_HELP_URL =
|
||||
'https://docs.gitlab.com/runner/fleet_scaling/#workers-executors-and-autoscaling-capabilities';
|
||||
export const INSTALL_HELP_URL = `${DOCS_URL}/runner/install`;
|
||||
export const EXECUTORS_HELP_URL = `${DOCS_URL}/runner/executors/`;
|
||||
export const SERVICE_COMMANDS_HELP_URL = `${DOCS_URL}/runner/commands/#service-related-commands`;
|
||||
export const CHANGELOG_URL = `https://gitlab.com/gitlab-org/gitlab-runner/blob/main/CHANGELOG.md`;
|
||||
export const DOCKER_HELP_URL = `${DOCS_URL}/runner/install/docker.html`;
|
||||
export const KUBERNETES_HELP_URL = `${DOCS_URL}/runner/install/kubernetes.html`;
|
||||
export const RUNNER_MANAGERS_HELP_URL = `${DOCS_URL}/runner/fleet_scaling/#workers-executors-and-autoscaling-capabilities`;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
<script>
|
||||
import { GlSprintf, GlTooltipDirective, GlModal } from '@gitlab/ui';
|
||||
import { __, s__ } from '~/locale';
|
||||
import { DOCS_URL_IN_EE_DIR } from 'jh_else_ce/lib/utils/url_utility';
|
||||
import eventHub from '../event_hub';
|
||||
import stopEnvironmentMutation from '../graphql/mutations/stop_environment.mutation.graphql';
|
||||
|
||||
export default {
|
||||
yamlDocsLink: `${DOCS_URL_IN_EE_DIR}/ee/ci/yaml/`,
|
||||
stoppingEnvironmentDocsLink: `${DOCS_URL_IN_EE_DIR}/environments/#stopping-an-environment`,
|
||||
|
||||
id: 'stop-environment-modal',
|
||||
name: 'StopEnvironmentModal',
|
||||
|
||||
|
|
@ -98,18 +102,15 @@ export default {
|
|||
<strong>{{ content }}</strong>
|
||||
</template>
|
||||
<template #ciConfigLink="{ content }">
|
||||
<a href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener noreferrer">
|
||||
<a :href="$options.yamlDocsLink" target="_blank" rel="noopener noreferrer">
|
||||
{{ content }}</a
|
||||
>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
<a
|
||||
href="https://docs.gitlab.com/ee/ci/environments/#stopping-an-environment"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>{{ s__('Environments|Learn more about stopping environments') }}</a
|
||||
>
|
||||
<a :href="$options.stoppingEnvironmentDocsLink" target="_blank" rel="noopener noreferrer">{{
|
||||
s__('Environments|Learn more about stopping environments')
|
||||
}}</a>
|
||||
</div>
|
||||
</gl-modal>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
|
||||
|
||||
export const STATUS_TYPES = {
|
||||
SUCCESS: 'success',
|
||||
|
|
@ -8,7 +9,7 @@ export const STATUS_TYPES = {
|
|||
|
||||
export const UPGRADE_DOCS_URL = helpPagePath('update/index');
|
||||
|
||||
export const ABOUT_RELEASES_PAGE = 'https://about.gitlab.com/releases/categories/releases/';
|
||||
export const ABOUT_RELEASES_PAGE = `${PROMO_URL}/releases/categories/releases/`;
|
||||
|
||||
export const ALERT_MODAL_ID = 'security-patch-upgrade-alert-modal';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlAlert, GlButton, GlEmptyState, GlLink, GlSprintf, GlTable } from '@gitlab/ui';
|
||||
import { setUrlParams } from '~/lib/utils/url_utility';
|
||||
import { setUrlParams, DOCS_URL_IN_EE_DIR } from 'jh_else_ce/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
const GOOGLE_CONSOLE_URL = 'https://console.cloud.google.com/iam-admin/serviceaccounts';
|
||||
|
|
@ -49,6 +49,7 @@ export default {
|
|||
},
|
||||
},
|
||||
GOOGLE_CONSOLE_URL,
|
||||
secretsDocsLink: `${DOCS_URL_IN_EE_DIR}/ci/secrets/`,
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -86,7 +87,7 @@ export default {
|
|||
<gl-alert class="gl-mt-5" :dismissible="false" variant="tip">
|
||||
<gl-sprintf :message="$options.i18n.secretManagersDescription">
|
||||
<template #docLink="{ content }">
|
||||
<gl-link href="https://docs.gitlab.com/ee/ci/secrets/">
|
||||
<gl-link :href="$options.secretsDocsLink">
|
||||
{{ content }}
|
||||
</gl-link>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlAlert, GlBadge, GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
|
||||
/**
|
||||
* Renders Stuck Runners block for job's view.
|
||||
*/
|
||||
|
|
@ -31,7 +32,7 @@ export default {
|
|||
return this.tags.length > 0;
|
||||
},
|
||||
protectedBranchSettingsDocsLink() {
|
||||
return 'https://docs.gitlab.com/runner/security/index.html#reduce-the-security-risk-of-using-privileged-containers';
|
||||
return `${DOCS_URL}/runner/security/index.html#reduce-the-security-risk-of-using-privileged-containers`;
|
||||
},
|
||||
stuckData() {
|
||||
if (this.hasNoRunnersWithCorrespondingTags) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import initPipelineSchedulesFormApp from '~/ci/pipeline_schedules/mount_pipeline
|
|||
import initForm from '../shared/init_form';
|
||||
|
||||
if (gon.features?.pipelineSchedulesVue) {
|
||||
initPipelineSchedulesFormApp('#pipeline-schedules-form-edit');
|
||||
initPipelineSchedulesFormApp('#pipeline-schedules-form-edit', true);
|
||||
} else {
|
||||
initForm();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
import { getWeekdayNames } from '~/lib/utils/datetime_utility';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { DOCS_URL_IN_EE_DIR } from 'jh_else_ce/lib/utils/url_utility';
|
||||
|
||||
const KEY_EVERY_DAY = 'everyDay';
|
||||
const KEY_EVERY_WEEK = 'everyWeek';
|
||||
|
|
@ -54,7 +55,7 @@ export default {
|
|||
inputNameAttribute: 'schedule[cron]',
|
||||
radioValue: this.initialCronInterval ? KEY_CUSTOM : KEY_EVERY_DAY,
|
||||
cronInterval: this.initialCronInterval,
|
||||
cronSyntaxUrl: 'https://docs.gitlab.com/ee/topics/cron/',
|
||||
cronSyntaxUrl: `${DOCS_URL_IN_EE_DIR}/topics/cron/`,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -116,7 +117,7 @@ export default {
|
|||
},
|
||||
},
|
||||
watch: {
|
||||
cronInterval() {
|
||||
cronInterval(val) {
|
||||
// updates field validation state when model changes, as
|
||||
// glFieldError only updates on input.
|
||||
if (this.sendNativeErrors) {
|
||||
|
|
@ -124,6 +125,8 @@ export default {
|
|||
gl.pipelineScheduleFieldErrors.updateFormValidityState();
|
||||
});
|
||||
}
|
||||
|
||||
this.$emit('cronValue', val);
|
||||
},
|
||||
radioValue: {
|
||||
immediate: true,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { GlButton, GlCard, GlSprintf, GlLink, GlPopover, GlModalDirective } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { mergeUrlParams } from '~/lib/utils/url_utility';
|
||||
import { mergeUrlParams, DOCS_URL } from '~/lib/utils/url_utility';
|
||||
import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
|
||||
import apolloProvider from '~/pipelines/graphql/provider';
|
||||
import CiTemplates from './ci_templates.vue';
|
||||
|
|
@ -31,7 +31,7 @@ export default {
|
|||
apolloProvider,
|
||||
iOSTemplateName: 'iOS-Fastlane',
|
||||
modalId: 'runner-instructions-modal',
|
||||
runnerDocsLink: 'https://docs.gitlab.com/runner/install/osx',
|
||||
runnerDocsLink: `${DOCS_URL}/runner/install/osx`,
|
||||
whatElseLink: helpPagePath('ci/index.md'),
|
||||
i18n: {
|
||||
title: s__('Pipelines|Get started with GitLab CI/CD'),
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@ import { __, n__, sprintf } from '~/locale';
|
|||
import { createAlert } from '~/alert';
|
||||
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { TYPENAME_ISSUE } from '~/graphql_shared/constants';
|
||||
import { DOCS_URL_IN_EE_DIR } from 'jh_else_ce/lib/utils/url_utility';
|
||||
import getIssueCrmContactsQuery from '../../queries/get_issue_crm_contacts.query.graphql';
|
||||
import issueCrmContactsSubscription from '../../queries/issue_crm_contacts.subscription.graphql';
|
||||
|
||||
export default {
|
||||
crmDocsLink: `${DOCS_URL_IN_EE_DIR}/user/crm/`,
|
||||
components: {
|
||||
GlIcon,
|
||||
GlLink,
|
||||
|
|
@ -104,9 +106,7 @@ export default {
|
|||
<span> {{ contactCount }} </span>
|
||||
</div>
|
||||
<div class="hide-collapsed help-button gl-float-right">
|
||||
<gl-link href="https://docs.gitlab.com/ee/user/crm/" target="_blank"
|
||||
><gl-icon name="question-o"
|
||||
/></gl-link>
|
||||
<gl-link :href="$options.crmDocsLink" target="_blank"><gl-icon name="question-o" /></gl-link>
|
||||
</div>
|
||||
<div class="title hide-collapsed gl-mb-2 gl-line-height-20 gl-font-weight-bold">
|
||||
{{ contactsLabel }}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { s__, __ } from '~/locale';
|
|||
import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
|
||||
import SatisfactionRate from '~/surveys/components/satisfaction_rate.vue';
|
||||
import Tracking from '~/tracking';
|
||||
import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
|
||||
|
||||
const steps = [
|
||||
{
|
||||
|
|
@ -50,6 +51,7 @@ export default {
|
|||
thanks: s__('MrSurvey|Thank you for your feedback!'),
|
||||
},
|
||||
gitlabLogo,
|
||||
privacyLink: `${PROMO_URL}/privacy/`,
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
|
|
@ -152,7 +154,7 @@ export default {
|
|||
<template #link="{ content }">
|
||||
<a
|
||||
class="gl-text-decoration-underline gl-text-gray-500"
|
||||
href="https://about.gitlab.com/privacy/"
|
||||
:href="$options.privacyLink"
|
||||
target="_blank"
|
||||
rel="noreferrer nofollow"
|
||||
v-text="content"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { s__ } from '~/locale';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { DOCS_URL_IN_EE_DIR } from 'jh_else_ce/lib/utils/url_utility';
|
||||
import { stateToComponentMap as classStateMap, stateKey } from './stores/state_maps';
|
||||
|
||||
export const FOUR_MINUTES_IN_MS = 1000 * 60 * 4;
|
||||
|
|
@ -26,7 +27,7 @@ export const SP_SHOW_TRACK_VALUE = 10;
|
|||
export const SP_HELP_CONTENT = s__(
|
||||
`mrWidget|GitLab %{linkStart}CI/CD can automatically build, test, and deploy your application.%{linkEnd} It only takes a few minutes to get started, and we can help you create a pipeline configuration file.`,
|
||||
);
|
||||
export const SP_HELP_URL = 'https://docs.gitlab.com/ee/ci/quick_start/';
|
||||
export const SP_HELP_URL = `${DOCS_URL_IN_EE_DIR}/ci/quick_start/`;
|
||||
export const SP_ICON_NAME = 'status_notfound';
|
||||
|
||||
export const MERGE_ACTIVE_STATUS_PHRASES = [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlButton, GlIcon } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -16,7 +17,7 @@ export default {
|
|||
'Runners|To install Runner in a container follow the instructions described in the GitLab documentation',
|
||||
),
|
||||
I18N_VIEW_INSTRUCTIONS: s__('Runners|View installation instructions'),
|
||||
HELP_URL: 'https://docs.gitlab.com/runner/install/docker.html',
|
||||
HELP_URL: `${DOCS_URL}/runner/install/docker.html`,
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlButton, GlIcon } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -16,7 +17,7 @@ export default {
|
|||
'Runners|To install Runner in Kubernetes follow the instructions described in the GitLab documentation.',
|
||||
),
|
||||
I18N_VIEW_INSTRUCTIONS: s__('Runners|View installation instructions'),
|
||||
HELP_URL: 'https://docs.gitlab.com/runner/install/kubernetes.html',
|
||||
HELP_URL: `${DOCS_URL}/runner/install/kubernetes.html`,
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#pipeline-schedules-callout{ data: { docs_url: help_page_path('ci/pipelines/schedules'), illustration_url: image_path('illustrations/pipeline_schedule_callout.svg') } }
|
||||
|
||||
- if Feature.enabled?(:pipeline_schedules_vue, @project)
|
||||
#pipeline-schedules-app{ data: { full_path: @project.full_path, pipelines_path: project_pipelines_path(@project) } }
|
||||
#pipeline-schedules-app{ data: { full_path: @project.full_path, pipelines_path: project_pipelines_path(@project), new_schedule_path: new_project_pipeline_schedule_path(@project) } }
|
||||
- else
|
||||
.top-area
|
||||
- schedule_path_proc = ->(scope) { pipeline_schedules_path(@project, scope: scope) }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
= _("Schedule a new pipeline")
|
||||
|
||||
- if Feature.enabled?(:pipeline_schedules_vue, @project)
|
||||
#pipeline-schedules-form-new{ data: { full_path: @project.full_path, cron: @schedule.cron, daily_limit: @schedule.daily_limit, timezone_data: timezone_data.to_json, cron_timezone: @schedule.cron_timezone, project_id: @project.id, default_branch: @project.default_branch, settings_link: project_settings_ci_cd_path(@project), } }
|
||||
#pipeline-schedules-form-new{ data: { full_path: @project.full_path, cron: @schedule.cron, daily_limit: @schedule.daily_limit, timezone_data: timezone_data.to_json, cron_timezone: @schedule.cron_timezone, project_id: @project.id, default_branch: @project.default_branch, settings_link: project_settings_ci_cd_path(@project), schedules_path: pipeline_schedules_path(@project) } }
|
||||
- else
|
||||
= render "form"
|
||||
|
|
|
|||
|
|
@ -91,19 +91,8 @@ changes.delete(:docs)
|
|||
changes.delete(:changelog)
|
||||
# No special review for feature flags needed.
|
||||
changes.delete(:feature_flag)
|
||||
categories = Set.new(changes.keys - [:unknown])
|
||||
|
||||
# Ensure to spin for database reviewer/maintainer when ~database is applied (e.g. to review SQL queries)
|
||||
categories << :database if helper.mr_labels.include?('database')
|
||||
|
||||
# Ensure to spin for UX reviewer when ~UX is applied (e.g. to review changes to the UI) except when it's from wider community contribution where we want to assign from the corresponding group
|
||||
categories << :ux if helper.mr_labels.include?('UX') && !helper.mr_labels.include?('Community contribution') # rubocop:disable Rails/NegateInclude
|
||||
|
||||
# Ensure to spin for Analytics Instrumentation reviewer when ~"analytics instrumentation::review pending" is applied
|
||||
categories << :analytics_instrumentation if helper.mr_labels.include?("analytics instrumentation::review pending")
|
||||
|
||||
# Skip Analytics Instrumentation reviews for growth experiment MRs
|
||||
categories.delete(:analytics_instrumentation) if helper.mr_labels.include?("growth experiment")
|
||||
categories = roulette.prepare_categories(changes.keys - [:unknown])
|
||||
|
||||
# Skip specialty reviews for stable branch MRs since they have already been merged to the default branch
|
||||
categories.subtract([:database, :ux, :analytics_instrumentation]) if stable_branch.valid_stable_branch?
|
||||
|
|
@ -111,6 +100,10 @@ categories.subtract([:database, :ux, :analytics_instrumentation]) if stable_bran
|
|||
if changes.any?
|
||||
random_roulette_spins = roulette.spin(nil, categories, timezone_experiment: false)
|
||||
|
||||
if categories.include?(:ux) # rubocop:disable Style/IfUnlessModifier
|
||||
roulette.assign_pedroms_for_ux_wider_community_contribution(random_roulette_spins)
|
||||
end
|
||||
|
||||
rows = random_roulette_spins.map do |spin|
|
||||
markdown_row_for_spin(spin.category, spin)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddElasticsearchNumberOfShardsToApplicationSettings < Gitlab::Database::Migration[2.1]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
add_column :application_settings, :elasticsearch_worker_number_of_shards, :integer, null: false, default: 2
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UpdateElasticsearchNumberOfShardsInApplicationSettingsForGitlabCom < Gitlab::Database::Migration[2.1]
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
enable_lock_retries!
|
||||
|
||||
def up
|
||||
return unless Gitlab.com?
|
||||
|
||||
execute 'UPDATE application_settings SET elasticsearch_worker_number_of_shards = 16'
|
||||
end
|
||||
|
||||
def down
|
||||
return unless Gitlab.com?
|
||||
|
||||
execute 'UPDATE application_settings SET elasticsearch_worker_number_of_shards = 2'
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
f40ca52d92fd6c2c3a64b5b3c46c46f1f690b67b5320e84f55f62d4723c7d7e6
|
||||
|
|
@ -0,0 +1 @@
|
|||
b44a08db74d15671a63afff9c41da67c0486c57bb893dc147ae073d78541457c
|
||||
|
|
@ -11758,6 +11758,7 @@ CREATE TABLE application_settings (
|
|||
default_branch_protection_defaults jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
gitlab_shell_operation_limit integer DEFAULT 600,
|
||||
elasticsearch_requeue_workers boolean DEFAULT false NOT NULL,
|
||||
elasticsearch_worker_number_of_shards integer DEFAULT 2 NOT NULL,
|
||||
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
|
||||
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
|
||||
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ configuration option in `gitlab.yml`. These metrics are served from the
|
|||
| `sidekiq_jobs_dead_total` | Counter | 13.7 | Sidekiq dead jobs (jobs that have run out of retries) | `queue`, `boundary`, `external_dependencies`, `feature_category`, `urgency` |
|
||||
| `sidekiq_redis_requests_total` | Counter | 13.1 | Redis requests during a Sidekiq job execution | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency` |
|
||||
| `sidekiq_elasticsearch_requests_total` | Counter | 13.1 | Elasticsearch requests during a Sidekiq job execution | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency` |
|
||||
| `sidekiq_jobs_deferred_total` | Counter | 16.1 | Number of jobs being deferred when `defer_sidekiq_jobs` feature flag is enabled | `worker` |
|
||||
| `sidekiq_jobs_deferred_total` | Counter | 16.1 | Number of jobs being deferred (either via `run_sidekiq_jobs` feature flag or DB health status indicator) | `worker` |
|
||||
| `sidekiq_running_jobs` | Gauge | 12.2 | Number of Sidekiq jobs running | `queue`, `boundary`, `external_dependencies`, `feature_category`, `urgency` |
|
||||
| `sidekiq_concurrency` | Gauge | 12.5 | Maximum number of Sidekiq jobs | |
|
||||
| `sidekiq_mem_total_bytes` | Gauge | 15.3 | Number of bytes allocated for both objects consuming an object slot and objects that required a malloc'| |
|
||||
|
|
|
|||
|
|
@ -435,22 +435,6 @@ The GitLab exporter allows you to measure various GitLab metrics, pulled from Re
|
|||
|
||||
[Read more about the GitLab exporter](gitlab_exporter.md).
|
||||
|
||||
## Configuring Prometheus to monitor Kubernetes
|
||||
|
||||
If your GitLab server is running within Kubernetes, Prometheus collects metrics from the Nodes and [annotated Pods](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config) in the cluster, including performance data on each container. This is particularly helpful if your CI/CD environments run in the same cluster, as you can use the [Prometheus project integration](../../../user/project/integrations/prometheus.md) to monitor them.
|
||||
|
||||
To disable the monitoring of Kubernetes:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`.
|
||||
1. Add (or find and uncomment) the following line and set it to `false`:
|
||||
|
||||
```ruby
|
||||
prometheus['monitor_kubernetes'] = false
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab](../../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to
|
||||
take effect.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### `/var/opt/gitlab/prometheus` consumes too much disk space
|
||||
|
|
|
|||
|
|
@ -375,6 +375,7 @@ listed in the descriptions of the relevant settings.
|
|||
| `elasticsearch_requeue_workers` **(PREMIUM)** | boolean | no | Enable automatic requeuing of indexing workers. This improves non-code indexing throughput by enqueuing Sidekiq jobs until all documents are processed. |
|
||||
| `elasticsearch_limit_indexing` **(PREMIUM)** | boolean | no | Limit Elasticsearch to index certain namespaces and projects. |
|
||||
| `elasticsearch_max_bulk_concurrency` **(PREMIUM)** | integer | no | Maximum concurrency of Elasticsearch bulk requests per indexing operation. This only applies to repository indexing operations. |
|
||||
| `elasticsearch_worker_number_of_shards` **(PREMIUM)** | integer | no | Number of indexing worker shards. This improves non-code indexing throughput by enqueuing more parallel Sidekiq jobs. Default is `2`. |
|
||||
| `elasticsearch_max_bulk_size_mb` **(PREMIUM)** | integer | no | Maximum size of Elasticsearch bulk indexing requests in MB. This only applies to repository indexing operations. |
|
||||
| `elasticsearch_namespace_ids` **(PREMIUM)** | array of integers | no | The namespaces to index via Elasticsearch if `elasticsearch_limit_indexing` is enabled. |
|
||||
| `elasticsearch_project_ids` **(PREMIUM)** | array of integers | no | The projects to index via Elasticsearch if `elasticsearch_limit_indexing` is enabled. |
|
||||
|
|
@ -555,6 +556,7 @@ listed in the descriptions of the relevant settings.
|
|||
| `unique_ips_limit_enabled` | boolean | no | (**If enabled, requires:** `unique_ips_limit_per_user` and `unique_ips_limit_time_window`) Limit sign in from multiple IPs. |
|
||||
| `unique_ips_limit_per_user` | integer | required by: `unique_ips_limit_enabled` | Maximum number of IPs per user. |
|
||||
| `unique_ips_limit_time_window` | integer | required by: `unique_ips_limit_enabled` | How many seconds an IP is counted towards the limit. |
|
||||
| `update_runner_versions_enabled` | boolean | no | Fetch GitLab Runner release version data from GitLab.com. For more information, see how to [determine which runners need to be upgraded](../ci/runners/configure_runners.md#determine-which-runners-need-to-be-upgraded). |
|
||||
| `usage_ping_enabled` | boolean | no | Every week GitLab reports license usage back to GitLab, Inc. |
|
||||
| `user_deactivation_emails_enabled` | boolean | no | Send an email to users upon account deactivation. |
|
||||
| `user_default_external` | boolean | no | Newly registered users are external by default. |
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 125 KiB |
|
|
@ -149,7 +149,7 @@ created using the [Experiment Tracking template](https://gitlab.com/gitlab-org/g
|
|||
`worker` feature flags are used for controlling Sidekiq workers behavior, such as deferring Sidekiq jobs.
|
||||
|
||||
`worker` feature flags likely do not have any YAML definition as the name could be dynamically generated using
|
||||
the worker name itself, e.g. `defer_sidekiq_jobs_AuthorizedProjectsWorker`. Some examples for using `worker` type feature
|
||||
the worker name itself, e.g. `run_sidekiq_jobs_AuthorizedProjectsWorker`. Some examples for using `worker` type feature
|
||||
flags can be found in [deferring Sidekiq jobs](#deferring-sidekiq-jobs).
|
||||
|
||||
## Feature flag definition and validation
|
||||
|
|
@ -713,33 +713,29 @@ Feature flags with [`worker` type](#worker-type) can be used to control the beha
|
|||
|
||||
### Deferring Sidekiq jobs
|
||||
|
||||
Feature flags with the format of `defer_sidekiq_jobs_{WorkerName}` delay the execution of the worker
|
||||
by scheduling the job at a later time.
|
||||
When disabled, feature flags with the format of `run_sidekiq_jobs_{WorkerName}` delay the execution of the worker
|
||||
by scheduling the job at a later time. This feature flag is enabled by default for all workers.
|
||||
Deferring jobs can be useful during an incident where contentious behavior from
|
||||
worker instances are saturating infrastructure resources (such as database and database connection pool).
|
||||
The implementation can be found at [DeferJobs Sidekiq server middleware](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/sidekiq_middleware/defer_jobs.rb).
|
||||
|
||||
NOTE:
|
||||
Jobs are deferred indefinitely as long as the feature flag is enabled. It is important to disable the
|
||||
Jobs are deferred indefinitely as long as the feature flag is disabled. It is important to enable the
|
||||
feature flag after the worker is deemed safe to continue processing.
|
||||
|
||||
When set to true, 100% of the jobs are deferred. When you want processing to resume, you can
|
||||
When set to false, 100% of the jobs are deferred. When you want processing to resume, you can
|
||||
use a **percentage of time** rollout. For example:
|
||||
|
||||
```shell
|
||||
# defer 100% of the jobs
|
||||
/chatops run feature set defer_sidekiq_jobs_SlowRunningWorker true
|
||||
# not running any jobs, deferring all 100% of the jobs
|
||||
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker false
|
||||
|
||||
# defer 99% of the jobs, only letting 1% processed
|
||||
/chatops run feature set defer_sidekiq_jobs_SlowRunningWorker 99
|
||||
# only running 10% of the jobs, deferring 90% of the jobs
|
||||
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker 10
|
||||
|
||||
# defer 50% of the jobs
|
||||
/chatops run feature set defer_sidekiq_jobs_SlowRunningWorker 50
|
||||
# running 50% of the jobs, deferring 50% of the jobs
|
||||
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker 50
|
||||
|
||||
# stop deferring the jobs, jobs are being processed normally
|
||||
/chatops run feature set defer_sidekiq_jobs_SlowRunningWorker false
|
||||
# back to running all jobs normally
|
||||
/chatops run feature set run_sidekiq_jobs_SlowRunningWorker true
|
||||
```
|
||||
|
||||
NOTE:
|
||||
The percentage of time value denotes the percentage of time the jobs are being deferred (instead of being processed).
|
||||
For example, setting to `99` means only 1% of the jobs are being processed at random.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ If the highest number stable branch is unclear, check the [GitLab blog](https://
|
|||
|:------------------------|:----------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [Ruby](#2-ruby) | `3.0.x` | From GitLab 15.10, Ruby 3.0 is required. You must use the standard MRI implementation of Ruby. We love [JRuby](https://www.jruby.org/) and [Rubinius](https://github.com/rubinius/rubinius#the-rubinius-language-platform), but GitLab needs several Gems that have native extensions. |
|
||||
| [RubyGems](#3-rubygems) | `3.4.x` | A specific RubyGems version is not fully needed, but it's recommended to update so you can enjoy some known performance improvements. |
|
||||
| [Go](#4-go) | `1.18.x` | From GitLab 15.6, Go 1.18 or later is required. |
|
||||
| [Go](#4-go) | `1.19.x` | From GitLab 16.1, Go 1.19 or later is required. |
|
||||
| [Git](#git) | `2.38.x` | From GitLab 15.8, Git 2.38.x and later is required. It's highly recommended that you use the [Git version provided by Gitaly](#git). |
|
||||
| [Node.js](#5-node) | `18.16.x` | From GitLab 16.1, Node.js 18.16 or later is required. |
|
||||
|
||||
|
|
@ -247,11 +247,11 @@ Linux. You can find downloads for other platforms at the
|
|||
# Remove former Go installation folder
|
||||
sudo rm -rf /usr/local/go
|
||||
|
||||
curl --remote-name --location --progress-bar "https://go.dev/dl/go1.18.8.linux-amd64.tar.gz"
|
||||
echo '4d854c7bad52d53470cf32f1b287a5c0c441dc6b98306dea27358e099698142a go1.18.8.linux-amd64.tar.gz' | shasum -a256 -c - && \
|
||||
sudo tar -C /usr/local -xzf go1.18.8.linux-amd64.tar.gz
|
||||
curl --remote-name --location --progress-bar "https://go.dev/dl/go1.19.10.linux-amd64.tar.gz"
|
||||
echo '8b045a483d3895c6edba2e90a9189262876190dbbd21756870cdd63821810677 go1.19.10.linux-amd64.tar.gz' | shasum -a256 -c - && \
|
||||
sudo tar -C /usr/local -xzf go1.19.10.linux-amd64.tar.gz
|
||||
sudo ln -sf /usr/local/go/bin/{go,gofmt} /usr/local/bin/
|
||||
rm go1.18.8.linux-amd64.tar.gz
|
||||
rm go1.19.10.linux-amd64.tar.gz
|
||||
```
|
||||
|
||||
## 5. Node
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ The following Rake tasks are available for use with GitLab:
|
|||
| [Migrate snippets to Git](migrate_snippets.md) | Migrate GitLab Snippets to Git repositories, and show the migration status. |
|
||||
| [Praefect Rake tasks](../administration/raketasks/praefect.md) | [Praefect](../administration/gitaly/praefect.md)-related tasks. |
|
||||
| [Project import/export](../administration/raketasks/project_import_export.md) | Prepare for [project exports and imports](../user/project/settings/import_export.md). |
|
||||
| [Sample Prometheus data](generate_sample_prometheus_data.md) | Generate sample Prometheus data. |
|
||||
| [Sidekiq job migration](../administration/sidekiq/sidekiq_job_migration.md) | Migrate Sidekiq jobs scheduled for future dates to a new queue. |
|
||||
| [Service Desk email](../administration/raketasks/service_desk_email.md) | Service Desk email-related tasks. |
|
||||
| [SMTP maintenance](../administration/raketasks/smtp.md) | SMTP-related tasks. |
|
||||
|
|
|
|||
|
|
@ -297,4 +297,3 @@ and customized to fit your workflow. Here are some helpful resources for further
|
|||
1. [Incremental rollout to production](../cicd_variables.md#incremental-rollout-to-production)
|
||||
1. [Disable jobs you don't need with CI/CD variables](../cicd_variables.md)
|
||||
1. [Use your own buildpacks to build your application](../customize.md#custom-buildpacks)
|
||||
1. [Prometheus monitoring](../../../user/project/integrations/prometheus.md)
|
||||
|
|
|
|||
|
|
@ -302,4 +302,3 @@ and customized to fit your workflow. Here are some helpful resources for further
|
|||
1. [Incremental rollout to production](../cicd_variables.md#incremental-rollout-to-production)
|
||||
1. [Disable jobs you don't need with CI/CD variables](../cicd_variables.md)
|
||||
1. [Use your own buildpacks to build your application](../customize.md#custom-buildpacks)
|
||||
1. [Prometheus monitoring](../../../user/project/integrations/prometheus.md)
|
||||
|
|
|
|||
|
|
@ -96,11 +96,11 @@ Download and install Go (for Linux, 64-bit):
|
|||
# Remove former Go installation folder
|
||||
sudo rm -rf /usr/local/go
|
||||
|
||||
curl --remote-name --location --progress-bar "https://go.dev/dl/go1.18.8.linux-amd64.tar.gz"
|
||||
echo '4d854c7bad52d53470cf32f1b287a5c0c441dc6b98306dea27358e099698142a go1.18.8.linux-amd64.tar.gz' | shasum -a256 -c - && \
|
||||
sudo tar -C /usr/local -xzf go1.18.8.linux-amd64.tar.gz
|
||||
curl --remote-name --location --progress-bar "https://go.dev/dl/go1.19.10.linux-amd64.tar.gz"
|
||||
echo '8b045a483d3895c6edba2e90a9189262876190dbbd21756870cdd63821810677 go1.19.10.linux-amd64.tar.gz' | shasum -a256 -c - && \
|
||||
sudo tar -C /usr/local -xzf go1.19.10.linux-amd64.tar.gz
|
||||
sudo ln -sf /usr/local/go/bin/{go,gofmt} /usr/local/bin/
|
||||
rm go1.18.8.linux-amd64.tar.gz
|
||||
rm go1.19.10.linux-amd64.tar.gz
|
||||
```
|
||||
|
||||
### 6. Update Git
|
||||
|
|
|
|||
|
|
@ -160,6 +160,30 @@ Any group owner can approve or decline the request.
|
|||
If you change your mind before your request is approved, select
|
||||
**Withdraw Access Request**.
|
||||
|
||||
## View group members
|
||||
|
||||
To view a group's members:
|
||||
|
||||
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
|
||||
1. Select **Manage > Members**.
|
||||
|
||||
A table displays the member's:
|
||||
|
||||
- **Account** name and username
|
||||
- **Source** of their [membership](../project/members/index.md#membership-types).
|
||||
For transparency, GitLab displays all membership sources of group members.
|
||||
Members who have multiple membership sources are displayed and counted as separate members.
|
||||
For example, if a member has been added to the group both directly and through inheritance,
|
||||
the member is displayed twice in the **Members** table, with different sources,
|
||||
and is counted as two individual members of the group.
|
||||
- [**Max role**](../project/members/index.md#which-roles-you-can-assign) in the group
|
||||
- **Expiration** date of their group membership
|
||||
- **Activity** related to their account
|
||||
|
||||
NOTE:
|
||||
The display of group members' **Source** might be inconsistent.
|
||||
For more information, see [issue 414557](https://gitlab.com/gitlab-org/gitlab/-/issues/414557).
|
||||
|
||||
## Filter and sort members in a group
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21727) in GitLab 12.6.
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ You can configure the following integrations.
|
|||
| Packagist | Keep your PHP dependencies updated on Packagist. | **{check-circle}** Yes |
|
||||
| [Pipelines emails](pipeline_status_emails.md) | Send the pipeline status to a list of recipients by email. | **{dotted-circle}** No |
|
||||
| [Pivotal Tracker](pivotal_tracker.md) | Add commit messages as comments to Pivotal Tracker stories. | **{dotted-circle}** No |
|
||||
| [Prometheus](prometheus.md) | Monitor application metrics. | **{dotted-circle}** No |
|
||||
| [Pumble](pumble.md) | Send event notifications to a Pumble channel. | **{dotted-circle}** No |
|
||||
| Pushover | Get real-time notifications on your device. | **{dotted-circle}** No |
|
||||
| [Redmine](redmine.md) | Use Redmine as the issue tracker. | **{dotted-circle}** No |
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ Use the toggles to enable or disable features in the project.
|
|||
| **Wiki** | **{check-circle}** Yes | Enables a separate system for [documentation](../wiki/index.md).
|
||||
| **Snippets** | **{check-circle}** Yes | Enables [sharing of code and text](../../snippets.md).
|
||||
| **Pages** | **{check-circle}** Yes | Allows you to [publish static websites](../pages/index.md).
|
||||
| **Metrics Dashboard** | **{check-circle}** Yes | Control access to [metrics dashboard](../integrations/prometheus.md).
|
||||
| **Releases** | **{check-circle}** Yes | Control access to [Releases](../releases/index.md).
|
||||
| **Environments** | **{check-circle}** Yes | Control access to [Environments and Deployments](../../../ci/environments/index.md).
|
||||
| **Feature flags** | **{check-circle}** Yes | Control access to [Feature flags](../../../operations/feature_flags.md).
|
||||
|
|
|
|||
|
|
@ -20,18 +20,18 @@ cache:
|
|||
paths:
|
||||
- ${TF_ROOT}/.terraform/
|
||||
|
||||
.terraform:fmt: &terraform_fmt
|
||||
.terraform:fmt:
|
||||
stage: validate
|
||||
script:
|
||||
- gitlab-terraform fmt
|
||||
allow_failure: true
|
||||
|
||||
.terraform:validate: &terraform_validate
|
||||
.terraform:validate:
|
||||
stage: validate
|
||||
script:
|
||||
- gitlab-terraform validate
|
||||
|
||||
.terraform:build: &terraform_build
|
||||
.terraform:build:
|
||||
stage: build
|
||||
script:
|
||||
- gitlab-terraform plan
|
||||
|
|
@ -46,7 +46,7 @@ cache:
|
|||
reports:
|
||||
terraform: ${TF_ROOT}/plan.json
|
||||
|
||||
.terraform:deploy: &terraform_deploy
|
||||
.terraform:deploy:
|
||||
stage: deploy
|
||||
script:
|
||||
- gitlab-terraform apply
|
||||
|
|
@ -56,7 +56,7 @@ cache:
|
|||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
when: manual
|
||||
|
||||
.terraform:destroy: &terraform_destroy
|
||||
.terraform:destroy:
|
||||
stage: cleanup
|
||||
script:
|
||||
- gitlab-terraform destroy
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ variables:
|
|||
TF_ROOT: ${CI_PROJECT_DIR} # The relative path to the root directory of the Terraform project
|
||||
TF_STATE_NAME: default # The name of the state file used by the GitLab Managed Terraform state backend
|
||||
|
||||
.terraform:fmt: &terraform_fmt
|
||||
.terraform:fmt:
|
||||
stage: validate
|
||||
script:
|
||||
- gitlab-terraform fmt
|
||||
|
|
@ -33,7 +33,7 @@ variables:
|
|||
when: never
|
||||
- if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead.
|
||||
|
||||
.terraform:validate: &terraform_validate
|
||||
.terraform:validate:
|
||||
stage: validate
|
||||
script:
|
||||
- gitlab-terraform validate
|
||||
|
|
@ -43,7 +43,7 @@ variables:
|
|||
when: never
|
||||
- if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead.
|
||||
|
||||
.terraform:build: &terraform_build
|
||||
.terraform:build:
|
||||
stage: build
|
||||
script:
|
||||
- gitlab-terraform plan
|
||||
|
|
@ -63,7 +63,7 @@ variables:
|
|||
when: never
|
||||
- if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead.
|
||||
|
||||
.terraform:deploy: &terraform_deploy
|
||||
.terraform:deploy:
|
||||
stage: deploy
|
||||
script:
|
||||
- gitlab-terraform apply
|
||||
|
|
@ -73,7 +73,7 @@ variables:
|
|||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
when: manual
|
||||
|
||||
.terraform:destroy: &terraform_destroy
|
||||
.terraform:destroy:
|
||||
stage: cleanup
|
||||
script:
|
||||
- gitlab-terraform destroy
|
||||
|
|
|
|||
|
|
@ -4,13 +4,19 @@ module Gitlab
|
|||
module SidekiqMiddleware
|
||||
class DeferJobs
|
||||
DELAY = ENV.fetch("SIDEKIQ_DEFER_JOBS_DELAY", 5.minutes)
|
||||
FEATURE_FLAG_PREFIX = "defer_sidekiq_jobs"
|
||||
RUN_FEATURE_FLAG_PREFIX = "run_sidekiq_jobs"
|
||||
|
||||
DatabaseHealthStatusChecker = Struct.new(:id, :job_class_name)
|
||||
|
||||
DEFERRED_COUNTER = :sidekiq_jobs_deferred_total
|
||||
|
||||
def initialize
|
||||
@metrics = init_metrics
|
||||
end
|
||||
|
||||
# There are 2 scenarios under which this middleware defers a job
|
||||
# 1. defer_sidekiq_jobs_#{worker_name} FF, jobs are deferred indefinitely until this feature flag
|
||||
# is turned off or when Feature.enabled? returns false by chance while using `percentage of time` value.
|
||||
# 1. When run_sidekiq_jobs_#{worker_name} FF is disabled. This FF is enabled by default
|
||||
# for all workers.
|
||||
# 2. Gitlab::Database::HealthStatus, on evaluating the db health status if it returns any indicator
|
||||
# with stop signal, the jobs will be delayed by 'x' seconds (set in worker).
|
||||
def call(worker, job, _queue)
|
||||
|
|
@ -26,7 +32,7 @@ module Gitlab
|
|||
job['deferred_count'] += 1
|
||||
|
||||
worker.class.perform_in(delay, *job['args'])
|
||||
counter.increment({ worker: worker.class.name })
|
||||
@metrics.fetch(DEFERRED_COUNTER).increment({ worker: worker.class.name })
|
||||
|
||||
# This breaks the middleware chain and return
|
||||
return
|
||||
|
|
@ -38,18 +44,19 @@ module Gitlab
|
|||
private
|
||||
|
||||
def defer_job_info(worker_class, job)
|
||||
if defer_job_by_ff?(worker_class)
|
||||
if !run_job_by_ff?(worker_class)
|
||||
[true, DELAY, :feature_flag]
|
||||
elsif defer_job_by_database_health_signal?(job, worker_class)
|
||||
[true, worker_class.database_health_check_attrs[:delay_by], :database_health_check]
|
||||
end
|
||||
end
|
||||
|
||||
def defer_job_by_ff?(worker_class)
|
||||
def run_job_by_ff?(worker_class)
|
||||
# always returns true by default for all workers unless the FF is specifically disabled, e.g. during an incident
|
||||
Feature.enabled?(
|
||||
:"#{FEATURE_FLAG_PREFIX}_#{worker_class.name}",
|
||||
:"#{RUN_FEATURE_FLAG_PREFIX}_#{worker_class.name}",
|
||||
type: :worker,
|
||||
default_enabled_if_undefined: false
|
||||
default_enabled_if_undefined: true
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -72,8 +79,10 @@ module Gitlab
|
|||
Gitlab::Database::HealthStatus.evaluate(health_context).any?(&:stop?)
|
||||
end
|
||||
|
||||
def counter
|
||||
@counter ||= Gitlab::Metrics.counter(:sidekiq_jobs_deferred_total, 'The number of jobs deferred')
|
||||
def init_metrics
|
||||
{
|
||||
DEFERRED_COUNTER => Gitlab::Metrics.counter(DEFERRED_COUNTER, 'The number of jobs deferred')
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23421,6 +23421,9 @@ msgstr ""
|
|||
msgid "Improve customer support with Service Desk"
|
||||
msgstr ""
|
||||
|
||||
msgid "Improve indexing performance by increasing Sidekiq load. Values greater than the current shard limit (%{limit}) are not allowed."
|
||||
msgstr ""
|
||||
|
||||
msgid "Improve quality with test cases"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -31531,6 +31534,9 @@ msgstr ""
|
|||
msgid "Number of shards"
|
||||
msgstr ""
|
||||
|
||||
msgid "Number of shards for non-code indexing"
|
||||
msgstr ""
|
||||
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -33499,6 +33505,9 @@ msgstr ""
|
|||
msgid "PipelineSchedules|All"
|
||||
msgstr ""
|
||||
|
||||
msgid "PipelineSchedules|An error occurred while creating the pipeline schedule."
|
||||
msgstr ""
|
||||
|
||||
msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Search
|
||||
# Cop that prevents checking migration_has_finished? on deprecated migrations
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# def disable_project_joins_for_blob?
|
||||
# Elastic::DataMigrationService
|
||||
# .migration_has_finished?(:backfill_project_permissions_in_blobs_using_permutations)
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# def disable_project_joins_for_blob?
|
||||
# Elastic::DataMigrationService.migration_has_finished?(:backfill_project_permissions_in_blobs)
|
||||
# end
|
||||
|
||||
class AvoidCheckingFinishedOnDeprecatedMigrations < RuboCop::Cop::Base
|
||||
MSG = 'Migration is deprecated and can not be used with `migration_has_finished?`.'
|
||||
|
||||
def_node_matcher :deprecated_migration?, <<~PATTERN
|
||||
(send
|
||||
(const (const {nil? cbase} :Elastic) :DataMigrationService) :migration_has_finished?
|
||||
(sym :backfill_project_permissions_in_blobs_using_permutations))
|
||||
PATTERN
|
||||
|
||||
RESTRICT_ON_SEND = %i[migration_has_finished?].freeze
|
||||
|
||||
def on_send(node)
|
||||
add_offense(node) if deprecated_migration?(node)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -151,7 +151,9 @@ function debug_rspec_variables() {
|
|||
function handle_retry_rspec_in_new_process() {
|
||||
local rspec_run_status="${1}"
|
||||
|
||||
if [[ $rspec_run_status -eq 2 ]]; then
|
||||
if [[ $rspec_run_status -eq 3 ]]; then
|
||||
echoerr "Not retrying failing examples since we failed early on purpose!"
|
||||
elif [[ $rspec_run_status -eq 2 ]]; then
|
||||
echoerr "Not retrying failing examples since there were errors happening outside of the RSpec examples!"
|
||||
elif [[ $rspec_run_status -eq 1 ]]; then
|
||||
# Experiment to retry failed examples in a new RSpec process: https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1148
|
||||
|
|
|
|||
|
|
@ -1,14 +1,29 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { GlForm } from '@gitlab/ui';
|
||||
import { nextTick } from 'vue';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { createAlert } from '~/alert';
|
||||
import PipelineSchedulesForm from '~/ci/pipeline_schedules/components/pipeline_schedules_form.vue';
|
||||
import RefSelector from '~/ref/components/ref_selector.vue';
|
||||
import { REF_TYPE_BRANCHES, REF_TYPE_TAGS } from '~/ref/constants';
|
||||
import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown/timezone_dropdown.vue';
|
||||
import IntervalPatternInput from '~/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue';
|
||||
import createPipelineScheduleMutation from '~/ci/pipeline_schedules/graphql/mutations/create_pipeline_schedule.mutation.graphql';
|
||||
import { timezoneDataFixture } from '../../../vue_shared/components/timezone_dropdown/helpers';
|
||||
import { createScheduleMutationResponse } from '../mock_data';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
jest.mock('~/alert');
|
||||
jest.mock('~/lib/utils/url_utility', () => ({
|
||||
visitUrl: jest.fn(),
|
||||
joinPaths: jest.fn().mockReturnValue(''),
|
||||
}));
|
||||
|
||||
describe('Pipeline schedules form', () => {
|
||||
let wrapper;
|
||||
|
|
@ -17,11 +32,21 @@ describe('Pipeline schedules form', () => {
|
|||
const cron = '';
|
||||
const dailyLimit = '';
|
||||
|
||||
const createComponent = (mountFn = shallowMountExtended, stubs = {}) => {
|
||||
const createMutationHandlerSuccess = jest.fn().mockResolvedValue(createScheduleMutationResponse);
|
||||
const createMutationHandlerFailed = jest.fn().mockRejectedValue(new Error('GraphQL error'));
|
||||
|
||||
const createMockApolloProvider = (
|
||||
requestHandlers = [[createPipelineScheduleMutation, createMutationHandlerSuccess]],
|
||||
) => {
|
||||
return createMockApollo(requestHandlers);
|
||||
};
|
||||
|
||||
const createComponent = (mountFn = shallowMountExtended, editing = false, requestHandlers) => {
|
||||
wrapper = mountFn(PipelineSchedulesForm, {
|
||||
propsData: {
|
||||
timezoneData: timezoneDataFixture,
|
||||
refParam: 'master',
|
||||
editing,
|
||||
},
|
||||
provide: {
|
||||
fullPath: 'gitlab-org/gitlab',
|
||||
|
|
@ -31,8 +56,9 @@ describe('Pipeline schedules form', () => {
|
|||
cronTimezone: '',
|
||||
dailyLimit,
|
||||
settingsLink: '',
|
||||
schedulesPath: '/root/ci-project/-/pipeline_schedules',
|
||||
},
|
||||
stubs,
|
||||
apolloProvider: createMockApolloProvider(requestHandlers),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -49,11 +75,17 @@ describe('Pipeline schedules form', () => {
|
|||
const findValueInputs = () => wrapper.findAllByTestId('pipeline-form-ci-variable-value');
|
||||
const findRemoveIcons = () => wrapper.findAllByTestId('remove-ci-variable-row');
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
const addVariableToForm = () => {
|
||||
const input = findKeyInputs().at(0);
|
||||
input.element.value = 'test_var_2';
|
||||
input.trigger('change');
|
||||
};
|
||||
|
||||
describe('Form elements', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('displays form', () => {
|
||||
expect(findForm().exists()).toBe(true);
|
||||
});
|
||||
|
|
@ -102,19 +134,16 @@ describe('Pipeline schedules form', () => {
|
|||
it('displays the submit and cancel buttons', () => {
|
||||
expect(findSubmitButton().exists()).toBe(true);
|
||||
expect(findCancelButton().exists()).toBe(true);
|
||||
expect(findCancelButton().attributes('href')).toBe('/root/ci-project/-/pipeline_schedules');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CI variables', () => {
|
||||
let mock;
|
||||
|
||||
const addVariableToForm = () => {
|
||||
const input = findKeyInputs().at(0);
|
||||
input.element.value = 'test_var_2';
|
||||
input.trigger('change');
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
// mock is needed when we fully mount
|
||||
// downstream components request needs to be mocked
|
||||
mock = new MockAdapter(axios);
|
||||
createComponent(mountExtended);
|
||||
});
|
||||
|
|
@ -157,4 +186,77 @@ describe('Pipeline schedules form', () => {
|
|||
expect(findVariableRows()).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('schedule creation', () => {
|
||||
describe('schedule creation success', () => {
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
// mock is needed when we fully mount
|
||||
// downstream components request needs to be mocked
|
||||
mock = new MockAdapter(axios);
|
||||
createComponent(mountExtended);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
it('creates pipeline schedule', async () => {
|
||||
findDescription().element.value = 'My schedule';
|
||||
findDescription().trigger('change');
|
||||
|
||||
findTimezoneDropdown().vm.$emit('input', {
|
||||
formattedTimezone: '[UTC-4] Eastern Time (US & Canada)',
|
||||
identifier: 'America/New_York',
|
||||
});
|
||||
|
||||
findIntervalComponent().vm.$emit('cronValue', '0 16 * * *');
|
||||
|
||||
addVariableToForm();
|
||||
|
||||
findSubmitButton().vm.$emit('click');
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(createMutationHandlerSuccess).toHaveBeenCalledWith({
|
||||
input: {
|
||||
active: true,
|
||||
cron: '0 16 * * *',
|
||||
cronTimezone: 'America/New_York',
|
||||
description: 'My schedule',
|
||||
projectPath: 'gitlab-org/gitlab',
|
||||
ref: 'main',
|
||||
variables: [
|
||||
{
|
||||
key: 'test_var_2',
|
||||
value: '',
|
||||
variableType: 'ENV_VAR',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(visitUrl).toHaveBeenCalledWith('/root/ci-project/-/pipeline_schedules');
|
||||
expect(createAlert).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('schedule creation failure', () => {
|
||||
beforeEach(() => {
|
||||
createComponent(shallowMountExtended, false, [
|
||||
[createPipelineScheduleMutation, createMutationHandlerFailed],
|
||||
]);
|
||||
});
|
||||
|
||||
it('shows error for failed pipeline schedule creation', async () => {
|
||||
findSubmitButton().vm.$emit('click');
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: 'An error occurred while creating the pipeline schedule.',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ describe('Pipeline schedules app', () => {
|
|||
wrapper = mountExtended(PipelineSchedules, {
|
||||
provide: {
|
||||
fullPath: 'gitlab-org/gitlab',
|
||||
newSchedulePath: '/root/ci-project/-/pipeline_schedules/new',
|
||||
},
|
||||
mocks: {
|
||||
$toast,
|
||||
|
|
@ -101,6 +102,10 @@ describe('Pipeline schedules app', () => {
|
|||
|
||||
expect(findLoadingIcon().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('new schedule button links to new schedule path', () => {
|
||||
expect(findNewButton().attributes('href')).toBe('/root/ci-project/-/pipeline_schedules/new');
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetching pipeline schedules', () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { GlButton } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import PipelineScheduleActions from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import {
|
||||
mockPipelineScheduleNodes,
|
||||
mockPipelineScheduleCurrentUser,
|
||||
|
|
@ -28,6 +29,7 @@ describe('Pipeline schedule actions', () => {
|
|||
const findDeleteBtn = () => wrapper.findByTestId('delete-pipeline-schedule-btn');
|
||||
const findTakeOwnershipBtn = () => wrapper.findByTestId('take-ownership-pipeline-schedule-btn');
|
||||
const findPlayScheduleBtn = () => wrapper.findByTestId('play-pipeline-schedule-btn');
|
||||
const findEditScheduleBtn = () => wrapper.findByTestId('edit-pipeline-schedule-btn');
|
||||
|
||||
it('displays buttons when user is the owner of schedule and has adminPipelineSchedule permissions', () => {
|
||||
createComponent();
|
||||
|
|
@ -76,4 +78,15 @@ describe('Pipeline schedule actions', () => {
|
|||
playPipelineSchedule: [[mockPipelineScheduleNodes[0].id]],
|
||||
});
|
||||
});
|
||||
|
||||
it('edit button links to edit schedule path', () => {
|
||||
createComponent();
|
||||
|
||||
const { schedule } = defaultProps;
|
||||
const id = getIdFromGraphQLId(schedule.id);
|
||||
|
||||
const expectedPath = `${schedule.editPath}?id=${id}`;
|
||||
|
||||
expect(findEditScheduleBtn().attributes('href')).toBe(expectedPath);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -79,4 +79,14 @@ export const takeOwnershipMutationResponse = {
|
|||
},
|
||||
};
|
||||
|
||||
export const createScheduleMutationResponse = {
|
||||
data: {
|
||||
pipelineScheduleCreate: {
|
||||
clientMutationId: null,
|
||||
errors: [],
|
||||
__typename: 'PipelineScheduleCreatePayload',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export { mockGetPipelineSchedulesGraphQLResponse };
|
||||
|
|
|
|||
|
|
@ -219,4 +219,17 @@ describe('Interval Pattern Input Component', () => {
|
|||
expect(findIcon().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cronValue event', () => {
|
||||
it('emits cronValue event with cron value', async () => {
|
||||
createWrapper();
|
||||
|
||||
findCustomInput().element.value = '0 16 * * *';
|
||||
findCustomInput().trigger('input');
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.emitted()).toEqual({ cronValue: [['0 16 * * *']] });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import todoMarkDoneMutation from '~/graphql_shared/mutations/todo_mark_done.mutation.graphql';
|
||||
import SidebarTodo from '~/vue_shared/alert_details/components/sidebar/sidebar_todo.vue';
|
||||
import createAlertTodoMutation from '~/vue_shared/alert_details/graphql/mutations/alert_todo_create.mutation.graphql';
|
||||
|
|
@ -9,41 +11,39 @@ const mockAlert = mockAlerts[0];
|
|||
|
||||
describe('Alert Details Sidebar To Do', () => {
|
||||
let wrapper;
|
||||
let requestHandler;
|
||||
|
||||
function mountComponent({ data, sidebarCollapsed = true, loading = false, stubs = {} } = {}) {
|
||||
const defaultHandler = {
|
||||
createAlertTodo: jest.fn().mockResolvedValue({}),
|
||||
markAsDone: jest.fn().mockResolvedValue({}),
|
||||
};
|
||||
|
||||
const createMockApolloProvider = (handler) => {
|
||||
Vue.use(VueApollo);
|
||||
|
||||
requestHandler = handler;
|
||||
|
||||
return createMockApollo([
|
||||
[todoMarkDoneMutation, handler.markAsDone],
|
||||
[createAlertTodoMutation, handler.createAlertTodo],
|
||||
]);
|
||||
};
|
||||
|
||||
function mountComponent({ data, sidebarCollapsed = true, handler = defaultHandler } = {}) {
|
||||
wrapper = mount(SidebarTodo, {
|
||||
apolloProvider: createMockApolloProvider(handler),
|
||||
propsData: {
|
||||
alert: { ...mockAlert },
|
||||
...data,
|
||||
sidebarCollapsed,
|
||||
projectPath: 'projectPath',
|
||||
},
|
||||
mocks: {
|
||||
$apollo: {
|
||||
mutate: jest.fn(),
|
||||
queries: {
|
||||
alert: {
|
||||
loading,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
stubs,
|
||||
});
|
||||
}
|
||||
|
||||
const findToDoButton = () => wrapper.find('[data-testid="alert-todo-button"]');
|
||||
|
||||
describe('updating the alert to do', () => {
|
||||
const mockUpdatedMutationResult = {
|
||||
data: {
|
||||
updateAlertTodo: {
|
||||
errors: [],
|
||||
alert: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('adding a todo', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({
|
||||
|
|
@ -60,18 +60,15 @@ describe('Alert Details Sidebar To Do', () => {
|
|||
});
|
||||
|
||||
it('calls `$apollo.mutate` with `createAlertTodoMutation` mutation and variables containing `iid`, `todoEvent`, & `projectPath`', async () => {
|
||||
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult);
|
||||
|
||||
findToDoButton().trigger('click');
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
|
||||
mutation: createAlertTodoMutation,
|
||||
variables: {
|
||||
expect(requestHandler.createAlertTodo).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
iid: '1527542',
|
||||
projectPath: 'projectPath',
|
||||
},
|
||||
});
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -91,17 +88,11 @@ describe('Alert Details Sidebar To Do', () => {
|
|||
});
|
||||
|
||||
it('calls `$apollo.mutate` with `todoMarkDoneMutation` mutation and variables containing `id`', async () => {
|
||||
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult);
|
||||
|
||||
findToDoButton().trigger('click');
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
|
||||
mutation: todoMarkDoneMutation,
|
||||
update: expect.anything(),
|
||||
variables: {
|
||||
id: '1234',
|
||||
},
|
||||
expect(requestHandler.markAsDone).toHaveBeenCalledWith({
|
||||
id: '1234',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,19 +5,10 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::SidekiqMiddleware::DeferJobs, feature_category: :scalability do
|
||||
let(:job) { { 'jid' => 123, 'args' => [456] } }
|
||||
let(:queue) { 'test_queue' }
|
||||
let(:deferred_worker) do
|
||||
let(:test_worker) do
|
||||
Class.new do
|
||||
def self.name
|
||||
'TestDeferredWorker'
|
||||
end
|
||||
include ApplicationWorker
|
||||
end
|
||||
end
|
||||
|
||||
let(:undeferred_worker) do
|
||||
Class.new do
|
||||
def self.name
|
||||
'UndeferredWorker'
|
||||
'TestWorker'
|
||||
end
|
||||
include ApplicationWorker
|
||||
end
|
||||
|
|
@ -26,55 +17,43 @@ RSpec.describe Gitlab::SidekiqMiddleware::DeferJobs, feature_category: :scalabil
|
|||
subject { described_class.new }
|
||||
|
||||
before do
|
||||
stub_const('TestDeferredWorker', deferred_worker)
|
||||
stub_const('UndeferredWorker', undeferred_worker)
|
||||
stub_const('TestWorker', test_worker)
|
||||
end
|
||||
|
||||
describe '#call' do
|
||||
context 'with worker not opted for database health check' do
|
||||
context 'when sidekiq_defer_jobs feature flag is enabled for a worker' do
|
||||
context 'when run_sidekiq_jobs feature flag is disabled' do
|
||||
let(:deferred_jobs_metric) { instance_double(Prometheus::Client::Counter, increment: true) }
|
||||
|
||||
before do
|
||||
stub_feature_flags("defer_sidekiq_jobs_#{TestDeferredWorker.name}": true)
|
||||
stub_feature_flags("defer_sidekiq_jobs_#{UndeferredWorker.name}": false)
|
||||
stub_feature_flags(run_sidekiq_jobs_TestWorker: false)
|
||||
allow(Gitlab::Metrics).to receive(:counter).and_call_original
|
||||
allow(Gitlab::Metrics).to receive(:counter).with(described_class::DEFERRED_COUNTER, anything)
|
||||
.and_return(deferred_jobs_metric)
|
||||
end
|
||||
|
||||
context 'for the affected worker' do
|
||||
it 'defers the job' do
|
||||
expect(TestDeferredWorker).to receive(:perform_in).with(described_class::DELAY, *job['args'])
|
||||
expect { |b| subject.call(TestDeferredWorker.new, job, queue, &b) }.not_to yield_control
|
||||
end
|
||||
it 'defers the job' do
|
||||
expect(TestWorker).to receive(:perform_in).with(described_class::DELAY, *job['args'])
|
||||
expect { |b| subject.call(TestWorker.new, job, queue, &b) }.not_to yield_control
|
||||
end
|
||||
|
||||
it 'increments the defer_count' do
|
||||
(1..5).each do |count|
|
||||
subject.call(TestDeferredWorker.new, job, queue)
|
||||
expect(job).to include('deferred_count' => count)
|
||||
end
|
||||
it 'increments the defer_count' do
|
||||
(1..5).each do |count|
|
||||
subject.call(TestWorker.new, job, queue)
|
||||
expect(job).to include('deferred_count' => count)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for other workers' do
|
||||
it 'runs the job normally' do
|
||||
expect { |b| subject.call(UndeferredWorker.new, job, queue, &b) }.to yield_control
|
||||
end
|
||||
end
|
||||
it 'increments the counter' do
|
||||
expect(deferred_jobs_metric).to receive(:increment).with({ worker: "TestWorker" })
|
||||
|
||||
it 'increments the metric counter' do
|
||||
subject.call(TestDeferredWorker.new, job, queue)
|
||||
|
||||
counter = ::Gitlab::Metrics.registry.get(:sidekiq_jobs_deferred_total)
|
||||
expect(counter.get({ worker: "TestDeferredWorker" })).to eq(1)
|
||||
subject.call(TestWorker.new, job, queue)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when sidekiq_defer_jobs feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags("defer_sidekiq_jobs_#{TestDeferredWorker.name}": false)
|
||||
stub_feature_flags("defer_sidekiq_jobs_#{UndeferredWorker.name}": false)
|
||||
end
|
||||
|
||||
context 'when run_sidekiq_jobs feature flag is enabled' do
|
||||
it 'runs the job normally' do
|
||||
expect { |b| subject.call(TestDeferredWorker.new, job, queue, &b) }.to yield_control
|
||||
expect { |b| subject.call(UndeferredWorker.new, job, queue, &b) }.to yield_control
|
||||
expect { |b| subject.call(TestWorker.new, job, queue, &b) }.to yield_control
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -90,14 +69,12 @@ RSpec.describe Gitlab::SidekiqMiddleware::DeferJobs, feature_category: :scalabil
|
|||
end
|
||||
|
||||
before do
|
||||
stub_feature_flags("defer_sidekiq_jobs_#{TestDeferredWorker.name}": false)
|
||||
|
||||
TestDeferredWorker.defer_on_database_health_signal(*health_signal_attrs.values)
|
||||
TestWorker.defer_on_database_health_signal(*health_signal_attrs.values)
|
||||
end
|
||||
|
||||
context 'without any stop signal from database health check' do
|
||||
it 'runs the job normally' do
|
||||
expect { |b| subject.call(TestDeferredWorker.new, job, queue, &b) }.to yield_control
|
||||
expect { |b| subject.call(TestWorker.new, job, queue, &b) }.to yield_control
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -108,9 +85,9 @@ RSpec.describe Gitlab::SidekiqMiddleware::DeferJobs, feature_category: :scalabil
|
|||
end
|
||||
|
||||
it 'defers the job by set time' do
|
||||
expect(TestDeferredWorker).to receive(:perform_in).with(health_signal_attrs[:delay], *job['args'])
|
||||
expect(TestWorker).to receive(:perform_in).with(health_signal_attrs[:delay], *job['args'])
|
||||
|
||||
TestDeferredWorker.perform_async(*job['args'])
|
||||
TestWorker.perform_async(*job['args'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ RSpec.describe Gitlab::SidekiqMiddleware do
|
|||
shared_examples "a middleware chain" do
|
||||
before do
|
||||
configurator.call(chain)
|
||||
stub_feature_flags("defer_sidekiq_jobs_#{worker_class.name}": false) # not letting this worker deferring its jobs
|
||||
end
|
||||
it "passes through the right middlewares", :aggregate_failures do
|
||||
enabled_sidekiq_middlewares.each do |middleware|
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe UpdateElasticsearchNumberOfShardsInApplicationSettingsForGitlabCom, feature_category: :global_search do
|
||||
let(:settings) { table(:application_settings) }
|
||||
|
||||
describe "#up" do
|
||||
it 'does nothing when not in gitlab.com' do
|
||||
record = settings.create!
|
||||
|
||||
expect { migrate! }.not_to change { record.reload.elasticsearch_worker_number_of_shards }
|
||||
end
|
||||
|
||||
it 'updates elasticsearch_worker_number_of_shards when gitlab.com' do
|
||||
allow(Gitlab).to receive(:com?).and_return(true)
|
||||
|
||||
record = settings.create!
|
||||
|
||||
expect { migrate! }.to change { record.reload.elasticsearch_worker_number_of_shards }.from(2).to(16)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#down" do
|
||||
it 'does nothing when not in gitlab.com' do
|
||||
record = settings.create!(elasticsearch_worker_number_of_shards: 16)
|
||||
|
||||
migrate!
|
||||
|
||||
expect { schema_migrate_down! }.not_to change { record.reload.elasticsearch_worker_number_of_shards }
|
||||
end
|
||||
|
||||
it 'updates elasticsearch_worker_number_of_shards when gitlab.com' do
|
||||
allow(Gitlab).to receive(:com?).and_return(true)
|
||||
|
||||
record = settings.create!(elasticsearch_worker_number_of_shards: 16)
|
||||
|
||||
migrate!
|
||||
|
||||
expect { schema_migrate_down! }.to change { record.reload.elasticsearch_worker_number_of_shards }.from(16).to(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rubocop_spec_helper'
|
||||
require_relative '../../../../rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations'
|
||||
|
||||
RSpec.describe RuboCop::Cop::Search::AvoidCheckingFinishedOnDeprecatedMigrations, feature_category: :global_search do
|
||||
context 'when a deprecated class is used with migration_has_finished?' do
|
||||
it 'flags it as an offense' do
|
||||
expect_offense <<~SOURCE
|
||||
return if Elastic::DataMigrationService.migration_has_finished?(:backfill_project_permissions_in_blobs_using_permutations)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migration is deprecated and can not be used with `migration_has_finished?`.
|
||||
SOURCE
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a non deprecated class is used with migration_has_finished?' do
|
||||
it 'does not flag it as an offense' do
|
||||
expect_no_offenses <<~SOURCE
|
||||
return if Elastic::DataMigrationService.migration_has_finished?(:backfill_project_permissions_in_blobs)
|
||||
SOURCE
|
||||
end
|
||||
end
|
||||
|
||||
context 'when migration_has_finished? method is called on another class' do
|
||||
it 'does not flag it as an offense' do
|
||||
expect_no_offenses <<~SOURCE
|
||||
return if Klass.migration_has_finished?(:backfill_project_permissions_in_blobs_using_permutations)
|
||||
SOURCE
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -122,7 +122,7 @@ RSpec.configure do |config|
|
|||
warn "********************************************************************************************"
|
||||
warn
|
||||
|
||||
exit 1
|
||||
exit 3
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue