Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-09-03 15:10:58 +00:00
parent 5210daf07e
commit d8a3221aa3
140 changed files with 2244 additions and 902 deletions

View File

@ -3,7 +3,7 @@ extends:
- plugin:@gitlab/i18n
- plugin:no-jquery/slim
- plugin:no-jquery/deprecated-3.4
- plugin:no-unsanitized/DOM
- plugin:no-unsanitized/recommended-legacy
- ./tooling/eslint-config/conditionally_ignore.js
globals:
__webpack_public_path__: true
@ -164,11 +164,11 @@ rules:
no-unsanitized/method:
- error
- escape:
methods: 'sanitize'
methods: ['sanitize']
no-unsanitized/property:
- error
- escape:
methods: 'sanitize'
methods: ['sanitize']
# This rule will be enabled later.
unicorn/no-array-callback-reference: off
vue/no-undef-components:
@ -234,17 +234,17 @@ overrides:
no-restricted-imports:
- error
- paths:
- name: mousetrap
message: 'Import { Mousetrap } from ~/lib/mousetrap instead.'
- name: vuex
message: 'See our documentation on "Migrating from VueX" for tips on how to avoid adding new VueX stores.'
- name: '@sentry/browser'
message: Use "import * as Sentry from '~/sentry/sentry_browser_wrapper';" instead
- name: ~/locale
importNames:
- __
- s__
message: 'Do not externalize strings in specs: https://docs.gitlab.com/ee/development/i18n/externalization.html#test-files-jest'
- name: mousetrap
message: 'Import { Mousetrap } from ~/lib/mousetrap instead.'
- name: vuex
message: 'See our documentation on "Migrating from VueX" for tips on how to avoid adding new VueX stores.'
- name: '@sentry/browser'
message: Use "import * as Sentry from '~/sentry/sentry_browser_wrapper';" instead
- name: ~/locale
importNames:
- __
- s__
message: 'Do not externalize strings in specs: https://docs.gitlab.com/ee/development/i18n/externalization.html#test-files-jest'
- files:
- 'config/**/*'
- 'scripts/**/*'

View File

@ -1,106 +0,0 @@
.dast_conf:
tags:
- prm
# For scheduling dast job
extends:
- .reports:rules:schedule-dast
image:
name: "${CI_TEMPLATE_REGISTRY_HOST}/security-products/dast:$DAST_VERSION"
resource_group: dast_scan
variables:
DAST_USERNAME_FIELD: "name:user[login]"
DAST_PASSWORD_FIELD: "name:user[password]"
DAST_SUBMIT_FIELD: "css:.js-sign-in-button"
DAST_FULL_SCAN_ENABLED: "true"
DAST_VERSION: 3
GIT_STRATEGY: none
# -Xmx is used to set the JVM memory to 6GB to prevent DAST OutOfMemoryError.
DAST_ZAP_CLI_OPTIONS: "-Xmx6144m"
before_script:
- 'export DAST_WEBSITE="${DAST_WEBSITE:-$(cat environment_url.txt)}"'
- 'export DAST_AUTH_URL="${DAST_WEBSITE}/users/sign_in"'
- 'export DAST_PASSWORD="${REVIEW_APPS_ROOT_PASSWORD}"'
# Help pages are excluded from scan as they are static pages.
# profile/two_factor_auth is excluded from scan to prevent 2FA from being turned on from user profile, which will reduce coverage.
- 'DAST_EXCLUDE_URLS="${DAST_WEBSITE}/help/.*,${DAST_WEBSITE}/-/profile/two_factor_auth,${DAST_WEBSITE}/users/sign_out"'
# Exclude the automatically generated monitoring project from being tested due to https://gitlab.com/gitlab-org/gitlab/-/issues/260362
- 'export DAST_EXCLUDE_URLS="${DAST_EXCLUDE_URLS},${DAST_WEBSITE}/gitlab-instance-.*"'
needs: ["review-deploy"]
stage: dast
# Default job timeout set to 90m and dast rules needs 2h to so that it won't timeout.
timeout: 3h
# Add retry because of intermittent connection problems. See https://gitlab.com/gitlab-org/gitlab/-/issues/244313
retry: 1
artifacts:
paths:
- gl-dast-report.json # GitLab-specific
reports:
dast: gl-dast-report.json
expire_in: 1 week # GitLab-specific
allow_failure: true
# DAST scan with a subset of Release scan rules.
# ZAP rule details can be found at https://www.zaproxy.org/docs/alerts/
dast:anti-clickjacking-header:
extends:
- .dast_conf
variables:
DAST_USERNAME: "user1"
DAST_ONLY_INCLUDE_RULES: "10020"
script:
- /analyze
dast:xss-persistant:
extends:
- .dast_conf
variables:
DAST_USERNAME: "user2"
DAST_ONLY_INCLUDE_RULES: "40014"
script:
- /analyze
dast:insecure-http-method:
extends:
- .dast_conf
variables:
DAST_USERNAME: "user3"
DAST_ONLY_INCLUDE_RULES: "90028"
script:
- /analyze
dast:server-side-template-inj:
extends:
- .dast_conf
variables:
DAST_USERNAME: "user4"
DAST_ONLY_INCLUDE_RULES: "90035"
script:
- /analyze
dast:server-side-template-inj-blind:
extends:
- .dast_conf
variables:
DAST_USERNAME: "user5"
DAST_ONLY_INCLUDE_RULES: "90035"
script:
- /analyze
dast:session-fixation:
extends:
- .dast_conf
variables:
DAST_USERNAME: "user6"
DAST_ONLY_INCLUDE_RULES: "40013"
script:
- /analyze
dast:xss-dombased:
extends:
- .dast_conf
variables:
DAST_USERNAME: "user10"
DAST_ONLY_INCLUDE_RULES: "40026"
script:
- /analyze

View File

@ -14,7 +14,6 @@ include:
- local: .gitlab/ci/global.gitlab-ci.yml
- local: .gitlab/ci/review-apps/rules.gitlab-ci.yml
- local: .gitlab/ci/review-apps/qa.gitlab-ci.yml
- local: .gitlab/ci/review-apps/dast.gitlab-ci.yml
- local: .gitlab/ci/review-apps/dast-api.gitlab-ci.yml
.base-before_script: &base-before_script

View File

@ -37,6 +37,8 @@ workflow:
QA_CAN_TEST_PRAEFECT: "false"
QA_ALLOW_LOCAL_REQUESTS: "true"
QA_SUITE_STATUS_ENV_FILE: $CI_PROJECT_DIR/suite_status.env
# Force color output for cng orchestrator
CLICOLOR_FORCE: 1
# disable selective test execution until pipeline setup is implemented to support it correctly
KNAPSACK_TEST_FILE_PATTERN: ""
QA_TESTS: ""

View File

@ -155,7 +155,7 @@ gem 'grape-path-helpers', '~> 2.0.1', feature_category: :api
gem 'rack-cors', '~> 2.0.1', require: 'rack/cors' # rubocop:todo Gemfile/MissingFeatureCategory
# GraphQL API
gem 'graphql', '~> 2.3.5', feature_category: :api
gem 'graphql', '~> 2.3.14', feature_category: :api
gem 'graphql-docs', '~> 5.0.0', group: [:development, :test], feature_category: :api
gem 'graphiql-rails', '~> 1.10', feature_category: :api
gem 'apollo_upload_server', '~> 2.1.6', feature_category: :api

View File

@ -281,7 +281,7 @@
{"name":"graphiql-rails","version":"1.10.0","platform":"ruby","checksum":"b557f989a737c8b9e985142609bec52fb1e9393a701eb50e02a7c14422891040"},
{"name":"graphlient","version":"0.8.0","platform":"ruby","checksum":"98c408da1d083454e9f5e274f3b0b6261e2a0c2b5f2ed7b3ef9441d46f8e7cb1"},
{"name":"graphlyte","version":"1.0.0","platform":"ruby","checksum":"b5af4ab67dde6e961f00ea1c18f159f73b52ed11395bb4ece297fe628fa1804d"},
{"name":"graphql","version":"2.3.5","platform":"ruby","checksum":"9c367835f86541660d24c3d81632267ecee553d304577aaee070f8ac05860af1"},
{"name":"graphql","version":"2.3.14","platform":"ruby","checksum":"1781f33ab52f250f7bd6082f40ef15363d6acf98009b7acba70d54bee142f295"},
{"name":"graphql-client","version":"0.23.0","platform":"ruby","checksum":"f238b8e451676baad06bd15f95396e018192243dcf12c4e6d13fb41d9a2babc1"},
{"name":"graphql-docs","version":"5.0.0","platform":"ruby","checksum":"76baca6e5a803a4b6a9fbbbfdbf16742b7c4c546c8592b6e1a7aa4e79e562d04"},
{"name":"grpc","version":"1.63.0","platform":"aarch64-linux","checksum":"dc75c5fd570b819470781d9512105dddfdd11d984f38b8e60bb946f92d1f79ee"},

View File

@ -906,8 +906,9 @@ GEM
faraday (~> 2.0)
graphql-client
graphlyte (1.0.0)
graphql (2.3.5)
graphql (2.3.14)
base64
fiber-storage
graphql-client (0.23.0)
activesupport (>= 3.0)
graphql (>= 1.13.0)
@ -2103,7 +2104,7 @@ DEPENDENCIES
graphiql-rails (~> 1.10)
graphlient (~> 0.8.0)
graphlyte (~> 1.0.0)
graphql (~> 2.3.5)
graphql (~> 2.3.14)
graphql-docs (~> 5.0.0)
grpc (= 1.63.0)
gssapi (~> 1.3.1)

View File

@ -2,12 +2,14 @@
import FILTERED_SVG_URL from '@gitlab/svgs/dist/illustrations/empty-state/empty-search-md.svg?url';
import { GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
import EMPTY_SVG_URL from '@gitlab/svgs/dist/illustrations/empty-state/empty-catalog-md.svg';
import { s__ } from '~/locale';
import { COMPONENTS_DOCS_URL } from '~/ci/catalog/constants';
export default {
name: 'CiCatalogEmptyState',
COMPONENTS_DOCS_URL,
EMPTY_SVG_URL,
components: {
GlEmptyState,
GlLink,
@ -77,6 +79,7 @@ export default {
v-else
:title="$options.i18n.default.title"
:description="$options.i18n.default.description"
:svg-path="$options.EMPTY_SVG_URL"
/>
</div>
</template>

View File

@ -120,7 +120,7 @@ export const getTimeago = (formatName) =>
export const localTimeAgo = (elements, updateTooltip = true) => {
const { format } = getTimeago();
elements.forEach((el) => {
el.innerText = format(el.dateTime, timeagoLanguageCode);
el.innerText = format(newDate(el.dateTime), timeagoLanguageCode);
});
if (!updateTooltip) {

View File

@ -11,3 +11,15 @@ export const semverRegex =
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
export const noSpacesRegex = /^\S+$/;
/**
* Checks if a string contains potential regular expression elements.
*
* @param {string} str - The string to check for potential regex elements.
* @returns {boolean} - Returns true if the string contains regex elements, otherwise false.
*/
export const containsPotentialRegex = (str) => {
const regexPattern = /[*+?^${}()|[\]\\]/;
return regexPattern.test(str);
};

View File

@ -9,6 +9,7 @@ import {
GlSprintf,
} from '@gitlab/ui';
import { debounce, intersectionWith, groupBy, differenceBy, intersectionBy } from 'lodash';
import glAbilitiesMixin from '~/vue_shared/mixins/gl_abilities_mixin';
import { createAlert } from '~/alert';
import { __, s__, n__ } from '~/locale';
import { getUsers, getGroups, getDeployKeys } from '../api/access_dropdown_api';
@ -35,6 +36,7 @@ export default {
GlAvatar,
GlSprintf,
},
mixins: [glAbilitiesMixin()],
props: {
accessLevelsData: {
type: Array,
@ -187,6 +189,9 @@ export default {
...this.getDataForSave(LEVEL_TYPES.DEPLOY_KEY, 'deploy_key_id'),
];
},
canAdminContainer() {
return this.glAbilities.adminProject || this.glAbilities.adminGroup;
},
},
watch: {
query: debounce(function debouncedSearch() {
@ -226,29 +231,45 @@ export default {
focusInput() {
this.$refs.search?.focusInput();
},
getGroups() {
return this.groups.length
? Promise.resolve({ data: this.groups })
: getGroups({ withProjectAccess: this.groupsWithProjectAccess });
},
getData({ initial = false } = {}) {
this.initialLoading = initial;
this.loading = true;
if (this.hasLicense) {
Promise.all([
getDeployKeys(this.query),
getUsers(this.query),
this.groups.length
? Promise.resolve({ data: this.groups })
: getGroups({ withProjectAccess: this.groupsWithProjectAccess }),
])
.then(([deployKeysResponse, usersResponse, groupsResponse]) => {
this.consolidateData(deployKeysResponse.data, usersResponse.data, groupsResponse.data);
this.setSelected({ initial });
})
.catch(() =>
createAlert({ message: __('Failed to load groups, users and deploy keys.') }),
)
.finally(() => {
this.initialLoading = false;
this.loading = false;
});
if (this.canAdminContainer) {
Promise.all([getDeployKeys(this.query), getUsers(this.query), this.getGroups()])
.then(([deployKeysResponse, usersResponse, groupsResponse]) => {
this.consolidateData(
deployKeysResponse.data,
usersResponse.data,
groupsResponse.data,
);
this.setSelected({ initial });
})
.catch(() =>
createAlert({ message: __('Failed to load groups, users and deploy keys.') }),
)
.finally(() => {
this.initialLoading = false;
this.loading = false;
});
} else if (this.glAbilities.adminProtectedBranch) {
Promise.all([getUsers(this.query), this.getGroups()])
.then(([usersResponse, groupsResponse]) => {
this.consolidateData(null, usersResponse.data, groupsResponse.data);
this.setSelected({ initial });
})
.catch(() => createAlert({ message: __('Failed to load groups and users.') }))
.finally(() => {
this.initialLoading = false;
this.loading = false;
});
}
} else {
getDeployKeys(this.query)
.then((deployKeysResponse) => {
@ -284,27 +305,31 @@ export default {
}
}
this.deployKeys = deployKeysResponse.map((response) => {
const {
id,
fingerprint,
fingerprint_sha256: fingerprintSha256,
title,
owner: { avatar_url, name, username },
} = response;
if (this.canAdminContainer) {
this.deployKeys = deployKeysResponse.map((response) => {
const {
id,
fingerprint,
fingerprint_sha256: fingerprintSha256,
title,
owner: { avatar_url, name, username },
} = response;
const availableFingerprint = fingerprintSha256 || fingerprint;
const shortFingerprint = `(${availableFingerprint.substring(0, 14)}...)`;
const availableFingerprint = fingerprintSha256 || fingerprint;
const shortFingerprint = `(${availableFingerprint.substring(0, 14)}...)`;
return {
id,
title: title.concat(' ', shortFingerprint),
avatar_url,
fullname: name,
username,
type: LEVEL_TYPES.DEPLOY_KEY,
};
});
return {
id,
title: title.concat(' ', shortFingerprint),
avatar_url,
fullname: name,
username,
type: LEVEL_TYPES.DEPLOY_KEY,
};
});
} else {
this.deployKeys = [];
}
},
setSelected({ initial } = {}) {
if (initial) {

View File

@ -143,13 +143,26 @@ export default class ProtectedBranchCreate {
});
}
createLimitedSuccessAlert() {
this.alert = createAlert({
variant: VARIANT_SUCCESS,
containerSelector: '.js-alert-protected-branch-created-container',
message: s__('ProtectedBranch|Protected branch was sucessfully created'),
});
}
showSuccessAlertIfNeeded() {
if (!this.hasProtectedBranchSuccessAlert()) {
return;
}
this.expandAndScroll(PROTECTED_BRANCHES_ANCHOR);
this.createSuccessAlert();
if (gon.abilities.adminProject || gon.abilities.adminGroup) {
this.createSuccessAlert();
} else {
this.createLimitedSuccessAlert();
}
localStorage.removeItem(IS_PROTECTED_BRANCH_CREATED);
}

View File

@ -13,6 +13,10 @@ export default {
type: Object,
required: true,
},
position: {
type: Number,
required: true,
},
},
data() {
return {
@ -40,6 +44,7 @@ export default {
if (this.showMore) {
return file.chunks;
}
return file.chunks.slice(0, DEFAULT_SHOW_CHUNKS);
},
},
@ -53,7 +58,12 @@ export default {
:key="`chunk${index}`"
class="chunks-block gl-border-b gl-border-subtle last:gl-border-0"
>
<blob-chunks :chunk="chunk" :blame-link="file.blameUrl" :file-url="file.fileUrl" />
<blob-chunks
:chunk="chunk"
:blame-link="file.blameUrl"
:file-url="file.fileUrl"
:position="position"
/>
</div>
</div>
</template>

View File

@ -2,6 +2,13 @@
import { GlTooltipDirective, GlIcon, GlLink } from '@gitlab/ui';
import GlSafeHtmlDirective from '~/vue_shared/directives/safe_html';
import { s__ } from '~/locale';
import { InternalEvents } from '~/tracking';
import {
EVENT_CLICK_BLOB_RESULT_LINE,
EVENT_CLICK_BLOB_RESULT_BLAME_LINE,
} from '~/search/results/tracking';
const trackingMixin = InternalEvents.mixin();
export default {
name: 'BlobChunks',
@ -13,6 +20,7 @@ export default {
GlTooltip: GlTooltipDirective,
SafeHtml: GlSafeHtmlDirective,
},
mixins: [trackingMixin],
i18n: {
viewBlame: s__('GlobalSearch|View blame'),
viewLine: s__('GlobalSearch|View line in repository'),
@ -32,6 +40,10 @@ export default {
required: false,
default: '',
},
position: {
type: Number,
required: true,
},
},
computed: {
codeTheme() {
@ -42,6 +54,18 @@ export default {
highlightedRichText(richText) {
return richText.replace('<b>', '<b class="hll">');
},
trackLineClick(lineNumber) {
this.trackEvent(EVENT_CLICK_BLOB_RESULT_LINE, {
property: lineNumber,
value: this.position,
});
},
trackBlameClick(lineNumber) {
this.trackEvent(EVENT_CLICK_BLOB_RESULT_BLAME_LINE, {
property: lineNumber,
value: this.position,
});
},
},
};
</script>
@ -63,6 +87,8 @@ export default {
:href="`${blameLink}#L${line.lineNumber}`"
:title="$options.i18n.viewBlame"
class="js-navigation-open"
data-testid="search-blob-line-blame-link"
@click="trackBlameClick(line.lineNumber)"
><gl-icon name="git"
/></gl-link>
</span>
@ -72,6 +98,8 @@ export default {
:href="`${fileUrl}#L${line.lineNumber}`"
:title="$options.i18n.viewLine"
class="!gl-flex gl-items-center gl-justify-end"
data-testid="search-blob-line-link"
@click="trackLineClick(line.lineNumber)"
>{{ line.lineNumber }}</gl-link
>
</span>

View File

@ -2,8 +2,12 @@
import { GlSprintf, GlButton, GlLink } from '@gitlab/ui';
import { s__ } from '~/locale';
import { DEFAULT_FETCH_CHUNKS, DEFAULT_SHOW_CHUNKS } from '~/search/results/constants';
import { EVENT_CLICK_BLOB_RESULTS_SHOW_MORE_LESS } from '~/search/results/tracking';
import { InternalEvents } from '~/tracking';
import eventHub from '../event_hub';
const trackingMixin = InternalEvents.mixin();
export default {
name: 'BlobFooter',
components: {
@ -11,6 +15,7 @@ export default {
GlButton,
GlLink,
},
mixins: [trackingMixin],
i18n: {
showMore: s__('GlobalSearch|Show %{matches} more matches'),
showLess: s__('GlobalSearch|Show less'),
@ -23,6 +28,10 @@ export default {
type: Object,
required: true,
},
position: {
type: Number,
required: true,
},
},
data() {
return {
@ -68,6 +77,10 @@ export default {
id: `${this.projectPath}:${this.filePath}`,
state: (this.showMore = !this.showMore),
});
this.trackEvent(EVENT_CLICK_BLOB_RESULTS_SHOW_MORE_LESS, {
label: `${this.position}`,
property: this.showMore ? 'open' : 'close',
});
},
},
DEFAULT_FETCH_CHUNKS,

View File

@ -1,8 +1,17 @@
<script>
import { GlLink } from '@gitlab/ui';
import { GlLink, GlLabel } from '@gitlab/ui';
// eslint-disable-next-line no-restricted-imports
import { mapState } from 'vuex';
import GlSafeHtmlDirective from '~/vue_shared/directives/safe_html';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import { s__ } from '~/locale';
import { InternalEvents } from '~/tracking';
import { containsPotentialRegex } from '~/lib/utils/regexp';
import { EVENT_CLICK_CLIPBOARD_BUTTON, EVENT_CLICK_HEADER_LINK } from '~/search/results/tracking';
import { DEFAULT_THEME_COLOR, DEFAULT_HEADER_LABEL_COLOR } from '../constants';
const trackingMixin = InternalEvents.mixin();
export default {
name: 'BlobHeader',
@ -10,7 +19,12 @@ export default {
FileIcon,
ClipboardButton,
GlLink,
GlLabel,
},
directives: {
SafeHtml: GlSafeHtmlDirective,
},
mixins: [trackingMixin],
props: {
filePath: {
type: String,
@ -26,29 +40,72 @@ export default {
required: false,
default: '',
},
isHeaderOnly: {
type: Boolean,
required: false,
default: false,
},
},
i18n: {
fileLink: s__('GlobalSearch|Open file in repository'),
isHeaderOnly: s__('GlobalSearch|File name match only'),
},
computed: {
...mapState(['query']),
gfmCopyText() {
return `\`${this.filePath}\``;
},
highlightedFilePath() {
if (!this?.query?.search) {
return this.filePath;
}
if (containsPotentialRegex(this.query.search)) {
return this.filePath;
}
const regex = new RegExp(`(${this.query.search})`, 'g');
return this.filePath.replace(
regex,
(match, p1) => `<span class="highlight_word">${p1}</span>`,
);
},
codeTheme() {
return gon.user_color_scheme || DEFAULT_THEME_COLOR;
},
},
methods: {
trackClipboardClick() {
this.trackEvent(EVENT_CLICK_CLIPBOARD_BUTTON);
},
trackHeaderClick() {
this.trackEvent(EVENT_CLICK_HEADER_LINK);
},
},
DEFAULT_HEADER_LABEL_COLOR,
};
</script>
<template>
<div class="file-header-content gl-flex gl-items-center gl-leading-1">
<file-icon :file-name="filePath" :size="16" aria-hidden="true" css-classes="gl-mr-3" />
<gl-link :href="fileUrl" :title="$options.i18n.fileLink">
<gl-link
:href="fileUrl"
:title="$options.i18n.fileLink"
:class="`code ${codeTheme}`"
@click="trackHeaderClick"
>
<template v-if="projectPath">
<strong class="project-path-content" data-testid="project-path-content"
>{{ projectPath }}:
</strong>
</template>
<strong class="file-name-content" data-testid="file-name-content">{{ filePath }}</strong>
<strong
v-safe-html="highlightedFilePath"
class="file-name-content"
data-testid="file-name-content"
></strong>
</gl-link>
<clipboard-button
:text="filePath"
@ -56,6 +113,13 @@ export default {
:title="__('Copy file path')"
category="tertiary"
css-class="gl-mr-2"
@click="trackClipboardClick"
/>
<gl-label
v-if="isHeaderOnly"
:background-color="$options.DEFAULT_HEADER_LABEL_COLOR"
:title="$options.i18n.isHeaderOnly"
class="gl-self-center"
/>
</div>
</template>

View File

@ -64,6 +64,9 @@ export default {
projectPathAndFilePath({ projectPath = '', path = '' }) {
return `${projectPath}:${path}`;
},
position(index) {
return index + 1;
},
},
};
</script>
@ -73,7 +76,7 @@ export default {
<gl-loading-icon v-if="isLoading" :label="__('Loading')" size="md" variant="spinner" />
<div v-if="hasResults && !isLoading" class="gl-relative">
<gl-card
v-for="file in blobSearch.files"
v-for="(file, index) in blobSearch.files"
:key="projectPathAndFilePath(file)"
class="file-result-holder file-holder gl-my-5"
:header-class="{
@ -88,13 +91,14 @@ export default {
:file-path="file.path"
:project-path="file.projectPath"
:file-url="file.fileUrl"
:is-header-only="!hasCode(file)"
/>
</template>
<blob-body v-if="hasCode(file)" :file="file" />
<blob-body v-if="hasCode(file)" :file="file" :position="position(index)" />
<template v-if="hasMore(file)" #footer>
<blob-footer :file="file" />
<blob-footer :file="file" :position="position(index)" />
</template>
</gl-card>
</div>

View File

@ -5,3 +5,6 @@ export const SEARCH_RESULTS_DEBOUNCE = 500;
export const DEFAULT_SHOW_CHUNKS = 3;
export const REF_FIELD_NAME = 'repository_ref';
export const DEFAULT_THEME_COLOR = 'white';
export const DEFAULT_HEADER_LABEL_COLOR = '#D9C2EE';

View File

@ -0,0 +1,5 @@
export const EVENT_CLICK_BLOB_RESULTS_SHOW_MORE_LESS = 'click_blob_results_show_more_less';
export const EVENT_CLICK_BLOB_RESULT_BLAME_LINE = 'click_search_blob_result_blame_line';
export const EVENT_CLICK_BLOB_RESULT_LINE = 'click_search_blob_result_line';
export const EVENT_CLICK_CLIPBOARD_BUTTON = 'click_clipboard_button_in_multimatch_file_header';
export const EVENT_CLICK_HEADER_LINK = 'click_header_link_of_blob_result';

View File

@ -13,7 +13,7 @@ export default {
timeFormatted(time, format) {
const timeago = getTimeago(format);
return timeago.format(time, timeagoLanguageCode);
return timeago.format(newDate(time), timeagoLanguageCode);
},
tooltipTitle(time) {

View File

@ -2,22 +2,17 @@ $notification-box-shadow-color: rgba(0, 0, 0, 0.25);
.flash-container {
margin: 0;
margin-bottom: $gl-padding;
font-size: 14px;
position: relative;
z-index: 1;
@apply gl-flex;
@apply gl-flex-col;
@apply gl-gap-3;
&.sticky {
position: sticky;
top: $calc-application-header-height;
z-index: 251;
.flash-alert,
.flash-notice,
.flash-success,
.flash-warning {
margin-bottom: $gl-spacing-scale-4;
}
}
&.flash-container-page {
@ -63,11 +58,6 @@ $notification-box-shadow-color: rgba(0, 0, 0, 0.25);
display: inline-block;
}
.gl-alert {
margin-top: $gl-spacing-scale-4;
margin-bottom: $gl-spacing-scale-4;
}
&.flash-container-no-margin {
.gl-alert {
margin-top:0;

View File

@ -50,17 +50,8 @@ html {
}
.alert-wrapper {
@include gl-media-breakpoint-up(xl) {
--gl-alert-padding-x: #{$gl-spacing-scale-3};
--gl-broadcast-message-padding-x: #{$gl-spacing-scale-3};
}
.alert {
margin-bottom: 0;
&:last-child {
margin-bottom: $gl-padding;
}
.gl-alert:first-child {
@apply gl-mt-3;
}
.alert-link-group {
@ -143,11 +134,6 @@ html {
margin-bottom: 0;
}
.alert-wrapper .flash-container .flash-alert:last-child,
.alert-wrapper .flash-container .flash-notice:last-child {
margin-bottom: 0;
}
.content-wrapper {
padding-bottom: 0;
flex: 1;

View File

@ -61,27 +61,6 @@ $gl-spacing-scale-48: 48 * $grid-size;
$gl-spacing-scale-75: 75 * $grid-size;
/* End gitlab-ui#1709 */
/*
* Why another sizing scale???
* Great question, friend!
* This size scale is a "backport" of the equivalent set of "named" sizes
* (e.g. `xl` versus `70`) that came from the following design document as of 2019-10-23:
*
* https://gitlab-org.gitlab.io/gitlab-design/hosted/design-gitlab-specs/forms-spec-previews/
*
* (See `input-` items at the bottom)
*
* The presumption here is that these sizes will be standardized in GitLab UI and thus will be
* broadly useful here in the GitLab product when not using the GitLab UI components.
*/
$size-scale: (
'xs': #{10 * $grid-size},
's': #{20 * $grid-size},
'm': #{30 * $grid-size},
'l': #{40 * $grid-size},
'xl': #{70 * $grid-size}
);
// Color schema
$purple: #6d49cb !default;
$purple-light: #ede8fb !default;
@ -115,15 +94,6 @@ $gl-font-size-16: 16px;
$gl-font-size-28: 28px;
$gl-font-size-42: 42px;
$type-scale: (
1: 12px,
2: 14px,
3: 16px,
4: 20px,
5: 28px,
6: 42px
);
/*
* Lists
*/

View File

@ -1,3 +0,0 @@
.learn-gitlab-info-card-content {
height: 200px;
}

View File

@ -4,24 +4,42 @@
to see the available utility classes. If you cannot find the class you need,
consider adding it to Gitlab UI before adding it here.
**/
$type-scale: (
1: 12px,
2: 14px,
4: 20px,
);
@each $index, $size in $type-scale {
#{'.text-#{$index}'} {
font-size: $size;
}
}
/*
* Why another sizing scale???
* Great question, friend!
* This size scale is a "backport" of the equivalent set of "named" sizes
* (e.g. `xl` versus `70`) that came from the following design document as of 2019-10-23:
*
* https://gitlab-org.gitlab.io/gitlab-design/hosted/design-gitlab-specs/forms-spec-previews/
*
* (See `input-` items at the bottom)
*
* The presumption here is that these sizes will be standardized in GitLab UI and thus will be
* broadly useful here in the GitLab product when not using the GitLab UI components.
*/
$size-scale: (
's': #{20 * $grid-size},
);
@each $index, $size in $size-scale {
#{'.mw-#{$index}'} {
max-width: $size;
}
}
@each $index, $size in $type-scale {
#{'.lh-#{$index}'} {
line-height: $size;
}
}
@for $i from 1 through 12 {
#{'.tab-width-#{$i}'} {
/* stylelint-disable-next-line property-no-vendor-prefix */
@ -30,13 +48,7 @@
}
}
.border-width-1px { border-width: 1px; }
.border-style-dashed { border-style: dashed; }
.border-style-solid { border-style: solid; }
.border-color-blue-300 { border-color: $blue-300; }
.border-color-default { border-color: $border-color; }
.border-radius-default { border-radius: $gl-border-radius-base; }
.border-radius-small { border-radius: $border-radius-small; }
.box-shadow-default { box-shadow: 0 2px 4px 0 $t-gray-a-24; }
// Override Bootstrap class with offset for system-header and
@ -50,34 +62,6 @@
top: $calc-application-header-height;
}
// stylelint-disable-next-line gitlab/no-gl-class
.gl-children-ml-sm-3 > * {
@include media-breakpoint-up(sm) {
margin-left: $gl-spacing-scale-3;
}
}
// stylelint-disable-next-line gitlab/no-gl-class
.gl-first-child-ml-sm-0 > a:first-child,
.gl-first-child-ml-sm-0 > button:first-child {
@include media-breakpoint-up(sm) {
margin-left: 0;
}
}
.mh-50vh { max-height: 50vh; }
.min-width-0 {
// By default flex items don't shrink below their minimum content size. To change this, set the item's min-width
min-width: 0;
}
// stylelint-disable-next-line gitlab/no-gl-class
.gl-w-16 { width: px-to-rem($grid-size * 2); }
// stylelint-disable-next-line gitlab/no-gl-class
.gl-w-64 { width: px-to-rem($grid-size * 8); }
// stylelint-disable-next-line gitlab/no-gl-class
.gl-h-32 { height: px-to-rem($grid-size * 4); }
// stylelint-disable-next-line gitlab/no-gl-class
.gl-h-64 { height: px-to-rem($grid-size * 8); }
@ -100,25 +84,6 @@
display: flex;
}
/**
Note: ::-webkit-scrollbar is a non-standard rule only
supported by webkit browsers.
It is added here to migrate components that use
scrolling-links() mixin from `app/assets/stylesheets/framework/mixins.scss`.
It should not be used elsewhere: it may impact accessibility as well as
add browser compatibility issues.
See: https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar
**/
// stylelint-disable-next-line gitlab/no-gl-class
.gl-webkit-scrollbar-display-none {
&::-webkit-scrollbar {
display: none;
}
}
// Will be moved to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1465
// stylelint-disable-next-line gitlab/no-gl-class
.gl-focus-ring-border-1-gray-900\! {
@ -147,13 +112,6 @@
border-bottom-width: 0;
}
// stylelint-disable-next-line gitlab/no-gl-class
.gl-md-h-9 {
@include gl-media-breakpoint-up(md) {
height: $gl-spacing-scale-9;
}
}
// stylelint-disable-next-line gitlab/no-gl-class
.gl-pl-12 {
padding-left: $gl-spacing-scale-12;

View File

@ -443,27 +443,18 @@ class ApplicationController < BaseActionController
end
def set_current_context(&block)
static_context =
if Feature.enabled?(:controller_static_context, Feature.current_request)
{} # middleware should've included caller_id and feature_category
else
{ caller_id: self.class.endpoint_id_for_action(action_name) }
end
# even though feature_category is pre-populated by
# Gitlab::Middleware::ActionControllerStaticContext
# using the static annotation on controllers, the
# controllers can override feature_category conditionally
static_context[:feature_category] = feature_category if feature_category.present?
Gitlab::ApplicationContext.push(feature_category: feature_category) if feature_category.present?
Gitlab::ApplicationContext.push(
static_context.merge({
user: -> { context_user },
project: -> { @project if @project&.persisted? },
namespace: -> { @group if @group&.persisted? },
remote_ip: request.ip,
**http_router_rule_context
})
user: -> { context_user },
project: -> { @project if @project&.persisted? },
namespace: -> { @group if @group&.persisted? },
remote_ip: request.ip,
**http_router_rule_context
)
yield
ensure

View File

@ -9,6 +9,10 @@ module Groups
before_action :authorize_access!, only: :show
before_action :define_deploy_token_variables, if: -> { can?(current_user, :create_deploy_token, @group) }
before_action do
push_frontend_ability(ability: :admin_group, resource: @group, user: current_user)
end
feature_category :continuous_delivery
urgency :low

View File

@ -11,7 +11,7 @@ class ProfilesController < Profiles::ApplicationController
end
feature_category :user_profile, [:reset_incoming_email_token, :reset_feed_token,
:reset_static_object_token, :update_username]
:reset_static_object_token, :update_username, :join_early_access_program]
def reset_incoming_email_token
Users::UpdateService.new(current_user, user: @user).execute! do |user|
@ -116,4 +116,4 @@ class ProfilesController < Profiles::ApplicationController
end
end
ProfilesController.prepend_mod
ProfilesController.prepend_mod_with('ProfilesController')

View File

@ -17,6 +17,8 @@ module Projects
push_frontend_feature_flag(:ci_variables_pages, current_user)
push_frontend_feature_flag(:allow_push_repository_for_job_token, @project)
push_frontend_feature_flag(:ci_hidden_variables, @project.root_ancestor)
push_frontend_ability(ability: :admin_project, resource: @project, user: current_user)
end
helper_method :highlight_badge

View File

@ -9,6 +9,8 @@ module Projects
before_action do
push_frontend_feature_flag(:edit_branch_rules, @project)
push_frontend_ability(ability: :admin_project, resource: @project, user: current_user)
push_frontend_ability(ability: :admin_protected_branch, resource: @project, user: current_user)
end
feature_category :source_code_management, [:show, :cleanup, :update]

View File

@ -16,6 +16,12 @@ module AntiAbuse
include ResolvableNote
include Sortable
extend ::Gitlab::Utils::Override
cache_markdown_field :note, pipeline: :note, issuable_reference_expansion_enabled: true
redact_field :note
self.table_name = 'abuse_report_notes'
belongs_to :abuse_report
@ -30,6 +36,11 @@ module AntiAbuse
def discussion_class(_noteable = nil)
AntiAbuse::Reports::IndividualNoteDiscussion
end
override :skip_project_check?
def skip_project_check?
true
end
end
end
end

View File

@ -8,9 +8,6 @@ class ApplicationSetting < ApplicationRecord
include IgnorableColumns
include Sanitizable
ignore_columns %i[instance_administration_project_id instance_administrators_group_id], remove_with: '16.2', remove_after: '2023-06-22'
ignore_columns %i[repository_storages], remove_with: '16.8', remove_after: '2023-12-21'
ignore_column :required_instance_ci_template, remove_with: '17.1', remove_after: '2024-05-10'
ignore_column :sign_in_text_html, remove_with: '17.5', remove_after: '2024-10-17'
ignore_columns %i[
encrypted_openai_api_key

View File

@ -3,6 +3,9 @@
module Ci
class JobAnnotation < Ci::ApplicationRecord
include Ci::Partitionable
before_validation :set_project_id, on: :create
include BulkInsertSafe
self.table_name = :p_ci_job_annotations
@ -18,7 +21,13 @@ module Ci
partitionable scope: :job, partitioned: true
validates :data, json_schema: { filename: 'ci_job_annotation_data' }
validates :name, presence: true,
length: { maximum: 255 }
validates :name, presence: true, length: { maximum: 255 }
validates :project_id, presence: true, on: :create
private
def set_project_id
self.project_id ||= job&.project_id
end
end
end

View File

@ -1,6 +1,10 @@
# frozen_string_literal: true
class Packages::Conan::Metadatum < ApplicationRecord
include IgnorableColumns
ignore_columns %i[os architecture build_type compiler compiler_version compiler_libcxx compiler_cppstd],
remove_with: '17.6', remove_after: '2024-10-22'
NONE_VALUE = '_'
belongs_to :package, class_name: 'Packages::Conan::Package', inverse_of: :conan_metadatum
@ -14,9 +18,6 @@ class Packages::Conan::Metadatum < ApplicationRecord
validate :username_channel_none_values
validates :os, :architecture, :build_type, :compiler, :compiler_libcxx, :compiler_cppstd, length: { maximum: 32 }
validates :compiler_version, length: { maximum: 16 }
def recipe
"#{package.name}/#{package.version}@#{package_username}/#{package_channel}"
end

View File

@ -2,10 +2,12 @@
module Projects
class BranchRulePolicy < ::ProtectedBranchPolicy
rule { can?(:read_protected_branch) }.enable :read_branch_rule
rule { can?(:create_protected_branch) }.enable :create_branch_rule
rule { can?(:update_protected_branch) }.enable :update_branch_rule
rule { can?(:destroy_protected_branch) }.enable :destroy_branch_rule
rule { can?(:admin_project) }.policy do
enable :read_branch_rule
enable :create_branch_rule
enable :update_branch_rule
enable :destroy_branch_rule
end
end
end

View File

@ -36,7 +36,8 @@ module Ci
raise ParserError, 'Annotations files must be a JSON object' unless blob_json.is_a?(Hash)
blob_json.each do |key, value|
annotations.push(Ci::JobAnnotation.new(job: artifact.job, name: key, data: value))
annotations.push(Ci::JobAnnotation.new(job: artifact.job, name: key, data: value,
project_id: project.id))
if annotations.size > annotations_num_limit
raise SizeLimitError,

View File

@ -19,6 +19,9 @@
"admin_merge_request": {
"type": "boolean"
},
"admin_protected_branch": {
"type": "boolean"
},
"admin_push_rules": {
"type": "boolean"
},

View File

@ -2,6 +2,7 @@
-# Render the parent group sidebar while creating a new subgroup/project, see GroupsController#new.
- group = @parent_group || @group
- context = group || @project
- alert_class = "container-limited" unless fluid_layout
- sidebar_panel = super_sidebar_nav_panel(nav: nav, user: current_user, group: group, project: @project, current_ref: current_ref, ref_type: @ref_type, viewed_user: @user, organization: @organization)
- sidebar_data = super_sidebar_context(current_user, group: group, project: @project, panel: sidebar_panel, panel_type: nav).to_json
@ -11,7 +12,15 @@
.content-wrapper{ class: "#{@content_wrapper_class}" }
= dispensable_render_if_exists 'layouts/header/verification_reminder'
.alert-wrapper.gl-force-block-formatting-context
-# Broadcast messages
.broadcast-wrapper
= dispensable_render_if_exists "shared/token_expiration_banner"
= dispensable_render "layouts/broadcast"
= yield :group_invite_members_banner
-# Alerts
.alert-wrapper.gl-flex.gl-flex-col.gl-gap-3.container-fluid{ class: alert_class }
= dispensable_render 'shared/outdated_browser'
= dispensable_render_if_exists "layouts/header/licensed_user_count_threshold"
= dispensable_render_if_exists "layouts/header/token_expiry_notification"
@ -20,8 +29,6 @@
= dispensable_render_if_exists "shared/groups_projects/self_or_ancestor_marked_for_deletion_notice", context: context
= dispensable_render "shared/projects/inactive_project_deletion_alert"
= dispensable_render "shared/projects/archived_alert"
= dispensable_render_if_exists "shared/token_expiration_banner"
= dispensable_render "layouts/broadcast"
= dispensable_render "layouts/header/read_only_banner"
= dispensable_render "layouts/header/registration_enabled_callout"
= dispensable_render "layouts/nav/classification_level_banner"
@ -35,13 +42,15 @@
= dispensable_render_if_exists "shared/new_user_signups_cap_reached_alert"
= dispensable_render_if_exists "shared/silent_mode_banner"
= yield :page_level_alert
= yield :group_invite_members_banner
- unless @hide_top_bar
= render "layouts/nav/top_bar"
= render "layouts/flash"
= yield :after_flash_content
-# Top bar
- unless @hide_top_bar
= render "layouts/nav/top_bar"
%div{ class: "#{container_class unless @no_container} #{@content_class}" }
%main.content{ id: "content-body", **page_itemtype }
= render "layouts/flash", extra_flash_class: 'limit-container-width'
= yield :after_flash_content
= yield :before_content
= yield
= yield :after_content

View File

@ -4,4 +4,4 @@
- deletion_date = inactive_project_deletion_date(@project)
- title = _('Due to inactivity, this project is scheduled to be deleted on %{deletion_date}. %{link_start}Why is this scheduled?%{link_end}').html_safe % { deletion_date: deletion_date, link_start: link_start, link_end: link_end }
= render Pajamas::AlertComponent.new(title: title, variant: :warning, alert_options: { class: 'gl-pb-3' }, dismissible: false)
= render Pajamas::AlertComponent.new(title: title, variant: :warning, dismissible: false)

View File

@ -328,7 +328,6 @@ module Gitlab
config.assets.precompile << "page_bundles/issues_list.css"
config.assets.precompile << "page_bundles/issues_show.css"
config.assets.precompile << "page_bundles/jira_connect.css"
config.assets.precompile << "page_bundles/learn_gitlab.css"
config.assets.precompile << "page_bundles/log_viewer.css"
config.assets.precompile << "page_bundles/login.css"
config.assets.precompile << "page_bundles/members.css"

View File

@ -0,0 +1,23 @@
---
description: User clicks show more or show less button on the multimatch results page
internal_events: true
action: click_blob_results_show_more_less
identifiers:
- project
- namespace
- user
additional_properties:
value:
description: Position of the result.
property:
description: Set to 'open' if show more is activated and 'close' if it is closed again.
product_group: global_search
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -0,0 +1,18 @@
---
description: Click on copy to clipboard button
internal_events: true
action: click_clipboard_button_in_multimatch_file_header
identifiers:
- project
- namespace
- user
product_group: global_search
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -0,0 +1,18 @@
---
description: Click on the header link of a file result on multimatch result page
internal_events: true
action: click_header_link_of_blob_result
identifiers:
- project
- namespace
- user
product_group: global_search
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -0,0 +1,23 @@
---
description: This event tracks click on a blame link inside the multimatch result
internal_events: true
action: click_search_blob_result_blame_line
identifiers:
- project
- namespace
- user
additional_properties:
value:
description: Position of the result.
property:
description: Blame line.
product_group: global_search
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -0,0 +1,23 @@
---
description: Click on line on the multimatch results page
internal_events: true
action: click_search_blob_result_line
identifiers:
- project
- namespace
- user
additional_properties:
value:
description: Position of the result.
property:
description: Line number.
product_group: global_search
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -1,9 +0,0 @@
---
name: controller_static_context
feature_issue_url: https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/3593
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/157628
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/470047
milestone: '17.4'
group: group::scalability
type: beta
default_enabled: false

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_blob_results_show_more_less_monthly
description: Monthly count of unique users who click the show more or less button
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_blob_results_show_more_less
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_clipboard_button_in_multimatch_file_header_monthly
description: Monthly count of unique users who clicked copy to clipboard button in header of multimatch result
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_clipboard_button_in_multimatch_file_header
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_header_link_of_blob_result_monthly
description: Monthly count of unique users who clicked the blob result header link
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_header_link_of_blob_result
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_search_blob_result_blame_line_monthly
description: Monthly count of unique users who clicked on blame line in the multimatch results page
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_search_blob_result_blame_line
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_search_blob_result_line_monthly
description: Monthly count of unique users who clicked on result line link
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 28d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_search_blob_result_line
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_blob_results_show_more_less_weekly
description: Weekly count of unique users who click the show more or less button
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_blob_results_show_more_less
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_clipboard_button_in_multimatch_file_header_weekly
description: Weekly count of unique users who clicked copy to clipboard button in header of multimatch result
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_clipboard_button_in_multimatch_file_header
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_header_link_of_blob_result_weekly
description: Weekly count of unique users who clicked the blob result header link
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_header_link_of_blob_result
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_search_blob_result_blame_line_weekly
description: Weekly count of unique users who clicked on blame line in the multimatch results page
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_search_blob_result_blame_line
unique: user.id

View File

@ -0,0 +1,22 @@
---
key_path: redis_hll_counters.count_distinct_user_id_from_click_search_blob_result_line_weekly
description: Weekly count of unique users who clicked on result line link
product_group: global_search
performance_indicator_type: []
value_type: number
status: active
milestone: '17.4'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161308
time_frame: 7d
data_source: internal_events
data_category: optional
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
events:
- name: click_search_blob_result_line
unique: user.id

View File

@ -12,6 +12,7 @@ resource :profile, only: [] do
put :reset_feed_token
put :reset_static_object_token
put :update_username
post :join_early_access_program
end
scope module: :profiles do

View File

@ -837,6 +837,8 @@
- 1
- - upload_checksum
- 1
- - users_experimental_communication_opt_in
- 1
- - users_record_last_activity
- 1
- - users_track_namespace_visits

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddProjectIdToPCiJobAnnotations < Gitlab::Database::Migration[2.2]
milestone '17.4'
def change
add_column(:p_ci_job_annotations, :project_id, :bigint)
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class IndexPCiJobAnnotationsOnProjectId < Gitlab::Database::Migration[2.2]
include Gitlab::Database::PartitioningMigrationHelpers
milestone '17.4'
disable_ddl_transaction!
TABLE_NAME = :p_ci_job_annotations
INDEX_NAME = :index_p_ci_job_annotations_on_project_id
def up
add_concurrent_partitioned_index(TABLE_NAME, :project_id, name: INDEX_NAME)
end
def down
remove_concurrent_partitioned_index_by_name(TABLE_NAME, INDEX_NAME)
end
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
class AddPCiJobAnnotationsProjectIdNullConstraint < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.4'
TABLE_NAME = :p_ci_job_annotations
COLUMN_NAME = :project_id
CONSTRAINT_NAME = :check_375bb9900a
def up
Gitlab::Database::PostgresPartitionedTable.each_partition(TABLE_NAME) do |partition|
add_not_null_constraint(partition.identifier, COLUMN_NAME, constraint_name: CONSTRAINT_NAME, validate: false)
end
end
def down
Gitlab::Database::PostgresPartitionedTable.each_partition(TABLE_NAME) do |partition|
remove_not_null_constraint(partition.identifier, COLUMN_NAME, constraint_name: CONSTRAINT_NAME)
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
class BackfillNullProjectCiJobAnnotationRecords < Gitlab::Database::Migration[2.2]
milestone '17.4'
restrict_gitlab_migration gitlab_schema: :gitlab_ci
disable_ddl_transaction!
BATCH_SIZE = 1_000
def up
annotations_model = define_batchable_model('p_ci_job_annotations', primary_key: :id)
annotations_model.each_batch(column: :id) do |batch|
batch
.where('p_ci_job_annotations.job_id = p_ci_builds.id')
.where('p_ci_job_annotations.partition_id = p_ci_builds.partition_id')
.update_all('project_id = p_ci_builds.project_id FROM p_ci_builds')
end
end
def down
# no-op
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class ValidatePCiJobAnnotationProjectIdNullConstraint < Gitlab::Database::Migration[2.2]
milestone '17.4'
disable_ddl_transaction!
TABLE_NAME = :p_ci_job_annotations
COLUMN_NAME = :project_id
CONSTRAINT_NAME = :check_375bb9900a
def up
Gitlab::Database::PostgresPartitionedTable.each_partition(TABLE_NAME) do |partition|
add_not_null_constraint(partition.identifier, COLUMN_NAME, constraint_name: CONSTRAINT_NAME)
end
add_not_null_constraint(TABLE_NAME, COLUMN_NAME, constraint_name: CONSTRAINT_NAME)
end
def down
remove_not_null_constraint(TABLE_NAME, COLUMN_NAME, constraint_name: CONSTRAINT_NAME)
Gitlab::Database::PostgresPartitionedTable.each_partition(TABLE_NAME) do |partition|
add_not_null_constraint(partition.identifier, COLUMN_NAME, constraint_name: CONSTRAINT_NAME, validate: false)
end
end
end

View File

@ -0,0 +1 @@
e359d298d6e198adc094e9c894ecfb2c80244d699eb27d8ff664269c0a3e9b21

View File

@ -0,0 +1 @@
1eb30f94ef39ce6c71efb80e5e068808958f9726f2282d09ed46ec42f6260b29

View File

@ -0,0 +1 @@
fb89e621e0a9d87cd2b304ac9d95f131c881f16fb02f3863dc984d7199a0e35e

View File

@ -0,0 +1 @@
b692b0618940cbfac49b5f358e38613f5fbd799e1853362705f7539bb14d9a41

View File

@ -0,0 +1 @@
771cadd0020345d7b52a97823f0b672465e0ab6c8f622fdee443162a73c79c30

View File

@ -2519,6 +2519,8 @@ CREATE TABLE p_ci_job_annotations (
job_id bigint NOT NULL,
name text NOT NULL,
data jsonb DEFAULT '[]'::jsonb NOT NULL,
project_id bigint,
CONSTRAINT check_375bb9900a CHECK ((project_id IS NOT NULL)),
CONSTRAINT check_bac9224e45 CHECK ((char_length(name) <= 255)),
CONSTRAINT data_is_array CHECK ((jsonb_typeof(data) = 'array'::text))
)
@ -29283,6 +29285,8 @@ CREATE INDEX index_p_ci_finished_build_ch_sync_events_on_project_id ON ONLY p_ci
CREATE UNIQUE INDEX index_p_ci_job_annotations_on_partition_id_job_id_name ON ONLY p_ci_job_annotations USING btree (partition_id, job_id, name);
CREATE INDEX index_p_ci_job_annotations_on_project_id ON ONLY p_ci_job_annotations USING btree (project_id);
CREATE INDEX index_p_ci_runner_machine_builds_on_runner_machine_id ON ONLY p_ci_runner_machine_builds USING btree (runner_machine_id);
CREATE INDEX index_packages_build_infos_on_pipeline_id ON packages_build_infos USING btree (pipeline_id);

View File

@ -205,6 +205,7 @@ The following API resources are available outside of project and group contexts
| [Topics](topics.md) | `/topics` |
| [Users](users.md) | `/users` |
| [Validate `.gitlab-ci.yml` file](lint.md) | `/lint` |
| [Web commits](web_commits.md) | `/web_commits/public_key` |
| [Version](version.md) | `/version` |
## Templates API resources

View File

@ -34288,6 +34288,7 @@ Represents the location of a vulnerability found by a container security scan.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="vulnerabilitylocationcontainerscanningcontainerrepositoryurl"></a>`containerRepositoryUrl` | [`String`](#string) | URL of scanned image. |
| <a id="vulnerabilitylocationcontainerscanningdependency"></a>`dependency` | [`VulnerableDependency`](#vulnerabledependency) | Dependency containing the vulnerability. |
| <a id="vulnerabilitylocationcontainerscanningimage"></a>`image` | [`String`](#string) | Name of the vulnerable container image. |
| <a id="vulnerabilitylocationcontainerscanningoperatingsystem"></a>`operatingSystem` | [`String`](#string) | Operating system that runs on the vulnerable container image. |
@ -36899,6 +36900,7 @@ Member role permission.
| <a id="memberrolepermissionadmin_group_member"></a>`ADMIN_GROUP_MEMBER` | Add or remove users in a group, and assign roles to users. When assigning a role, users with this custom permission must select a role that has the same or fewer permissions as the default role used as the base for their custom role. |
| <a id="memberrolepermissionadmin_integrations"></a>`ADMIN_INTEGRATIONS` | Create, read, update, and delete integrations with external applications. |
| <a id="memberrolepermissionadmin_merge_request"></a>`ADMIN_MERGE_REQUEST` | Allows approval of merge requests. |
| <a id="memberrolepermissionadmin_protected_branch"></a>`ADMIN_PROTECTED_BRANCH` | Create, read, update, and delete protected branches for a project. |
| <a id="memberrolepermissionadmin_push_rules"></a>`ADMIN_PUSH_RULES` | Configure push rules for repositories at the group or project level. |
| <a id="memberrolepermissionadmin_runners"></a>`ADMIN_RUNNERS` | Create, view, edit, and delete group or project Runners. Includes configuring Runner settings. |
| <a id="memberrolepermissionadmin_terraform_state"></a>`ADMIN_TERRAFORM_STATE` | Execute terraform commands, lock/unlock terraform state files, and remove file versions. |

View File

@ -22,6 +22,8 @@ tags:
description: Operations about groups
- name: runners
description: Operations about runners
- name: web_commits
description: Operations about web commits
- name: group_avatar
description: Operations about group_avatars
- name: invitations
@ -39492,6 +39494,23 @@ paths:
tags:
- metadata
operationId: getApiV4Version
"/api/v4/web_commits/public_key":
get:
summary: Get the GitLab public key for signing web commits.
description: This feature was introduced in GitLab 17.4.
tags:
- web_commits
produces:
- application/json
responses:
'200':
description: Get the GitLab public key for signing web commits.
schema:
"$ref": "#/definitions/API_Entities_Web_Commits"
'503':
description: Service unavailable
'404':
description: Not found
"/api/v4/topics":
get:
summary: Get topics
@ -59883,6 +59902,11 @@ definitions:
avatar_url:
type: string
description: API_Entities_Projects_Topic model
API_Entities_Web_Commits:
type: object
properties:
public_key:
type: string
postApiV4Topics:
type: object
properties:

View File

@ -383,6 +383,86 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
- `400: Bad Request` if not revoked successfully.
- `401: Unauthorized` if the access token is invalid.
## List token associations
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/466046) in GitLab 17.4.
Returns an unfiltered list of all groups, subgroups, and projects the current authenticated user can access.
```plaintext
GET /personal_access_tokens/self/associations
GET /personal_access_tokens/self/associations?page=2
GET /personal_access_tokens/self/associations?min_access_level=40
```
Supported attributes:
| Attribute | Type | Required | Description |
|---------------------|----------|----------|--------------------------------------------------------------------------|
| `min_access_level` | integer | No | Limit by current user minimal [role (`access_level`)](members.md#roles). |
| `page` | integer | No | Page to retrieve. Defaults to `1`. |
| `per_page` | integer | No | Number of records to return per page. Defaults to `20`. |
Example request:
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/personal_access_tokens/self/associations"
```
Example response:
```json
{
"groups": [
{
"id": 1,
"web_url": "http://gitlab.example.com/groups/test",
"name": "Test",
"parent_id": null,
"organization_id": 1,
"access_levels": 20,
"visibility": "public"
},
{
"id": 3,
"web_url": "http://gitlab.example.com/groups/test/test_private",
"name": "Test Private",
"parent_id": 1,
"organization_id": 1,
"access_levels": 50,
"visibility": "test_private"
}
],
"projects": [
{
"id": 1337,
"description": "Leet.",
"name": "Test Project",
"name_with_namespace": "Test / Test Project",
"path": "test-project",
"path_with_namespace": "Test/test-project",
"created_at": "2024-07-02T13:37:00.123Z",
"access_levels": {
"project_access_level": null,
"group_access_level": 20
},
"visibility": "private",
"web_url": "http://gitlab.example.com/test/test_project",
"namespace": {
"id": 1,
"name": "Test",
"path": "Test",
"kind": "group",
"full_path": "Test",
"parent_id": null,
"avatar_url": null,
"web_url": "http://gitlab.example.com/groups/test"
}
}
]
}
```
## Create a personal access token (administrator only)
See the [Users API documentation](users.md#create-a-personal-access-token) for information on creating a personal access token.

View File

@ -21,6 +21,9 @@ these additional scopes are available for the [advanced search](#advanced-search
- `blobs`
- `notes`
If you want to use basic search instead, see
[specify a search type](../user/search/index.md#specify-a-search-type).
## Advanced search API
Search for a [term](../user/search/advanced_search.md#syntax) across the entire GitLab instance.

46
doc/api/web_commits.md Normal file
View File

@ -0,0 +1,46 @@
---
stage: Create
group: Source Code
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Web Commits API
DETAILS:
**Tier:** Free
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/442533) in GitLab 17.4.
Use this API to retrieve information about commits created with the Web UI.
## Get public signing key
Get the GitLab public key for signing web commits.
```plaintext
GET /web_commits/public_key
```
If successful, returns [`200`](rest/index.md#status-codes) and the following
response attribute:
| Attribute | Type | Description |
|--------------|--------|---------------------------------------------|
| `public_key` | string | GitLab public key for signing web commits. |
Example request:
```shell
curl --url "https://gitlab.example.com/api/v4/web_commits/public_key"
```
Example response:
```json
[
{
public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=\""
}
]
```

View File

@ -221,6 +221,38 @@ Apply the following feature flags to any AI feature work:
See the [feature flag tracker epic](https://gitlab.com/groups/gitlab-org/-/epics/10524) for the list of all feature flags and how to use them.
### Push feature flags to AI Gateway
You can push [feature flags](../feature_flags/index.md) to AI Gateway. This is helpful to gradually rollout user-facing changes even if the feature resides in AI Gateway.
See the following example:
```ruby
# Push a feature flag state to AI Gateway.
Gitlab::AiGateway.push_feature_flag(:new_prompt_template, user)
```
Later, you can use the feature flag state in AI Gateway in the following way:
```python
from ai_gateway.feature_flags import is_feature_enabled
# Check if the feature flag "new_prompt_template" is enabled.
if is_feature_enabled('new_prompt_template'):
# Build a prompt from the new prompt template
else:
# Build a prompt from the old prompt template
```
**IMPORTANT:** At the [cleaning up](../feature_flags/controls.md#cleaning-up) step, remove the feature flag in AI Gateway repository **before** removing the flag in GitLab-Rails repository.
If you clean up the flag in GitLab-Rails repository at first, the feature flag in AI Gateway will be disabled immediately as it's the default state, hence you might encounter a surprising behavior.
**IMPORTANT:** Cleaning up the feature flag in AI Gateway will immediately distribute the change to all GitLab instances, including GitLab.com, Self-managed GitLab, and Dedicated.
Technical details: When `push_feature_flag` runs on an enabled feature flag, the name of flag is cached in the current context,
which is later attached to `x-gitlab-enabled-feature-flags` HTTP header when GitLab-Sidekiq/Rails requests to AI Gateway.
As a simialr concept, we also have [`push_frontend_feature_flag`](../feature_flags/index.md) to push feature flags to frontend.
### GraphQL API
To connect to the AI provider API using the Abstraction Layer, use an extendable

View File

@ -92,6 +92,33 @@ To pause indexing for [exact code search](../../user/search/exact_code_search.md
When you pause indexing for exact code search, all changes in your repository are queued.
To resume indexing, clear the **Pause indexing for exact code search** checkbox.
## Control indexing concurrency
Prerequisites:
- You must have administrator access to the instance.
You can set the number of concurrent indexing tasks
that can be run on a Zoekt node relative to its CPU capacity.
A higher ratio allows more tasks to run concurrently, potentially
improving indexing throughput at the cost of increased CPU usage.
The default value is `1.0`, meaning one task per CPU core.
You can adjust this value based on your Zoekt node's performance
characteristics and workload.
To set the number of concurrent indexing tasks:
1. On the left sidebar, at the bottom, select **Admin**.
1. Select **Settings > Search**.
1. Expand **Exact code search configuration**.
1. In the **Indexing CPU to tasks multiplier** text box, enter a value.
For example, if a Zoekt node has `4` CPU cores and the ratio is set to `1.5`, the
number of concurrent tasks for a node is going to be `4 * 1.5`, which is `6`.
1. Select **Save changes**.
## Troubleshooting
When working with Zoekt, you might encounter the following issues.

View File

@ -2,163 +2,14 @@
stage: Fulfillment
group: Provision
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
remove_date: '2024-12-02'
redirect_to: 'index.md'
---
# Marketplace partners
<!--- start_remove The following content will be removed on remove_date: '2024-12-02' -->
GitLab supports automation for selected distribution marketplaces to process sales of GitLab products to authorized
channel partners. Marketplace partners can use the GitLab Marketplace APIs to integrate their systems with GitLab to
sell GitLab subscriptions on their site.
# Marketplace partners (removed)
This document's target audience is third-party developers for Marketplace partners.
This feature was removed in GitLab 17.4.
## How the Marketplace APIs work
The Marketplace APIs are hosted in the [Customers Portal](https://customers.gitlab.com/). The Customers Portal allows
individual customers to purchase and manage GitLab subscriptions and supports APIs for partners
to make sales on behalf of their customers. The Customers Portal integrates with other GitLab services, including
Zuora and Salesforce, to provide a task-oriented interface for users.
The following example shows a typical purchase flow of request and response between the following components:
- Customer
- Marketplace partner system
- Customers Portal
- Zuora
- Salesforce
```mermaid
%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
accTitle: Purchase flow
accDescr: Shows the flow of a purchase from the customer, through the customer portal, Zuora, and Salesforce.
participant Customer
participant Marketplace partner system
participant Customers Portal
participant Zuora
participant Salesforce
Customer ->> Marketplace partner system: Place order to purchase GitLab subscription
Marketplace partner system ->> Customers Portal: Get OAuth token
Customers Portal ->> Marketplace partner system: Access token
Marketplace partner system ->> Customers Portal: Place order
Customers Portal ->> Zuora: Create Zuora subscription
Customers Portal ->> Salesforce: Create Salesforce objects
Zuora ->> Customers Portal: Success response with Zuora subscription data
Customers Portal ->> Marketplace partner system: Success response with order ID
Zuora ->> Customers Portal: Zuora callout event
Customers Portal ->> Customer: send license notification
Marketplace partner system ->> Customers Portal: Poll order status
Customers Portal ->> Marketplace partner system: Success response with order status
```
## Marketplace API Specification
OpenAPI specs for the Marketplace APIs are available at [Marketplace interactive API documentation](https://customers.staging.gitlab.com/openapi_docs/marketplace).
## Access the Marketplace API
To access the Marketplace API you need to:
- Request access from GitLab.
- Retrieve an OAuth access token.
Marketplace API endpoints are secured with [OAuth 2.0](https://oauth.net/2/). OAuth is an authorization framework
that grants 3rd party or client applications, like a Marketplace partner application, limited access to resources on an
HTTP service, like the Customers Portal.
OAuth 2.0 uses _grant types_ (or _flows_) that describe how a client application gets authorization in
the form of an _access token_. An access token is a string that the client application uses to make authorized requests to
the resource server.
The Marketplace API uses the `client_credentials` grant type. The client application uses the access token to access its
own resources, instead of accessing resources on behalf of a user.
### Step 1: Request access
Before you can use the Marketplace API, you must contact your Marketplace partner Manager or email `partnerorderops@gitlab.com`
to request access. After you request access, GitLab configures the following accounts and credentials for you:
1. Client credentials. Marketplace APIs are secured with OAuth 2.0. The client credentials include the client ID and client secret
that you need to retrieve the OAuth access token.
1. Invoice owner account in Zuora system. Required for invoice processing.
1. Distributor account in Salesforce system.
1. Trading partner account in Salesforce system. GitLab adds the Trading Partner ID to a permitted list to pass the validations.
### Step 2: Retrieve an access token
To retrieve an access token,
- Make a POST request to the [`/oauth/token`](https://customers.staging.gitlab.com/openapi_docs/marketplace#/marketplace/post_oauth_token) endpoint with the following required parameters:
| Parameter | Type | Required |Description |
|-----------------|--------|----------|------------------------------------------------------------------------------------------------------------------------------------|
| `client_id` | string | yes |ID of your client application record on the Customers Portal. Received from GitLab. |
| `client_secret` | string | yes |Secret of your client application record on the Customers Portal. Received from GitLab. |
| `grant_type` | string | yes |Specifies the type of credential flow. Use `client_credentials`. |
| `scope` | string | yes |Specifies the level of access. Use `marketplace.order:read` for read-only access. Use `marketplace.order:create` for create access. |
If the request is successful, the response body includes the access token that you can use in subsequent requests. For an example of a successful
response, see the [Marketplace interactive API documentation](https://customers.staging.gitlab.com/openapi_docs/marketplace)
If the request is unsuccessful, the response body includes an error and error description. The errors can be:
| Status | Description |
|--------|----------------------------------------------------------------------------------------------------------------------------------------------|
| 400 | Invalid scope. Ensure the `scope` is `marketplace.order:read` or `marketplace.order:create`. |
| 401 | Invalid client. Ensure that there are no typos or extra spaces on the client specific credentials. Incorrect `client_id` or `client_secret` |
### Step 3: Use the access token
To use the access token from a client application:
1. Set the `Authorization` header of the request to `Bearer <your_access_token>`.
1. Set parameters or data needed for the endpoint and send the request.
Example request:
```shell
curl \
--url "https://customers.staging.gitlab.com/api/v1/marketplace/subscriptions/:external_subscription_id" \
--header "Authorization: Bearer NHb_VhZhPOnBTSNfBSzmCmt28lLDWb2xtwr_c3DL148"
```
## Create a new customer subscription
To create a new customer subscription from a Marketplace partner client application,
- Make an authorized POST request to the
[`/api/v1/marketplace/subscriptions`](https://customers.staging.gitlab.com/openapi_docs/marketplace#/marketplace/post_api_v1_marketplace_subscriptions)
endpoint in the Customers Portal with the following parameters in JSON format:
| Parameter | Type | Required | Description |
|--------------------------|--------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| `externalSubscriptionId` | string | yes | ID of the subscription on the Marketplace partner system. |
| `tradingPartnerId` | string | yes | ID of the Trading Partner account in Salesforce. Received from GitLab. |
| `customer` | object | yes | Information about the customer. Must include company name. Contact must include `firstName`, `lastName` and `email`. Address must include `country`. |
| `orderLines` | array | yes | Specifies the product purchased. Must include `quantity` and `productId`. |
If the request is successful, the response body includes the newly created subscription number. For an example of a full request body,
see the [Marketplace interactive API documentation](https://customers.staging.gitlab.com/openapi_docs/marketplace).
If the subscription creation is unsuccessful, the response body includes an error message with details about the cause of the error.
## Check the status of a subscription
To get the status of a given subscription,
- Make an authorized GET request to the
[`/api/v1/marketplace/subscriptions/{external_subscription_id}`](https://customers.staging.gitlab.com/openapi_docs/marketplace#/marketplace/get_api_v1_marketplace_subscriptions__external_subscription_id_)
endpoint in the Customers Portal.
The request must include the Marketplace partner system ID of the subscription to fetch the status for.
If the request is successful, the response body contains the status of the subscription provision. The status can be:
- Creating
- Created
- Failed
- Provisioned
If the subscription cannot be found using the passed `external_subscription_id`, the response has
a 404 Not Found status.
<!--- end_remove -->

View File

@ -86,6 +86,7 @@ These requirements are documented in the `Required permission` column in the fol
| Name | Required permission | Description | Introduced in | Feature flag | Enabled in |
|:-----|:------------|:------------------|:---------|:--------------|:---------|
| [`admin_merge_request`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128302) | | Allows approval of merge requests. | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/412708) | | |
| [`admin_protected_branch`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/162208) | | Create, read, update, and delete protected branches for a project. | GitLab [17.4](https://gitlab.com/gitlab-org/gitlab/-/issues/448823) | | |
| [`admin_push_rules`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147872) | | Configure push rules for repositories at the group or project level. | GitLab [16.11](https://gitlab.com/gitlab-org/gitlab/-/issues/421786) | `custom_ability_admin_push_rules` | |
| [`read_code`](https://gitlab.com/gitlab-org/gitlab/-/issues/376180) | | Allows read-only access to the source code in the user interface. Does not allow users to edit or download repository archives, clone or pull repositories, view source code in an IDE, or view merge requests for private projects. You can download individual files because read-only access inherently grants the ability to make a local copy of the file. | GitLab [15.7](https://gitlab.com/gitlab-org/gitlab/-/issues/20277) | `customizable_roles` | GitLab [15.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110810) |

View File

@ -85,55 +85,72 @@ Prerequisites:
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Usage Quotas**.
1. To view all members, select the **Seats** tab.
1. To remove a member, select **Remove user**.
If you need more time to manage your members, or to try GitLab features
with a team of more than five members, you can [start a trial](https://gitlab.com/-/trial_registrations/new?glm_source=docs.gitlab.com?&glm_content=free-user-limit-faq/ee/user/free_user_limit.html).
A trial lasts for 30 days and includes an unlimited number of members.
On this page, you can view and manage all members in your namespace. For example,
to remove a member, select **Remove user**.
## Include a group in an organization's subscription
If there are multiple groups in your organization, they might have a
combination of Paid and Free subscriptions. When a group
with a Free subscription exceeds the user limit, their namespace becomes [read-only](../user/read_only_namespaces.md).
If you have multiple groups in your organization, they might have a
combination of paid (Premium or Ultimate tier) and Free tier subscriptions.
When a group with a Free tier subscription exceeds the user limit, their
namespace becomes [read-only](../user/read_only_namespaces.md).
To avoid user limits on groups with Free subscriptions, you can
include them in your organization's subscription. To check if a group is included in the subscription,
[view the group's subscription details](../subscriptions/gitlab_com/index.md#view-your-gitlabcom-subscription).
If the group is on the Free tier, it is not included in your organization's subscription.
To remove user limits on groups with Free tier subscriptions, include those groups
in your organization's subscription:
To include the group in your Paid subscription, [transfer the group](../user/group/manage.md#transfer-a-group) to your organization's
top-level namespace.
1. To check if a group is included in the subscription,
[view that group's subscription details](../subscriptions/gitlab_com/index.md#view-your-gitlabcom-subscription).
NOTE:
If you previously purchased a subscription and the 5-user limit was applied to a group,
ensure that [your subscription is linked](../subscriptions/gitlab_com/index.md#change-the-linked-group)
to the correct top-level namespace, or that it has been
linked to your Customers Portal account.
If the group has a Free tier subscription, it is not included in your organization's
subscription.
### Impact on seat count by transferred groups
1. To include a group in your paid Premium or Ultimate tier subscription,
[transfer that group](../user/group/manage.md#transfer-a-group) to your
organization's top-level namespace.
When you transfer a group, there might be an increase in your seat count,
which could incur additional costs for your subscription.
If the five-user limit has been applied to your group even though you have
a paid subscription in the Premium or Ultimate tier, make sure that
[your subscription is linked](../subscriptions/gitlab_com/index.md#change-the-linked-group)
to either of the following:
For example, a company has Group A and Group B:
- The correct top-level namespace.
- Your [Customers Portal](../subscriptions/customers_portal.md) account.
- Group A is on a Paid tier and has five users.
- Group B is on the Free tier and has eight users, four of which are members of Group A.
- Group B is placed in a read-only state when it exceeds the user limit.
- Group B is transferred to the company's subscription to remove the read-only state.
- The company incurs an additional cost of four seats for the
### Impact of transferred groups on subscription costs
When you transfer a group to your organization's subscription, this might
increase your seat count. This could incur additional costs for your subscription.
For example, your company has Group A and Group B:
- Group A has a paid Premium or Ultimate tier subscription and has five users.
- Group B has a Free tier subscription and has eight users, four of which are
members of Group A.
- Group B is a read-only state because it exceeds the five-user limit.
- You transfer Group B to your company's subscription to remove the read-only state.
- Your company incurs an additional cost of four seats for the
four members of Group B that are not members of Group A.
Users that are not part of the top-level namespace require additional seats to remain active. For more information, see [Add seats to your subscription](../subscriptions/gitlab_com/index.md#add-seats-to-your-subscription).
Users that are not part of the top-level namespace require additional seats to
remain active. For more information, see
[add seats to your subscription](../subscriptions/gitlab_com/index.md#add-seats-to-your-subscription).
## Increase the five-user limit
On the Free tier on GitLab.com, you cannot increase the limit of five users on top-level groups with private visibility.
On the Free subscription tier on GitLab.com, you cannot increase the limit of five users on
top-level groups with private visibility.
For larger teams, you should upgrade to the Premium or Ultimate tier, which
has no user limits and offers more features to increase team productivity. To experience the
value of Paid features and unlimited users, you should start a [free trial](https://gitlab.com/-/trial_registrations/new?glm_source=docs.gitlab.com/ee/user/free_user_limit.html) for GitLab Ultimate.
For larger teams, you should upgrade to the paid Premium or Ultimate tiers. These tiers
do not limit users and have more features to increase team productivity. For more
information, see:
- [Upgrade your subscription tier on GitLab self-managed](../subscriptions/self_managed/index.md#upgrade-your-subscription-tier).
- [Upgrade your subscription tier on GitLab.com](../subscriptions/gitlab_com/index.md#upgrade-your-gitlabcom-subscription-tier).
To try the paid tiers before deciding to upgrade, start a
[free trial](https://gitlab.com/-/trial_registrations/new?glm_source=docs.gitlab.com/ee/user/free_user_limit.html)
for GitLab Ultimate.
## Manage members in personal projects outside a group namespace

View File

@ -0,0 +1,81 @@
---
stage: AI-powered
group: AI Model Validation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# AI gateway
The [AI gateway](../../architecture/blueprints/ai_gateway/index.md) is a standalone service that gives access to AI-powered GitLab Duo features.
GitLab operates an instance of *AI Gateway* that is used by all GitLab instances, including self-managed, GitLab Dedicated, and GitLab.com via [Cloud Connector](../../development/cloud_connector/index.md).
This page describes where the AI gateway is deployed, and answers questions about region selection, data routing, and data sovereignty.
## Region support
For self-managed and Dedicated customers, the ability to choose the region is planned for future implementation. Currently, the process for region selection is managed internally by GitLab.
Runway, is currently not available to external customers. GitLab is working on expanding support to include self-managed instances in the future (Epic: [Expand Platform Engineering to more runtimes](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/1330)).
[View the available regions](https://gitlab-com.gitlab.io/gl-infra/platform/runway/runwayctl/manifest.schema.html#spec_regions).
For GitLab.com customers, it's important to note that the current routing mechanism is based on the location of the GitLab instance, not the user's location. As GitLab.com is currently single-homed in `us-east1`, requests to the AI gateway are routed to us-east4 in almost all cases. This means that the routing may not always result in the absolute nearest deployment for every user.
GitLab is working on an initiative to bypass the monolith when communicating with the AI Gateway (Epic: [Let the client (IDE) request Code Suggestions](https://gitlab.com/groups/gitlab-org/-/epics/13252)). This effort aims to improve routing efficiency and potentially allow for more user-location-based routing in the future.
### Automatic routing
GitLab leverages Cloudflare and *Google Cloud Platform* (GCP) load balancers to route AI
gateway requests to the nearest available deployment automatically. This routing
mechanism prioritizes low latency and efficient processing of user requests.
You cannot manually control this routing process. The system dynamically selects the optimal region based on factors like network conditions and server load.
### Tracing requests to specific regions
You cannot directly trace your AI requests to specific regions at this time.
If you need assistance with tracing a particular request, GitLab Support can access and
analyze logs that contain Cloudflare headers and instance UUIDs. These logs provide
insights into the routing path and can help identify the region where a request was processed.
## Data sovereignty
It's important to acknowledge the current limitations regarding strict data sovereignty enforcement in our multi-region AI gateway deployment. Currently, we cannot guarantee requests will go to or remain within a particular region and therefore is not a data residency solution.
### Factors that influence data routing
The following factors influence where data is routed.
- **Network latency:** The primary routing mechanism focuses on minimizing latency, meaning data might be processed in a region other than the nearest one if network conditions dictate.
- **Service availability:** In case of regional outages or service disruptions, requests might be automatically rerouted to ensure uninterrupted service.
- **Third-Party dependencies:** The GitLab AI infrastructure relies on third-party model providers, like Google Vertex AI, which have their own data handling practices.
### AI-gateway deployment regions
For the most up-to-date information on AI gateway deployment regions, please refer to the [AI-assist runway configuration file](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/main/.runway/runway.yml?ref_type=heads#L12).
As of the last update (2023-11-21), GitLab deploys the AI gateway in the following regions:
- North America (`us-east4`)
- Europe (`europe-west2`, `europe-west3`, `europe-west9`)
- Asia Pacific (`asia-northeast1`, `asia-northeast3`)
Please note that deployment regions may change frequently. For the most current information, always check the configuration file linked above.
The exact location of the LLM models used by the AI gateway is determined by the third-party model providers. Currently, there is no guarantee that the models reside in the same geographical regions as the AI gateway deployments. This implies that data may flow back to the US or other regions where the model provider operates, even if the AI-gateway processes the initial request in a different region.
### Data Flow and LLM model locations
GitLab is working closely with LLM providers to understand their regional data handling practices fully. Currently, there might be instances where data is transmitted to regions outside the one closest to the user due to the factors mentioned above.
### Future enhancements
GitLab is actively working to let customers specify data residency requirements more granularly in the future. The proposed functionality can provide greater control over data processing locations and help meet specific compliance needs.
## Specific regional questions
### Data routing post-Brexit
The UK's exit from the EU does not directly impact data routing preferences or decisions for AI gateway. Data will continue to be routed to the most optimal region based on performance and availability. Data can still flow freely between the EU and UK.

View File

@ -119,6 +119,7 @@ For use cases and best practices, follow the [GitLab Duo examples documentation]
> - [Introduced](https://gitlab.com/gitlab-org/editor-extensions/gitlab-lsp/-/issues/276) in GitLab VS Code Extension 4.20.0.
> - [Introduced](https://gitlab.com/gitlab-org/editor-extensions/gitlab-jetbrains-plugin/-/issues/462) in GitLab Duo for JetBrains 2.7.0.
> - [Added](https://gitlab.com/gitlab-org/editor-extensions/gitlab.vim/-/merge_requests/152) to the GitLab Neovim plugin on July 16, 2024.
> - Feature flags `advanced_context_resolver` and `code_suggestions_context` [enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161538) in GitLab 17.4.
FLAG:
The availability of this feature is controlled by a feature flag.

View File

@ -54,13 +54,7 @@ to check a commit's signature.
### Verify commits made in the web UI
GitLab signs the commits created using the web UI using SSH.
To verify these commits locally, [follow the steps for SSH](ssh.md#verify-commits-locally)
and add the following public key to the `allowed_signers` file:
`ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIADOCCUoN3Q1UPQqUvp845fKy7haJH17qsSkVXzWXilW`.
```plaintext
noreply@gitlab.com namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIADOCCUoN3Q1UPQqUvp845fKy7haJH17qsSkVXzWXilW
```
To verify these commits locally, use the [Web Commits API](../../../../api/web_commits.md#get-public-signing-key) to get the GitLab public key for signing web commits.
## Troubleshooting

View File

@ -43,7 +43,8 @@ For more information, see the history.
This feature is available for testing, but not ready for production use.
With the Zoekt search API, you can use the [search API](../../api/search.md) for exact code search.
When this feature is disabled, [advanced search](advanced_search.md) or [basic search](index.md) is used instead.
If you want to use [advanced search](advanced_search.md) or basic search instead, see
[specify a search type](index.md#specify-a-search-type).
By default, the Zoekt search API is disabled on GitLab.com to avoid breaking changes.
To request access to this feature, contact GitLab.

View File

@ -21,8 +21,18 @@ For code search, GitLab uses these types in this order:
or when you search against a non-default branch.
This type does not support group or global search.
When exact code search or advanced search is enabled, you can still use
basic search by specifying the `basic_search=true` URL parameter.
## Specify a search type
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161999) in GitLab 17.4.
To specify a search type, set the `search_type` URL parameter as follows:
- `search_type=zoekt` for [exact code search](exact_code_search.md)
- `search_type=advanced` for [advanced search](advanced_search.md)
- `search_type=basic` for basic search
`search_type` replaces the deprecated `basic_search` parameter.
For more information, see [issue 477333](https://gitlab.com/gitlab-org/gitlab/-/issues/477333).
## Global search scopes

View File

@ -360,6 +360,7 @@ module API
mount ::API::UserCounts
mount ::API::UserRunners
mount ::API::VirtualRegistries::Packages::Maven
mount ::API::WebCommits
mount ::API::Wikis
add_open_api_documentation!

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
module API
module Entities
class GroupAssociationDetails < Entities::BasicGroupDetails
expose :parent_id
expose :organization_id
expose :access_levels do |group, options|
group.highest_group_member(options[:current_user])&.access_level
end
expose :visibility, documentation: { type: 'string', example: 'public' }
end
end
end

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
module API
module Entities
class PersonalAccessTokenAssociations < Grape::Entity
expose :groups, using: Entities::GroupAssociationDetails, documentation: { is_array: true }
expose :projects, using: Entities::ProjectAssociationDetails, documentation: { is_array: true }
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
module API
module Entities
class ProjectAssociationDetails < Entities::ProjectIdentity
expose :access_levels do
expose :project_access_level do |project, options|
project.member(options[:current_user])&.access_level
end
expose :group_access_level do |project, options|
project.group.highest_group_member(options[:current_user])&.access_level if project.group
end
end
expose :visibility, documentation: { type: 'string', example: 'public' }
expose :web_url, documentation: { type: 'string', example: 'https://gitlab.example.com/gitlab/gitlab' }
expose :namespace, using: 'API::Entities::NamespaceBasic'
end
end
end

View File

@ -6,6 +6,18 @@ module API
extend ActiveSupport::Concern
extend Grape::API::Helpers
def authorize_create_protected_branch!
authorize!(:create_protected_branch, user_project)
end
def authorize_update_protected_branch!(protected_branch)
authorize!(:update_protected_branch, protected_branch)
end
def authorize_destroy_protected_branch!(protected_branch)
authorize!(:read_protected_branch, protected_branch)
end
params :optional_params_ee do
end
end

View File

@ -4,6 +4,7 @@ module API
class PersonalAccessTokens
class SelfInformation < ::API::Base
include APIGuard
include PaginationParams
feature_category :system_access
@ -16,6 +17,20 @@ module API
before { authenticate! }
helpers do
def load_groups
finder_params = {}
finder_params[:min_access_level] = params[:min_access_level] if params[:min_access_level]
GroupsFinder.new(current_user, finder_params).execute
end
def load_projects
finder_params = {}
finder_params[:min_access_level] = params[:min_access_level] if params[:min_access_level]
ProjectsFinder.new(current_user: current_user, params: finder_params).execute
end
end
resource :personal_access_tokens do
desc "Get single personal access token" do
detail 'Get the details of a personal access token by passing it to the API in a header'
@ -30,6 +45,28 @@ module API
present access_token, with: Entities::PersonalAccessToken
end
desc "Return personal access token associations" do
detail 'Get groups and projects this personal access token can access by passing it to the API in a header'
success code: 200, model: Entities::PersonalAccessToken
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 404, message: 'Not found' }
]
tags %w[personal_access_tokens]
end
params do
optional :min_access_level, type: Integer, values: Gitlab::Access.all_values,
desc: 'Limit by minimum access level of authenticated user'
use :pagination
end
get 'self/associations' do
access_token_associations = {
groups: paginate(load_groups),
projects: paginate(load_projects)
}
present access_token_associations, with: Entities::PersonalAccessTokenAssociations, current_user: current_user
end
desc "Revoke a personal access token" do
detail 'Revoke a personal access token by passing it to the API in a header'
success code: 204
@ -38,7 +75,6 @@ module API
]
tags %w[personal_access_tokens]
end
delete 'self' do
revoke_token(access_token)
end

View File

@ -88,7 +88,7 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
post ':id/protected_branches' do
authorize_admin_project
authorize_create_protected_branch!
protected_branch = user_project.protected_branches.find_by(name: params[:name])
@ -127,10 +127,10 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
patch ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
authorize_admin_project
protected_branch = user_project.protected_branches.find_by!(name: params[:name])
authorize_update_protected_branch!(protected_branch)
declared_params = declared_params(include_missing: false)
api_service = ::ProtectedBranches::ApiService.new(user_project, current_user, declared_params)
protected_branch = api_service.update(protected_branch)
@ -156,10 +156,10 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS, urgency: :low do
authorize_admin_project
protected_branch = user_project.protected_branches.find_by!(name: params[:name])
authorize_destroy_protected_branch!(protected_branch)
destroy_conditionally!(protected_branch) do
destroy_service = ::ProtectedBranches::DestroyService.new(user_project, current_user)
destroy_service.execute(protected_branch)

View File

@ -53,7 +53,6 @@ module API
state: params[:state],
confidential: params[:confidential],
snippets: snippets?,
basic_search: params[:basic_search],
num_context_lines: params[:num_context_lines],
search_type: params[:search_type],
page: params[:page],

57
lib/api/web_commits.rb Normal file
View File

@ -0,0 +1,57 @@
# frozen_string_literal: true
module API
class WebCommits < ::API::Base
GITALY_PUBLIC_KEY_CACHE_KEY = 'gitaly_public_key'
GITALY_UNAVAILABLE = 'The git server, Gitaly, is not available at this time. Please contact your administrator.'
PUBLIC_KEY_NOT_FOUND = 'Public key not found.'
feature_category :source_code_management
before { authenticate_non_get! }
helpers do
def gitaly_server
@gitaly_server ||= Gitaly::Server.new(::Gitlab::GitalyClient.random_storage)
end
def server_signature_public_key
gitaly_server.server_signature_public_key
end
def server_signature_error?
gitaly_server.server_signature_error?
end
def handle_gitaly_unavailable
render_api_error!(GITALY_UNAVAILABLE, :service_unavailable)
end
def handle_public_key_not_found
render_api_error!(PUBLIC_KEY_NOT_FOUND, :not_found)
end
def cache_public_key
Rails.cache.fetch(GITALY_PUBLIC_KEY_CACHE_KEY, expires_in: 1.hour.to_i, skip_nil: true) do
{ public_key: server_signature_public_key }
end
end
end
desc 'Get the public key for web commits' do
detail 'This feature was introduced in GitLab 17.4.'
success code: 200
failure [
{ code: 503, message: GITALY_UNAVAILABLE },
{ code: 404, message: PUBLIC_KEY_NOT_FOUND }
]
end
get 'web_commits/public_key' do
handle_gitaly_unavailable if server_signature_error?
handle_public_key_not_found if server_signature_public_key.empty?
cache_public_key
end
end
end

View File

@ -5,6 +5,8 @@ module Gitaly
SHA_VERSION_REGEX = /\A\d+\.\d+\.\d+-\d+-g([a-f0-9]{8})\z/
DEFAULT_REPLICATION_FACTOR = 1
ServerSignature = Struct.new(:public_key, :error)
class << self
def all
Gitlab.config.repositories.storages.keys.map { |s| Gitaly::Server.new(s) }
@ -58,6 +60,14 @@ module Gitaly
storage_status&.fs_type
end
def server_signature_public_key
server_signature&.public_key
end
def server_signature_error?
!!server_signature.try(:error)
end
def disk_used
disk_statistics_storage_status&.used
end
@ -99,26 +109,30 @@ module Gitaly
Gitlab::GitalyClient.expected_server_version.start_with?(match[1])
end
def server_signature
@server_signature ||= Gitlab::GitalyClient::ServerService.new(@storage).server_signature
rescue GRPC::Unavailable, GRPC::DeadlineExceeded
ServerSignature.new(public_key: nil, error: true)
end
def info
@info ||=
begin
Gitlab::GitalyClient::ServerService.new(@storage).info
rescue GRPC::Unavailable, GRPC::DeadlineExceeded => ex
Gitlab::ErrorTracking.track_exception(ex)
# This will show the server as being out of date
Gitaly::ServerInfoResponse.new(git_version: '', server_version: '', storage_statuses: [])
end
@info ||= wrapper_gitaly_rpc_errors do
Gitlab::GitalyClient::ServerService.new(@storage).info
end
end
def disk_statistics
@disk_statistics ||=
begin
Gitlab::GitalyClient::ServerService.new(@storage).disk_statistics
rescue GRPC::Unavailable, GRPC::DeadlineExceeded => ex
Gitlab::ErrorTracking.track_exception(ex)
# This will show the server as being out of date
Gitaly::ServerInfoResponse.new(git_version: '', server_version: '', storage_statuses: [])
end
@disk_statistics ||= wrapper_gitaly_rpc_errors do
Gitlab::GitalyClient::ServerService.new(@storage).disk_statistics
end
end
def wrapper_gitaly_rpc_errors
yield
rescue GRPC::Unavailable, GRPC::DeadlineExceeded => ex
Gitlab::ErrorTracking.track_exception(ex)
# This will show the server as being out of date
Gitaly::ServerInfoResponse.new(git_version: '', server_version: '', storage_statuses: [])
end
end
end

View File

@ -876,9 +876,9 @@ module Gitlab
end
# peel_tags slows down the request by a factor of 3-4
def list_refs(patterns = [Gitlab::Git::BRANCH_REF_PREFIX], pointing_at_oids: [], peel_tags: false)
def list_refs(...)
wrapped_gitaly_errors do
gitaly_ref_client.list_refs(patterns, pointing_at_oids: pointing_at_oids, peel_tags: peel_tags)
gitaly_ref_client.list_refs(...)
end
end

View File

@ -167,6 +167,7 @@ module Gitlab
{ service: 'gitaly.ServerService', method: 'DiskStatistics' },
{ service: 'gitaly.ServerService', method: 'ReadinessCheck' },
{ service: 'gitaly.ServerService', method: 'ServerInfo' },
{ service: 'gitaly.ServerService', method: 'ServerSignature' },
{ service: 'grpc.health.v1.Health', method: 'Check' }
],
retryPolicy: {

View File

@ -237,7 +237,7 @@ module Gitlab
end
# peel_tags slows down the request by a factor of 3-4
def list_refs(patterns = [Gitlab::Git::BRANCH_REF_PREFIX], pointing_at_oids: [], peel_tags: false)
def list_refs(patterns = [Gitlab::Git::BRANCH_REF_PREFIX], pointing_at_oids: [], peel_tags: false, dynamic_timeout: nil)
request = Gitaly::ListRefsRequest.new(
repository: @gitaly_repo,
patterns: patterns,
@ -245,7 +245,9 @@ module Gitlab
peel_tags: peel_tags
)
response = gitaly_client_call(@storage, :ref_service, :list_refs, request, timeout: GitalyClient.fast_timeout)
timeout = dynamic_timeout || GitalyClient.fast_timeout
response = gitaly_client_call(@storage, :ref_service, :list_refs, request, timeout: timeout)
consume_list_refs_response(response)
end

View File

@ -18,6 +18,10 @@ module Gitlab
GitalyClient.call(@storage, :server_service, :disk_statistics, Gitaly::DiskStatisticsRequest.new, timeout: GitalyClient.fast_timeout)
end
def server_signature
GitalyClient.call(@storage, :server_service, :server_signature, Gitaly::ServerSignatureRequest.new, timeout: GitalyClient.fast_timeout)
end
def storage_info
storage_specific(info)
end

View File

@ -8,8 +8,6 @@ module Gitlab
end
def call(env)
return @app.call(env) unless Feature.enabled?(:controller_static_context, Feature.current_request)
req = ActionDispatch::Request.new(env)
action_name = req.path_parameters[:action]

Some files were not shown because too many files have changed in this diff Show More