Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
7b6a6bfc58
commit
c55eb679a2
39 changed files with 512 additions and 437 deletions
|
@ -153,7 +153,7 @@ export default {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="cycle-analytics">
|
<div>
|
||||||
<h3>{{ $options.i18n.pageTitle }}</h3>
|
<h3>{{ $options.i18n.pageTitle }}</h3>
|
||||||
<div class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row">
|
<div class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row">
|
||||||
<path-navigation
|
<path-navigation
|
||||||
|
|
|
@ -213,7 +213,7 @@ export default {
|
||||||
<p class="gl-m-0">
|
<p class="gl-m-0">
|
||||||
<gl-link
|
<gl-link
|
||||||
data-testid="vsa-stage-event-link"
|
data-testid="vsa-stage-event-link"
|
||||||
class="gl-text-black-normal pipeline-id"
|
class="gl-text-black-normal"
|
||||||
:href="item.url"
|
:href="item.url"
|
||||||
>{{ itemId(item.id, '#') }}</gl-link
|
>{{ itemId(item.id, '#') }}</gl-link
|
||||||
>
|
>
|
||||||
|
|
|
@ -84,6 +84,14 @@ export default {
|
||||||
showNoMatchingResultsMessage() {
|
showNoMatchingResultsMessage() {
|
||||||
return Boolean(this.searchKey) && this.visibleLabels.length === 0;
|
return Boolean(this.searchKey) && this.visibleLabels.length === 0;
|
||||||
},
|
},
|
||||||
|
shouldHighlighFirstItem() {
|
||||||
|
return this.searchKey !== '' && this.visibleLabels.length > 0;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
updated() {
|
||||||
|
if (this.shouldHighlighFirstItem) {
|
||||||
|
this.$refs.labelItem[0]?.$el?.firstChild?.focus();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isLabelSelected(label) {
|
isLabelSelected(label) {
|
||||||
|
@ -143,11 +151,14 @@ export default {
|
||||||
/>
|
/>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<gl-dropdown-item
|
<gl-dropdown-item
|
||||||
v-for="label in visibleLabels"
|
v-for="(label, index) in visibleLabels"
|
||||||
|
ref="labelItem"
|
||||||
:key="label.id"
|
:key="label.id"
|
||||||
:is-checked="isLabelSelected(label)"
|
:is-checked="isLabelSelected(label)"
|
||||||
:is-check-centered="true"
|
:is-check-centered="true"
|
||||||
:is-check-item="true"
|
:is-check-item="true"
|
||||||
|
:active="shouldHighlighFirstItem && index === 0"
|
||||||
|
active-class="is-focused"
|
||||||
data-testid="labels-list"
|
data-testid="labels-list"
|
||||||
@click.native.capture.stop="handleLabelClick(label)"
|
@click.native.capture.stop="handleLabelClick(label)"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
@import 'mixins_and_variables_and_functions';
|
|
||||||
|
|
||||||
.cycle-analytics {
|
|
||||||
margin: 24px auto 0;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
|
@ -20,7 +20,7 @@ module SessionlessAuthentication
|
||||||
end
|
end
|
||||||
|
|
||||||
def sessionless_sign_in(user)
|
def sessionless_sign_in(user)
|
||||||
if can?(user, :log_in) && !user.password_expired_if_applicable?
|
if user.can_log_in_with_non_expired_password?
|
||||||
# Notice we are passing store false, so the user is not
|
# Notice we are passing store false, so the user is not
|
||||||
# actually stored in the session and a token is needed
|
# actually stored in the session and a token is needed
|
||||||
# for every request. If you want the token to work as a
|
# for every request. If you want the token to work as a
|
||||||
|
|
|
@ -9,7 +9,6 @@ class Groups::BoardsController < Groups::ApplicationController
|
||||||
before_action do
|
before_action do
|
||||||
push_frontend_feature_flag(:issue_boards_filtered_search, group, default_enabled: :yaml)
|
push_frontend_feature_flag(:issue_boards_filtered_search, group, default_enabled: :yaml)
|
||||||
push_frontend_feature_flag(:board_multi_select, group, default_enabled: :yaml)
|
push_frontend_feature_flag(:board_multi_select, group, default_enabled: :yaml)
|
||||||
push_frontend_feature_flag(:swimlanes_buffered_rendering, group, default_enabled: :yaml)
|
|
||||||
push_frontend_feature_flag(:iteration_cadences, group, default_enabled: :yaml)
|
push_frontend_feature_flag(:iteration_cadences, group, default_enabled: :yaml)
|
||||||
experiment(:prominent_create_board_btn, subject: current_user) do |e|
|
experiment(:prominent_create_board_btn, subject: current_user) do |e|
|
||||||
e.use { }
|
e.use { }
|
||||||
|
|
|
@ -7,7 +7,6 @@ class Projects::BoardsController < Projects::ApplicationController
|
||||||
before_action :check_issues_available!
|
before_action :check_issues_available!
|
||||||
before_action :assign_endpoint_vars
|
before_action :assign_endpoint_vars
|
||||||
before_action do
|
before_action do
|
||||||
push_frontend_feature_flag(:swimlanes_buffered_rendering, project, default_enabled: :yaml)
|
|
||||||
push_frontend_feature_flag(:issue_boards_filtered_search, project&.group, default_enabled: :yaml)
|
push_frontend_feature_flag(:issue_boards_filtered_search, project&.group, default_enabled: :yaml)
|
||||||
push_frontend_feature_flag(:board_multi_select, project, default_enabled: :yaml)
|
push_frontend_feature_flag(:board_multi_select, project, default_enabled: :yaml)
|
||||||
push_frontend_feature_flag(:iteration_cadences, project&.group, default_enabled: :yaml)
|
push_frontend_feature_flag(:iteration_cadences, project&.group, default_enabled: :yaml)
|
||||||
|
|
|
@ -426,7 +426,9 @@ module ApplicationHelper
|
||||||
return if current_user
|
return if current_user
|
||||||
|
|
||||||
experiment(:logged_out_marketing_header, actor: nil) do |e|
|
experiment(:logged_out_marketing_header, actor: nil) do |e|
|
||||||
e.candidate { 'logged-out-marketing-header-candidate' }
|
html_class = 'logged-out-marketing-header-candidate'
|
||||||
|
e.candidate { html_class }
|
||||||
|
e.try(:trial_focused) { html_class }
|
||||||
e.control {}
|
e.control {}
|
||||||
e.run
|
e.run
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,8 +38,7 @@ module IssuablesDescriptionTemplatesHelper
|
||||||
# Only local templates will be listed if licenses for inherited templates are not present
|
# Only local templates will be listed if licenses for inherited templates are not present
|
||||||
all_templates = all_templates.values.flatten.map { |tpl| tpl[:name] }.compact.uniq
|
all_templates = all_templates.values.flatten.map { |tpl| tpl[:name] }.compact.uniq
|
||||||
|
|
||||||
template = all_templates.find { |tmpl_name| tmpl_name == params[:issuable_template] }
|
all_templates.find { |tmpl_name| tmpl_name == params[:issuable_template] }
|
||||||
template || all_templates.find { |tmpl_name| tmpl_name.casecmp?('default') }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def available_service_desk_templates_for(project)
|
def available_service_desk_templates_for(project)
|
||||||
|
|
|
@ -1901,6 +1901,10 @@ class User < ApplicationRecord
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_log_in_with_non_expired_password?
|
||||||
|
can?(:log_in) && !password_expired_if_applicable?
|
||||||
|
end
|
||||||
|
|
||||||
def can_be_deactivated?
|
def can_be_deactivated?
|
||||||
active? && no_recent_activity? && !internal?
|
active? && no_recent_activity? && !internal?
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,57 +13,72 @@
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"exception": {
|
"exception": {
|
||||||
"type": "object",
|
"oneOf": [
|
||||||
"required": ["values"],
|
{
|
||||||
"properties": {
|
|
||||||
"values": {
|
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"$ref": "#/definitions/exception"
|
||||||
"required": [],
|
}
|
||||||
"properties": {
|
},
|
||||||
"type": {
|
{
|
||||||
"type": "string"
|
"type": "object",
|
||||||
},
|
"required": ["values"],
|
||||||
"value": {
|
"properties": {
|
||||||
"type": "string"
|
"values": {
|
||||||
},
|
"type": "array",
|
||||||
"stacktrace": {
|
"items": {
|
||||||
|
"$ref": "#/definitions/exception"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"exception": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"stacktrace": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [],
|
||||||
|
"properties": {
|
||||||
|
"frames": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [],
|
"required": [],
|
||||||
"properties": {
|
"properties": {
|
||||||
"frames": {
|
"abs_path": {
|
||||||
"type": "array",
|
"type": "string"
|
||||||
"items": {
|
},
|
||||||
"type": "object",
|
"function": {
|
||||||
"required": [],
|
"type": "string"
|
||||||
"properties": {
|
},
|
||||||
"abs_path": {
|
"lineno": {
|
||||||
"type": "string"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"function": {
|
"in_app": {
|
||||||
"type": "string"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"lineno": {
|
"filename": {
|
||||||
"type": "number"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"in_app": {
|
"pre_context": {
|
||||||
"type": "boolean"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"filename": {
|
"context_line": {
|
||||||
"type": "string"
|
"type": ["string", "null"]
|
||||||
},
|
},
|
||||||
"pre_context": {
|
"post_context": {
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
|
||||||
"context_line": {
|
|
||||||
"type": ["string", "null"]
|
|
||||||
},
|
|
||||||
"post_context": {
|
|
||||||
"type": "array"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
= f.check_box :container_expiration_policies_enable_historic_entries, class: 'form-check-input'
|
= f.check_box :container_expiration_policies_enable_historic_entries, class: 'form-check-input'
|
||||||
= f.label :container_expiration_policies_enable_historic_entries, class: 'form-check-label' do
|
= f.label :container_expiration_policies_enable_historic_entries, class: 'form-check-label' do
|
||||||
= _("Enable container expiration and retention policies for projects created earlier than GitLab 12.7.")
|
= _("Enable container expiration and retention policies for projects created earlier than GitLab 12.7.")
|
||||||
= link_to sprite_icon('question-o'), help_page_path('user/packages/container_registry/index', anchor: 'cleanup-policy')
|
= link_to sprite_icon('question-o'), help_page_path('user/packages/container_registry/reduce_container_registry_storage', anchor: 'cleanup-policy')
|
||||||
.form-text.text-muted
|
.form-text.text-muted
|
||||||
= _("Existing projects will be able to use expiration policies. Avoid enabling this if an external Container Registry is being used, as there is a performance risk if many images exist on one project.")
|
= _("Existing projects will be able to use expiration policies. Avoid enabling this if an external Container Registry is being used, as there is a performance risk if many images exist on one project.")
|
||||||
= link_to sprite_icon('question-o'), help_page_path('user/packages/container_registry/index', anchor: 'use-with-external-container-registries')
|
= link_to sprite_icon('question-o'), help_page_path('user/packages/container_registry/reduce_container_registry_storage', anchor: 'use-with-external-container-registries')
|
||||||
- if container_registry_expiration_policies_throttling?
|
- if container_registry_expiration_policies_throttling?
|
||||||
.form-group
|
.form-group
|
||||||
= f.label :container_registry_delete_tags_service_timeout, _('Cleanup policy maximum processing time (seconds)'), class: 'label-bold'
|
= f.label :container_registry_delete_tags_service_timeout, _('Cleanup policy maximum processing time (seconds)'), class: 'label-bold'
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
- experiment(:logged_out_marketing_header, actor: nil) do |e|
|
- experiment(:logged_out_marketing_header, actor: nil) do |e|
|
||||||
- e.candidate do
|
- e.candidate do
|
||||||
= render 'layouts/header/marketing_links'
|
= render 'layouts/header/marketing_links'
|
||||||
|
- e.try(:trial_focused) do
|
||||||
|
= render 'layouts/header/marketing_links'
|
||||||
- e.control do
|
- e.control do
|
||||||
.gl-display-none.gl-sm-display-block
|
.gl-display-none.gl-sm-display-block
|
||||||
= render "layouts/nav/top_nav"
|
= render "layouts/nav/top_nav"
|
||||||
|
@ -117,6 +119,9 @@
|
||||||
- e.candidate do
|
- e.candidate do
|
||||||
%li.nav-item.gl-display-none.gl-sm-display-block
|
%li.nav-item.gl-display-none.gl-sm-display-block
|
||||||
= render "layouts/nav/top_nav"
|
= render "layouts/nav/top_nav"
|
||||||
|
- e.try(:trial_focused) do
|
||||||
|
%li.nav-item.gl-display-none.gl-sm-display-block
|
||||||
|
= render "layouts/nav/top_nav"
|
||||||
- e.control {}
|
- e.control {}
|
||||||
- if header_link?(:user_dropdown)
|
- if header_link?(:user_dropdown)
|
||||||
%li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { track_label: "profile_dropdown", track_action: "click_dropdown", track_value: "", qa_selector: 'user_menu' }, class: ('mr-0' if has_impersonation_link) }
|
%li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { track_label: "profile_dropdown", track_action: "click_dropdown", track_value: "", qa_selector: 'user_menu' }, class: ('mr-0' if has_impersonation_link) }
|
||||||
|
@ -138,6 +143,14 @@
|
||||||
%li.nav-item.gl-display-none.gl-sm-display-block
|
%li.nav-item.gl-display-none.gl-sm-display-block
|
||||||
= link_to _('Login'), new_session_path(:user, redirect_to_referer: 'yes')
|
= link_to _('Login'), new_session_path(:user, redirect_to_referer: 'yes')
|
||||||
= render 'layouts/header/sign_in_register_button', class: 'gl-sm-display-none'
|
= render 'layouts/header/sign_in_register_button', class: 'gl-sm-display-none'
|
||||||
|
- e.try(:trial_focused) do
|
||||||
|
%li.nav-item.gl-display-none.gl-sm-display-block
|
||||||
|
= link_to _('Get a free trial'), 'https://about.gitlab.com/free-trial/', class: 'gl-button btn btn-default btn-sign-in'
|
||||||
|
%li.nav-item.gl-display-none.gl-sm-display-block
|
||||||
|
= link_to _('Sign up'), new_user_registration_path
|
||||||
|
%li.nav-item.gl-display-none.gl-sm-display-block
|
||||||
|
= link_to _('Login'), new_session_path(:user, redirect_to_referer: 'yes')
|
||||||
|
= render 'layouts/header/sign_in_register_button', class: 'gl-sm-display-none'
|
||||||
- e.control do
|
- e.control do
|
||||||
= render 'layouts/header/sign_in_register_button'
|
= render 'layouts/header/sign_in_register_button'
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"containers_error_image" => image_path('illustrations/docker-error-state.svg'),
|
"containers_error_image" => image_path('illustrations/docker-error-state.svg'),
|
||||||
"repository_url" => escape_once(@project.container_registry_url),
|
"repository_url" => escape_once(@project.container_registry_url),
|
||||||
"registry_host_url_with_port" => escape_once(registry_config.host_port),
|
"registry_host_url_with_port" => escape_once(registry_config.host_port),
|
||||||
"expiration_policy_help_page_path" => help_page_path('user/packages/container_registry/index.md', anchor: 'cleanup-policy'),
|
"expiration_policy_help_page_path" => help_page_path('user/packages/container_registry/reduce_container_registry_storage', anchor: 'cleanup-policy'),
|
||||||
"garbage_collection_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'container-registry-garbage-collection'),
|
"garbage_collection_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'container-registry-garbage-collection'),
|
||||||
"run_cleanup_policies_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'run-the-cleanup-policy-now'),
|
"run_cleanup_policies_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'run-the-cleanup-policy-now'),
|
||||||
"project_path": @project.full_path,
|
"project_path": @project.full_path,
|
||||||
|
|
|
@ -10,6 +10,6 @@
|
||||||
is_admin: current_user&.admin.to_s,
|
is_admin: current_user&.admin.to_s,
|
||||||
admin_settings_path: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'),
|
admin_settings_path: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'),
|
||||||
enable_historic_entries: container_expiration_policies_historic_entry_enabled?(@project).to_s,
|
enable_historic_entries: container_expiration_policies_historic_entry_enabled?(@project).to_s,
|
||||||
help_page_path: help_page_path('user/packages/container_registry/index', anchor: 'cleanup-policy'),
|
help_page_path: help_page_path('user/packages/container_registry/reduce_container_registry_storage', anchor: 'cleanup-policy'),
|
||||||
show_cleanup_policy_on_alert: show_cleanup_policy_on_alert(@project).to_s,
|
show_cleanup_policy_on_alert: show_cleanup_policy_on_alert(@project).to_s,
|
||||||
tags_regex_help_page_path: help_page_path('user/packages/container_registry/index', anchor: 'regex-pattern-examples') } }
|
tags_regex_help_page_path: help_page_path('user/packages/container_registry/reduce_container_registry_storage', anchor: 'regex-pattern-examples') } }
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
name: swimlanes_buffered_rendering
|
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56614
|
|
||||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/324994
|
|
||||||
milestone: '13.11'
|
|
||||||
type: development
|
|
||||||
group: group::product planning
|
|
||||||
default_enabled: false
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RemoveProjectsCiDailyBuildGroupReportResultsProjectIdFk < Gitlab::Database::Migration[1.0]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
with_lock_retries do
|
||||||
|
execute('LOCK projects, ci_daily_build_group_report_results IN ACCESS EXCLUSIVE MODE')
|
||||||
|
remove_foreign_key_if_exists(:ci_daily_build_group_report_results, :projects, name: "fk_rails_0667f7608c")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
add_concurrent_foreign_key(:ci_daily_build_group_report_results, :projects, name: "fk_rails_0667f7608c", column: :project_id, target_column: :id, on_delete: "cascade")
|
||||||
|
end
|
||||||
|
end
|
1
db/schema_migrations/20220112232723
Normal file
1
db/schema_migrations/20220112232723
Normal file
|
@ -0,0 +1 @@
|
||||||
|
cbea97a0d067939ba9d713489448cb6e0cc45b2bbd2c717ecf521493cc39d568
|
|
@ -29973,9 +29973,6 @@ ALTER TABLE ONLY ip_restrictions
|
||||||
ALTER TABLE ONLY terraform_state_versions
|
ALTER TABLE ONLY terraform_state_versions
|
||||||
ADD CONSTRAINT fk_rails_04f176e239 FOREIGN KEY (terraform_state_id) REFERENCES terraform_states(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_rails_04f176e239 FOREIGN KEY (terraform_state_id) REFERENCES terraform_states(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_daily_build_group_report_results
|
|
||||||
ADD CONSTRAINT fk_rails_0667f7608c FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_subscriptions_projects
|
ALTER TABLE ONLY ci_subscriptions_projects
|
||||||
ADD CONSTRAINT fk_rails_0818751483 FOREIGN KEY (downstream_project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_rails_0818751483 FOREIGN KEY (downstream_project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
|
@ -694,7 +694,7 @@ project, you can [disable it from your project's settings](../../user/project/se
|
||||||
## Use an external container registry with GitLab as an auth endpoint
|
## Use an external container registry with GitLab as an auth endpoint
|
||||||
|
|
||||||
If you use an external container registry, some features associated with the
|
If you use an external container registry, some features associated with the
|
||||||
container registry may be unavailable or have [inherent risks](../../user/packages/container_registry/index.md#use-with-external-container-registries).
|
container registry may be unavailable or have [inherent risks](../../user/packages/container_registry/reduce_container_registry_storage.md#use-with-external-container-registries).
|
||||||
|
|
||||||
For the integration to work, the external registry must be configured to
|
For the integration to work, the external registry must be configured to
|
||||||
use a JSON Web Token to authenticate with GitLab. The
|
use a JSON Web Token to authenticate with GitLab. The
|
||||||
|
@ -883,7 +883,7 @@ project.container_repositories.find_each do |repo|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also [run cleanup on a schedule](../../user/packages/container_registry/index.md#cleanup-policy).
|
You can also [run cleanup on a schedule](../../user/packages/container_registry/reduce_container_registry_storage.md#cleanup-policy).
|
||||||
|
|
||||||
## Container Registry garbage collection
|
## Container Registry garbage collection
|
||||||
|
|
||||||
|
|
|
@ -394,7 +394,7 @@ The number of tags deleted by this API is limited on GitLab.com
|
||||||
because of the scale of the Container Registry there.
|
because of the scale of the Container Registry there.
|
||||||
If your Container Registry has a large number of tags to delete,
|
If your Container Registry has a large number of tags to delete,
|
||||||
only some of them will be deleted, and you might need to call this API multiple times.
|
only some of them will be deleted, and you might need to call this API multiple times.
|
||||||
To schedule tags for automatic deletion, use a [cleanup policy](../user/packages/container_registry/index.md#cleanup-policy) instead.
|
To schedule tags for automatic deletion, use a [cleanup policy](../user/packages/container_registry/reduce_container_registry_storage.md#cleanup-policy) instead.
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
In GitLab 12.4 and later, individual tags are deleted.
|
In GitLab 12.4 and later, individual tags are deleted.
|
||||||
|
|
|
@ -78,7 +78,7 @@ The single entrypoint for the registry is the [HTTP API](https://gitlab.com/gitl
|
||||||
| Operation | UI | Background | Observations |
|
| Operation | UI | Background | Observations |
|
||||||
| ------------------------------------------------------------ | ------------------ | ------------------------ | ------------------------------------------------------------ |
|
| ------------------------------------------------------------ | ------------------ | ------------------------ | ------------------------------------------------------------ |
|
||||||
| [Check API version](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#api-version-check) | **{check-circle}** Yes | **{check-circle}** Yes | Used globally to ensure that the registry supports the Docker Distribution V2 API, as well as for identifying whether GitLab Rails is talking to the GitLab Container Registry or a third-party one (used to toggle features only available in the former). |
|
| [Check API version](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#api-version-check) | **{check-circle}** Yes | **{check-circle}** Yes | Used globally to ensure that the registry supports the Docker Distribution V2 API, as well as for identifying whether GitLab Rails is talking to the GitLab Container Registry or a third-party one (used to toggle features only available in the former). |
|
||||||
| [List repository tags](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#listing-image-tags) | **{check-circle}** Yes | **{check-circle}** Yes | Used to list and show tags in the UI. Used to list tags in the background for [cleanup policies](../../../user/packages/container_registry/#cleanup-policy) and [Geo replication](../../../administration/geo/replication/docker_registry.md). |
|
| [List repository tags](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#listing-image-tags) | **{check-circle}** Yes | **{check-circle}** Yes | Used to list and show tags in the UI. Used to list tags in the background for [cleanup policies](../../../user/packages/container_registry/reduce_container_registry_storage.md#cleanup-policy) and [Geo replication](../../../administration/geo/replication/docker_registry.md). |
|
||||||
| [Check if manifest exists](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#existing-manifests) | **{check-circle}** Yes | **{dotted-circle}** No | Used to get the digest of a manifest by tag. This is then used to pull the manifest and show the tag details in the UI. |
|
| [Check if manifest exists](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#existing-manifests) | **{check-circle}** Yes | **{dotted-circle}** No | Used to get the digest of a manifest by tag. This is then used to pull the manifest and show the tag details in the UI. |
|
||||||
| [Pull manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-an-image-manifest) | **{check-circle}** Yes | **{dotted-circle}** No | Used to show the image size and the manifest digest in the tag details UI. |
|
| [Pull manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-an-image-manifest) | **{check-circle}** Yes | **{dotted-circle}** No | Used to show the image size and the manifest digest in the tag details UI. |
|
||||||
| [Pull blob](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-a-layer) | **{check-circle}** Yes | **{dotted-circle}** No | Used to show the configuration digest and the creation date in the tag details UI. |
|
| [Pull blob](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-a-layer) | **{check-circle}** Yes | **{dotted-circle}** No | Used to show the configuration digest and the creation date in the tag details UI. |
|
||||||
|
|
|
@ -64,7 +64,7 @@ The **CI/CD** settings contain:
|
||||||
This pipeline configuration is run after the project's own configuration.
|
This pipeline configuration is run after the project's own configuration.
|
||||||
- [Package Registry](continuous_integration.md#package-registry-configuration) -
|
- [Package Registry](continuous_integration.md#package-registry-configuration) -
|
||||||
Settings related to the use and experience of using the GitLab Package Registry. Some
|
Settings related to the use and experience of using the GitLab Package Registry. Some
|
||||||
[risks are involved](../../packages/container_registry/index.md#use-with-external-container-registries)
|
[risks are involved](../../packages/container_registry/reduce_container_registry_storage.md#use-with-external-container-registries)
|
||||||
in enabling some of these settings.
|
in enabling some of these settings.
|
||||||
|
|
||||||
### Geo **(PREMIUM SELF)**
|
### Geo **(PREMIUM SELF)**
|
||||||
|
|
|
@ -483,256 +483,9 @@ defined in the `delete_image` job.
|
||||||
|
|
||||||
### Delete images by using a cleanup policy
|
### Delete images by using a cleanup policy
|
||||||
|
|
||||||
You can create a per-project [cleanup policy](#cleanup-policy) to ensure older tags and images are regularly removed from the
|
You can create a per-project [cleanup policy](reduce_container_registry_storage.md#cleanup-policy) to ensure older tags and images are regularly removed from the
|
||||||
Container Registry.
|
Container Registry.
|
||||||
|
|
||||||
## Cleanup policy
|
|
||||||
|
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15398) in GitLab 12.8.
|
|
||||||
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/218737) from "expiration policy" to "cleanup policy" in GitLab 13.2.
|
|
||||||
|
|
||||||
The cleanup policy is a scheduled job you can use to remove tags from the Container Registry.
|
|
||||||
For the project where it's defined, tags matching the regex pattern are removed.
|
|
||||||
The underlying layers and images remain.
|
|
||||||
|
|
||||||
To delete the underlying layers and images that aren't associated with any tags, administrators can use
|
|
||||||
[garbage collection](../../../administration/packages/container_registry.md#removing-untagged-manifests-and-unreferenced-layers) with the `-m` switch.
|
|
||||||
|
|
||||||
### Enable the cleanup policy
|
|
||||||
|
|
||||||
Cleanup policies can be run on all projects, with these exceptions:
|
|
||||||
|
|
||||||
- For GitLab.com, the project must have been created after 2020-02-22.
|
|
||||||
Support for projects created earlier is tracked
|
|
||||||
[in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/196124).
|
|
||||||
- For self-managed GitLab instances, the project must have been created
|
|
||||||
in GitLab 12.8 or later. However, an administrator can enable the cleanup policy
|
|
||||||
for all projects (even those created before 12.8) in
|
|
||||||
[GitLab application settings](../../../api/settings.md#change-application-settings)
|
|
||||||
by setting `container_expiration_policies_enable_historic_entries` to true.
|
|
||||||
Alternatively, you can execute the following command in the [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
ApplicationSetting.last.update(container_expiration_policies_enable_historic_entries: true)
|
|
||||||
```
|
|
||||||
|
|
||||||
There are performance risks with enabling it for all projects, especially if you
|
|
||||||
are using an [external registry](index.md#use-with-external-container-registries).
|
|
||||||
- For self-managed GitLab instances, you can enable or disable the cleanup policy for a specific
|
|
||||||
project.
|
|
||||||
|
|
||||||
To enable it:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
Feature.enable(:container_expiration_policies_historic_entry, Project.find(<project id>))
|
|
||||||
```
|
|
||||||
|
|
||||||
To disable it:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
Feature.disable(:container_expiration_policies_historic_entry, Project.find(<project id>))
|
|
||||||
```
|
|
||||||
|
|
||||||
WARNING:
|
|
||||||
For performance reasons, enabled cleanup policies are automatically disabled for projects on
|
|
||||||
GitLab.com that don't have a container image.
|
|
||||||
|
|
||||||
### How the cleanup policy works
|
|
||||||
|
|
||||||
The cleanup policy collects all tags in the Container Registry and excludes tags
|
|
||||||
until only the tags to be deleted remain.
|
|
||||||
|
|
||||||
The cleanup policy searches for images based on the tag name. Support for the full path [has not yet been implemented](https://gitlab.com/gitlab-org/gitlab/-/issues/281071), but would allow you to clean up dynamically-named tags.
|
|
||||||
|
|
||||||
The cleanup policy:
|
|
||||||
|
|
||||||
1. Collects all tags for a given repository in a list.
|
|
||||||
1. Excludes the tag named `latest` from the list.
|
|
||||||
1. Evaluates the `name_regex` (tags to expire), excluding non-matching names from the list.
|
|
||||||
1. Excludes from the list any tags matching the `name_regex_keep` value (tags to preserve).
|
|
||||||
1. Excludes any tags that do not have a manifest (not part of the options in the UI).
|
|
||||||
1. Orders the remaining tags by `created_date`.
|
|
||||||
1. Excludes from the list the N tags based on the `keep_n` value (Number of tags to retain).
|
|
||||||
1. Excludes from the list the tags more recent than the `older_than` value (Expiration interval).
|
|
||||||
1. Finally, the remaining tags in the list are deleted from the Container Registry.
|
|
||||||
|
|
||||||
WARNING:
|
|
||||||
On GitLab.com, the execution time for the cleanup policy is limited, and some of the tags may remain in
|
|
||||||
the Container Registry after the policy runs. The next time the policy runs, the remaining tags are included,
|
|
||||||
so it may take multiple runs for all tags to be deleted.
|
|
||||||
|
|
||||||
WARNING:
|
|
||||||
GitLab self-managed installs support for third-party container registries that comply with the
|
|
||||||
[Docker Registry HTTP API V2](https://docs.docker.com/registry/spec/api/)
|
|
||||||
specification. However, this specification does not include a tag delete operation. Therefore, when
|
|
||||||
interacting with third-party container registries, GitLab uses a workaround to delete tags. See the
|
|
||||||
[related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/15737)
|
|
||||||
for more information. Due to possible implementation variations, this workaround is not guaranteed
|
|
||||||
to work with all third-party registries in the same predictable way. If you use the GitLab Container
|
|
||||||
Registry, this workaround is not required because we implemented a special tag delete operation. In
|
|
||||||
this case, you can expect cleanup policies to be consistent and predictable.
|
|
||||||
|
|
||||||
### Create a cleanup policy
|
|
||||||
|
|
||||||
You can create a cleanup policy in [the API](#use-the-cleanup-policy-api) or the UI.
|
|
||||||
|
|
||||||
To create a cleanup policy in the UI:
|
|
||||||
|
|
||||||
1. For your project, go to **Settings > Packages & Registries**.
|
|
||||||
1. Expand the **Clean up image tags** section.
|
|
||||||
1. Complete the fields.
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
|---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|
|
|
||||||
| **Toggle** | Turn the policy on or off. |
|
|
||||||
| **Run cleanup** | How often the policy should run. |
|
|
||||||
| **Keep the most recent** | How many tags to _always_ keep for each image. |
|
|
||||||
| **Keep tags matching** | The regex pattern that determines which tags to preserve. The `latest` tag is always preserved. For all tags, use `.*`. See other [regex pattern examples](#regex-pattern-examples). |
|
|
||||||
| **Remove tags older than** | Remove only tags older than X days. |
|
|
||||||
| **Remove tags matching** | The regex pattern that determines which tags to remove. This value cannot be blank. For all tags, use `.*`. See other [regex pattern examples](#regex-pattern-examples). |
|
|
||||||
|
|
||||||
1. Click **Save**.
|
|
||||||
|
|
||||||
Depending on the interval you chose, the policy is scheduled to run.
|
|
||||||
|
|
||||||
NOTE:
|
|
||||||
If you edit the policy and click **Save** again, the interval is reset.
|
|
||||||
|
|
||||||
### Regex pattern examples
|
|
||||||
|
|
||||||
Cleanup policies use regex patterns to determine which tags should be preserved or removed, both in the UI and the API.
|
|
||||||
|
|
||||||
Regex patterns are automatically surrounded with `\A` and `\Z` anchors. Do not include any `\A`, `\Z`, `^` or `$` token in the regex patterns as they are not necessary.
|
|
||||||
|
|
||||||
Here are examples of regex patterns you may want to use:
|
|
||||||
|
|
||||||
- Match all tags:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
.*
|
|
||||||
```
|
|
||||||
|
|
||||||
This is the default value for the expiration regex.
|
|
||||||
|
|
||||||
- Match tags that start with `v`:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
v.+
|
|
||||||
```
|
|
||||||
|
|
||||||
- Match only the tag named `main`:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
main
|
|
||||||
```
|
|
||||||
|
|
||||||
- Match tags that are either named or start with `release`:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
release.*
|
|
||||||
```
|
|
||||||
|
|
||||||
- Match tags that either start with `v`, are named `main`, or begin with `release`:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
(?:v.+|main|release.*)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Set cleanup limits to conserve resources
|
|
||||||
|
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/288812) in GitLab 13.9.
|
|
||||||
> - It's [deployed behind a feature flag](../../feature_flags.md), disabled by default.
|
|
||||||
> - It's enabled on GitLab.com.
|
|
||||||
> - It's not recommended for production use.
|
|
||||||
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-cleanup-policy-limits).
|
|
||||||
|
|
||||||
Cleanup policies are executed as a background process. This process is complex, and depending on the number of tags to delete,
|
|
||||||
the process can take time to finish.
|
|
||||||
|
|
||||||
To prevent server resource starvation, the following application settings are available:
|
|
||||||
|
|
||||||
- `container_registry_expiration_policies_worker_capacity`. The maximum number of cleanup workers running concurrently. This must be greater than `1`.
|
|
||||||
We recommend starting with a low number and increasing it after monitoring the resources used by the background workers.
|
|
||||||
- `container_registry_delete_tags_service_timeout`. The maximum time, in seconds, that the cleanup process can take to delete a batch of tags.
|
|
||||||
- `container_registry_cleanup_tags_service_max_list_size`. The maximum number of tags that can be deleted in a single execution. Additional tags must be deleted in another execution.
|
|
||||||
We recommend starting with a low number, like `100`, and increasing it after monitoring that container images are properly deleted.
|
|
||||||
|
|
||||||
For self-managed instances, those settings can be updated in the [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
ApplicationSetting.last.update(container_registry_expiration_policies_worker_capacity: 3)
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, once the limits are [enabled](#enable-or-disable-cleanup-policy-limits),
|
|
||||||
they are available in the [administrator area](../../admin_area/index.md):
|
|
||||||
|
|
||||||
1. On the top bar, select **Menu > Admin**.
|
|
||||||
1. Go to **Settings > CI/CD > Container Registry**.
|
|
||||||
|
|
||||||
#### Enable or disable cleanup policy limits
|
|
||||||
|
|
||||||
The cleanup policies limits are under development and not ready for production use. They are
|
|
||||||
deployed behind a feature flag that is **disabled by default**.
|
|
||||||
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
|
|
||||||
can enable it.
|
|
||||||
|
|
||||||
To enable it:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
Feature.enable(:container_registry_expiration_policies_throttling)
|
|
||||||
```
|
|
||||||
|
|
||||||
To disable it:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
Feature.disable(:container_registry_expiration_policies_throttling)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Use the cleanup policy API
|
|
||||||
|
|
||||||
You can set, update, and disable the cleanup policies using the GitLab API.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
- Select all tags, keep at least 1 tag per image, clean up any tag older than 14 days, run once a month, preserve any images with the name `main` and the policy is enabled:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl --request PUT --header 'Content-Type: application/json;charset=UTF-8' --header "PRIVATE-TOKEN: <your_access_token>" \
|
|
||||||
--data-binary '{"container_expiration_policy_attributes":{"cadence":"1month","enabled":true,"keep_n":1,"older_than":"14d","name_regex":"","name_regex_delete":".*","name_regex_keep":".*-main"}}' \
|
|
||||||
"https://gitlab.example.com/api/v4/projects/2"
|
|
||||||
```
|
|
||||||
|
|
||||||
Valid values for `cadence` when using the API are:
|
|
||||||
|
|
||||||
- `1d` (every day)
|
|
||||||
- `7d` (every week)
|
|
||||||
- `14d` (every two weeks)
|
|
||||||
- `1month` (every month)
|
|
||||||
- `3month` (every quarter)
|
|
||||||
|
|
||||||
See the API documentation for further details: [Edit project](../../../api/projects.md#edit-project).
|
|
||||||
|
|
||||||
### Use with external container registries
|
|
||||||
|
|
||||||
When using an [external container registry](../../../administration/packages/container_registry.md#use-an-external-container-registry-with-gitlab-as-an-auth-endpoint),
|
|
||||||
running a cleanup policy on a project may have some performance risks.
|
|
||||||
If a project runs a policy to remove thousands of tags
|
|
||||||
the GitLab background jobs may get backed up or fail completely.
|
|
||||||
It is recommended you only enable container cleanup
|
|
||||||
policies for projects that were created before GitLab 12.8 if you are confident the number of tags
|
|
||||||
being cleaned up is minimal.
|
|
||||||
|
|
||||||
### Troubleshooting cleanup policies
|
|
||||||
|
|
||||||
If you see the following message:
|
|
||||||
|
|
||||||
"Something went wrong while updating the cleanup policy."
|
|
||||||
|
|
||||||
Check the regex patterns to ensure they are valid.
|
|
||||||
|
|
||||||
GitLab uses [RE2 syntax](https://github.com/google/re2/wiki/Syntax) for regular expressions in the cleanup policy. You can test them with the [regex101 regex tester](https://regex101.com/).
|
|
||||||
View some common [regex pattern examples](#regex-pattern-examples).
|
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
- Moving or renaming existing Container Registry repositories is not supported
|
- Moving or renaming existing Container Registry repositories is not supported
|
||||||
|
@ -852,7 +605,7 @@ There can be different reasons behind this:
|
||||||
|
|
||||||
To fix this, there are two workarounds:
|
To fix this, there are two workarounds:
|
||||||
|
|
||||||
- If you are on GitLab 13.9 or later, you can [set limits for the cleanup policy](#set-cleanup-limits-to-conserve-resources).
|
- If you are on GitLab 13.9 or later, you can [set limits for the cleanup policy](reduce_container_registry_storage.md#set-cleanup-limits-to-conserve-resources).
|
||||||
This limits the cleanup execution in time, and avoids the expired token error.
|
This limits the cleanup execution in time, and avoids the expired token error.
|
||||||
|
|
||||||
- Extend the expiration delay of the Container Registry authentication tokens. This defaults to 5
|
- Extend the expiration delay of the Container Registry authentication tokens. This defaults to 5
|
||||||
|
|
|
@ -0,0 +1,275 @@
|
||||||
|
---
|
||||||
|
stage: Package
|
||||||
|
group: Package
|
||||||
|
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||||
|
---
|
||||||
|
|
||||||
|
# Reduce Container Registry Storage **(FREE)**
|
||||||
|
|
||||||
|
Container registries become large over time without cleanup. When a large number of images or tags are added:
|
||||||
|
|
||||||
|
- Fetching the list of available tags or images becomes slower.
|
||||||
|
- They take up a large amount of storage space on the server.
|
||||||
|
|
||||||
|
We recommend deleting unnecessary images and tags, and setting up a [cleanup policy](#cleanup-policy)
|
||||||
|
to automatically manage your container registry usage.
|
||||||
|
|
||||||
|
## Check Container Registry Storage Use
|
||||||
|
|
||||||
|
The Usage Quotas page (**Settings > Usage Quotas > Storage**) displays storage usage for Packages, which includes Container Registry,
|
||||||
|
however, the storage is not being calculated.
|
||||||
|
|
||||||
|
## Cleanup policy
|
||||||
|
|
||||||
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15398) in GitLab 12.8.
|
||||||
|
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/218737) from "expiration policy" to "cleanup policy" in GitLab 13.2.
|
||||||
|
|
||||||
|
The cleanup policy is a scheduled job you can use to remove tags from the Container Registry.
|
||||||
|
For the project where it's defined, tags matching the regex pattern are removed.
|
||||||
|
The underlying layers and images remain.
|
||||||
|
|
||||||
|
To delete the underlying layers and images that aren't associated with any tags, administrators can use
|
||||||
|
[garbage collection](../../../administration/packages/container_registry.md#removing-untagged-manifests-and-unreferenced-layers) with the `-m` switch.
|
||||||
|
|
||||||
|
### Enable the cleanup policy
|
||||||
|
|
||||||
|
Cleanup policies can be run on all projects, with these exceptions:
|
||||||
|
|
||||||
|
- For GitLab.com, the project must have been created after 2020-02-22.
|
||||||
|
Support for projects created earlier is tracked
|
||||||
|
[in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/196124).
|
||||||
|
- For self-managed GitLab instances, the project must have been created
|
||||||
|
in GitLab 12.8 or later. However, an administrator can enable the cleanup policy
|
||||||
|
for all projects (even those created before 12.8) in
|
||||||
|
[GitLab application settings](../../../api/settings.md#change-application-settings)
|
||||||
|
by setting `container_expiration_policies_enable_historic_entries` to true.
|
||||||
|
Alternatively, you can execute the following command in the [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
ApplicationSetting.last.update(container_expiration_policies_enable_historic_entries: true)
|
||||||
|
```
|
||||||
|
|
||||||
|
There are performance risks with enabling it for all projects, especially if you
|
||||||
|
are using an [external registry](#use-with-external-container-registries).
|
||||||
|
- For self-managed GitLab instances, you can enable or disable the cleanup policy for a specific
|
||||||
|
project.
|
||||||
|
|
||||||
|
To enable it:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Feature.enable(:container_expiration_policies_historic_entry, Project.find(<project id>))
|
||||||
|
```
|
||||||
|
|
||||||
|
To disable it:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Feature.disable(:container_expiration_policies_historic_entry, Project.find(<project id>))
|
||||||
|
```
|
||||||
|
|
||||||
|
WARNING:
|
||||||
|
For performance reasons, enabled cleanup policies are automatically disabled for projects on
|
||||||
|
GitLab.com that don't have a container image.
|
||||||
|
|
||||||
|
### How the cleanup policy works
|
||||||
|
|
||||||
|
The cleanup policy collects all tags in the Container Registry and excludes tags
|
||||||
|
until only the tags to be deleted remain.
|
||||||
|
|
||||||
|
The cleanup policy searches for images based on the tag name. Support for the full path [has not yet been implemented](https://gitlab.com/gitlab-org/gitlab/-/issues/281071), but would allow you to clean up dynamically-named tags.
|
||||||
|
|
||||||
|
The cleanup policy:
|
||||||
|
|
||||||
|
1. Collects all tags for a given repository in a list.
|
||||||
|
1. Excludes the tag named `latest` from the list.
|
||||||
|
1. Evaluates the `name_regex` (tags to expire), excluding non-matching names from the list.
|
||||||
|
1. Excludes from the list any tags matching the `name_regex_keep` value (tags to preserve).
|
||||||
|
1. Excludes any tags that do not have a manifest (not part of the options in the UI).
|
||||||
|
1. Orders the remaining tags by `created_date`.
|
||||||
|
1. Excludes from the list the N tags based on the `keep_n` value (Number of tags to retain).
|
||||||
|
1. Excludes from the list the tags more recent than the `older_than` value (Expiration interval).
|
||||||
|
1. Finally, the remaining tags in the list are deleted from the Container Registry.
|
||||||
|
|
||||||
|
WARNING:
|
||||||
|
On GitLab.com, the execution time for the cleanup policy is limited, and some of the tags may remain in
|
||||||
|
the Container Registry after the policy runs. The next time the policy runs, the remaining tags are included,
|
||||||
|
so it may take multiple runs for all tags to be deleted.
|
||||||
|
|
||||||
|
WARNING:
|
||||||
|
GitLab self-managed installs support for third-party container registries that comply with the
|
||||||
|
[Docker Registry HTTP API V2](https://docs.docker.com/registry/spec/api/)
|
||||||
|
specification. However, this specification does not include a tag delete operation. Therefore, when
|
||||||
|
interacting with third-party container registries, GitLab uses a workaround to delete tags. See the
|
||||||
|
[related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/15737)
|
||||||
|
for more information. Due to possible implementation variations, this workaround is not guaranteed
|
||||||
|
to work with all third-party registries in the same predictable way. If you use the GitLab Container
|
||||||
|
Registry, this workaround is not required because we implemented a special tag delete operation. In
|
||||||
|
this case, you can expect cleanup policies to be consistent and predictable.
|
||||||
|
|
||||||
|
### Create a cleanup policy
|
||||||
|
|
||||||
|
You can create a cleanup policy in [the API](#use-the-cleanup-policy-api) or the UI.
|
||||||
|
|
||||||
|
To create a cleanup policy in the UI:
|
||||||
|
|
||||||
|
1. For your project, go to **Settings > Packages & Registries**.
|
||||||
|
1. Expand the **Clean up image tags** section.
|
||||||
|
1. Complete the fields.
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| **Toggle** | Turn the policy on or off. |
|
||||||
|
| **Run cleanup** | How often the policy should run. |
|
||||||
|
| **Keep the most recent** | How many tags to _always_ keep for each image. |
|
||||||
|
| **Keep tags matching** | The regex pattern that determines which tags to preserve. The `latest` tag is always preserved. For all tags, use `.*`. See other [regex pattern examples](#regex-pattern-examples). |
|
||||||
|
| **Remove tags older than** | Remove only tags older than X days. |
|
||||||
|
| **Remove tags matching** | The regex pattern that determines which tags to remove. This value cannot be blank. For all tags, use `.*`. See other [regex pattern examples](#regex-pattern-examples). |
|
||||||
|
|
||||||
|
1. Click **Save**.
|
||||||
|
|
||||||
|
Depending on the interval you chose, the policy is scheduled to run.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
If you edit the policy and click **Save** again, the interval is reset.
|
||||||
|
|
||||||
|
### Regex pattern examples
|
||||||
|
|
||||||
|
Cleanup policies use regex patterns to determine which tags should be preserved or removed, both in the UI and the API.
|
||||||
|
|
||||||
|
Regex patterns are automatically surrounded with `\A` and `\Z` anchors. Do not include any `\A`, `\Z`, `^` or `$` token in the regex patterns as they are not necessary.
|
||||||
|
|
||||||
|
Here are examples of regex patterns you may want to use:
|
||||||
|
|
||||||
|
- Match all tags:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
.*
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the default value for the expiration regex.
|
||||||
|
|
||||||
|
- Match tags that start with `v`:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
v.+
|
||||||
|
```
|
||||||
|
|
||||||
|
- Match only the tag named `main`:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
main
|
||||||
|
```
|
||||||
|
|
||||||
|
- Match tags that are either named or start with `release`:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
release.*
|
||||||
|
```
|
||||||
|
|
||||||
|
- Match tags that either start with `v`, are named `main`, or begin with `release`:
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
(?:v.+|main|release.*)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Set cleanup limits to conserve resources
|
||||||
|
|
||||||
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/288812) in GitLab 13.9.
|
||||||
|
> - It's [deployed behind a feature flag](../../feature_flags.md), disabled by default.
|
||||||
|
> - It's enabled on GitLab.com.
|
||||||
|
> - It's not recommended for production use.
|
||||||
|
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-cleanup-policy-limits).
|
||||||
|
|
||||||
|
Cleanup policies are executed as a background process. This process is complex, and depending on the number of tags to delete,
|
||||||
|
the process can take time to finish.
|
||||||
|
|
||||||
|
To prevent server resource starvation, the following application settings are available:
|
||||||
|
|
||||||
|
- `container_registry_expiration_policies_worker_capacity`. The maximum number of cleanup workers running concurrently. This must be greater than `1`.
|
||||||
|
We recommend starting with a low number and increasing it after monitoring the resources used by the background workers.
|
||||||
|
- `container_registry_delete_tags_service_timeout`. The maximum time, in seconds, that the cleanup process can take to delete a batch of tags.
|
||||||
|
- `container_registry_cleanup_tags_service_max_list_size`. The maximum number of tags that can be deleted in a single execution. Additional tags must be deleted in another execution.
|
||||||
|
We recommend starting with a low number, like `100`, and increasing it after monitoring that container images are properly deleted.
|
||||||
|
|
||||||
|
For self-managed instances, those settings can be updated in the [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
ApplicationSetting.last.update(container_registry_expiration_policies_worker_capacity: 3)
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, once the limits are [enabled](#enable-or-disable-cleanup-policy-limits),
|
||||||
|
they are available in the [administrator area](../../admin_area/index.md):
|
||||||
|
|
||||||
|
1. On the top bar, select **Menu > Admin**.
|
||||||
|
1. Go to **Settings > CI/CD > Container Registry**.
|
||||||
|
|
||||||
|
#### Enable or disable cleanup policy limits
|
||||||
|
|
||||||
|
The cleanup policies limits are under development and not ready for production use. They are
|
||||||
|
deployed behind a feature flag that is **disabled by default**.
|
||||||
|
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
|
||||||
|
can enable it.
|
||||||
|
|
||||||
|
To enable it:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Feature.enable(:container_registry_expiration_policies_throttling)
|
||||||
|
```
|
||||||
|
|
||||||
|
To disable it:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Feature.disable(:container_registry_expiration_policies_throttling)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use the cleanup policy API
|
||||||
|
|
||||||
|
You can set, update, and disable the cleanup policies using the GitLab API.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- Select all tags, keep at least 1 tag per image, clean up any tag older than 14 days, run once a month, preserve any images with the name `main` and the policy is enabled:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl --request PUT --header 'Content-Type: application/json;charset=UTF-8' --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||||
|
--data-binary '{"container_expiration_policy_attributes":{"cadence":"1month","enabled":true,"keep_n":1,"older_than":"14d","name_regex":"","name_regex_delete":".*","name_regex_keep":".*-main"}}' \
|
||||||
|
"https://gitlab.example.com/api/v4/projects/2"
|
||||||
|
```
|
||||||
|
|
||||||
|
Valid values for `cadence` when using the API are:
|
||||||
|
|
||||||
|
- `1d` (every day)
|
||||||
|
- `7d` (every week)
|
||||||
|
- `14d` (every two weeks)
|
||||||
|
- `1month` (every month)
|
||||||
|
- `3month` (every quarter)
|
||||||
|
|
||||||
|
See the API documentation for further details: [Edit project](../../../api/projects.md#edit-project).
|
||||||
|
|
||||||
|
### Use with external container registries
|
||||||
|
|
||||||
|
When using an [external container registry](../../../administration/packages/container_registry.md#use-an-external-container-registry-with-gitlab-as-an-auth-endpoint),
|
||||||
|
running a cleanup policy on a project may have some performance risks.
|
||||||
|
If a project runs a policy to remove thousands of tags
|
||||||
|
the GitLab background jobs may get backed up or fail completely.
|
||||||
|
It is recommended you only enable container cleanup
|
||||||
|
policies for projects that were created before GitLab 12.8 if you are confident the number of tags
|
||||||
|
being cleaned up is minimal.
|
||||||
|
|
||||||
|
## Related topics
|
||||||
|
|
||||||
|
- [Delete images](index.md#delete-images)
|
||||||
|
- [Delete registry repository](../../../api/container_registry.md#delete-registry-repository)
|
||||||
|
- [Delete a registry repository tag](../../../api/container_registry.md#delete-a-registry-repository-tag)
|
||||||
|
- [Delete registry repository tags in bulk](../../../api/container_registry.md#delete-registry-repository-tags-in-bulk)
|
||||||
|
- [Delete a package](../package_registry/index.md#delete-a-package)
|
||||||
|
|
||||||
|
## Troubleshooting cleanup policies
|
||||||
|
|
||||||
|
If you see the following message:
|
||||||
|
|
||||||
|
"Something went wrong while updating the cleanup policy."
|
||||||
|
|
||||||
|
Check the regex patterns to ensure they are valid.
|
||||||
|
|
||||||
|
GitLab uses [RE2 syntax](https://github.com/google/re2/wiki/Syntax) for regular expressions in the cleanup policy. You can test them with the [regex101 regex tester](https://regex101.com/).
|
||||||
|
View some common [regex pattern examples](#regex-pattern-examples).
|
|
@ -116,8 +116,6 @@ You might also be interested in templates for various
|
||||||
|
|
||||||
### Set a default template for merge requests and issues **(PREMIUM)**
|
### Set a default template for merge requests and issues **(PREMIUM)**
|
||||||
|
|
||||||
> The `default.md` template becoming the default [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76326) in GitLab 14.7.
|
|
||||||
|
|
||||||
In a project, you can choose a default description template for new issues and merge requests.
|
In a project, you can choose a default description template for new issues and merge requests.
|
||||||
As a result, every time a new merge request or issue is created, it's pre-filled with the text you
|
As a result, every time a new merge request or issue is created, it's pre-filled with the text you
|
||||||
entered in the template.
|
entered in the template.
|
||||||
|
@ -127,29 +125,17 @@ Prerequisites:
|
||||||
- On your project's left sidebar, select **Settings > General** and expand **Visibility, project features, permissions**.
|
- On your project's left sidebar, select **Settings > General** and expand **Visibility, project features, permissions**.
|
||||||
Ensure issues or merge requests are set to either **Everyone with access** or **Only Project Members**.
|
Ensure issues or merge requests are set to either **Everyone with access** or **Only Project Members**.
|
||||||
|
|
||||||
To set a default description template for merge requests, either:
|
To set a default description template for merge requests:
|
||||||
|
|
||||||
- [Create a merge request template](#create-a-merge-request-template) named `default.md` and save it in `.gitlab/merge_request_templates/`.
|
1. Go to your project's **Settings**.
|
||||||
**If a `default.md` file exists, it's used as the default template even if you select another one in the project settings.**
|
1. Select **Expand** under the **Merge requests** header.
|
||||||
- Select the default template in project settings:
|
1. Fill in the **Default description template for merge requests** text area.
|
||||||
|
1. Select **Save changes**.
|
||||||
|
|
||||||
1. On the top bar, select **Menu > Projects** and find your project.
|
To set a default description template for issues:
|
||||||
1. On the left sidebar, select **Settings**.
|
|
||||||
1. Expand **Merge requests**.
|
|
||||||
1. Fill in the **Default description template for merge requests** text area.
|
|
||||||
1. Select **Save changes**.
|
|
||||||
|
|
||||||
To set a default description template for issues, either:
|
1. Select **Expand** under **Default issue template**.
|
||||||
|
1. Fill in the **Default description template for issues** text area.
|
||||||
- [Create an issue template](#create-an-issue-template) named `default.md` and save it in `.gitlab/issue_templates/`.
|
|
||||||
**If a `default.md` file exists, it's used as the default template even if you select another one in the project settings.**
|
|
||||||
- Select the default template in project settings:
|
|
||||||
|
|
||||||
1. On the top bar, select **Menu > Projects** and find your project.
|
|
||||||
1. On the left sidebar, select **Settings**.
|
|
||||||
1. Expand **Default issue template**.
|
|
||||||
1. Fill in the **Default description template for issues** text area.
|
|
||||||
1. Select **Save changes**.
|
|
||||||
|
|
||||||
Because GitLab merge request and issues support [Markdown](../markdown.md), you can use it to format
|
Because GitLab merge request and issues support [Markdown](../markdown.md), you can use it to format
|
||||||
headings, lists, and so on.
|
headings, lists, and so on.
|
||||||
|
|
|
@ -84,7 +84,7 @@ module Gitlab
|
||||||
Gitlab::Auth::UniqueIpsLimiter.limit_user! do
|
Gitlab::Auth::UniqueIpsLimiter.limit_user! do
|
||||||
user = User.by_login(login)
|
user = User.by_login(login)
|
||||||
|
|
||||||
break if user && !can_user_login_with_non_expired_password?(user)
|
break if user && !user.can_log_in_with_non_expired_password?
|
||||||
|
|
||||||
authenticators = []
|
authenticators = []
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ module Gitlab
|
||||||
|
|
||||||
if valid_oauth_token?(token)
|
if valid_oauth_token?(token)
|
||||||
user = User.id_in(token.resource_owner_id).first
|
user = User.id_in(token.resource_owner_id).first
|
||||||
return unless user && can_user_login_with_non_expired_password?(user)
|
return unless user && user.can_log_in_with_non_expired_password?
|
||||||
|
|
||||||
Gitlab::Auth::Result.new(user, nil, :oauth, abilities_for_scopes(token.scopes))
|
Gitlab::Auth::Result.new(user, nil, :oauth, abilities_for_scopes(token.scopes))
|
||||||
end
|
end
|
||||||
|
@ -210,7 +210,7 @@ module Gitlab
|
||||||
return unless token_bot_in_project?(token.user, project) || token_bot_in_group?(token.user, project)
|
return unless token_bot_in_project?(token.user, project) || token_bot_in_group?(token.user, project)
|
||||||
end
|
end
|
||||||
|
|
||||||
if can_user_login_with_non_expired_password?(token.user) || token.user.project_bot?
|
if token.user.can_log_in_with_non_expired_password? || token.user.project_bot?
|
||||||
Gitlab::Auth::Result.new(token.user, nil, :personal_access_token, abilities_for_scopes(token.scopes))
|
Gitlab::Auth::Result.new(token.user, nil, :personal_access_token, abilities_for_scopes(token.scopes))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -309,7 +309,7 @@ module Gitlab
|
||||||
return unless build.project.builds_enabled?
|
return unless build.project.builds_enabled?
|
||||||
|
|
||||||
if build.user
|
if build.user
|
||||||
return unless can_user_login_with_non_expired_password?(build.user) || (build.user.project_bot? && build.project.bots&.include?(build.user))
|
return unless build.user.can_log_in_with_non_expired_password? || (build.user.project_bot? && build.project.bots&.include?(build.user))
|
||||||
|
|
||||||
# If user is assigned to build, use restricted credentials of user
|
# If user is assigned to build, use restricted credentials of user
|
||||||
Gitlab::Auth::Result.new(build.user, build.project, :build, build_authentication_abilities)
|
Gitlab::Auth::Result.new(build.user, build.project, :build, build_authentication_abilities)
|
||||||
|
@ -406,10 +406,6 @@ module Gitlab
|
||||||
|
|
||||||
user.increment_failed_attempts!
|
user.increment_failed_attempts!
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_user_login_with_non_expired_password?(user)
|
|
||||||
user.can?(:log_in) && !user.password_expired_if_applicable?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,6 +35,9 @@ ci_daily_build_group_report_results:
|
||||||
- table: namespaces
|
- table: namespaces
|
||||||
column: group_id
|
column: group_id
|
||||||
on_delete: async_delete
|
on_delete: async_delete
|
||||||
|
- table: projects
|
||||||
|
column: project_id
|
||||||
|
on_delete: async_delete
|
||||||
ci_freeze_periods:
|
ci_freeze_periods:
|
||||||
- table: projects
|
- table: projects
|
||||||
column: project_id
|
column: project_id
|
||||||
|
|
|
@ -16040,6 +16040,9 @@ msgstr ""
|
||||||
msgid "Get a free instance review"
|
msgid "Get a free instance review"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Get a free trial"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Get a support subscription"
|
msgid "Get a support subscription"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -27964,12 +27967,6 @@ msgstr ""
|
||||||
msgid "ProjectSettings|Highlight the usage of hidden unicode characters. These have innocent uses for right-to-left languages, but can also be used in potential exploits."
|
msgid "ProjectSettings|Highlight the usage of hidden unicode characters. These have innocent uses for right-to-left languages, but can also be used in potential exploits."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "ProjectSettings|If a %{code_start}default.md%{code_end} file exists in %{code_start}.gitlab/issue_templates%{code_end} in the repository, it overrides this setting."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "ProjectSettings|If a %{code_start}default.md%{code_end} file exists in %{code_start}.gitlab/merge_request_templates%{code_end} in the repository, it overrides this setting."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
|
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module QA
|
module QA
|
||||||
RSpec.describe 'Create', :requires_admin do # remove :requires_admin once the ff is enabled by default in https://gitlab.com/gitlab-org/gitlab/-/issues/345398
|
RSpec.describe 'Create', :requires_admin, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/350220', type: :investigating } do # remove :requires_admin once the ff is enabled by default in https://gitlab.com/gitlab-org/gitlab/-/issues/345398
|
||||||
context 'Content Editor' do
|
context 'Content Editor' do
|
||||||
let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
|
let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
|
||||||
let(:page_title) { 'Content Editor Page' }
|
let(:page_title) { 'Content Editor Page' }
|
||||||
|
|
|
@ -16,15 +16,6 @@ RSpec.describe Groups::BoardsController do
|
||||||
expect { list_boards }.to change(group.boards, :count).by(1)
|
expect { list_boards }.to change(group.boards, :count).by(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'pushes swimlanes_buffered_rendering feature flag' do
|
|
||||||
allow(controller).to receive(:push_frontend_feature_flag).and_call_original
|
|
||||||
|
|
||||||
expect(controller).to receive(:push_frontend_feature_flag)
|
|
||||||
.with(:swimlanes_buffered_rendering, group, default_enabled: :yaml)
|
|
||||||
|
|
||||||
list_boards
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when format is HTML' do
|
context 'when format is HTML' do
|
||||||
it 'renders template' do
|
it 'renders template' do
|
||||||
list_boards
|
list_boards
|
||||||
|
@ -107,15 +98,6 @@ RSpec.describe Groups::BoardsController do
|
||||||
describe 'GET show' do
|
describe 'GET show' do
|
||||||
let!(:board) { create(:board, group: group) }
|
let!(:board) { create(:board, group: group) }
|
||||||
|
|
||||||
it 'pushes swimlanes_buffered_rendering feature flag' do
|
|
||||||
allow(controller).to receive(:push_frontend_feature_flag).and_call_original
|
|
||||||
|
|
||||||
expect(controller).to receive(:push_frontend_feature_flag)
|
|
||||||
.with(:swimlanes_buffered_rendering, group, default_enabled: :yaml)
|
|
||||||
|
|
||||||
read_board board: board
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when format is HTML' do
|
context 'when format is HTML' do
|
||||||
it 'renders template' do
|
it 'renders template' do
|
||||||
expect { read_board board: board }.to change(BoardGroupRecentVisit, :count).by(1)
|
expect { read_board board: board }.to change(BoardGroupRecentVisit, :count).by(1)
|
||||||
|
|
|
@ -22,15 +22,6 @@ RSpec.describe Projects::BoardsController do
|
||||||
expect(assigns(:boards_endpoint)).to eq project_boards_path(project)
|
expect(assigns(:boards_endpoint)).to eq project_boards_path(project)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'pushes swimlanes_buffered_rendering feature flag' do
|
|
||||||
allow(controller).to receive(:push_frontend_feature_flag).and_call_original
|
|
||||||
|
|
||||||
expect(controller).to receive(:push_frontend_feature_flag)
|
|
||||||
.with(:swimlanes_buffered_rendering, project, default_enabled: :yaml)
|
|
||||||
|
|
||||||
list_boards
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when format is HTML' do
|
context 'when format is HTML' do
|
||||||
it 'renders template' do
|
it 'renders template' do
|
||||||
list_boards
|
list_boards
|
||||||
|
@ -125,15 +116,6 @@ RSpec.describe Projects::BoardsController do
|
||||||
describe 'GET show' do
|
describe 'GET show' do
|
||||||
let!(:board) { create(:board, project: project) }
|
let!(:board) { create(:board, project: project) }
|
||||||
|
|
||||||
it 'pushes swimlanes_buffered_rendering feature flag' do
|
|
||||||
allow(controller).to receive(:push_frontend_feature_flag).and_call_original
|
|
||||||
|
|
||||||
expect(controller).to receive(:push_frontend_feature_flag)
|
|
||||||
.with(:swimlanes_buffered_rendering, project, default_enabled: :yaml)
|
|
||||||
|
|
||||||
read_board board: board
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'sets boards_endpoint instance variable to a boards path' do
|
it 'sets boards_endpoint instance variable to a boards path' do
|
||||||
read_board board: board
|
read_board board: board
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,21 @@ RSpec.describe 'User sees experimental lmarketing header' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when experiment candidate (trial focused variant)' do
|
||||||
|
it 'shows marketing header links', :aggregate_failures do
|
||||||
|
stub_experiments(logged_out_marketing_header: :trial_focused)
|
||||||
|
|
||||||
|
visit project_path(project)
|
||||||
|
|
||||||
|
expect(page).to have_text "About GitLab"
|
||||||
|
expect(page).to have_text "Pricing"
|
||||||
|
expect(page).to have_text "Talk to an expert"
|
||||||
|
expect(page).to have_text "Get a free trial"
|
||||||
|
expect(page).to have_text "Sign up"
|
||||||
|
expect(page).to have_text "Login"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when experiment control' do
|
context 'when experiment control' do
|
||||||
it 'does not show marketing header links', :aggregate_failures do
|
it 'does not show marketing header links', :aggregate_failures do
|
||||||
stub_experiments(logged_out_marketing_header: :control)
|
stub_experiments(logged_out_marketing_header: :control)
|
||||||
|
@ -31,6 +46,8 @@ RSpec.describe 'User sees experimental lmarketing header' do
|
||||||
expect(page).not_to have_text "Talk to an expert"
|
expect(page).not_to have_text "Talk to an expert"
|
||||||
expect(page).not_to have_text "Sign up now"
|
expect(page).not_to have_text "Sign up now"
|
||||||
expect(page).not_to have_text "Login"
|
expect(page).not_to have_text "Login"
|
||||||
|
expect(page).not_to have_text "Get a free trial"
|
||||||
|
expect(page).not_to have_text "Sign up"
|
||||||
expect(page).to have_text "Sign in / Register"
|
expect(page).to have_text "Sign in / Register"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -110,6 +110,19 @@ describe('DropdownContentsLabelsView', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('first item is active when search is not empty', async () => {
|
||||||
|
createComponent({
|
||||||
|
queryHandler: jest.fn().mockResolvedValue(workspaceLabelsQueryResponse),
|
||||||
|
searchKey: 'Label',
|
||||||
|
});
|
||||||
|
await makeObserverAppear();
|
||||||
|
await waitForPromises();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(findLabelsList().exists()).toBe(true);
|
||||||
|
expect(findFirstLabel().attributes('active')).toBe('true');
|
||||||
|
});
|
||||||
|
|
||||||
it('when search returns 0 results', async () => {
|
it('when search returns 0 results', async () => {
|
||||||
createComponent({
|
createComponent({
|
||||||
queryHandler: jest.fn().mockResolvedValue({
|
queryHandler: jest.fn().mockResolvedValue({
|
||||||
|
|
|
@ -498,6 +498,12 @@ RSpec.describe ApplicationHelper do
|
||||||
it { is_expected.to include(expected_class) }
|
it { is_expected.to include(expected_class) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when candidate (:trial_focused variant)' do
|
||||||
|
let(:variant) { :trial_focused }
|
||||||
|
|
||||||
|
it { is_expected.to include(expected_class) }
|
||||||
|
end
|
||||||
|
|
||||||
context 'when control' do
|
context 'when control' do
|
||||||
let(:variant) { :control }
|
let(:variant) { :control }
|
||||||
|
|
||||||
|
|
|
@ -72,37 +72,6 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do
|
||||||
].to_json
|
].to_json
|
||||||
expect(helper.available_service_desk_templates_for(@project)).to eq(value)
|
expect(helper.available_service_desk_templates_for(@project)).to eq(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when no issuable_template parameter or default template is present' do
|
|
||||||
it 'does not select a template' do
|
|
||||||
expect(helper.selected_template(project)).to be(nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when an issuable_template parameter has been provided' do
|
|
||||||
before do
|
|
||||||
allow(helper).to receive(:params).and_return({ issuable_template: 'another_issue_template' })
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'selects the issuable template' do
|
|
||||||
expect(helper.selected_template(project)).to eq('another_issue_template')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when there is a default template' do
|
|
||||||
let(:templates) do
|
|
||||||
{
|
|
||||||
"" => [
|
|
||||||
{ name: "another_issue_template", id: "another_issue_template", project_id: project.id },
|
|
||||||
{ name: "default", id: "default", project_id: project.id }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'selects the default template' do
|
|
||||||
expect(helper.selected_template(project)).to eq('default')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when there are not templates in the project' do
|
context 'when there are not templates in the project' do
|
||||||
|
|
|
@ -42,6 +42,12 @@ RSpec.describe ErrorTracking::Collector::PayloadValidator do
|
||||||
it_behaves_like 'valid payload'
|
it_behaves_like 'valid payload'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'go payload' do
|
||||||
|
let(:payload) { Gitlab::Json.parse(fixture_file('error_tracking/go_parsed_event.json')) }
|
||||||
|
|
||||||
|
it_behaves_like 'valid payload'
|
||||||
|
end
|
||||||
|
|
||||||
context 'empty payload' do
|
context 'empty payload' do
|
||||||
let(:payload) { '' }
|
let(:payload) { '' }
|
||||||
|
|
||||||
|
|
|
@ -170,4 +170,10 @@ RSpec.describe Ci::DailyBuildGroupReportResult do
|
||||||
|
|
||||||
let!(:parent) { model.group }
|
let!(:parent) { model.group }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'cleanup by a loose foreign key' do
|
||||||
|
let!(:model) { create(:ci_daily_build_group_report_result) }
|
||||||
|
|
||||||
|
let!(:parent) { model.project }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5805,6 +5805,48 @@ RSpec.describe User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#can_log_in_with_non_expired_password?' do
|
||||||
|
let(:user) { build(:user) }
|
||||||
|
|
||||||
|
subject { user.can_log_in_with_non_expired_password? }
|
||||||
|
|
||||||
|
context 'when user can log in' do
|
||||||
|
it 'returns true' do
|
||||||
|
is_expected.to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user with expired password' do
|
||||||
|
before do
|
||||||
|
user.password_expires_at = 2.minutes.ago
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false' do
|
||||||
|
is_expected.to be_falsey
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when password expiration is not applicable' do
|
||||||
|
context 'when ldap user' do
|
||||||
|
let(:user) { build(:omniauth_user, provider: 'ldap') }
|
||||||
|
|
||||||
|
it 'returns true' do
|
||||||
|
is_expected.to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user cannot log in' do
|
||||||
|
context 'when user is blocked' do
|
||||||
|
let(:user) { build(:user, :blocked) }
|
||||||
|
|
||||||
|
it 'returns false' do
|
||||||
|
is_expected.to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#read_only_attribute?' do
|
describe '#read_only_attribute?' do
|
||||||
context 'when synced attributes metadata is present' do
|
context 'when synced attributes metadata is present' do
|
||||||
it 'delegates to synced_attributes_metadata' do
|
it 'delegates to synced_attributes_metadata' do
|
||||||
|
|
Loading…
Reference in a new issue