Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-06-11 18:24:06 +00:00
parent b377f6d091
commit f731c095d6
87 changed files with 903 additions and 196 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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', '')"
>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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?

View File

@ -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

View File

@ -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'

View File

@ -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')

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
3914eb6a992c6df54e74f24fb5c7890faaab0c46c27506e24840054704790b56

View File

@ -0,0 +1 @@
1a01537566a911ff788e5345c806e58930e7f8d8348126df7a9490ffa4700fc3

View File

@ -0,0 +1 @@
f8dc0c648771a938526d6b14d9967c352fad08547a939eb177c0e6639b727e52

View File

@ -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);

View File

@ -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:

View File

@ -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.

View File

@ -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,

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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

View File

@ -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.
![Forecast deployment frequency](img/forecast_deployment_frequency.png)
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**.

View File

@ -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

View File

@ -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:

View File

@ -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 -->

View File

@ -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

View File

@ -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.

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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.

View File

@ -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

View File

@ -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 |
| :-----: | :---------- |
| ![Approvals not yet satisfied](img/approvals_unsatisfied_v17_1.png) | Required approvals are missing. (**{approval}**) |
| ![Approvals are satisfied](img/approvals_satisfied_v17_1.png) | Approvals are satisfied. (**{check}**) |
| ![Approvals are satisfied, and you approved](img/you_approvals_satisfied_v17_1.png) | 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. -->

View File

@ -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 -->

View File

@ -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'

View File

@ -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 }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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

View File

@ -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',

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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) }

View File

@ -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

View File

@ -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])}
}
}
}

View File

@ -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) }

View File

@ -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

View File

@ -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

View File

@ -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/')

View File

@ -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') }

View File

@ -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/') }

View File

@ -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

View File

@ -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) }

View File

@ -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')