Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-03-22 03:10:05 +00:00
parent f2e8d3f288
commit 7a4582e967
141 changed files with 1701 additions and 756 deletions

View File

@ -57,7 +57,7 @@ release-environments-qa:
- .qa-base
timeout: 3h
variables:
QA_SCENARIO: "Test::Instance::Smoke"
QA_SCENARIO: "Test::Instance::Any"
RELEASE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_SHA}"
GITLAB_QA_OPTS: --address "https://gitlab.${ENVIRONMENT}.release.gke.gitlab.net"
GITLAB_INITIAL_ROOT_PASSWORD: "${RELEASE_ENVIRONMENTS_ROOT_PASSWORD}"

View File

@ -1 +1 @@
f68eed8a9d41bfe20840e87c8a9f6cd58db30de3
cb8bec7d843749b73a0fc06f44e6aec25b378d92

View File

@ -376,7 +376,7 @@ gem 'thrift', '>= 0.16.0' # rubocop:todo Gemfile/MissingFeatureCategory
# I18n
gem 'rails-i18n', '~> 7.0', feature_category: :internationalization
gem 'gettext_i18n_rails', '~> 1.11.0', feature_category: :internationalization
gem 'gettext_i18n_rails', '~> 1.12.0', feature_category: :internationalization
gem 'gettext', '~> 3.4', '>= 3.4.9',
require: false,
group: [:development, :test],
@ -419,6 +419,8 @@ group :development do
gem 'ruby-lsp-rails', "~> 0.3.0", feature_category: :tooling
gem 'ruby-lsp-rspec', "~> 0.1.10", require: false, feature_category: :tooling
gem 'gdk-toogle', '~> 0.9', require: 'toogle', feature_category: :tooling
end
group :development, :test do
@ -500,7 +502,7 @@ end
group :test do
gem 'fuubar', '~> 2.2.0' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'rspec-retry', '~> 0.6.2', feature_category: :tooling
gem 'rspec_profiling', '~> 0.0.8', feature_category: :tooling
gem 'rspec_profiling', '~> 0.0.9', feature_category: :tooling
gem 'rspec-benchmark', '~> 0.6.0', feature_category: :tooling
gem 'rspec-parameterized', '~> 1.0', require: false, feature_category: :tooling
gem 'os', '~> 1.1', '>= 1.1.4', feature_category: :tooling

View File

@ -201,10 +201,11 @@
{"name":"fuubar","version":"2.2.0","platform":"ruby","checksum":"9b0263c4074f39c68b37f1e4e69a7d3cfc7523c41bea43601235daa723179b4a"},
{"name":"fuzzyurl","version":"0.9.0","platform":"ruby","checksum":"542efa80f2bcaadbdc402c2f0b572f2e335a1d53e375aecad68bbb3d86860c0f"},
{"name":"gapic-common","version":"0.20.0","platform":"ruby","checksum":"af304704b440f7a2a1e8ce6ecce109a67b79fa173f36f11b513b8a35ce509366"},
{"name":"gdk-toogle","version":"0.9.3","platform":"ruby","checksum":"897f5d3d5d2b2d4a4438c5fb8227f2888d3ad0180353c0d62d0dece2cd22eebf"},
{"name":"gemoji","version":"3.0.1","platform":"ruby","checksum":"80553f2f4932a7a95fb1b3c7c63f7dd937e7c8c610164bbdea28fd06eba5f36d"},
{"name":"get_process_mem","version":"0.2.7","platform":"ruby","checksum":"4afd3c3641dd6a817c09806c7d6d509d8a9984512ac38dea8b917426bbf77eba"},
{"name":"gettext","version":"3.4.9","platform":"ruby","checksum":"292864fe6a15c224cee4125a4a72fab426fdbb280e4cff3cfe44935f549b009a"},
{"name":"gettext_i18n_rails","version":"1.11.0","platform":"ruby","checksum":"e19c7e4a256c500f7f38396dca44a282b9838ae278f57c362993a54964b22bbe"},
{"name":"gettext_i18n_rails","version":"1.12.0","platform":"ruby","checksum":"6ac4817731a9e2ce47e1e83381ac34f9142263bc2911aaaafb2526d2f1afc1be"},
{"name":"git","version":"1.18.0","platform":"ruby","checksum":"c9b80462e4565cd3d7a9ba8440c41d2c52244b17b0dad0bfddb46de70630c465"},
{"name":"gitaly","version":"16.10.0.pre.rc1","platform":"ruby","checksum":"483162f2c271fc78e985ad6b25bd06f69a91a4fabc2ff6f25909db7f69458cdb"},
{"name":"gitlab","version":"4.19.0","platform":"ruby","checksum":"3f645e3e195dbc24f0834fbf83e8ccfb2056d8e9712b01a640aad418a6949679"},
@ -560,7 +561,7 @@
{"name":"rspec-retry","version":"0.6.2","platform":"ruby","checksum":"6101ba23a38809811ae3484acde4ab481c54d846ac66d5037ccb40131a60d858"},
{"name":"rspec-support","version":"3.12.0","platform":"ruby","checksum":"dd4d44b247ff679b95b5607ac5641d197a5f9b1d33f916123cb98fc5f917c58b"},
{"name":"rspec_junit_formatter","version":"0.6.0","platform":"ruby","checksum":"40dde674e6ae4e6cc0ff560da25497677e34fefd2338cc467a8972f602b62b15"},
{"name":"rspec_profiling","version":"0.0.8","platform":"ruby","checksum":"b31ee456811b8914806a9d46b07959877fc319a0515b1c207987d70a1c499445"},
{"name":"rspec_profiling","version":"0.0.9","platform":"ruby","checksum":"6199be2daeaa14bac3d10d704dbb0a8df052cf046332c505603263aea24f7590"},
{"name":"rubocop","version":"1.57.2","platform":"ruby","checksum":"8f679dfe42d7821dc61dafb17d14b1294343157a197b9f8a23720ca17fb9161b"},
{"name":"rubocop-ast","version":"1.29.0","platform":"ruby","checksum":"d1da2ab279a074baefc81758ac430c5768a8da8c7438dd4e5819ce5984d00ba1"},
{"name":"rubocop-capybara","version":"2.19.0","platform":"ruby","checksum":"fa329e0f185be313fa5dabd6056f83a718db7f4a259aa97fc287a40254899ccb"},

View File

@ -669,6 +669,9 @@ GEM
googleapis-common-protos-types (>= 1.3.1, < 2.a)
googleauth (~> 1.0)
grpc (~> 1.36)
gdk-toogle (0.9.3)
haml
rails (>= 7.0.4.2)
gemoji (3.0.1)
get_process_mem (0.2.7)
ffi (~> 1.0)
@ -678,7 +681,7 @@ GEM
prime
racc
text (>= 1.3.0)
gettext_i18n_rails (1.11.0)
gettext_i18n_rails (1.12.0)
fast_gettext (>= 0.9.0)
git (1.18.0)
addressable (~> 2.8)
@ -1471,7 +1474,7 @@ GEM
rspec-support (3.12.0)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rspec_profiling (0.0.8)
rspec_profiling (0.0.9)
activerecord
get_process_mem
rails
@ -1899,8 +1902,9 @@ DEPENDENCIES
fog-local (~> 0.8)
fugit (~> 1.8.1)
fuubar (~> 2.2.0)
gdk-toogle (~> 0.9)
gettext (~> 3.4, >= 3.4.9)
gettext_i18n_rails (~> 1.11.0)
gettext_i18n_rails (~> 1.12.0)
gitaly (~> 16.10.0.pre.rc1)
gitlab-backup-cli!
gitlab-chronic (~> 0.10.5)
@ -2076,7 +2080,7 @@ DEPENDENCIES
rspec-rails (~> 6.1.1)
rspec-retry (~> 0.6.2)
rspec_junit_formatter
rspec_profiling (~> 0.0.8)
rspec_profiling (~> 0.0.9)
rubocop
ruby-fogbugz (~> 0.3.0)
ruby-lsp (~> 0.14.4)

View File

@ -51,7 +51,7 @@ export default {
tokens() {
return [
{
icon: 'clock',
icon: 'milestone',
title: TOKEN_TITLE_MILESTONE,
type: TOKEN_TYPE_MILESTONE,
token: MilestoneToken,

View File

@ -22,7 +22,7 @@ export const initReviewBar = () => {
ReviewBar: () => import('./components/review_bar.vue'),
},
provide: {
newCommentTemplatePath: el.dataset.newCommentTemplatePath,
newCommentTemplatePaths: JSON.parse(el.dataset.newCommentTemplatePaths),
canSummarize: parseBoolean(el.dataset.canSummarize),
},
computed: {

View File

@ -145,7 +145,7 @@ export default {
{
type: TOKEN_TYPE_MILESTONE,
title: TOKEN_TITLE_MILESTONE,
icon: 'clock',
icon: 'milestone',
symbol: '%',
token: MilestoneToken,
unique: true,

View File

@ -1,20 +1,40 @@
<script>
import { GlAvatar, GlAvatarLink, GlBadge } from '@gitlab/ui';
import {
GlAvatar,
GlAvatarLink,
GlBadge,
GlDisclosureDropdown,
GlDisclosureDropdownItem,
GlTooltipDirective,
} from '@gitlab/ui';
import { __ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
import CiIcon from '~/vue_shared/components/ci_icon/ci_icon.vue';
import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
import CiResourceAbout from './ci_resource_about.vue';
import CiResourceHeaderSkeletonLoader from './ci_resource_header_skeleton_loader.vue';
export default {
i18n: {
moreActionsLabel: __('More actions'),
reportAbuse: __('Report abuse to administrator'),
},
components: {
AbuseCategorySelector,
CiIcon,
CiResourceAbout,
CiResourceHeaderSkeletonLoader,
GlAvatar,
GlAvatarLink,
GlDisclosureDropdown,
GlDisclosureDropdownItem,
GlBadge,
},
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['reportAbusePath'],
props: {
isLoadingDetails: {
type: Boolean,
@ -44,7 +64,17 @@ export default {
required: true,
},
},
data() {
return {
isReportAbuseDrawerOpen: false,
};
},
computed: {
authorId() {
return this.hasLatestVersion && this.latestVersion?.author?.state === 'active'
? getIdFromGraphQLId(this.latestVersion?.author?.id)
: 0;
},
entityId() {
return getIdFromGraphQLId(this.resource.id);
},
@ -57,6 +87,9 @@ export default {
latestVersion() {
return this.resource?.versions?.nodes[0] || {};
},
reportedFromUrl() {
return window.location.href;
},
versionBadgeText() {
return this.latestVersion.name;
},
@ -64,45 +97,77 @@ export default {
return cleanLeadingSeparator(this.resource?.webPath);
},
},
methods: {
onAbuseButtonClicked() {
this.toggleReportAbuseDrawer(true);
},
toggleReportAbuseDrawer(isOpen) {
this.isReportAbuseDrawerOpen = isOpen;
},
},
};
</script>
<template>
<div>
<ci-resource-header-skeleton-loader v-if="isLoadingSharedData" class="gl-py-5" />
<div v-else class="gl-display-flex gl-py-5">
<gl-avatar-link :href="resource.webPath">
<gl-avatar
class="gl-mr-4"
:entity-id="entityId"
:entity-name="resource.name"
shape="rect"
:size="64"
:src="resource.icon"
/>
</gl-avatar-link>
<div
class="gl-display-flex gl-flex-direction-column gl-align-items-flex-start gl-justify-content-center"
>
<div class="gl-font-sm gl-text-secondary">
{{ webPath }}
<div v-else class="gl-display-flex gl-justify-content-space-between gl-py-5">
<div class="gl-display-flex">
<gl-avatar-link :href="resource.webPath">
<gl-avatar
class="gl-mr-4"
:entity-id="entityId"
:entity-name="resource.name"
shape="rect"
:size="64"
:src="resource.icon"
/>
</gl-avatar-link>
<div
class="gl-display-flex gl-flex-direction-column gl-align-items-flex-start gl-justify-content-center"
>
<div class="gl-font-sm gl-text-secondary">
{{ webPath }}
</div>
<span class="gl-display-flex">
<div class="gl-font-lg gl-font-weight-bold">{{ resource.name }}</div>
<gl-badge
v-if="hasLatestVersion"
size="sm"
class="gl-ml-3 gl-my-1"
:href="latestVersion.path"
>
{{ versionBadgeText }}
</gl-badge>
</span>
<ci-icon
v-if="hasPipelineStatus"
:status="pipelineStatus"
show-status-text
class="gl-mt-2"
/>
</div>
<span class="gl-display-flex">
<div class="gl-font-lg gl-font-weight-bold">{{ resource.name }}</div>
<gl-badge
v-if="hasLatestVersion"
size="sm"
class="gl-ml-3 gl-my-1"
:href="latestVersion.path"
</div>
<div>
<gl-disclosure-dropdown
v-gl-tooltip
:title="$options.i18n.moreActionsLabel"
:toggle-text="$options.i18n.moreActionsLabel"
text-sr-only
icon="ellipsis_v"
category="tertiary"
placement="right"
class="note-action-button more-actions-toggle"
no-caret
>
<gl-disclosure-dropdown-item
data-testid="report-abuse-button"
@action="onAbuseButtonClicked"
>
{{ versionBadgeText }}
</gl-badge>
</span>
<ci-icon
v-if="hasPipelineStatus"
:status="pipelineStatus"
show-status-text
class="gl-mt-2"
/>
<template #list-item>
{{ $options.i18n.reportAbuse }}
</template>
</gl-disclosure-dropdown-item>
</gl-disclosure-dropdown>
</div>
</div>
<ci-resource-about
@ -120,5 +185,12 @@ export default {
<p v-else class="gl-mt-3">
{{ resource.description }}
</p>
<abuse-category-selector
v-if="hasLatestVersion && isReportAbuseDrawerOpen && reportAbusePath"
:reported-user-id="authorId"
:reported-from-url="reportedFromUrl"
:show-drawer="isReportAbuseDrawerOpen"
@close-drawer="toggleReportAbuseDrawer(false)"
/>
</div>
</template>

View File

@ -21,6 +21,7 @@ fragment CatalogResourceFields on CiCatalogResource {
author {
id
name
state
webUrl
}
}

View File

@ -15,7 +15,7 @@ export const initCatalog = (selector = '#js-ci-cd-catalog') => {
}
const { dataset } = el;
const { ciCatalogPath } = dataset;
const { ciCatalogPath, reportAbusePath } = dataset;
Vue.use(VueApollo);
@ -30,6 +30,7 @@ export const initCatalog = (selector = '#js-ci-cd-catalog') => {
apolloProvider,
provide: {
ciCatalogPath,
reportAbusePath,
},
render(h) {
return h(GlobalCatalog);

View File

@ -21,7 +21,7 @@ export default {
HeaderDivider,
},
inject: {
newCommentTemplatePath: { default: null },
newCommentTemplatePaths: { default: () => [] },
tiptapEditor: { default: null },
contentEditor: { default: null },
},
@ -199,11 +199,11 @@ export default {
:label="__('Add a quick action')"
@execute="trackToolbarControlExecution"
/>
<header-divider v-if="newCommentTemplatePath" />
<header-divider v-if="newCommentTemplatePaths.length" />
</div>
<comment-templates-dropdown
v-if="newCommentTemplatePath"
:new-comment-template-path="newCommentTemplatePath"
v-if="newCommentTemplatePaths.length"
:new-comment-template-paths="newCommentTemplatePaths"
@select="insertSavedReply"
/>
<toolbar-more-dropdown data-testid="more" @execute="trackToolbarControlExecution" />

View File

@ -14,7 +14,7 @@ export default () => {
issuePath,
registerPath,
signInPath,
newCommentTemplatePath,
newCommentTemplatePaths,
} = el.dataset;
const router = createRouter(issuePath);
@ -39,7 +39,7 @@ export default () => {
issueIid,
registerPath,
signInPath,
newCommentTemplatePath,
newCommentTemplatePaths: JSON.parse(newCommentTemplatePaths),
},
mounted() {
performanceMarkAndMeasure({

View File

@ -17,6 +17,7 @@ export default function initDiffsApp(store = notesStore) {
const { dataset } = el;
Vue.use(VueApollo);
const { newCommentTemplatePaths } = dataset;
const vm = new Vue({
el,
@ -27,7 +28,7 @@ export default function initDiffsApp(store = notesStore) {
store,
apolloProvider,
provide: {
newCommentTemplatePath: dataset.newCommentTemplatePath,
newCommentTemplatePaths: newCommentTemplatePaths ? JSON.parse(newCommentTemplatePaths) : [],
},
data() {
return {

View File

@ -43,7 +43,7 @@ export const createTokenKeys = ({ disableReleaseFilter = false } = {}) => {
type: 'string',
param: 'title',
symbol: '%',
icon: 'clock',
icon: 'milestone',
tag: '%milestone',
},
{

View File

@ -52,6 +52,23 @@ export default {
default: '',
},
},
props: {
buttonClass: {
type: String,
required: false,
default: null,
},
variant: {
type: String,
required: false,
default: 'link',
},
text: {
type: String,
required: false,
default: __('Email a new %{name} to this project'),
},
},
data() {
return {
email: this.initialEmail,
@ -90,8 +107,8 @@ export default {
<template>
<div>
<gl-button v-gl-modal="$options.modalId" variant="link"
><gl-sprintf :message="__('Email a new %{name} to this project')"
<gl-button v-gl-modal="$options.modalId" :class="buttonClass" :variant="variant"
><gl-sprintf :message="text"
><template #name>{{ issuableName }}</template></gl-sprintf
></gl-button
>

View File

@ -73,7 +73,7 @@ export default {
</script>
<template>
<div ref="milestoneDetails" class="issue-milestone-details">
<gl-icon :size="16" class="gl-mr-2 flex-shrink-0" name="clock" />
<gl-icon :size="16" class="gl-mr-2 flex-shrink-0" name="milestone" />
<span class="milestone-title gl-display-inline-block gl-text-truncate">{{
milestone.title
}}</span>

View File

@ -258,7 +258,7 @@ export default {
{
type: TOKEN_TYPE_MILESTONE,
title: TOKEN_TITLE_MILESTONE,
icon: 'clock',
icon: 'milestone',
token: MilestoneToken,
fetchMilestones: this.fetchMilestones,
recentSuggestionsStorageKey: 'dashboard-issues-recent-tokens-milestone',

View File

@ -3,8 +3,10 @@ import { GlButton, GlDisclosureDropdown, GlEmptyState, GlLink, GlSprintf } from
import { helpPagePath } from '~/helpers/help_page_helper';
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
import NewResourceDropdown from '~/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue';
import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
import { i18n } from '../constants';
import { hasNewIssueDropdown } from '../has_new_issue_dropdown_mixin';
import EmptyStateWithoutAnyIssuesExperiment from './empty_state_without_any_issues_experiment.vue';
export default {
i18n,
@ -17,6 +19,8 @@ export default {
GlLink,
GlSprintf,
NewResourceDropdown,
GitlabExperiment,
EmptyStateWithoutAnyIssuesExperiment,
},
mixins: [hasNewIssueDropdown()],
inject: [
@ -51,80 +55,102 @@ export default {
required: false,
default: false,
},
showIssuableByEmail: {
type: Boolean,
required: false,
default: false,
},
},
};
</script>
<template>
<div v-if="isSignedIn">
<gl-empty-state
:title="$options.i18n.noIssuesTitle"
:svg-path="emptyStateSvgPath"
:svg-height="150"
data-testid="issuable-empty-state"
>
<template #description>
<gl-link :href="$options.issuesHelpPagePath">
{{ $options.i18n.noIssuesDescription }}
</gl-link>
<p v-if="canCreateProjects">
<strong>{{ $options.i18n.noGroupIssuesSignedInDescription }}</strong>
</p>
</template>
<template #actions>
<gl-button
v-if="canCreateProjects"
:href="newProjectPath"
variant="confirm"
class="gl-mx-2 gl-mb-3"
>
{{ $options.i18n.newProjectLabel }}
</gl-button>
<gl-button
v-if="showNewIssueLink"
:href="newIssuePath"
variant="confirm"
class="gl-mx-2 gl-mb-3"
>
{{ $options.i18n.newIssueLabel }}
</gl-button>
<gl-disclosure-dropdown
v-if="showCsvButtons"
class="gl-mx-2 gl-mb-3"
:toggle-text="$options.i18n.importIssues"
data-testid="import-issues-dropdown"
>
<csv-import-export-buttons
:export-csv-path="exportCsvPathWithQuery"
:issuable-count="currentTabCount"
/>
</gl-disclosure-dropdown>
<new-resource-dropdown
v-if="showNewIssueDropdown"
class="gl-align-self-center gl-mx-2 gl-mb-3"
:query="$options.searchProjectsQuery"
:query-variables="newIssueDropdownQueryVariables"
:extract-projects="extractProjects"
:group-id="groupId"
<gitlab-experiment name="issues_mrs_empty_state">
<template #candidate>
<empty-state-without-any-issues-experiment
:show-csv-buttons="showCsvButtons"
:show-issuable-by-email="showIssuableByEmail"
/>
</template>
</gl-empty-state>
<hr />
<p class="gl-text-center gl-font-weight-bold gl-mb-0">
{{ $options.i18n.jiraIntegrationTitle }}
</p>
<p class="gl-text-center gl-mb-0">
<gl-sprintf :message="$options.i18n.jiraIntegrationMessage">
<template #jiraDocsLink="{ content }">
<gl-link :href="jiraIntegrationPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
<p class="gl-text-center gl-text-secondary">
{{ $options.i18n.jiraIntegrationSecondaryMessage }}
</p>
<template #control>
<div>
<gl-empty-state
:title="$options.i18n.noIssuesTitle"
:svg-path="emptyStateSvgPath"
:svg-height="150"
data-testid="issuable-empty-state"
>
<template #description>
<gl-link :href="$options.issuesHelpPagePath">
{{ $options.i18n.noIssuesDescription }}
</gl-link>
<p v-if="canCreateProjects">
<strong>{{ $options.i18n.noGroupIssuesSignedInDescription }}</strong>
</p>
</template>
<template #actions>
<!-- This component is shared between groups and projects issues list
Now issues_mrs_empty_state experiment is run only for projects page
If this experiment is successful new project buttons from 'control' should be
moved to 'candidate' template to take affect for groups page as well -->
<gl-button
v-if="canCreateProjects"
:href="newProjectPath"
variant="confirm"
class="gl-mx-2 gl-mb-3"
>
{{ $options.i18n.newProjectLabel }}
</gl-button>
<gl-button
v-if="showNewIssueLink"
:href="newIssuePath"
variant="confirm"
class="gl-mx-2 gl-mb-3"
>
{{ $options.i18n.newIssueLabel }}
</gl-button>
<gl-disclosure-dropdown
v-if="showCsvButtons"
class="gl-mx-2 gl-mb-3"
:toggle-text="$options.i18n.importIssues"
data-testid="import-issues-dropdown"
>
<csv-import-export-buttons
:export-csv-path="exportCsvPathWithQuery"
:issuable-count="currentTabCount"
/>
</gl-disclosure-dropdown>
<new-resource-dropdown
v-if="showNewIssueDropdown"
class="gl-align-self-center gl-mx-2 gl-mb-3"
:query="$options.searchProjectsQuery"
:query-variables="newIssueDropdownQueryVariables"
:extract-projects="extractProjects"
:group-id="groupId"
/>
</template>
</gl-empty-state>
<hr />
<p class="gl-text-center gl-font-weight-bold gl-mb-0">
{{ $options.i18n.jiraIntegrationTitle }}
</p>
<p class="gl-text-center gl-mb-0">
<gl-sprintf :message="$options.i18n.jiraIntegrationMessage">
<template #jiraDocsLink="{ content }">
<gl-link :href="jiraIntegrationPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
<p class="gl-text-center gl-text-secondary">
{{ $options.i18n.jiraIntegrationSecondaryMessage }}
</p>
</div>
</template>
</gitlab-experiment>
</div>
<gl-empty-state

View File

@ -0,0 +1,180 @@
<script>
import { GlButton, GlModalDirective, GlIcon } from '@gitlab/ui';
import { TYPE_ISSUE } from '~/issues/constants';
import { helpPagePath } from '~/helpers/help_page_helper';
import IssuableByEmail from '~/issuable/components/issuable_by_email.vue';
import CsvImportModal from '~/issuable/components/csv_import_modal.vue';
import { i18n } from '../constants';
import GlCardEmptyStateExperiment from './gl_card_empty_state_experiment.vue';
export default {
i18n,
issuesHelpPagePath: helpPagePath('user/project/issues/index'),
components: {
GlCardEmptyStateExperiment,
GlButton,
GlIcon,
IssuableByEmail,
CsvImportModal,
},
directives: {
GlModal: GlModalDirective,
},
inject: {
jiraIntegrationPath: {
default: null,
},
newIssuePath: {
default: null,
},
showNewIssueLink: {
default: false,
},
showImportButton: {
default: false,
},
canEdit: {
default: false,
},
projectImportJiraPath: {
default: null,
},
},
props: {
showCsvButtons: {
type: Boolean,
required: false,
default: false,
},
showIssuableByEmail: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
importModalId() {
return `${TYPE_ISSUE}-import-modal`;
},
},
};
</script>
<template>
<div class="gl-text-center gl-empty-state">
<iframe
class="video-container gl-h-auto gl-w-full"
src="https://www.youtube-nocookie.com/embed/-4SGhGpwZDY?si=Ym-29hpY22cgdGdH"
title="Create an Issue - The basics"
frameborder="0"
allow="accelerometer; encrypted-media; gyroscope;"
sandbox="allow-scripts allow-same-origin allow-presentation"
data-testid="create-an-issue-iframe-video"
allowfullscreen
></iframe>
<h1 class="gl-font-size-h-display gl-max-w-75 gl-m-auto gl-pt-8">
{{ $options.i18n.noIssuesTitle }}
</h1>
<p class="gl-max-w-75 gl-m-auto gl-pt-4 gl-pb-5">
{{
__(
'With issues you can discuss the implementation of an idea, track tasks and work status, elaborate on code implementations, and accept feature proposals, questions, support requests, or bug reports.',
)
}}
</p>
<div
class="gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row gl-justify-content-center gl-gap-3"
>
<gl-button
v-if="showNewIssueLink"
:href="newIssuePath"
variant="confirm"
data-testid="empty-state-new-issue-btn"
>
{{ __('Create a new issue') }}
</gl-button>
<issuable-by-email
v-if="showIssuableByEmail"
button-class="gl-w-full"
variant="default"
:text="__('Email a new issue')"
/>
</div>
<div class="gl-display-flex gl-flex-direction-column gl-gap-6 gl-max-w-88 gl-mx-auto gl-pt-9">
<div
class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-justify-content-center gl-gap-6"
>
<gl-card-empty-state-experiment v-if="showCsvButtons && showImportButton" icon="download">
<template #header>
{{ __('Import existing issues') }}
</template>
<template #body>
<csv-import-modal :modal-id="importModalId" />
<div class="gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row gl-gap-3">
<gl-button
v-gl-modal="importModalId"
class="gl-mt-3 gl-ml-0! gl-mb-0!"
data-testid="empty-state-import-csv-btn"
>
{{ __('Import CSV') }}
</gl-button>
<gl-button
v-if="canEdit"
class="gl-mt-3 gl-mb-0!"
:href="projectImportJiraPath"
data-testid="empty-state-import-jira-btn"
>
{{ __('Import from Jira') }}
</gl-button>
</div>
</template>
</gl-card-empty-state-experiment>
<a class="gl-text-decoration-none!" :href="$options.issuesHelpPagePath">
<gl-card-empty-state-experiment
class="gl-h-13 gl-justify-content-center gl-hover-text-blue-600 gl-text-gray-900"
icon="issue-type-issue"
>
<template #header>
{{ __('Learn more about issues') }}
<gl-icon class="gl-display-inline gl-ml-2" name="arrow-right" />
</template>
<template #body>
<span class="gl-text-gray-900">{{ __('Read our documentation') }}</span>
</template>
</gl-card-empty-state-experiment>
</a>
</div>
<div
class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-justify-content-center"
>
<a class="gl-text-decoration-none!" :href="jiraIntegrationPath">
<gl-card-empty-state-experiment
class="gl-h-13 gl-hover-text-blue-600 gl-text-gray-900"
icon="api"
>
<template #header>
{{ __('Enable Jira integration') }}
<gl-icon class="gl-display-inline gl-ml-2" name="arrow-right" />
</template>
<template #body>
<span class="gl-text-gray-900">
{{ __('This feature is only available on paid plans.') }}
</span>
</template>
</gl-card-empty-state-experiment>
</a>
</div>
</div>
</div>
</template>

View File

@ -0,0 +1,34 @@
<script>
import { GlCard, GlIcon } from '@gitlab/ui';
export default {
components: {
GlCard,
GlIcon,
},
props: {
icon: {
type: String,
required: true,
},
},
};
</script>
<template>
<gl-card class="gl-text-left gl-hover-bg-blue-50">
<div class="gl-display-flex gl-gap-4">
<div class="gl-display-flex gl-my-auto gl-bg-blue-100 gl-rounded-full gl-min-w-8 gl-min-h-8">
<gl-icon class="gl-display-flex gl-m-auto gl-text-gray-900" :name="icon" />
</div>
<div class="gl-w-31">
<p class="gl-heading-4 gl-mb-1!">
<slot name="header"></slot>
</p>
<slot name="body"></slot>
</div>
</div>
</gl-card>
</template>

View File

@ -95,7 +95,7 @@ export default {
:title="milestoneDate"
class="gl-font-sm gl-text-gray-500!"
>
<gl-icon name="clock" :size="12" />
<gl-icon name="milestone" :size="12" />
{{ milestone.title }}
</gl-link>
</span>

View File

@ -75,6 +75,7 @@ import NewResourceDropdown from '~/vue_shared/components/new_resource_dropdown/n
import WorkItemDetail from '~/work_items/components/work_item_detail.vue';
import deleteWorkItemMutation from '~/work_items/graphql/delete_work_item.mutation.graphql';
import { WORK_ITEM_TYPE_ENUM_OBJECTIVE } from '~/work_items/constants';
import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
import {
CREATED_DESC,
defaultTypeTokenOptions,
@ -153,6 +154,7 @@ export default {
LocalStorageSync,
WorkItemDetail,
GlLink,
GitlabExperiment,
},
directives: {
GlTooltip: GlTooltipDirective,
@ -403,7 +405,7 @@ export default {
{
type: TOKEN_TYPE_MILESTONE,
title: TOKEN_TITLE_MILESTONE,
icon: 'clock',
icon: 'milestone',
token: MilestoneToken,
recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-milestone`,
shouldSkipSort: true,
@ -1073,8 +1075,13 @@ export default {
:export-csv-path-with-query="exportCsvPathWithQuery"
:show-csv-buttons="showCsvButtons"
:show-new-issue-dropdown="showNewIssueDropdown"
:show-issuable-by-email="showIssuableByEmail"
/>
<issuable-by-email v-if="showIssuableByEmail" class="gl-text-center gl-pt-5 gl-pb-7" />
<gitlab-experiment v-if="showIssuableByEmail" name="issues_mrs_empty_state">
<template #control>
<issuable-by-email class="gl-text-center gl-pt-5 gl-pb-7" />
</template>
</gitlab-experiment>
</div>
</template>

View File

@ -56,7 +56,7 @@ export const assigneeTokenBase = {
export const milestoneTokenBase = {
type: TOKEN_TYPE_MILESTONE,
title: TOKEN_TITLE_MILESTONE,
icon: 'clock',
icon: 'milestone',
token: MilestoneToken,
shouldSkipSort: true,
};

View File

@ -42,7 +42,7 @@ export default () => {
apolloProvider,
provide: {
reportAbusePath: notesDataset.reportAbusePath,
newCommentTemplatePath: notesDataset.newCommentTemplatePath,
newCommentTemplatePaths: JSON.parse(notesDataset.newCommentTemplatePaths),
mrFilter: true,
newCustomEmojiPath: notesDataset.newCustomEmojiPath,
},

View File

@ -59,7 +59,7 @@ export default ({ editorAiActions = [] } = {}) => {
provide: {
showTimelineViewToggle,
reportAbusePath: notesDataset.reportAbusePath,
newCommentTemplatePath: notesDataset.newCommentTemplatePath,
newCommentTemplatePaths: JSON.parse(notesDataset.newCommentTemplatePaths),
resourceGlobalId: convertToGraphQLId(noteableData.noteableType, noteableData.id),
editorAiActions: editorAiActions.map((factory) => factory(noteableData)),
newCustomEmojiPath: notesDataset.newCustomEmojiPath,

View File

@ -29,7 +29,7 @@ export const ICON_MAP = {
merge_requests: 'merge-request',
commits: 'commit',
notes: 'comments',
milestones: 'clock',
milestones: 'milestone',
users: 'users',
projects: 'project',
wiki_blobs: 'book',

View File

@ -272,7 +272,7 @@ function mountSidebarMilestoneWidget() {
iid: issueIid,
issuableType: isInIssuePage() || isInDesignPage() ? TYPE_ISSUE : TYPE_MERGE_REQUEST,
issuableAttribute: IssuableAttributeType.Milestone,
icon: 'clock',
icon: 'milestone',
},
}),
});

View File

@ -42,8 +42,8 @@ export default {
},
mixins: [InternalEvents.mixin()],
props: {
newCommentTemplatePath: {
type: String,
newCommentTemplatePaths: {
type: Array,
required: true,
},
},
@ -147,14 +147,17 @@ export default {
</template>
<template #footer>
<div
class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-200 gl-display-flex gl-justify-content-center gl-p-2"
class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-200 gl-display-flex gl-justify-content-center gl-flex-direction-column gl-p-2"
>
<gl-button
:href="newCommentTemplatePath"
v-for="(manage, index) in newCommentTemplatePaths"
:key="index"
:href="manage.path"
category="tertiary"
block
class="gl-justify-content-start! gl-mt-0! gl-mb-0! gl-px-3!"
>{{ __('Add a new comment template') }}</gl-button
data-testid="manage-button"
>{{ manage.text }}</gl-button
>
</div>
</template>
@ -167,7 +170,7 @@ export default {
<style>
.comment-template-dropdown .gl-new-dropdown-panel {
width: 350px;
width: 350px !important;
}
.comment-template-dropdown .gl-new-dropdown-item-check-icon {

View File

@ -38,8 +38,8 @@ export default {
},
mixins: [glFeatureFlagsMixin()],
inject: {
newCommentTemplatePath: {
default: null,
newCommentTemplatePaths: {
default: () => [],
},
editorAiActions: { default: () => [] },
mrGeneratedContent: { default: null },
@ -512,8 +512,8 @@ export default {
tracking-property="quickAction"
/>
<comment-templates-dropdown
v-if="!previewMarkdown && newCommentTemplatePath"
:new-comment-template-path="newCommentTemplatePath"
v-if="!previewMarkdown && newCommentTemplatePaths.length"
:new-comment-template-paths="newCommentTemplatePaths"
@select="insertSavedReply"
/>
</div>

View File

@ -25,7 +25,7 @@ export const initWorkItemsRoot = ({ workItemType, workspaceType } = {}) => {
hasIterationsFeature,
hasOkrsFeature,
hasIssuableHealthStatusFeature,
newCommentTemplatePath,
newCommentTemplatePaths,
reportAbusePath,
} = el.dataset;
@ -46,7 +46,7 @@ export const initWorkItemsRoot = ({ workItemType, workspaceType } = {}) => {
signInPath,
hasIterationsFeature: parseBoolean(hasIterationsFeature),
hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature),
newCommentTemplatePath,
newCommentTemplatePaths: JSON.parse(newCommentTemplatePaths),
reportAbusePath,
},
render(createElement) {

View File

@ -106,3 +106,10 @@
}
}
}
.gl-empty-state {
.video-container {
aspect-ratio: 16/9;
max-width: 350px;
}
}

View File

@ -38,9 +38,10 @@ class Admin::GroupsController < Admin::ApplicationController
end
def create
@group = ::Groups::CreateService.new(current_user, group_params).execute
response = ::Groups::CreateService.new(current_user, group_params).execute
@group = response[:group]
if @group.persisted?
if response.success?
redirect_to [:admin, @group], notice: format(_('Group %{group_name} was successfully created.'), group_name: @group.name)
else
render "new"

View File

@ -85,9 +85,10 @@ class GroupsController < Groups::ApplicationController
end
def create
@group = Groups::CreateService.new(current_user, group_params).execute
response = Groups::CreateService.new(current_user, group_params).execute
@group = response[:group]
if @group.persisted?
if response.success?
successful_creation_hooks
notice = if @group.chat_team.present?

View File

@ -18,9 +18,10 @@ class Import::GitlabGroupsController < ApplicationController
import_export_upload: ImportExportUpload.new(import_file: group_params[:file])
)
group = ::Groups::CreateService.new(current_user, group_data).execute
response = ::Groups::CreateService.new(current_user, group_data).execute
group = response[:group]
if group.persisted?
if response.success?
if Groups::ImportExport::ImportService.new(group: group, user: current_user).async_execute
redirect_to(
group_path(group),

View File

@ -26,8 +26,6 @@ class SessionsController < Devise::SessionsController
prepend_before_action :check_captcha, only: [:create]
prepend_before_action :store_redirect_uri, only: [:new]
prepend_before_action :require_no_authentication_without_flash, only: [:new, :create]
prepend_before_action :ensure_user_allowed_to_password_authenticate,
if: -> { action_name == 'create' && password_based_login? }
prepend_before_action :ensure_password_authentication_enabled!,
if: -> { action_name == 'create' && password_based_login? }
before_action :auto_sign_in_with_provider, only: [:new]
@ -316,13 +314,6 @@ class SessionsController < Devise::SessionsController
def set_invite_params
@invite_email = ActionController::Base.helpers.sanitize(params[:invite_email])
end
def ensure_user_allowed_to_password_authenticate
return unless find_user
return if find_user.allow_password_authentication_for_web? && !find_user.password_based_login_forbidden?
redirect_to new_user_session_path, alert: I18n.t('devise.failure.invalid')
end
end
SessionsController.prepend_mod_with('SessionsController')

View File

@ -417,6 +417,13 @@ module IssuablesHelper
}
}
end
def new_comment_template_paths(group)
[{
text: _('Manage your comment templates'),
path: profile_comment_templates_path
}]
end
end
IssuablesHelper.prepend_mod_with('IssuablesHelper')

View File

@ -198,7 +198,7 @@ module MergeRequestsHelper
source_project_default_url: merge_request.source_project && default_url_to_repo(merge_request.source_project),
source_project_full_path: merge_request.source_project&.full_path,
is_forked: project.forked?.to_s,
new_comment_template_path: profile_comment_templates_path,
new_comment_template_paths: new_comment_template_paths(project.group).to_json,
iid: merge_request.iid,
per_page: DIFF_BATCH_ENDPOINT_PER_PAGE,
pinned_file_url: @pinned_file_url
@ -315,7 +315,7 @@ module MergeRequestsHelper
end
def review_bar_data(_merge_request, _user)
{ new_comment_template_path: profile_comment_templates_path }
{ new_comment_template_paths: new_comment_template_paths(@project.group).to_json }
end
def project_merge_requests_list_data(project, current_user)

View File

@ -21,7 +21,7 @@ module SystemNoteHelper
'branch' => 'fork',
'confidential' => 'eye-slash',
'visible' => 'eye',
'milestone' => 'clock',
'milestone' => 'milestone',
'discussion' => 'comment',
'moved' => 'arrow-right',
'outdated' => 'pencil',

View File

@ -2,13 +2,15 @@
module WorkItemsHelper
def work_items_show_data(resource_parent)
group = resource_parent.is_a?(Group) ? resource_parent : resource_parent.group
{
full_path: resource_parent.full_path,
issues_list_path:
resource_parent.is_a?(Group) ? issues_group_path(resource_parent) : project_issues_path(resource_parent),
register_path: new_user_registration_path(redirect_to_referer: 'yes'),
sign_in_path: new_session_path(:user, redirect_to_referer: 'yes'),
new_comment_template_path: profile_comment_templates_path,
new_comment_template_paths: new_comment_template_paths(group).to_json,
report_abuse_path: add_category_abuse_reports_path
}
end

View File

@ -31,6 +31,7 @@ class Commit
MIN_SHA_LENGTH = Gitlab::Git::Commit::MIN_SHA_LENGTH
MAX_SHA_LENGTH = Gitlab::Git::Commit::MAX_SHA_LENGTH
COMMIT_SHA_PATTERN = Gitlab::Git::Commit::SHA_PATTERN
WHOLE_WORD_COMMIT_SHA_PATTERN = /\b#{COMMIT_SHA_PATTERN}\b/
EXACT_COMMIT_SHA_PATTERN = /\A#{COMMIT_SHA_PATTERN}\z/
# Used by GFM to match and present link extensions on node texts and hrefs.
LINK_EXTENSION_PATTERN = /(patch)/
@ -205,7 +206,7 @@ class Commit
def self.reference_pattern
@reference_pattern ||= %r{
(?:#{Project.reference_pattern}#{reference_prefix})?
(?<commit>#{COMMIT_SHA_PATTERN})
(?<commit>#{WHOLE_WORD_COMMIT_SHA_PATTERN})
}x
end

View File

@ -1058,6 +1058,7 @@ class User < MainClusterwide::ApplicationRecord
def valid_password?(password)
return false unless password_allowed?(password)
return false if password_automatically_set?
return false unless allow_password_authentication?
super
end

View File

@ -2,6 +2,9 @@
module Groups
class CreateService < Groups::BaseService
VisibilityError = Class.new(StandardError)
PermissionError = Class.new(StandardError)
def initialize(user, params = {})
@current_user = user
@params = params.dup
@ -10,6 +13,43 @@ module Groups
end
def execute
build_group
after_build_hook
validate_visibility_level!
validate_user_permissions!
@group.name ||= @group.path.dup
create_chat_team
create_group
if @group.persisted?
after_successful_creation_hook
ServiceResponse.success(payload: { group: @group })
else
ServiceResponse.error(message: 'Group has errors', payload: { group: @group })
end
rescue VisibilityError, PermissionError
ServiceResponse.error(message: 'Group has errors', payload: { group: @group })
end
private
attr_reader :create_event
def create_chat_team
return unless valid_to_create_chat_team?
response = ::Mattermost::CreateTeamService.new(@group, current_user).execute
return ServiceResponse.error(message: 'Group has errors', payload: { group: @group }) if @group.errors.any?
@group.build_chat_team(name: response['name'], team_id: response['id'])
end
def build_group
remove_unallowed_params
set_visibility_level
@ -19,24 +59,9 @@ module Groups
@group.build_namespace_settings
handle_namespace_settings
end
after_build_hook(@group, params)
inherit_group_shared_runners_settings
unless can_use_visibility_level? && can_create_group?
return @group
end
@group.name ||= @group.path.dup
if create_chat_team?
response = ::Mattermost::CreateTeamService.new(@group, current_user).execute
return @group if @group.errors.any?
@group.build_chat_team(name: response['name'], team_id: response['id'])
end
def create_group
Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
%w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424281'
) do
@ -47,21 +72,13 @@ module Groups
end
end
end
after_create_hook
@group
end
private
attr_reader :create_event
def after_build_hook(group, params)
# overridden in EE
def after_build_hook
inherit_group_shared_runners_settings
end
def after_create_hook
def after_successful_creation_hook
# overridden in EE
end
@ -76,35 +93,33 @@ module Groups
params.delete(:lock_math_rendering_limits_enabled)
end
def create_chat_team?
Gitlab.config.mattermost.enabled && @chat_team && group.chat_team.nil?
def valid_to_create_chat_team?
Gitlab.config.mattermost.enabled && @chat_team && @group.chat_team.nil?
end
def can_create_group?
def validate_user_permissions!
if @group.subgroup?
unless can?(current_user, :create_subgroup, @group.parent)
@group.parent = nil
@group.errors.add(:parent_id, s_('CreateGroup|You dont have permission to create a subgroup in this group.'))
return false
raise PermissionError
end
else
unless can?(current_user, :create_group)
@group.errors.add(:base, s_('CreateGroup|You dont have permission to create groups.'))
return false
raise PermissionError
end
end
unless organization_setting_valid?
# We are unsetting this here to match behavior of invalid parent_id above and protect against possible
# committing to the database of a value that isn't allowed.
@group.organization = nil
return if organization_setting_valid?
return false
end
# We are unsetting this here to match behavior of invalid parent_id above and protect against possible
# committing to the database of a value that isn't allowed.
@group.organization = nil
true
raise PermissionError
end
def can_create_group_in_organization?
@ -143,13 +158,12 @@ module Groups
can_create_group_in_organization? && matches_parent_organization?
end
def can_use_visibility_level?
unless Gitlab::VisibilityLevel.allowed_for?(current_user, visibility_level)
deny_visibility_level(@group)
return false
end
def validate_visibility_level!
return if Gitlab::VisibilityLevel.allowed_for?(current_user, visibility_level)
true
deny_visibility_level(@group)
raise VisibilityError, 'Visibility level not allowed'
end
def set_visibility_level

View File

@ -41,7 +41,7 @@ module Groups
)
last_group = namespace_or_group(partial_path) ||
Groups::CreateService.new(current_user, new_params).execute
Groups::CreateService.new(current_user, new_params).execute[:group]
end
last_group

View File

@ -1,3 +1,3 @@
- page_title _('CI/CD Catalog')
#js-ci-cd-catalog{ data: { ci_catalog_path: explore_catalog_index_path } }
#js-ci-cd-catalog{ data: { ci_catalog_path: explore_catalog_index_path, report_abuse_path: add_category_abuse_reports_path } }

View File

@ -27,7 +27,7 @@
%span.issuable-milestone.gl-display-none.gl-sm-display-inline-block
&nbsp;
= link_to project_issues_path(issue.project, milestone_title: issue.milestone.title), data: { html: 'true', toggle: 'tooltip', title: milestone_tooltip_due_date(issue.milestone) } do
= sprite_icon('clock', css_class: 'gl-vertical-align-text-bottom')
= sprite_icon('milestone', css_class: 'gl-vertical-align-text-bottom')
= issue.milestone.title
- if issue.due_date
%span.issuable-due-date.gl-display-none.gl-sm-display-inline-block.has-tooltip{ class: "#{'cred' if issue.overdue? && !issue.closed?}", title: _('Due date') }

View File

@ -13,7 +13,7 @@
issue_path: project_issue_path(@project, @issue),
register_path: new_user_registration_path(redirect_to_referer: 'yes'),
sign_in_path: new_session_path(:user, redirect_to_referer: 'yes'),
new_comment_template_path: profile_comment_templates_path } }
new_comment_template_paths: new_comment_template_paths(@project.group).to_json } }
- else
.gl-border-solid.gl-border-1.gl-border-gray-100.gl-rounded-base.gl-mt-5.gl-p-3.gl-text-center
= enable_lfs_message

View File

@ -13,5 +13,5 @@
current_user_data: UserSerializer.new.represent(current_user, {only_path: true}, CurrentUserEntity).to_json,
can_add_timeline_events: "#{can?(current_user, :admin_incident_management_timeline_event, @issue)}",
report_abuse_path: add_category_abuse_reports_path,
new_comment_template_path: profile_comment_templates_path,
new_comment_template_paths: new_comment_template_paths(@project.group).to_json,
new_custom_emoji_path: new_custom_emoji_path(@project.group) } }

View File

@ -29,7 +29,7 @@
%span.issuable-milestone.gl-display-none.gl-sm-display-inline-block.gl-text-truncate.gl-max-w-26.gl-vertical-align-bottom
&nbsp;
= link_to project_merge_requests_path(merge_request.project, milestone_title: merge_request.milestone.title), class: 'gl-text-gray-500!', data: { html: 'true', toggle: 'tooltip', title: milestone_tooltip_due_date(merge_request.milestone) } do
= sprite_icon('clock', size: 12, css_class: 'gl-vertical-align-text-bottom')
= sprite_icon('milestone', size: 12, css_class: 'gl-vertical-align-text-bottom')
= merge_request.milestone.title
- if merge_request.target_project.default_branch != merge_request.target_branch
%span.project-ref-path.has-tooltip.d-inline-block.gl-text-truncate.gl-max-w-26.gl-vertical-align-bottom{ title: _('Target branch: %{target_branch}') % {target_branch: merge_request.target_branch} }

View File

@ -83,7 +83,7 @@
current_user_data: @current_user_data,
is_locked: @merge_request.discussion_locked.to_s,
report_abuse_path: add_category_abuse_reports_path,
new_comment_template_path: profile_comment_templates_path,
new_comment_template_paths: new_comment_template_paths(@project.group).to_json,
new_custom_emoji_path: new_custom_emoji_path(@project.group) } }
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees, reviewers: @merge_request.reviewers, source_branch: @merge_request.source_branch

View File

@ -18,9 +18,8 @@
= sprite_icon('comments', css_class: 'gl-vertical-align-text-bottom')
= notes_count
%li
%span.sr-only{ data: { testid: 'snippet-visibility-content', qa_snippet_visibility: visibility_level_label(snippet.visibility_level) } }
= visibility_level_label(snippet.visibility_level)
= visibility_level_icon(snippet.visibility_level)
%span.has-tooltip{ title: visibility_level_label(snippet.visibility_level), data: { testid: 'snippet-visibility-content', qa_snippet_visibility: visibility_level_label(snippet.visibility_level) } }
= visibility_level_icon(snippet.visibility_level)
.snippet-info
.gl-display-inline{ data: { testid: 'snippet-created-at'} }

View File

@ -1,9 +0,0 @@
---
name: ci_fix_input_types
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/434826
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/145257
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/443301
milestone: '16.10'
group: group::pipeline authoring
type: gitlab_com_derisk
default_enabled: false

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_load_performance
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_accessibility_mo
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_failfast_monthly
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_browser_performa
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_browser_performa
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_security_secure_binarie
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: static_analysis
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_load_performance_t
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_secret_detection_m
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: static_analysis
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_browser_performanc
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_browser_performanc
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_load_perf
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: removed
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_browser_p
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_browser_p
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: removed
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_security_secur
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: static_analysis
value_type: number
status: removed
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_qualys_iac_security_mon
description: ""
product_section: ""
product_stage: ""
product_group: ""
product_group: static_analysis
value_type: number
status: active
milestone: "14.7"

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_load_performance
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_accessibility_we
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_failfast_weekly
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_browser_performa
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_verify_browser_performa
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_security_secure_binarie
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: static_analysis
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_load_performance_t
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_secret_detection_w
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: static_analysis
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_browser_performanc
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_browser_performanc
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_load_perf
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: removed
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_browser_p
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: active
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_browser_p
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: pipeline_execution
value_type: number
status: removed
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_security_secur
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_group: static_analysis
value_type: number
status: removed
milestone: '14.3'

View File

@ -3,7 +3,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_qualys_iac_security_wee
description: ""
product_section: ""
product_stage: ""
product_group: ""
product_group: static_analysis
value_type: number
status: active
milestone: "14.7"

View File

@ -13,4 +13,5 @@ if Rails.env.development?
mount LetterOpenerWeb::Engine, at: '/rails/letter_opener'
mount Lookbook::Engine, at: '/rails/lookbook'
mount Toogle::Engine, at: '/rails/features'
end

View File

@ -0,0 +1,83 @@
- name: Semantic versioning in the CI/CD catalog
description: |
To enforce consistent behavior across published components, in GitLab 16.10 we will enforce Semantic versioning for components that are published to the CI/CD catalog. When publishing a component, the tag must follow the 3-digit semantic versioning standard (for example `1.0.0`).
When using a component with the `include: component` syntax, you should use the published semantic version (`x`, `x.x`. or `x.x.x`). Using `~latest` continues to be supported, but it will always return the latest published version, so you must use it with caution as it could include breaking changes. Shorthand syntax is not supported, but it will be in an upcoming milestone.
stage: verify
self-managed: true
gitlab-com: true
available_in: [Free, Premium, Ultimate]
documentation_link: https://docs.gitlab.com/ee/ci/components/#component-versions
image_url: https://release-16-10.about.gitlab-review.app/images/16_10/component.png
published_at: 2024-03-21
release: 16.10
- name: Offload CI traffic to Geo secondaries
description: |
You can now offload CI runner traffic to Geo secondary sites. Locate runner fleets where they are more convenient and economical to operate and manage, while reducing cross-region traffic. Distribute the load across multiple secondary Geo sites. Reduce load on the primary site, reserving resources for serving developer traffic. After this setup, the developer experience is transparent and seamless. Developer workflows for the setup and configuration of jobs remain unchanged.
stage: systems
self-managed: true
gitlab-com: false
available_in: [Premium, Ultimate]
documentation_link: https://docs.gitlab.com/ee/administration/geo/secondary_proxy/runners.html
image_url: https://release-16-10.about.gitlab-review.app/images/16_10/systems_geo_runner_acceleration.png
published_at: 2024-03-21
release: 16.10
- name: Wiki templates
description: |
This version of GitLab introduces all-new templates to the Wiki. Now, you can create templates to streamline creating new pages or modifying existing ones. Templates are wiki pages that are stored in the templates directory in the wiki repository.
With this enhancement, you can make your wiki page layouts more consistent, create or restructure pages faster, and ensure that information is presented clearly and coherently in your knowledge base.
stage: plan
self-managed: true
gitlab-com: true
available_in: [Free, Premium, Ultimate]
documentation_link: https://docs.gitlab.com/ee/user/project/wiki/index.html#wiki-page-templates
image_url: https://release-16-10.about.gitlab-review.app/images/16_10/wiki_templates.gif
published_at: 2024-03-21
release: 16.10
- name: New ClickHouse integration for high-performance DevOps Analytics
description: |
The [Contribution Analytics report](https://docs.gitlab.com/ee/user/group/contribution_analytics/) is now more performant and backed by an advanced analytics database using [ClickHouse](https://docs.gitlab.com/ee/architecture/blueprints/clickhouse_usage/#summary) on GitLab.com. This upgrade set the foundation for new extensive analytics and reporting features, allowing us to deliver high-performance analytics aggregations, filtering, and slicing across multiple dimensions. Support for self-managed customers to be able to add to this capability is proposed in [issue 441626](https://gitlab.com/gitlab-org/gitlab/-/issues/441626).
Although ClickHouse enhances GitLab's analytics capabilities, it's not meant to replace PostgreSQL or Redis, and the existing capabilities remain unchanged.
stage: plan
self-managed: false
gitlab-com: true
available_in: [Ultimate]
documentation_link: https://docs.gitlab.com/ee/user/group/contribution_analytics/
image_url: https://release-16-10.about.gitlab-review.app/images/16_10/ca_ch16.10_2.png
published_at: 2024-03-21
release: 16.10
- name: GitLab Duo access governance control
description: |
Generative AI is revolutionizing work processes, and you can now facilitate the adoption of these technologies without compromising privacy, compliance, or intellectual property (IP) protections.
You can now disable GitLab Duo AI features for a project, a group, or an instance by using the API. You can then enable GitLab Duo for specific projects or groups when you're ready. These changes are part of a suite of expected work to make AI features more granular to control.
stage: ai-powered
self-managed: true
gitlab-com: true
available_in: [Premium, Ultimate]
documentation_link: https://docs.gitlab.com/ee/user/ai_features.html#disable-gitlab-duo-features
image_url: https://release-16-10.about.gitlab-review.app/images/16_10/Turn-off-GitLab-Duo-features.png
published_at: 2024-03-21
release: 16.10
- name: GitLab Pages and Advanced Search available on GitLab Dedicated
description: |
[GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/) and [Advanced Search](https://docs.gitlab.com/ee/user/search/advanced_search.html) have been enabled for all [GitLab Dedicated instances](https://about.gitlab.com/dedicated/). These features are included in your GitLab Dedicated subscription.
Advanced Search enables faster, more efficient search across your entire GitLab Dedicated instance. All capabilities of Advanced Search can be used with GitLab Dedicated instances.
With GitLab Pages, you can publish static websites directly from a repository in GitLab Dedicated. Some capabilities of Pages are [not yet available](https://docs.gitlab.com/ee/subscriptions/gitlab_dedicated/#gitlab-pages) for GitLab Dedicated instances.
stage: platforms
self-managed: false
gitlab-com: true
available_in: [Ultimate]
documentation_link: https://docs.gitlab.com/ee/subscriptions/gitlab_dedicated/#available-features
image_url: https://release-16-10.about.gitlab-review.app/images/16_10/gitlab-dedicated.png
published_at: 2024-03-21
release: 16.10

View File

@ -82,4 +82,4 @@ The metrics server cannot serve both HTTP and HTTPS at the same time.
When running [GitLab in Docker](../../../install/docker.md), your container might run out of space. This can happen if you enable certain features which increase your space consumption, for example Web Exporter.
To work around this issue, [update your `shm-size`](../../../install/docker.md#devshm-mount-not-having-enough-space-in-docker-container).
To work around this issue, [update your `shm-size`](../../../install/docker_troubleshooting.md#devshm-mount-not-having-enough-space-in-docker-container).

View File

@ -2676,15 +2676,57 @@ Get a single merge request diff version.
GET /projects/:id/merge_requests/:merge_request_iid/versions/:version_id
```
Supported attributes:
| Attribute | Type | Required | Description |
|---------------------|---------|----------|-------------------------------------------|
| `id` | String | Yes | The ID of the project. |
| `merge_request_iid` | integer | Yes | The internal ID of the merge request. |
| `version_id` | integer | Yes | The ID of the merge request diff version. |
| `id` | String | Yes | ID of the project. |
| `merge_request_iid` | integer | Yes | Internal ID of the merge request. |
| `version_id` | integer | Yes | ID of the merge request diff version. |
| `unidiff` | boolean | No | Present diffs in the [unified diff](https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html) format. Default is false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130610) in GitLab 16.5. |
For an explanation of the SHAs in the response,
see [SHAs in the API response](#shas-in-the-api-response).
If successful, returns [`200 OK`](rest/index.md#status-codes) and the following
response attributes:
| Attribute | Type | Description |
|-------------------------------|--------------|-------------|
| `id` | integer | ID of the merge request diff version. |
| `base_commit_sha` | string | Merge-base commit SHA between the source branch and the target branches. |
| `commits` | object array | Commits in the merge request diff. |
| `commits[].id` | string | ID of the commit. |
| `commits[].short_id` | string | Short ID of the commit. |
| `commits[].created_at` | datetime | Identical to the `committed_date` field. |
| `commits[].parent_ids` | array | IDs of the parent commits. |
| `commits[].title` | string | Commit title. |
| `commits[].message` | string | Commit message. |
| `commits[].author_name` | string | Commit author's name. |
| `commits[].author_email` | string | Commit author's email address. |
| `commits[].authored_date` | datetime | Commit authored date. |
| `commits[].committer_name` | string | Committer's name. |
| `commits[].committer_email` | string | Committer's email address. |
| `commits[].committed_date` | datetime | Commit date. |
| `commits[].trailers` | object | Git trailers that were parsed for the commit. Duplicate keys include the last value only. |
| `commits[].extended_trailers` | object | Git trailers that were parsed for the commit. |
| `commits[].web_url` | string | Web URL of the merge request. |
| `created_at` | datetime | Timestamp of when the merge request was created. |
| `diffs` | object array | Diffs in the merge request diff version. |
| `diffs[].diff` | string | Content of the diff. |
| `diffs[].new_path` | string | New path of the file. |
| `diffs[].old_path` | string | Old path of the file. |
| `diffs[].a_mode` | string | Old file mode of the file. |
| `diffs[].b_mode` | string | New file mode of the file. |
| `diffs[].new_file` | boolean | Indicates if the file has just been added. |
| `diffs[].renamed_file` | boolean | Indicates if the file has been renamed. |
| `diffs[].deleted_file` | boolean | Indicates if the file has been removed. |
| `diffs[].generated_file` | boolean | Indicates if the file is [marked as generated](../user/project/merge_requests/changes.md#collapse-generated-files). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141576) in GitLab 16.9. |
| `head_commit_sha` | string | HEAD commit of the source branch. |
| `merge_request_id` | integer | ID of the merge request. |
| `patch_id_sha` | string | [Patch ID](https://git-scm.com/docs/git-patch-id) for the merge request diff. |
| `real_size` | string | Number of changes in the merge request diff. |
| `start_commit_sha` | string | HEAD commit SHA of the target branch when this version of the diff was created. |
| `state` | string | State of the merge request diff. Can be `collected`, `overflow`, `without_files`. Deprecated values: `timeout`, `overflow_commits_safe_size`, `overflow_diff_files_limit`, `overflow_diff_lines_limit`. |
Example request:
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" \
@ -2707,27 +2749,51 @@ Example response:
"commits": [{
"id": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
"short_id": "33e2ee85",
"parent_ids": [],
"title": "Change year to 2018",
"author_name": "Administrator",
"author_email": "admin@example.com",
"authored_date": "2016-07-26T17:44:29.000+03:00",
"committer_name": "Administrator",
"committer_email": "admin@example.com",
"committed_date": "2016-07-26T17:44:29.000+03:00",
"created_at": "2016-07-26T17:44:29.000+03:00",
"message": "Change year to 2018"
"message": "Change year to 2018",
"trailers": {},
"extended_trailers": {},
"web_url": "https://gitlab.example.com/project/-/commit/33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30"
}, {
"id": "aa24655de48b36335556ac8a3cd8bb521f977cbd",
"short_id": "aa24655d",
"parent_ids": [],
"title": "Update LICENSE",
"author_name": "Administrator",
"author_email": "admin@example.com",
"authored_date": "2016-07-25T17:21:53.000+03:00",
"committer_name": "Administrator",
"committer_email": "admin@example.com",
"committed_date": "2016-07-25T17:21:53.000+03:00",
"created_at": "2016-07-25T17:21:53.000+03:00",
"message": "Update LICENSE"
"message": "Update LICENSE",
"trailers": {},
"extended_trailers": {},
"web_url": "https://gitlab.example.com/project/-/commit/aa24655de48b36335556ac8a3cd8bb521f977cbd"
}, {
"id": "3eed087b29835c48015768f839d76e5ea8f07a24",
"short_id": "3eed087b",
"parent_ids": [],
"title": "Add license",
"author_name": "Administrator",
"author_email": "admin@example.com",
"authored_date": "2016-07-25T17:21:20.000+03:00",
"committer_name": "Administrator",
"committer_email": "admin@example.com",
"committed_date": "2016-07-25T17:21:20.000+03:00",
"created_at": "2016-07-25T17:21:20.000+03:00",
"message": "Add license"
"message": "Add license",
"trailers": {},
"extended_trailers": {},
"web_url": "https://gitlab.example.com/project/-/commit/3eed087b29835c48015768f839d76e5ea8f07a24"
}],
"diffs": [{
"old_path": "LICENSE",
@ -2737,7 +2803,8 @@ Example response:
"diff": "@@ -0,0 +1,21 @@\n+The MIT License (MIT)\n+\n+Copyright (c) 2018 Administrator\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n",
"new_file": true,
"renamed_file": false,
"deleted_file": false
"deleted_file": false,
"generated_file": false
}]
}
```

View File

@ -513,7 +513,7 @@ When using CI/CD variables in a component, evaluate if the `inputs` keyword
should be used instead. Avoid asking users to define custom variables to configure
components when `inputs` is a better solution.
Inputs are explicitly defined in the component's specs, and have better validation than variables.
Inputs are explicitly defined in the component's `spec` section, and have better validation than variables.
For example, if a required input is not passed to the component, GitLab returns a pipeline error.
By contrast, if a variable is not defined, its value is empty, and there is no error.

View File

@ -19,9 +19,11 @@ For example, as part of a migration from [Jenkins](../migration/jenkins.md) or [
When authenticating with the API, you can use:
- A [pipeline trigger token](#create-a-pipeline-trigger-token) to trigger a branch or tag pipeline.
- A [pipeline trigger token](#create-a-pipeline-trigger-token) to trigger a branch or tag pipeline
with the [pipeline triggers API endpoint](../../api/pipeline_triggers.md).
- A [CI/CD job token](../jobs/ci_job_token.md) to [trigger a multi-project pipeline](../pipelines/downstream_pipelines.md#trigger-a-multi-project-pipeline-by-using-the-api).
- A [personal access token](../../user/profile/personal_access_tokens.md).
- Another [token with API access](../../security/token_overview.md) to create a new pipeline
with the [project pipeline API endpoint](../../api/pipelines.md#create-a-new-pipeline).
## Create a pipeline trigger token
@ -57,7 +59,7 @@ pipelines with a tool that can access the API, or a webhook.
### Use cURL
You can use cURL to trigger pipelines with the [pipeline trigger token API endpoint](../../api/pipeline_triggers.md).
You can use cURL to trigger pipelines with the [pipeline triggers API endpoint](../../api/pipeline_triggers.md).
For example:
- Use a multiline cURL command:

View File

@ -824,7 +824,7 @@ Use the interpolation format `$[[ input.input-id ]]` to reference the values out
Inputs are evaluated and interpolated when the configuration is fetched during pipeline creation, but before the
configuration is merged with the contents of the `.gitlab-ci.yml` file.
**Keyword type**: Header keyword. `specs` must be declared at the top of the configuration file,
**Keyword type**: Header keyword. `spec` must be declared at the top of the configuration file,
in a header section.
**Possible inputs**: A hash of strings representing the expected inputs.
@ -864,7 +864,7 @@ Inputs are mandatory when included, unless you set a default value with `spec:in
Use `default: ''` to have no default value.
**Keyword type**: Header keyword. `specs` must be declared at the top of the configuration file,
**Keyword type**: Header keyword. `spec` must be declared at the top of the configuration file,
in a header section.
**Possible inputs**: A string representing the default value, or `''`.
@ -906,7 +906,7 @@ Use `description` to give a description to a specific input. The description doe
not affect the behavior of the input and is only used to help users of the file
understand the input.
**Keyword type**: Header keyword. `specs` must be declared at the top of the configuration file,
**Keyword type**: Header keyword. `spec` must be declared at the top of the configuration file,
in a header section.
**Possible inputs**: A string representing the description.
@ -930,7 +930,7 @@ spec:
Inputs can use `options` to specify a list of allowed values for an input.
The limit is 50 options per input.
**Keyword type**: Header keyword. `specs` must be declared at the top of the configuration file,
**Keyword type**: Header keyword. `spec` must be declared at the top of the configuration file,
in a header section.
**Possible inputs**: An array of input options.
@ -968,7 +968,7 @@ In this example:
Use `spec:inputs:regex` to specify a regular expression that the input must match.
**Keyword type**: Header keyword. `specs` must be declared at the top of the configuration file,
**Keyword type**: Header keyword. `spec` must be declared at the top of the configuration file,
in a header section.
**Possible inputs**: Must be a regular expression that starts and ends with the `/` character.
@ -998,7 +998,7 @@ An input of `v1.A.B` does not match the regular expression and fails validation.
By default, inputs expect strings. Use `spec:inputs:type` to set a different required
type for inputs.
**Keyword type**: Header keyword. `specs` must be declared at the top of the configuration file,
**Keyword type**: Header keyword. `spec` must be declared at the top of the configuration file,
in a header section.
**Possible inputs**: Can be one of:
@ -4348,20 +4348,20 @@ build-prod:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script: echo "Default branch, so building prod version..."
specs:
tests:
stage: test
needs: ['build-dev']
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
needs: ['build-prod']
- when: on_success # Run the job in other cases
script: echo "Running dev specs by default, or prod specs when default branch..."
script: echo "Running tests for dev by default, or prod when default branch..."
```
In this example:
- If the pipeline runs on a branch that is not the default branch, the `specs` job needs the `build-dev` job (default behavior).
- If the pipeline runs on the default branch, and therefore the rule matches the condition, the `specs` job needs the `build-prod` job instead.
- If the pipeline runs on a branch that is not the default branch, the `tests` job needs the `build-dev` job (default behavior).
- If the pipeline runs on the default branch, and therefore the rule matches the condition, the `tests` job needs the `build-prod` job instead.
**Additional details**:

View File

@ -133,73 +133,25 @@ For information on testing migrations, review our
NOTE:
You must have `AllFeaturesUser` [`psql` access](#access-database-lab-engine) to access the console with `psql`.
#### Simplified access through `pgai` Ruby gem
To access the database lab instances, you must:
[@mbobin](https://gitlab.com/mbobin) created the [`pgai` Ruby Gem](https://gitlab.com/mbobin/pgai/#pgai) that
greatly simplifies access to a database clone, with support for:
- File an [access request](https://handbook.gitlab.com/handbook/business-technology/end-user-services/onboarding-access-requests/access-requests/#individual-or-bulk-access-request).
- Have a user data bag entry in [chef-repo](https://gitlab.com/gitlab-com/gl-infra/chef-repo) with your SSH key and the `db-lab` role.
- Configure `ssh` as follows:
- Access to all database clones listed in the [Postgres.ai instances page](https://console.postgres.ai/gitlab/instances);
- Multiple `psql` sessions on the same clone.
```plaintext
Host lb-bastion.db-lab.gitlab.com
User ${USER}
IdentitiesOnly yes
IdentityFile ~/.ssh/ed25519
If you have `AllFeaturesUser` [`psql` access](#access-database-lab-engine), you can follow the steps below to configure
the `pgai` Gem:
1. To get started, you need to gather some values from the [Postgres.ai instances page](https://console.postgres.ai/gitlab/instances):
1. Go to the instance that you want to configure and the on right side of the screen.
1. Under **Connection**, select **Connect**. The menu might be collapsed.
A dialog with everything that's needed for configuration appears, using this format:
```shell
dblab init --url "http://127.0.0.1:1234" --token TOKEN --environment-id <environment-id>
```
```shell
ssh -NTML 1234:localhost:<environment-port> <postgresai-user>@<postgresai-proxy> -i ~/.ssh/id_rsa
```
1. Add the following snippet to your SSH configuration file at `~/.ssh/config`, replacing the variable values:
```plaintext
Host pgai-proxy
HostName <postgresai-proxy>
User <postgresai-user>
IdentityFile ~/.ssh/id_ed25519
```
1. Run the following command so you can accept the server key fingerprint:
```shell
ssh pgai-proxy
```
1. Run the following commands:
```shell
gem install pgai
# Grab an access token: https://console.postgres.ai/gitlab/tokens
# GITLAB_USER is your GitLab handle
pgai config --dbname=gitlabhq_dblab --prefix=$GITLAB_USER --proxy=pgai-proxy
# Grab the respective port values from https://console.postgres.ai/gitlab/instances
# for the instances you'll be using (in this case, for the `main` database instance)
pgai env add --alias main --id <environment-id> --port <environment-port>
```
1. Once this one-time configuration is done, you can use `pgai connect` to connect to a particular database. For
instance, to connect to the `main` database:
```shell
pgai connect main
```
1. Once done with the clone, you can destroy it:
```shell
pgai destroy main
```
Host *.gitlab-db-lab.internal
User ${USER}
PreferredAuthentications publickey
IdentitiesOnly yes
IdentityFile ~/.ssh/ed25519
ProxyCommand ssh lb-bastion.db-lab.gitlab.com -W %h:%p
```
#### Manual access through the Postgres.ai instances page
@ -211,7 +163,7 @@ To connect to a clone using `psql`:
1. Create a clone from the [desired instance](https://console.postgres.ai/gitlab/instances/).
1. Provide a **Clone ID**: Something that uniquely identifies your clone, such as `yourname-testing-gitlabissue`.
1. Provide a **Database username** and **Database password**: Connects `psql` to your clone.
1. Select **Enable deletion protection** if you want to preserve your clone. Avoid selecting this option.
1. Select **Enable deletion protection** if you need to preserve your clone. Avoid selecting this option.
Clones are removed after 12 hours.
1. In the **Clone details** page of the Postgres.ai web interface, copy and run
the command to start SSH port forwarding for the clone.
@ -220,3 +172,10 @@ To connect to a clone using `psql`:
After you connect, use clone like you would any `psql` console in production, but with
the added benefit and safety of an isolated writeable environment.
#### Simplified access through `pgai` Ruby gem
WARNING:
The `pgai` gem has not yet been updated to use the new database lab instances so you will only be able to access the legacy instance using this tool.
For instructions on using the `pgai` Ruby gem, see: [Database Lab access using the pgai Ruby gem](database_lab_pgai.md).

View File

@ -0,0 +1,76 @@
---
stage: Data Stores
group: Database
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
---
# Database Lab access using the `pgai` Ruby gem
WARNING:
The `pgai` gem has not yet been updated to use the new database lab instances so you will only be able to access `gitlab-production-main` and `gitlab-production-ci` using this tool.
[@mbobin](https://gitlab.com/mbobin) created the [`pgai` Ruby Gem](https://gitlab.com/mbobin/pgai/#pgai) that
greatly simplifies access to a database clone, with support for:
- Access to all database clones listed in the [Postgres.ai instances page](https://console.postgres.ai/gitlab/instances);
- Multiple `psql` sessions on the same clone.
If you have `AllFeaturesUser` [`psql` access](database_lab.md#access-database-lab-engine),
you can follow the steps below to configure the `pgai` Gem:
1. To get started, you need to gather some values from the [Postgres.ai instances page](https://console.postgres.ai/gitlab/instances):
1. Go to the instance that you want to configure and the on right side of the screen.
1. Under **Connection**, select **Connect**. The menu might be collapsed.
A dialog with everything that's needed for configuration appears, using this format:
```shell
dblab init --url "http://127.0.0.1:1234" --token TOKEN --environment-id <environment-id>
```
```shell
ssh -NTML 1234:localhost:<environment-port> <postgresai-user>@<postgresai-proxy> -i ~/.ssh/id_rsa
```
1. Add the following snippet to your SSH configuration file at `~/.ssh/config`, replacing the variable values:
```plaintext
Host pgai-proxy
HostName <postgresai-proxy>
User <postgresai-user>
IdentityFile ~/.ssh/id_ed25519
```
1. Run the following command so you can accept the server key fingerprint:
```shell
ssh pgai-proxy
```
1. Run the following commands:
```shell
gem install pgai
# Grab an access token: https://console.postgres.ai/gitlab/tokens
# GITLAB_USER is your GitLab handle
pgai config --dbname=gitlabhq_dblab --prefix=$GITLAB_USER --proxy=pgai-proxy
# Grab the respective port values from https://console.postgres.ai/gitlab/instances
# for the instances you'll be using (in this case, for the `main` database instance)
pgai env add --alias main --id <environment-id> --port <environment-port>
```
1. Once this one-time configuration is done, you can use `pgai connect` to connect to a particular database. For
instance, to connect to the `main` database:
```shell
pgai connect main
```
1. Once done with the clone, you can destroy it:
```shell
pgai destroy main
```

View File

@ -4,7 +4,7 @@ group: Distribution
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
---
# Install GitLab using Docker
# Install GitLab by using Docker
DETAILS:
**Tier:** Free, Premium, Ultimate
@ -700,150 +700,3 @@ docker exec -t <container name> gitlab-backup create SKIP=artifacts,repositories
The backup is written to `/var/opt/gitlab/backups` which should be on a
[volume mounted by Docker](#set-up-the-volumes-location).
## Troubleshooting
The following information will help if you encounter problems with an installation that used the Linux package and Docker.
### Diagnose potential problems
Read container logs:
```shell
sudo docker logs gitlab
```
Enter running container:
```shell
sudo docker exec -it gitlab /bin/bash
```
From within the container you can administer the GitLab container as you would
usually administer a [Linux package installation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md).
### 500 Internal Error
When updating the Docker image you may encounter an issue where all paths
display a `500` page. If this occurs, restart the container to try to rectify the
issue:
```shell
sudo docker restart gitlab
```
### Permission problems
When updating from older GitLab Docker images you might encounter permission
problems. This happens when users in previous images were not
preserved correctly. There's script that fixes permissions for all files.
To fix your container, execute `update-permissions` and restart the
container afterwards:
```shell
sudo docker exec gitlab update-permissions
sudo docker restart gitlab
```
### Windows/Mac: `Error executing action run on resource ruby_block[directory resource: /data/GitLab]`
This error occurs when using Docker Toolbox with VirtualBox on Windows or Mac,
and making use of Docker volumes. The `/c/Users` volume is mounted as a
VirtualBox Shared Folder, and does not support the all POSIX file system features.
The directory ownership and permissions cannot be changed without remounting, and
GitLab fails.
Our recommendation is to switch to using the native Docker install for your
platform, instead of using Docker Toolbox.
If you cannot use the native Docker install (Windows 10 Home Edition, or Windows 7/8),
then an alternative solution is to setup NFS mounts instead of VirtualBox shares for
Docker Toolbox's boot2docker.
### Linux ACL issues
If you are using file ACLs on the Docker host, the `docker` group requires full access to the volumes in order for GitLab to work:
```shell
getfacl $GITLAB_HOME
# file: $GITLAB_HOME
# owner: XXXX
# group: XXXX
user::rwx
group::rwx
group:docker:rwx
mask::rwx
default:user::rwx
default:group::rwx
default:group:docker:rwx
default:mask::rwx
default:other::r-x
```
If these are not correct, set them with:
```shell
sudo setfacl -mR default:group:docker:rwx $GITLAB_HOME
```
The default group is `docker`. If you changed the group, be sure to update your
commands.
### `/dev/shm` mount not having enough space in Docker container
GitLab comes with a Prometheus metrics endpoint at `/-/metrics` to expose a
variety of statistics on the health and performance of GitLab. The files
required for this gets written to a temporary file system (like `/run` or
`/dev/shm`).
By default, Docker allocates 64 MB to the shared memory directory (mounted at
`/dev/shm`). This is insufficient to hold all the Prometheus metrics related
files generated, and will generate error logs like the following:
```plaintext
writing value to /dev/shm/gitlab/sidekiq/gauge_all_sidekiq_0-1.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/gauge_all_sidekiq_0-1.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/gauge_all_sidekiq_0-1.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/histogram_sidekiq_0-0.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/histogram_sidekiq_0-0.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/histogram_sidekiq_0-0.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/histogram_sidekiq_0-0.db failed with unmapped file
```
Other than disabling the Prometheus Metrics from the Admin Area, the recommended
solution to fix this problem is to increase the size of shared memory to at least 256 MB.
If using `docker run`, this can be done by passing the flag `--shm-size 256m`.
If using a `docker-compose.yml` file, the `shm_size` key can be used for this
purpose.
### Docker containers exhausts space due to the `json-file`
Docker uses the [`json-file` default logging driver](https://docs.docker.com/config/containers/logging/configure/#configure-the-default-logging-driver), which performs no log rotation by default. As a result of this lack of rotation, log files stored by the `json-file` driver can consume a significant amount of disk space for containers that generate a lot of output. This can lead to disk space exhaustion. To address this, use [`journald`](https://docs.docker.com/config/containers/logging/journald/) as the logging driver when available, or [another supported driver](https://docs.docker.com/config/containers/logging/configure/#supported-logging-drivers) with native rotation support.
### Buffer overflow error when starting Docker
If you receive this buffer overflow error, you should purge old log files in
`/var/log/gitlab`:
```plaintext
buffer overflow detected : terminated
xargs: tail: terminated by signal 6
```
Removing old log files helps fix the error, and ensures a clean startup of the instance.
### ThreadError can't create Thread Operation not permitted
```plaintext
can't create Thread: Operation not permitted
```
This error occurs when running a container built with newer `glibc` versions on a
[host that doesn't have support for the new clone3 function](https://github.com/moby/moby/issues/42680). In GitLab 16.0 and later, the container image includes
the Ubuntu 22.04 Linux package which is built with this newer `glibc`.
This problem is fixed with newer container runtime tools like [Docker 20.10.10](https://github.com/moby/moby/pull/42836).
To resolve this issue, update Docker to version 20.10.10 or later.

View File

@ -0,0 +1,156 @@
---
stage: Systems
group: Distribution
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
---
# Troubleshooting GitLab installations that use Docker
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed
When installing GitLab by using Docker, you might encounter the following issues.
## Diagnose potential problems
Read container logs:
```shell
sudo docker logs gitlab
```
Enter running container:
```shell
sudo docker exec -it gitlab /bin/bash
```
From within the container you can administer the GitLab container as you would
usually administer a [Linux package installation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md).
## 500 Internal Error
When updating the Docker image you may encounter an issue where all paths
display a `500` page. If this occurs, restart the container to try to rectify the
issue:
```shell
sudo docker restart gitlab
```
## Permission problems
When updating from older GitLab Docker images you might encounter permission
problems. This happens when users in previous images were not
preserved correctly. There's script that fixes permissions for all files.
To fix your container, execute `update-permissions` and restart the
container afterwards:
```shell
sudo docker exec gitlab update-permissions
sudo docker restart gitlab
```
## Windows/Mac: `Error executing action run on resource ruby_block[directory resource: /data/GitLab]`
This error occurs when using Docker Toolbox with VirtualBox on Windows or Mac,
and making use of Docker volumes. The `/c/Users` volume is mounted as a
VirtualBox Shared Folder, and does not support the all POSIX file system features.
The directory ownership and permissions cannot be changed without remounting, and
GitLab fails.
Our recommendation is to switch to using the native Docker install for your
platform, instead of using Docker Toolbox.
If you cannot use the native Docker install (Windows 10 Home Edition, or Windows 7/8),
then an alternative solution is to setup NFS mounts instead of VirtualBox shares for
Docker Toolbox's boot2docker.
## Linux ACL issues
If you are using file ACLs on the Docker host, the `docker` group requires full access to the volumes in order for GitLab to work:
```shell
getfacl $GITLAB_HOME
# file: $GITLAB_HOME
# owner: XXXX
# group: XXXX
user::rwx
group::rwx
group:docker:rwx
mask::rwx
default:user::rwx
default:group::rwx
default:group:docker:rwx
default:mask::rwx
default:other::r-x
```
If these are not correct, set them with:
```shell
sudo setfacl -mR default:group:docker:rwx $GITLAB_HOME
```
The default group is `docker`. If you changed the group, be sure to update your
commands.
## `/dev/shm` mount not having enough space in Docker container
GitLab comes with a Prometheus metrics endpoint at `/-/metrics` to expose a
variety of statistics on the health and performance of GitLab. The files
required for this gets written to a temporary file system (like `/run` or
`/dev/shm`).
By default, Docker allocates 64 MB to the shared memory directory (mounted at
`/dev/shm`). This is insufficient to hold all the Prometheus metrics related
files generated, and will generate error logs like the following:
```plaintext
writing value to /dev/shm/gitlab/sidekiq/gauge_all_sidekiq_0-1.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/gauge_all_sidekiq_0-1.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/gauge_all_sidekiq_0-1.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/histogram_sidekiq_0-0.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/histogram_sidekiq_0-0.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/histogram_sidekiq_0-0.db failed with unmapped file
writing value to /dev/shm/gitlab/sidekiq/histogram_sidekiq_0-0.db failed with unmapped file
```
Other than disabling the Prometheus Metrics from the Admin Area, the recommended
solution to fix this problem is to increase the size of shared memory to at least 256 MB.
If using `docker run`, this can be done by passing the flag `--shm-size 256m`.
If using a `docker-compose.yml` file, the `shm_size` key can be used for this
purpose.
## Docker containers exhausts space due to the `json-file`
Docker uses the [`json-file` default logging driver](https://docs.docker.com/config/containers/logging/configure/#configure-the-default-logging-driver), which performs no log rotation by default. As a result of this lack of rotation, log files stored by the `json-file` driver can consume a significant amount of disk space for containers that generate a lot of output. This can lead to disk space exhaustion. To address this, use [`journald`](https://docs.docker.com/config/containers/logging/journald/) as the logging driver when available, or [another supported driver](https://docs.docker.com/config/containers/logging/configure/#supported-logging-drivers) with native rotation support.
## Buffer overflow error when starting Docker
If you receive this buffer overflow error, you should purge old log files in
`/var/log/gitlab`:
```plaintext
buffer overflow detected : terminated
xargs: tail: terminated by signal 6
```
Removing old log files helps fix the error, and ensures a clean startup of the instance.
## ThreadError can't create Thread Operation not permitted
```plaintext
can't create Thread: Operation not permitted
```
This error occurs when running a container built with newer `glibc` versions on a
[host that doesn't have support for the new clone3 function](https://github.com/moby/moby/issues/42680). In GitLab 16.0 and later, the container image includes
the Ubuntu 22.04 Linux package which is built with this newer `glibc`.
This problem is fixed with newer container runtime tools like [Docker 20.10.10](https://github.com/moby/moby/pull/42836).
To resolve this issue, update Docker to version 20.10.10 or later.

View File

@ -376,122 +376,3 @@ When you create a keytab with Advanced Encryption Standard (AES)-only encryption
1. Right-click the account and select **Properties**.
1. In **Account Options** on the **Account** tab, select the appropriate AES encryption support checkbox.
1. Save and close.
## Troubleshooting
### Using Google Chrome with Kerberos authentication against Windows AD
When you use Google Chrome to sign in to GitLab with Kerberos, you must enter your full username. For example, `username@domain.com`.
If you do not enter your full username, the sign-in fails. Check the logs to see the following event message as evidence of this sign-in failure:
```plain
"message":"OmniauthKerberosController: failed to process Negotiate/Kerberos authentication: gss_accept_sec_context did not return GSS_S_COMPLETE: An unsupported mechanism was requested\nUnknown error"`.
```
### Test connectivity between the GitLab and Kerberos servers
You can use utilities like [`kinit`](https://web.mit.edu/kerberos/krb5-1.12/doc/user/user_commands/kinit.html) and [`klist`](https://web.mit.edu/kerberos/krb5-1.12/doc/user/user_commands/klist.html) to test connectivity between the GitLab server
and the Kerberos server. How you install these depends on your specific OS.
Use `klist` to see the service principal names (SPN) available in your `keytab` file and the encryption type for each SPN:
```shell
klist -ke /etc/http.keytab
```
On an Ubuntu server, the output would look similar to the following:
```shell
Keytab name: FILE:/etc/http.keytab
KVNO Principal
---- --------------------------------------------------------------------------
3 HTTP/my.gitlab.domain@MY.REALM (des-cbc-crc)
3 HTTP/my.gitlab.domain@MY.REALM (des-cbc-md5)
3 HTTP/my.gitlab.domain@MY.REALM (arcfour-hmac)
3 HTTP/my.gitlab.domain@MY.REALM (aes256-cts-hmac-sha1-96)
3 HTTP/my.gitlab.domain@MY.REALM (aes128-cts-hmac-sha1-96)
```
Use `kinit` in verbose mode to test whether GitLab can use the keytab file to connect to the Kerberos server:
```shell
KRB5_TRACE=/dev/stdout kinit -kt /etc/http.keytab HTTP/my.gitlab.domain@MY.REALM
```
This command shows a detailed output of the authentication process.
### Unsupported GSSAPI mechanism
With Kerberos SPNEGO authentication, the browser is expected to send a list of
mechanisms it supports to GitLab. If it doesn't support any of the mechanisms
GitLab supports, authentication fails with a message like this in the log:
```plaintext
OmniauthKerberosController: failed to process Negotiate/Kerberos authentication: gss_accept_sec_context did not return GSS_S_COMPLETE: An unsupported mechanism was requested Unknown error
```
There are a number of potential causes and solutions for this error message.
#### Kerberos integration not using a dedicated port
GitLab CI/CD doesn't work with a Kerberos-enabled GitLab instance unless the Kerberos integration
is configured to [use a dedicated port](kerberos.md#http-git-access-with-kerberos-token-passwordless-authentication).
#### Lack of connectivity between client machine and Kerberos server
This is usually seen when the browser is unable to contact the Kerberos server
directly. It falls back to an unsupported mechanism known as
[`IAKERB`](https://k5wiki.kerberos.org/wiki/Projects/IAKERB), which tries to use
the GitLab server as an intermediary to the Kerberos server.
If you're experiencing this error, ensure there is connectivity between the
client machine and the Kerberos server - this is a prerequisite! Traffic may be
blocked by a firewall, or the DNS records may be incorrect.
#### `GitLab DNS record is a CNAME record` error
Kerberos fails with this error when GitLab is referenced with a `CNAME` record.
To resolve this issue, ensure the DNS record for GitLab is an `A` record.
#### Mismatched forward and reverse DNS records for GitLab instance hostname
Another failure mode occurs when the forward and reverse DNS records for the
GitLab server do not match. Often, Windows clients work in this case while
Linux clients fail. They use reverse DNS while detecting the Kerberos
realm. If they get the wrong realm then ordinary Kerberos mechanisms fail,
so the client falls back to attempting to negotiate `IAKERB`, leading to the
above error message.
To fix this, ensure that the forward and reverse DNS for your GitLab server
match. So for instance, if you access GitLab as `gitlab.example.com`, resolving
to IP address `10.0.2.2`, then `2.2.0.10.in-addr.arpa` must be a `PTR` record for
`gitlab.example.com`.
#### Missing Kerberos libraries on browser or client machine
Finally, it's possible that the browser or client machine lack Kerberos support
completely. Ensure that the Kerberos libraries are installed and that you can
authenticate to other Kerberos services.
### HTTP Basic: Access denied when cloning
```shell
remote: HTTP Basic: Access denied
fatal: Authentication failed for '<KRB5 path>'
```
If you are using Git v2.11 or newer and see the above error when cloning, you can
set the `http.emptyAuth` Git option to `true` to fix this:
```shell
git config --global http.emptyAuth true
```
See also: [Git v2.11 release notes](https://github.com/git/git/blob/master/Documentation/RelNotes/2.11.0.txt#L482-L486)
## Helpful links
- <https://help.ubuntu.com/community/Kerberos>
- <https://blog.manula.org/2012/04/setting-up-kerberos-server-with-debian.html>
- <https://www.roguelynn.com/words/explain-like-im-5-kerberos/>

View File

@ -0,0 +1,130 @@
---
stage: Govern
group: Authentication
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"
---
# Troubleshooting GitLab with Kerberos integration
DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed
When working with GitLab with Kerberos integration, you might encounter the following issues.
## Using Google Chrome with Kerberos authentication against Windows AD
When you use Google Chrome to sign in to GitLab with Kerberos, you must enter your full username. For example, `username@domain.com`.
If you do not enter your full username, the sign-in fails. Check the logs to see the following event message as evidence of this sign-in failure:
```plain
"message":"OmniauthKerberosController: failed to process Negotiate/Kerberos authentication: gss_accept_sec_context did not return GSS_S_COMPLETE: An unsupported mechanism was requested\nUnknown error"`.
```
## Test connectivity between the GitLab and Kerberos servers
You can use utilities like [`kinit`](https://web.mit.edu/kerberos/krb5-1.12/doc/user/user_commands/kinit.html) and [`klist`](https://web.mit.edu/kerberos/krb5-1.12/doc/user/user_commands/klist.html) to test connectivity between the GitLab server
and the Kerberos server. How you install these depends on your specific OS.
Use `klist` to see the service principal names (SPN) available in your `keytab` file and the encryption type for each SPN:
```shell
klist -ke /etc/http.keytab
```
On an Ubuntu server, the output would look similar to the following:
```shell
Keytab name: FILE:/etc/http.keytab
KVNO Principal
---- --------------------------------------------------------------------------
3 HTTP/my.gitlab.domain@MY.REALM (des-cbc-crc)
3 HTTP/my.gitlab.domain@MY.REALM (des-cbc-md5)
3 HTTP/my.gitlab.domain@MY.REALM (arcfour-hmac)
3 HTTP/my.gitlab.domain@MY.REALM (aes256-cts-hmac-sha1-96)
3 HTTP/my.gitlab.domain@MY.REALM (aes128-cts-hmac-sha1-96)
```
Use `kinit` in verbose mode to test whether GitLab can use the keytab file to connect to the Kerberos server:
```shell
KRB5_TRACE=/dev/stdout kinit -kt /etc/http.keytab HTTP/my.gitlab.domain@MY.REALM
```
This command shows a detailed output of the authentication process.
## Unsupported GSSAPI mechanism
With Kerberos SPNEGO authentication, the browser is expected to send a list of
mechanisms it supports to GitLab. If it doesn't support any of the mechanisms
GitLab supports, authentication fails with a message like this in the log:
```plaintext
OmniauthKerberosController: failed to process Negotiate/Kerberos authentication: gss_accept_sec_context did not return GSS_S_COMPLETE: An unsupported mechanism was requested Unknown error
```
There are a number of potential causes and solutions for this error message.
### Kerberos integration not using a dedicated port
GitLab CI/CD doesn't work with a Kerberos-enabled GitLab instance unless the Kerberos integration
is configured to [use a dedicated port](kerberos.md#http-git-access-with-kerberos-token-passwordless-authentication).
### Lack of connectivity between client machine and Kerberos server
This is usually seen when the browser is unable to contact the Kerberos server
directly. It falls back to an unsupported mechanism known as
[`IAKERB`](https://k5wiki.kerberos.org/wiki/Projects/IAKERB), which tries to use
the GitLab server as an intermediary to the Kerberos server.
If you're experiencing this error, ensure there is connectivity between the
client machine and the Kerberos server - this is a prerequisite! Traffic may be
blocked by a firewall, or the DNS records may be incorrect.
### `GitLab DNS record is a CNAME record` error
Kerberos fails with this error when GitLab is referenced with a `CNAME` record.
To resolve this issue, ensure the DNS record for GitLab is an `A` record.
### Mismatched forward and reverse DNS records for GitLab instance hostname
Another failure mode occurs when the forward and reverse DNS records for the
GitLab server do not match. Often, Windows clients work in this case while
Linux clients fail. They use reverse DNS while detecting the Kerberos
realm. If they get the wrong realm then ordinary Kerberos mechanisms fail,
so the client falls back to attempting to negotiate `IAKERB`, leading to the
above error message.
To fix this, ensure that the forward and reverse DNS for your GitLab server
match. So for instance, if you access GitLab as `gitlab.example.com`, resolving
to IP address `10.0.2.2`, then `2.2.0.10.in-addr.arpa` must be a `PTR` record for
`gitlab.example.com`.
### Missing Kerberos libraries on browser or client machine
Finally, it's possible that the browser or client machine lack Kerberos support
completely. Ensure that the Kerberos libraries are installed and that you can
authenticate to other Kerberos services.
## HTTP Basic: Access denied when cloning
```shell
remote: HTTP Basic: Access denied
fatal: Authentication failed for '<KRB5 path>'
```
If you are using Git v2.11 or newer and see the above error when cloning, you can
set the `http.emptyAuth` Git option to `true` to fix this:
```shell
git config --global http.emptyAuth true
```
See also: [Git v2.11 release notes](https://github.com/git/git/blob/master/Documentation/RelNotes/2.11.0.txt#L482-L486)
## Helpful links
- <https://help.ubuntu.com/community/Kerberos>
- <https://blog.manula.org/2012/04/setting-up-kerberos-server-with-debian.html>
- <https://www.roguelynn.com/words/explain-like-im-5-kerberos/>

View File

@ -952,7 +952,7 @@ by this issue.
every Sidekiq process also listens to those queues to ensure all jobs are processed across
all queues. This behavior does not apply if you have configured the [routing rules](../../administration/sidekiq/processing_specific_job_classes.md#routing-rules).
- Docker 20.10.10 or later is required to run the GitLab Docker image. Older versions
[throw errors on startup](../../install/docker.md#threaderror-cant-create-thread-operation-not-permitted).
[throw errors on startup](../../install/docker_troubleshooting.md#threaderror-cant-create-thread-operation-not-permitted).
- Container registry using Azure storage might be empty with zero tags. You can fix this by following the [breaking change instructions](../deprecations.md#azure-storage-driver-defaults-to-the-correct-root-prefix).
- Normally, backups in environments that have PgBouncer must [bypass PgBouncer by setting variables that are prefixed with `GITLAB_BACKUP_`](../../administration/backup_restore/backup_gitlab.md#bypassing-pgbouncer). However, due to an [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/422163), `gitlab-backup` uses the regular database connection through PgBouncer instead of the direct connection defined in the override, and the database backup fails. The workaround is to use `pg_dump` directly.

View File

@ -79,9 +79,10 @@ module API
import_export_upload: ImportExportUpload.new(import_file: params[:file])
}
group = ::Groups::CreateService.new(current_user, group_params).execute
response = ::Groups::CreateService.new(current_user, group_params).execute
group = response[:group]
if group.persisted?
if response.success?
::Groups::ImportExport::ImportService.new(group: group, user: current_user).async_execute
accepted!

View File

@ -62,9 +62,7 @@ module API
def create_group
# This is a separate method so that EE can extend its behaviour, without
# having to modify this code directly.
::Groups::CreateService
.new(current_user, declared_params(include_missing: false))
.execute
::Groups::CreateService.new(current_user, declared_params(include_missing: false)).execute
end
def update_group(group)
@ -244,10 +242,11 @@ module API
authorize_group_creation!
end
group = create_group
response = create_group
group = response[:group]
group.preload_shared_group_links
if group.persisted?
if response.success?
present group, with: Entities::GroupDetail, current_user: current_user
else
render_api_error!("Failed to save group #{group.errors.messages}", 400)

View File

@ -22,9 +22,10 @@ module BulkImports
raise(GroupCreationError, 'User requires Two-Factor Authentication')
end
group = ::Groups::CreateService.new(current_user, data).execute
response = ::Groups::CreateService.new(current_user, data).execute
group = response[:group]
raise(GroupCreationError, group.errors.full_messages.to_sentence) if group.errors.any?
raise(GroupCreationError, group.errors.full_messages.to_sentence) if response.error?
context.entity.update!(group: group)

View File

@ -19,14 +19,6 @@ module Gitlab
attr_reader :data, :ctx, :errors
def self.match(data)
return data unless data.is_a?(String) && data.include?(PREFIX)
data.gsub(PATTERN) do
yield ::Regexp.last_match(1), ::Regexp.last_match(2)
end
end
def initialize(block, data, ctx)
@block = block
@data = data

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