Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
1efcb3739b
commit
c5cd0c605e
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
# Cop supports --autocorrect.
|
||||
Lint/OrAssignmentToConstant:
|
||||
Exclude:
|
||||
- 'lib/gitlab/email/handler/base_handler.rb'
|
||||
- 'tooling/danger/project_helper.rb'
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
# Cop supports --autocorrect.
|
||||
Lint/RedundantStringCoercion:
|
||||
Exclude:
|
||||
- 'ee/bin/geo_log_cursor'
|
||||
- 'ee/db/fixtures/development/31_devops_adoption.rb'
|
||||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export default CodeBlockHighlight.extend({
|
|||
return [
|
||||
{
|
||||
priority: PARSE_HTML_PRIORITY_HIGHEST,
|
||||
tag: 'pre[lang="suggestion"]',
|
||||
tag: 'pre[data-canonical-lang="suggestion"]',
|
||||
},
|
||||
];
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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' }),
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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' },
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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? },
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module Ci
|
|||
|
||||
PARTITIONABLE_MODELS = %w[
|
||||
CommitStatus
|
||||
Ci::BuildExecutionConfig
|
||||
Ci::BuildMetadata
|
||||
Ci::BuildName
|
||||
Ci::BuildNeed
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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') }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) %>
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
3fd334e0639a0cc383f603738001b1a4b5bfbc94092e56c01040cbfbf515ae76
|
||||
|
|
@ -0,0 +1 @@
|
|||
f86ec5ddd56086044f26214622b2a656d21a8e258cdb24923063c3e046375cad
|
||||
|
|
@ -0,0 +1 @@
|
|||
324cf74a398ab88fd61018cd6bdea3ef699e91485e34a5fd02850644e9832187
|
||||
|
|
@ -0,0 +1 @@
|
|||
091e3d00d140167fc7dba73fe46cc8df642bc1ca70b9741f0c0f8db38daea888
|
||||
|
|
@ -0,0 +1 @@
|
|||
393c51beee226eadf2e9d4c5142669e2efb8f7a445bd18d6e6121727d241d9ac
|
||||
|
|
@ -0,0 +1 @@
|
|||
43e1ebef09400b5199d9d2e1bb906bab62ee8530cbd8a785f2068f5f9b2f55d1
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue