Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
8b2a413032
commit
55a8c39b97
|
|
@ -795,7 +795,6 @@ lib/gitlab/checks/**
|
|||
/doc/api/import.md @ashrafkhamis
|
||||
/doc/api/instance_clusters.md @z_painter
|
||||
/doc/api/instance_level_ci_variables.md @marcel.amirault
|
||||
/doc/api/integrations.md @ashrafkhamis
|
||||
/doc/api/invitations.md @emily.sahlani
|
||||
/doc/api/issue_links.md @msedlakjakubowski
|
||||
/doc/api/issues.md @msedlakjakubowski
|
||||
|
|
@ -840,6 +839,7 @@ lib/gitlab/checks/**
|
|||
/doc/api/project_clusters.md @z_painter
|
||||
/doc/api/project_forks.md @emily.sahlani
|
||||
/doc/api/project_import_export.md @ashrafkhamis
|
||||
/doc/api/project_integrations.md @ashrafkhamis
|
||||
/doc/api/project_job_token_scopes.md @marcel.amirault
|
||||
/doc/api/project_level_variables.md @marcel.amirault
|
||||
/doc/api/project_markdown_uploads.md @msedlakjakubowski
|
||||
|
|
@ -1027,7 +1027,7 @@ lib/gitlab/checks/**
|
|||
/doc/raketasks/x509_signatures.md @brendan777
|
||||
/doc/security/ @idurham
|
||||
/doc/security/hardening_nist_800_53.md @emily.sahlani
|
||||
/doc/solutions/ @jfullam @brianwald @Darwinjs
|
||||
/doc/solutions/ @jfullam @Darwinjs @sbrightwell
|
||||
/doc/solutions/integrations/servicenow.md @ashrafkhamis
|
||||
/doc/subscriptions/ @lciutacu
|
||||
/doc/subscriptions/gitlab_com/ @lyspin
|
||||
|
|
@ -1111,8 +1111,6 @@ lib/gitlab/checks/**
|
|||
/doc/user/group/_index.md @emily.sahlani
|
||||
/doc/user/group/access_and_permissions.md @emily.sahlani
|
||||
/doc/user/group/clusters/ @z_painter
|
||||
/doc/user/group/compliance_frameworks.md @eread
|
||||
/doc/user/group/compliance_pipelines.md @eread
|
||||
/doc/user/group/contribution_analytics/ @lciutacu
|
||||
/doc/user/group/credentials_inventory.md @idurham
|
||||
/doc/user/group/custom_project_templates.md @brendan777
|
||||
|
|
|
|||
|
|
@ -2,15 +2,8 @@
|
|||
# Cop supports --autocorrect.
|
||||
Style/SymbolProc:
|
||||
Exclude:
|
||||
- 'app/controllers/profiles_controller.rb'
|
||||
- 'app/models/ci/pipeline.rb'
|
||||
- 'app/models/container_repository.rb'
|
||||
- 'app/models/discussion.rb'
|
||||
- 'app/models/environment.rb'
|
||||
- 'app/models/integrations/prometheus.rb'
|
||||
- 'app/models/members/project_member.rb'
|
||||
- 'app/models/preloaders/merge_request_diff_preloader.rb'
|
||||
- 'app/models/release.rb'
|
||||
- 'app/models/remote_mirror.rb'
|
||||
- 'app/models/snippet_input_action_collection.rb'
|
||||
- 'app/policies/group_policy.rb'
|
||||
|
|
@ -95,10 +88,6 @@ Style/SymbolProc:
|
|||
- 'lib/api/helpers/internal_helpers.rb'
|
||||
- 'lib/atlassian/jira_connect/serializers/base_entity.rb'
|
||||
- 'lib/bulk_imports/common/pipelines/entity_finisher.rb'
|
||||
- 'lib/bulk_imports/ndjson_pipeline.rb'
|
||||
- 'lib/container_registry/client.rb'
|
||||
- 'lib/container_registry/gitlab_api_client.rb'
|
||||
- 'lib/gitlab/analytics/cycle_analytics/stage_events.rb'
|
||||
- 'lib/gitlab/auth/o_auth/auth_hash.rb'
|
||||
- 'lib/gitlab/blob_helper.rb'
|
||||
- 'lib/gitlab/cache/ci/project_pipeline_status.rb'
|
||||
|
|
@ -188,4 +177,3 @@ Style/SymbolProc:
|
|||
- 'spec/support/shared_examples/models/label_note_shared_examples.rb'
|
||||
- 'spec/views/layouts/_published_experiments.html.haml_spec.rb'
|
||||
- 'spec/workers/snippets/schedule_bulk_repository_shard_moves_worker_spec.rb'
|
||||
- 'tooling/lib/tooling/test_map_generator.rb'
|
||||
|
|
|
|||
35
CHANGELOG.md
35
CHANGELOG.md
|
|
@ -2,6 +2,19 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 17.9.1 (2025-02-26)
|
||||
|
||||
### Fixed (1 change)
|
||||
|
||||
- [Fix instance level dashboard by default severity override](https://gitlab.com/gitlab-org/security/gitlab/-/commit/56d2f940bb6e87b34e4f26ba9a298f28360dd23a) **GitLab Enterprise Edition**
|
||||
|
||||
### Security (4 changes)
|
||||
|
||||
- [Increase minimum role in SPP to read policy yaml](https://gitlab.com/gitlab-org/security/gitlab/-/commit/593c0a6f70564e9570fb16b25a37298eacf6c644) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4718))
|
||||
- [Fix access to read code review analytics in private projects](https://gitlab.com/gitlab-org/security/gitlab/-/commit/0faa526c76e3c523ff6486057c5b5b07e8e4e5d9) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4794))
|
||||
- [Escape work item dropdown items and restrict HTML tags](https://gitlab.com/gitlab-org/security/gitlab/-/commit/fc777a98ebd45b30ab95bc0d94a418479d15f09c) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4788))
|
||||
- [Use stricter CSP values in the packages dependency proxy](https://gitlab.com/gitlab-org/security/gitlab/-/commit/922d3ad17cf7493a10f8dbf90c0cae8d9d4b063d) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4787))
|
||||
|
||||
## 17.9.0 (2025-02-19)
|
||||
|
||||
### Added (202 changes)
|
||||
|
|
@ -1083,6 +1096,15 @@ entry.
|
|||
- [Quarantine a flaky test](https://gitlab.com/gitlab-org/gitlab/-/commit/c932e35efdc0e3c6f316a3c2d37045e115ce8cd5) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/176452))
|
||||
- [Finalize migration BackfillRemoteDevelopmentAgentConfigsProjectId](https://gitlab.com/gitlab-org/gitlab/-/commit/da4c63d7aab3685c3fbe9d1e48f68ba2162a0b5e) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/172769))
|
||||
|
||||
## 17.8.4 (2025-02-26)
|
||||
|
||||
### Security (4 changes)
|
||||
|
||||
- [Increase minimum role in SPP to read policy yaml](https://gitlab.com/gitlab-org/security/gitlab/-/commit/9bfcf4a596b965ce73426d68861cec83ee70f19e) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4716))
|
||||
- [Fix access to read code review analytics in private projects](https://gitlab.com/gitlab-org/security/gitlab/-/commit/537159f505cad7d23cded01140fbdfd84e9cdfa2) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4758))
|
||||
- [Escape work item dropdown items and restrict HTML tags](https://gitlab.com/gitlab-org/security/gitlab/-/commit/5548168c3d4e0ba660ed934f23c332045a640799) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4784))
|
||||
- [Use stricter CSP values in the packages dependency proxy](https://gitlab.com/gitlab-org/security/gitlab/-/commit/d491abd511c9c1cb00c928e28dc84cb7ef8e4cd3) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4764))
|
||||
|
||||
## 17.8.3 (2025-02-21)
|
||||
|
||||
### Fixed (2 changes)
|
||||
|
|
@ -1574,6 +1596,19 @@ entry.
|
|||
- [Remove default on `group_saved_replies_flag feature flag](https://gitlab.com/gitlab-org/gitlab/-/commit/75d49fe13646e1e0d3b68233ac4a965c86853917) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175647))
|
||||
- [Remove use_actual_plan_in_license_check flag](https://gitlab.com/gitlab-org/gitlab/-/commit/b8c3fe16aedb69c82ff52d1c695d72e933c4b946) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175649))
|
||||
|
||||
## 17.7.6 (2025-02-26)
|
||||
|
||||
### Fixed (1 change)
|
||||
|
||||
- [Fix failed jobs widget polling issue](https://gitlab.com/gitlab-org/security/gitlab/-/commit/e2154d3d886d82e1f5fe62fb9d234d00e257e784)
|
||||
|
||||
### Security (4 changes)
|
||||
|
||||
- [Increase minimum role in SPP to read policy yaml](https://gitlab.com/gitlab-org/security/gitlab/-/commit/6d5c2ea1feb6097cb5720650f39b3808554b6a29) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4717))
|
||||
- [Fix access to read code review analytics in private projects](https://gitlab.com/gitlab-org/security/gitlab/-/commit/4454c18d19d2d8df92520f4c0fafa24ddbf9fbe4) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4757))
|
||||
- [Escape work item dropdown items and restrict HTML tags](https://gitlab.com/gitlab-org/security/gitlab/-/commit/a834b94cf4e967065590f6b78b15c8733d67df30) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4785))
|
||||
- [Use stricter CSP values in the packages dependency proxy](https://gitlab.com/gitlab-org/security/gitlab/-/commit/d975b402434b9e17ff2963d9c4c6f438f52545ed) ([merge request](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4765))
|
||||
|
||||
## 17.7.5 (2025-02-21)
|
||||
|
||||
### Fixed (1 change)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
afc35fcc49db7d999d74b4f2fcccc2625567bd75
|
||||
efced52dc4e4f9f202e32dc6239573d4aceb4d4e
|
||||
|
|
|
|||
|
|
@ -58,6 +58,11 @@ export default {
|
|||
required: false,
|
||||
default: '',
|
||||
},
|
||||
ariaLabelledBy: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -158,6 +163,7 @@ export default {
|
|||
:loading="isDropdownLoading"
|
||||
:searching="isDropdownSearching"
|
||||
:toggle-text="toggleText"
|
||||
:toggle-aria-labelled-by="ariaLabelledBy"
|
||||
@search="debouncedSearch"
|
||||
@select="selectEnvironment"
|
||||
@shown="toggleDropdownShown(true)"
|
||||
|
|
|
|||
|
|
@ -482,16 +482,18 @@ export default {
|
|||
</gl-alert>
|
||||
<gl-form-group
|
||||
:label="$options.i18n.type"
|
||||
label-for="ci-variable-type"
|
||||
label-class="!gl-pt-5 -gl-mb-5"
|
||||
class="gl-border-none"
|
||||
:class="{
|
||||
'-gl-mb-5': !hideEnvironmentScope,
|
||||
'-gl-mb-1': hideEnvironmentScope,
|
||||
}"
|
||||
>
|
||||
<span id="ci-variable-type" class="gl-sr-only">{{ $options.i18n.type }}</span>
|
||||
<gl-collapsible-listbox
|
||||
v-model="variable.variableType"
|
||||
:items="$options.variableOptions"
|
||||
toggle-aria-labelled-by="ci-variable-type"
|
||||
block
|
||||
fluid-width
|
||||
/>
|
||||
|
|
@ -499,12 +501,12 @@ export default {
|
|||
<gl-form-group
|
||||
v-if="!hideEnvironmentScope"
|
||||
class="-gl-mb-5 gl-border-none"
|
||||
label-for="ci-variable-env"
|
||||
label-class="!gl-pt-5 -gl-mb-5"
|
||||
data-testid="environment-scope"
|
||||
>
|
||||
<template #label>
|
||||
<div class="gl-flex gl-items-center">
|
||||
<span class="gl-mr-2">
|
||||
<span id="ci-variable-environments" class="gl-mr-2">
|
||||
{{ $options.i18n.environments }}
|
||||
</span>
|
||||
<span
|
||||
|
|
@ -533,6 +535,7 @@ export default {
|
|||
</template>
|
||||
<ci-environments-dropdown
|
||||
v-if="areScopedVariablesAvailable"
|
||||
aria-labelled-by="ci-variable-environments"
|
||||
class="gl-mb-5"
|
||||
:are-environments-loading="areEnvironmentsLoading"
|
||||
:environments="environments"
|
||||
|
|
@ -636,8 +639,8 @@ export default {
|
|||
</gl-form-checkbox>
|
||||
</gl-form-group>
|
||||
<gl-form-group
|
||||
label-for="ci-variable-description"
|
||||
:label="$options.i18n.description"
|
||||
label-for="ci-variable-description"
|
||||
class="-gl-mb-5 gl-border-none"
|
||||
data-testid="ci-variable-description-label"
|
||||
:description="$options.i18n.descriptionHelpText"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { isFunction } from 'lodash';
|
||||
import { identity, isFunction } from 'lodash';
|
||||
|
||||
const defaultAttrs = {
|
||||
td: { colspan: 1, rowspan: 1, colwidth: null, align: 'left' },
|
||||
|
|
@ -194,10 +194,11 @@ export function preserveUnchanged(configOrRender) {
|
|||
};
|
||||
}
|
||||
|
||||
export function preserveUnchangedMark({ open, close, ...restConfig }) {
|
||||
export function preserveUnchangedMark({ open, close, escape = true, ...restConfig }) {
|
||||
// use a buffer to replace the content of the serialized mark with the sourceMarkdown
|
||||
// when the mark is unchanged
|
||||
let bufferStartPos = -1;
|
||||
let esc;
|
||||
|
||||
function startBuffer(state) {
|
||||
bufferStartPos = state.out.length;
|
||||
|
|
@ -216,6 +217,11 @@ export function preserveUnchangedMark({ open, close, ...restConfig }) {
|
|||
...restConfig,
|
||||
// eslint-disable-next-line max-params
|
||||
open: (state, mark, parent, index) => {
|
||||
if (!escape) {
|
||||
esc = state.esc;
|
||||
state.esc = identity;
|
||||
}
|
||||
|
||||
const same = state.options.changeTracker.get(mark);
|
||||
|
||||
if (same) {
|
||||
|
|
@ -227,6 +233,10 @@ export function preserveUnchangedMark({ open, close, ...restConfig }) {
|
|||
},
|
||||
// eslint-disable-next-line max-params
|
||||
close: (state, mark, parent, index) => {
|
||||
if (!escape) {
|
||||
state.esc = esc;
|
||||
}
|
||||
|
||||
const { sourceMarkdown } = mark.attrs;
|
||||
|
||||
if (bufferStarted()) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { pickBy, identity } from 'lodash';
|
||||
import { preserveUnchanged, openTag } from '../serialization_helpers';
|
||||
import { escape, quote } from './link';
|
||||
|
||||
function getMediaSrc(node, useCanonicalSrc = true) {
|
||||
const { canonicalSrc, src } = node.attrs;
|
||||
|
|
@ -12,7 +13,7 @@ const image = preserveUnchanged({
|
|||
render: (state, node) => {
|
||||
const { alt, title, width, height, isReference, sourceMarkdown, sourceTagName } = node.attrs;
|
||||
|
||||
const realSrc = getMediaSrc(node, state.options.useCanonicalSrc);
|
||||
const realSrc = escape(getMediaSrc(node, state.options.useCanonicalSrc));
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
if (realSrc.startsWith('data:') || realSrc.startsWith('blob:')) return;
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ const image = preserveUnchanged({
|
|||
state.write(openTag(sourceTagName, { src: realSrc, ...attrs }));
|
||||
return;
|
||||
}
|
||||
const quotedTitle = title ? ` ${state.quote(title)}` : '';
|
||||
const quotedTitle = title ? ` ${quote(title)}` : '';
|
||||
const sourceExpression = isReference ? `[${realSrc}]` : `(${realSrc}${quotedTitle})`;
|
||||
|
||||
const sizeAttributes = [];
|
||||
|
|
@ -35,7 +36,7 @@ const image = preserveUnchanged({
|
|||
|
||||
const attributes = sizeAttributes.length ? `{${sizeAttributes.join(' ')}}` : '';
|
||||
|
||||
state.write(`![${state.esc(alt || '')}]${sourceExpression}${attributes}`);
|
||||
state.write(`![${escape(alt || '')}]${sourceExpression}${attributes}`);
|
||||
}
|
||||
},
|
||||
inline: true,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ const normalizeUrl = (url) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const escape = (link) => link.replace(/[()"]/g, '\\$&');
|
||||
export const quote = (title) => `"${title.replace(/"/g, '\\"')}"`;
|
||||
|
||||
/**
|
||||
* This function detects whether a link should be serialized
|
||||
* as an autolink.
|
||||
|
|
@ -67,6 +70,7 @@ function getLinkHref(mark, useCanonicalSrc = true) {
|
|||
}
|
||||
|
||||
const link = preserveUnchangedMark({
|
||||
escape: false,
|
||||
open(state, mark, parent) {
|
||||
if (isAutoLink(mark, parent)) {
|
||||
return isBracketAutoLink(mark.attrs.sourceMarkdown) ? '<' : '';
|
||||
|
|
@ -78,11 +82,11 @@ const link = preserveUnchangedMark({
|
|||
if (href.startsWith('data:') || href.startsWith('blob:')) return '';
|
||||
|
||||
const attrs = {
|
||||
href: state.esc(getLinkHref(mark, state.options.useCanonicalSrc)),
|
||||
href: escape(getLinkHref(mark, state.options.useCanonicalSrc)),
|
||||
};
|
||||
|
||||
if (title) {
|
||||
attrs.title = state.esc(title);
|
||||
attrs.title = title;
|
||||
}
|
||||
|
||||
if (sourceTagName && !sourceMarkdown) return openTag(sourceTagName, attrs);
|
||||
|
|
@ -112,12 +116,12 @@ const link = preserveUnchangedMark({
|
|||
}
|
||||
|
||||
if (isReference) {
|
||||
return `][${state.esc(getLinkHref(mark, state.options.useCanonicalSrc))}]`;
|
||||
return `][${escape(getLinkHref(mark, state.options.useCanonicalSrc))}]`;
|
||||
}
|
||||
|
||||
if (isGollumLink) {
|
||||
const text = getMarkText(mark, parent);
|
||||
const escapedCanonicalSrc = state.esc(canonicalSrc);
|
||||
const escapedCanonicalSrc = escape(canonicalSrc);
|
||||
|
||||
if (text.toLowerCase() === escapedCanonicalSrc.toLowerCase()) {
|
||||
return ']]';
|
||||
|
|
@ -126,8 +130,8 @@ const link = preserveUnchangedMark({
|
|||
return `|${escapedCanonicalSrc}]]`;
|
||||
}
|
||||
|
||||
return `](${state.esc(getLinkHref(mark, state.options.useCanonicalSrc))}${
|
||||
title ? ` ${state.quote(title)}` : ''
|
||||
return `](${escape(getLinkHref(mark, state.options.useCanonicalSrc))}${
|
||||
title ? ` ${quote(title)}` : ''
|
||||
})`;
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -108,11 +108,15 @@ export default {
|
|||
return escape(suggestion);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.renderGFM();
|
||||
},
|
||||
updated() {
|
||||
this.renderGFM();
|
||||
watch: {
|
||||
note: {
|
||||
async handler() {
|
||||
await this.$nextTick();
|
||||
this.renderGFM();
|
||||
},
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
import initCommitActions from '~/projects/commit';
|
||||
import { initCommitBoxInfo } from '~/projects/commit_box/info';
|
||||
import { renderHtmlStreams } from '~/streaming/render_html_streams';
|
||||
import { toPolyfillReadable } from '~/streaming/polyfills';
|
||||
import { createRapidDiffsApp } from '~/rapid_diffs/app';
|
||||
|
||||
initCommitBoxInfo();
|
||||
initCommitActions();
|
||||
|
||||
const streamContainer = document.getElementById('js-stream-container');
|
||||
if (streamContainer) {
|
||||
const request = fetch(streamContainer.dataset.diffsStreamUrl);
|
||||
renderHtmlStreams(
|
||||
[request.then((response) => toPolyfillReadable(response.body))],
|
||||
streamContainer,
|
||||
);
|
||||
}
|
||||
const app = createRapidDiffsApp();
|
||||
app.streamRemainingDiffs();
|
||||
app.init();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ import ZenMode from '~/zen_mode';
|
|||
import '~/sourcegraph/load';
|
||||
import DiffStats from '~/diffs/components/diff_stats.vue';
|
||||
import { initReportAbuse } from '~/projects/report_abuse';
|
||||
import * as popovers from '~/popovers';
|
||||
|
||||
popovers.initPopovers();
|
||||
initDiffStatsDropdown();
|
||||
new ZenMode();
|
||||
addShortcutsExtension(ShortcutsNavigation);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Vue from 'vue';
|
|||
import PopoversComponent from './components/popovers.vue';
|
||||
|
||||
let app;
|
||||
let isInitialized = false;
|
||||
|
||||
const APP_ELEMENT_ID = 'gl-popovers-app';
|
||||
|
||||
|
|
@ -32,13 +33,16 @@ const handlePopoverEvent = (rootTarget, e, selector) => {
|
|||
};
|
||||
|
||||
export const initPopovers = () => {
|
||||
['mouseenter', 'focus', 'click'].forEach((event) => {
|
||||
document.addEventListener(
|
||||
event,
|
||||
(e) => handlePopoverEvent(document, e, '[data-toggle="popover"]'),
|
||||
true,
|
||||
);
|
||||
});
|
||||
if (!isInitialized) {
|
||||
['mouseenter', 'focus', 'click'].forEach((event) => {
|
||||
document.addEventListener(
|
||||
event,
|
||||
(e) => handlePopoverEvent(document, e, '[data-toggle="popover"]'),
|
||||
true,
|
||||
);
|
||||
});
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
return getPopoversApp();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export class DiffFile extends HTMLElement {
|
|||
if (clickActionElement) {
|
||||
const clickAction = clickActionElement.dataset.click;
|
||||
this.adapters.forEach((adapter) =>
|
||||
adapter.clicks?.[clickAction]?.call?.(this.adapterContext, event),
|
||||
adapter.clicks?.[clickAction]?.call?.(this.adapterContext, event, clickActionElement),
|
||||
);
|
||||
}
|
||||
this.trigger(events.CLICK, event);
|
||||
|
|
|
|||
|
|
@ -1,44 +1,37 @@
|
|||
import { getLines } from '~/rapid_diffs/expand_lines/get_lines';
|
||||
import { DiffLineRow } from '~/rapid_diffs/expand_lines/diff_line_row';
|
||||
|
||||
const getLineNumber = (el) => parseInt(el.dataset.linenumber, 10);
|
||||
|
||||
const collectLineData = (element) => {
|
||||
const buttons = element.querySelectorAll('[data-linenumber]');
|
||||
const lineNumbers = Array.from(buttons).map(getLineNumber);
|
||||
const previousEl = element.previousElementSibling;
|
||||
const prevNewLine = previousEl?.querySelector('[data-linenumber]:last-child');
|
||||
const prevNewLineNumber = prevNewLine ? getLineNumber(prevNewLine) : 0;
|
||||
return [...lineNumbers, prevNewLineNumber];
|
||||
};
|
||||
|
||||
const viewersMap = {
|
||||
text_inline: 'text',
|
||||
text_parallel: 'parallel',
|
||||
const getSurroundingLines = (hunkHeaderRow) => {
|
||||
const wrapperElements = Array.from(hunkHeaderRow.parentElement.children);
|
||||
const rowIndex = wrapperElements.indexOf(hunkHeaderRow);
|
||||
const lineBefore = wrapperElements.slice(0, rowIndex).findLast((el) => 'hunkLines' in el.dataset);
|
||||
const lineAfter = wrapperElements
|
||||
.slice(rowIndex, wrapperElements.length)
|
||||
.find((el) => 'hunkLines' in el.dataset);
|
||||
return [lineBefore, lineAfter].map((lineRow) => (lineRow ? new DiffLineRow(lineRow) : null));
|
||||
};
|
||||
|
||||
export const ExpandLinesAdapter = {
|
||||
clicks: {
|
||||
async expandLines(event) {
|
||||
const { target } = event;
|
||||
const { expandPrevLine, expandNextLine } = target.dataset;
|
||||
if (!expandPrevLine && !expandNextLine) return;
|
||||
const parent = target.closest('tr');
|
||||
if (parent.dataset.loading) return;
|
||||
async expandLines(event, button) {
|
||||
const { expandDirection } = button.dataset;
|
||||
const hunkHeaderRow = button.closest('tr');
|
||||
|
||||
parent.dataset.loading = true;
|
||||
if (hunkHeaderRow.dataset.loading) return;
|
||||
hunkHeaderRow.dataset.loading = expandDirection;
|
||||
button.setAttribute('disabled', 'disabled');
|
||||
|
||||
const { blobDiffPath } = this.data;
|
||||
const { diffLinesPath } = this.data;
|
||||
const lines = await getLines({
|
||||
expandPrevLine,
|
||||
lineData: collectLineData(parent),
|
||||
blobDiffPath,
|
||||
view: viewersMap[this.viewer],
|
||||
expandDirection,
|
||||
surroundingLines: getSurroundingLines(hunkHeaderRow),
|
||||
diffLinesPath,
|
||||
view: this.viewer === 'text_parallel' ? 'parallel' : undefined,
|
||||
});
|
||||
|
||||
const method = expandPrevLine ? 'beforebegin' : 'afterend';
|
||||
// eslint-disable-next-line no-unsanitized/method
|
||||
parent.insertAdjacentHTML(method, lines);
|
||||
parent.remove();
|
||||
hunkHeaderRow.insertAdjacentHTML('afterend', lines);
|
||||
hunkHeaderRow.remove();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
export class DiffLineRow {
|
||||
constructor(row) {
|
||||
this.row = row;
|
||||
}
|
||||
|
||||
#getLineNumber(position) {
|
||||
const { lineNumber } = this.row.querySelector(
|
||||
`[data-position="${position}"] [data-line-number]`,
|
||||
).dataset;
|
||||
return parseInt(lineNumber, 10);
|
||||
}
|
||||
|
||||
get oldLineNumber() {
|
||||
return this.#getLineNumber('old');
|
||||
}
|
||||
|
||||
get newLineNumber() {
|
||||
return this.#getLineNumber('new');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +1,68 @@
|
|||
/**
|
||||
* @typedef {import('./diff_line_row').DiffLineRow} DiffLineRow
|
||||
*/
|
||||
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
const UNFOLD_COUNT = 20;
|
||||
|
||||
// eslint-disable-next-line max-params
|
||||
const getRequestParams = (expandPrevLine, oldLineNumber, newLineNumber, prevNewLineNumber) => {
|
||||
const offset = newLineNumber - oldLineNumber;
|
||||
let since;
|
||||
let to;
|
||||
let unfold = true;
|
||||
|
||||
if (!expandPrevLine) {
|
||||
const lineNumber = newLineNumber + 1;
|
||||
since = lineNumber;
|
||||
to = lineNumber + UNFOLD_COUNT;
|
||||
} else {
|
||||
const lineNumber = newLineNumber - 1;
|
||||
since = lineNumber - UNFOLD_COUNT;
|
||||
to = lineNumber;
|
||||
|
||||
// make sure we aren't loading more than we need
|
||||
if (since <= prevNewLineNumber + 1) {
|
||||
since = prevNewLineNumber + 1;
|
||||
unfold = false;
|
||||
}
|
||||
/**
|
||||
* @typedef {'up' | 'down' | 'both'} ExpandDirection
|
||||
* 'up' - ↑
|
||||
* 'down' - ↓
|
||||
* 'both' - ↕
|
||||
*/
|
||||
/**
|
||||
* @typedef {Object} RequestParams
|
||||
* @property {boolean} unfold - Adds hunk header (contains expand buttons) to the returned HTML
|
||||
* @property {number} since - Starting new line number for the line range
|
||||
* @property {number} to - Ending new line number for the line range
|
||||
* @property {boolean} bottom - Positions diff hunk header either before or after the lines
|
||||
* @property {number} offset - The difference between new and old line numbers
|
||||
* @property {number} [closest_line_number] - The next new line number near the existing diff hunk header
|
||||
* 'closest_line_number' - this param helps backend understand which expand buttons should be shown: ↑/↓ or ↕
|
||||
*/
|
||||
/**
|
||||
* @param {ExpandDirection} expandDirection
|
||||
* @param {[DiffLineRow, DiffLineRow]} surroundingLines
|
||||
* @returns {RequestParams}
|
||||
*/
|
||||
const getRequestParams = (expandDirection, [lineBefore, lineAfter]) => {
|
||||
switch (expandDirection) {
|
||||
case 'both':
|
||||
return {
|
||||
unfold: false,
|
||||
since: lineBefore.newLineNumber + 1,
|
||||
to: lineAfter.newLineNumber - 1,
|
||||
bottom: false,
|
||||
offset: lineBefore.newLineNumber - lineBefore.oldLineNumber,
|
||||
};
|
||||
case 'up':
|
||||
return {
|
||||
unfold: true,
|
||||
since: Math.max(lineAfter.newLineNumber - UNFOLD_COUNT - 1, 1),
|
||||
to: lineAfter.newLineNumber - 1,
|
||||
closest_line_number: lineBefore ? lineBefore.newLineNumber : 0,
|
||||
offset: lineAfter.newLineNumber - lineAfter.oldLineNumber,
|
||||
bottom: false,
|
||||
};
|
||||
case 'down':
|
||||
return {
|
||||
unfold: true,
|
||||
since: lineBefore.newLineNumber + 1,
|
||||
to: lineBefore.newLineNumber + UNFOLD_COUNT + 1,
|
||||
closest_line_number: lineAfter ? lineAfter.newLineNumber : 0,
|
||||
offset: lineBefore.newLineNumber - lineBefore.oldLineNumber,
|
||||
bottom: true,
|
||||
};
|
||||
default:
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
throw new Error('Invalid expand option provided');
|
||||
}
|
||||
|
||||
return { since, to, bottom: !expandPrevLine, offset, unfold };
|
||||
};
|
||||
|
||||
export const getLines = async ({ expandPrevLine, lineData, blobDiffPath, view }) => {
|
||||
const params = getRequestParams(expandPrevLine, ...lineData);
|
||||
const { data: lines } = await axios.get(blobDiffPath, { params: { ...params, view } });
|
||||
export const getLines = async ({ expandDirection, surroundingLines, diffLinesPath, view }) => {
|
||||
const params = getRequestParams(expandDirection, surroundingLines);
|
||||
const { data: lines } = await axios.get(diffLinesPath, { params: { ...params, view } });
|
||||
return lines;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ export default {
|
|||
false;
|
||||
this.commitMessage = data.project.mergeRequest.defaultMergeCommitMessage;
|
||||
this.squashBeforeMerge = data.project.mergeRequest.squashOnMerge;
|
||||
this.isSquashReadOnly = data.project.squashReadOnly;
|
||||
this.isSquashReadOnly = data.project.mergeRequest.squashReadOnly;
|
||||
this.squashCommitMessage = data.project.mergeRequest.defaultSquashCommitMessage;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ fragment ReadyToMerge on Project {
|
|||
id
|
||||
onlyAllowMergeIfPipelineSucceeds
|
||||
mergeRequestsFfOnlyEnabled
|
||||
squashReadOnly
|
||||
mergeRequest(iid: $iid) {
|
||||
...ReadyToMergeMergeRequest
|
||||
squashReadOnly
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const initProjectSelects = () => {
|
|||
document.querySelectorAll(SELECTOR).forEach((el) => {
|
||||
const {
|
||||
label,
|
||||
description,
|
||||
inputName,
|
||||
inputId,
|
||||
groupId,
|
||||
|
|
@ -34,6 +35,7 @@ export const initProjectSelects = () => {
|
|||
props: {
|
||||
label,
|
||||
hasHtmlLabel,
|
||||
description,
|
||||
inputName,
|
||||
inputId,
|
||||
groupId,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,11 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
hasHtmlLabel: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
|
@ -168,6 +173,7 @@ export default {
|
|||
<template>
|
||||
<entity-selector
|
||||
:label="label"
|
||||
:description="description"
|
||||
:input-name="inputName"
|
||||
:input-id="inputId"
|
||||
:initial-selection="initialSelection"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlTokenSelector, GlAlert } from '@gitlab/ui';
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce, escape } from 'lodash';
|
||||
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { isNumeric } from '~/lib/utils/number_utils';
|
||||
|
|
@ -208,11 +208,13 @@ export default {
|
|||
});
|
||||
},
|
||||
formatResults(input) {
|
||||
const escapedInput = escape(input);
|
||||
|
||||
if (!this.searchTerm) {
|
||||
return input;
|
||||
return escapedInput;
|
||||
}
|
||||
|
||||
return highlighter(`<span class="gl-text-default">${input}</span>`, this.searchTerm);
|
||||
return highlighter(`<span class="gl-text-default">${escapedInput}</span>`, this.searchTerm);
|
||||
},
|
||||
unsetError() {
|
||||
this.error = '';
|
||||
|
|
@ -233,6 +235,7 @@ export default {
|
|||
noMatchesFoundMessage: I18N_WORK_ITEM_NO_MATCHES_FOUND,
|
||||
addInputPlaceholder: I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER,
|
||||
},
|
||||
safeHtmlConfig: { ADD_TAGS: ['strong', 'span'] },
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
|
|
@ -262,10 +265,13 @@ export default {
|
|||
<template #dropdown-item-content="{ dropdownItem }">
|
||||
<div class="gl-flex">
|
||||
<div
|
||||
v-safe-html="formatResults(dropdownItem.iid)"
|
||||
v-safe-html:[$options.safeHtmlConfig]="formatResults(dropdownItem.iid)"
|
||||
class="gl-mr-4 gl-text-sm gl-text-subtle"
|
||||
></div>
|
||||
<div v-safe-html="formatResults(dropdownItem.title)" class="gl-truncate"></div>
|
||||
<div
|
||||
v-safe-html:[$options.safeHtmlConfig]="formatResults(dropdownItem.title)"
|
||||
class="gl-truncate"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
<template #no-results-content>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
}
|
||||
|
||||
.rd-hunk-header {
|
||||
// this is used when a hunk header doesn't have any text, only expand buttons
|
||||
min-height: calc(1em * $code-line-height);
|
||||
border-top: 1px solid var(--rd-hunk-header-border-color, $gray-100);
|
||||
border-bottom: 1px solid var(--rd-hunk-header-border-color, $gray-100);
|
||||
background-color: var(--rd-hunk-header-background-color, $gray-50);
|
||||
|
|
@ -40,6 +42,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
.rd-hunk-header[data-loading=both] [data-visible-when=loading],
|
||||
.rd-hunk-header[data-loading=up] [data-expand-direction=up] [data-visible-when=loading],
|
||||
.rd-hunk-header[data-loading=down] [data-expand-direction=down] [data-visible-when=loading] {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.rd-hunk-header[data-loading=both] [data-visible-when=idle],
|
||||
.rd-hunk-header[data-loading=up] [data-expand-direction=up] [data-visible-when=idle],
|
||||
.rd-hunk-header[data-loading=down] [data-expand-direction=down] [data-visible-when=idle] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.rd-hunk-header-parallel,
|
||||
.rd-hunk-lines-parallel, {
|
||||
grid-template-columns: 50px 1fr 50px 1fr;
|
||||
|
|
@ -62,7 +76,12 @@
|
|||
.rd-expand-lines-button {
|
||||
@include common.diff-expansion($gray-100, $gray-700, $gray-200, $gray-800);
|
||||
|
||||
display: block;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
// whitespace inside button increases the minimum size of the row
|
||||
// this causes jumps when the icons change from idle to loading
|
||||
font-size: 0;
|
||||
border: 0;
|
||||
|
||||
background-color: var(--rd-expand-lines-button-background-color, $gray-100);
|
||||
|
|
@ -75,6 +94,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.rd-expand-lines-button [data-visible-when=loading] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.rd-line-number {
|
||||
padding: 0 10px 0 5px;
|
||||
text-align: right;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ module RapidDiffs
|
|||
params = tree_join(@diff_file.content_sha, @diff_file.file_path)
|
||||
{
|
||||
viewer: viewer_component.viewer_name,
|
||||
blob_diff_path: project_blob_diff_path(project, params)
|
||||
diff_lines_path: project_blob_diff_lines_path(project, params)
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
- @directions.each do |direction|
|
||||
%button.rd-expand-lines-button{ type: "button", data: { click: 'expandLines' } }
|
||||
= helpers.sprite_icon(icon_name(direction))
|
||||
%button.rd-expand-lines-button{ type: "button", data: { click: 'expandLines', expand_direction: direction } }
|
||||
%span{ data: { visible_when: 'idle' } }
|
||||
= helpers.sprite_icon(icon_name(direction))
|
||||
%span{ data: { visible_when: 'loading' } }
|
||||
= helpers.gl_loading_icon(size: 'sm', inline: true)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
- if @diff_hunk.lines
|
||||
- @diff_hunk.lines.each do |line|
|
||||
%tr.rd-hunk-lines.rd-hunk-lines-inline{ data: { testid: testid } }
|
||||
%tr.rd-hunk-lines.rd-hunk-lines-inline{ data: { testid: 'hunk-lines-inline', hunk_lines: true } }
|
||||
= render RapidDiffs::Viewers::Text::LineNumberComponent.new(file_hash: @file_hash, file_path: @file_path, line: line, position: :old)
|
||||
= render RapidDiffs::Viewers::Text::LineNumberComponent.new(file_hash: @file_hash, file_path: @file_path, line: line, position: :new, border: :right)
|
||||
= render RapidDiffs::Viewers::Text::LineContentComponent.new(line: line, position: nil)
|
||||
|
|
|
|||
|
|
@ -11,10 +11,6 @@ module RapidDiffs
|
|||
@file_hash = file_hash
|
||||
@file_path = file_path
|
||||
end
|
||||
|
||||
def testid
|
||||
'hunk-lines-inline'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
- if visible?
|
||||
%td.rd-line-number{ id: id, class: border_class, data: { legacy_id: legacy_id, change: change_type } }
|
||||
%td.rd-line-number{ id: id, class: border_class, data: { legacy_id: legacy_id, change: change_type, position: @position } }
|
||||
= link_to '', "##{id}", { class: 'rd-line-link', data: { line_number: line_number }, aria: { label: s_('Line number %{number}').html_safe % { number: line_number } } }
|
||||
- else
|
||||
%td.rd-line-number{ class: border_class, data: { change: change_type } }
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
%td.rd-hunk-header-content{ data: { position: index == 0 ? :old : :new }, tabindex: '-1' }= @diff_hunk.header.text
|
||||
|
||||
- @diff_hunk.parallel_lines.each do |pair|
|
||||
%tr.rd-hunk-lines.rd-hunk-lines-parallel{ data: { testid: testid } }
|
||||
%tr.rd-hunk-lines.rd-hunk-lines-parallel{ data: { testid: 'hunk-lines-parallel', hunk_lines: true } }
|
||||
- sides(pair).each do |side|
|
||||
- line, position = side.values_at(:line, :position)
|
||||
= render RapidDiffs::Viewers::Text::LineNumberComponent.new(file_hash: @file_hash, file_path: @file_path, **side)
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@ module RapidDiffs
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
def testid
|
||||
'hunk-lines-parallel'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -105,7 +105,8 @@ class Clusters::ClustersController < ::Clusters::BaseController
|
|||
response = Clusters::Migration::CreateService.new(
|
||||
cluster.cluster,
|
||||
current_user: current_user,
|
||||
configuration_project_id: migrate_params[:configuration_project_id]
|
||||
configuration_project_id: migrate_params[:configuration_project_id],
|
||||
agent_name: migrate_params[:agent_name]
|
||||
).execute
|
||||
|
||||
if response.success?
|
||||
|
|
@ -120,7 +121,7 @@ class Clusters::ClustersController < ::Clusters::BaseController
|
|||
private
|
||||
|
||||
def migrate_params
|
||||
params.permit(:configuration_project_id)
|
||||
params.require(:cluster_migration).permit(:configuration_project_id, :agent_name)
|
||||
end
|
||||
|
||||
def ensure_feature_enabled!
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module EventForward
|
||||
class EventForwardController < BaseActionController
|
||||
def forward
|
||||
process_events
|
||||
|
||||
head :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_events
|
||||
payload = Gitlab::Json.parse(request.raw_post)
|
||||
tracker = Gitlab::Tracking.tracker
|
||||
|
||||
payload['data'].each do |event|
|
||||
tracker.emit_event_payload(event)
|
||||
end
|
||||
|
||||
logger.info("Enqueued events for forwarding. Count: #{payload['data'].size}")
|
||||
end
|
||||
|
||||
def logger
|
||||
@logger ||= EventForward::Logger.build
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module EventForward
|
||||
class Logger < ::Gitlab::JsonLogger
|
||||
def self.file_name_noext
|
||||
'event_collection'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -15,9 +15,7 @@ class ProfilesController < Profiles::ApplicationController
|
|||
:reset_static_object_token, :update_username]
|
||||
|
||||
def reset_incoming_email_token
|
||||
Users::UpdateService.new(current_user, user: @user).execute! do |user|
|
||||
user.reset_incoming_email_token!
|
||||
end
|
||||
Users::UpdateService.new(current_user, user: @user).execute!(&:reset_incoming_email_token!)
|
||||
|
||||
flash[:notice] = s_("Profiles|Incoming email token was successfully reset")
|
||||
|
||||
|
|
@ -37,9 +35,7 @@ class ProfilesController < Profiles::ApplicationController
|
|||
end
|
||||
|
||||
def reset_static_object_token
|
||||
Users::UpdateService.new(current_user, user: @user).execute! do |user|
|
||||
user.reset_static_object_token!
|
||||
end
|
||||
Users::UpdateService.new(current_user, user: @user).execute!(&:reset_static_object_token!)
|
||||
|
||||
redirect_to user_settings_personal_access_tokens_path,
|
||||
notice: s_('Profiles|Static object token was successfully reset')
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
return render_404 unless ::Feature.enabled?(:rapid_diffs, current_user, type: :wip)
|
||||
|
||||
streaming_offset = 5
|
||||
@reload_stream_url = diffs_stream_url(@commit)
|
||||
@stream_url = diffs_stream_url(@commit, streaming_offset, diff_view)
|
||||
@diffs_slice = @commit.first_diffs_slice(streaming_offset, commit_diff_options)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
module Repositories
|
||||
class CommitResolver < BaseResolver
|
||||
type Types::Repositories::CommitType, null: true
|
||||
|
||||
argument :ref,
|
||||
GraphQL::Types::String,
|
||||
required: true,
|
||||
description: "Commit reference (SHA, branch name, or tag name)."
|
||||
|
||||
calls_gitaly!
|
||||
|
||||
alias_method :repository, :object
|
||||
|
||||
def resolve(ref:)
|
||||
repository.commit(ref)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -11,6 +11,10 @@ module Types
|
|||
field :branch_names, [GraphQL::Types::String], null: true, calls_gitaly: true,
|
||||
complexity: 170, description: 'Names of branches available in this repository that match the search pattern.',
|
||||
resolver: Resolvers::RepositoryBranchNamesResolver
|
||||
field :commit, Types::Repositories::CommitType, null: true,
|
||||
calls_gitaly: true,
|
||||
description: 'Commit from the repository.',
|
||||
resolver: Resolvers::Repositories::CommitResolver
|
||||
field :disk_path, GraphQL::Types::String,
|
||||
description: 'Shows a disk path of the repository.',
|
||||
null: true,
|
||||
|
|
|
|||
|
|
@ -101,6 +101,17 @@ module ClustersHelper
|
|||
can?(user, :admin_cluster, cluster)
|
||||
end
|
||||
|
||||
def migration_alert_config(migration)
|
||||
return unless migration
|
||||
|
||||
status = migration.agent_install_status.to_sym
|
||||
config = migration_alert_configs[status]
|
||||
|
||||
return config unless config && status == :error && migration.agent_install_message.present?
|
||||
|
||||
config.merge(details: migration.agent_install_message)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_branch_name(clusterable)
|
||||
|
|
@ -110,4 +121,23 @@ module ClustersHelper
|
|||
def clusterable_project_path(clusterable)
|
||||
clusterable.full_path if clusterable.is_a?(Project)
|
||||
end
|
||||
|
||||
def migration_alert_configs
|
||||
{
|
||||
in_progress: {
|
||||
variant: :info,
|
||||
message: s_('ClusterIntegration|Installing agent in progress.')
|
||||
},
|
||||
success: {
|
||||
variant: :success,
|
||||
message: s_('ClusterIntegration|The agent connection is set up.')
|
||||
},
|
||||
error: {
|
||||
variant: :warning,
|
||||
title: s_('ClusterIntegration|Agent setup failed'),
|
||||
message: s_('ClusterIntegration|The agent was not installed in the cluster.'),
|
||||
show_help: true
|
||||
}
|
||||
}.freeze
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ module Clusters
|
|||
class AgentMigration < ApplicationRecord
|
||||
self.table_name = 'cluster_agent_migrations'
|
||||
|
||||
attr_accessor :agent_name
|
||||
|
||||
belongs_to :cluster, optional: false, class_name: 'Clusters::Cluster'
|
||||
belongs_to :project, optional: false, class_name: '::Project'
|
||||
belongs_to :agent, optional: false, class_name: 'Clusters::Agent'
|
||||
|
|
|
|||
|
|
@ -608,7 +608,7 @@ class Commit
|
|||
def first_diffs_slice(limit, diff_options = {})
|
||||
diff_options[:max_files] = limit
|
||||
|
||||
diffs(diff_options)
|
||||
diffs(diff_options).diff_files
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module CachedCommit
|
|||
end
|
||||
end
|
||||
|
||||
# We don't save these, because they would need a table or a serialised
|
||||
# We don't save these, because they would need a table or a serialized
|
||||
# field. They aren't used anywhere, so just pretend the commit has no parents.
|
||||
def parent_ids
|
||||
[]
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ class ContainerRepository < ApplicationRecord
|
|||
def delete_tags!
|
||||
return unless has_tags?
|
||||
|
||||
digests = tags.map { |tag| tag.digest }.compact.to_set
|
||||
digests = tags.map(&:digest).compact.to_set
|
||||
|
||||
digests.map { |digest| delete_tag(digest) }.all?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class Discussion
|
|||
notes = model_class.where(discussion_id: discussion_ids).fresh
|
||||
notes = notes.inc_note_diff_file if preload_note_diff_file
|
||||
|
||||
grouped_notes = notes.group_by { |n| n.discussion_id }
|
||||
grouped_notes = notes.group_by(&:discussion_id)
|
||||
grouped_notes.transform_values { |notes| Discussion.build(notes, context_noteable) }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -93,9 +93,7 @@ module Integrations
|
|||
def prometheus_available?
|
||||
return false unless project
|
||||
|
||||
project.all_clusters.enabled.eager_load(:integration_prometheus).any? do |cluster|
|
||||
cluster.integration_prometheus_available?
|
||||
end
|
||||
project.all_clusters.enabled.eager_load(:integration_prometheus).any?(&:integration_prometheus_available?)
|
||||
end
|
||||
|
||||
def allow_local_api_url?
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@ class ProjectMember < Member
|
|||
ProjectMember.transaction do
|
||||
members = ProjectMember.where(source_id: project_ids)
|
||||
|
||||
members.each do |member|
|
||||
member.destroy
|
||||
end
|
||||
members.each(&:destroy)
|
||||
end
|
||||
|
||||
true
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ module Packages
|
|||
class PackageRevision < ApplicationRecord
|
||||
include ShaAttribute
|
||||
|
||||
REVISION_LENGTH_MAX = 40
|
||||
|
||||
sha_attribute :revision
|
||||
|
||||
belongs_to :package, class_name: 'Packages::Conan::Package', inverse_of: :conan_package_revisions
|
||||
|
|
@ -17,8 +15,8 @@ module Packages
|
|||
has_many :file_metadata, inverse_of: :package_revision, class_name: 'Packages::Conan::FileMetadatum'
|
||||
|
||||
validates :package, :package_reference, :project, presence: true
|
||||
validates :revision, presence: true, bytesize: { maximum: -> { REVISION_LENGTH_MAX } },
|
||||
uniqueness: { scope: [:package_id, :package_reference_id] }
|
||||
validates :revision, presence: true, uniqueness: { scope: [:package_id, :package_reference_id] },
|
||||
format: { with: ::Gitlab::Regex.conan_revision_regex_v2 }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ module Packages
|
|||
class RecipeRevision < ApplicationRecord
|
||||
include ShaAttribute
|
||||
|
||||
REVISION_LENGTH_MAX = 40
|
||||
|
||||
sha_attribute :revision
|
||||
|
||||
belongs_to :package, class_name: 'Packages::Conan::Package', inverse_of: :conan_recipe_revisions
|
||||
|
|
@ -17,8 +15,8 @@ module Packages
|
|||
has_many :file_metadata, inverse_of: :recipe_revision, class_name: 'Packages::Conan::FileMetadatum'
|
||||
|
||||
validates :package, :project, presence: true
|
||||
validates :revision, presence: true, bytesize: { maximum: -> { REVISION_LENGTH_MAX } },
|
||||
uniqueness: { scope: :package_id }
|
||||
validates :revision, presence: true,
|
||||
uniqueness: { scope: :package_id }, format: { with: ::Gitlab::Regex.conan_revision_regex_v2 }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module Preloaders
|
|||
|
||||
def preload_all
|
||||
merge_request_diffs = MergeRequestDiff.latest_diff_for_merge_requests(@merge_requests)
|
||||
cache = merge_request_diffs.index_by { |diff| diff.merge_request_id }
|
||||
cache = merge_request_diffs.index_by(&:merge_request_id)
|
||||
|
||||
@merge_requests.each do |merge_request|
|
||||
merge_request_diff = cache[merge_request.id]
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class Release < ApplicationRecord
|
|||
end
|
||||
|
||||
def milestone_titles
|
||||
self.milestones.order_by_dates_and_title.map { |m| m.title }.join(', ')
|
||||
self.milestones.order_by_dates_and_title.map(&:title).join(', ')
|
||||
end
|
||||
|
||||
def to_hook_data(action)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ module Clusters
|
|||
}
|
||||
end
|
||||
|
||||
def agent_migration_for_display
|
||||
cluster.agent_migration || Clusters::AgentMigration.new(cluster: cluster)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def image_path(path)
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@
|
|||
module Clusters
|
||||
module Migration
|
||||
class CreateService
|
||||
attr_reader :cluster, :clusterable, :current_user, :configuration_project
|
||||
attr_reader :cluster, :clusterable, :current_user, :configuration_project, :agent_name
|
||||
|
||||
def initialize(cluster, current_user:, configuration_project_id:)
|
||||
def initialize(cluster, current_user:, configuration_project_id:, agent_name:)
|
||||
@cluster = cluster
|
||||
@clusterable = cluster.clusterable
|
||||
@current_user = current_user
|
||||
@configuration_project = find_configuration_project(configuration_project_id)
|
||||
@agent_name = agent_name
|
||||
end
|
||||
|
||||
def execute
|
||||
|
|
@ -27,7 +28,8 @@ module Clusters
|
|||
migration = Clusters::AgentMigration.new(
|
||||
cluster: cluster,
|
||||
agent: agent,
|
||||
project: configuration_project
|
||||
project: configuration_project,
|
||||
agent_name: agent_name
|
||||
)
|
||||
|
||||
if migration.save
|
||||
|
|
@ -41,11 +43,11 @@ module Clusters
|
|||
|
||||
def validate_inputs
|
||||
message = if !feature_enabled?
|
||||
'Feature disabled'
|
||||
_('Feature disabled')
|
||||
elsif !current_user.can?(:admin_cluster, cluster)
|
||||
'Unauthorized'
|
||||
_('Unauthorized')
|
||||
elsif configuration_project.nil?
|
||||
'Invalid configuration project'
|
||||
s_('ClusterIntegration|Invalid configuration project')
|
||||
end
|
||||
|
||||
error_response(message: message) if message
|
||||
|
|
@ -74,10 +76,6 @@ module Clusters
|
|||
clusterable.root_ancestor.all_projects.find_by_id(project_id)
|
||||
end
|
||||
|
||||
def agent_name
|
||||
cluster.name.first(63).parameterize
|
||||
end
|
||||
|
||||
def feature_enabled?
|
||||
Feature.enabled?(:cluster_agent_migrations, clusterable)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,12 +1,72 @@
|
|||
- if can_admin_cluster?(current_user, @cluster)
|
||||
.settings.expanded.border-0.m-0
|
||||
- cluster_migration = @cluster.agent_migration_for_display
|
||||
|
||||
%h4.gl-mt-0= s_('ClusterIntegration|Migrate to GitLab Agent for Kubernetes')
|
||||
|
||||
- tag_pair_agent_docs = tag_pair(link_to('', help_page_path('user/clusters/agent/_index.md'), target: '_blank', rel: 'noopener noreferrer'), :agent_docs_link_start, :agent_docs_link_end)
|
||||
- tag_pair_install_docs = tag_pair(link_to('', help_page_path('user/clusters/agent/install/_index.md'), target: '_blank', rel: 'noopener noreferrer'), :install_docs_link_start, :install_docs_link_end)
|
||||
|
||||
%p
|
||||
= safe_format(s_('ClusterIntegration|The %{agent_docs_link_start}GitLab Agent for Kubernetes %{agent_docs_link_end} offers improved security, reliability, and functionality. Follow the steps below to create a new agent and migrate your existing certificate-based integration. The process is automated, but you still need to %{install_docs_link_start}install the agent%{install_docs_link_end} in your cluster.') , tag_pair_agent_docs, tag_pair_install_docs)
|
||||
= link_to s_('ClusterIntegration|How do I migrate to the GitLab agent?'), help_page_path('user/infrastructure/clusters/migrate_to_gitlab_agent.md'), target: '_blank', rel: 'noopener noreferrer'
|
||||
|
||||
%h5= s_('ClusterIntegration|Step 1. Connect the agent')
|
||||
|
||||
- if (config = migration_alert_config(cluster_migration))
|
||||
= render Pajamas::AlertComponent.new(title: config[:title],
|
||||
variant: config[:variant],
|
||||
alert_options: { class: 'gl-mb-5' }) do |c|
|
||||
= c.with_body do
|
||||
= config[:message]
|
||||
- if config[:details].present?
|
||||
= config[:details]
|
||||
- if config[:show_help]
|
||||
- c.with_actions do
|
||||
= link_to s_('ClusterIntegration|Learn more about migrating to GitLab Agent'),
|
||||
help_page_path('user/infrastructure/clusters/migrate_to_gitlab_agent.md'),
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer'
|
||||
|
||||
- agent = cluster_migration&.agent
|
||||
- project = cluster_migration&.project
|
||||
- if agent.present?
|
||||
|
||||
%p.gl-font-bold.gl-mb-2
|
||||
= s_('ClusterIntegration|Project name')
|
||||
%p
|
||||
= s_('ClusterIntegration|Migrate this cluster to use the GitLab agent for Kubernetes')
|
||||
.settings-content#migrate-section
|
||||
.sub-section.form-group
|
||||
%h4
|
||||
= s_('ClusterIntegration|Migrate to the GitLab agent for Kubernetes')
|
||||
%p
|
||||
= s_("ClusterIntegration|This cluster integration is deprecated. To continue using this Kubernetes cluster with GitLab, you must install the agent.")
|
||||
= render Pajamas::ButtonComponent.new(method: :post, href: clusterable.create_cluster_migration_path(@cluster)) do
|
||||
= s_('ClusterIntegration|Install agent')
|
||||
= link_to project.full_name, project_path(project)
|
||||
|
||||
%p.gl-font-bold.gl-mb-2
|
||||
= s_('ClusterIntegration|Agent name')
|
||||
%p
|
||||
- agent_link_name = "#{agent.name}##{agent.id}"
|
||||
= link_to agent_link_name, project_cluster_agent_path(project, agent.name)
|
||||
|
||||
- else
|
||||
- group_id = @cluster.group.id if @cluster.group_type?
|
||||
|
||||
- if @cluster.project_type?
|
||||
- group_id = @cluster.project.group.id if @cluster.project.group
|
||||
- user_id = @cluster.project.namespace.owner_id unless group_id
|
||||
|
||||
= gitlab_ui_form_for cluster_migration, url: clusterable.create_cluster_migration_path(@cluster), html: { class: 'fieldset-form' }, data: { testid: 'cluster-migration-form' }, method: :post do |f|
|
||||
.form-group{ class: 'md:gl-w-1/2' }
|
||||
.js-vue-project-select{ data: { label: s_('ClusterIntegration|Project name'),
|
||||
description: s_('ClusterIntegration|Select a project for the GitLab Agent.'),
|
||||
input_name: 'cluster_migration[configuration_project_id]',
|
||||
input_id: 'cluster_migration_configuration_project_id',
|
||||
order_by: 'last_activity_at',
|
||||
group_id: group_id,
|
||||
user_id: user_id,
|
||||
with_shared: true.to_s,
|
||||
include_subgroups: true.to_s,
|
||||
membership: true.to_s,
|
||||
selected: @cluster.management_project_id } }
|
||||
|
||||
.form-group.-gl-mt-2{ class: 'md:gl-w-1/2' }
|
||||
= f.label :agent_name, s_('ClusterIntegration|Agent name'), class: 'label-bold'
|
||||
= f.text_field :agent_name, name: 'cluster_migration[agent_name]', class: 'form-control gl-form-input', placeholder: s_('ClusterIntegration|New agent name')
|
||||
.form-text.gl-text-subtle
|
||||
= s_('ClusterIntegration|Enter a unique name for your new GitLab Agent. This name will be used to identify the agent in your project.')
|
||||
|
||||
= f.submit s_('ClusterIntegration|Create agent and migrate'), pajamas_button: true
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
|
||||
- if Feature.enabled?(:cluster_agent_migrations, clusterable) && can_admin_cluster?(current_user, @cluster)
|
||||
= gl_tab_link_to clusterable.cluster_path(@cluster.id, params: { tab: 'migrate' }), { item_active: active } do
|
||||
= sprite_icon('warning', css_class: 'gl-mr-2')
|
||||
= s_('ClusterIntegration|Migrate')
|
||||
|
|
|
|||
|
|
@ -32,4 +32,4 @@
|
|||
|
||||
= link_to(_('Learn about signing commits'), help_page_path('user/project/repository/signed_commits/_index.md'), class: 'gl-link gl-block gl-mt-3')
|
||||
|
||||
= gl_badge_tag(label, { variant: variant, icon: icon, href: '#' }, { class: 'signature-badge gl-inline-flex gl-ml-4 gl-align-middle', role: 'button', tabindex: 0, data: { toggle: 'popover', html: 'true', placement: 'bottom', title: title, content: content } })
|
||||
= gl_badge_tag(label, { variant: variant, icon: icon, href: '#' }, { class: 'signature-badge gl-inline-flex gl-ml-4 gl-align-middle', role: 'button', tabindex: 0, data: { toggle: 'popover', html: 'true', triggers: 'click blur', placement: 'bottom', title: title, content: content} })
|
||||
|
|
|
|||
|
|
@ -11,7 +11,5 @@
|
|||
.container-fluid{ class: [container_class] }
|
||||
= render "commit_box"
|
||||
= render "ci_menu"
|
||||
.code{ class: user_color_scheme }
|
||||
= render RapidDiffs::DiffFileComponent.with_collection(@diffs_slice.diff_files, parallel_view: diff_view == :parallel)
|
||||
- if @stream_url
|
||||
#js-stream-container{ data: { diffs_stream_url: @stream_url } }
|
||||
- args = { diffs_slice: @diffs_slice, reload_stream_url: @reload_stream_url, stream_url: @stream_url, show_whitespace: @show_whitespace_default, diff_view: @diff_view, update_user_endpoint: @update_current_user_path, metadata_endpoint: @endpoint_metadata_url }
|
||||
= render ::RapidDiffs::AppComponent.new(**args)
|
||||
|
|
|
|||
|
|
@ -27,8 +27,11 @@ module ResourceAccessTokens
|
|||
.select(1)
|
||||
.where('"personal_access_tokens"."user_id" = "users"."id"')
|
||||
.and(
|
||||
PersonalAccessToken.expired_before(cut_off).or(PersonalAccessToken.revoked_before(cut_off))
|
||||
.invert_where
|
||||
PersonalAccessToken.active
|
||||
.or(
|
||||
PersonalAccessToken.expired_before(cut_off).or(PersonalAccessToken.revoked_before(cut_off))
|
||||
.invert_where
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -242,6 +242,8 @@ InitializerConnections.raise_if_new_database_connection do
|
|||
post '/track_namespace_visits' => 'users/namespace_visits#create'
|
||||
|
||||
get '/external_redirect' => 'external_redirect/external_redirect#index'
|
||||
|
||||
post '/collect_events', to: 'event_forward/event_forward#forward', as: :event_forwarding
|
||||
end
|
||||
# End of the /-/ scope.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
- title: "Coverage-guided fuzz testing is deprecated"
|
||||
removal_milestone: "19.0"
|
||||
announcement_milestone: "18.0"
|
||||
breaking_change: true
|
||||
window: 1
|
||||
reporter: mikeeddington
|
||||
stage: application security testing
|
||||
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/517841
|
||||
impact: high
|
||||
scope: project
|
||||
resolution_role: Owner
|
||||
manual_task: false
|
||||
body: | # (required) Don't change this line.
|
||||
Coverage-guided fuzz testing is deprecated and will not be supported
|
||||
from GitLab 18.0. The feature will be completely removed in GitLab 19.0.
|
||||
|
||||
Coverage-guided fuzz testing integrated several open-source fuzzers into GitLab.
|
||||
If you are impacted, you can integrate your open-source fuzzers as standalone applications,
|
||||
or migrate to another security feature like [GitLab Advanced SAST](https://docs.gitlab.com/ee/user/application_security/sast/gitlab_advanced_sast.html).
|
||||
end_of_support_milestone: 18.0
|
||||
tiers: [Ultimate]
|
||||
documentation_url: https://docs.gitlab.com/ee/user/application_security/coverage_fuzzing/
|
||||
image_url:
|
||||
video_url:
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NewFkForWorkItemTypeCustomFieldsWorkItemTypeId < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '17.10'
|
||||
|
||||
NEW_CONSTRAINT_NAME = 'fk_work_item_type_custom_fields_on_work_item_type_id'
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key :work_item_type_custom_fields,
|
||||
:work_item_types,
|
||||
column: :work_item_type_id,
|
||||
name: NEW_CONSTRAINT_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists :work_item_type_custom_fields,
|
||||
:work_item_types,
|
||||
column: :work_item_type_id,
|
||||
name: NEW_CONSTRAINT_NAME
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropOldFkForWorkItemTypeCustomFieldsWorkItemTypeId < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '17.10'
|
||||
|
||||
OLD_CONSTRAINT_NAME = 'fk_9447fad7b4'
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists :work_item_type_custom_fields,
|
||||
:work_item_types,
|
||||
column: :work_item_type_id,
|
||||
on_delete: :cascade,
|
||||
name: OLD_CONSTRAINT_NAME
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_foreign_key :work_item_type_custom_fields,
|
||||
:work_item_types,
|
||||
column: :work_item_type_id,
|
||||
target_column: :correct_id,
|
||||
on_delete: :cascade
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NewFkForWorkItemTypeUserPreferencesWorkItemTypeId < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '17.10'
|
||||
|
||||
NEW_CONSTRAINT_NAME = 'fk_work_item_type_user_preferences_on_work_item_type_id'
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key :work_item_type_user_preferences,
|
||||
:work_item_types,
|
||||
column: :work_item_type_id,
|
||||
name: NEW_CONSTRAINT_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists :work_item_type_user_preferences,
|
||||
:work_item_types,
|
||||
column: :work_item_type_id,
|
||||
name: NEW_CONSTRAINT_NAME
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropOldFkForWorkItemTypeUserPreferencesWorkItemTypeId < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '17.10'
|
||||
|
||||
OLD_CONSTRAINT_NAME = 'fk_79e0353950'
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists :work_item_type_user_preferences,
|
||||
:work_item_types,
|
||||
column: :work_item_type_id,
|
||||
on_delete: :cascade,
|
||||
name: OLD_CONSTRAINT_NAME
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_foreign_key :work_item_type_user_preferences,
|
||||
:work_item_types,
|
||||
column: :work_item_type_id,
|
||||
target_column: :correct_id,
|
||||
on_delete: :cascade
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
844ab7d792599f4f2e3da9ad2bc4a182b9d15947ca703ad00f31e4602261cd3f
|
||||
|
|
@ -0,0 +1 @@
|
|||
50efa17bf234df2e972eeb81b4d9897b496655e79162bc6d78c9c99b7a39c259
|
||||
|
|
@ -0,0 +1 @@
|
|||
d5b47a465e11070c8a35712609a787f695e4236d6596503ff17a32c5c1bf51d1
|
||||
|
|
@ -0,0 +1 @@
|
|||
e4f05e6255bed30ce5a19679fd9b5bb0652f5ef302dcdec629532be11b1c9599
|
||||
|
|
@ -39627,9 +39627,6 @@ ALTER TABLE ONLY topics
|
|||
ALTER TABLE ONLY work_item_text_field_values
|
||||
ADD CONSTRAINT fk_79c719630f FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY work_item_type_user_preferences
|
||||
ADD CONSTRAINT fk_79e0353950 FOREIGN KEY (work_item_type_id) REFERENCES work_item_types(correct_id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY packages_maven_metadata
|
||||
ADD CONSTRAINT fk_7a170ee0a3 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
@ -39807,9 +39804,6 @@ ALTER TABLE ONLY todos
|
|||
ALTER TABLE ONLY packages_debian_group_architectures
|
||||
ADD CONSTRAINT fk_92714bcab1 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY work_item_type_custom_fields
|
||||
ADD CONSTRAINT fk_9447fad7b4 FOREIGN KEY (work_item_type_id) REFERENCES work_item_types(correct_id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY workspaces_agent_configs
|
||||
ADD CONSTRAINT fk_94660551c8 FOREIGN KEY (cluster_agent_id) REFERENCES cluster_agents(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
@ -42729,6 +42723,12 @@ ALTER TABLE ONLY work_item_related_link_restrictions
|
|||
ALTER TABLE ONLY work_item_related_link_restrictions
|
||||
ADD CONSTRAINT fk_work_item_related_link_restrictions_target_type_id FOREIGN KEY (target_type_id) REFERENCES work_item_types(id) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY work_item_type_custom_fields
|
||||
ADD CONSTRAINT fk_work_item_type_custom_fields_on_work_item_type_id FOREIGN KEY (work_item_type_id) REFERENCES work_item_types(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY work_item_type_user_preferences
|
||||
ADD CONSTRAINT fk_work_item_type_user_preferences_on_work_item_type_id FOREIGN KEY (work_item_type_id) REFERENCES work_item_types(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY work_item_widget_definitions
|
||||
ADD CONSTRAINT fk_work_item_widget_definitions_work_item_type_id FOREIGN KEY (work_item_type_id) REFERENCES work_item_types(id) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ Azure
|
|||
B-tree
|
||||
backfilling
|
||||
backfills
|
||||
backoff
|
||||
backport
|
||||
backported
|
||||
backporting
|
||||
|
|
@ -182,9 +183,10 @@ Coinbase
|
|||
colocate
|
||||
colocated
|
||||
colocating
|
||||
Colorama
|
||||
Command Palette
|
||||
commit's
|
||||
committer's
|
||||
Command Palette
|
||||
CommonMark
|
||||
compilable
|
||||
composable
|
||||
|
|
@ -252,6 +254,7 @@ deduplicated
|
|||
deduplicates
|
||||
deduplicating
|
||||
deduplication
|
||||
Deepin
|
||||
delegators
|
||||
deliverables
|
||||
denormalization
|
||||
|
|
@ -378,6 +381,7 @@ Flutterwave
|
|||
Flycheck
|
||||
focusable
|
||||
Forgerock
|
||||
Forky
|
||||
formatters
|
||||
Fortanix
|
||||
Fortinet
|
||||
|
|
@ -515,6 +519,7 @@ kaniko
|
|||
Karma
|
||||
Kata
|
||||
KCachegrind
|
||||
keepalive
|
||||
Kerberos
|
||||
KEV
|
||||
Keycloak
|
||||
|
|
@ -549,6 +554,7 @@ Lemmy
|
|||
libFuzzer
|
||||
Libgcrypt
|
||||
Libravatar
|
||||
LinuxMint
|
||||
liveness
|
||||
LLM
|
||||
LLMs
|
||||
|
|
@ -567,6 +573,7 @@ Lookbook
|
|||
lookups
|
||||
loopback
|
||||
LSP
|
||||
Lts
|
||||
Lua
|
||||
Lucene
|
||||
Lucidchart
|
||||
|
|
@ -650,6 +657,7 @@ nosniff
|
|||
noteable
|
||||
noteables
|
||||
npm
|
||||
NTFSSecurity
|
||||
NuGet
|
||||
nullability
|
||||
nullable
|
||||
|
|
@ -664,7 +672,6 @@ offboarding
|
|||
offboards
|
||||
OIDs
|
||||
OKRs
|
||||
OKRs
|
||||
Okta
|
||||
OLM
|
||||
OmniAuth
|
||||
|
|
@ -681,6 +688,7 @@ OSs
|
|||
OTel
|
||||
outdent
|
||||
Overcommit
|
||||
Packagecloud
|
||||
Packagist
|
||||
packfile
|
||||
packfiles
|
||||
|
|
@ -1069,6 +1077,7 @@ triaged
|
|||
triages
|
||||
triaging
|
||||
Trivy
|
||||
Trixie
|
||||
Truststore
|
||||
truthy
|
||||
Twilio
|
||||
|
|
@ -1080,6 +1089,11 @@ Ubuntu
|
|||
Udemy
|
||||
UI
|
||||
UIDs
|
||||
ulimit
|
||||
Ulyana
|
||||
Ulyssa
|
||||
Uma
|
||||
Una
|
||||
unapplied
|
||||
unapprove
|
||||
unapproved
|
||||
|
|
@ -1234,7 +1248,9 @@ worktree
|
|||
worktrees
|
||||
Worldline
|
||||
Xcode
|
||||
Xenial
|
||||
Xeon
|
||||
Xerus
|
||||
XPath
|
||||
Yandex
|
||||
YouTrack
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ The following metrics are available:
|
|||
| `gitlab_rack_attack_throttle_limit` | Gauge | 17.6 | Reports the maximum number of requests that a client can make before Rack Attack throttles them. | `event_name` |
|
||||
| `gitlab_rack_attack_throttle_period_seconds` | Gauge | 17.6 | Reports the duration over which requests for a client are counted before Rack Attack throttles them. | `event_name` |
|
||||
| `gitlab_application_rate_limiter_throttle_utilization_ratio` | Histogram | 17.6 | Utilization ratio of a throttle in GitLab Application Rate Limiter. | `throttle_key`, `peek`, `feature_category` |
|
||||
| `search_zoekt_task_processing_queue_size` | Gauge | 17.9 | Number of tasks waiting to be processed by Zoekt. | |
|
||||
| `search_zoekt_task_processing_queue_size` | Gauge | 17.9 | Number of tasks waiting to be processed by Zoekt. | `node_name` |
|
||||
|
||||
## Metrics controlled by a feature flag
|
||||
|
||||
|
|
|
|||
|
|
@ -36350,6 +36350,18 @@ Returns [`String`](#string).
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="repositorycodeownerspathref"></a>`ref` | [`String`](#string) | Name of the ref. |
|
||||
|
||||
##### `Repository.commit`
|
||||
|
||||
Commit from the repository.
|
||||
|
||||
Returns [`Commit`](#commit).
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="repositorycommitref"></a>`ref` | [`String!`](#string) | Commit reference (SHA, branch name, or tag name). |
|
||||
|
||||
##### `Repository.paginatedTree`
|
||||
|
||||
Paginated tree of the repository.
|
||||
|
|
|
|||
|
|
@ -36,132 +36,132 @@ Predefined variables become available at three different phases of pipeline exec
|
|||
|
||||
## Predefined variables
|
||||
|
||||
| Variable | Availability | Description |
|
||||
|-------------------------------------------------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `CHAT_CHANNEL` | Pipeline | The Source chat channel that triggered the [ChatOps](../chatops/_index.md) command. |
|
||||
| `CHAT_INPUT` | Pipeline | The additional arguments passed with the [ChatOps](../chatops/_index.md) command. |
|
||||
| `CHAT_USER_ID` | Pipeline | The chat service's user ID of the user who triggered the [ChatOps](../chatops/_index.md) command. |
|
||||
| `CI` | Pre-pipeline | Available for all jobs executed in CI/CD. `true` when available. |
|
||||
| `CI_API_V4_URL` | Pre-pipeline | The GitLab API v4 root URL. |
|
||||
| `CI_API_GRAPHQL_URL` | Pre-pipeline | The GitLab API GraphQL root URL. Introduced in GitLab 15.11. |
|
||||
| `CI_BUILDS_DIR` | Job-only | The top-level directory where builds are executed. |
|
||||
| `CI_COMMIT_AUTHOR` | Pre-pipeline | The author of the commit in `Name <email>` format. |
|
||||
| `CI_COMMIT_BEFORE_SHA` | Pre-pipeline | The previous latest commit present on a branch or tag. Is always `0000000000000000000000000000000000000000` for merge request pipelines, the first commit in pipelines for branches or tags, or when manually running a pipeline. |
|
||||
| `CI_COMMIT_BRANCH` | Pre-pipeline | The commit branch name. Available in branch pipelines, including pipelines for the default branch. Not available in merge request pipelines or tag pipelines. |
|
||||
| `CI_COMMIT_DESCRIPTION` | Pre-pipeline | The description of the commit. If the title is shorter than 100 characters, the message without the first line. |
|
||||
| `CI_COMMIT_MESSAGE` | Pre-pipeline | The full commit message. |
|
||||
| `CI_COMMIT_REF_NAME` | Pre-pipeline | The branch or tag name for which project is built. |
|
||||
| `CI_COMMIT_REF_PROTECTED` | Pre-pipeline | `true` if the job is running for a protected reference, `false` otherwise. |
|
||||
| `CI_COMMIT_REF_SLUG` | Pre-pipeline | `CI_COMMIT_REF_NAME` in lowercase, shortened to 63 bytes, and with everything except `0-9` and `a-z` replaced with `-`. No leading / trailing `-`. Use in URLs, host names and domain names. |
|
||||
| `CI_COMMIT_SHA` | Pre-pipeline | The commit revision the project is built for. |
|
||||
| `CI_COMMIT_SHORT_SHA` | Pre-pipeline | The first eight characters of `CI_COMMIT_SHA`. |
|
||||
| `CI_COMMIT_TAG` | Pre-pipeline | The commit tag name. Available only in pipelines for tags. |
|
||||
| `CI_COMMIT_TAG_MESSAGE` | Pre-pipeline | The commit tag message. Available only in pipelines for tags. Introduced in GitLab 15.5. |
|
||||
| `CI_COMMIT_TIMESTAMP` | Pre-pipeline | The timestamp of the commit in the [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_COMMIT_TITLE` | Pre-pipeline | The title of the commit. The full first line of the message. |
|
||||
| `CI_CONCURRENT_ID` | Job-only | The unique ID of build execution in a single executor. |
|
||||
| `CI_CONCURRENT_PROJECT_ID` | Job-only | The unique ID of build execution in a single executor and project. |
|
||||
| `CI_CONFIG_PATH` | Pre-pipeline | The path to the CI/CD configuration file. Defaults to `.gitlab-ci.yml`. |
|
||||
| `CI_DEBUG_TRACE` | Pipeline | `true` if [debug logging (tracing)](_index.md#enable-debug-logging) is enabled. |
|
||||
| `CI_DEBUG_SERVICES` | Pipeline | `true` if [service container logging](../services/_index.md#capturing-service-container-logs) is enabled. Introduced in GitLab 15.7. Requires GitLab Runner 15.7. |
|
||||
| `CI_DEFAULT_BRANCH` | Pre-pipeline | The name of the project's default branch. |
|
||||
| `CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX` | Pre-pipeline | The direct group image prefix for pulling images through the Dependency Proxy. |
|
||||
| `CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX` | Pre-pipeline | The top-level group image prefix for pulling images through the Dependency Proxy. |
|
||||
| `CI_DEPENDENCY_PROXY_PASSWORD` | Pipeline | The password to pull images through the Dependency Proxy. |
|
||||
| `CI_DEPENDENCY_PROXY_SERVER` | Pre-pipeline | The server for logging in to the Dependency Proxy. This variable is equivalent to `$CI_SERVER_HOST:$CI_SERVER_PORT`. |
|
||||
| `CI_DEPENDENCY_PROXY_USER` | Pipeline | The username to pull images through the Dependency Proxy. |
|
||||
| `CI_DEPLOY_FREEZE` | Pre-pipeline | Only available if the pipeline runs during a [deploy freeze window](../../user/project/releases/_index.md#prevent-unintentional-releases-by-setting-a-deploy-freeze). `true` when available. |
|
||||
| `CI_DEPLOY_PASSWORD` | Job-only | The authentication password of the [GitLab Deploy Token](../../user/project/deploy_tokens/_index.md#gitlab-deploy-token), if the project has one. |
|
||||
| `CI_DEPLOY_USER` | Job-only | The authentication username of the [GitLab Deploy Token](../../user/project/deploy_tokens/_index.md#gitlab-deploy-token), if the project has one. |
|
||||
| `CI_DISPOSABLE_ENVIRONMENT` | Pipeline | Only available if the job is executed in a disposable environment (something that is created only for this job and disposed of/destroyed after the execution - all executors except `shell` and `ssh`). `true` when available. |
|
||||
| `CI_ENVIRONMENT_NAME` | Pipeline | The name of the environment for this job. Available if [`environment:name`](../yaml/_index.md#environmentname) is set. |
|
||||
| `CI_ENVIRONMENT_SLUG` | Pipeline | The simplified version of the environment name, suitable for inclusion in DNS, URLs, Kubernetes labels, and so on. Available if [`environment:name`](../yaml/_index.md#environmentname) is set. The slug is [truncated to 24 characters](https://gitlab.com/gitlab-org/gitlab/-/issues/20941). A random suffix is automatically added to [uppercase environment names](https://gitlab.com/gitlab-org/gitlab/-/issues/415526). |
|
||||
| `CI_ENVIRONMENT_URL` | Pipeline | The URL of the environment for this job. Available if [`environment:url`](../yaml/_index.md#environmenturl) is set. |
|
||||
| `CI_ENVIRONMENT_ACTION` | Pipeline | The action annotation specified for this job's environment. Available if [`environment:action`](../yaml/_index.md#environmentaction) is set. Can be `start`, `prepare`, or `stop`. |
|
||||
| `CI_ENVIRONMENT_TIER` | Pipeline | The [deployment tier of the environment](../environments/_index.md#deployment-tier-of-environments) for this job. |
|
||||
| `CI_GITLAB_FIPS_MODE` | Pre-pipeline | Only available if [FIPS mode](../../development/fips_gitlab.md) is enabled in the GitLab instance. `true` when available. |
|
||||
| `CI_HAS_OPEN_REQUIREMENTS` | Pipeline | Only available if the pipeline's project has an open [requirement](../../user/project/requirements/_index.md). `true` when available. |
|
||||
| `CI_JOB_ID` | Job-only | The internal ID of the job, unique across all jobs in the GitLab instance. |
|
||||
| `CI_JOB_IMAGE` | Pipeline | The name of the Docker image running the job. |
|
||||
| `CI_JOB_MANUAL` | Pipeline | Only available if the job was started manually. `true` when available. |
|
||||
| `CI_JOB_NAME` | Pipeline | The name of the job. |
|
||||
| `CI_JOB_NAME_SLUG` | Pipeline | `CI_JOB_NAME` in lowercase, shortened to 63 bytes, and with everything except `0-9` and `a-z` replaced with `-`. No leading / trailing `-`. Use in paths. Introduced in GitLab 15.4. |
|
||||
| `CI_JOB_STAGE` | Pipeline | The name of the job's stage. |
|
||||
| `CI_JOB_STATUS` | Job-only | The status of the job as each runner stage is executed. Use with [`after_script`](../yaml/_index.md#after_script). Can be `success`, `failed`, or `canceled`. |
|
||||
| `CI_JOB_TIMEOUT` | Job-only | The job timeout, in seconds. Introduced in GitLab 15.7. Requires GitLab Runner 15.7. |
|
||||
| `CI_JOB_TOKEN` | Job-only | A token to authenticate with [certain API endpoints](../jobs/ci_job_token.md). The token is valid as long as the job is running. |
|
||||
| `CI_JOB_URL` | Job-only | The job details URL. |
|
||||
| `CI_JOB_STARTED_AT` | Job-only | The date and time when a job started, 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_KUBERNETES_ACTIVE` | Pre-pipeline | Only available if the pipeline has a Kubernetes cluster available for deployments. `true` when available. |
|
||||
| `CI_NODE_INDEX` | Pipeline | The index of the job in the job set. Only available if the job uses [`parallel`](../yaml/_index.md#parallel). |
|
||||
| `CI_NODE_TOTAL` | Pipeline | The total number of instances of this job running in parallel. Set to `1` if the job does not use [`parallel`](../yaml/_index.md#parallel). |
|
||||
| `CI_OPEN_MERGE_REQUESTS` | Pre-pipeline | A comma-separated list of up to four merge requests that use the current branch and project as the merge request source. Only available in branch and merge request pipelines if the branch has an associated merge request. For example, `gitlab-org/gitlab!333,gitlab-org/gitlab-foss!11`. |
|
||||
| `CI_PAGES_DOMAIN` | Pre-pipeline | The instance's domain that hosts GitLab Pages, not including the namespace subdomain. To use the full hostname, use `CI_PAGES_HOSTNAME` instead. |
|
||||
| `CI_PAGES_HOSTNAME` | Job-only | The full hostname of the Pages deployment. |
|
||||
| `CI_PAGES_URL` | Job-only | The URL for a GitLab Pages site. Always a subdomain of `CI_PAGES_DOMAIN`. In GitLab 17.9 and later, the value includes the `path_prefix` when one is specified. |
|
||||
| `CI_PIPELINE_ID` | Job-only | The instance-level ID of the current pipeline. This ID is unique across all projects on the GitLab instance. |
|
||||
| `CI_PIPELINE_IID` | Pipeline | The project-level IID (internal ID) of the current pipeline. This ID is unique only in the current project. |
|
||||
| `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_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). |
|
||||
| `CI_PROJECT_ID` | Pre-pipeline | The ID of the current project. This ID is unique across all projects on the GitLab instance. |
|
||||
| `CI_PROJECT_NAME` | Pre-pipeline | The name of the directory for the project. For example if the project URL is `gitlab.example.com/group-name/project-1`, `CI_PROJECT_NAME` is `project-1`. |
|
||||
| `CI_PROJECT_NAMESPACE` | Pre-pipeline | The project namespace (username or group name) of the job. |
|
||||
| `CI_PROJECT_NAMESPACE_ID` | Pre-pipeline | The project namespace ID of the job. Introduced in GitLab 15.7. |
|
||||
| `CI_PROJECT_PATH_SLUG` | Pre-pipeline | `$CI_PROJECT_PATH` in lowercase with characters that are not `a-z` or `0-9` replaced with `-` and shortened to 63 bytes. Use in URLs and domain names. |
|
||||
| `CI_PROJECT_PATH` | Pre-pipeline | The project namespace with the project name included. |
|
||||
| `CI_PROJECT_REPOSITORY_LANGUAGES` | Pre-pipeline | A comma-separated, lowercase list of the languages used in the repository. For example `ruby,javascript,html,css`. The maximum number of languages is limited to 5. An issue [proposes to increase the limit](https://gitlab.com/gitlab-org/gitlab/-/issues/368925). |
|
||||
| `CI_PROJECT_ROOT_NAMESPACE` | Pre-pipeline | The root project namespace (username or group name) of the job. For example, if `CI_PROJECT_NAMESPACE` is `root-group/child-group/grandchild-group`, `CI_PROJECT_ROOT_NAMESPACE` is `root-group`. |
|
||||
| `CI_PROJECT_TITLE` | Pre-pipeline | The human-readable project name as displayed in the GitLab web interface. |
|
||||
| `CI_PROJECT_DESCRIPTION` | Pre-pipeline | The project description as displayed in the GitLab web interface. Introduced in GitLab 15.1. |
|
||||
| `CI_PROJECT_URL` | Pre-pipeline | The HTTP(S) address of the project. |
|
||||
| `CI_PROJECT_VISIBILITY` | Pre-pipeline | The project visibility. Can be `internal`, `private`, or `public`. |
|
||||
| `CI_PROJECT_CLASSIFICATION_LABEL` | Pre-pipeline | The project [external authorization classification label](../../administration/settings/external_authorization.md). |
|
||||
| `CI_REGISTRY` | Pre-pipeline | Address of the [container registry](../../user/packages/container_registry/_index.md) server, formatted as `<host>[:<port>]`. For example: `registry.gitlab.example.com`. Only available if the container registry is enabled for the GitLab instance. |
|
||||
| Variable | Availability | Description |
|
||||
|-------------------------------------------------|--------------|-------------|
|
||||
| `CHAT_CHANNEL` | Pipeline | The Source chat channel that triggered the [ChatOps](../chatops/_index.md) command. |
|
||||
| `CHAT_INPUT` | Pipeline | The additional arguments passed with the [ChatOps](../chatops/_index.md) command. |
|
||||
| `CHAT_USER_ID` | Pipeline | The chat service's user ID of the user who triggered the [ChatOps](../chatops/_index.md) command. |
|
||||
| `CI` | Pre-pipeline | Available for all jobs executed in CI/CD. `true` when available. |
|
||||
| `CI_API_V4_URL` | Pre-pipeline | The GitLab API v4 root URL. |
|
||||
| `CI_API_GRAPHQL_URL` | Pre-pipeline | The GitLab API GraphQL root URL. Introduced in GitLab 15.11. |
|
||||
| `CI_BUILDS_DIR` | Job-only | The top-level directory where builds are executed. |
|
||||
| `CI_COMMIT_AUTHOR` | Pre-pipeline | The author of the commit in `Name <email>` format. |
|
||||
| `CI_COMMIT_BEFORE_SHA` | Pre-pipeline | The previous latest commit present on a branch or tag. Is always `0000000000000000000000000000000000000000` for merge request pipelines, the first commit in pipelines for branches or tags, or when manually running a pipeline. |
|
||||
| `CI_COMMIT_BRANCH` | Pre-pipeline | The commit branch name. Available in branch pipelines, including pipelines for the default branch. Not available in merge request pipelines or tag pipelines. |
|
||||
| `CI_COMMIT_DESCRIPTION` | Pre-pipeline | The description of the commit. If the title is shorter than 100 characters, the message without the first line. |
|
||||
| `CI_COMMIT_MESSAGE` | Pre-pipeline | The full commit message. |
|
||||
| `CI_COMMIT_REF_NAME` | Pre-pipeline | The branch or tag name for which project is built. |
|
||||
| `CI_COMMIT_REF_PROTECTED` | Pre-pipeline | `true` if the job is running for a protected reference, `false` otherwise. |
|
||||
| `CI_COMMIT_REF_SLUG` | Pre-pipeline | `CI_COMMIT_REF_NAME` in lowercase, shortened to 63 bytes, and with everything except `0-9` and `a-z` replaced with `-`. No leading / trailing `-`. Use in URLs, host names and domain names. |
|
||||
| `CI_COMMIT_SHA` | Pre-pipeline | The commit revision the project is built for. |
|
||||
| `CI_COMMIT_SHORT_SHA` | Pre-pipeline | The first eight characters of `CI_COMMIT_SHA`. |
|
||||
| `CI_COMMIT_TAG` | Pre-pipeline | The commit tag name. Available only in pipelines for tags. |
|
||||
| `CI_COMMIT_TAG_MESSAGE` | Pre-pipeline | The commit tag message. Available only in pipelines for tags. Introduced in GitLab 15.5. |
|
||||
| `CI_COMMIT_TIMESTAMP` | Pre-pipeline | The timestamp of the commit in the [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_COMMIT_TITLE` | Pre-pipeline | The title of the commit. The full first line of the message. |
|
||||
| `CI_CONCURRENT_ID` | Job-only | The unique ID of build execution in a single executor. |
|
||||
| `CI_CONCURRENT_PROJECT_ID` | Job-only | The unique ID of build execution in a single executor and project. |
|
||||
| `CI_CONFIG_PATH` | Pre-pipeline | The path to the CI/CD configuration file. Defaults to `.gitlab-ci.yml`. |
|
||||
| `CI_DEBUG_TRACE` | Pipeline | `true` if [debug logging (tracing)](_index.md#enable-debug-logging) is enabled. |
|
||||
| `CI_DEBUG_SERVICES` | Pipeline | `true` if [service container logging](../services/_index.md#capturing-service-container-logs) is enabled. Introduced in GitLab 15.7. Requires GitLab Runner 15.7. |
|
||||
| `CI_DEFAULT_BRANCH` | Pre-pipeline | The name of the project's default branch. |
|
||||
| `CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX` | Pre-pipeline | The direct group image prefix for pulling images through the Dependency Proxy. |
|
||||
| `CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX` | Pre-pipeline | The top-level group image prefix for pulling images through the Dependency Proxy. |
|
||||
| `CI_DEPENDENCY_PROXY_PASSWORD` | Pipeline | The password to pull images through the Dependency Proxy. |
|
||||
| `CI_DEPENDENCY_PROXY_SERVER` | Pre-pipeline | The server for logging in to the Dependency Proxy. This variable is equivalent to `$CI_SERVER_HOST:$CI_SERVER_PORT`. |
|
||||
| `CI_DEPENDENCY_PROXY_USER` | Pipeline | The username to pull images through the Dependency Proxy. |
|
||||
| `CI_DEPLOY_FREEZE` | Pre-pipeline | Only available if the pipeline runs during a [deploy freeze window](../../user/project/releases/_index.md#prevent-unintentional-releases-by-setting-a-deploy-freeze). `true` when available. |
|
||||
| `CI_DEPLOY_PASSWORD` | Job-only | The authentication password of the [GitLab Deploy Token](../../user/project/deploy_tokens/_index.md#gitlab-deploy-token), if the project has one. |
|
||||
| `CI_DEPLOY_USER` | Job-only | The authentication username of the [GitLab Deploy Token](../../user/project/deploy_tokens/_index.md#gitlab-deploy-token), if the project has one. |
|
||||
| `CI_DISPOSABLE_ENVIRONMENT` | Pipeline | Only available if the job is executed in a disposable environment (something that is created only for this job and disposed of/destroyed after the execution - all executors except `shell` and `ssh`). `true` when available. |
|
||||
| `CI_ENVIRONMENT_NAME` | Pipeline | The name of the environment for this job. Available if [`environment:name`](../yaml/_index.md#environmentname) is set. |
|
||||
| `CI_ENVIRONMENT_SLUG` | Pipeline | The simplified version of the environment name, suitable for inclusion in DNS, URLs, Kubernetes labels, and so on. Available if [`environment:name`](../yaml/_index.md#environmentname) is set. The slug is [truncated to 24 characters](https://gitlab.com/gitlab-org/gitlab/-/issues/20941). A random suffix is automatically added to [uppercase environment names](https://gitlab.com/gitlab-org/gitlab/-/issues/415526). |
|
||||
| `CI_ENVIRONMENT_URL` | Pipeline | The URL of the environment for this job. Available if [`environment:url`](../yaml/_index.md#environmenturl) is set. |
|
||||
| `CI_ENVIRONMENT_ACTION` | Pipeline | The action annotation specified for this job's environment. Available if [`environment:action`](../yaml/_index.md#environmentaction) is set. Can be `start`, `prepare`, or `stop`. |
|
||||
| `CI_ENVIRONMENT_TIER` | Pipeline | The [deployment tier of the environment](../environments/_index.md#deployment-tier-of-environments) for this job. |
|
||||
| `CI_GITLAB_FIPS_MODE` | Pre-pipeline | Only available if [FIPS mode](../../development/fips_gitlab.md) is enabled in the GitLab instance. `true` when available. |
|
||||
| `CI_HAS_OPEN_REQUIREMENTS` | Pipeline | Only available if the pipeline's project has an open [requirement](../../user/project/requirements/_index.md). `true` when available. |
|
||||
| `CI_JOB_ID` | Job-only | The internal ID of the job, unique across all jobs in the GitLab instance. |
|
||||
| `CI_JOB_IMAGE` | Pipeline | The name of the Docker image running the job. |
|
||||
| `CI_JOB_MANUAL` | Pipeline | Only available if the job was started manually. `true` when available. |
|
||||
| `CI_JOB_NAME` | Pipeline | The name of the job. |
|
||||
| `CI_JOB_NAME_SLUG` | Pipeline | `CI_JOB_NAME` in lowercase, shortened to 63 bytes, and with everything except `0-9` and `a-z` replaced with `-`. No leading / trailing `-`. Use in paths. Introduced in GitLab 15.4. |
|
||||
| `CI_JOB_STAGE` | Pipeline | The name of the job's stage. |
|
||||
| `CI_JOB_STATUS` | Job-only | The status of the job as each runner stage is executed. Use with [`after_script`](../yaml/_index.md#after_script). Can be `success`, `failed`, or `canceled`. |
|
||||
| `CI_JOB_TIMEOUT` | Job-only | The job timeout, in seconds. Introduced in GitLab 15.7. Requires GitLab Runner 15.7. |
|
||||
| `CI_JOB_TOKEN` | Job-only | A token to authenticate with [certain API endpoints](../jobs/ci_job_token.md). The token is valid as long as the job is running. |
|
||||
| `CI_JOB_URL` | Job-only | The job details URL. |
|
||||
| `CI_JOB_STARTED_AT` | Job-only | The date and time when a job started, 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_KUBERNETES_ACTIVE` | Pre-pipeline | Only available if the pipeline has a Kubernetes cluster available for deployments. `true` when available. |
|
||||
| `CI_NODE_INDEX` | Pipeline | The index of the job in the job set. Only available if the job uses [`parallel`](../yaml/_index.md#parallel). |
|
||||
| `CI_NODE_TOTAL` | Pipeline | The total number of instances of this job running in parallel. Set to `1` if the job does not use [`parallel`](../yaml/_index.md#parallel). |
|
||||
| `CI_OPEN_MERGE_REQUESTS` | Pre-pipeline | A comma-separated list of up to four merge requests that use the current branch and project as the merge request source. Only available in branch and merge request pipelines if the branch has an associated merge request. For example, `gitlab-org/gitlab!333,gitlab-org/gitlab-foss!11`. |
|
||||
| `CI_PAGES_DOMAIN` | Pre-pipeline | The instance's domain that hosts GitLab Pages, not including the namespace subdomain. To use the full hostname, use `CI_PAGES_HOSTNAME` instead. |
|
||||
| `CI_PAGES_HOSTNAME` | Job-only | The full hostname of the Pages deployment. |
|
||||
| `CI_PAGES_URL` | Job-only | The URL for a GitLab Pages site. Always a subdomain of `CI_PAGES_DOMAIN`. In GitLab 17.9 and later, the value includes the `path_prefix` when one is specified. |
|
||||
| `CI_PIPELINE_ID` | Job-only | The instance-level ID of the current pipeline. This ID is unique across all projects on the GitLab instance. |
|
||||
| `CI_PIPELINE_IID` | Pipeline | The project-level IID (internal ID) of the current pipeline. This ID is unique only in the current project. |
|
||||
| `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_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). |
|
||||
| `CI_PROJECT_ID` | Pre-pipeline | The ID of the current project. This ID is unique across all projects on the GitLab instance. |
|
||||
| `CI_PROJECT_NAME` | Pre-pipeline | The name of the directory for the project. For example if the project URL is `gitlab.example.com/group-name/project-1`, `CI_PROJECT_NAME` is `project-1`. |
|
||||
| `CI_PROJECT_NAMESPACE` | Pre-pipeline | The project namespace (username or group name) of the job. |
|
||||
| `CI_PROJECT_NAMESPACE_ID` | Pre-pipeline | The project namespace ID of the job. Introduced in GitLab 15.7. |
|
||||
| `CI_PROJECT_PATH_SLUG` | Pre-pipeline | `$CI_PROJECT_PATH` in lowercase with characters that are not `a-z` or `0-9` replaced with `-` and shortened to 63 bytes. Use in URLs and domain names. |
|
||||
| `CI_PROJECT_PATH` | Pre-pipeline | The project namespace with the project name included. |
|
||||
| `CI_PROJECT_REPOSITORY_LANGUAGES` | Pre-pipeline | A comma-separated, lowercase list of the languages used in the repository. For example `ruby,javascript,html,css`. The maximum number of languages is limited to 5. An issue [proposes to increase the limit](https://gitlab.com/gitlab-org/gitlab/-/issues/368925). |
|
||||
| `CI_PROJECT_ROOT_NAMESPACE` | Pre-pipeline | The root project namespace (username or group name) of the job. For example, if `CI_PROJECT_NAMESPACE` is `root-group/child-group/grandchild-group`, `CI_PROJECT_ROOT_NAMESPACE` is `root-group`. |
|
||||
| `CI_PROJECT_TITLE` | Pre-pipeline | The human-readable project name as displayed in the GitLab web interface. |
|
||||
| `CI_PROJECT_DESCRIPTION` | Pre-pipeline | The project description as displayed in the GitLab web interface. Introduced in GitLab 15.1. |
|
||||
| `CI_PROJECT_URL` | Pre-pipeline | The HTTP(S) address of the project. |
|
||||
| `CI_PROJECT_VISIBILITY` | Pre-pipeline | The project visibility. Can be `internal`, `private`, or `public`. |
|
||||
| `CI_PROJECT_CLASSIFICATION_LABEL` | Pre-pipeline | The project [external authorization classification label](../../administration/settings/external_authorization.md). |
|
||||
| `CI_REGISTRY` | Pre-pipeline | Address of the [container registry](../../user/packages/container_registry/_index.md) server, formatted as `<host>[:<port>]`. For example: `registry.gitlab.example.com`. Only available if the container registry is enabled for the GitLab instance. |
|
||||
| `CI_REGISTRY_IMAGE` | Pre-pipeline | Base address for the container registry to push, pull, or tag project's images, formatted as `<host>[:<port>]/<project_full_path>`. For example: `registry.gitlab.example.com/my_group/my_project`. Image names must follow the [container registry naming convention](../../user/packages/container_registry/_index.md#naming-convention-for-your-container-images). Only available if the container registry is enabled for the project. |
|
||||
| `CI_REGISTRY_PASSWORD` | Job-only | The password to push containers to the GitLab project's container registry. Only available if the container registry is enabled for the project. This password value is the same as the `CI_JOB_TOKEN` and is valid only as long as the job is running. Use the `CI_DEPLOY_PASSWORD` for long-lived access to the registry |
|
||||
| `CI_REGISTRY_USER` | Job-only | The username to push containers to the project's GitLab container registry. Only available if the container registry is enabled for the project. |
|
||||
| `CI_RELEASE_DESCRIPTION` | Pipeline | The description of the release. Available only on pipelines for tags. Description length is limited to first 1024 characters. Introduced in GitLab 15.5. |
|
||||
| `CI_REPOSITORY_URL` | Job-only | The full path to Git clone (HTTP) the repository with a [CI/CD job token](../jobs/ci_job_token.md), in the format `https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.example.com/my-group/my-project.git`. |
|
||||
| `CI_RUNNER_DESCRIPTION` | Job-only | The description of the runner. |
|
||||
| `CI_RUNNER_EXECUTABLE_ARCH` | Job-only | The OS/architecture of the GitLab Runner executable. Might not be the same as the environment of the executor. |
|
||||
| `CI_RUNNER_ID` | Job-only | The unique ID of the runner being used. |
|
||||
| `CI_RUNNER_REVISION` | Job-only | The revision of the runner running the job. |
|
||||
| `CI_RUNNER_SHORT_TOKEN` | Job-only | The runner's unique ID, used to authenticate new job requests. The token contains a prefix, and the first 17 characters are used. |
|
||||
| `CI_RUNNER_TAGS` | Job-only | A JSON array of runner tags. For example `["tag_1", "tag_2"]`. |
|
||||
| `CI_RUNNER_VERSION` | Job-only | The version of the GitLab Runner running the job. |
|
||||
| `CI_SERVER_FQDN` | Pre-pipeline | The fully qualified domain name (FQDN) of the instance. For example `gitlab.example.com:8080`. Introduced in GitLab 16.10. |
|
||||
| `CI_SERVER_HOST` | Pre-pipeline | The host of the GitLab instance URL, without protocol or port. For example `gitlab.example.com`. |
|
||||
| `CI_SERVER_NAME` | Pre-pipeline | The name of CI/CD server that coordinates jobs. |
|
||||
| `CI_SERVER_PORT` | Pre-pipeline | The port of the GitLab instance URL, without host or protocol. For example `8080`. |
|
||||
| `CI_SERVER_PROTOCOL` | Pre-pipeline | The protocol of the GitLab instance URL, without host or port. For example `https`. |
|
||||
| `CI_SERVER_SHELL_SSH_HOST` | Pre-pipeline | The SSH host of the GitLab instance, used for access to Git repositories through SSH. For example `gitlab.com`. Introduced in GitLab 15.11. |
|
||||
| `CI_SERVER_SHELL_SSH_PORT` | Pre-pipeline | The SSH port of the GitLab instance, used for access to Git repositories through SSH. For example `22`. Introduced in GitLab 15.11. |
|
||||
| `CI_SERVER_REVISION` | Pre-pipeline | GitLab revision that schedules jobs. |
|
||||
| `CI_SERVER_TLS_CA_FILE` | Pipeline | File containing the TLS CA certificate to verify the GitLab server when `tls-ca-file` set in [runner settings](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section). |
|
||||
| `CI_SERVER_TLS_CERT_FILE` | Pipeline | File containing the TLS certificate to verify the GitLab server when `tls-cert-file` set in [runner settings](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section). |
|
||||
| `CI_SERVER_TLS_KEY_FILE` | Pipeline | File containing the TLS key to verify the GitLab server when `tls-key-file` set in [runner settings](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section). |
|
||||
| `CI_SERVER_URL` | Pre-pipeline | The base URL of the GitLab instance, including protocol and port. For example `https://gitlab.example.com:8080`. |
|
||||
| `CI_SERVER_VERSION_MAJOR` | Pre-pipeline | The major version of the GitLab instance. For example, if the GitLab version is `17.2.1`, the `CI_SERVER_VERSION_MAJOR` is `17`. |
|
||||
| `CI_SERVER_VERSION_MINOR` | Pre-pipeline | The minor version of the GitLab instance. For example, if the GitLab version is `17.2.1`, the `CI_SERVER_VERSION_MINOR` is `2`. |
|
||||
| `CI_SERVER_VERSION_PATCH` | Pre-pipeline | The patch version of the GitLab instance. For example, if the GitLab version is `17.2.1`, the `CI_SERVER_VERSION_PATCH` is `1`. |
|
||||
| `CI_SERVER_VERSION` | Pre-pipeline | The full version of the GitLab instance. |
|
||||
| `CI_SERVER` | Job-only | Available for all jobs executed in CI/CD. `yes` when available. |
|
||||
| `CI_SHARED_ENVIRONMENT` | Pipeline | Only available if the job is executed in a shared environment (something that is persisted across CI/CD invocations, like the `shell` or `ssh` executor). `true` when available. |
|
||||
| `CI_TEMPLATE_REGISTRY_HOST` | Pre-pipeline | The host of the registry used by CI/CD templates. Defaults to `registry.gitlab.com`. Introduced in GitLab 15.3. |
|
||||
| `CI_TRIGGER_SHORT_TOKEN` | Job-only | First 4 characters of the [trigger token](../triggers/_index.md#create-a-pipeline-trigger-token) of the current job. Only available if the pipeline was [triggered with a trigger token](../triggers/_index.md). For example, for a trigger token of `glptt-1234567890abcdefghij`, `CI_TRIGGER_SHORT_TOKEN` would be `1234`. Introduced in GitLab 17.0. <!-- gitleaks:allow --> |
|
||||
| `GITLAB_CI` | Pre-pipeline | Available for all jobs executed in CI/CD. `true` when available. |
|
||||
| `GITLAB_FEATURES` | Pre-pipeline | The comma-separated list of licensed features available for the GitLab instance and license. |
|
||||
| `GITLAB_USER_EMAIL` | Pipeline | The email of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the email of the user who started the job. |
|
||||
| `GITLAB_USER_ID` | Pipeline | The numeric ID of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the ID of the user who started the job. |
|
||||
| `GITLAB_USER_LOGIN` | Pipeline | The unique username of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the username of the user who started the job. |
|
||||
| `GITLAB_USER_NAME` | Pipeline | The display name (user-defined **Full name** in the profile settings) of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the name of the user who started the job. |
|
||||
| `KUBECONFIG` | Pipeline | The path to the `kubeconfig` file with contexts for every shared agent connection. Only available when a [GitLab agent is authorized to access the project](../../user/clusters/agent/ci_cd_workflow.md#authorize-the-agent). |
|
||||
| `TRIGGER_PAYLOAD` | Pipeline | The webhook payload. Only available when a pipeline is [triggered with a webhook](../triggers/_index.md#access-webhook-payload). |
|
||||
| `CI_REGISTRY_PASSWORD` | Job-only | The password to push containers to the GitLab project's container registry. Only available if the container registry is enabled for the project. This password value is the same as the `CI_JOB_TOKEN` and is valid only as long as the job is running. Use the `CI_DEPLOY_PASSWORD` for long-lived access to the registry |
|
||||
| `CI_REGISTRY_USER` | Job-only | The username to push containers to the project's GitLab container registry. Only available if the container registry is enabled for the project. |
|
||||
| `CI_RELEASE_DESCRIPTION` | Pipeline | The description of the release. Available only on pipelines for tags. Description length is limited to first 1024 characters. Introduced in GitLab 15.5. |
|
||||
| `CI_REPOSITORY_URL` | Job-only | The full path to Git clone (HTTP) the repository with a [CI/CD job token](../jobs/ci_job_token.md), in the format `https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.example.com/my-group/my-project.git`. |
|
||||
| `CI_RUNNER_DESCRIPTION` | Job-only | The description of the runner. |
|
||||
| `CI_RUNNER_EXECUTABLE_ARCH` | Job-only | The OS/architecture of the GitLab Runner executable. Might not be the same as the environment of the executor. |
|
||||
| `CI_RUNNER_ID` | Job-only | The unique ID of the runner being used. |
|
||||
| `CI_RUNNER_REVISION` | Job-only | The revision of the runner running the job. |
|
||||
| `CI_RUNNER_SHORT_TOKEN` | Job-only | The runner's unique ID, used to authenticate new job requests. The token contains a prefix, and the first 17 characters are used. |
|
||||
| `CI_RUNNER_TAGS` | Job-only | A JSON array of runner tags. For example `["tag_1", "tag_2"]`. |
|
||||
| `CI_RUNNER_VERSION` | Job-only | The version of the GitLab Runner running the job. |
|
||||
| `CI_SERVER_FQDN` | Pre-pipeline | The fully qualified domain name (FQDN) of the instance. For example `gitlab.example.com:8080`. Introduced in GitLab 16.10. |
|
||||
| `CI_SERVER_HOST` | Pre-pipeline | The host of the GitLab instance URL, without protocol or port. For example `gitlab.example.com`. |
|
||||
| `CI_SERVER_NAME` | Pre-pipeline | The name of CI/CD server that coordinates jobs. |
|
||||
| `CI_SERVER_PORT` | Pre-pipeline | The port of the GitLab instance URL, without host or protocol. For example `8080`. |
|
||||
| `CI_SERVER_PROTOCOL` | Pre-pipeline | The protocol of the GitLab instance URL, without host or port. For example `https`. |
|
||||
| `CI_SERVER_SHELL_SSH_HOST` | Pre-pipeline | The SSH host of the GitLab instance, used for access to Git repositories through SSH. For example `gitlab.com`. Introduced in GitLab 15.11. |
|
||||
| `CI_SERVER_SHELL_SSH_PORT` | Pre-pipeline | The SSH port of the GitLab instance, used for access to Git repositories through SSH. For example `22`. Introduced in GitLab 15.11. |
|
||||
| `CI_SERVER_REVISION` | Pre-pipeline | GitLab revision that schedules jobs. |
|
||||
| `CI_SERVER_TLS_CA_FILE` | Pipeline | File containing the TLS CA certificate to verify the GitLab server when `tls-ca-file` set in [runner settings](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section). |
|
||||
| `CI_SERVER_TLS_CERT_FILE` | Pipeline | File containing the TLS certificate to verify the GitLab server when `tls-cert-file` set in [runner settings](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section). |
|
||||
| `CI_SERVER_TLS_KEY_FILE` | Pipeline | File containing the TLS key to verify the GitLab server when `tls-key-file` set in [runner settings](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section). |
|
||||
| `CI_SERVER_URL` | Pre-pipeline | The base URL of the GitLab instance, including protocol and port. For example `https://gitlab.example.com:8080`. |
|
||||
| `CI_SERVER_VERSION_MAJOR` | Pre-pipeline | The major version of the GitLab instance. For example, if the GitLab version is `17.2.1`, the `CI_SERVER_VERSION_MAJOR` is `17`. |
|
||||
| `CI_SERVER_VERSION_MINOR` | Pre-pipeline | The minor version of the GitLab instance. For example, if the GitLab version is `17.2.1`, the `CI_SERVER_VERSION_MINOR` is `2`. |
|
||||
| `CI_SERVER_VERSION_PATCH` | Pre-pipeline | The patch version of the GitLab instance. For example, if the GitLab version is `17.2.1`, the `CI_SERVER_VERSION_PATCH` is `1`. |
|
||||
| `CI_SERVER_VERSION` | Pre-pipeline | The full version of the GitLab instance. |
|
||||
| `CI_SERVER` | Job-only | Available for all jobs executed in CI/CD. `yes` when available. |
|
||||
| `CI_SHARED_ENVIRONMENT` | Pipeline | Only available if the job is executed in a shared environment (something that is persisted across CI/CD invocations, like the `shell` or `ssh` executor). `true` when available. |
|
||||
| `CI_TEMPLATE_REGISTRY_HOST` | Pre-pipeline | The host of the registry used by CI/CD templates. Defaults to `registry.gitlab.com`. Introduced in GitLab 15.3. |
|
||||
| `CI_TRIGGER_SHORT_TOKEN` | Job-only | First 4 characters of the [trigger token](../triggers/_index.md#create-a-pipeline-trigger-token) of the current job. Only available if the pipeline was [triggered with a trigger token](../triggers/_index.md). For example, for a trigger token of `glptt-1234567890abcdefghij`, `CI_TRIGGER_SHORT_TOKEN` would be `1234`. Introduced in GitLab 17.0. <!-- gitleaks:allow --> |
|
||||
| `GITLAB_CI` | Pre-pipeline | Available for all jobs executed in CI/CD. `true` when available. |
|
||||
| `GITLAB_FEATURES` | Pre-pipeline | The comma-separated list of licensed features available for the GitLab instance and license. |
|
||||
| `GITLAB_USER_EMAIL` | Pipeline | The email of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the email of the user who started the job. |
|
||||
| `GITLAB_USER_ID` | Pipeline | The numeric ID of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the ID of the user who started the job. |
|
||||
| `GITLAB_USER_LOGIN` | Pipeline | The unique username of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the username of the user who started the job. |
|
||||
| `GITLAB_USER_NAME` | Pipeline | The display name (user-defined **Full name** in the profile settings) of the user who started the pipeline, unless the job is a manual job. In manual jobs, the value is the name of the user who started the job. |
|
||||
| `KUBECONFIG` | Pipeline | The path to the `kubeconfig` file with contexts for every shared agent connection. Only available when a [GitLab agent is authorized to access the project](../../user/clusters/agent/ci_cd_workflow.md#authorize-the-agent). |
|
||||
| `TRIGGER_PAYLOAD` | Pipeline | The webhook payload. Only available when a pipeline is [triggered with a webhook](../triggers/_index.md#access-webhook-payload). |
|
||||
|
||||
## Predefined variables for merge request pipelines
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB |
|
|
@ -261,9 +261,22 @@ was merged into your branch. In that case, you must revert the changes on the re
|
|||
### Revert remote changes without altering history
|
||||
|
||||
To undo changes in the remote repository, you can create a new commit with the changes you
|
||||
want to undo. This process preserves the history and provides a clear timeline and development structure.
|
||||
want to undo. This process preserves the history and provides a clear timeline and development structure:
|
||||
|
||||

|
||||
```mermaid
|
||||
%%{init: { "fontFamily": "GitLab Sans" }}%%
|
||||
flowchart LR
|
||||
REMOTE["REMOTE"] --> A(A)
|
||||
A --> B(B)
|
||||
B --> C(C)
|
||||
C --> negB("-B")
|
||||
negB --> D(D)
|
||||
|
||||
B:::crossed
|
||||
classDef crossed stroke:#000,stroke-width:3px,color:#000,stroke-dasharray: 5 5
|
||||
|
||||
negB -.->|reverts| B
|
||||
```
|
||||
|
||||
To revert changes introduced in a specific commit `B`:
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,28 @@ For details, see the [migration guide](https://docs.gitlab.com/user/group/compli
|
|||
|
||||
<div class="deprecation breaking-change" data-milestone="19.0">
|
||||
|
||||
### Coverage-guided fuzz testing is deprecated
|
||||
|
||||
<div class="deprecation-notes">
|
||||
|
||||
- Announced in GitLab <span class="milestone">18.0</span>
|
||||
- End of Support in GitLab <span class="milestone">18.0</span>
|
||||
- Removal in GitLab <span class="milestone">19.0</span> ([breaking change](https://docs.gitlab.com/update/terminology/#breaking-change))
|
||||
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/517841).
|
||||
|
||||
</div>
|
||||
|
||||
Coverage-guided fuzz testing is deprecated and will not be supported
|
||||
from GitLab 18.0. The feature will be completely removed in GitLab 19.0.
|
||||
|
||||
Coverage-guided fuzz testing integrated several open-source fuzzers into GitLab.
|
||||
If you are impacted, you can integrate your open-source fuzzers as standalone applications,
|
||||
or migrate to another security feature like [GitLab Advanced SAST](https://docs.gitlab.com/ee/user/application_security/sast/gitlab_advanced_sast.html).
|
||||
|
||||
</div>
|
||||
|
||||
<div class="deprecation breaking-change" data-milestone="19.0">
|
||||
|
||||
### GitLab Self-Managed certificate-based integration with Kubernetes
|
||||
|
||||
<div class="deprecation-notes">
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@ granularly per policy, you can set a "policy scope" in each policy.
|
|||
Prerequisites:
|
||||
|
||||
- You must have the Owner role or [custom role](../../custom_roles.md) with the`manage_security_policy_link` permission to link to the security policy project. For more information, see [separation of duties](#separation-of-duties).
|
||||
- You must have at least the Reporter role or [custom role](../../custom_roles.md) with the `manage_security_policy_link` permission to the project you want to assign as the security policy project. For more information, see [separation of duties](#separation-of-duties).
|
||||
|
||||
To link a group, subgroup, or project to a security policy project:
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ title: GLQL fields
|
|||
|
||||
- [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/14767) in GitLab 17.4 [with a flag](../../administration/feature_flags.md) named `glql_integration`. Disabled by default.
|
||||
- Enabled on GitLab.com in GitLab 17.4 for a subset of groups and projects.
|
||||
- `iteration` and `cadence` fields [introduced](https://gitlab.com/gitlab-org/gitlab-query-language/gitlab-query-language/-/issues/74) in GitLab 17.6.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
|
|
@ -40,6 +39,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Type
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/81) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: The type of object to query: one of the work item types or merge requests.
|
||||
|
||||
**Field name**: `type`
|
||||
|
||||
**Allowed operators**: `=`, `in`
|
||||
|
|
@ -80,6 +87,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Approved by user
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/81) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query merge requests by one or more users who approved the merge request.
|
||||
|
||||
**Field name**: `approver`
|
||||
|
||||
**Allowed operators**: `=`, `!=`
|
||||
|
|
@ -105,6 +120,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Assignees
|
||||
|
||||
**Description**: Query issues or merge requests by one or more users who are assigned to the issue or merge request.
|
||||
|
||||
**Field name**: `assignee`
|
||||
|
||||
**Allowed operators**: `=`, `in`, `!=`
|
||||
|
|
@ -124,6 +141,10 @@ This page lists fields available to use as filters when querying issues or work
|
|||
- Work item types like `Task` or `Objective`
|
||||
- `MergeRequest`
|
||||
|
||||
**Additional details:**
|
||||
|
||||
- `List` values and the `in` operator are not supported for `MergeRequest` types.
|
||||
|
||||
**Examples**:
|
||||
|
||||
- List all issues where assignee is `@johndoe`:
|
||||
|
|
@ -156,12 +177,10 @@ This page lists fields available to use as filters when querying issues or work
|
|||
type = MergeRequest and assignee = @johndoe
|
||||
```
|
||||
|
||||
**Additional details:**
|
||||
|
||||
- `List` values and the `in` operator are not supported for `MergeRequest` types.
|
||||
|
||||
## Author
|
||||
|
||||
**Description**: Query issues or merge request by their author.
|
||||
|
||||
**Field name**: `author`
|
||||
|
||||
**Allowed operators**: `=`, `in`, `!=`
|
||||
|
|
@ -215,6 +234,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Cadence
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-haskell/-/issues/74) in GitLab 17.6.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query issues by the [cadence](../group/iterations/_index.md#iteration-cadences) that the issue's iteration is a part of.
|
||||
|
||||
**Field name**: `cadence`
|
||||
|
||||
**Allowed operators**: `=`, `in`, `!=`
|
||||
|
|
@ -241,7 +268,7 @@ This page lists fields available to use as filters when querying issues or work
|
|||
- List all issues with iteration that are a part of cadence ID `123456`:
|
||||
|
||||
```plaintext
|
||||
cadences = 123456
|
||||
cadence = 123456
|
||||
```
|
||||
|
||||
- List all issues with iterations that are a part of any cadences `123` or `456`:
|
||||
|
|
@ -252,6 +279,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Closed at
|
||||
|
||||
**Description**: Query issues or merge requests by the date when they were closed.
|
||||
|
||||
**Field name**: `closed`
|
||||
|
||||
**Allowed operators**: `=`, `>`, `<`
|
||||
|
|
@ -295,6 +324,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Confidential
|
||||
|
||||
**Description**: Query issues by their visibility to project members.
|
||||
|
||||
**Field name**: `confidential`
|
||||
|
||||
**Allowed operators**: `=`, `!=`
|
||||
|
|
@ -330,6 +361,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Created at
|
||||
|
||||
**Description**: Query issues or merge requests by the date when they were created.
|
||||
|
||||
**Field name**: `created`
|
||||
|
||||
**Allowed operators**: `=`, `>`, `<`
|
||||
|
|
@ -374,6 +407,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Deployed at
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/81) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query merge requests by the date when they were deployed.
|
||||
|
||||
**Field name**: `deployed`
|
||||
|
||||
**Allowed operators**: `=`, `>`, `<`
|
||||
|
|
@ -408,6 +449,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Draft
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/81) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query merge requests by their draft status.
|
||||
|
||||
**Field name**: `draft`
|
||||
|
||||
**Allowed operators**: `=`, `!=`
|
||||
|
|
@ -436,6 +485,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Due date
|
||||
|
||||
**Description**: Query issues by the date when they are due.
|
||||
|
||||
**Field name**: `due`
|
||||
|
||||
**Allowed operators**: `=`, `>`, `<`
|
||||
|
|
@ -485,6 +536,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Environment
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/81) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query merge requests by the environment to which they have been deployed.
|
||||
|
||||
**Field name**: `environment`
|
||||
|
||||
**Allowed operators**: `=`
|
||||
|
|
@ -505,6 +564,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Group
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Changed](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/106) in GitLab 17.10: Group queries no longer search the entire hierarchy by default.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query issues or merge requests within all projects in a given group.
|
||||
|
||||
**Field name**: `group`
|
||||
|
||||
**Allowed operators**: `=`
|
||||
|
|
@ -526,6 +593,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
- If omitted when using inside a GLQL view in a group object (like an epic), `group` is assumed to
|
||||
be the current group.
|
||||
- Using the `group` field queries all objects in that group, all its subgroups, and child projects.
|
||||
- By default, issues or merge requests are searched only in direct descendant projects in a group.
|
||||
To query in the entire hierarchy of a project use the [`includeSubgroups` field](#include-subgroups).
|
||||
|
||||
**Examples**:
|
||||
|
||||
|
|
@ -543,6 +612,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Health status
|
||||
|
||||
**Description**: Query issues by their health status.
|
||||
|
||||
**Field name**: `health`
|
||||
|
||||
**Allowed operators**: `=`
|
||||
|
|
@ -575,6 +646,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## ID
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/92) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query issues or merge requests by their IDs.
|
||||
|
||||
**Field name**: `id`
|
||||
|
||||
**Allowed operators**: `=`, `in`
|
||||
|
|
@ -612,8 +691,62 @@ This page lists fields available to use as filters when querying issues or work
|
|||
type = MergeRequest and id in (1, 2, 3)
|
||||
```
|
||||
|
||||
## Include subgroups
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/106) in GitLab 17.10.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query within the entire hierarchy of a group.
|
||||
|
||||
**Field name**: `includeSubgroups`
|
||||
|
||||
**Allowed operators**: `=`, `!=`
|
||||
|
||||
**Allowed value types**:
|
||||
|
||||
- `Boolean` (either of `true` or `false`)
|
||||
|
||||
**Allowed in columns of a GLQL view**: Yes
|
||||
|
||||
**Supported for object types**:
|
||||
|
||||
- `Issue`
|
||||
- Work item types like `Task` or `Objective`
|
||||
- `MergeRequest`
|
||||
|
||||
**Additional details**:
|
||||
|
||||
- This field can only be used with the `group` field.
|
||||
- The value of this field defaults to `false`.
|
||||
|
||||
**Examples**:
|
||||
|
||||
- List issues in any project that is a direct child of the `gitlab-org` group:
|
||||
|
||||
```plaintext
|
||||
group = "gitlab-org" and includeSubgroups = false
|
||||
```
|
||||
|
||||
- List issues in any project within the entire hierarchy of the `gitlab-org` group:
|
||||
|
||||
```plaintext
|
||||
group = "gitlab-org" and includeSubgroups = true
|
||||
```
|
||||
|
||||
## Iteration
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-haskell/-/issues/74) in GitLab 17.6.
|
||||
- Support for iteration value types [introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/79) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query issues by their associated [iteration](../group/iterations/_index.md).
|
||||
|
||||
**Field name**: `iteration`
|
||||
|
||||
**Allowed operators**: `=`, `in`, `!=`
|
||||
|
|
@ -672,6 +805,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Labels
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- Support for label value types [introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/79) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query issues or merge requests by their associated labels.
|
||||
|
||||
**Field name**: `label`
|
||||
|
||||
**Allowed operators**: `=`, `in`, `!=`
|
||||
|
|
@ -742,6 +883,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Merged at
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/81) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query merge requests by the date when they were merged.
|
||||
|
||||
**Field name**: `merged`
|
||||
|
||||
**Allowed operators**: `=`, `>`, `<`
|
||||
|
|
@ -776,6 +925,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Merged by user
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/81) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query merge requests by the user that merged the merge request.
|
||||
|
||||
**Field name**: `merger`
|
||||
|
||||
**Allowed operators**: `=`
|
||||
|
|
@ -801,6 +958,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Milestone
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- Support for milestone value types [introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/77) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: Query issues or merge requests by their associated milestone.
|
||||
|
||||
**Field name**: `milestone`
|
||||
|
||||
**Allowed operators**: `=`, `in`, `!=`
|
||||
|
|
@ -860,6 +1025,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Project
|
||||
|
||||
**Description**: Query issues or merge requests within a particular project.
|
||||
|
||||
**Field name**: `project`
|
||||
|
||||
**Allowed operators**: `=`
|
||||
|
|
@ -890,6 +1057,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Reviewers
|
||||
|
||||
**Description**: Query merge requests that were reviewed by one or more users.
|
||||
|
||||
**Field name**: `reviewer`
|
||||
|
||||
**Allowed operators**: `=`, `!=`
|
||||
|
|
@ -915,6 +1084,14 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## State
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab-query-language/glql-rust/-/merge_requests/96) in GitLab 17.8.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
**Description**: The state of this issue or merge request.
|
||||
|
||||
**Field name**: `state`
|
||||
|
||||
**Allowed operators**: `=`
|
||||
|
|
@ -965,6 +1142,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Updated at
|
||||
|
||||
**Description**: Query issues or merge requests by when they were last updated.
|
||||
|
||||
**Field name**: `updated`
|
||||
|
||||
**Allowed operators**: `=`, `>`, `<`
|
||||
|
|
@ -1009,6 +1188,8 @@ This page lists fields available to use as filters when querying issues or work
|
|||
|
||||
## Weight
|
||||
|
||||
**Description**: Query issues by their weight.
|
||||
|
||||
**Field name**: `weight`
|
||||
|
||||
**Allowed operators**: `=`, `!=`
|
||||
|
|
|
|||
|
|
@ -13,14 +13,20 @@ title: Create users
|
|||
|
||||
{{< /details >}}
|
||||
|
||||
User accounts form the foundation of GitLab collaboration. Every person who needs access to your GitLab
|
||||
projects requires an account. User accounts control access permissions, track contributions, and maintain
|
||||
security across your instance.
|
||||
|
||||
You can create user accounts in GitLab in different ways:
|
||||
|
||||
- Direct users to create their own account.
|
||||
- Create accounts for other users manually.
|
||||
- Configure authentication integrations.
|
||||
- Create users through the Rails console.
|
||||
- Self-registration for teams who value autonomy
|
||||
- Admin-driven creation for controlled onboarding
|
||||
- Authentication integration for enterprise environments
|
||||
- Console access for automation and bulk operations
|
||||
|
||||
If you want to automate user creation, you should use the [users API endpoint](../../../api/users.md#create-a-user).
|
||||
You can also use the [users API endpoint](../../../api/users.md#create-a-user) to automatically create users.
|
||||
|
||||
Choose the right method based on your organization's size, security requirements, and workflows.
|
||||
|
||||
## Create users on sign-in page
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ module BulkImports
|
|||
if sub_relation.is_a?(Array)
|
||||
sub_relation
|
||||
.map { |entry| deep_transform_relation!(entry, sub_relation_key, sub_relation_definition, &block) }
|
||||
.tap { |entry| entry.compact! }
|
||||
.tap(&:compact!)
|
||||
.presence
|
||||
else
|
||||
deep_transform_relation!(sub_relation, sub_relation_key, sub_relation_definition, &block)
|
||||
|
|
|
|||
|
|
@ -30,15 +30,11 @@ module ContainerRegistry
|
|||
}.freeze
|
||||
|
||||
def self.supports_tag_delete?
|
||||
with_dummy_client(return_value_if_disabled: false) do |client|
|
||||
client.supports_tag_delete?
|
||||
end
|
||||
with_dummy_client(return_value_if_disabled: false, &:supports_tag_delete?)
|
||||
end
|
||||
|
||||
def self.registry_info
|
||||
with_dummy_client do |client|
|
||||
client.registry_info
|
||||
end
|
||||
with_dummy_client(&:registry_info)
|
||||
end
|
||||
|
||||
def registry_info
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@ module ContainerRegistry
|
|||
UnsuccessfulResponseError = Class.new(StandardError)
|
||||
|
||||
def self.supports_gitlab_api?
|
||||
with_dummy_client(return_value_if_disabled: false) do |client|
|
||||
client.supports_gitlab_api?
|
||||
end
|
||||
with_dummy_client(return_value_if_disabled: false, &:supports_gitlab_api?)
|
||||
end
|
||||
|
||||
def self.deduplicated_size(path)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ module Gitlab
|
|||
|
||||
# hash for defining ActiveRecord enum: identifier => number
|
||||
def self.to_enum
|
||||
enum_mapping.transform_keys { |k| k.identifier }
|
||||
enum_mapping.transform_keys(&:identifier)
|
||||
end
|
||||
|
||||
def self.pairing_rules
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def expand_directions
|
||||
return [:both] if (1...MAX_EXPANDABLE_LINES).cover?(line_count_between)
|
||||
return [:both] if (1..MAX_EXPANDABLE_LINES).cover?(line_count_between)
|
||||
|
||||
directions = []
|
||||
directions << :down if @previous_line_pos&.positive?
|
||||
|
|
@ -123,7 +123,8 @@ module Gitlab
|
|||
def line_count_between
|
||||
return 0 if invalid_pos?(@previous_line_pos) || invalid_pos?(@next_line_pos)
|
||||
|
||||
@next_line_pos - @previous_line_pos
|
||||
# 1..3 -> lines in between: 1
|
||||
@next_line_pos - @previous_line_pos - 1
|
||||
end
|
||||
|
||||
def invalid_pos?(pos)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,12 @@ module Gitlab
|
|||
increment_total_events_counter
|
||||
end
|
||||
|
||||
def emit_event_payload(payload)
|
||||
# Using #input as the tracker doesn't have an option to track using a json object
|
||||
# https://snowplow.github.io/snowplow-ruby-tracker/SnowplowTracker/Emitter.html#input-instance_method
|
||||
emitter.input(payload)
|
||||
end
|
||||
|
||||
def options(group)
|
||||
additional_features = Feature.enabled?(:additional_snowplow_tracking, group, type: :ops)
|
||||
{
|
||||
|
|
@ -77,7 +83,14 @@ module Gitlab
|
|||
end
|
||||
|
||||
def emitter
|
||||
emitter_options = {
|
||||
@emitter ||= SnowplowTracker::AsyncEmitter.new(
|
||||
endpoint: hostname,
|
||||
options: emitter_options
|
||||
)
|
||||
end
|
||||
|
||||
def emitter_options
|
||||
options = {
|
||||
protocol: protocol,
|
||||
on_success: method(:increment_successful_events_emissions),
|
||||
on_failure: method(:failure_callback)
|
||||
|
|
@ -86,15 +99,12 @@ module Gitlab
|
|||
if Feature.enabled?(:snowplow_tracking_post_method, :instance, type: :gitlab_com_derisk)
|
||||
# By default, Snowplow uses `get` method with buffer_size set to `1`.
|
||||
# However, setting method to `post` changes default buffer_size to `10`
|
||||
emitter_options[:method] = 'post'
|
||||
options[:method] = 'post'
|
||||
buffer_size = Feature.enabled?(:snowplow_buffer_events, :instance, type: :gitlab_com_derisk) ? 10 : 1
|
||||
emitter_options[:buffer_size] = buffer_size
|
||||
options[:buffer_size] = buffer_size
|
||||
end
|
||||
|
||||
SnowplowTracker::AsyncEmitter.new(
|
||||
endpoint: hostname,
|
||||
options: emitter_options
|
||||
)
|
||||
options
|
||||
end
|
||||
|
||||
def failure_callback(success_count, failures)
|
||||
|
|
|
|||
|
|
@ -13579,6 +13579,12 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster’s integration"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Agent name"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Agent setup failed"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13657,6 +13663,9 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Create a Kubernetes cluster"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Create agent and migrate"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13672,6 +13681,9 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Enable this setting if using role-based access control (RBAC)."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Enter a unique name for your new GitLab Agent. This name will be used to identify the agent in your project."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Enter details about your cluster. %{linkStart}How do I use a certificate to connect to my cluster?%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13714,10 +13726,13 @@ msgstr ""
|
|||
msgid "ClusterIntegration|HTTP Error"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|How do I migrate to the GitLab agent?"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|If you do not wish to delete all associated GitLab resources, you can simply remove the integration."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Install agent"
|
||||
msgid "ClusterIntegration|Installing agent in progress."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Instance cluster"
|
||||
|
|
@ -13729,6 +13744,9 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Integration enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Invalid configuration project"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Kubernetes cluster is being created..."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13747,6 +13765,9 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Learn more about instance Kubernetes clusters"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Learn more about migrating to GitLab Agent"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Make sure your API endpoint is correct"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13756,10 +13777,7 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Migrate"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Migrate this cluster to use the GitLab agent for Kubernetes"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Migrate to the GitLab agent for Kubernetes"
|
||||
msgid "ClusterIntegration|Migrate to GitLab Agent for Kubernetes"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Migrating cluster - failed: \"%{error}\""
|
||||
|
|
@ -13771,12 +13789,18 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Namespace per environment"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|New agent name"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Project cluster"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Project name"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Project namespace (optional, unique)"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13813,6 +13837,9 @@ msgstr ""
|
|||
msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Select a project for the GitLab Agent."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Service Token"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13831,12 +13858,24 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{linkStart}Auto DevOps.%{linkEnd} The domain should have a wildcard DNS configured matching the domain. "
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Step 1. Connect the agent"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|The %{agent_docs_link_start}GitLab Agent for Kubernetes %{agent_docs_link_end} offers improved security, reliability, and functionality. Follow the steps below to create a new agent and migrate your existing certificate-based integration. The process is automated, but you still need to %{install_docs_link_start}install the agent%{install_docs_link_end} in your cluster."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|The Kubernetes certificate used to authenticate to the cluster."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|The agent connection is set up."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|The agent was not installed in the cluster."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|The certificate-based Kubernetes integration is deprecated and will be removed in the future. You should %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}. For more information, see the %{deprecationLinkStart}deprecation epic%{deprecationLinkEnd}, or contact GitLab support."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13855,9 +13894,6 @@ msgstr ""
|
|||
msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|This cluster integration is deprecated. To continue using this Kubernetes cluster with GitLab, you must install the agent."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -61722,6 +61758,9 @@ msgstr ""
|
|||
msgid "Unauthenticated web rate limit period in seconds"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unauthorized"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unauthorized to access the cluster agent in this project"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'yaml'
|
||||
|
||||
class Database
|
||||
module Database
|
||||
class QueryAnalyzers
|
||||
attr_reader :analyzers
|
||||
|
||||
|
|
|
|||
|
|
@ -9,3 +9,5 @@ MultiplePartitionScanDetector:
|
|||
# These fingerprints can be found in the auto_explain pipeline artifacts.
|
||||
# Example:
|
||||
# - c2cfe803a497101b
|
||||
JSONBScanDetector:
|
||||
todos:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'json'
|
||||
require 'zlib'
|
||||
|
||||
class Database
|
||||
module Database
|
||||
class QueryAnalyzers
|
||||
class Base
|
||||
attr_accessor :output
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'base'
|
||||
|
||||
module Database
|
||||
class QueryAnalyzers
|
||||
class JSONBScanDetector < Database::QueryAnalyzers::Base
|
||||
JSONB_MATCH_OPERATOR_EXPRESSION = /<@|@>/
|
||||
|
||||
def initialize(*args)
|
||||
super
|
||||
output[:bad_queries] = []
|
||||
end
|
||||
|
||||
def analyze(query)
|
||||
super
|
||||
return if config['todos']&.include?(query['fingerprint'])
|
||||
|
||||
output[:bad_queries] << query if has_operator_in_where?(query['query'])
|
||||
end
|
||||
|
||||
def save!
|
||||
return if output[:bad_queries].empty?
|
||||
|
||||
Zlib::GzipWriter.open(output_path("jsonb_column_scans.ndjson")) do |file|
|
||||
output[:bad_queries].each do |query|
|
||||
file.puts(JSON.generate(query))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def has_operator_in_where?(query)
|
||||
return false unless query.match?(JSONB_MATCH_OPERATOR_EXPRESSION)
|
||||
|
||||
clauses = query.split(/\sWHERE\s|\sJOIN\s/)
|
||||
return false if clauses.length < 2
|
||||
|
||||
clauses[1..].each do |c|
|
||||
return true if c.include?('::jsonb')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require_relative 'base'
|
||||
|
||||
class Database
|
||||
module Database
|
||||
class QueryAnalyzers
|
||||
class MultiplePartitionScanDetector < Database::QueryAnalyzers::Base
|
||||
def analyze(query)
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ RSpec.describe RapidDiffs::DiffFileComponent, type: :component, feature_category
|
|||
|
||||
it "renders server data" do
|
||||
render_component
|
||||
diff_path = "/#{namespace.to_param}/#{project.to_param}/-/blob/#{diff_file.content_sha}/#{diff_file.file_path}/diff"
|
||||
expect(web_component['data-blob-diff-path']).to eq(diff_path)
|
||||
diff_path = "/#{namespace.to_param}/#{project.to_param}/-/blob/#{diff_file.content_sha}/#{diff_file.file_path}"
|
||||
expect(web_component['data-diff-lines-path']).to eq("#{diff_path}/diff_lines")
|
||||
end
|
||||
|
||||
context "when is text diff" do
|
||||
|
|
|
|||
|
|
@ -6,21 +6,27 @@ RSpec.describe RapidDiffs::Viewers::Text::ExpandLinesComponent, type: :component
|
|||
it "renders expand up" do
|
||||
render_component([:up])
|
||||
expect(page).to have_selector('button svg use[href$="#expand-up"]')
|
||||
expect(page).to have_selector('[data-expand-direction="up"]')
|
||||
end
|
||||
|
||||
it "renders expand down" do
|
||||
render_component([:down])
|
||||
expect(page).to have_selector('button svg use[href$="#expand-down"]')
|
||||
expect(page).to have_selector('[data-expand-direction="down"]')
|
||||
end
|
||||
|
||||
it "renders expand up and down" do
|
||||
render_component([:down, :up])
|
||||
expect(page).to have_selector('button svg use[href$="#expand-up"]')
|
||||
expect(page).to have_selector('button svg use[href$="#expand-down"]')
|
||||
expect(page).to have_selector('[data-expand-direction="up"]')
|
||||
expect(page).to have_selector('[data-expand-direction="down"]')
|
||||
end
|
||||
|
||||
it "renders expand both" do
|
||||
render_component([:both])
|
||||
expect(page).to have_selector('button svg use[href$="#expand"]')
|
||||
expect(page).to have_selector('[data-expand-direction="both"]')
|
||||
end
|
||||
|
||||
def render_component(directions)
|
||||
|
|
|
|||
|
|
@ -90,6 +90,16 @@ RSpec.describe RapidDiffs::Viewers::Text::InlineHunkComponent, type: :component,
|
|||
expect(page).to have_selector('button svg use[href$="#expand"]')
|
||||
end
|
||||
|
||||
it "renders testid" do
|
||||
render_component
|
||||
expect(page).to have_selector("[data-testid='hunk-lines-inline']")
|
||||
end
|
||||
|
||||
it "renders data-hunk-lines" do
|
||||
render_component
|
||||
expect(page).to have_selector("[data-hunk-lines]")
|
||||
end
|
||||
|
||||
def render_component(diff_hunk = hunk)
|
||||
render_inline(
|
||||
described_class.new(
|
||||
|
|
@ -99,9 +109,4 @@ RSpec.describe RapidDiffs::Viewers::Text::InlineHunkComponent, type: :component,
|
|||
)
|
||||
)
|
||||
end
|
||||
|
||||
it "renders testid" do
|
||||
render_component
|
||||
expect(page).to have_selector("[data-testid='hunk-lines-inline']")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ RSpec.describe RapidDiffs::Viewers::Text::LineNumberComponent, type: :component,
|
|||
expect(link[:'data-line-number']).to eq(old_line.old_pos.to_s)
|
||||
expect(td[:id]).to eq(old_line.id(diff_file.file_hash, :old))
|
||||
expect(td[:'data-legacy-id']).to eq(diff_file.line_code(old_line))
|
||||
expect(page).to have_selector('[data-position="old"]')
|
||||
end
|
||||
|
||||
it "renders link for added line on right side" do
|
||||
|
|
@ -41,6 +42,7 @@ RSpec.describe RapidDiffs::Viewers::Text::LineNumberComponent, type: :component,
|
|||
expect(link[:'data-line-number']).to eq(new_line.new_pos.to_s)
|
||||
expect(td[:id]).to eq(new_line.id(diff_file.file_hash, :new))
|
||||
expect(td[:'data-legacy-id']).to eq(diff_file.line_code(new_line))
|
||||
expect(page).to have_selector('[data-position="new"]')
|
||||
end
|
||||
|
||||
def render_component(line:, position: nil)
|
||||
|
|
|
|||
|
|
@ -90,6 +90,16 @@ RSpec.describe RapidDiffs::Viewers::Text::ParallelHunkComponent, type: :componen
|
|||
expect(page).to have_selector('button svg use[href$="#expand"]')
|
||||
end
|
||||
|
||||
it "renders testid" do
|
||||
render_component
|
||||
expect(page).to have_selector("[data-testid='hunk-lines-parallel']")
|
||||
end
|
||||
|
||||
it "renders data-hunk-lines" do
|
||||
render_component
|
||||
expect(page).to have_selector("[data-hunk-lines]")
|
||||
end
|
||||
|
||||
def render_component(diff_hunk = hunk)
|
||||
render_inline(
|
||||
described_class.new(
|
||||
|
|
@ -99,9 +109,4 @@ RSpec.describe RapidDiffs::Viewers::Text::ParallelHunkComponent, type: :componen
|
|||
)
|
||||
)
|
||||
end
|
||||
|
||||
it "renders testid" do
|
||||
render_component
|
||||
expect(page).to have_selector("[data-testid='hunk-lines-parallel']")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -212,7 +212,10 @@ RSpec.describe Admin::ClustersController, feature_category: :deployment_manageme
|
|||
def go
|
||||
post :migrate,
|
||||
params: {
|
||||
configuration_project_id: configuration_project.id,
|
||||
cluster_migration: {
|
||||
configuration_project_id: configuration_project.id,
|
||||
agent_name: 'new-agent'
|
||||
},
|
||||
id: cluster
|
||||
}
|
||||
end
|
||||
|
|
@ -226,6 +229,7 @@ RSpec.describe Admin::ClustersController, feature_category: :deployment_manageme
|
|||
Clusters::Migration::CreateService,
|
||||
an_object_having_attributes(class: cluster.class, id: cluster.id),
|
||||
current_user: admin,
|
||||
agent_name: 'new-agent',
|
||||
configuration_project_id: configuration_project.id.to_s
|
||||
) do |service|
|
||||
expect(service).to receive(:execute).and_call_original
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe EventForward::Logger, feature_category: :product_analytics do
|
||||
subject(:logger) { described_class.new('/dev/null') }
|
||||
|
||||
it_behaves_like 'a json logger', {}
|
||||
|
||||
describe '#file_name_noext' do
|
||||
it 'returns log file name without extension' do
|
||||
expect(described_class.file_name_noext).to eq('event_collection')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -257,8 +257,11 @@ RSpec.describe Groups::ClustersController, feature_category: :deployment_managem
|
|||
def go
|
||||
post :migrate,
|
||||
params: {
|
||||
cluster_migration: {
|
||||
configuration_project_id: configuration_project.id,
|
||||
agent_name: 'new-agent'
|
||||
},
|
||||
group_id: group,
|
||||
configuration_project_id: configuration_project.id,
|
||||
id: cluster
|
||||
}
|
||||
end
|
||||
|
|
@ -272,6 +275,7 @@ RSpec.describe Groups::ClustersController, feature_category: :deployment_managem
|
|||
Clusters::Migration::CreateService,
|
||||
an_object_having_attributes(class: cluster.class, id: cluster.id),
|
||||
current_user: user,
|
||||
agent_name: 'new-agent',
|
||||
configuration_project_id: configuration_project.id.to_s
|
||||
) do |service|
|
||||
expect(service).to receive(:execute).and_call_original
|
||||
|
|
@ -300,6 +304,7 @@ RSpec.describe Groups::ClustersController, feature_category: :deployment_managem
|
|||
|
||||
describe 'security' do
|
||||
it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { expect { go }.to be_allowed_for(:admin) }
|
||||
|
||||
it('is denied for admin when admin mode is disabled') { expect { go }.to be_denied_for(:admin) }
|
||||
it { expect { go }.to be_allowed_for(:owner).of(group) }
|
||||
it { expect { go }.to be_allowed_for(:maintainer).of(group) }
|
||||
|
|
|
|||
|
|
@ -278,9 +278,12 @@ RSpec.describe Projects::ClustersController, feature_category: :deployment_manag
|
|||
def go
|
||||
post :migrate,
|
||||
params: {
|
||||
cluster_migration: {
|
||||
configuration_project_id: project.id,
|
||||
agent_name: 'new-agent'
|
||||
},
|
||||
namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
configuration_project_id: project.id,
|
||||
id: cluster
|
||||
}
|
||||
end
|
||||
|
|
@ -294,6 +297,7 @@ RSpec.describe Projects::ClustersController, feature_category: :deployment_manag
|
|||
Clusters::Migration::CreateService,
|
||||
an_object_having_attributes(class: cluster.class, id: cluster.id),
|
||||
current_user: user,
|
||||
agent_name: 'new-agent',
|
||||
configuration_project_id: project.id.to_s
|
||||
) do |service|
|
||||
expect(service).to receive(:execute).and_call_original
|
||||
|
|
@ -322,6 +326,7 @@ RSpec.describe Projects::ClustersController, feature_category: :deployment_manag
|
|||
|
||||
describe 'security' do
|
||||
it('is allowed for admin when admin mode is enabled', :enable_admin_mode) { expect { go }.to be_allowed_for(:admin) }
|
||||
|
||||
it('is denied for admin when admin mode is disabled') { expect { go }.to be_denied_for(:admin) }
|
||||
it { expect { go }.to be_allowed_for(:owner).of(project) }
|
||||
it { expect { go }.to be_allowed_for(:maintainer).of(project) }
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ FactoryBot.define do
|
|||
|
||||
before(:create) do |migration|
|
||||
migration.project = migration.agent.project
|
||||
migration.agent_name = migration.agent.name
|
||||
end
|
||||
|
||||
agent_install_status { :pending }
|
||||
|
|
|
|||
|
|
@ -99,10 +99,79 @@ RSpec.describe 'Clusterable > Show page', feature_category: :deployment_manageme
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'migration tab' do
|
||||
describe 'migration tab' do
|
||||
before do
|
||||
stub_feature_flags(cluster_agent_migrations: true)
|
||||
visit cluster_path
|
||||
click_link 'Migrate'
|
||||
end
|
||||
|
||||
it 'shows the migration form when no agent exists' do
|
||||
expect(page).to have_content('Migrate to GitLab Agent for Kubernetes')
|
||||
expect(page).to have_selector('.js-vue-project-select')
|
||||
expect(page).to have_field('Agent name')
|
||||
expect(page).to have_button('Create agent and migrate')
|
||||
end
|
||||
|
||||
context 'when agent exists' do
|
||||
let!(:agent) { create(:cluster_agent) }
|
||||
let!(:cluster_migration) do
|
||||
create(:cluster_agent_migration, cluster: cluster, agent: agent, agent_install_status: :success)
|
||||
end
|
||||
|
||||
before do
|
||||
visit cluster_path
|
||||
click_link 'Migrate'
|
||||
end
|
||||
|
||||
it 'shows agent information' do
|
||||
expect(page).to have_content('The agent connection is set up')
|
||||
expect(page).to have_content("#{agent.name}##{agent.id}")
|
||||
expect(page).to have_content(cluster_migration.project.full_name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with different installation states' do
|
||||
let!(:cluster_migration) { create(:cluster_agent_migration, cluster: cluster) }
|
||||
|
||||
it 'shows in_progress state' do
|
||||
cluster_migration.update!(agent_install_status: :in_progress)
|
||||
visit cluster_path
|
||||
click_link 'Migrate'
|
||||
|
||||
expect(page).to have_content('Installing agent in progress')
|
||||
end
|
||||
|
||||
it 'shows error state' do
|
||||
cluster_migration.update!(agent_install_status: :error, agent_install_message: 'Failed to install')
|
||||
visit cluster_path
|
||||
click_link 'Migrate'
|
||||
|
||||
expect(page).to have_content('Agent setup failed')
|
||||
expect(page).to have_content('Failed to install')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'creating an agent', :js do
|
||||
it 'creates agent successfully' do
|
||||
within_testid('cluster-migration-form') do
|
||||
select_from_project_select
|
||||
fill_in 'Agent name', with: 'test-agent'
|
||||
click_button 'Create agent and migrate'
|
||||
end
|
||||
|
||||
expect(page).to have_content('Migrating cluster - initiated')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when clusterable is a project' do
|
||||
let(:clusterable) { create(:project) }
|
||||
let(:cluster_path) { project_cluster_path(clusterable, cluster) }
|
||||
let(:cluster) { create(:cluster, :provided_by_gcp, :project, projects: [clusterable]) }
|
||||
let!(:configuration_project) { clusterable }
|
||||
|
||||
before do
|
||||
clusterable.add_maintainer(current_user)
|
||||
|
|
@ -117,12 +186,15 @@ RSpec.describe 'Clusterable > Show page', feature_category: :deployment_manageme
|
|||
it_behaves_like 'editing a user-provided cluster' do
|
||||
let(:cluster) { create(:cluster, :provided_by_user, :project, projects: [clusterable]) }
|
||||
end
|
||||
|
||||
it_behaves_like 'migration tab'
|
||||
end
|
||||
|
||||
context 'when clusterable is a group' do
|
||||
let(:clusterable) { create(:group) }
|
||||
let(:cluster_path) { group_cluster_path(clusterable, cluster) }
|
||||
let(:cluster) { create(:cluster, :provided_by_gcp, :group, groups: [clusterable]) }
|
||||
let!(:configuration_project) { create(:project, group: clusterable) }
|
||||
|
||||
before do
|
||||
clusterable.add_maintainer(current_user)
|
||||
|
|
@ -137,15 +209,20 @@ RSpec.describe 'Clusterable > Show page', feature_category: :deployment_manageme
|
|||
it_behaves_like 'editing a user-provided cluster' do
|
||||
let(:cluster) { create(:cluster, :provided_by_user, :group, groups: [clusterable]) }
|
||||
end
|
||||
|
||||
it_behaves_like 'migration tab'
|
||||
end
|
||||
|
||||
context 'when clusterable is an instance' do
|
||||
let(:current_user) { create(:admin) }
|
||||
let(:cluster_path) { admin_cluster_path(cluster) }
|
||||
let(:cluster) { create(:cluster, :provided_by_gcp, :instance) }
|
||||
let!(:configuration_project) { create(:project) }
|
||||
|
||||
before do
|
||||
enable_admin_mode!(current_user)
|
||||
configuration_project.add_owner(current_user)
|
||||
enable_admin_mode!(current_user)
|
||||
end
|
||||
|
||||
it_behaves_like 'show page' do
|
||||
|
|
@ -157,6 +234,8 @@ RSpec.describe 'Clusterable > Show page', feature_category: :deployment_manageme
|
|||
it_behaves_like 'editing a user-provided cluster' do
|
||||
let(:cluster) { create(:cluster, :provided_by_user, :instance) }
|
||||
end
|
||||
|
||||
it_behaves_like 'migration tab'
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -168,4 +247,10 @@ RSpec.describe 'Clusterable > Show page', feature_category: :deployment_manageme
|
|||
expect(page).to have_content('Remove Kubernetes cluster integration')
|
||||
end
|
||||
end
|
||||
|
||||
def select_from_project_select
|
||||
click_button('Search for project')
|
||||
wait_for_requests
|
||||
find('.gl-new-dropdown-item').click
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue