Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-05-10 15:15:58 +00:00
parent 1efcb3739b
commit c5cd0c605e
140 changed files with 1944 additions and 733 deletions

View File

@ -1701,9 +1701,6 @@
# Run tests automatically for MRs that touch QA files
- <<: *if-merge-request
changes: *qa-patterns
# Run tests automatically for MRS that touch GITALY_SERVER_VERSION
- <<: *if-merge-request
changes: *gitaly-patterns
# Otherwise, only run tests after the MR is approved
- <<: *if-merge-request-not-approved
when: never
@ -2366,6 +2363,9 @@
changes: *code-backstage-qa-patterns
- <<: *if-merge-request
changes: *workhorse-patterns
- <<: *if-merge-request
changes: *rubocop-patterns
.rails:rules:detect-previous-failed-tests:
rules:

View File

@ -86,22 +86,6 @@ Layout/ArgumentAlignment:
- 'app/graphql/types/notes/update_diff_image_position_input_type.rb'
- 'app/graphql/types/packages/cleanup/policy_type.rb'
- 'app/graphql/types/packages/file_metadata_type.rb'
- 'app/graphql/types/work_items/widgets/hierarchy_type.rb'
- 'app/graphql/types/work_items/widgets/hierarchy_update_input_type.rb'
- 'app/graphql/types/work_items/widgets/labels_update_input_type.rb'
- 'app/graphql/types/work_items/widgets/milestone_input_type.rb'
- 'app/graphql/types/work_items/widgets/milestone_type.rb'
- 'app/graphql/types/work_items/widgets/start_and_due_date_update_input_type.rb'
- 'app/graphql/types/x509_certificate_type.rb'
- 'app/graphql/types/x509_issuer_type.rb'
- 'app/services/lfs/lock_file_service.rb'
- 'app/services/markdown_content_rewriter_service.rb'
- 'app/services/members/base_service.rb'
- 'app/services/ml/experiment_tracking/experiment_repository.rb'
- 'app/services/post_receive_service.rb'
- 'app/services/preview_markdown_service.rb'
- 'app/services/protected_branches/api_service.rb'
- 'app/services/protected_branches/legacy_api_create_service.rb'
- 'ee/app/graphql/ee/mutations/issues/create.rb'
- 'ee/app/graphql/ee/mutations/issues/update.rb'
- 'ee/app/graphql/ee/mutations/work_items/create.rb'

View File

@ -1,6 +0,0 @@
---
# Cop supports --autocorrect.
Lint/OrAssignmentToConstant:
Exclude:
- 'lib/gitlab/email/handler/base_handler.rb'
- 'tooling/danger/project_helper.rb'

View File

@ -1,6 +0,0 @@
---
# Cop supports --autocorrect.
Lint/RedundantStringCoercion:
Exclude:
- 'ee/bin/geo_log_cursor'
- 'ee/db/fixtures/development/31_devops_adoption.rb'

View File

@ -56,3 +56,4 @@ Migration/EnsureFactoryForTable:
- 'db/migrate/20240304184128_create_ci_build_names_table.rb'
- 'db/migrate/20240306121653_create_relation_import_tracker.rb'
- 'db/migrate/20240404192955_create_early_access_program_tracking_events.rb'
- 'db/migrate/20240423064716_create_ci_build_execution_config.rb'

View File

@ -1,7 +0,0 @@
---
# Cop supports --autocorrect.
RSpec/EnvMocking:
Exclude:
- 'ee/spec/lib/gitlab/elastic/client_spec.rb'
- 'spec/initializers/net_http_patch_spec.rb'
- 'spec/lib/gitlab/database/reflection_spec.rb'

View File

@ -134,7 +134,7 @@ export default {
if (!this.editor.isActive('diagram')) return;
this.diagramSource = this.$refs.nodeViewContent.$el.textContent;
this.diagramSource = this.$refs.nodeViewContent?.$el.textContent || '';
if (this.node.attrs.language !== 'mermaid') {
this.diagramUrl = await this.contentEditor.renderDiagram(

View File

@ -67,7 +67,7 @@ export default CodeBlockHighlight.extend({
return [
{
priority: PARSE_HTML_PRIORITY_HIGHEST,
tag: 'pre[lang="suggestion"]',
tag: 'pre[data-canonical-lang="suggestion"]',
},
];
},

View File

@ -39,7 +39,7 @@ export default CodeBlockHighlight.extend({
return [
{
priority: PARSE_HTML_PRIORITY_HIGHEST,
tag: 'pre[lang="mermaid"]',
tag: 'pre[data-canonical-lang="mermaid"]',
getAttrs: () => ({ language: 'mermaid' }),
},
{

View File

@ -7,6 +7,9 @@ Vue.use(VueApollo);
export default () => {
const el = document.getElementById('js-deploy-keys');
if (!el) return false;
return new Vue({
el,
apolloProvider: createApolloProvider({

View File

@ -2,7 +2,6 @@
import { GlFormGroup, GlFormCheckbox, GlFormInput } from '@gitlab/ui';
// eslint-disable-next-line no-restricted-imports
import { mapGetters } from 'vuex';
import { s__, __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
@ -65,38 +64,15 @@ export default {
data() {
return {
enableJiraIssues: this.initialEnableJiraIssues,
projectKey: this.initialProjectKey,
projectKeys: this.initialProjectKeys,
};
},
computed: {
...mapGetters(['isInheriting']),
multipleProjectKeys() {
return this.glFeatures.jiraMultipleProjectKeys;
},
checkboxDisabled() {
return !this.showJiraIssuesIntegration || this.isInheriting;
},
validProjectKey() {
// Allow saving the form without project_key when feature flag is enabled.
// This will be improved in https://gitlab.com/gitlab-org/gitlab/-/issues/452161.
if (this.multipleProjectKeys) {
return true;
}
return !this.enableJiraIssues || Boolean(this.projectKey) || !this.isValidated;
},
},
i18n: {
enableCheckboxHelp: s__(
'JiraService|Warning: All users with access to this GitLab project can view all issues from the Jira project you specify.',
),
projectKeyLabel: s__('JiraService|Jira project key'),
projectKeyPlaceholder: s__('JiraService|AB'),
requiredFieldFeedback: __('This field is required.'),
},
};
</script>
@ -112,14 +88,18 @@ export default {
>
{{ s__('JiraService|View Jira issues') }}
<template #help>
{{ $options.i18n.enableCheckboxHelp }}
{{
s__(
'JiraService|Warning: All users with access to this GitLab project can view all issues from the Jira project you specify.',
)
}}
</template>
</gl-form-checkbox>
</template>
<div v-if="enableJiraIssues" class="gl-pl-6 gl-mt-3">
<gl-form-group
v-if="multipleProjectKeys && !isIssueCreation"
v-if="!isIssueCreation"
:label="s__('JiraService|Jira project keys')"
label-for="service_project_keys"
:description="
@ -134,47 +114,15 @@ export default {
v-model="projectKeys"
name="service[project_keys]"
width="xl"
data-testid="jira-project-keys-field"
:placeholder="s__('JiraService|AB,CD')"
:readonly="isInheriting"
/>
</gl-form-group>
<template v-if="!multipleProjectKeys">
<gl-form-group
:label="$options.i18n.projectKeyLabel"
label-for="service_project_key"
:invalid-feedback="$options.i18n.requiredFieldFeedback"
:state="validProjectKey"
data-testid="project-key-form-group"
>
<gl-form-input
id="service_project_key"
v-model="projectKey"
name="service[project_key]"
data-testid="jira-project-key-field"
width="md"
:placeholder="$options.i18n.projectKeyPlaceholder"
:required="enableJiraIssues"
:state="validProjectKey"
:readonly="isInheriting"
/>
</gl-form-group>
<jira-issue-creation-vulnerabilities
:project-key="projectKey"
:initial-is-enabled="initialEnableJiraVulnerabilities"
:initial-issue-type-id="initialVulnerabilitiesIssuetype"
:show-full-feature="showJiraVulnerabilitiesIntegration"
class="gl-mt-6"
data-testid="jira-for-vulnerabilities"
@request-jira-issue-types="$emit('request-jira-issue-types')"
/>
</template>
</div>
<template v-if="isIssueCreation">
<jira-issue-creation-vulnerabilities
:project-key="projectKey"
:initial-is-enabled="initialEnableJiraVulnerabilities"
:initial-project-key="initialProjectKey"
:initial-issue-type-id="initialVulnerabilitiesIssuetype"

View File

@ -24,6 +24,7 @@ import {
TOKEN_TYPE_MY_REACTION,
TOKEN_TYPE_ORGANIZATION,
TOKEN_TYPE_RELEASE,
TOKEN_TYPE_SOURCE_BRANCH,
TOKEN_TYPE_TARGET_BRANCH,
TOKEN_TYPE_TYPE,
TOKEN_TYPE_WEIGHT,
@ -268,6 +269,16 @@ export const filtersMap = {
},
},
},
[TOKEN_TYPE_SOURCE_BRANCH]: {
[API_PARAM]: {
[NORMAL_FILTER]: 'sourceBranches',
},
[URL_PARAM]: {
[OPERATOR_IS]: {
[NORMAL_FILTER]: 'source_branches[]',
},
},
},
[TOKEN_TYPE_TARGET_BRANCH]: {
[API_PARAM]: {
[NORMAL_FILTER]: 'targetBranches',

View File

@ -21,6 +21,8 @@ import {
TOKEN_TYPE_DRAFT,
TOKEN_TITLE_TARGET_BRANCH,
TOKEN_TYPE_TARGET_BRANCH,
TOKEN_TITLE_SOURCE_BRANCH,
TOKEN_TYPE_SOURCE_BRANCH,
} from '~/vue_shared/components/filtered_search_bar/constants';
import {
convertToApiParams,
@ -206,7 +208,16 @@ export default {
operators: OPERATORS_IS,
fullPath: this.fullPath,
isProject: true,
multiselect: true,
fetchBranches: this.fetchBranches,
},
{
type: TOKEN_TYPE_SOURCE_BRANCH,
title: TOKEN_TITLE_SOURCE_BRANCH,
icon: 'branch',
token: BranchToken,
operators: OPERATORS_IS,
fullPath: this.fullPath,
isProject: true,
fetchBranches: this.fetchBranches,
},
];

View File

@ -9,6 +9,7 @@ query getMergeRequests(
$state: MergeRequestState
$authorUsername: String
$draft: Boolean
$sourceBranches: [String!]
$targetBranches: [String!]
$beforeCursor: String
$afterCursor: String
@ -22,6 +23,7 @@ query getMergeRequests(
state: $state
authorUsername: $authorUsername
draft: $draft
sourceBranches: $sourceBranches
targetBranches: $targetBranches
before: $beforeCursor
after: $afterCursor

View File

@ -10,8 +10,12 @@ export default class ProtectedTagCreate {
constructor({ hasLicense }) {
this.hasLicense = hasLicense;
this.$form = $('.js-new-protected-tag');
this.buildDropdowns();
this.bindEvents();
if (this.$form.length > 0) {
this.buildDropdowns();
this.bindEvents();
}
this.selectedItems = [];
}
@ -35,6 +39,7 @@ export default class ProtectedTagCreate {
// Allowed to Create dropdown
const createTagSelector = 'js-allowed-to-create';
const [dropdownEl] = this.$form.find(`.${createTagSelector}`);
this.protectedTagAccessDropdown = initAccessDropdown(dropdownEl, {
toggleClass: createTagSelector,
hasLicense: this.hasLicense,

View File

@ -9,17 +9,14 @@ export default class ProtectedTagEditList {
}
initEditForm() {
document
.querySelector('.protected-tags-list')
.querySelectorAll('.js-protected-tag-edit-form')
?.forEach((el) => {
const accessDropdownEl = el.querySelector('.js-allowed-to-create');
this.initAccessDropdown(accessDropdownEl, {
url: el.dataset.url,
hasLicense: this.hasLicense,
accessLevelsData: gon.create_access_levels.roles,
});
document.querySelectorAll('.protected-tags-list .js-protected-tag-edit-form')?.forEach((el) => {
const accessDropdownEl = el.querySelector('.js-allowed-to-create');
this.initAccessDropdown(accessDropdownEl, {
url: el.dataset.url,
hasLicense: this.hasLicense,
accessLevelsData: gon.create_access_levels.roles,
});
});
}
// eslint-disable-next-line class-methods-use-this

View File

@ -183,7 +183,6 @@ export default {
ref="issuableFormWrapper"
:class="{ focus: isInputFocused }"
class="add-issuable-form-input-wrapper form-control gl-field-error-outline gl-h-auto gl-px-3 gl-pt-2 gl-pb-0"
role="button"
@click="onIssuableFormWrapperClick"
>
<ul class="gl-display-flex gl-flex-wrap gl-align-items-baseline gl-list-none gl-m-0 gl-p-0">

View File

@ -52,6 +52,8 @@ export const CLUSTER_IMAGE_SCANNING_NAME = s__('ciReport|Cluster Image Scanning'
export const PRE_RECEIVE_SECRET_DETECTION = 'pre_receive_secret_detection';
export const PRE_RECEIVE_SECRET_DETECTION_NAME = __('Pre-receive Secret Detection');
export const SCANNER_NAMES_MAP = {
SAST: SAST_SHORT_NAME,
SAST_IAC: SAST_IAC_NAME,
@ -63,6 +65,7 @@ export const SCANNER_NAMES_MAP = {
DEPENDENCY_SCANNING: DEPENDENCY_SCANNING_NAME,
BREACH_AND_ATTACK_SIMULATION: BAS_NAME,
CLUSTER_IMAGE_SCANNING: CLUSTER_IMAGE_SCANNING_NAME,
PRE_RECEIVE_SECRET_DETECTION: PRE_RECEIVE_SECRET_DETECTION_NAME,
GENERIC: s__('ciReport|Manually added'),
};

View File

@ -6,9 +6,6 @@ module Groups
include ::Integrations::Actions
before_action :authorize_admin_group!
before_action only: [:edit, :update] do
push_frontend_feature_flag(:jira_multiple_project_keys, group)
end
feature_category :integrations

View File

@ -0,0 +1,66 @@
# frozen_string_literal: true
module Import
class SourceUsersController < ApplicationController
prepend_before_action :check_feature_flag!
before_action :source_user
before_action :check_current_user_matches_invite!
respond_to :html
feature_category :importers
def accept
if source_user.accept
# TODO: This is where we enqueue the job to assign the contributions.
redirect_to(root_path, notice: format(mapping_decision_notice('approved'), invite_details))
else
redirect_to(root_path, alert: _('The invitation could not be accepted.'))
end
end
def decline
if source_user.reject
redirect_to(root_path, notice: format(mapping_decision_notice('rejected'), invite_details))
else
redirect_to(root_path, alert: _('The invitation could not be declined.'))
end
end
private
def check_current_user_matches_invite!
not_found unless current_user_matches_invite?
end
def current_user_matches_invite?
current_user.id == source_user.reassign_to_user_id
end
def source_user
Import::SourceUser.find(params[:id])
end
strong_memoize_attr :source_user
def invite_details
{
source_username: source_user.source_username,
source_hostname: source_user.source_hostname,
destination_group: source_user.namespace.name
}
end
def check_feature_flag!
not_found unless Feature.enabled?(:bulk_import_user_mapping, current_user)
end
# TODO: This is a placeholder for the proper UI to be provided
# in a follow-up MR.
def mapping_decision_notice(decision)
"You have #{decision} the reassignment of contributions from " \
"%{source_username} on %{source_hostname} " \
"to yourself on %{destination_group}."
end
end
end

View File

@ -12,9 +12,6 @@ module Projects
before_action :default_integration, only: [:edit, :update]
before_action :web_hook_logs, only: [:edit, :update]
before_action -> { check_test_rate_limit! }, only: :test
before_action only: [:edit, :update] do
push_frontend_feature_flag(:jira_multiple_project_keys, project.group)
end
respond_to :html

View File

@ -4,7 +4,8 @@ module Projects
module Settings
class RepositoryController < Projects::ApplicationController
layout 'project_settings'
before_action :authorize_admin_project!
before_action :authorize_admin_project!, except: [:show, :update]
before_action :authorize_admin_push_rules!, only: [:show, :update]
before_action :define_variables, only: [:create_deploy_token]
before_action do

View File

@ -0,0 +1,45 @@
# frozen_string_literal: true
module Mutations
module Integrations
module Exclusions
class Create < BaseMutation
graphql_name 'IntegrationExclusionCreate'
include ResolvesIds
field :exclusions, [::Types::Integrations::ExclusionType],
null: true,
description: 'Integration exclusions created by the mutation.'
argument :integration_name,
::Types::Integrations::IntegrationTypeEnum,
required: true,
description: 'Type of integration to exclude.'
argument :project_ids,
[::Types::GlobalIDType[::Project]],
required: true,
description: 'Ids of projects to exclude.'
authorize :admin_all_resources
def resolve(integration_name:, project_ids:)
authorize!(:global)
projects = Project.id_in(resolve_ids(project_ids))
result = ::Integrations::Exclusions::CreateService.new(
current_user: current_user,
projects: projects,
integration_name: integration_name
).execute
{
exclusions: result.payload,
errors: result.errors
}
end
end
end
end
end

View File

@ -0,0 +1,45 @@
# frozen_string_literal: true
module Mutations
module Integrations
module Exclusions
class Delete < BaseMutation
graphql_name 'IntegrationExclusionDelete'
include ResolvesIds
field :exclusions, [::Types::Integrations::ExclusionType],
null: true,
description: 'Project no longer excluded due to the mutation.'
argument :integration_name,
::Types::Integrations::IntegrationTypeEnum,
required: true,
description: 'Type of integration.'
argument :project_ids,
[::Types::GlobalIDType[::Project]],
required: true,
description: 'Id of excluded project.'
authorize :admin_all_resources
def resolve(integration_name:, project_ids:)
authorize!(:global)
projects = Project.id_in(resolve_ids(project_ids))
result = ::Integrations::Exclusions::DestroyService.new(
current_user: current_user,
projects: projects,
integration_name: integration_name
).execute
{
exclusions: result.payload,
errors: result.errors
}
end
end
end
end
end

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Resolvers
module Integrations
class ExclusionsResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
type Types::Integrations::ExclusionType.connection_type, null: true
argument :integration_name, Types::Integrations::IntegrationTypeEnum,
required: true,
description: 'Type of integration.'
def resolve(integration_name:)
authorize!
Integration.integration_name_to_model(integration_name).with_custom_settings.by_active_flag(false)
end
def authorize!
raise_resource_not_available_error! unless context[:current_user]&.can_admin_all_resources?
end
end
end
end

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
module Types
module Integrations
class ExclusionType < BaseObject
graphql_name 'IntegrationExclusion'
description 'An integration to override the level settings of instance specific integrations.'
authorize :admin_all_resources
field :project, ::Types::ProjectType,
description: 'Project that has been excluded from the instance specific integration.'
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
module Types
module Integrations
class IntegrationTypeEnum < BaseEnum
graphql_name 'IntegrationType'
description 'Integration Names'
value 'BEYOND_IDENTITY', description: 'Beyond Identity.', value: 'beyond_identity'
end
end
end

View File

@ -63,6 +63,8 @@ module Types
mount_mutation Mutations::IncidentManagement::TimelineEvent::Update
mount_mutation Mutations::IncidentManagement::TimelineEvent::Destroy
mount_mutation Mutations::IncidentManagement::TimelineEventTag::Create
mount_mutation Mutations::Integrations::Exclusions::Create, alpha: { milestone: '17.0' }
mount_mutation Mutations::Integrations::Exclusions::Delete, alpha: { milestone: '17.0' }
mount_mutation Mutations::Issues::Create
mount_mutation Mutations::Issues::SetAssignees
mount_mutation Mutations::Issues::SetCrmContacts

View File

@ -222,6 +222,11 @@ module Types
description: 'Find machine learning models.',
resolver: Resolvers::Ml::ModelDetailResolver
field :integration_exclusions, Types::Integrations::ExclusionType.connection_type,
null: true,
alpha: { milestone: '17.0' },
resolver: Resolvers::Integrations::ExclusionsResolver
field :work_items_by_reference,
null: true,
alpha: { milestone: '16.7' },

View File

@ -27,7 +27,7 @@ module Types
resolver: Resolvers::WorkItems::AncestorsResolver
field :has_children, GraphQL::Types::Boolean,
null: false, description: 'Indicates if the work item has children.'
null: false, description: 'Indicates if the work item has children.'
# rubocop: disable CodeReuse/ActiveRecord
def has_children?

View File

@ -7,26 +7,26 @@ module Types
graphql_name 'WorkItemWidgetHierarchyUpdateInput'
argument :adjacent_work_item_id,
::Types::GlobalIDType[::WorkItem],
required: false,
loads: ::Types::WorkItemType,
description: 'ID of the work item to be switched with.'
::Types::GlobalIDType[::WorkItem],
required: false,
loads: ::Types::WorkItemType,
description: 'ID of the work item to be switched with.'
argument :children_ids, [::Types::GlobalIDType[::WorkItem]],
required: false,
description: 'Global IDs of children work items.',
loads: ::Types::WorkItemType,
as: :children
required: false,
description: 'Global IDs of children work items.',
loads: ::Types::WorkItemType,
as: :children
argument :parent_id, ::Types::GlobalIDType[::WorkItem],
required: false,
loads: ::Types::WorkItemType,
description: 'Global ID of the parent work item. Use `null` to remove the association.'
required: false,
loads: ::Types::WorkItemType,
description: 'Global ID of the parent work item. Use `null` to remove the association.'
argument :relative_position,
Types::RelativePositionTypeEnum,
required: false,
description: 'Type of switch. Valid values are `BEFORE` or `AFTER`.'
Types::RelativePositionTypeEnum,
required: false,
description: 'Type of switch. Valid values are `BEFORE` or `AFTER`.'
end
end
end

View File

@ -7,13 +7,13 @@ module Types
graphql_name 'WorkItemWidgetLabelsUpdateInput'
argument :add_label_ids, [Types::GlobalIDType[::Label]],
required: false,
description: 'Global IDs of labels to be added to the work item.',
prepare: ->(label_ids, _ctx) { label_ids.map(&:model_id) }
required: false,
description: 'Global IDs of labels to be added to the work item.',
prepare: ->(label_ids, _ctx) { label_ids.map(&:model_id) }
argument :remove_label_ids, [Types::GlobalIDType[::Label]],
required: false,
description: 'Global IDs of labels to be removed from the work item.',
prepare: ->(label_ids, _ctx) { label_ids.map(&:model_id) }
required: false,
description: 'Global IDs of labels to be removed from the work item.',
prepare: ->(label_ids, _ctx) { label_ids.map(&:model_id) }
end
end
end

View File

@ -7,10 +7,10 @@ module Types
graphql_name 'WorkItemWidgetMilestoneInput'
argument :milestone_id,
Types::GlobalIDType[::Milestone],
required: :nullable,
prepare: ->(id, _) { id.model_id unless id.nil? },
description: 'Milestone to assign to the work item.'
Types::GlobalIDType[::Milestone],
required: :nullable,
prepare: ->(id, _) { id.model_id unless id.nil? },
description: 'Milestone to assign to the work item.'
end
end
end

View File

@ -13,9 +13,9 @@ module Types
implements Types::WorkItems::WidgetInterface
field :milestone,
::Types::MilestoneType,
null: true,
description: 'Milestone of the work item.'
::Types::MilestoneType,
null: true,
description: 'Milestone of the work item.'
end
# rubocop:enable Graphql/AuthorizeTypes
end

View File

@ -7,11 +7,11 @@ module Types
graphql_name 'WorkItemWidgetStartAndDueDateUpdateInput'
argument :due_date, Types::DateType,
required: false,
description: 'Due date for the work item.'
required: false,
description: 'Due date for the work item.'
argument :start_date, Types::DateType,
required: false,
description: 'Start date for the work item.'
required: false,
description: 'Start date for the work item.'
end
end
end

View File

@ -8,31 +8,31 @@ module Types
description 'Represents an X.509 certificate.'
field :certificate_status, GraphQL::Types::String,
null: false,
description: 'Indicates if the certificate is good or revoked.'
null: false,
description: 'Indicates if the certificate is good or revoked.'
field :created_at, Types::TimeType, null: false,
description: 'Timestamp of when the certificate was saved.'
description: 'Timestamp of when the certificate was saved.'
field :email, GraphQL::Types::String, null: false,
description: 'Email associated with the cerificate.'
description: 'Email associated with the cerificate.'
field :id, GraphQL::Types::ID, null: false, description: 'ID of the certificate.'
field :serial_number, GraphQL::Types::String, null: false,
description: 'Serial number of the certificate.'
description: 'Serial number of the certificate.'
field :subject, GraphQL::Types::String, null: false, description: 'Subject of the certificate.'
field :subject_key_identifier, GraphQL::Types::String,
null: false,
description: 'Subject key identifier of the certificate.'
null: false,
description: 'Subject key identifier of the certificate.'
field :updated_at, Types::TimeType, null: false,
description: 'Timestamp of when the certificate was last updated.'
description: 'Timestamp of when the certificate was last updated.'
field :x509_issuer, Types::X509IssuerType, null: false,
description: 'Issuer of the certificate.'
description: 'Issuer of the certificate.'
end
end

View File

@ -8,21 +8,21 @@ module Types
description 'Issuer of an X.509 certificate.'
field :created_at, Types::TimeType, null: true,
description: 'Timestamp of when the issuer was created.'
description: 'Timestamp of when the issuer was created.'
field :crl_url, GraphQL::Types::String, null: true,
description: 'Certificate revokation list of the issuer.'
description: 'Certificate revokation list of the issuer.'
field :id, GraphQL::Types::ID, null: true, description: 'ID of the issuer.'
field :subject, GraphQL::Types::String, null: true, description: 'Subject of the issuer.'
field :subject_key_identifier, GraphQL::Types::String,
null: true,
description: 'Subject key identifier of the issuer.'
null: true,
description: 'Subject key identifier of the issuer.'
field :updated_at, Types::TimeType, null: true,
description: 'Timestamp of when the issuer was last updated.'
description: 'Timestamp of when the issuer was last updated.'
end
end

View File

@ -12,6 +12,13 @@ class DeviseMailerPreview < ActionMailer::Preview
DeviseMailer.confirmation_instructions(user, 'faketoken', {})
end
def confirmation_instructions_for_secondary_email
user = User.last
secondary_email = user.emails.build(email: 'unconfirmed@example.com')
DeviseMailer.confirmation_instructions(secondary_email, 'faketoken', {})
end
def reset_password_instructions
DeviseMailer.reset_password_instructions(unsaved_user, 'faketoken', {})
end

View File

@ -46,6 +46,8 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
PACKAGE_REGISTRY_SETTINGS = [:nuget_skip_metadata_url_validation].freeze
USERS_UNCONFIRMED_SECONDARY_EMAILS_DELETE_AFTER_DAYS = 3
enum whats_new_variant: { all_tiers: 0, current_tier: 1, disabled: 2 }, _prefix: true
enum email_confirmation_setting: { off: 0, soft: 1, hard: 2 }, _prefix: true

View File

@ -28,6 +28,13 @@ module Ci
inverse_of: :builds
belongs_to :project_mirror, primary_key: :project_id, foreign_key: :project_id, inverse_of: :builds
belongs_to :execution_config,
->(build) { in_partition(build) },
class_name: 'Ci::BuildExecutionConfig',
foreign_key: :execution_config_id,
partition_foreign_key: :partition_id,
inverse_of: :builds
RUNNER_FEATURES = {
upload_multiple_artifacts: ->(build) { build.publishes_artifacts_reports? },
refspecs: ->(build) { build.merge_request_ref? },

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
module Ci
class BuildExecutionConfig < Ci::ApplicationRecord
include Ci::Partitionable
self.table_name = :p_ci_builds_execution_configs
self.primary_key = :id
partitionable scope: :pipeline, partitioned: true
query_constraints :id, :partition_id
belongs_to :pipeline,
->(execution_config) { in_partition(execution_config) },
class_name: 'Ci::Pipeline',
partition_foreign_key: :partition_id,
inverse_of: :build_execution_configs
belongs_to :project
has_many :builds,
->(execution_config) { in_partition(execution_config) },
class_name: 'Ci::Build',
foreign_key: :execution_config_id,
inverse_of: :execution_config,
partition_foreign_key: :partition_id
validates :run_steps, json_schema: { filename: 'run_steps' }, presence: true
end
end

View File

@ -86,6 +86,7 @@ module Ci
inverse_of: :pipeline, partition_foreign_key: :partition_id
has_many :bridges, ->(pipeline) { in_partition(pipeline) }, class_name: 'Ci::Bridge', foreign_key: :commit_id, inverse_of: :pipeline, partition_foreign_key: :partition_id
has_many :builds, ->(pipeline) { in_partition(pipeline) }, foreign_key: :commit_id, inverse_of: :pipeline, partition_foreign_key: :partition_id
has_many :build_execution_configs, ->(pipeline) { in_partition(pipeline) }, class_name: 'Ci::BuildExecutionConfig', inverse_of: :pipeline, partition_foreign_key: :partition_id
has_many :generic_commit_statuses, ->(pipeline) { in_partition(pipeline) }, foreign_key: :commit_id, inverse_of: :pipeline, class_name: 'GenericCommitStatus', partition_foreign_key: :partition_id
#
# NEW:

View File

@ -7,6 +7,7 @@ module Ci
PARTITIONABLE_MODELS = %w[
CommitStatus
Ci::BuildExecutionConfig
Ci::BuildMetadata
Ci::BuildName
Ci::BuildNeed

View File

@ -1,12 +1,14 @@
# frozen_string_literal: true
module Import
SOURCE_DIRECT_TRANSFER = :gitlab_migration # aka BulkImports
module HasImportSource
extend ActiveSupport::Concern
IMPORT_SOURCES = {
none: 0, # not imported
gitlab_migration: 1, # aka direct transfer & bulk_import
SOURCE_DIRECT_TRANSFER => 1,
gitlab_project: 2, # aka gitlab import/export
github: 3,
bitbucket: 4, # aka bitbucket cloud

View File

@ -11,6 +11,8 @@ class Email < MainClusterwide::ApplicationRecord
validate :unique_email, if: ->(email) { email.email_changed? }
scope :confirmed, -> { where.not(confirmed_at: nil) }
scope :unconfirmed, -> { where(confirmed_at: nil) }
scope :unconfirmed_and_created_before, ->(created_cut_off) { unconfirmed.where('created_at < ?', created_cut_off) }
after_commit :update_invalid_gpg_signatures, if: -> { previous_changes.key?('confirmed_at') }

View File

@ -171,7 +171,6 @@ class Group < Namespace
format_with_prefix: :runners_token_prefix,
require_prefix_for_validation: true
before_save :ensure_runner_registration_token_disabled_on_com
after_create :post_create_hook
after_create -> { create_or_load_association(:group_feature) }
after_update :path_changed_hook, if: :saved_change_to_path?
@ -601,15 +600,6 @@ class Group < Namespace
system_hook_service.execute_hooks_for(self, :destroy)
end
def ensure_runner_registration_token_disabled_on_com
return unless parent.nil?
return if namespace_settings
return if ::Gitlab::CurrentSettings.gitlab_dedicated_instance?
return unless ::Gitlab.com? # rubocop: disable Gitlab/AvoidGitlabInstanceChecks -- this is not based on a feature, but indeed on the location of the code
self.namespace_settings = NamespaceSetting.new(namespace_id: id, allow_runner_registration_token: false)
end
# rubocop: disable CodeReuse/ServiceClass
def system_hook_service
SystemHooksService.new

View File

@ -19,6 +19,22 @@ module Import
state :rejected, value: 2
state :failed, value: 3
state :completed, value: 4
event :cancel_assignment do
transition [:awaiting_approval, :rejected] => :pending_assignment
end
event :accept do
transition awaiting_approval: :completed
end
event :reject do
transition awaiting_approval: :rejected
end
after_transition any => [:pending_assignment, :rejected] do |status|
status.update!(reassign_to_user: nil)
end
end
def self.find_source_user(source_user_identifier:, namespace:, source_hostname:, import_type:)

View File

@ -61,10 +61,6 @@ module Integrations
# We should use username/password for Jira Server and email/api_token for Jira Cloud,
# for more information check: https://gitlab.com/gitlab-org/gitlab-foss/issues/49936.
before_save :copy_project_key_to_project_keys,
if: -> {
Feature.disabled?(:jira_multiple_project_keys, group || project&.group)
}
before_save :format_project_keys, if: :project_keys_changed?
after_commit :update_deployment_type, on: [:create, :update], if: :update_deployment_type?
@ -260,28 +256,20 @@ module Integrations
# Currently, Jira issues are only configurable at the project and group levels.
unless instance_level?
issues_title = if Feature.enabled?(:jira_multiple_project_keys, group || project&.group)
s_('JiraService|Jira issues (optional)')
else
_('Issues')
end
sections.push({
type: SECTION_TYPE_JIRA_ISSUES,
title: issues_title,
title: s_('JiraService|Jira issues (optional)'),
description: jira_issues_section_description,
plan: 'premium'
})
if Feature.enabled?(:jira_multiple_project_keys, group || project&.group)
sections.push({
type: SECTION_TYPE_JIRA_ISSUE_CREATION,
title: s_('JiraService|Jira issues for vulnerabilities (optional)'),
description: s_('JiraService|Create Jira issues from GitLab to track any action taken ' \
'to resolve or mitigate vulnerabilities.'),
plan: 'ultimate'
})
end
sections.push({
type: SECTION_TYPE_JIRA_ISSUE_CREATION,
title: s_('JiraService|Jira issues for vulnerabilities (optional)'),
description: s_('JiraService|Create Jira issues from GitLab to track any action taken ' \
'to resolve or mitigate vulnerabilities.'),
plan: 'ultimate'
})
end
sections
@ -456,11 +444,7 @@ module Integrations
end
def issue_key_allowed?(issue_key)
if Feature.disabled?(:jira_multiple_project_keys)
parse_project_from_issue_key(issue_key) == project_key
else
project_keys.blank? || project_keys.include?(parse_project_from_issue_key(issue_key))
end
project_keys.blank? || project_keys.include?(parse_project_from_issue_key(issue_key))
end
def branch_name(commit)
@ -733,10 +717,6 @@ module Integrations
end
end
def copy_project_key_to_project_keys
data_fields.project_keys = [project_key]
end
def format_project_keys
data_fields.project_keys = project_keys.compact_blank.map(&:strip).uniq
end

View File

@ -50,7 +50,7 @@ module WorkItems
private
def validate_max_children
return unless work_item_parent
return unless work_item_parent && work_item_parent_id_changed?
max = persisted? ? MAX_CHILDREN : MAX_CHILDREN - 1
if work_item_parent.child_links.count > max

View File

@ -604,6 +604,7 @@ class ProjectPolicy < BasePolicy
enable :stop_environment
enable :read_import_error
enable :admin_cicd_variables
enable :admin_push_rules
end
rule { can?(:admin_build) }.enable :manage_trigger

View File

@ -26,7 +26,7 @@ module Lfs
def create_lock!
lock = project.lfs_file_locks.create!(user: current_user,
path: params[:path])
path: params[:path])
success(http_status: 201, lock: lock)
end

View File

@ -67,6 +67,6 @@ class MarkdownContentRewriterService
end
attr_reader :current_user, :content, :source_parent,
:target_parent, :rewriters, :content_html,
:field, :html_field, :object, :result
:target_parent, :rewriters, :content_html,
:field, :html_field, :object, :result
end

View File

@ -76,6 +76,6 @@ module Members
end
alias_method :cannot_revoke_owner_responsibilities_from_member_in_project?,
:cannot_assign_owner_responsibilities_to_member_in_project?
:cannot_assign_owner_responsibilities_to_member_in_project?
end
end

View File

@ -22,8 +22,8 @@ module Ml
def create!(name, tags = nil)
experiment = ::Ml::Experiment.create!(name: name,
user: user,
project: project)
user: user,
project: project)
add_tags(experiment, tags)

View File

@ -27,7 +27,7 @@ class PostReceiveService
repository&.expire_branches_cache if mr_options&.fetch(:create, false)
PostReceive.perform_async(params[:gl_repository], params[:identifier],
params[:changes], push_options.as_json)
params[:changes], push_options.as_json)
if mr_options.present?
message = process_mr_push_options(mr_options, params[:changes])

View File

@ -37,14 +37,14 @@ class PreviewMarkdownService < BaseContainerService
return [] unless preview_sugestions?
position = Gitlab::Diff::Position.new(new_path: params[:file_path],
new_line: params[:line].to_i,
base_sha: params[:base_sha],
head_sha: params[:head_sha],
start_sha: params[:start_sha])
new_line: params[:line].to_i,
base_sha: params[:base_sha],
head_sha: params[:head_sha],
start_sha: params[:start_sha])
Gitlab::Diff::SuggestionsParser.parse(text, position: position,
project: project,
supports_suggestion: params[:preview_suggestions])
project: project,
supports_suggestion: params[:preview_suggestions])
end
def preview_sugestions?

View File

@ -8,7 +8,7 @@ module ProtectedBranches
def update(protected_branch)
::ProtectedBranches::UpdateService.new(project_or_group, @current_user,
protected_branch_params(with_defaults: false)).execute(protected_branch)
protected_branch_params(with_defaults: false)).execute(protected_branch)
end
private

View File

@ -22,7 +22,7 @@ module ProtectedBranches
end
@params.merge!(push_access_levels_attributes: [{ access_level: push_access_level }],
merge_access_levels_attributes: [{ access_level: merge_access_level }])
merge_access_levels_attributes: [{ access_level: merge_access_level }])
service = ProtectedBranches::CreateService.new(project_or_group, @current_user, @params)
service.execute

View File

@ -0,0 +1,52 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://gitlab.com/gitlab-org/step-runner/schema/v1/steps",
"items": {
"oneOf": [
{
"required": [
"step"
],
"title": "step"
},
{
"required": [
"script"
],
"title": "script"
}
],
"properties": {
"name": {
"type": "string",
"description": "Name is a unique identifier for this step."
},
"step": {
"type": "string",
"description": "Step is a reference to the step to invoke."
},
"env": {
"additionalProperties": {
"type": "string"
},
"type": "object",
"description": "Env is a map of environment variable names to string values."
},
"inputs": {
"type": "object",
"description": "Inputs is a map of step input names to structured values."
},
"script": {
"type": "string",
"description": "Script is a shell script to evaluate."
}
},
"additionalProperties": false,
"type": "object",
"required": [
"name"
],
"description": "Step is a single step invocation."
},
"type": "array"
}

View File

@ -6,3 +6,5 @@
%p
= _('If this email was added in error, you can remove it here:')
= link_to _("Emails"), profile_emails_url
%p
= format(_('Confirm this email address within %{cut_off_days} days, otherwise the email address is removed.'), cut_off_days: ApplicationSetting::USERS_UNCONFIRMED_SECONDARY_EMAILS_DELETE_AFTER_DAYS)

View File

@ -5,3 +5,5 @@
<%= confirmation_url(@resource, confirmation_token: @token) %>
<%= _("If this email was added in error, you can remove it here: %{profile_emails_url}") % { profile_emails_url: profile_emails_url } %>
<%= format(_('Confirm this email address within %{cut_off_days} days, otherwise the email address is removed.'), cut_off_days: ApplicationSetting::USERS_UNCONFIRMED_SECONDARY_EMAILS_DELETE_AFTER_DAYS) %>

View File

@ -3,18 +3,23 @@
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to packages, your repository, and registry images.')
- @force_desktop_expanded_sidebar = true
= render "projects/branch_defaults/show"
= render "projects/branch_rules/show"
= render_if_exists "projects/push_rules/index"
= render "projects/mirrors/mirror_repos"
- if can?(current_user, :admin_project, @project)
= render "projects/branch_defaults/show"
= render "projects/branch_rules/show"
-# Protected branches & tags use a lot of nested partials.
-# The shared parts of the views can be found in the `shared` directory.
-# Those are used throughout the actual views. These `shared` views are then
-# reused in EE.
= render "projects/settings/repository/protected_branches", protected_branch_entity: @project
= render "shared/deploy_tokens/index", group_or_project: @project, description: deploy_token_description
= render 'shared/deploy_keys/index'
= render "projects/maintenance/show"
- if can?(current_user, :admin_push_rules, @project)
= render_if_exists "projects/push_rules/index"
= render_if_exists 'shared/promotions/promote_repository_features'
- if can?(current_user, :admin_project, @project)
= render "projects/mirrors/mirror_repos"
-# Protected branches & tags use a lot of nested partials.
-# The shared parts of the views can be found in the `shared` directory.
-# Those are used throughout the actual views. These `shared` views are then
-# reused in EE.
= render "projects/settings/repository/protected_branches", protected_branch_entity: @project
= render "shared/deploy_tokens/index", group_or_project: @project, description: deploy_token_description
= render 'shared/deploy_keys/index'
= render "projects/maintenance/show"
= render_if_exists 'shared/promotions/promote_repository_features'

View File

@ -975,6 +975,15 @@
:weight: 1
:idempotent: true
:tags: []
- :name: cronjob:users_unconfirmed_secondary_emails_deletion_cron
:worker_name: Users::UnconfirmedSecondaryEmailsDeletionCronWorker
:feature_category: :user_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent: true
:tags: []
- :name: cronjob:x509_issuer_crl_check
:worker_name: X509IssuerCrlCheckWorker
:feature_category: :source_code_management

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
module Users
class UnconfirmedSecondaryEmailsDeletionCronWorker
include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext -- This worker does not perform work scoped to a context
deduplicate :until_executed
idempotent!
data_consistency :always # rubocop:disable SidekiqLoadBalancing/WorkerDataConsistency -- This is a cron job
feature_category :user_management
BATCH_SIZE = 1000
def perform
loop do
records_deleted = Email.unconfirmed_and_created_before(created_cut_off).limit(BATCH_SIZE).delete_all
break if records_deleted == 0
end
end
private
def created_cut_off
ApplicationSetting::USERS_UNCONFIRMED_SECONDARY_EMAILS_DELETE_AFTER_DAYS.days.ago
end
end
end

View File

@ -1,9 +0,0 @@
---
name: jira_multiple_project_keys
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/440430
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146087
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/455259
milestone: '16.10'
group: group::import and integrate
type: gitlab_com_derisk
default_enabled: false

View File

@ -303,6 +303,10 @@ p_ci_builds:
- table: ci_runners
column: runner_id
on_delete: async_nullify
p_ci_builds_execution_configs:
- table: projects
column: project_id
on_delete: async_delete
p_ci_builds_metadata:
- table: projects
column: project_id

View File

@ -870,6 +870,9 @@ Gitlab.ee do
Settings.cron_jobs['users_delete_unconfirmed_users_worker'] ||= {}
Settings.cron_jobs['users_delete_unconfirmed_users_worker']['cron'] ||= '0 * * * *'
Settings.cron_jobs['users_delete_unconfirmed_users_worker']['job_class'] = 'Users::UnconfirmedUsersDeletionCronWorker'
Settings.cron_jobs['users_unconfirmed_secondary_emails_deletion_cron_worker'] ||= {}
Settings.cron_jobs['users_unconfirmed_secondary_emails_deletion_cron_worker']['cron'] ||= '0 * * * *'
Settings.cron_jobs['users_unconfirmed_secondary_emails_deletion_cron_worker']['job_class'] = 'Users::UnconfirmedSecondaryEmailsDeletionCronWorker'
Settings.cron_jobs['package_metadata_advisories_sync_worker'] ||= {}
Settings.cron_jobs['package_metadata_advisories_sync_worker']['cron'] ||= "*/5 * * * *"
Settings.cron_jobs['package_metadata_advisories_sync_worker']['job_class'] = 'PackageMetadata::AdvisoriesSyncWorker'

View File

@ -5,6 +5,7 @@ Gitlab::Database::Partitioning.register_models(
AuditEvent,
BatchedGitRefUpdates::Deletion,
Ci::BuildMetadata,
Ci::BuildExecutionConfig,
Ci::BuildName,
Ci::Catalog::Resources::Components::Usage,
Ci::Catalog::Resources::SyncEvent,

View File

@ -88,4 +88,11 @@ namespace :import do
get :realtime_changes
post :upload
end
resources :source_users, only: [] do
member do
post :accept
post :decline
end
end
end

View File

@ -0,0 +1,12 @@
---
table_name: p_ci_builds_execution_configs
classes:
- Ci::BuildExecutionConfig
feature_categories:
- pipeline_composition
description: Represents execution config for a group of builds
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/150451
milestone: '17.0'
gitlab_schema: gitlab_ci
sharding_key:
project_id: projects

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class CreateCiBuildExecutionConfig < Gitlab::Database::Migration[2.2]
milestone '17.0'
def change
create_table(:p_ci_builds_execution_configs,
primary_key: [:id, :partition_id],
options: 'PARTITION BY LIST (partition_id)', if_not_exists: true) do |t|
t.bigserial :id, null: false
t.bigint :partition_id, null: false
t.bigint :project_id, null: false, index: true
t.bigint(:pipeline_id, null: false, index: true)
t.jsonb :run_steps, default: {}, null: false
end
end
end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
class CreatePartitionsForPCiBuildsExecutionConfigs < Gitlab::Database::Migration[2.2]
milestone '17.0'
def up
with_lock_retries do
connection.execute(<<~SQL)
CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic.ci_builds_execution_configs_100
PARTITION OF p_ci_builds_execution_configs
FOR VALUES IN (100);
CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic.ci_builds_execution_configs_101
PARTITION OF p_ci_builds_execution_configs
FOR VALUES IN (101);
CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic.ci_builds_execution_configs_102
PARTITION OF p_ci_builds_execution_configs
FOR VALUES IN (102);
SQL
end
end
def down
connection.execute(<<~SQL)
DROP TABLE IF EXISTS gitlab_partitions_dynamic.ci_builds_execution_configs_100;
DROP TABLE IF EXISTS gitlab_partitions_dynamic.ci_builds_execution_configs_101;
DROP TABLE IF EXISTS gitlab_partitions_dynamic.ci_builds_execution_configs_102;
SQL
end
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class AddExecutionConfigIdToPCiBuilds < Gitlab::Database::Migration[2.2]
milestone '17.0'
# rubocop:disable Migration/AddColumnsToWideTables -- We need this to store run step config
def up
add_column :p_ci_builds, :execution_config_id, :bigint
end
# rubocop:enable Migration/AddColumnsToWideTables
def down
remove_column :p_ci_builds, :execution_config_id
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class IndexEmailsOnCreatedAtWhereConfirmedAtIsNull < Gitlab::Database::Migration[2.2]
milestone '17.0'
disable_ddl_transaction!
INDEX_NAME = 'index_emails_on_created_at_where_confirmed_at_is_null'
def up
add_concurrent_index :emails, :created_at, where: 'confirmed_at IS NULL', name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :emails, name: INDEX_NAME
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class PrepareAsyncIndexToExecutionConfigIdInCiBuild < Gitlab::Database::Migration[2.2]
include Gitlab::Database::PartitioningMigrationHelpers
disable_ddl_transaction!
milestone '17.0'
INDEX_NAME = 'index_p_ci_builds_on_execution_config_id'
COLUMNS = [:execution_config_id]
def up
Gitlab::Database::PostgresPartitionedTable.each_partition(:p_ci_builds) do |partition|
index_name = generated_index_name(partition.identifier, INDEX_NAME)
prepare_async_index(partition.identifier, COLUMNS, name: index_name, where: "execution_config_id IS NOT NULL")
end
end
def down
Gitlab::Database::PostgresPartitionedTable.each_partition(:p_ci_builds) do |partition|
index_name = generated_index_name(partition.identifier, INDEX_NAME)
unprepare_async_index(partition.identifier, index_name)
end
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class AddForeignKeyFromPipelineToCiBuildsToExecutionConfigs < Gitlab::Database::Migration[2.2]
include Gitlab::Database::PartitioningMigrationHelpers
milestone '17.0'
disable_ddl_transaction!
def up
add_concurrent_partitioned_foreign_key(
:p_ci_builds_execution_configs, :ci_pipelines,
name: :fk_rails_c26408d02c, column: :pipeline_id,
on_delete: :cascade, reverse_lock_order: true
)
end
def down
with_lock_retries(raise_on_exhaustion: true) do
remove_foreign_key_if_exists(
:p_ci_builds_execution_configs, :ci_pipelines,
name: :fk_rails_c26408d02c, reverse_lock_order: true
)
end
end
end

View File

@ -0,0 +1 @@
3fd334e0639a0cc383f603738001b1a4b5bfbc94092e56c01040cbfbf515ae76

View File

@ -0,0 +1 @@
f86ec5ddd56086044f26214622b2a656d21a8e258cdb24923063c3e046375cad

View File

@ -0,0 +1 @@
324cf74a398ab88fd61018cd6bdea3ef699e91485e34a5fd02850644e9832187

View File

@ -0,0 +1 @@
091e3d00d140167fc7dba73fe46cc8df642bc1ca70b9741f0c0f8db38daea888

View File

@ -0,0 +1 @@
393c51beee226eadf2e9d4c5142669e2efb8f7a445bd18d6e6121727d241d9ac

View File

@ -0,0 +1 @@
43e1ebef09400b5199d9d2e1bb906bab62ee8530cbd8a785f2068f5f9b2f55d1

View File

@ -1131,10 +1131,20 @@ CREATE TABLE p_ci_builds (
trigger_request_id_convert_to_bigint bigint,
upstream_pipeline_id bigint,
user_id bigint,
execution_config_id bigint,
CONSTRAINT check_1e2fbd1b39 CHECK ((lock_version IS NOT NULL))
)
PARTITION BY LIST (partition_id);
CREATE TABLE p_ci_builds_execution_configs (
id bigint NOT NULL,
partition_id bigint NOT NULL,
project_id bigint NOT NULL,
pipeline_id bigint NOT NULL,
run_steps jsonb DEFAULT '{}'::jsonb NOT NULL
)
PARTITION BY LIST (partition_id);
CREATE TABLE p_ci_builds_metadata (
project_id integer NOT NULL,
timeout integer,
@ -6264,6 +6274,7 @@ CREATE TABLE ci_builds (
trigger_request_id_convert_to_bigint bigint,
upstream_pipeline_id bigint,
user_id bigint,
execution_config_id bigint,
CONSTRAINT check_1e2fbd1b39 CHECK ((lock_version IS NOT NULL))
);
@ -12550,6 +12561,15 @@ CREATE SEQUENCE p_catalog_resource_sync_events_id_seq
ALTER SEQUENCE p_catalog_resource_sync_events_id_seq OWNED BY p_catalog_resource_sync_events.id;
CREATE SEQUENCE p_ci_builds_execution_configs_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE p_ci_builds_execution_configs_id_seq OWNED BY p_ci_builds_execution_configs.id;
CREATE SEQUENCE p_ci_job_annotations_id_seq
START WITH 1
INCREMENT BY 1
@ -19610,6 +19630,8 @@ ALTER TABLE ONLY p_catalog_resource_component_usages ALTER COLUMN id SET DEFAULT
ALTER TABLE ONLY p_catalog_resource_sync_events ALTER COLUMN id SET DEFAULT nextval('p_catalog_resource_sync_events_id_seq'::regclass);
ALTER TABLE ONLY p_ci_builds_execution_configs ALTER COLUMN id SET DEFAULT nextval('p_ci_builds_execution_configs_id_seq'::regclass);
ALTER TABLE ONLY p_ci_builds_metadata ALTER COLUMN id SET DEFAULT nextval('ci_builds_metadata_id_seq'::regclass);
ALTER TABLE ONLY p_ci_job_annotations ALTER COLUMN id SET DEFAULT nextval('p_ci_job_annotations_id_seq'::regclass);
@ -21939,6 +21961,9 @@ ALTER TABLE ONLY p_catalog_resource_sync_events
ALTER TABLE ONLY p_ci_build_names
ADD CONSTRAINT p_ci_build_names_pkey PRIMARY KEY (build_id, partition_id);
ALTER TABLE ONLY p_ci_builds_execution_configs
ADD CONSTRAINT p_ci_builds_execution_configs_pkey PRIMARY KEY (id, partition_id);
ALTER TABLE ONLY p_ci_finished_build_ch_sync_events
ADD CONSTRAINT p_ci_finished_build_ch_sync_events_pkey PRIMARY KEY (build_id, partition);
@ -25404,6 +25429,8 @@ CREATE INDEX index_elasticsearch_indexed_namespaces_on_created_at ON elasticsear
CREATE UNIQUE INDEX index_emails_on_confirmation_token ON emails USING btree (confirmation_token);
CREATE INDEX index_emails_on_created_at_where_confirmed_at_is_null ON emails USING btree (created_at) WHERE (confirmed_at IS NULL);
CREATE UNIQUE INDEX index_emails_on_email ON emails USING btree (email);
CREATE INDEX index_emails_on_user_id ON emails USING btree (user_id);
@ -26522,6 +26549,10 @@ CREATE INDEX index_p_ci_build_names_on_project_id_and_build_id ON ONLY p_ci_buil
CREATE INDEX index_p_ci_build_names_on_search_vector ON ONLY p_ci_build_names USING gin (search_vector);
CREATE INDEX index_p_ci_builds_execution_configs_on_pipeline_id ON ONLY p_ci_builds_execution_configs USING btree (pipeline_id);
CREATE INDEX index_p_ci_builds_execution_configs_on_project_id ON ONLY p_ci_builds_execution_configs USING btree (project_id);
CREATE INDEX index_p_ci_finished_build_ch_sync_events_finished_at ON ONLY p_ci_finished_build_ch_sync_events USING btree (partition, build_finished_at);
CREATE UNIQUE INDEX index_p_ci_job_annotations_on_partition_id_job_id_name ON ONLY p_ci_job_annotations USING btree (partition_id, job_id, name);
@ -32469,6 +32500,9 @@ ALTER TABLE ONLY labels
ALTER TABLE ONLY project_feature_usages
ADD CONSTRAINT fk_rails_c22a50024b FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE p_ci_builds_execution_configs
ADD CONSTRAINT fk_rails_c26408d02c FOREIGN KEY (pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
ALTER TABLE ONLY user_canonical_emails
ADD CONSTRAINT fk_rails_c2bd828b51 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;

View File

@ -271,6 +271,78 @@ gitlab_rails['omniauth_providers'] = [
Microsoft has documented how its platform works with [the OIDC protocol](https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols-oidc).
#### Migrate to Generic OpenID Connect configuration
You can migrate to the Generic OpenID Connect configuration from both `azure_activedirectory_v2` and `azure_oauth2`.
First, set the `uid_field`, which differs between providers:
| Provider | `uid` | Supporting information |
|-----------------------------------------------------------------------------------------------------------------|-------|-----------------------------------------------------------------------|
| [`omniauth-azure-oauth2`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/vendor/gems/omniauth-azure-oauth2) | `sub` | Additional attributes `oid` and `tid` are offered within the `info` object. |
| [`omniauth-azure-activedirectory-v2`](https://github.com/RIPAGlobal/omniauth-azure-activedirectory-v2/) | `oid` | You must configure `oid` as `uid_field` when migrating. |
| [`omniauth_openid_connect`](https://github.com/omniauth/omniauth_openid_connect/) | `sub` | Specify `uid_field` to use another field. |
To migrate to the Generic OpenID Connect configuration, you must change the configuration to the following:
::Tabs
:::Azure OAuth 2.0
```ruby
gitlab_rails['omniauth_providers'] = [
{
name: "azure_oauth2",
label: "Azure OIDC", # optional label for login button, defaults to "Openid Connect"
args: {
name: "azure_activedirectory_v2",
strategy_class: "OmniAuth::Strategies::OpenIDConnect",
scope: ["openid", "profile", "email"],
response_type: "code",
issuer: "https://login.microsoftonline.com/<YOUR-TENANT-ID>/v2.0",
client_auth_method: "query",
discovery: true,
uid_field: "sub",
send_scope_to_token_endpoint: "false",
client_options: {
identifier: "<YOUR APP CLIENT ID>",
secret: "<YOUR APP CLIENT SECRET>",
redirect_uri: "https://gitlab.example.com/users/auth/azure_oauth2/callback"
}
}
}
]
```
:::Azure Active Directory v2
```ruby
gitlab_rails['omniauth_providers'] = [
{
name: "azure_oauth2",
label: "Azure OIDC", # optional label for login button, defaults to "Openid Connect"
args: {
name: "azure_activedirectory_v2",
strategy_class: "OmniAuth::Strategies::OpenIDConnect",
scope: ["openid", "profile", "email"],
response_type: "code",
issuer: "https://login.microsoftonline.com/<YOUR-TENANT-ID>/v2.0",
client_auth_method: "query",
discovery: true,
uid_field: "oid",
send_scope_to_token_endpoint: "false",
client_options: {
identifier: "<YOUR APP CLIENT ID>",
secret: "<YOUR APP CLIENT SECRET>",
redirect_uri: "https://gitlab.example.com/users/auth/azure_activedirectory_v2/callback"
}
}
}
]
```
::EndTabs
### Configure Microsoft Azure Active Directory B2C
GitLab requires special
@ -610,7 +682,7 @@ You can configure your application to use multiple OpenID Connect (OIDC) provide
You should do this in either of the following scenarios:
- [Migrating to the OpenID Connect protocol](../../integration/azure.md#migrate-to-the-openid-connect-protocol).
- [Migrating to the OpenID Connect protocol](#migrate-to-generic-openid-connect-configuration).
- Offering different levels of authentication.
NOTE:

View File

@ -192,6 +192,33 @@ If something unexpected happens during the migration, it is safe to start over.
1. Configure GitLab to [use multiple databases](#set-up-multiple-databases).
### Existing Linux package installations using streaming replication
To reduce downtime, you can set up streaming replication to migrate existing data from the `main` database to the `ci` database.
This procedure results in two database clusters.
This procedure can be both time- and resource-consuming.
Consider their trade-offs with availability before executing it.
To set up streaming replication for creating two database clusters:
1. Set up streaming replication from the GitLab database to new database instance.
1. When the new replica has caught up, [disable background migrations](../../development/database/batched_background_migrations.md#enable-or-disable-background-migrations).
1. [Ensure all background migrations are finished](../../update/background_migrations.md#check-the-status-of-batched-background-migrations).
1. Stop GitLab, except for PostgreSQL:
```shell
sudo gitlab-ctl stop
sudo gitlab-ctl start postgresql
```
1. After the replication is complete, stop the streaming replication, and promote the replica to a primary instance.
You now have two database clusters, one for `main`, and one for `ci`.
1. Configure GitLab to [use multiple databases](#set-up-multiple-databases).
For more information on how to set up Streaming Replication,
see [PostgreSQL replication and failover for Linux package installations](replication_and_failover.md).
## Set up multiple databases
To configure GitLab to use multiple application databases, follow the instructions below for your installation type.

View File

@ -477,6 +477,24 @@ Fields related to Instance Security Dashboard.
Returns [`InstanceSecurityDashboard`](#instancesecuritydashboard).
### `Query.integrationExclusions`
DETAILS:
**Introduced** in GitLab 17.0.
**Status**: Experiment.
Returns [`IntegrationExclusionConnection`](#integrationexclusionconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#pagination-arguments):
`before: String`, `after: String`, `first: Int`, and `last: Int`.
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="queryintegrationexclusionsintegrationname"></a>`integrationName` | [`IntegrationType!`](#integrationtype) | Type of integration. |
### `Query.issue`
Find an issue.
@ -5428,6 +5446,54 @@ Input type: `InstanceGoogleCloudLoggingConfigurationUpdateInput`
| <a id="mutationinstancegooglecloudloggingconfigurationupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationinstancegooglecloudloggingconfigurationupdateinstancegooglecloudloggingconfiguration"></a>`instanceGoogleCloudLoggingConfiguration` | [`InstanceGoogleCloudLoggingConfigurationType`](#instancegooglecloudloggingconfigurationtype) | configuration updated. |
### `Mutation.integrationExclusionCreate`
DETAILS:
**Introduced** in GitLab 17.0.
**Status**: Experiment.
Input type: `IntegrationExclusionCreateInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationintegrationexclusioncreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationintegrationexclusioncreateintegrationname"></a>`integrationName` | [`IntegrationType!`](#integrationtype) | Type of integration to exclude. |
| <a id="mutationintegrationexclusioncreateprojectids"></a>`projectIds` | [`[ProjectID!]!`](#projectid) | Ids of projects to exclude. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationintegrationexclusioncreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationintegrationexclusioncreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationintegrationexclusioncreateexclusions"></a>`exclusions` | [`[IntegrationExclusion!]`](#integrationexclusion) | Integration exclusions created by the mutation. |
### `Mutation.integrationExclusionDelete`
DETAILS:
**Introduced** in GitLab 17.0.
**Status**: Experiment.
Input type: `IntegrationExclusionDeleteInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationintegrationexclusiondeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationintegrationexclusiondeleteintegrationname"></a>`integrationName` | [`IntegrationType!`](#integrationtype) | Type of integration. |
| <a id="mutationintegrationexclusiondeleteprojectids"></a>`projectIds` | [`[ProjectID!]!`](#projectid) | Id of excluded project. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationintegrationexclusiondeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationintegrationexclusiondeleteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationintegrationexclusiondeleteexclusions"></a>`exclusions` | [`[IntegrationExclusion!]`](#integrationexclusion) | Project no longer excluded due to the mutation. |
### `Mutation.issuableResourceLinkCreate`
Input type: `IssuableResourceLinkCreateInput`
@ -12526,6 +12592,29 @@ The edge type for [`InstanceGoogleCloudLoggingConfigurationType`](#instancegoogl
| <a id="instancegooglecloudloggingconfigurationtypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="instancegooglecloudloggingconfigurationtypeedgenode"></a>`node` | [`InstanceGoogleCloudLoggingConfigurationType`](#instancegooglecloudloggingconfigurationtype) | The item at the end of the edge. |
#### `IntegrationExclusionConnection`
The connection type for [`IntegrationExclusion`](#integrationexclusion).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="integrationexclusionconnectionedges"></a>`edges` | [`[IntegrationExclusionEdge]`](#integrationexclusionedge) | A list of edges. |
| <a id="integrationexclusionconnectionnodes"></a>`nodes` | [`[IntegrationExclusion]`](#integrationexclusion) | A list of nodes. |
| <a id="integrationexclusionconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
#### `IntegrationExclusionEdge`
The edge type for [`IntegrationExclusion`](#integrationexclusion).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="integrationexclusionedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="integrationexclusionedgenode"></a>`node` | [`IntegrationExclusion`](#integrationexclusion) | The item at the end of the edge. |
#### `IssuableResourceLinkConnection`
The connection type for [`IssuableResourceLink`](#issuableresourcelink).
@ -22949,6 +23038,16 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| <a id="instancesecuritydashboardvulnerabilityseveritiescountseverity"></a>`severity` | [`[VulnerabilitySeverity!]`](#vulnerabilityseverity) | Filter vulnerabilities by severity. |
| <a id="instancesecuritydashboardvulnerabilityseveritiescountstate"></a>`state` | [`[VulnerabilityState!]`](#vulnerabilitystate) | Filter vulnerabilities by state. |
### `IntegrationExclusion`
An integration to override the level settings of instance specific integrations.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="integrationexclusionproject"></a>`project` | [`Project`](#project) | Project that has been excluded from the instance specific integration. |
### `IssuableResourceLink`
Describes an issuable resource link for incident issues.
@ -33410,6 +33509,14 @@ Import source.
| <a id="importsourcemanifest"></a>`MANIFEST` | Imported from Manifest. |
| <a id="importsourcenone"></a>`NONE` | Not imported. |
### `IntegrationType`
Integration Names.
| Value | Description |
| ----- | ----------- |
| <a id="integrationtypebeyond_identity"></a>`BEYOND_IDENTITY` | Beyond Identity. |
### `IssuableResourceLinkType`
Issuable resource link type enum.

View File

@ -172,6 +172,39 @@ You can use any version supported by the component, but using a version publishe
to the CI/CD catalog is recommended. The version referenced with a commit SHA or branch name
might not be published in the CI/CD catalog, but could be used for testing.
#### Semantic version ranges
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/450835) in GitLab 16.11
When [referencing a CI/CD catalog component](#component-versions), you can use a
special format to specify the latest [semantic version](#semantic-versioning) in a range.
To specify the latest release of:
- A minor version, use both the major and minor version numbers in the reference,
but not the patch version number. For example, use `1.1` to use the latest version
that starts with `1.1`, including `1.1.0` or `1.1.9`, but not `1.2.0`.
- A major version, use only the major version number in the reference. For example,
use `1` to use the latest version that starts with `1.`, like `1.0.0` or `1.9.9`,
but not `2.0.0`.
- All versions, use `~latest` to use the latest released version.
For example, a component is released in this exact order:
1. `1.0.0`
1. `1.1.0`
1. `2.0.0`
1. `1.1.1`
1. `1.2.0`
1. `2.1.0`
1. `2.0.1`
In this example, referencing the component with:
- `1` would use the `1.2.0` version.
- `1.1` would use the `1.1.1` version.
- `~latest` would use the `2.1.0` version.
## CI/CD Catalog
DETAILS:
@ -280,39 +313,6 @@ for communicating that a change is a major, minor, patch, or other kind of chang
For example, `1.0.0`, `2.3.4`, and `1.0.0-alpha` are all valid semantic versions.
##### Semantic version ranges
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/450835) in GitLab 16.11
When [referencing a CI/CD catalog component](#component-versions), you can use a
special format to specify the latest version in a range.
To specify the latest release of:
- A minor version, use both the major and minor version numbers in the reference,
but not the patch version number. For example, use `1.1` to use the latest version
that starts with `1.1`, including `1.1.0` or `1.1.9`, but not `1.2.0`.
- A major version, use only the major version number in the reference. For example,
use `1` to use the latest version that starts with `1.`, like `1.0.0` or `1.9.9`,
but not `2.0.0`.
- All versions, use `~latest` to use the latest released version.
For example, a component is released in this exact order:
1. `1.0.0`
1. `1.1.0`
1. `2.0.0`
1. `1.1.1`
1. `1.2.0`
1. `2.1.0`
1. `2.0.1`
In this example, referencing the component with:
- `1` would use the `1.2.0` version.
- `1.1` would use the `1.1.1` version.
- `~latest` would use the `2.1.0` version.
### Unpublish a component project
To remove a component project from the catalog, turn off the [**CI/CD Catalog resource**](#set-a-component-project-as-a-catalog-project)

View File

@ -13,8 +13,12 @@ which itself includes files under
for easier maintenance.
We're striving to [dogfood](https://handbook.gitlab.com/handbook/engineering/development/principles/#dogfooding)
GitLab [CI/CD features and best-practices](../../ci/index.md)
as much as possible.
GitLab [CI/CD features and best-practices](../../ci/index.md) as much as possible.
Do not use [CI/CD components](../../ci/components/index.md) in `gitlab-org/gitlab` pipelines
unless they are mirrored on the `dev.gitlab.com` instance. CI/CD components do not work across different instances,
and [cause failing pipelines](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/17683#note_1795756077)
on the `dev.gitlab.com` mirror if they do not exist on that instance.
## Predictive test jobs before a merge request is approved

View File

@ -58,6 +58,27 @@ To update Elastic index mappings, apply the configuration to the respective file
Migrations can be built with a retry limit and have the ability to be [failed and marked as halted](https://gitlab.com/gitlab-org/gitlab/-/blob/66e899b6637372a4faf61cfd2f254cbdd2fb9f6d/ee/lib/elastic/migration.rb#L40).
Any data or index cleanup needed to support migration retries should be handled in the migration.
### Skipped migrations
You can skip a migration by adding a `skip_if` proc which evaluates to `true` or `false`:
```ruby
class MigrationName < Elastic::Migration
skip_if ->() { true|false }
```
The migration is executed only if the condition is `false`. Skipped migrations will not be shown as part of pending migrations.
Skipped migrations can be marked as obsolete, but the `skip_if` condition must be kept so that these migrations are always skipped.
Once a skipped migration is obsolete, the only way to apply the change is by [recreating the index from scratch](../../integration/advanced_search/elasticsearch_troubleshooting.md#last-resort-to-recreate-an-index).
Update the skipped migration's documentation file with the following attributes:
```yaml
skippable: true
skip_condition: '<description>'
```
### Migration helpers
The following migration helpers are available in `ee/app/workers/concerns/elastic/`:
@ -176,6 +197,8 @@ class MigrationName < Elastic::Migration
end
```
When marking a skippable migration as obsolete, you must keep the `skip_if` condition.
#### `Elastic::MigrationCreateIndex`
Creates a new index.
@ -455,6 +478,7 @@ being upgraded to, we do the following:
include Elastic::MigrationObsolete
```
1. When marking a skippable migration as obsolete, keep the `skip_if` condition.
1. Delete any spec files to support this migration.
1. Verify that there are no references of the migration in the `.rubocop_todo/` directory.
1. Remove any logic handling backwards compatibility for this migration. You

View File

@ -655,6 +655,14 @@ any pending migrations that have been removed in the new version cannot be execu
In this case, you must
[re-create your index from scratch](elasticsearch_troubleshooting.md#last-resort-to-recreate-an-index).
### Skippable migrations
Skippable migrations are only executed when a condition is met.
For example, if a migration depends on a specific version of Elasticsearch, it could be skipped until that version is reached.
If a skippable migration is not executed by the time the migration is marked as obsolete, to apply the change you must
[re-create the index](elasticsearch_troubleshooting.md#last-resort-to-recreate-an-index).
## GitLab advanced search Rake tasks
Rake tasks are available to:

View File

@ -11,164 +11,7 @@ DETAILS:
**Offering:** Self-managed
You can enable the Microsoft Azure OAuth 2.0 OmniAuth provider and sign in to
GitLab with your Microsoft Azure credentials. You can configure the provider that uses
[the earlier Azure Active Directory v1.0 endpoint](https://learn.microsoft.com/en-us/previous-versions/azure/active-directory/azuread-dev/v1-protocols-oauth-code),
or the provider that uses the v2.0 endpoint.
NOTE:
For new projects, Microsoft suggests you use the
[OpenID Connect protocol](../administration/auth/oidc.md#configure-microsoft-azure),
which uses the Microsoft identity platform (v2.0) endpoint.
## Migrate to the OpenID Connect protocol
To migrate to the OpenID Connect protocol, see [configure multiple OpenID Connect providers](../administration/auth/oidc.md#configure-multiple-openid-connect-providers).
You must set the `uid_field`, which differs across the providers:
| Provider | `uid` | Remarks |
|-----------------------------------------------------------------------------------------------------------------|-------|-----------------------------------------------------------------------|
| [`omniauth-azure-oauth2`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/vendor/gems/omniauth-azure-oauth2) | `sub` | Additional attributes `oid`, `tid` are offered within the info object |
| [`omniauth-azure-activedirectory-v2`](https://github.com/RIPAGlobal/omniauth-azure-activedirectory-v2/) | `oid` | You must configure `oid` as `uid_field` when migrating |
| [`omniauth_openid_connect`](https://github.com/omniauth/omniauth_openid_connect/) | `sub` | Specify `uid_field` to use another field |
To migrate from `omniauth-azure-oauth2` to `omniauth_openid_connect` you
must change the configuration.
::Tabs
:::TabTitle Linux package (Omnibus)
Remove some of the existing configuration and add new configuration as shown.
```diff
gitlab_rails['omniauth_providers'] = [
{
name: "azure_oauth2",
# label: "Provider name", # optional label for login button, defaults to "Azure AD"
args: {
+ name: "azure_oauth2",
+ strategy_class: "OmniAuth::Strategies::OpenIDConnect",
+ scope: ["openid", "profile", "email"],
+ response_type: "code",
+ issuer: "https://login.microsoftonline.com/<tenant_id>/v2.0",
+ client_auth_method: "query",
+ discovery: true,
+ uid_field: "sub",
+ client_options: {
+ identifier: "<client_id>",
+ secret: "<client_secret>",
+ redirect_uri: "https://gitlab.example.com/users/auth/azure_oauth2/callback"
+ }
- client_id: "<client_id>",
- client_secret: "<client_secret>",
- tenant_id: "<tenant_id>",
}
}
]
```
:::TabTitle Self-compiled (source)
Remove some of the existing configuration and add new configuration as shown.
```diff
- { name: 'azure_oauth2',
# label: 'Provider name', # optional label for login button, defaults to "Azure AD"
- args: { client_id: '<client_id>',
- client_secret: '<client_secret>',
- tenant_id: '<tenant_id>' } }
+ icon: "<custom_provider_icon>",
+ args: {
+ name: "azure_oauth2",
+ strategy_class: "OmniAuth::Strategies::OpenIDConnect",
+ scope: ["openid","profile","email"],
+ response_type: "code",
+ issuer: 'https://login.microsoftonline.com/<tenant_id>/v2.0',
+ discovery: true,
+ client_auth_method: 'query',
+ uid_field: 'sub',
+ send_scope_to_token_endpoint: "false",
+ client_options: {
+ identifier: "<client_id>",
+ secret: "<client_secret>",
+ redirect_uri: "<your_gitlab_url>/users/auth/azure_oauth2/callback"
+ }
+ }
}
```
::EndTabs
To migrate for example from `omniauth-azure-activedirectory-v2` to `omniauth_openid_connect` you
must change the configuration.
::Tabs
:::TabTitle Linux package (Omnibus)
Remove some of the existing configuration and add new configuration as shown.
```diff
gitlab_rails['omniauth_providers'] = [
{
- name: "azure_activedirectory_v2",
# label: "Provider name", # optional label for login button, defaults to "Azure AD v2"
args: {
+ name: "azure_activedirectory_v2",
+ strategy_class: "OmniAuth::Strategies::OpenIDConnect",
+ scope: ["openid", "profile", "email"],
+ response_type: "code",
+ issuer: "https://login.microsoftonline.com/<tenant_id>/v2.0",
+ client_auth_method: "query",
+ discovery: true,
+ uid_field: "oid",
+ client_options: {
+ identifier: "<client_id>",
+ secret: "<client_secret>",
+ redirect_uri: "https://gitlab.example.com/users/auth/azure_activedirectory_v2/callback"
+ }
- client_id: "<client_id>",
- client_secret: "<client_secret>",
- tenant_id: "<tenant_id>",
}
}
]
```
:::TabTitle Self-compiled (source)
Remove some of the existing configuration and add new configuration as shown.
```diff
- { name: 'azure_activedirectory_v2',
# label: 'Provider name', # optional label for login button, defaults to "Azure AD v2"
- args: { client_id: '<client_id>',
- client_secret: '<client_secret>',
- tenant_id: '<tenant_id>' } }
+ icon: "<custom_provider_icon>",
+ args: {
+ name: "azure_activedirectory_v2",
+ strategy_class: "OmniAuth::Strategies::OpenIDConnect",
+ scope: ["openid","profile","email"],
+ response_type: "code",
+ issuer: 'https://login.microsoftonline.com/<tenant_id>/v2.0',
+ discovery: true,
+ client_auth_method: 'query',
+ uid_field: 'oid',
+ send_scope_to_token_endpoint: "false",
+ client_options: {
+ identifier: "<client_id>",
+ secret: "<client_secret>",
+ redirect_uri: "<your_gitlab_url>/users/auth/azure_activedirectory_v2/callback"
+ }
+ }
}
```
::EndTabs
For more information on other customizations, see [`gitlab_username_claim`](omniauth.md#per-provider-configuration).
GitLab with your Microsoft Azure credentials.
## Register an Azure application
@ -180,9 +23,7 @@ an Azure application and get a client ID and secret key.
1. [Register an application](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app)
and provide the following information:
- The redirect URI, which requires the URL of the Azure OAuth callback of your GitLab
installation. For example:
- For the v1.0 endpoint: `https://gitlab.example.com/users/auth/azure_oauth2/callback`.
- For the v2.0 endpoint: `https://gitlab.example.com/users/auth/azure_activedirectory_v2/callback`.
installation. `https://gitlab.example.com/users/auth/azure_activedirectory_v2/callback`.
- The application type, which must be set to **Web**.
1. Save the client ID and client secret. The client secret is only
displayed once.
@ -195,7 +36,7 @@ In some Microsoft documentation, the terms are named `Application ID` and
## Add API permissions (scopes)
If you're using the v2.0 endpoint, after you create the application, [configure it to expose a web API](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-configure-app-expose-web-apis).
After you create the application, [configure it to expose a web API](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-configure-app-expose-web-apis).
Add the following delegated permissions under the Microsoft Graph API:
- `email`
@ -206,6 +47,11 @@ Alternatively, add the `User.Read.All` application permission.
## Enable Microsoft OAuth in GitLab
NOTE:
For new projects, you should use the
[OpenID Connect protocol](../administration/auth/oidc.md#configure-microsoft-azure),
which uses the Microsoft identity platform (v2.0) endpoint.
1. On your GitLab server, open the configuration file.
- For Linux package installations:
@ -223,7 +69,7 @@ Alternatively, add the `User.Read.All` application permission.
```
1. Configure the [common settings](omniauth.md#configure-common-settings)
to add `azure_oauth2` as a single sign-on provider. This enables Just-In-Time
to add `azure_activedirectory_v2` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration. Replace `<client_id>`, `<client_secret>`, and `<tenant_id>`
@ -231,24 +77,6 @@ Alternatively, add the `User.Read.All` application permission.
- For Linux package installations:
For the v1.0 endpoint:
```ruby
gitlab_rails['omniauth_providers'] = [
{
name: "azure_oauth2",
# label: "Provider name", # optional label for login button, defaults to "Azure AD"
args: {
client_id: "<client_id>",
client_secret: "<client_secret>",
tenant_id: "<tenant_id>",
}
}
]
```
For the v2.0 endpoint:
```ruby
gitlab_rails['omniauth_providers'] = [
{
@ -261,9 +89,10 @@ Alternatively, add the `User.Read.All` application permission.
}
}
]
```
For [alternative Azure clouds](https://learn.microsoft.com/en-us/entra/identity-platform/authentication-national-cloud),
- For [alternative Azure clouds](https://learn.microsoft.com/en-us/entra/identity-platform/authentication-national-cloud),
configure `base_azure_url` under the `args` section. For example, for Azure Government Community Cloud (GCC):
```ruby
@ -283,16 +112,6 @@ Alternatively, add the `User.Read.All` application permission.
- For self-compiled installations:
For the v1.0 endpoint:
```yaml
- { name: 'azure_oauth2',
# label: 'Provider name', # optional label for login button, defaults to "Azure AD"
args: { client_id: '<client_id>',
client_secret: '<client_secret>',
tenant_id: '<tenant_id>' } }
```
For the v2.0 endpoint:
```yaml

View File

@ -49,6 +49,20 @@ After you purchase GitLab Duo Pro, you can assign seats to billable users to gra
To use Code Suggestions in any project or group, a user must be assigned a seat in at least one top-level group.
#### Enable automatic assignment of new users
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/13637) in GitLab 17.0 [with a flag](../administration/feature_flags.md) named `auto_assign_gitlab_duo_pro_seats`.
You can enable automatic assignment of GitLab Duo Pro seats for new users. When this feature is enabled,
any member added to a top-level group, subgroup, or project is automatically allocated a GitLab Duo Pro
seat if one is available.
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Locate **GitLab Duo Pro seats**.
1. Select the **Automatic assignment of GitLab Duo Pro seats** checkbox.
### For self-managed
Prerequisites:
@ -69,7 +83,7 @@ Prerequisites:
For self-managed instances, to enable GitLab Duo features,
You must [enable network connectivity](../user/ai_features_enable.md#configure-gitlab-duo-on-a-self-managed-instance).
## Assign and remove seats in bulk
## Assign and remove GitLab Duo Pro seats in bulk
You can assign or remove seats in bulk for multiple users.

View File

@ -537,6 +537,7 @@ If you find a bug, [comment on the feedback issue](https://gitlab.com/gitlab-org
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139394) in GitLab 16.7.
> - Adding related items by entering their URLs and IDs [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/427594) in GitLab 16.8.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/150148) in GitLab 17.0. Feature flag `linked_work_items` removed.
> - [Changed](https://gitlab.com/groups/gitlab-org/-/epics/10267) minimum required role from Reporter (if true) to Guest in GitLab 17.0.
Linked items are a bi-directional relationship and appear in a block below
the Child objectives and key results. You can link an objective, key result, or a task in the same project with each other.

View File

@ -237,6 +237,15 @@ It also demonstrates how to manage a semantic version for the generic package: s
## Troubleshooting
### HTTP 403 errors
You might get a `HTTP 403 Forbidden` error. This error happens when either:
- You don't have access to a resource.
- The package registry is not enabled for the project.
To resolve the issue, ensure the package registry is enabled, and you have permission to access it.
### Internal Server error on large file uploads to S3
S3-compatible object storage [limits the size of a single PUT request to 5 GB](https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html). If the `aws_signature_version` is set to `2` in the [object storage connection settings](../../../administration/object_storage.md), attempting to publish a package file larger than the 5 GB limit can result in a `HTTP 500: Internal Server Error` response.

View File

@ -76,12 +76,16 @@ NOTE:
## Delete emails from your user profile
> - Automatic deletion of unverified secondary email addresses [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151562) in GitLab 17.0.
You can delete a secondary email address from your account. You cannot delete your
primary email address.
If the deleted email address is used for any user emails, those user emails are
sent to the primary email address instead.
Unverified secondary email addresses are automatically deleted after three days.
NOTE:
Because of [issue 438600](https://gitlab.com/gitlab-org/gitlab/-/issues/438600), group notifications are still sent to
the deleted email address.

View File

@ -135,9 +135,21 @@ Prerequisites:
Use the groups API to [rotate the personal access token](../../api/groups.md#rotate-a-personal-access-token-for-service-account-user) for a service account user.
### Delete a service account
Prerequisites:
- You must be an administrator for the instance the service account is associated with.
To delete a service account, [use the API to delete the service account user](../../api/users.md#user-deletion).
### Disable a service account
You cannot directly disable or delete a service account. Instead, you must:
Prerequisites:
- You must have the Owner role for the group the service account is associated with.
If you are not an administrator for the instance or group a service account is associated with, you cannot directly delete that service account. Instead:
1. Remove the service account as a member of all subgroups and projects:

View File

@ -10,6 +10,8 @@ DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - [Changed](https://gitlab.com/groups/gitlab-org/-/epics/10267) minimum required role from Reporter (if true) to Guest in GitLab 17.0.
Linked issues are a bi-directional relationship between any two issues and appear in a block below
the issue description. You can link issues in different projects.

View File

@ -541,6 +541,7 @@ If you find a bug, [comment on the feedback issue](https://gitlab.com/gitlab-org
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139394) in GitLab 16.7.
> - Adding related items by entering their URLs and IDs [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/427594) in GitLab 16.8.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/150148) in GitLab 17.0. Feature flag `linked_work_items` removed.
> - [Changed](https://gitlab.com/groups/gitlab-org/-/epics/10267) minimum required role from Reporter (if true) to Guest in GitLab 17.0.
Linked items are a bi-directional relationship and appear in a block below
the emoji reactions section. You can link an objective, key result, or a task in the same project with each other.

View File

@ -26,7 +26,8 @@ module BulkImports
members_mapper: members_mapper,
object_builder: object_builder,
user: context.current_user,
excluded_keys: import_export_config.relation_excluded_keys(key)
excluded_keys: import_export_config.relation_excluded_keys(key),
import_source: Import::SOURCE_DIRECT_TRANSFER
)
end

View File

@ -6,7 +6,7 @@ module Gitlab
class BaseHandler
attr_reader :mail, :mail_key
HANDLER_ACTION_BASE_REGEX ||= /(?<project_slug>.+)-(?<project_id>\d+)/
HANDLER_ACTION_BASE_REGEX = /(?<project_slug>.+)-(?<project_id>\d+)/
def initialize(mail, mail_key)
@mail = mail

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