Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b377f6d091
commit
f731c095d6
|
|
@ -5,7 +5,7 @@ workflow:
|
|||
name: $PIPELINE_NAME
|
||||
|
||||
include:
|
||||
- component: "gitlab.com/gitlab-org/quality/pipeline-common/allure-report@8.15.0"
|
||||
- component: "gitlab.com/gitlab-org/quality/pipeline-common/allure-report@8.15.1"
|
||||
inputs:
|
||||
job_name: "e2e-test-report"
|
||||
job_stage: "report"
|
||||
|
|
@ -15,7 +15,7 @@ include:
|
|||
gitlab_auth_token_variable_name: "PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE"
|
||||
allure_job_name: "${QA_RUN_TYPE}"
|
||||
- project: gitlab-org/quality/pipeline-common
|
||||
ref: 8.15.0
|
||||
ref: 8.15.1
|
||||
file:
|
||||
- /ci/base.gitlab-ci.yml
|
||||
- /ci/knapsack-report.yml
|
||||
|
|
@ -44,6 +44,12 @@ stages:
|
|||
BUNDLE_SILENCE_ROOT_WARNING: "true"
|
||||
BUNDLE_WITHOUT: development
|
||||
|
||||
.qa-run-e2e-with-bundler:
|
||||
script:
|
||||
- source $CI_PROJECT_DIR/scripts/utils.sh
|
||||
- source $CI_PROJECT_DIR/scripts/rspec_helpers.sh
|
||||
- run_e2e_specs "${QA_GITLAB_URL}" "${QA_TESTS}" "${QA_RSPEC_TAGS}"
|
||||
|
||||
.qa-install:
|
||||
extends:
|
||||
- .bundler-variables
|
||||
|
|
|
|||
|
|
@ -16,4 +16,4 @@ variables:
|
|||
QA_OMNIBUS_MR_TESTS: "only-smoke"
|
||||
# Retry failed specs in separate process
|
||||
QA_RETRY_FAILED_SPECS: "true"
|
||||
GITLAB_HELM_CHART_REF: "d1eaee3922df2bfbdc23b55720965c10eec2b93d" # helm chart ref used by test-on-cng pipeline
|
||||
GITLAB_HELM_CHART_REF: "c7532b6e1ba98d5663b58012a879a781689db916" # helm chart ref used by test-on-cng pipeline
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ workflow:
|
|||
.cng-base:
|
||||
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/${BUILD_OS}-${OS_VERSION}-ruby-${RUBY_VERSION}:bundler-${BUNDLER_VERSION}-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}-kubectl-1.23-helm-3.14-kind-0.20
|
||||
stage: test
|
||||
extends: .qa-cache
|
||||
extends:
|
||||
- .qa-cache
|
||||
- .qa-run-e2e-with-bundler
|
||||
needs: [build-cng]
|
||||
tags: [e2e]
|
||||
services:
|
||||
|
|
@ -29,22 +31,19 @@ workflow:
|
|||
GITLAB_ADMIN_USERNAME: root
|
||||
GITLAB_ADMIN_PASSWORD: 5iveL!fe
|
||||
GITLAB_QA_ADMIN_ACCESS_TOKEN: $QA_ADMIN_ACCESS_TOKEN
|
||||
KNAPSACK_TEST_FILE_PATTERN: ""
|
||||
KNAPSACK_TEST_FILE_PATTERN: "" # overridden because currently selective test execution is skipped
|
||||
RSPEC_LAST_RUN_RESULTS_FILE: "$CI_PROJECT_DIR/qa/tmp/examples.txt"
|
||||
QA_DOCKER_NETWORK: host
|
||||
QA_GENERATE_ALLURE_REPORT: "true"
|
||||
QA_CAN_TEST_PRAEFECT: "false"
|
||||
QA_ALLOW_LOCAL_REQUESTS: "true"
|
||||
QA_SUITE_STATUS_ENV_FILE: $CI_PROJECT_DIR/suite_status.env
|
||||
QA_DISABLE_RSPEC_RETRY: "true"
|
||||
before_script:
|
||||
- echo "SUITE_RAN=true" > "$QA_SUITE_STATUS_ENV_FILE"
|
||||
# save extra values to be available for after_script if created dynamically
|
||||
- echo "${EXTRA_DEPLOY_VALUES}" > $CI_PROJECT_DIR/EXTRA_DEPLOY_VALUES
|
||||
- export GITLAB_DOMAIN="$(getent hosts docker | awk '{ print $1 }' | head -n1).nip.io"
|
||||
- export QA_GITLAB_URL="http://gitlab.${GITLAB_DOMAIN}"
|
||||
- source scripts/utils.sh
|
||||
- source scripts/rspec_helpers.sh
|
||||
- cd qa && bundle install
|
||||
- |
|
||||
bundle exec cng create deployment "${DEPLOYMENT_TYPE}" \
|
||||
|
|
@ -55,15 +54,6 @@ workflow:
|
|||
--chart-sha "${GITLAB_HELM_CHART_REF}" \
|
||||
--ci \
|
||||
${EXTRA_DEPLOY_VALUES}
|
||||
script:
|
||||
- export QA_COMMAND="bundle exec bin/qa ${QA_SCENARIO:=Test::Instance::All} $QA_GITLAB_URL -- --force-color --order random --format documentation"
|
||||
- echo "Running - '$QA_COMMAND'"
|
||||
- |
|
||||
if eval "$QA_COMMAND --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml"; then
|
||||
echo "Test run finished successfully"
|
||||
else
|
||||
retry_failed_e2e_rspec_examples
|
||||
fi
|
||||
after_script:
|
||||
- |
|
||||
if [ "$CI_JOB_STATUS" == "failed" ]; then
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ include:
|
|||
- .qa-cache
|
||||
- .default-retry
|
||||
- .gitlab-qa-report
|
||||
- .qa-run-e2e-with-bundler
|
||||
stage: test
|
||||
services:
|
||||
- name: docker:${DOCKER_VERSION}-dind
|
||||
|
|
@ -66,26 +67,15 @@ include:
|
|||
QA_SUITE_STATUS_ENV_FILE: "$CI_PROJECT_DIR/suite_status.env"
|
||||
QA_DOCKER_NETWORK: host
|
||||
QA_DISABLE_RSPEC_RETRY: "true"
|
||||
QA_GITLAB_URL: http://gdk.test:3000
|
||||
GITLAB_QA_ADMIN_ACCESS_TOKEN: $QA_ADMIN_ACCESS_TOKEN
|
||||
GDK_URL: http://gdk.test:3000
|
||||
FF_NETWORK_PER_BUILD: "true"
|
||||
RSPEC_LAST_RUN_RESULTS_FILE: "$CI_PROJECT_DIR/qa/tmp/examples.txt"
|
||||
before_script:
|
||||
- echo "SUITE_RAN=true" > "$QA_SUITE_STATUS_ENV_FILE"
|
||||
- echo -e "\e[0Ksection_start:`date +%s`:install_gems[collapsed=true]\r\e[0KInstall gems"
|
||||
- source scripts/utils.sh
|
||||
- source scripts/rspec_helpers.sh
|
||||
- cd qa && bundle install
|
||||
- echo -e "\e[0Ksection_end:`date +%s`:install_gems\r\e[0K"
|
||||
script:
|
||||
- export QA_COMMAND="bundle exec bin/qa ${QA_SCENARIO:=Test::Instance::All} $GDK_URL $GITLAB_QA_OPTS -- $QA_TESTS --order random --force-color --format documentation --format QA::Support::JsonFormatter --out tmp/rspec-${CI_JOB_ID}-\${QA_RSPEC_RETRIED:-false}.json"
|
||||
- echo "Running - '$QA_COMMAND'"
|
||||
- |
|
||||
if eval "$QA_COMMAND --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml"; then
|
||||
echo "Test run finished successfully"
|
||||
else
|
||||
retry_failed_e2e_rspec_examples
|
||||
fi
|
||||
after_script:
|
||||
- !reference [.with-gdk-log, after_script]
|
||||
- !reference [.gitlab-qa-report, after_script]
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div
|
||||
class="board-add-new-list board gl-display-inline-block gl-h-full gl-align-top gl-white-space-normal gl-flex-shrink-0 gl-rounded-base gl-pl-2"
|
||||
class="board-add-new-list board gl-display-inline-block gl-h-full gl-align-top gl-whitespace-normal gl-flex-shrink-0 gl-rounded-base gl-pl-2"
|
||||
data-testid="board-add-new-column"
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export default {
|
|||
'board-type-assignee': list.listType === 'assignee',
|
||||
}"
|
||||
:data-list-id="list.id"
|
||||
class="board gl-display-inline-block gl-h-full gl-px-3 gl-align-top gl-white-space-normal is-expandable"
|
||||
class="board gl-display-inline-block gl-h-full gl-px-3 gl-align-top gl-whitespace-normal is-expandable"
|
||||
data-testid="board-list"
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ export default {
|
|||
:id="groupId(group)"
|
||||
:key="getGroupId(group)"
|
||||
data-testid="stage-column-group"
|
||||
class="gl-relative gl-white-space-normal gl-pipeline-job-width gl-mb-2"
|
||||
class="gl-relative gl-whitespace-normal gl-pipeline-job-width gl-mb-2"
|
||||
@mouseenter="$emit('jobHover', group.name)"
|
||||
@mouseleave="$emit('jobHover', '')"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ export default {
|
|||
</div>
|
||||
<div
|
||||
v-safe-html="line.rich_text"
|
||||
class="gl-display-flex! gl-flex-direction-column gl-justify-content-center diff-td line_content left-side gl-white-space-normal!"
|
||||
class="gl-display-flex! gl-flex-direction-column gl-justify-content-center diff-td line_content left-side gl-whitespace-normal!"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ export default {
|
|||
v-for="strategy in featureFlag.strategies"
|
||||
:key="strategy.id"
|
||||
data-testid="strategy-label"
|
||||
class="gl-w-full gl-mr-3 gl-mt-2 gl-white-space-normal gl-text-left"
|
||||
class="gl-w-full gl-mr-3 gl-mt-2 gl-whitespace-normal gl-text-left"
|
||||
v-bind="strategyBadgeText(strategy)"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ class Admin::PlanLimitsController < Admin::ApplicationController
|
|||
ci_needs_size_limit
|
||||
ci_registered_group_runners
|
||||
ci_registered_project_runners
|
||||
dotenv_size
|
||||
dotenv_variables
|
||||
pipeline_hierarchy_size
|
||||
])
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,6 +21,18 @@ module IdeHelper
|
|||
)
|
||||
end
|
||||
|
||||
def show_web_ide_oauth_callback_mismatch_callout?
|
||||
return false unless ::Gitlab::WebIde::DefaultOauthApplication.feature_enabled?(current_user)
|
||||
|
||||
callback_urls = ::Gitlab::WebIde::DefaultOauthApplication.oauth_application_callback_urls
|
||||
callback_url_domains = callback_urls.map { |url| URI.parse(url).origin }
|
||||
callback_url_domains.any? && callback_url_domains.exclude?(request.base_url)
|
||||
end
|
||||
|
||||
def web_ide_oauth_application_id
|
||||
::Gitlab::WebIde::DefaultOauthApplication.oauth_application_id
|
||||
end
|
||||
|
||||
def use_new_web_ide?
|
||||
Feature.enabled?(:vscode_web_ide, current_user)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ module PlanLimitsHelper
|
|||
s_('AdminSettings|Maximum number of runners registered per group')
|
||||
when :ci_registered_project_runners
|
||||
s_('AdminSettings|Maximum number of runners registered per project')
|
||||
when :dotenv_size
|
||||
s_('AdminSettings|Maximum size of a dotenv artifact in bytes')
|
||||
when :dotenv_variables
|
||||
s_('AdminSettings|Maximum number of variables in a dotenv artifact')
|
||||
when :pipeline_hierarchy_size
|
||||
s_("AdminSettings|Maximum number of downstream pipelines in a pipeline's hierarchy tree")
|
||||
else
|
||||
|
|
|
|||
|
|
@ -343,6 +343,10 @@ class Integration < ApplicationRecord
|
|||
INSTANCE_SPECIFIC_INTEGRATION_NAMES
|
||||
end
|
||||
|
||||
def self.instance_specific_integration_types
|
||||
instance_specific_integration_names.map { |name| integration_name_to_type(name) }
|
||||
end
|
||||
|
||||
def self.dev_integration_names
|
||||
return [] unless Gitlab.dev_or_test_env?
|
||||
|
||||
|
|
@ -453,17 +457,37 @@ class Integration < ApplicationRecord
|
|||
end
|
||||
private_class_method :instance_level_integration
|
||||
|
||||
# Returns the number of successfully saved integrations
|
||||
# Duplicate integrations are excluded from this count by their validations.
|
||||
def self.create_from_active_default_integrations(owner, association)
|
||||
def self.default_integrations(owner, scope)
|
||||
group_ids = sorted_ancestors(owner).select(:id)
|
||||
array = group_ids.to_sql.present? ? "array(#{group_ids.to_sql})" : 'ARRAY[]'
|
||||
order = Arel.sql("type_new ASC, array_position(#{array}::bigint[], #{table_name}.group_id), instance DESC")
|
||||
|
||||
from_union([active.where(instance: true), active.where(group_id: group_ids, inherit_from_id: nil)])
|
||||
from_union([scope.where(instance: true), scope.where(group_id: group_ids, inherit_from_id: nil)])
|
||||
.order(order)
|
||||
.group_by(&:type)
|
||||
.count { |_type, parents| build_from_integration(parents.first, association => owner.id).save }
|
||||
.transform_values(&:first)
|
||||
end
|
||||
private_class_method :default_integrations
|
||||
|
||||
def self.create_from_default_integrations(owner, association)
|
||||
active_default_count = create_from_active_default_integrations(owner, association)
|
||||
default_instance_specific_count = create_from_default_instance_specific_integrations(owner, association)
|
||||
active_default_count + default_instance_specific_count
|
||||
end
|
||||
|
||||
# Returns the number of successfully saved integrations
|
||||
# Duplicate integrations are excluded from this count by their validations.
|
||||
def self.create_from_active_default_integrations(owner, association)
|
||||
default_integrations(
|
||||
owner,
|
||||
active.where.not(type: instance_specific_integration_types)
|
||||
).count { |_type, integration| build_from_integration(integration, association => owner.id).save }
|
||||
end
|
||||
|
||||
def self.create_from_default_instance_specific_integrations(owner, association)
|
||||
default_integrations(
|
||||
owner,
|
||||
where(type: instance_specific_integration_types)
|
||||
).count { |_type, integration| build_from_integration(integration, association => owner.id).save }
|
||||
end
|
||||
|
||||
def self.descendants_from_self_or_ancestors_from(integration)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ module Ci
|
|||
# rubocop: disable Database/AvoidUsingPluckWithoutLimit -- plucking on batch
|
||||
def execute
|
||||
keys = %i[build_id partition_id name project_id]
|
||||
pipeline.latest_builds.each_batch(of: 50) do |batch|
|
||||
pipeline.builds.latest.each_batch(of: 50) do |batch|
|
||||
builds_upsert_data =
|
||||
batch
|
||||
.pluck(:id, :partition_id, :name, :project_id)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ module Groups
|
|||
if @group.save
|
||||
@group.add_owner(current_user)
|
||||
@group.add_creator(current_user)
|
||||
Integration.create_from_active_default_integrations(@group, :group_id)
|
||||
Integration.create_from_default_integrations(@group, :group_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ module Groups
|
|||
|
||||
def update_integrations
|
||||
@group.integrations.with_default_settings.delete_all
|
||||
Integration.create_from_active_default_integrations(@group, :group_id)
|
||||
Integration.create_from_default_integrations(@group, :group_id)
|
||||
end
|
||||
|
||||
def propagate_integrations
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ module Projects
|
|||
Namespaces::ProjectNamespace.create_from_project!(@project) if @project.valid?
|
||||
|
||||
if @project.saved?
|
||||
Integration.create_from_active_default_integrations(@project, :project_id)
|
||||
Integration.create_from_default_integrations(@project, :project_id)
|
||||
|
||||
@project.create_labels unless @project.gitlab_project_import?
|
||||
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ module Projects
|
|||
|
||||
def update_integrations
|
||||
project.integrations.with_default_settings.delete_all
|
||||
Integration.create_from_active_default_integrations(project, :project_id)
|
||||
Integration.create_from_default_integrations(project, :project_id)
|
||||
end
|
||||
|
||||
def update_pending_builds
|
||||
|
|
|
|||
|
|
@ -93,6 +93,12 @@
|
|||
.form-group
|
||||
= f.label :ci_instance_level_variables, plan_limit_setting_description(:ci_instance_level_variables)
|
||||
= f.number_field :ci_instance_level_variables, class: 'form-control gl-form-input'
|
||||
.form-group
|
||||
= f.label :dotenv_size, plan_limit_setting_description(:dotenv_size)
|
||||
= f.number_field :dotenv_size, class: 'form-control gl-form-input'
|
||||
.form-group
|
||||
= f.label :dotenv_variables, plan_limit_setting_description(:dotenv_variables)
|
||||
= f.number_field :dotenv_variables, class: 'form-control gl-form-input'
|
||||
.form-group
|
||||
= f.label :ci_pipeline_size, plan_limit_setting_description(:ci_pipeline_size)
|
||||
= f.number_field :ci_pipeline_size, class: 'form-control gl-form-input'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
- return unless show_web_ide_oauth_callback_mismatch_callout?
|
||||
|
||||
= render Pajamas::AlertComponent.new(variant: :warning,
|
||||
title: s_('AdminArea|Current domain doesn\'t match the Web IDE OAuth configuration'),
|
||||
alert_options: { class: 'gl-mt-4' }) do |c|
|
||||
- c.with_body do
|
||||
= s_('AdminArea|The Web IDE OAuth application doesn\'t have a redirect URL with the domain that you are using to visit GitLab. This issue will prevent Web IDE users from authenticating and often occurs when using a reverse proxy.')
|
||||
- c.with_actions do
|
||||
= render Pajamas::ButtonComponent.new(variant: :confirm, href: edit_admin_application_path(web_ide_oauth_application_id), button_options: { class: 'deferred-link gl-alert-action', rel: 'noreferrer noopener' }) do
|
||||
= s_('AdminArea|Edit OAuth configuration')
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
= render_if_exists 'shared/submit_license_usage_data_banner'
|
||||
= render_if_exists 'shared/qrtly_reconciliation_alert'
|
||||
= render 'admin/dashboard/security_newsletter_callout'
|
||||
= render 'admin/dashboard/web_ide_oauth_callback_mismatch_callout'
|
||||
|
||||
- if show_transition_to_jihu_callout?
|
||||
.js-jh-transition-banner{ data: { feature_name: Users::CalloutsHelper::TRANSITION_TO_JIHU_CALLOUT,
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@
|
|||
= render Pajamas::ButtonComponent.new(variant: :confirm, category: :secondary, href: help_path, button_options: { class: "gl-flex-direction-column gl-flex-basis-third" }) do
|
||||
%span.gl-display-flex.gl-align-items-center.gl-m-3.gl-h-64
|
||||
= image_tag logo_path, alt: label, class: "gl-w-15 gl-max-h-full gl-max-w-full"
|
||||
%span.gl-white-space-normal
|
||||
%span.gl-whitespace-normal
|
||||
= label
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
%span.term.str-truncated= simple_search_highlight_and_truncate(milestone.title, @search_term)
|
||||
|
||||
- if milestone.project_milestone?
|
||||
.gl-mt-2= gl_badge_tag milestone.project.full_name, { variant: :muted }, { class: 'gl-white-space-normal gl-text-left' }
|
||||
.gl-mt-2= gl_badge_tag milestone.project.full_name, { variant: :muted }, { class: 'gl-whitespace-normal gl-text-left' }
|
||||
|
||||
- if milestone.description.present?
|
||||
.description.term
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@
|
|||
%div
|
||||
= render('shared/milestone_expired', milestone: milestone)
|
||||
- if milestone.group_milestone?
|
||||
= gl_badge_tag milestone.group.full_name, { variant: :info }, { class: 'gl-white-space-normal gl-text-left' }
|
||||
= gl_badge_tag milestone.group.full_name, { variant: :info }, { class: 'gl-whitespace-normal gl-text-left' }
|
||||
- if milestone.project_milestone?
|
||||
= gl_badge_tag milestone.project.full_name, { variant: :muted }, { class: 'gl-white-space-normal gl-text-left' }
|
||||
= gl_badge_tag milestone.project.full_name, { variant: :muted }, { class: 'gl-whitespace-normal gl-text-left' }
|
||||
|
||||
.order-3.order-md-2.mt-2.mt-md-0.milestone-progress{ class: can_admin_milestone ? 'col-md-4' : 'col-md-5' }
|
||||
= milestone_progress_bar(milestone)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
name: track_ai_metrics_in_usage_data
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/457504
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/155973
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/466664
|
||||
milestone: '17.1'
|
||||
group: group::optimize
|
||||
type: beta
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIssuesMilestoneAndIdIndexConcurrently < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.1'
|
||||
|
||||
INDEX_NAME = 'index_issues_on_milestone_id_and_id'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
# rubocop: disable Migration/PreventIndexCreation -- Replacing an existing index
|
||||
def up
|
||||
add_concurrent_index :issues, %i[milestone_id id], name: INDEX_NAME
|
||||
end
|
||||
# rubocop: enable Migration/PreventIndexCreation
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :issues, INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveIssuesMilestoneIndexConcurrently < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.1'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
remove_concurrent_index_by_name :issues, 'index_issues_on_milestone_id'
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index :issues, %i[milestone_id]
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveIndexIdentitiesOnProvider < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
|
||||
milestone '17.1'
|
||||
|
||||
INDEX_NAME = 'index_identities_on_provider'
|
||||
|
||||
def up
|
||||
remove_concurrent_index_by_name :identities, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index :identities, :provider, name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
3914eb6a992c6df54e74f24fb5c7890faaab0c46c27506e24840054704790b56
|
||||
|
|
@ -0,0 +1 @@
|
|||
1a01537566a911ff788e5345c806e58930e7f8d8348126df7a9490ffa4700fc3
|
||||
|
|
@ -0,0 +1 @@
|
|||
f8dc0c648771a938526d6b14d9967c352fad08547a939eb177c0e6639b727e52
|
||||
|
|
@ -26627,8 +26627,6 @@ CREATE INDEX index_historical_data_on_recorded_at ON historical_data USING btree
|
|||
|
||||
CREATE UNIQUE INDEX index_http_integrations_on_project_and_endpoint ON alert_management_http_integrations USING btree (project_id, endpoint_identifier);
|
||||
|
||||
CREATE INDEX index_identities_on_provider ON identities USING btree (provider);
|
||||
|
||||
CREATE INDEX index_identities_on_saml_provider_id ON identities USING btree (saml_provider_id) WHERE (saml_provider_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX index_identities_on_user_id ON identities USING btree (user_id);
|
||||
|
|
@ -26791,7 +26789,7 @@ CREATE INDEX index_issues_on_id_and_weight ON issues USING btree (id, weight);
|
|||
|
||||
CREATE INDEX index_issues_on_last_edited_by_id ON issues USING btree (last_edited_by_id);
|
||||
|
||||
CREATE INDEX index_issues_on_milestone_id ON issues USING btree (milestone_id);
|
||||
CREATE INDEX index_issues_on_milestone_id_and_id ON issues USING btree (milestone_id, id);
|
||||
|
||||
CREATE INDEX index_issues_on_moved_to_id ON issues USING btree (moved_to_id) WHERE (moved_to_id IS NOT NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -339,6 +339,37 @@ GitLab administrators can prevent this behavior:
|
|||
1. Clear the **Allow users with up to Guest role to create groups and personal projects** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Allow users to make their profiles private
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** Self-managed
|
||||
**Status:** Experiment
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/421310) in GitLab 17.1 [with a flag](../../administration/feature_flags.md) named `disallow_private_profiles`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
This feature is available for testing, but not ready for production use.
|
||||
|
||||
By default, users can make their profiles private.
|
||||
GitLab administrators can disable this setting to prevent users from making their profiles private:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||
1. Select **Settings > General**.
|
||||
1. Expand **Account and limit**.
|
||||
1. Clear the **Allow users to make their profiles private** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
NOTE:
|
||||
If this setting is disabled, [Set profiles of new users to private by default](#set-profiles-of-new-users-to-private-by-default) is also disabled.
|
||||
|
||||
WARNING:
|
||||
When this setting is disabled, it doesn't mark existing private profiles as public.
|
||||
GitLab administrators must manually update all existing private profiles back to public.
|
||||
For more information, see [issue 461701](https://gitlab.com/gitlab-org/gitlab/-/issues/461701).
|
||||
|
||||
## Set profiles of new users to private by default
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231301) in GitLab 15.8.
|
||||
|
|
@ -351,6 +382,9 @@ By default, newly created users have a public profile. GitLab administrators can
|
|||
1. Select the **Make new users' profiles private by default** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
NOTE:
|
||||
If [Allow users to make their profiles private](#allow-users-to-make-their-profiles-private) is disabled, this setting is also disabled.
|
||||
|
||||
## Prevent users from deleting their accounts
|
||||
|
||||
DETAILS:
|
||||
|
|
|
|||
|
|
@ -13407,6 +13407,54 @@ The edge type for [`MergeRequestReviewer`](#mergerequestreviewer).
|
|||
| <a id="mergerequestrevieweredgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="mergerequestrevieweredgenode"></a>`node` | [`MergeRequestReviewer`](#mergerequestreviewer) | The item at the end of the edge. |
|
||||
|
||||
#### `MergeTrainCarConnection`
|
||||
|
||||
The connection type for [`MergeTrainCar`](#mergetraincar).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergetraincarconnectioncount"></a>`count` | [`Int!`](#int) | Total count of collection. |
|
||||
| <a id="mergetraincarconnectionedges"></a>`edges` | [`[MergeTrainCarEdge]`](#mergetraincaredge) | A list of edges. |
|
||||
| <a id="mergetraincarconnectionnodes"></a>`nodes` | [`[MergeTrainCar]`](#mergetraincar) | A list of nodes. |
|
||||
| <a id="mergetraincarconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||
|
||||
#### `MergeTrainCarEdge`
|
||||
|
||||
The edge type for [`MergeTrainCar`](#mergetraincar).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergetraincaredgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="mergetraincaredgenode"></a>`node` | [`MergeTrainCar`](#mergetraincar) | The item at the end of the edge. |
|
||||
|
||||
#### `MergeTrainConnection`
|
||||
|
||||
The connection type for [`MergeTrain`](#mergetrain).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergetrainconnectioncount"></a>`count` | [`Int!`](#int) | Total count of collection. |
|
||||
| <a id="mergetrainconnectionedges"></a>`edges` | [`[MergeTrainEdge]`](#mergetrainedge) | A list of edges. |
|
||||
| <a id="mergetrainconnectionnodes"></a>`nodes` | [`[MergeTrain]`](#mergetrain) | A list of nodes. |
|
||||
| <a id="mergetrainconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||
|
||||
#### `MergeTrainEdge`
|
||||
|
||||
The edge type for [`MergeTrain`](#mergetrain).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergetrainedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="mergetrainedgenode"></a>`node` | [`MergeTrain`](#mergetrain) | The item at the end of the edge. |
|
||||
|
||||
#### `MilestoneConnection`
|
||||
|
||||
The connection type for [`Milestone`](#milestone).
|
||||
|
|
@ -25675,6 +25723,58 @@ four standard [pagination arguments](#pagination-arguments):
|
|||
| <a id="mergerequestreviewerworkspacesincludeactualstates"></a>`includeActualStates` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in GitLab 16.7. Use actual_states instead. |
|
||||
| <a id="mergerequestreviewerworkspacesprojectids"></a>`projectIds` | [`[ProjectID!]`](#projectid) | Filter workspaces by project GlobalIDs. |
|
||||
|
||||
### `MergeTrain`
|
||||
|
||||
Represents a set of cars/merge_requests queued for merging.
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergetraintargetbranch"></a>`targetBranch` | [`String!`](#string) | Target branch of the car's merge request. |
|
||||
|
||||
#### Fields with arguments
|
||||
|
||||
##### `MergeTrain.cars`
|
||||
|
||||
Cars queued in the train.
|
||||
|
||||
DETAILS:
|
||||
**Introduced** in GitLab 17.1.
|
||||
**Status**: Experiment.
|
||||
|
||||
Returns [`MergeTrainCarConnection!`](#mergetraincarconnection).
|
||||
|
||||
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="mergetraincarsactivitystatus"></a>`activityStatus` | [`MergeTrainStatus!`](#mergetrainstatus) | Filter cars by their high-level status. Defaults to ACTIVE. |
|
||||
|
||||
### `MergeTrainCar`
|
||||
|
||||
MergeTrainCar represents an attempt to merge a merge requestusing merge trains.
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergetraincarcreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of when the car was created. |
|
||||
| <a id="mergetraincarduration"></a>`duration` | [`Int`](#int) | Duration of the car. |
|
||||
| <a id="mergetraincarid"></a>`id` | [`MergeTrainsCarID!`](#mergetrainscarid) | Global ID of the car. |
|
||||
| <a id="mergetraincarmergerequest"></a>`mergeRequest` | [`MergeRequest!`](#mergerequest) | Merge request the car contains. |
|
||||
| <a id="mergetraincarmergedat"></a>`mergedAt` | [`Time`](#time) | Timestamp of when the car was merged. |
|
||||
| <a id="mergetraincarpipeline"></a>`pipeline` | [`Pipeline`](#pipeline) | Pipeline of the car. |
|
||||
| <a id="mergetraincarstatus"></a>`status` | [`CarStatus!`](#carstatus) | Status of the car. |
|
||||
| <a id="mergetraincartargetbranch"></a>`targetBranch` | [`Branch!`](#branch) | Target branch of the car's merge request. |
|
||||
| <a id="mergetraincartargetproject"></a>`targetProject` | [`Project!`](#project) | Project the car's MR targets. |
|
||||
| <a id="mergetraincarupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the car was last updated. |
|
||||
| <a id="mergetraincaruser"></a>`user` | [`UserCore!`](#usercore) | Creator of the car (user who added the merge request to the train). |
|
||||
|
||||
### `Metadata`
|
||||
|
||||
#### Fields
|
||||
|
|
@ -28439,6 +28539,27 @@ four standard [pagination arguments](#pagination-arguments):
|
|||
| <a id="projectmergerequestsupdatedafter"></a>`updatedAfter` | [`Time`](#time) | Merge requests updated after the timestamp. |
|
||||
| <a id="projectmergerequestsupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Merge requests updated before the timestamp. |
|
||||
|
||||
##### `Project.mergeTrains`
|
||||
|
||||
Merge trains available to the project.
|
||||
|
||||
DETAILS:
|
||||
**Introduced** in GitLab 17.1.
|
||||
**Status**: Experiment.
|
||||
|
||||
Returns [`MergeTrainConnection`](#mergetrainconnection).
|
||||
|
||||
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="projectmergetrainsstatus"></a>`status` | [`MergeTrainStatus`](#mergetrainstatus) | Filter merge trains by a specific status. Defaults to ACTIVE. |
|
||||
| <a id="projectmergetrainstargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Filter merge trains by a list of target branches. |
|
||||
|
||||
##### `Project.milestones`
|
||||
|
||||
Milestones of the project.
|
||||
|
|
@ -33114,6 +33235,19 @@ Types of blob viewers.
|
|||
| <a id="blobviewerstyperich"></a>`rich` | Rich blob viewers type. |
|
||||
| <a id="blobviewerstypesimple"></a>`simple` | Simple blob viewers type. |
|
||||
|
||||
### `CarStatus`
|
||||
|
||||
Status of a merge train's car.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="carstatusfresh"></a>`FRESH` | Car's status: fresh. |
|
||||
| <a id="carstatusidle"></a>`IDLE` | Car's status: idle. |
|
||||
| <a id="carstatusmerged"></a>`MERGED` | Car's status: merged. |
|
||||
| <a id="carstatusmerging"></a>`MERGING` | Car's status: merging. |
|
||||
| <a id="carstatusskip_merged"></a>`SKIP_MERGED` | Car's status: skip_merged. |
|
||||
| <a id="carstatusstale"></a>`STALE` | Car's status: stale. |
|
||||
|
||||
### `CiCatalogResourceScope`
|
||||
|
||||
Values for scoping catalog resources.
|
||||
|
|
@ -34613,6 +34747,13 @@ Representation of whether a GitLab merge request can be merged.
|
|||
| <a id="mergestrategyenummerge_when_checks_pass"></a>`MERGE_WHEN_CHECKS_PASS` | Use the merge_when_checks_pass merge strategy. |
|
||||
| <a id="mergestrategyenummerge_when_pipeline_succeeds"></a>`MERGE_WHEN_PIPELINE_SUCCEEDS` | Use the merge_when_pipeline_succeeds merge strategy. |
|
||||
|
||||
### `MergeTrainStatus`
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="mergetrainstatusactive"></a>`ACTIVE` | Active merge train. |
|
||||
| <a id="mergetrainstatuscompleted"></a>`COMPLETED` | Completed merge train. |
|
||||
|
||||
### `MergeabilityCheckIdentifier`
|
||||
|
||||
Representation of mergeability check identifier.
|
||||
|
|
@ -36598,6 +36739,12 @@ A `MergeRequestsExternalStatusCheckID` is a global ID. It is encoded as a string
|
|||
|
||||
An example `MergeRequestsExternalStatusCheckID` is: `"gid://gitlab/MergeRequests::ExternalStatusCheck/1"`.
|
||||
|
||||
### `MergeTrainsCarID`
|
||||
|
||||
A `MergeTrainsCarID` is a global ID. It is encoded as a string.
|
||||
|
||||
An example `MergeTrainsCarID` is: `"gid://gitlab/MergeTrains::Car/1"`.
|
||||
|
||||
### `MilestoneID`
|
||||
|
||||
A `MilestoneID` is a global ID. It is encoded as a string.
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ Example response:
|
|||
"ci_needs_size_limit": 50,
|
||||
"ci_registered_group_runners": 1000,
|
||||
"ci_registered_project_runners": 1000,
|
||||
"dotenv_size": 5120,
|
||||
"dotenv_variables": 20,
|
||||
"conan_max_file_size": 3221225472,
|
||||
"enforcement_limit": 10000,
|
||||
"generic_packages_max_file_size": 5368709120,
|
||||
|
|
@ -78,6 +80,8 @@ PUT /application/plan_limits
|
|||
| `ci_needs_size_limit` | integer | no | Maximum number of [DAG](../ci/directed_acyclic_graph/index.md) dependencies that a job can have. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
|
||||
| `ci_registered_group_runners` | integer | no | Maximum number of runners registered per group. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
|
||||
| `ci_registered_project_runners` | integer | no | Maximum number of runners registered per project. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85895) in GitLab 15.0. |
|
||||
| `dotenv_size` | integer | no | Maximum size of a dotenv artifact in bytes. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/432529) in GitLab 17.1. |
|
||||
| `dotenv_variables` | integer | no | Maximum number of variables in a dotenv artifact. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/432529) in GitLab 17.1. |
|
||||
| `conan_max_file_size` | integer | no | Maximum Conan package file size in bytes. |
|
||||
| `enforcement_limit` | integer | no | Maximum storage size for root namespace limit enforcement in MiB. |
|
||||
| `generic_packages_max_file_size` | integer | no | Maximum generic package file size in bytes. |
|
||||
|
|
@ -107,6 +111,8 @@ Example response:
|
|||
"ci_registered_group_runners": 1000,
|
||||
"ci_registered_project_runners": 1000,
|
||||
"conan_max_file_size": 3221225472,
|
||||
"dotenv_variables": 20,
|
||||
"dotenv_size": 5120,
|
||||
"generic_packages_max_file_size": 5368709120,
|
||||
"helm_max_file_size": 5242880,
|
||||
"maven_max_file_size": 3221225472,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../user/gitlab_duo/experiments.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/gitlab_duo/experiments.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../user/gitlab_duo/index.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/gitlab_duo/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../user/gitlab_duo/turn_on_off.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/gitlab_duo/turn_on_off.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Detected secrets
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
**Status:** GA
|
||||
|
||||
This table lists the secrets detected by [pipeline secret detection](index.md).
|
||||
|
||||
<!-- markdownlint-disable MD034 -->
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Detected secrets
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Ultimate
|
||||
**Offering:** GitLab.com, GitLab Dedicated
|
||||
**Status:** Beta
|
||||
|
||||
This table lists the secrets detected by [secret push protection](index.md).
|
||||
|
||||
<!-- markdownlint-disable MD044 -->
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ For details, see:
|
|||
|
||||
- [Request a review of your merge request](../project/merge_requests/reviews/index.md#request-a-review)
|
||||
- [Add suggestions to a merge request](../project/merge_requests/reviews/suggestions.md#create-suggestions)
|
||||
- [How approvals work](../project/merge_requests/approvals/index.md#how-approvals-work)
|
||||
- [Merge request approvals](../project/merge_requests/approvals/index.md)
|
||||
|
||||
## Step 5: Merge the merge request
|
||||
|
||||
|
|
|
|||
|
|
@ -19,15 +19,14 @@ DETAILS:
|
|||
|
||||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10344) in GitLab 16.0 as an [experiment](../../policy/experiment-beta-support.md#experiment).
|
||||
|
||||
To use this feature:
|
||||
Generate a summary of discussions on an issue.
|
||||
|
||||
- The parent group of the issue must:
|
||||
- Enable the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features).
|
||||
- You must:
|
||||
- Belong to at least one group with the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features) enabled.
|
||||
- Have sufficient permissions to view the issue.
|
||||
Prerequisites:
|
||||
|
||||
You can generate a summary of discussions on an issue:
|
||||
- You must belong to at least one group with the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features) enabled.
|
||||
- You must have permission to view the issue.
|
||||
|
||||
To generate a summary of issue discussions:
|
||||
|
||||
1. In an issue, scroll to the **Activity** section.
|
||||
1. Select **View summary**.
|
||||
|
|
@ -49,15 +48,15 @@ DETAILS:
|
|||
|
||||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10228) in GitLab 16.2 as an [experiment](../../policy/experiment-beta-support.md#experiment).
|
||||
|
||||
To use this feature:
|
||||
Improve your planning and decision-making by predicting productivity metrics and
|
||||
identifying anomalies across your software development lifecycle.
|
||||
|
||||
- The parent group of the project must:
|
||||
- Enable the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features).
|
||||
- You must:
|
||||
- Belong to at least one group with the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features) enabled.
|
||||
- Have sufficient permissions to view the CI/CD analytics.
|
||||
Prerequisites:
|
||||
|
||||
In CI/CD Analytics, you can view a forecast of deployment frequency:
|
||||
- You must belong to at least one group with the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features) enabled.
|
||||
- You must have permission to view the CI/CD analytics.
|
||||
|
||||
To view a forecast of deployment frequency in CI/CD Analytics:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Analyze > CI/CD analytics**.
|
||||
|
|
@ -65,14 +64,17 @@ In CI/CD Analytics, you can view a forecast of deployment frequency:
|
|||
1. Turn on the **Show forecast** toggle.
|
||||
1. On the confirmation dialog, select **Accept testing terms**.
|
||||
|
||||
The forecast is displayed as a dotted line on the chart. Data is forecasted for a duration that is half of the selected date range.
|
||||
For example, if you select a 30-day range, a forecast for the following 15 days is displayed.
|
||||
The forecast is displayed as a dotted line on the chart. Data is forecasted for
|
||||
a duration that is half of the selected date range.
|
||||
|
||||
For example, if you select a 30-day range, a forecast for the following 15 days
|
||||
is displayed.
|
||||
|
||||

|
||||
|
||||
Provide feedback on this experimental feature in [issue 416833](https://gitlab.com/gitlab-org/gitlab/-/issues/416833).
|
||||
|
||||
## Root cause analysis
|
||||
## Troubleshoot failed CI/CD jobs with Root cause analysis
|
||||
|
||||
DETAILS:
|
||||
**Tier:** For a limited time, Ultimate. In the future, [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
|
||||
|
|
@ -81,15 +83,12 @@ DETAILS:
|
|||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123692) in GitLab 16.2 as an [experiment](../../policy/experiment-beta-support.md#experiment).
|
||||
|
||||
You can learn more about failed CI/CD jobs by using GitLab Duo Root cause analysis.
|
||||
Determine the root cause of a CI/CD job failure by analyzing the logs.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- The parent group of the project must:
|
||||
- Enable the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features).
|
||||
- You must:
|
||||
- Belong to at least one group with the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features) enabled.
|
||||
- Have sufficient permissions to view the CI/CD job.
|
||||
- You must belong to at least one group with the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features) enabled.
|
||||
- You must have permission to view the CI/CD job.
|
||||
|
||||
To view root cause analysis:
|
||||
|
||||
|
|
@ -108,15 +107,14 @@ DETAILS:
|
|||
|
||||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10762) in GitLab 16.3 as an [experiment](../../policy/experiment-beta-support.md#experiment).
|
||||
|
||||
To use this feature:
|
||||
Generate a detailed description for an issue based on a short summary you provide.
|
||||
|
||||
- The parent group of the project must:
|
||||
- Enable the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features).
|
||||
- You must:
|
||||
- Belong to at least one group with the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features) enabled.
|
||||
- Have sufficient permissions to view the issue.
|
||||
Prerequisites:
|
||||
|
||||
You can generate the description for an issue from a short summary.
|
||||
- You must belong to at least one group with the [experiment and beta features setting](turn_on_off.md#turn-on-beta-and-experimental-features) enabled.
|
||||
- You must have permission to view the issue.
|
||||
|
||||
To generate an issue description:
|
||||
|
||||
1. Create a new issue.
|
||||
1. Above the **Description** field, select **GitLab Duo** (**{tanuki-ai}**) **> Generate issue description**.
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ DETAILS:
|
|||
|
||||
- Helps you determine the root cause for a CI/CD job failure by analyzing the logs.
|
||||
- LLM: Vertex AI Codey [`text-bison`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text)
|
||||
- [View documentation](experiments.md#root-cause-analysis).
|
||||
- [View documentation](experiments.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis).
|
||||
|
||||
### Vulnerability resolution
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ CI/CD configuration is needed.
|
|||
Please show a .gitignore and .gitlab-ci.yml configuration for a C# project.
|
||||
```
|
||||
|
||||
- If your CI/CD job fails, [Root Cause Analysis](../../user/gitlab_duo/experiments.md#root-cause-analysis)
|
||||
- If your CI/CD job fails, [Root Cause Analysis](../../user/gitlab_duo/experiments.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis)
|
||||
can help understand the problem. Alternatively, you can copy the error message into
|
||||
GitLab Duo Chat, and ask for help:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../user/gitlab_duo_chat/index.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/gitlab_duo_chat/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ You can also ask to explain specific job errors by copy-pasting the error messag
|
|||
|
||||
- `Please explain this CI/CD job error message in the context of a Go project: build.sh: line 14: go command not found`
|
||||
|
||||
Alternatively, you can use [root cause analysis in CI/CD](../gitlab_duo/experiments.md#root-cause-analysis).
|
||||
Alternatively, you can use [root cause analysis in CI/CD](../gitlab_duo/experiments.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis).
|
||||
|
||||
## Explain code in the IDE
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ You can express interest in other IDE extension support
|
|||
1. Optional. Ask a follow-up question.
|
||||
|
||||
To ask a new question unrelated to the previous conversation, you might receive better answers
|
||||
if you clear the context by typing `/reset` and selecting **Send**.
|
||||
if you clear the context by typing `/reset` or `/clear` and selecting **Send**.
|
||||
|
||||
NOTE:
|
||||
Only the last 50 messages are retained in the chat history. The chat history expires 3 days after last use.
|
||||
|
|
@ -152,12 +152,19 @@ Alternatively, use the context menu to perform these tasks.
|
|||
|
||||
When you use a slash command, you can also add additional instructions, for example: `/tests using the Boost.Test framework`.
|
||||
|
||||
## Delete all conversations
|
||||
## Delete or reset the conversation
|
||||
|
||||
To delete all previous conversations:
|
||||
To delete all conversations permanently and clear the chat window:
|
||||
|
||||
- In the text box, type `/clear` and select **Send**.
|
||||
|
||||
To start a new conversation, but keep the previous conversations visible in the chat window:
|
||||
|
||||
- In the text box, type `/reset` and select **Send**.
|
||||
|
||||
In both cases, the conversation history will not be considered when you ask new questions.
|
||||
Deleting or resetting might help improve the answers when you switch contexts, because Duo Chat will not get confused by the unrelated conversations.
|
||||
|
||||
## Give feedback
|
||||
|
||||
Your feedback is important to us as we continually enhance your GitLab Duo Chat experience.
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../user/gitlab_duo_chat/turn_on_off.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/gitlab_duo_chat/turn_on_off.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../user/gitlab_duo_chat/examples.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/gitlab_duo_chat/examples.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../user/gitlab_duo_chat/troubleshooting.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/gitlab_duo_chat/troubleshooting.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../user/gitlab_duo/use_cases.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/gitlab_duo/use_cases.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -103,6 +103,9 @@ You can also [use the API to delete a secondary email address](../../api/users.m
|
|||
|
||||
You can make your user profile visible to only you and GitLab administrators.
|
||||
|
||||
NOTE:
|
||||
A GitLab administrator can [disable](../../administration/settings/account_and_limit_settings.md#allow-users-to-make-their-profiles-private) this setting, forcing all profiles to be made public.
|
||||
|
||||
To make your profile private:
|
||||
|
||||
1. On the left sidebar, select your avatar.
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: 'duo_in_merge_requests.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](duo_in_merge_requests.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
|
|
@ -11,28 +11,46 @@ DETAILS:
|
|||
**Tier:** Free, Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
You can configure your merge requests so that they must be approved before
|
||||
they can be merged. While [GitLab Free](https://about.gitlab.com/pricing/) allows
|
||||
You can configure your merge requests to allow (or require) approval before
|
||||
they merge. While [GitLab Free](https://about.gitlab.com/pricing/) allows
|
||||
all users with Developer or greater [permissions](../../../permissions.md) to
|
||||
approve merge requests, these approvals are [optional](#optional-approvals).
|
||||
[GitLab Premium](https://about.gitlab.com/pricing/) and
|
||||
[GitLab Ultimate](https://about.gitlab.com/pricing/) provide additional
|
||||
[GitLab Ultimate](https://about.gitlab.com/pricing/) give you more
|
||||
flexibility:
|
||||
|
||||
- Create required [rules](rules.md) about the number and type of approvers before work can merge.
|
||||
- Specify a list of users who act as [code owners](../../codeowners/index.md) for specific files,
|
||||
- Build a list of users who act as [code owners](../../codeowners/index.md) for specific files,
|
||||
and require their approval before work can merge.
|
||||
- For GitLab Premium and GitLab Ultimate, configure approvals
|
||||
[for the entire instance](../../../../administration/merge_requests_approvals.md).
|
||||
|
||||
You can configure merge request approvals on a per-project basis, and some approvals can be configured
|
||||
[on the group level](../../../group/manage.md#group-merge-request-approval-settings). Support for
|
||||
group-level settings for merge request approval rules is tracked in this
|
||||
[epic](https://gitlab.com/groups/gitlab-org/-/epics/4367).
|
||||
You can configure merge request approvals on a per-project basis, and configure some approvals
|
||||
[at the group level](../../../group/manage.md#group-merge-request-approval-settings). Support for
|
||||
group-level settings for merge request approval rules is tracked in
|
||||
[epic 4367](https://gitlab.com/groups/gitlab-org/-/epics/4367).
|
||||
|
||||
## How approvals work
|
||||
## View approval status
|
||||
|
||||
With [merge request approval rules](rules.md), you can set the minimum number of
|
||||
The list of merge requests for your project shows the approval status for each merge request:
|
||||
|
||||
| Example | Description |
|
||||
| :-----: | :---------- |
|
||||
|  | Required approvals are missing. (**{approval}**) |
|
||||
|  | Approvals are satisfied. (**{check}**) |
|
||||
|  | Approvals are satisfied, and you are one of the approvers. (**{approval-solid}**) |
|
||||
|
||||
When an [eligible approver](rules.md#eligible-approvers) visits an open merge request,
|
||||
GitLab shows one of these statuses after the body of the merge request:
|
||||
|
||||
- **Approve**: The merge request doesn't yet have the required number of approvals.
|
||||
- **Approve additionally**: The merge request has the required number of approvals.
|
||||
- **Revoke approval**: The user viewing the merge request has already approved
|
||||
the merge request.
|
||||
|
||||
## Configuration options for approvals
|
||||
|
||||
Use [merge request approval rules](rules.md) to set the minimum number of
|
||||
required approvals before work can merge into your project. You can also extend these
|
||||
rules to define what types of users can approve work. Some examples of rules you can create include:
|
||||
|
||||
|
|
@ -51,44 +69,15 @@ You can also configure:
|
|||
- Merge request approval rules and settings through the GitLab UI or with the
|
||||
[Merge request approvals API](../../../../api/merge_request_approvals.md).
|
||||
|
||||
Approvals cannot be changed after a merge request is merged.
|
||||
You can't change the approvals on a merge request after it merges.
|
||||
|
||||
## Approve a merge request
|
||||
|
||||
When an [eligible approver](rules.md#eligible-approvers) visits an open merge request,
|
||||
GitLab displays one of these buttons after the body of the merge request:
|
||||
|
||||
- **Approve**: The merge request doesn't yet have the required number of approvals.
|
||||
- **Approve additionally**: The merge request has the required number of approvals.
|
||||
- **Revoke approval**: The user viewing the merge request has already approved
|
||||
the merge request.
|
||||
|
||||
Eligible approvers can also use the `/approve`
|
||||
[quick action](../../../project/quick_actions.md) when adding a comment to
|
||||
a merge request. Users in the reviewer list who have approved a merge request display
|
||||
a green check mark (**{check-circle-filled}**) next to their name.
|
||||
|
||||
After a merge request receives the [number and type of approvals](rules.md) you configure, it can merge
|
||||
unless it's blocked for another reason. Merge requests can be blocked by other problems,
|
||||
such as merge conflicts, [unresolved threads](../index.md#prevent-merge-unless-all-threads-are-resolved),
|
||||
or a [failed CI/CD pipeline](../merge_when_pipeline_succeeds.md).
|
||||
|
||||
To prevent merge request authors from approving their own merge requests,
|
||||
enable [**Prevent author approval**](settings.md#prevent-approval-by-author)
|
||||
in your project's settings.
|
||||
|
||||
If you enable [approval rule overrides](settings.md#prevent-editing-approval-rules-in-merge-requests),
|
||||
merge requests created before a change to default approval rules are not affected.
|
||||
The only exceptions are changes to the [target branch](rules.md#approvals-for-protected-branches)
|
||||
of the rule.
|
||||
|
||||
## Optional approvals
|
||||
### Optional approvals
|
||||
|
||||
GitLab allows all users with Developer or greater [permissions](../../../permissions.md)
|
||||
to approve merge requests. Approvals in GitLab Free are optional, and don't prevent
|
||||
a merge request from merging without approval.
|
||||
|
||||
## Required approvals
|
||||
### Required approvals
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
|
|
@ -110,36 +99,49 @@ Without the approvals, the work cannot merge. Required approvals enable multiple
|
|||
- Users on GitLab Ultimate can also [require approval from a security team](../../../application_security/index.md#security-approvals-in-merge-requests)
|
||||
before merging code that could introduce a vulnerability.
|
||||
|
||||
## Approve a merge request
|
||||
|
||||
Eligible approvers can also use the `/approve`
|
||||
[quick action](../../../project/quick_actions.md) when adding a comment to
|
||||
a merge request. Users in the reviewer list who have approved a merge request display
|
||||
a green check mark (**{check-circle-filled}**) next to their name.
|
||||
|
||||
After a merge request receives the [number and type of approvals](rules.md) you configure, it can merge
|
||||
unless it's blocked for another reason. Merge requests can be blocked by other problems,
|
||||
such as merge conflicts, [unresolved threads](../index.md#prevent-merge-unless-all-threads-are-resolved),
|
||||
or a [failed CI/CD pipeline](../merge_when_pipeline_succeeds.md).
|
||||
|
||||
To prevent merge request authors from approving their own merge requests,
|
||||
enable [**Prevent author approval**](settings.md#prevent-approval-by-author)
|
||||
in your project's settings.
|
||||
|
||||
If you enable [approval rule overrides](settings.md#prevent-editing-approval-rules-in-merge-requests),
|
||||
merge requests created before a change to default approval rules are not affected.
|
||||
The only exceptions are changes to the [target branch](rules.md#approvals-for-protected-branches)
|
||||
of the rule.
|
||||
|
||||
## Invalid rules
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334698) in GitLab 15.1.
|
||||
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/389905) in GitLab 15.11 [with a flag](../../../../administration/feature_flags.md) named `invalid_scan_result_policy_prevents_merge`. Disabled by default.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/405023) in GitLab 16.2. Feature flag `invalid_scan_result_policy_prevents_merge` removed.
|
||||
|
||||
Whenever an approval rule cannot be satisfied, the rule is displayed as **Auto approved**. This applies to the following conditions:
|
||||
When an approval rule is impossible to satisfy, GitLab shows the rule as
|
||||
**Auto approved**. This happens when:
|
||||
|
||||
- The only eligible approver is the author of the merge request.
|
||||
- No eligible approvers (either groups or users) have been assigned to the approval rule.
|
||||
- The number of required approvals is more than the number of eligible approvers.
|
||||
- The only eligible approver is also the merge request author.
|
||||
- No eligible approvers (either groups or users) are assigned to the approval rule.
|
||||
- The number of required approvals is greater than the number of eligible approvers.
|
||||
|
||||
These rules are automatically approved to unblock their respective merge requests, unless they were
|
||||
created through a [merge request approval policy](../../../application_security/policies/scan-result-policies.md).
|
||||
Invalid approval rules created through a merge request approval policy are presented with
|
||||
**Action required** and are not automatically approved, blocking their respective merge requests.
|
||||
These rules are automatically approved to unblock their respective merge requests, unless you
|
||||
created them through a [merge request approval policy](../../../application_security/policies/scan-result-policies.md).
|
||||
Invalid approval rules created through a merge request approval policy are:
|
||||
|
||||
- Shown with **Action required**.
|
||||
- Not automatically approved.
|
||||
- Blockers for merge requests they affect.
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Merge request approvals API](../../../../api/merge_request_approvals.md)
|
||||
- [Instance-level approval rules](../../../../administration/merge_requests_approvals.md) for self-managed installations
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
|
||||
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
|
||||
one might have when setting this up, or when something is changed, or on upgrading, it's
|
||||
important to describe those, too. Think of things that may go wrong and include them here.
|
||||
This is important to minimize requests for support, and to avoid doc comments with
|
||||
questions that you know someone might ask.
|
||||
|
||||
Each scenario can be a third-level heading, for example, `### Getting error message X`.
|
||||
If you have none to add when creating a doc, leave this section in place
|
||||
but commented out to help encourage others to add to it in the future. -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: 'files/index.md'
|
||||
remove_date: '2024-09-07'
|
||||
remove_date: '2025-06-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](files/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2024-09-07>. -->
|
||||
<!-- This redirect file can be deleted after <2025-06-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ module API
|
|||
optional :ci_registered_group_runners, type: Integer, desc: 'Maximum number of runners registered per group'
|
||||
optional :ci_registered_project_runners, type: Integer, desc: 'Maximum number of runners registered per project'
|
||||
optional :conan_max_file_size, type: Integer, desc: 'Maximum Conan package file size in bytes'
|
||||
optional :dotenv_size, type: Integer, desc: 'Maximum size of a dotenv artifact in bytes'
|
||||
optional :dotenv_variables, type: Integer, desc: 'Maximum number of variables in a dotenv artifact'
|
||||
optional :enforcement_limit, type: Integer,
|
||||
desc: 'Maximum storage size for the root namespace enforcement in MiB'
|
||||
optional :generic_packages_max_file_size, type: Integer, desc: 'Maximum generic package file size in bytes'
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ module API
|
|||
expose :ci_registered_group_runners, documentation: { type: 'integer', example: 1000 }
|
||||
expose :ci_registered_project_runners, documentation: { type: 'integer', example: 1000 }
|
||||
expose :conan_max_file_size, documentation: { type: 'integer', example: 3221225472 }
|
||||
expose :dotenv_variables, documentation: { type: 'integer', example: 20 }
|
||||
expose :dotenv_size, documentation: { type: 'integer', example: 5120 }
|
||||
expose :enforcement_limit, documentation: { type: 'integer', example: 15000 }
|
||||
expose :generic_packages_max_file_size, documentation: { type: 'integer', example: 5368709120 }
|
||||
expose :helm_max_file_size, documentation: { type: 'integer', example: 5242880 }
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ module API
|
|||
.fetch(:additional_properties, Gitlab::InternalEvents::DEFAULT_ADDITIONAL_PROPERTIES)
|
||||
.symbolize_keys
|
||||
|
||||
unless Gitlab::Tracking::AiTracking.track_via_code_suggestions?(event_name, current_user)
|
||||
if Feature.enabled?(:track_ai_metrics_in_usage_data) && # rubocop:disable Gitlab/FeatureFlagWithoutActor -- beta
|
||||
!Gitlab::Tracking::AiTracking.track_via_code_suggestions?(event_name, current_user)
|
||||
|
||||
Gitlab::Tracking::AiTracking.track_event(event_name, additional_properties.merge(user: current_user))
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ module Banzai
|
|||
# Pattern to match allowed image extensions
|
||||
ALLOWED_IMAGE_EXTENSIONS = /(jpg|png|gif|svg|bmp)\z/i
|
||||
|
||||
CSS_WIKILINK_STYLE = 'a[data-wikilink]'
|
||||
CSS_WIKILINK_STYLE = 'a[href][data-wikilink]'
|
||||
XPATH_WIKILINK_STYLE = Gitlab::Utils::Nokogiri.css_to_xpath(CSS_WIKILINK_STYLE).freeze
|
||||
|
||||
def call
|
||||
|
|
|
|||
|
|
@ -16,7 +16,13 @@ module Gitlab
|
|||
Gitlab::Routing.url_helpers.ide_oauth_redirect_url
|
||||
end
|
||||
|
||||
def oauth_application_id
|
||||
oauth_application ? oauth_application.id : nil
|
||||
end
|
||||
|
||||
def oauth_application_callback_urls
|
||||
return [] unless oauth_application
|
||||
|
||||
URI.extract(oauth_application.redirect_uri, %w[http https]).uniq
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -3485,12 +3485,18 @@ msgstr ""
|
|||
msgid "AdminArea|Components"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminArea|Current domain doesn't match the Web IDE OAuth configuration"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminArea|Developer"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminArea|Documentation"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminArea|Edit OAuth configuration"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminArea|Features"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -3557,6 +3563,9 @@ msgstr ""
|
|||
msgid "AdminArea|Sign up for the GitLab newsletter"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminArea|The Web IDE OAuth application doesn't have a redirect URL with the domain that you are using to visit GitLab. This issue will prevent Web IDE users from authenticating and often occurs when using a reverse proxy."
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminArea|Total Billable users"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -3908,6 +3917,12 @@ msgstr ""
|
|||
msgid "AdminSettings|Maximum number of runners registered per project"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Maximum number of variables in a dotenv artifact"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Maximum size of a dotenv artifact in bytes"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdminSettings|Minimum size must be at least 0."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -292,6 +292,21 @@ function rspec_parallelized_job() {
|
|||
handle_retry_rspec_in_new_process $rspec_run_status
|
||||
}
|
||||
|
||||
function run_e2e_specs() {
|
||||
local url=$1
|
||||
local tests=$2
|
||||
local tags=$3
|
||||
|
||||
export QA_COMMAND="bundle exec bin/qa ${QA_SCENARIO:=Test::Instance::All} $url -- $tests $tags --order random --force-color --format documentation --format QA::Support::JsonFormatter --out tmp/rspec-${CI_JOB_ID}-\${QA_RSPEC_RETRIED:-false}.json"
|
||||
echo "Running e2e specs via command: '$QA_COMMAND'"
|
||||
|
||||
if eval "$QA_COMMAND --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml"; then
|
||||
echo "Test run finished successfully"
|
||||
else
|
||||
retry_failed_e2e_rspec_examples
|
||||
fi
|
||||
}
|
||||
|
||||
function retry_failed_e2e_rspec_examples() {
|
||||
local rspec_run_status=0
|
||||
|
||||
|
|
|
|||
|
|
@ -486,6 +486,8 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
|
|||
|
||||
page.within('.as-ci-cd') do
|
||||
fill_in 'plan_limits_ci_instance_level_variables', with: 5
|
||||
fill_in 'plan_limits_dotenv_size', with: 6
|
||||
fill_in 'plan_limits_dotenv_variables', with: 7
|
||||
fill_in 'plan_limits_ci_pipeline_size', with: 10
|
||||
fill_in 'plan_limits_ci_active_jobs', with: 20
|
||||
fill_in 'plan_limits_ci_project_subscriptions', with: 30
|
||||
|
|
@ -498,6 +500,8 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
|
|||
|
||||
limits = default_plan.reload.limits
|
||||
expect(limits.ci_instance_level_variables).to eq(5)
|
||||
expect(limits.dotenv_size).to eq(6)
|
||||
expect(limits.dotenv_variables).to eq(7)
|
||||
expect(limits.ci_pipeline_size).to eq(10)
|
||||
expect(limits.ci_active_jobs).to eq(20)
|
||||
expect(limits.ci_project_subscriptions).to eq(30)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,17 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe IdeHelper, feature_category: :web_ide do
|
||||
describe '#ide_data' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:user) { project.creator }
|
||||
let_it_be(:fork_info) { { ide_path: '/test/ide/path' } }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:user) { project.creator }
|
||||
|
||||
before do
|
||||
allow(helper).to receive(:current_user).and_return(user)
|
||||
allow(helper).to receive(:content_security_policy_nonce).and_return('test-csp-nonce')
|
||||
allow(helper).to receive(:new_session_path).and_return('test-sign-in-path')
|
||||
end
|
||||
|
||||
describe '#ide_data' do
|
||||
let_it_be(:fork_info) { { ide_path: '/test/ide/path' } }
|
||||
let_it_be(:params) do
|
||||
{
|
||||
branch: 'master',
|
||||
|
|
@ -26,12 +32,6 @@ RSpec.describe IdeHelper, feature_category: :web_ide do
|
|||
}
|
||||
end
|
||||
|
||||
before do
|
||||
allow(helper).to receive(:current_user).and_return(user)
|
||||
allow(helper).to receive(:content_security_policy_nonce).and_return('test-csp-nonce')
|
||||
allow(helper).to receive(:new_session_path).and_return('test-sign-in-path')
|
||||
end
|
||||
|
||||
it 'returns hash' do
|
||||
expect(helper.ide_data(project: nil, fork_info: fork_info, params: params))
|
||||
.to include(base_data)
|
||||
|
|
@ -141,4 +141,43 @@ RSpec.describe IdeHelper, feature_category: :web_ide do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#show_web_ide_oauth_callback_mismatch_callout?' do
|
||||
let_it_be(:oauth_application) { create(:oauth_application, owner: nil) }
|
||||
|
||||
it 'returns false if Web IDE OAuth is not enabled' do
|
||||
stub_feature_flags(vscode_web_ide: true, web_ide_oauth: false)
|
||||
expect(helper.show_web_ide_oauth_callback_mismatch_callout?).to be false
|
||||
end
|
||||
|
||||
context 'when Web IDE OAuth is enabled' do
|
||||
before do
|
||||
stub_feature_flags(vscode_web_ide: true, web_ide_oauth: true)
|
||||
end
|
||||
|
||||
it 'returns false if no Web IDE OAuth application found' do
|
||||
expect(helper.show_web_ide_oauth_callback_mismatch_callout?).to be false
|
||||
end
|
||||
|
||||
it "returns true if domain does not match OAuth application callback URLs" do
|
||||
stub_application_setting({ web_ide_oauth_application: oauth_application })
|
||||
expect(helper.show_web_ide_oauth_callback_mismatch_callout?).to be true
|
||||
end
|
||||
|
||||
it "returns false if domain matches OAuth application callback URL" do
|
||||
oauth_application.redirect_uri = "#{request.base_url}/oauth-redirect"
|
||||
stub_application_setting({ web_ide_oauth_application: oauth_application })
|
||||
expect(helper.show_web_ide_oauth_callback_mismatch_callout?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#web_ide_oauth_application_id' do
|
||||
let_it_be(:oauth_application) { create(:oauth_application, owner: nil) }
|
||||
|
||||
it 'returns Web IDE OAuth application ID' do
|
||||
stub_application_setting({ web_ide_oauth_application: oauth_application })
|
||||
expect(helper.web_ide_oauth_application_id).to eq(oauth_application.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ RSpec.describe PlanLimitsHelper, feature_category: :continuous_integration do
|
|||
it 'describes known limits', :aggregate_failures do
|
||||
[
|
||||
:ci_instance_level_variables,
|
||||
:dotenv_size,
|
||||
:dotenv_variables,
|
||||
:ci_pipeline_size,
|
||||
:ci_active_jobs,
|
||||
:ci_project_subscriptions,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ RSpec.describe API::Entities::PlanLimit do
|
|||
:ci_needs_size_limit,
|
||||
:ci_registered_group_runners,
|
||||
:ci_registered_project_runners,
|
||||
:dotenv_size,
|
||||
:dotenv_variables,
|
||||
:conan_max_file_size,
|
||||
:enforcement_limit,
|
||||
:generic_packages_max_file_size,
|
||||
|
|
|
|||
|
|
@ -192,6 +192,14 @@ RSpec.describe Banzai::Filter::WikiLinkGollumFilter, feature_category: :wiki do
|
|||
end
|
||||
# rubocop:enable Layout/LineLength
|
||||
|
||||
context 'when the href gets sanitized out' do
|
||||
it 'ignores the link' do
|
||||
doc = pipeline_filter('[[test|http://]]', wiki: wiki)
|
||||
|
||||
expect(doc.at_css('a')['data-gollum']).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
def pipeline_filter(text, context = {})
|
||||
context = { project: project, no_sourcepos: true }.merge(context)
|
||||
|
||||
|
|
|
|||
|
|
@ -593,6 +593,31 @@ RSpec.describe Integration, feature_category: :integrations do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.create_from_default_integrations' do
|
||||
let!(:instance_integration) { create(:prometheus_integration, :instance, api_url: 'https://prometheus.instance.com/') }
|
||||
let!(:instance_level_instance_specific_integration) { create(:beyond_identity_integration) }
|
||||
|
||||
it 'creates integrations from default integrations' do
|
||||
expect(described_class).to receive(:create_from_active_default_integrations)
|
||||
.with(project, :project_id).and_call_original
|
||||
expect(described_class).to receive(:create_from_default_instance_specific_integrations)
|
||||
.with(project, :project_id).and_call_original
|
||||
|
||||
expect(described_class.create_from_default_integrations(project, :project_id)).to eq(2)
|
||||
end
|
||||
|
||||
context 'when called with a group' do
|
||||
it 'creates integrations from default integrations' do
|
||||
expect(described_class).to receive(:create_from_active_default_integrations)
|
||||
.with(group, :group_id).and_call_original
|
||||
expect(described_class).to receive(:create_from_default_instance_specific_integrations)
|
||||
.with(group, :group_id).and_call_original
|
||||
|
||||
expect(described_class.create_from_default_integrations(group, :group_id)).to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.create_from_active_default_integrations' do
|
||||
context 'with an active instance-level integration' do
|
||||
let!(:instance_integration) { create(:prometheus_integration, :instance, api_url: 'https://prometheus.instance.com/') }
|
||||
|
|
@ -651,9 +676,10 @@ RSpec.describe Integration, feature_category: :integrations do
|
|||
end
|
||||
|
||||
context 'with an active subgroup' do
|
||||
let_it_be(:subgroup) { create(:group, parent: group) }
|
||||
let_it_be(:project) { create(:project, group: subgroup) }
|
||||
|
||||
let!(:subgroup_integration) { create(:prometheus_integration, :group, group: subgroup, api_url: 'https://prometheus.subgroup.com/') }
|
||||
let!(:subgroup) { create(:group, parent: group) }
|
||||
let(:project) { create(:project, group: subgroup) }
|
||||
|
||||
it 'creates an integration from the subgroup-level integration' do
|
||||
described_class.create_from_active_default_integrations(project, :project_id)
|
||||
|
|
@ -701,6 +727,131 @@ RSpec.describe Integration, feature_category: :integrations do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the integration is instance specific' do
|
||||
let!(:instance_integration) { create(:beyond_identity_integration) }
|
||||
|
||||
it 'does not create an integration from the instance level instance specific integration' do
|
||||
described_class.create_from_active_default_integrations(project, :project_id)
|
||||
|
||||
expect(project.reload.integrations).to be_blank
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.create_from_default_instance_specific_integrations' do
|
||||
context 'with an active instance-level integration' do
|
||||
let!(:instance_integration) { create(:beyond_identity_integration) }
|
||||
|
||||
it 'creates an integration from the instance-level integration' do
|
||||
described_class.create_from_default_instance_specific_integrations(project, :project_id)
|
||||
expect(project.reload.integrations.size).to eq(1)
|
||||
expect(project.reload.integrations.first.inherit_from_id).to eq(instance_integration.id)
|
||||
end
|
||||
|
||||
context 'when passing a group' do
|
||||
it 'creates an integration from the instance-level integration' do
|
||||
described_class.create_from_default_instance_specific_integrations(group, :group_id)
|
||||
|
||||
expect(group.reload.integrations.size).to eq(1)
|
||||
expect(group.reload.integrations.first.inherit_from_id).to eq(instance_integration.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with active group-level integration' do
|
||||
let!(:group_integration) { create(:beyond_identity_integration, group: group, instance: false) }
|
||||
|
||||
it 'creates an integration from the group-level integration' do
|
||||
described_class.create_from_default_instance_specific_integrations(project, :project_id)
|
||||
|
||||
expect(project.reload.integrations.size).to eq(1)
|
||||
expect(project.reload.integrations.first.inherit_from_id).to eq(group_integration.id)
|
||||
end
|
||||
|
||||
context 'when group level integration is not active' do
|
||||
let!(:group_integration) do
|
||||
create(:beyond_identity_integration, group: group, instance: false, active: false)
|
||||
end
|
||||
|
||||
it 'creates an integration from the group-level integration' do
|
||||
described_class.create_from_default_instance_specific_integrations(project, :project_id)
|
||||
|
||||
expect(project.reload.integrations.size).to eq(1)
|
||||
expect(project.reload.integrations.first.inherit_from_id).to eq(group_integration.id)
|
||||
expect(project.reload.integrations.first).not_to be_active
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passing a group' do
|
||||
let!(:subgroup) { create(:group, parent: group) }
|
||||
|
||||
it 'creates an integration from the group-level integration' do
|
||||
described_class.create_from_default_instance_specific_integrations(subgroup, :group_id)
|
||||
|
||||
expect(subgroup.reload.integrations.size).to eq(1)
|
||||
expect(subgroup.reload.integrations.first.inherit_from_id).to eq(group_integration.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an active subgroup' do
|
||||
let_it_be(:subgroup) { create(:group, parent: group) }
|
||||
let_it_be(:project) { create(:project, group: subgroup) }
|
||||
let!(:subgroup_integration) { create(:beyond_identity_integration, group: subgroup, instance: false) }
|
||||
|
||||
it 'creates an integration from the subgroup-level integration' do
|
||||
described_class.create_from_default_instance_specific_integrations(project, :project_id)
|
||||
|
||||
expect(project.reload.integrations.size).to eq(1)
|
||||
expect(project.reload.integrations.first.inherit_from_id).to eq(subgroup_integration.id)
|
||||
end
|
||||
|
||||
context 'when passing a group' do
|
||||
let!(:sub_subgroup) { create(:group, parent: subgroup) }
|
||||
|
||||
context 'with traversal queries' do
|
||||
shared_examples 'correct ancestor order' do
|
||||
it 'creates an integration from the subgroup-level integration' do
|
||||
described_class.create_from_default_instance_specific_integrations(sub_subgroup, :group_id)
|
||||
|
||||
sub_subgroup.reload
|
||||
|
||||
expect(sub_subgroup.integrations.size).to eq(1)
|
||||
expect(sub_subgroup.integrations.first.inherit_from_id).to eq(subgroup_integration.id)
|
||||
end
|
||||
|
||||
context 'when having an integration inheriting settings' do
|
||||
let!(:subgroup_integration) do
|
||||
create(:beyond_identity_integration, group: subgroup, inherit_from_id: group_integration.id,
|
||||
instance: false)
|
||||
end
|
||||
|
||||
it 'creates an integration from the group-level integration' do
|
||||
described_class.create_from_default_instance_specific_integrations(sub_subgroup, :group_id)
|
||||
|
||||
sub_subgroup.reload
|
||||
|
||||
expect(sub_subgroup.integrations.size).to eq(1)
|
||||
expect(sub_subgroup.integrations.first.inherit_from_id).to eq(group_integration.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'correct ancestor order'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the integration is not instance specific' do
|
||||
let!(:instance_integration) { create(:prometheus_integration, :instance) }
|
||||
|
||||
it 'does not create an integration from the instance level instance specific integration' do
|
||||
described_class.create_from_default_instance_specific_integrations(project, :project_id)
|
||||
|
||||
expect(project.reload.integrations).to be_blank
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1554,4 +1705,10 @@ RSpec.describe Integration, feature_category: :integrations do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.instance_specific_integration_types' do
|
||||
subject { described_class.instance_specific_integration_types }
|
||||
|
||||
it { is_expected.to eq(['Integrations::BeyondIdentity']) }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :shared d
|
|||
expect(json_response['ci_needs_size_limit']).to eq(Plan.default.actual_limits.ci_needs_size_limit)
|
||||
expect(json_response['ci_registered_group_runners']).to eq(Plan.default.actual_limits.ci_registered_group_runners)
|
||||
expect(json_response['ci_registered_project_runners']).to eq(Plan.default.actual_limits.ci_registered_project_runners)
|
||||
expect(json_response['dotenv_size']).to eq(Plan.default.actual_limits.dotenv_size)
|
||||
expect(json_response['dotenv_variables']).to eq(Plan.default.actual_limits.dotenv_variables)
|
||||
expect(json_response['conan_max_file_size']).to eq(Plan.default.actual_limits.conan_max_file_size)
|
||||
expect(json_response['generic_packages_max_file_size']).to eq(Plan.default.actual_limits.generic_packages_max_file_size)
|
||||
expect(json_response['helm_max_file_size']).to eq(Plan.default.actual_limits.helm_max_file_size)
|
||||
|
|
@ -104,6 +106,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :shared d
|
|||
ci_needs_size_limit: 106,
|
||||
ci_registered_group_runners: 107,
|
||||
ci_registered_project_runners: 108,
|
||||
dotenv_size: 109,
|
||||
dotenv_variables: 110,
|
||||
conan_max_file_size: 10,
|
||||
enforcement_limit: 100,
|
||||
generic_packages_max_file_size: 20,
|
||||
|
|
@ -127,6 +131,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :shared d
|
|||
expect(json_response['ci_needs_size_limit']).to eq(106)
|
||||
expect(json_response['ci_registered_group_runners']).to eq(107)
|
||||
expect(json_response['ci_registered_project_runners']).to eq(108)
|
||||
expect(json_response['dotenv_size']).to eq(109)
|
||||
expect(json_response['dotenv_variables']).to eq(110)
|
||||
expect(json_response['conan_max_file_size']).to eq(10)
|
||||
expect(json_response['enforcement_limit']).to eq(100)
|
||||
expect(json_response['generic_packages_max_file_size']).to eq(20)
|
||||
|
|
@ -179,6 +185,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :shared d
|
|||
ci_needs_size_limit: 'u',
|
||||
ci_registered_group_runners: 't',
|
||||
ci_registered_project_runners: 's',
|
||||
dotenv_size: 'r',
|
||||
dotenv_variables: 'q',
|
||||
conan_max_file_size: 'a',
|
||||
enforcement_limit: 'e',
|
||||
generic_packages_max_file_size: 'b',
|
||||
|
|
@ -203,6 +211,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :shared d
|
|||
'ci_needs_size_limit is invalid',
|
||||
'ci_registered_group_runners is invalid',
|
||||
'ci_registered_project_runners is invalid',
|
||||
'dotenv_size is invalid',
|
||||
'dotenv_variables is invalid',
|
||||
'conan_max_file_size is invalid',
|
||||
'enforcement_limit is invalid',
|
||||
'generic_packages_max_file_size is invalid',
|
||||
|
|
|
|||
|
|
@ -1011,7 +1011,8 @@ RSpec.describe 'Query.runner(id)', :freeze_time, feature_category: :fleet_visibi
|
|||
# - createdBy: Known N+1 issues, but only on exotic fields which we don't normally use
|
||||
# - ownerProject.pipeline: Needs arguments (iid or sha)
|
||||
# - project.productAnalyticsState: Can be requested only for 1 Project(s) at a time.
|
||||
let(:excluded_fields) { %w[createdBy jobs pipeline productAnalyticsState] }
|
||||
# - project.mergeTrains: Is a licensed feature
|
||||
let(:excluded_fields) { %w[createdBy jobs pipeline productAnalyticsState mergeTrains] }
|
||||
|
||||
it 'avoids N+1 queries', :use_sql_query_cache do
|
||||
discrete_runners_control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ RSpec.describe 'Query.runners', feature_category: :fleet_visibility do
|
|||
# Exclude fields from deeper objects which are problematic:
|
||||
# - ownerProject.pipeline: Needs arguments (iid or sha)
|
||||
# - project.productAnalyticsState: Can be requested only for 1 Project(s) at a time.
|
||||
let(:excluded_fields) { %w[pipeline productAnalyticsState] }
|
||||
# - mergeTrains Licensed feature
|
||||
let(:excluded_fields) { %w[pipeline productAnalyticsState mergeTrains] }
|
||||
|
||||
it 'returns expected runners' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ RSpec.describe 'getting container repositories in a group', feature_category: :s
|
|||
let_it_be(:container_repositories) { [container_repository, container_repositories_delete_scheduled, container_repositories_delete_failed].flatten }
|
||||
let_it_be(:container_expiration_policy) { project.container_expiration_policy }
|
||||
|
||||
let(:excluded_fields) { %w[pipeline jobs productAnalyticsState mlModels] }
|
||||
let(:excluded_fields) { %w[pipeline jobs productAnalyticsState mlModels mergeTrains] }
|
||||
let(:container_repositories_fields) do
|
||||
<<~GQL
|
||||
edges {
|
||||
|
|
@ -156,7 +156,7 @@ RSpec.describe 'getting container repositories in a group', feature_category: :s
|
|||
it_behaves_like 'handling graphql network errors with the container registry'
|
||||
|
||||
it_behaves_like 'not hitting graphql network errors with the container registry' do
|
||||
let(:excluded_fields) { %w[pipeline jobs tags tagsCount productAnalyticsState mlModels] }
|
||||
let(:excluded_fields) { %w[pipeline jobs tags tagsCount productAnalyticsState mlModels mergeTrains] }
|
||||
end
|
||||
|
||||
it 'returns the total count of container repositories' do
|
||||
|
|
|
|||
|
|
@ -16,7 +16,11 @@ RSpec.describe 'package details', feature_category: :package_registry do
|
|||
end
|
||||
|
||||
let(:depth) { 3 }
|
||||
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles runners inboundAllowlistCount groupsAllowlistCount] }
|
||||
let(:excluded) do
|
||||
%w[metadata apiFuzzingCiConfiguration pipeline packageFiles
|
||||
runners inboundAllowlistCount groupsAllowlistCount mergeTrains]
|
||||
end
|
||||
|
||||
let(:metadata) { query_graphql_fragment('ComposerMetadata') }
|
||||
let(:package_files) { all_graphql_fields_for('PackageFile') }
|
||||
let(:package_global_id) { global_id_of(composer_package) }
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ RSpec.describe 'getting container repositories in a project', feature_category:
|
|||
let_it_be(:container_repositories) { [container_repository, container_repositories_delete_scheduled, container_repositories_delete_failed].flatten }
|
||||
let_it_be(:container_expiration_policy) { project.container_expiration_policy }
|
||||
|
||||
let(:excluded_fields) { %w[pipeline jobs productAnalyticsState mlModels] }
|
||||
let(:excluded_fields) { %w[pipeline jobs productAnalyticsState mlModels mergeTrains] }
|
||||
let(:container_repositories_fields) do
|
||||
<<~GQL
|
||||
edges {
|
||||
|
|
@ -155,7 +155,7 @@ RSpec.describe 'getting container repositories in a project', feature_category:
|
|||
it_behaves_like 'handling graphql network errors with the container registry'
|
||||
|
||||
it_behaves_like 'not hitting graphql network errors with the container registry' do
|
||||
let(:excluded_fields) { %w[pipeline jobs tags tagsCount productAnalyticsState mlModels] }
|
||||
let(:excluded_fields) { %w[pipeline jobs tags tagsCount productAnalyticsState mlModels mergeTrains] }
|
||||
end
|
||||
|
||||
it 'returns the total count of container repositories' do
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ RSpec.describe 'getting notes for a merge request', feature_category: :code_revi
|
|||
notes {
|
||||
edges {
|
||||
node {
|
||||
#{all_graphql_fields_for('Note', excluded: ['pipeline'])}
|
||||
#{all_graphql_fields_for('Note', excluded: %w[pipeline mergeTrains])}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ RSpec.describe 'getting merge request information nested in a project', feature_
|
|||
# codequalityReportsComparer because it is behind a feature flag
|
||||
# and runners because the user is not an admin and therefore has no access
|
||||
# and inboundAllowlistCount, groupsAllowlistCount the user has no access
|
||||
# mergeTrains because it is a licensed feature
|
||||
let(:excluded) do
|
||||
%w[jobs pipeline runners codequalityReportsComparer mlModels inboundAllowlistCount groupsAllowlistCount]
|
||||
%w[jobs pipeline runners codequalityReportsComparer
|
||||
mlModels inboundAllowlistCount groupsAllowlistCount mergeTrains]
|
||||
end
|
||||
|
||||
let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: excluded) }
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ RSpec.describe API::ProjectImport, :aggregate_failures, feature_category: :impor
|
|||
it 'executes a limited number of queries', :use_clean_rails_redis_caching do
|
||||
control = ActiveRecord::QueryRecorder.new { perform_archive_upload }
|
||||
|
||||
expect(control.count).to be <= 113
|
||||
expect(control.count).to be <= 114
|
||||
end
|
||||
|
||||
it 'schedules an import using a namespace' do
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ RSpec.describe Ci::UpdateBuildNamesService, feature_category: :continuous_integr
|
|||
let_it_be(:build1) { create(:ci_build, name: 'build1', pipeline: pipeline) }
|
||||
let_it_be(:build2) { create(:ci_build, name: 'build2', pipeline: pipeline) }
|
||||
let_it_be(:build3) { create(:ci_build, name: 'build3', pipeline: pipeline) }
|
||||
let_it_be(:bridge1) { create(:ci_bridge, name: 'bridge1', pipeline: pipeline) }
|
||||
|
||||
describe '#execute' do
|
||||
subject(:service) { described_class.new(pipeline) }
|
||||
|
|
@ -54,5 +55,11 @@ RSpec.describe Ci::UpdateBuildNamesService, feature_category: :continuous_integr
|
|||
|
||||
service.execute
|
||||
end
|
||||
|
||||
it 'does not create build name for bridge job' do
|
||||
service.execute
|
||||
|
||||
expect(Ci::BuildName.find_by_build_id(bridge1.id)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -326,6 +326,30 @@ RSpec.describe Groups::CreateService, '#execute', feature_category: :groups_and_
|
|||
end
|
||||
end
|
||||
|
||||
context 'when an instance-level instance specific integration' do
|
||||
let_it_be(:instance_specific_integration) { create(:beyond_identity_integration) }
|
||||
|
||||
it 'creates integration inheriting from the instance level integration' do
|
||||
expect(created_group.integrations.count).to eq(1)
|
||||
expect(created_group.integrations.last.active).to eq(instance_specific_integration.active)
|
||||
expect(created_group.integrations.last.inherit_from_id).to eq(instance_specific_integration.id)
|
||||
end
|
||||
|
||||
context 'when there is a group-level exclusion' do
|
||||
let(:extra_params) { { parent_id: group.id } }
|
||||
let_it_be(:group) { create(:group) { |g| g.add_owner(user) } }
|
||||
let_it_be(:group_integration) do
|
||||
create(:beyond_identity_integration, group: group, instance: false, active: false)
|
||||
end
|
||||
|
||||
it 'creates a service from the group-level integration' do
|
||||
expect(created_group.integrations.count).to eq(1)
|
||||
expect(created_group.integrations.last.active).to eq(group_integration.active)
|
||||
expect(created_group.integrations.last.inherit_from_id).to eq(group_integration.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an active instance-level integration' do
|
||||
let_it_be(:instance_integration) do
|
||||
create(:prometheus_integration, :instance, api_url: 'https://prometheus.instance.com/')
|
||||
|
|
|
|||
|
|
@ -365,6 +365,31 @@ RSpec.describe Groups::TransferService, :sidekiq_inline, feature_category: :grou
|
|||
end
|
||||
end
|
||||
|
||||
context 'with instance specific integration' do
|
||||
let_it_be(:instance_specific_integration) { create(:beyond_identity_integration) }
|
||||
let_it_be(:group_instance_specific_integration) do
|
||||
create(
|
||||
:beyond_identity_integration,
|
||||
group: group,
|
||||
instance: false,
|
||||
active: true,
|
||||
inherit_from_id: instance_specific_integration.id
|
||||
)
|
||||
end
|
||||
|
||||
let_it_be(:parent_group_instance_specific_integration) do
|
||||
create(:beyond_identity_integration, group: new_parent_group, instance: false, active: false)
|
||||
end
|
||||
|
||||
it 'replaces inherited integrations', :aggregate_failures do
|
||||
new_group_instance_specific_integration = Integration.find_by(group: group, type: instance_specific_integration.type)
|
||||
expect(new_group_instance_specific_integration.inherit_from_id).to eq(parent_group_instance_specific_integration.id)
|
||||
expect(new_group_instance_specific_integration.active).to be_falsey
|
||||
expect(PropagateIntegrationWorker).to have_received(:perform_async).with(new_group_instance_specific_integration.id)
|
||||
expect(Integration.count).to eq(5)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a custom integration' do
|
||||
let_it_be(:group_integration) { create(:integrations_slack, :group, group: group, webhook: 'http://group.slack.com') }
|
||||
|
||||
|
|
|
|||
|
|
@ -868,6 +868,41 @@ RSpec.describe Projects::CreateService, '#execute', feature_category: :groups_an
|
|||
describe 'create integration for the project' do
|
||||
subject(:project) { create_project(user, opts) }
|
||||
|
||||
context 'when an instance-level instance specific integration' do
|
||||
let!(:instance_specific_integration) { create(:beyond_identity_integration) }
|
||||
|
||||
it 'creates integration inheriting from the instance level integration' do
|
||||
expect(project.integrations.count).to eq(1)
|
||||
expect(project.integrations.first.active).to eq(instance_specific_integration.active)
|
||||
expect(project.integrations.first.inherit_from_id).to eq(instance_specific_integration.id)
|
||||
end
|
||||
|
||||
context 'when there is a group-level exclusion' do
|
||||
let(:opts) do
|
||||
{
|
||||
name: project_name,
|
||||
namespace_id: group.id
|
||||
}
|
||||
end
|
||||
|
||||
let!(:group) do
|
||||
create(:group).tap do |group|
|
||||
group.add_owner(user)
|
||||
end
|
||||
end
|
||||
|
||||
let!(:group_integration) do
|
||||
create(:beyond_identity_integration, group: group, instance: false, active: false)
|
||||
end
|
||||
|
||||
it 'creates a service from the group-level integration' do
|
||||
expect(project.integrations.count).to eq(1)
|
||||
expect(project.integrations.first.active).to eq(group_integration.active)
|
||||
expect(project.integrations.first.inherit_from_id).to eq(group_integration.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an active instance-level integration' do
|
||||
let!(:instance_integration) { create(:prometheus_integration, :instance, api_url: 'https://prometheus.instance.com/') }
|
||||
|
||||
|
|
|
|||
|
|
@ -274,6 +274,29 @@ RSpec.describe Projects::TransferService, feature_category: :groups_and_projects
|
|||
expect { execute_transfer }.not_to change { project.slack_integration.webhook }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the new default integration is instance specific and deactivated' do
|
||||
let!(:instance_specific_integration) { create(:beyond_identity_integration) }
|
||||
let!(:project_instance_specific_integration) do
|
||||
create(
|
||||
:beyond_identity_integration,
|
||||
project: project,
|
||||
instance: false,
|
||||
active: true,
|
||||
inherit_from_id: instance_specific_integration.id
|
||||
)
|
||||
end
|
||||
|
||||
let!(:group_instance_specific_integration) do
|
||||
create(:beyond_identity_integration, group: target, instance: false, active: false)
|
||||
end
|
||||
|
||||
it 'creates an integration inheriting from the default' do
|
||||
expect { execute_transfer }
|
||||
.to change { project.beyond_identity_integration.reload.active }.from(true).to(false)
|
||||
.and change { project.beyond_identity_integration.inherit_from_id }.to(group_instance_specific_integration.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project has pending builds', :sidekiq_inline do
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ RSpec.shared_context 'package details setup' do
|
|||
let(:package_global_id) { global_id_of(package) }
|
||||
|
||||
let(:depth) { 3 }
|
||||
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] }
|
||||
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles mergeTrains] }
|
||||
let(:package_files) { all_graphql_fields_for('PackageFile') }
|
||||
let(:dependency_links) { all_graphql_fields_for('PackageDependencyLink') }
|
||||
let(:pipelines) { all_graphql_fields_for('Pipeline', max_depth: 1) }
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ RSpec.describe 'admin/application_settings/_ci_cd' do
|
|||
ci_needs_size_limit: 50,
|
||||
ci_registered_group_runners: 60,
|
||||
ci_registered_project_runners: 70,
|
||||
dotenv_size: 80,
|
||||
dotenv_variables: 90,
|
||||
pipeline_hierarchy_size: 300
|
||||
}
|
||||
end
|
||||
|
|
@ -44,6 +46,12 @@ RSpec.describe 'admin/application_settings/_ci_cd' do
|
|||
type: 'number')
|
||||
expect(page.find_field('Maximum number of Instance-level CI/CD variables that can be defined').value).to eq('5')
|
||||
|
||||
expect(rendered).to have_field('Maximum size of a dotenv artifact in bytes', type: 'number')
|
||||
expect(page.find_field('Maximum size of a dotenv artifact in bytes').value).to eq('80')
|
||||
|
||||
expect(rendered).to have_field('Maximum number of variables in a dotenv artifact', type: 'number')
|
||||
expect(page.find_field('Maximum number of variables in a dotenv artifact').value).to eq('90')
|
||||
|
||||
expect(rendered).to have_field('Maximum number of jobs in a single pipeline', type: 'number')
|
||||
expect(page.find_field('Maximum number of jobs in a single pipeline').value).to eq('10')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue