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>
|
||||
<template>
|
||||
<div class="cycle-analytics">
|
||||
<div>
|
||||
<h3>{{ $options.i18n.pageTitle }}</h3>
|
||||
<div class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row">
|
||||
<path-navigation
|
||||
|
|
|
@ -213,7 +213,7 @@ export default {
|
|||
<p class="gl-m-0">
|
||||
<gl-link
|
||||
data-testid="vsa-stage-event-link"
|
||||
class="gl-text-black-normal pipeline-id"
|
||||
class="gl-text-black-normal"
|
||||
:href="item.url"
|
||||
>{{ itemId(item.id, '#') }}</gl-link
|
||||
>
|
||||
|
|
|
@ -84,6 +84,14 @@ export default {
|
|||
showNoMatchingResultsMessage() {
|
||||
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: {
|
||||
isLabelSelected(label) {
|
||||
|
@ -143,11 +151,14 @@ export default {
|
|||
/>
|
||||
<template v-else>
|
||||
<gl-dropdown-item
|
||||
v-for="label in visibleLabels"
|
||||
v-for="(label, index) in visibleLabels"
|
||||
ref="labelItem"
|
||||
:key="label.id"
|
||||
:is-checked="isLabelSelected(label)"
|
||||
:is-check-centered="true"
|
||||
:is-check-item="true"
|
||||
:active="shouldHighlighFirstItem && index === 0"
|
||||
active-class="is-focused"
|
||||
data-testid="labels-list"
|
||||
@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
|
||||
|
||||
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
|
||||
# actually stored in the session and a token is needed
|
||||
# for every request. If you want the token to work as a
|
||||
|
|
|
@ -9,7 +9,6 @@ class Groups::BoardsController < Groups::ApplicationController
|
|||
before_action do
|
||||
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(:swimlanes_buffered_rendering, group, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:iteration_cadences, group, default_enabled: :yaml)
|
||||
experiment(:prominent_create_board_btn, subject: current_user) do |e|
|
||||
e.use { }
|
||||
|
|
|
@ -7,7 +7,6 @@ class Projects::BoardsController < Projects::ApplicationController
|
|||
before_action :check_issues_available!
|
||||
before_action :assign_endpoint_vars
|
||||
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(:board_multi_select, project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:iteration_cadences, project&.group, default_enabled: :yaml)
|
||||
|
|
|
@ -426,7 +426,9 @@ module ApplicationHelper
|
|||
return if current_user
|
||||
|
||||
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.run
|
||||
end
|
||||
|
|
|
@ -38,8 +38,7 @@ module IssuablesDescriptionTemplatesHelper
|
|||
# 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
|
||||
|
||||
template = all_templates.find { |tmpl_name| tmpl_name == params[:issuable_template] }
|
||||
template || all_templates.find { |tmpl_name| tmpl_name.casecmp?('default') }
|
||||
all_templates.find { |tmpl_name| tmpl_name == params[:issuable_template] }
|
||||
end
|
||||
|
||||
def available_service_desk_templates_for(project)
|
||||
|
|
|
@ -1901,6 +1901,10 @@ class User < ApplicationRecord
|
|||
true
|
||||
end
|
||||
|
||||
def can_log_in_with_non_expired_password?
|
||||
can?(:log_in) && !password_expired_if_applicable?
|
||||
end
|
||||
|
||||
def can_be_deactivated?
|
||||
active? && no_recent_activity? && !internal?
|
||||
end
|
||||
|
|
|
@ -13,57 +13,72 @@
|
|||
"type": "object"
|
||||
},
|
||||
"exception": {
|
||||
"type": "object",
|
||||
"required": ["values"],
|
||||
"properties": {
|
||||
"values": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"stacktrace": {
|
||||
"$ref": "#/definitions/exception"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["values"],
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"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",
|
||||
"required": [],
|
||||
"properties": {
|
||||
"frames": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [],
|
||||
"properties": {
|
||||
"abs_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"function": {
|
||||
"type": "string"
|
||||
},
|
||||
"lineno": {
|
||||
"type": "number"
|
||||
},
|
||||
"in_app": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"filename": {
|
||||
"type": "string"
|
||||
},
|
||||
"pre_context": {
|
||||
"type": "array"
|
||||
},
|
||||
"context_line": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"post_context": {
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
}
|
||||
"abs_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"function": {
|
||||
"type": "string"
|
||||
},
|
||||
"lineno": {
|
||||
"type": "number"
|
||||
},
|
||||
"in_app": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"filename": {
|
||||
"type": "string"
|
||||
},
|
||||
"pre_context": {
|
||||
"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.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.")
|
||||
= 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
|
||||
= _("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?
|
||||
.form-group
|
||||
= 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|
|
||||
- e.candidate do
|
||||
= render 'layouts/header/marketing_links'
|
||||
- e.try(:trial_focused) do
|
||||
= render 'layouts/header/marketing_links'
|
||||
- e.control do
|
||||
.gl-display-none.gl-sm-display-block
|
||||
= render "layouts/nav/top_nav"
|
||||
|
@ -117,6 +119,9 @@
|
|||
- e.candidate do
|
||||
%li.nav-item.gl-display-none.gl-sm-display-block
|
||||
= 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 {}
|
||||
- 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) }
|
||||
|
@ -138,6 +143,14 @@
|
|||
%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.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
|
||||
= render 'layouts/header/sign_in_register_button'
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"containers_error_image" => image_path('illustrations/docker-error-state.svg'),
|
||||
"repository_url" => escape_once(@project.container_registry_url),
|
||||
"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'),
|
||||
"run_cleanup_policies_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'run-the-cleanup-policy-now'),
|
||||
"project_path": @project.full_path,
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
is_admin: current_user&.admin.to_s,
|
||||
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,
|
||||
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,
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
use a JSON Web Token to authenticate with GitLab. The
|
||||
|
@ -883,7 +883,7 @@ project.container_repositories.find_each do |repo|
|
|||
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
|
||||
|
||||
|
|
|
@ -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.
|
||||
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.
|
||||
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:
|
||||
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 |
|
||||
| ------------------------------------------------------------ | ------------------ | ------------------------ | ------------------------------------------------------------ |
|
||||
| [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. |
|
||||
| [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. |
|
||||
|
|
|
@ -64,7 +64,7 @@ The **CI/CD** settings contain:
|
|||
This pipeline configuration is run after the project's own configuration.
|
||||
- [Package Registry](continuous_integration.md#package-registry-configuration) -
|
||||
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.
|
||||
|
||||
### Geo **(PREMIUM SELF)**
|
||||
|
|
|
@ -483,256 +483,9 @@ defined in the `delete_image` job.
|
|||
|
||||
### 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.
|
||||
|
||||
## 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
|
||||
|
||||
- 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:
|
||||
|
||||
- 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.
|
||||
|
||||
- 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)**
|
||||
|
||||
> 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.
|
||||
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.
|
||||
|
@ -127,29 +125,17 @@ Prerequisites:
|
|||
- 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**.
|
||||
|
||||
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/`.
|
||||
**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. Go to your project's **Settings**.
|
||||
1. Select **Expand** under the **Merge requests** header.
|
||||
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.
|
||||
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:
|
||||
|
||||
To set a default description template for issues, either:
|
||||
|
||||
- [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**.
|
||||
1. Select **Expand** under **Default issue template**.
|
||||
1. Fill in the **Default description template for issues** text area.
|
||||
|
||||
Because GitLab merge request and issues support [Markdown](../markdown.md), you can use it to format
|
||||
headings, lists, and so on.
|
||||
|
|
|
@ -84,7 +84,7 @@ module Gitlab
|
|||
Gitlab::Auth::UniqueIpsLimiter.limit_user! do
|
||||
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 = []
|
||||
|
||||
|
@ -187,7 +187,7 @@ module Gitlab
|
|||
|
||||
if valid_oauth_token?(token)
|
||||
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))
|
||||
end
|
||||
|
@ -210,7 +210,7 @@ module Gitlab
|
|||
return unless token_bot_in_project?(token.user, project) || token_bot_in_group?(token.user, project)
|
||||
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))
|
||||
end
|
||||
end
|
||||
|
@ -309,7 +309,7 @@ module Gitlab
|
|||
return unless build.project.builds_enabled?
|
||||
|
||||
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
|
||||
Gitlab::Auth::Result.new(build.user, build.project, :build, build_authentication_abilities)
|
||||
|
@ -406,10 +406,6 @@ module Gitlab
|
|||
|
||||
user.increment_failed_attempts!
|
||||
end
|
||||
|
||||
def can_user_login_with_non_expired_password?(user)
|
||||
user.can?(:log_in) && !user.password_expired_if_applicable?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,6 +35,9 @@ ci_daily_build_group_report_results:
|
|||
- table: namespaces
|
||||
column: group_id
|
||||
on_delete: async_delete
|
||||
- table: projects
|
||||
column: project_id
|
||||
on_delete: async_delete
|
||||
ci_freeze_periods:
|
||||
- table: projects
|
||||
column: project_id
|
||||
|
|
|
@ -16040,6 +16040,9 @@ msgstr ""
|
|||
msgid "Get a free instance review"
|
||||
msgstr ""
|
||||
|
||||
msgid "Get a free trial"
|
||||
msgstr ""
|
||||
|
||||
msgid "Get a support subscription"
|
||||
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."
|
||||
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."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
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
|
||||
let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
|
||||
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)
|
||||
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
|
||||
it 'renders template' do
|
||||
list_boards
|
||||
|
@ -107,15 +98,6 @@ RSpec.describe Groups::BoardsController do
|
|||
describe 'GET show' do
|
||||
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
|
||||
it 'renders template' do
|
||||
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)
|
||||
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
|
||||
it 'renders template' do
|
||||
list_boards
|
||||
|
@ -125,15 +116,6 @@ RSpec.describe Projects::BoardsController do
|
|||
describe 'GET show' do
|
||||
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
|
||||
read_board board: board
|
||||
|
||||
|
|
|
@ -20,6 +20,21 @@ RSpec.describe 'User sees experimental lmarketing header' do
|
|||
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
|
||||
it 'does not show marketing header links', :aggregate_failures do
|
||||
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 "Sign up now"
|
||||
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"
|
||||
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 () => {
|
||||
createComponent({
|
||||
queryHandler: jest.fn().mockResolvedValue({
|
||||
|
|
|
@ -498,6 +498,12 @@ RSpec.describe ApplicationHelper do
|
|||
it { is_expected.to include(expected_class) }
|
||||
end
|
||||
|
||||
context 'when candidate (:trial_focused variant)' do
|
||||
let(:variant) { :trial_focused }
|
||||
|
||||
it { is_expected.to include(expected_class) }
|
||||
end
|
||||
|
||||
context 'when control' do
|
||||
let(:variant) { :control }
|
||||
|
||||
|
|
|
@ -72,37 +72,6 @@ RSpec.describe IssuablesDescriptionTemplatesHelper, :clean_gitlab_redis_cache do
|
|||
].to_json
|
||||
expect(helper.available_service_desk_templates_for(@project)).to eq(value)
|
||||
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
|
||||
|
||||
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'
|
||||
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
|
||||
let(:payload) { '' }
|
||||
|
||||
|
|
|
@ -170,4 +170,10 @@ RSpec.describe Ci::DailyBuildGroupReportResult do
|
|||
|
||||
let!(:parent) { model.group }
|
||||
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
|
||||
|
|
|
@ -5805,6 +5805,48 @@ RSpec.describe User do
|
|||
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
|
||||
context 'when synced attributes metadata is present' do
|
||||
it 'delegates to synced_attributes_metadata' do
|
||||
|
|
Loading…
Reference in a new issue