{{ statusText }}
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue
index 4ffd8390e4d..19d35a135fd 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue
@@ -107,7 +107,7 @@ export default {
diff --git a/app/assets/javascripts/pages/admin/application_settings/repository/index.js b/app/assets/javascripts/pages/admin/application_settings/repository/index.js
new file mode 100644
index 00000000000..9a67fe7b6f8
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/application_settings/repository/index.js
@@ -0,0 +1,3 @@
+import initInactiveProjectDeletion from '~/admin/application_settings/inactive_project_deletion';
+
+initInactiveProjectDeletion();
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 1949603b416..18a878214e7 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -20,7 +20,7 @@ $system-note-svg-size: 16px;
}
.note-wrapper {
- padding: $gl-padding;
+ padding: $gl-padding $gl-padding-8 $gl-padding $gl-padding;
&.outlined {
@include outline-comment();
diff --git a/app/controllers/projects/usage_quotas_controller.rb b/app/controllers/projects/usage_quotas_controller.rb
index 07a3c010f4f..f52b9f30250 100644
--- a/app/controllers/projects/usage_quotas_controller.rb
+++ b/app/controllers/projects/usage_quotas_controller.rb
@@ -3,6 +3,10 @@
class Projects::UsageQuotasController < Projects::ApplicationController
before_action :authorize_read_usage_quotas!
+ before_action do
+ push_frontend_feature_flag(:container_registry_project_statistics, project)
+ end
+
layout "project_settings"
feature_category :utilization
diff --git a/app/helpers/admin/application_settings/settings_helper.rb b/app/helpers/admin/application_settings/settings_helper.rb
new file mode 100644
index 00000000000..bd83ed19705
--- /dev/null
+++ b/app/helpers/admin/application_settings/settings_helper.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Admin
+ module ApplicationSettings
+ module SettingsHelper
+ def inactive_projects_deletion_data(settings)
+ {
+ delete_inactive_projects: settings.delete_inactive_projects.to_s,
+ inactive_projects_delete_after_months: settings.inactive_projects_delete_after_months,
+ inactive_projects_min_size_mb: settings.inactive_projects_min_size_mb,
+ inactive_projects_send_warning_email_after_months: settings.inactive_projects_send_warning_email_after_months
+ }
+ end
+ end
+ end
+end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 5293bfcf1ab..f405f5bc663 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -513,6 +513,10 @@ class Commit
# We don't want to do anything for `Commit` model, so this is empty.
end
+ # We are continuing to support `(fixup!|squash!)` here as it is the prefix
+ # added by `git commit --fixup` which is used by some community members.
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/342937#note_892065311
+ #
DRAFT_REGEX = /\A\s*#{Gitlab::Regex.merge_request_draft}|(fixup!|squash!)\s/.freeze
def work_in_progress?
diff --git a/app/views/admin/application_settings/_repository_check.html.haml b/app/views/admin/application_settings/_repository_check.html.haml
index c2087efa650..ef8d3ccc8ab 100644
--- a/app/views/admin/application_settings/_repository_check.html.haml
+++ b/app/views/admin/application_settings/_repository_check.html.haml
@@ -39,4 +39,8 @@
.form-text.text-muted
= html_escape(s_('Number of Git pushes after which %{code_start}git gc%{code_end} is run.')) % { code_start: ''.html_safe, code_end: ''.html_safe }
+ .sub-section
+ %h4= s_("AdminSettings|Inactive project deletion")
+ .js-inactive-project-deletion-form{ data: inactive_projects_deletion_data(@application_setting) }
+
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
diff --git a/app/views/groups/_create_chat_team.html.haml b/app/views/groups/_create_chat_team.html.haml
index 8f50d499605..45561031083 100644
--- a/app/views/groups/_create_chat_team.html.haml
+++ b/app/views/groups/_create_chat_team.html.haml
@@ -1,3 +1,6 @@
+- bind_out_tag = content_tag(:span, nil, { data: { bind_out: :create_chat_team } })
+- checkbox_help_text = "%s %s/%s".html_safe % [_('Mattermost URL:'), Settings.mattermost.host, bind_out_tag]
+
.form-group
.col-sm-2.col-form-label
= f.label :create_chat_team do
@@ -5,13 +8,5 @@
= custom_icon('icon_mattermost')
%span.gl-ml-2= _('Mattermost')
.col-sm-12
- .form-check.js-toggle-container
- .js-toggle-button.form-check-input= f.check_box(:create_chat_team, { checked: false }, true, false)
- = f.label :create_chat_team, class: 'form-check-label' do
- = _('Create a Mattermost team for this group')
- %br
- %small.light.js-toggle-content
- = _('Mattermost URL:')
- = Settings.mattermost.host
- %span> /
- %span{ "data-bind-out" => "create_chat_team" }
+ = f.gitlab_ui_checkbox_component :create_chat_team, _('Create a Mattermost team for this group'), help_text: checkbox_help_text, checkbox_options: { checked: false }, checked_value: true, unchecked_value: false
+
diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml
index 58a78a8adc1..3fb2b88dadd 100644
--- a/app/views/groups/new.html.haml
+++ b/app/views/groups/new.html.haml
@@ -10,7 +10,7 @@
.row{ 'v-cloak': true }
#create-group-pane.tab-pane
- = form_for @group, html: { class: 'group-form gl-show-field-errors gl-mt-3' } do |f|
+ = gitlab_ui_form_for @group, html: { class: 'group-form gl-show-field-errors gl-mt-3' } do |f|
= render 'new_group_fields', f: f, group_name_id: 'create-group-name'
#import-group-pane.tab-pane
diff --git a/app/views/projects/issues/_service_desk_info_content.html.haml b/app/views/projects/issues/_service_desk_info_content.html.haml
index f0ec68ba54b..bad75ac2cd9 100644
--- a/app/views/projects/issues/_service_desk_info_content.html.haml
+++ b/app/views/projects/issues/_service_desk_info_content.html.haml
@@ -21,4 +21,4 @@
- if can_edit_project_settings && !service_desk_enabled
.gl-mt-3
- = link_to s_("ServiceDesk|Enable Service Desk"), edit_project_path(@project), class: 'gl-button btn btn-success'
+ = link_to s_("ServiceDesk|Enable Service Desk"), edit_project_path(@project), class: 'gl-button btn btn-confirm'
diff --git a/config/feature_flags/development/delayed_repository_update_mirror_worker.yml b/config/feature_flags/development/delayed_repository_update_mirror_worker.yml
new file mode 100644
index 00000000000..0de84c81e1d
--- /dev/null
+++ b/config/feature_flags/development/delayed_repository_update_mirror_worker.yml
@@ -0,0 +1,8 @@
+---
+name: delayed_repository_update_mirror_worker
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87995
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/362894
+milestone: '15.1'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml b/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml
index a0dd87cd7dc..67cae705601 100644
--- a/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml
+++ b/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: counts_monthly.aggregated_metrics.code_review_category_monthly_active_users
description: Unique users performing actions on code review events
product_section: dev
-product_stage: devops::create
+product_stage: create
product_group: group::code review
product_category:
value_type: number
diff --git a/config/metrics/counts_28d/20210427103010_code_review_extension_category_monthly_active_users.yml b/config/metrics/counts_28d/20210427103010_code_review_extension_category_monthly_active_users.yml
index faa452f73a6..b379aa78586 100644
--- a/config/metrics/counts_28d/20210427103010_code_review_extension_category_monthly_active_users.yml
+++ b/config/metrics/counts_28d/20210427103010_code_review_extension_category_monthly_active_users.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts_monthly.aggregated_metrics.code_review_extension_category_monthly_active_users
description: Number of users performing i_code_review_user_vs_code_api_request event
product_section: dev
-product_stage: devops::create
+product_stage: create
product_group: group::code review
product_category:
value_type: number
diff --git a/config/metrics/counts_28d/20210427103119_code_review_group_monthly_active_users.yml b/config/metrics/counts_28d/20210427103119_code_review_group_monthly_active_users.yml
index 5cbdd9afa54..01c4724971d 100644
--- a/config/metrics/counts_28d/20210427103119_code_review_group_monthly_active_users.yml
+++ b/config/metrics/counts_28d/20210427103119_code_review_group_monthly_active_users.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts_monthly.aggregated_metrics.code_review_group_monthly_active_users
description: Number of users performing at least one of the code review events
product_section: dev
-product_stage: devops::create
+product_stage: create
product_group: group::code review
product_category:
value_type: number
diff --git a/config/metrics/counts_28d/20210930125418_github_import_project_start_monthly.yml b/config/metrics/counts_28d/20210930125418_github_import_project_start_monthly.yml
index 2812aa73cad..d79dede39f0 100644
--- a/config/metrics/counts_28d/20210930125418_github_import_project_start_monthly.yml
+++ b/config/metrics/counts_28d/20210930125418_github_import_project_start_monthly.yml
@@ -2,7 +2,7 @@
key_path: redis_hll_counters.importer.github_import_project_start_monthly
description: The number of github projects that were enqueued to start monthy
product_section: dev
-product_stage: devops
+product_stage: manage
product_group: group::import
product_category:
value_type: number
diff --git a/config/metrics/counts_28d/20210930130531_github_import_project_success_monthly.yml b/config/metrics/counts_28d/20210930130531_github_import_project_success_monthly.yml
index ab599c67376..eb4ce81997f 100644
--- a/config/metrics/counts_28d/20210930130531_github_import_project_success_monthly.yml
+++ b/config/metrics/counts_28d/20210930130531_github_import_project_success_monthly.yml
@@ -2,7 +2,7 @@
key_path: redis_hll_counters.importer.github_import_project_success_monthly
description: The number of github projects that were successful monthly
product_section: dev
-product_stage: devops
+product_stage: manage
product_group: group::import
product_category:
value_type: number
diff --git a/config/metrics/counts_28d/20210930163813_github_import_project_failure_monthly.yml b/config/metrics/counts_28d/20210930163813_github_import_project_failure_monthly.yml
index 6651a770920..0f16cf65ca5 100644
--- a/config/metrics/counts_28d/20210930163813_github_import_project_failure_monthly.yml
+++ b/config/metrics/counts_28d/20210930163813_github_import_project_failure_monthly.yml
@@ -2,7 +2,7 @@
key_path: redis_hll_counters.importer.github_import_project_failure_monthly
description: The number of github projects that failed monthly
product_section: dev
-product_stage: devops
+product_stage: manage
product_group: group::import
product_category:
value_type: number
diff --git a/config/metrics/counts_7d/20210427103328_code_review_group_monthly_active_users.yml b/config/metrics/counts_7d/20210427103328_code_review_group_monthly_active_users.yml
index fa58494cc05..1143a233e85 100644
--- a/config/metrics/counts_7d/20210427103328_code_review_group_monthly_active_users.yml
+++ b/config/metrics/counts_7d/20210427103328_code_review_group_monthly_active_users.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts_weekly.aggregated_metrics.code_review_group_monthly_active_users
description: Number of users performing at least one of the code review events
product_section: dev
-product_stage: devops::create
+product_stage: create
product_group: group::code review
product_category:
value_type: number
diff --git a/config/metrics/counts_7d/20210427103407_code_review_category_monthly_active_users.yml b/config/metrics/counts_7d/20210427103407_code_review_category_monthly_active_users.yml
index e1c61db272b..96490623d95 100644
--- a/config/metrics/counts_7d/20210427103407_code_review_category_monthly_active_users.yml
+++ b/config/metrics/counts_7d/20210427103407_code_review_category_monthly_active_users.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts_weekly.aggregated_metrics.code_review_category_monthly_active_users
description: Unique users performing actions on code review events
product_section: dev
-product_stage: devops::create
+product_stage: create
product_group: group::code review
product_category:
value_type: number
diff --git a/config/metrics/counts_7d/20210427103452_code_review_extension_category_monthly_active_users.yml b/config/metrics/counts_7d/20210427103452_code_review_extension_category_monthly_active_users.yml
index 29e52e07a14..d452a7d2c28 100644
--- a/config/metrics/counts_7d/20210427103452_code_review_extension_category_monthly_active_users.yml
+++ b/config/metrics/counts_7d/20210427103452_code_review_extension_category_monthly_active_users.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts_weekly.aggregated_metrics.code_review_extension_category_monthly_active_users
description: Number of users performing code review extension_category events
product_section: dev
-product_stage: devops::create
+product_stage: create
product_group: group::code review
product_category:
value_type: number
diff --git a/config/metrics/counts_7d/20210930125411_github_import_project_start_weekly.yml b/config/metrics/counts_7d/20210930125411_github_import_project_start_weekly.yml
index 2c5b7d46e1a..fb065ffe3b1 100644
--- a/config/metrics/counts_7d/20210930125411_github_import_project_start_weekly.yml
+++ b/config/metrics/counts_7d/20210930125411_github_import_project_start_weekly.yml
@@ -2,7 +2,7 @@
key_path: redis_hll_counters.importer.github_import_project_start_weekly
description: The number of github projects that were enqueued to start weekly
product_section: dev
-product_stage: devops
+product_stage: manage
product_group: group::import
product_category:
value_type: number
diff --git a/config/metrics/counts_7d/20210930130525_github_import_project_success_weekly.yml b/config/metrics/counts_7d/20210930130525_github_import_project_success_weekly.yml
index 10147658ddc..887dc2565dc 100644
--- a/config/metrics/counts_7d/20210930130525_github_import_project_success_weekly.yml
+++ b/config/metrics/counts_7d/20210930130525_github_import_project_success_weekly.yml
@@ -2,7 +2,7 @@
key_path: redis_hll_counters.importer.github_import_project_success_weekly
description: The number of github projects that were successful weekly
product_section: dev
-product_stage: devops
+product_stage: manage
product_group: group::import
product_category:
value_type: number
diff --git a/config/metrics/counts_7d/20210930163807_github_import_project_failure_weekly.yml b/config/metrics/counts_7d/20210930163807_github_import_project_failure_weekly.yml
index 33a1902504f..c4ffb079c38 100644
--- a/config/metrics/counts_7d/20210930163807_github_import_project_failure_weekly.yml
+++ b/config/metrics/counts_7d/20210930163807_github_import_project_failure_weekly.yml
@@ -2,7 +2,7 @@
key_path: redis_hll_counters.importer.github_import_project_failure_weekly
description: The number of github projects that failed weekly
product_section: dev
-product_stage: devops
+product_stage: manage
product_group: group::import
product_category:
value_type: number
diff --git a/data/deprecations/14-8-remove-support-for-fixup-in-commit-message-triggering-draft-status.yml b/data/deprecations/14-8-remove-support-for-fixup-in-commit-message-triggering-draft-status.yml
deleted file mode 100644
index f738b71f1b7..00000000000
--- a/data/deprecations/14-8-remove-support-for-fixup-in-commit-message-triggering-draft-status.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-- name: "`fixup!` commit messages setting draft status of associated Merge Request" # The name of the feature to be deprecated
- announcement_milestone: "14.8" # The milestone when this feature was first announced as deprecated.
- announcement_date: "2022-02-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
- removal_milestone: "15.0" # The milestone when this feature is planned to be removed
- removal_date: "2022-06-22" # This should almost always be the 22nd of a month (YYYY-MM-22), the date of the milestone release when this feature is planned to be removed.
- body: | # Do not modify this line, instead modify the lines below.
- The use of `fixup!` as a commit message to trigger draft status
- of the associated Merge Request is generally unused, and can cause
- confusion with other uses of the term. "Draft" is the preferred
- and supported trigger for triggering draft status from commit
- messages, as part of our streamlining of the feature.
- Support for `fixup!` is now considered deprecated, and will be
- removed in GitLab 15.0.
- documentation_url: "https://docs.gitlab.com/ee/user/project/merge_requests/drafts.html#mark-merge-requests-as-drafts"
- issue_url: "https://gitlab.com/gitlab-org/gitlab/-/issues/342937"
diff --git a/doc/administration/inactive_project_deletion.md b/doc/administration/inactive_project_deletion.md
index 40ca5e8bce3..224b52d420e 100644
--- a/doc/administration/inactive_project_deletion.md
+++ b/doc/administration/inactive_project_deletion.md
@@ -20,21 +20,24 @@ deleted, the action generates an audit event that it was performed by the first
## Configure inactive project deletion
-You can configure inactive projects deletion or turn it off using the
-[Application settings API](../api/settings.md#change-application-settings).
+You can configure inactive projects deletion or turn it off using either:
+
+- [The GitLab API](#using-the-api) (GitLab 15.0 and later).
+- [The GitLab UI](#using-the-gitlab-ui) (GitLab 15.1 and later).
The following options are available:
-- `delete_inactive_projects`: Enable or disable inactive project deletion.
-- `inactive_projects_min_size_mb`: Minimum size (MB) of inactive projects to be considered for deletion.
- Projects smaller in size than this threshold aren't considered inactive.
-- `inactive_projects_delete_after_months`: Minimum duration (months) after which a project is scheduled for deletion if
- it continues be inactive.
-- `inactive_projects_send_warning_email_after_months`: Minimum duration (months) after which a deletion warning email is
- sent if a project continues to be inactive. The warning email is sent to users with the Owner and Maintainer roles of
- the inactive project. This duration should be less than the `inactive_projects_delete_after_months` duration.
+- **Delete inactive projects** (`delete_inactive_projects`): Enable or disable inactive project deletion.
+- **Delete inactive projects that exceed** (`inactive_projects_min_size_mb`): Minimum size (MB) of inactive projects to
+ be considered for deletion. Projects smaller in size than this threshold aren't considered inactive.
+- **Delete project after** (`inactive_projects_delete_after_months`): Minimum duration (months) after which a project is
+ scheduled for deletion if it continues be inactive.
+- **Send warning email** (`inactive_projects_send_warning_email_after_months`): Minimum duration (months) after which a
+ deletion warning email is sent if a project continues to be inactive. The warning email is sent to users with the
+ Owner and Maintainer roles of the inactive project. This duration must be less than the
+ **Delete project after** (`inactive_projects_delete_after_months`) duration.
-For example:
+For example (using the API):
- `delete_inactive_projects` enabled.
- `inactive_projects_min_size_mb` set to `50`.
@@ -49,6 +52,22 @@ In this scenario, when a project's size is:
with the scheduled date of deletion.
- More than 12 months, the project is scheduled for deletion.
+### Using the API
+
+You can use the [Application settings API](../api/settings.md#change-application-settings) to configure inactive projects.
+
+### Using the GitLab UI
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85575) in GitLab 15.1.
+
+To configure inactive projects with the GitLab UI:
+
+1. On the top bar, select **Menu > Admin**.
+1. On the left sidebar, select **Settings > Repository**.
+1. Expand **Repository maintenance**.
+1. In the **Inactive project deletion** section, configure the necessary options.
+1. Select **Save changes**.
+
## Determine when a project was last active
You can view a project's activities and determine when the project was last active in the following ways:
diff --git a/doc/integration/index.md b/doc/integration/index.md
index f1d16dc409d..bcc3eb6c030 100644
--- a/doc/integration/index.md
+++ b/doc/integration/index.md
@@ -104,3 +104,13 @@ After that restart GitLab with:
```shell
sudo gitlab-ctl restart
```
+
+### Search Sidekiq logs in Kibana
+
+To locate a specific integration in Kibana, use the following KQL search string:
+
+```plaintext
+`json.integration_class.keyword : "Integrations::Jira" and json.project_path : "path/to/project"`
+```
+
+You can find information in `json.exception.backtrace`, `json.exception.class`, `json.exception.message`, and `json.message`.
diff --git a/doc/integration/jira/index.md b/doc/integration/jira/index.md
index 371f3a4ab8e..1d45577da85 100644
--- a/doc/integration/jira/index.md
+++ b/doc/integration/jira/index.md
@@ -91,6 +91,8 @@ set up for the integration has permission to:
Jira issue references and update comments do not work if the GitLab issue tracker is disabled.
+If you [restrict IP addresses for Jira access](https://support.atlassian.com/security-and-access-policies/docs/specify-ip-addresses-for-product-access/), make sure you add your self-managed IP addresses or [GitLab.com IP range](../../user/gitlab_com/index.md#ip-range) to the allowlist in Jira.
+
### GitLab cannot close a Jira issue
If GitLab cannot close a Jira issue:
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 903ae9c714c..8dfaeb73c9f 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -1094,21 +1094,6 @@ The predefined CI/CD variables that start with `CI_BUILD_*` were deprecated in G
**Planned removal milestone: 16.0 (2023-04-22)**
-
-
-### `fixup!` commit messages setting draft status of associated Merge Request
-
-The use of `fixup!` as a commit message to trigger draft status
-of the associated Merge Request is generally unused, and can cause
-confusion with other uses of the term. "Draft" is the preferred
-and supported trigger for triggering draft status from commit
-messages, as part of our streamlining of the feature.
-Support for `fixup!` is now considered deprecated, and will be
-removed in GitLab 15.0.
-
-**Planned removal milestone: 15.0 (2022-06-22)**
-
-
### `projectFingerprint` in `PipelineSecurityReportFinding` GraphQL
diff --git a/doc/user/project/description_templates.md b/doc/user/project/description_templates.md
index 4f8cfad1444..342d843c306 100644
--- a/doc/user/project/description_templates.md
+++ b/doc/user/project/description_templates.md
@@ -116,7 +116,7 @@ You might also be interested in templates for various
### Set a default template for merge requests and issues
-> `Default.md` template [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78302) in GitLab 14.8.
+> `Default.md` (case insensitive) template [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78302) in GitLab 14.8.
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
@@ -129,9 +129,9 @@ Prerequisites:
To set a default description template for merge requests, either:
-- [Create a merge request template](#create-a-merge-request-template) named `Default.md` or `default.md`
+- [In GitLab 14.8 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78302), [create a merge request template](#create-a-merge-request-template) named `Default.md` (case insensitive)
and save it in `.gitlab/merge_request_templates/`.
- This doesn't overwrite the default template if one has been set in the project settings.
+ This [doesn't overwrite](#priority-of-default-description-templates) the default template if one has been set in the project settings.
- Users on GitLab Premium and higher: set the default template in project settings:
1. On the top bar, select **Menu > Projects** and find your project.
@@ -142,9 +142,9 @@ To set a default description template for merge requests, either:
To set a default description template for issues, either:
-- [Create an issue template](#create-an-issue-template) named `Default.md` or `default.md`
+- [In GitLab 14.8 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78302), [create an issue template](#create-an-issue-template) named `Default.md` (case insensitive) [in GitLab 14.8 or higher]
and save it in `.gitlab/issue_templates/`.
- This doesn't overwrite the default template if one has been set in the project settings.
+ This [doesn't overwrite](#priority-of-default-description-templates) the default template if one has been set in the project settings.
- Users on GitLab Premium and higher: set the default template in project settings:
1. On the top bar, select **Menu > Projects** and find your project.
@@ -159,15 +159,15 @@ headings, lists, and so on.
You can also provide `issues_template` and `merge_requests_template` attributes in the
[Projects REST API](../../api/projects.md) to keep your default issue and merge request templates up to date.
-#### Priority of description templates
+#### Priority of default description templates
When you set [merge request and issue description templates](#set-a-default-template-for-merge-requests-and-issues)
in various places, they have the following priorities in a project.
The ones higher up override the ones below:
-1. Template selected in project settings.
-1. `Default.md` from the parent group.
-1. `Default.md` from the project repository.
+1. Template set in project settings.
+1. `Default.md` (case insensitive) from the parent group.
+1. `Default.md` (case insensitive) from the project repository.
## Example description template
diff --git a/lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb b/lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb
index 1754f27137c..d5886d7bae7 100644
--- a/lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb
+++ b/lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb
@@ -10,17 +10,10 @@ module BulkImports
relation_name BulkImports::FileTransfer::BaseConfig::SELF_RELATION
+ extractor ::BulkImports::Common::Extractors::JsonExtractor, relation: relation
+
transformer ::BulkImports::Common::Transformers::ProhibitedAttributesTransformer
- def extract(_context)
- download_service.execute
- decompression_service.execute
-
- project_attributes = json_decode(json_attributes)
-
- BulkImports::Pipeline::ExtractedData.new(data: project_attributes)
- end
-
def transform(_context, data)
subrelations = config.portable_relations_tree.keys.map(&:to_s)
@@ -39,51 +32,14 @@ module BulkImports
end
def after_run(_context)
- FileUtils.remove_entry(tmpdir) if Dir.exist?(tmpdir)
- end
-
- def json_attributes
- @json_attributes ||= File.read(File.join(tmpdir, filename))
+ extractor.remove_tmpdir
end
private
- def tmpdir
- @tmpdir ||= Dir.mktmpdir('bulk_imports')
- end
-
def config
@config ||= BulkImports::FileTransfer.config_for(portable)
end
-
- def download_service
- @download_service ||= BulkImports::FileDownloadService.new(
- configuration: context.configuration,
- relative_url: context.entity.relation_download_url_path(self.class.relation),
- tmpdir: tmpdir,
- filename: compressed_filename
- )
- end
-
- def decompression_service
- @decompression_service ||= BulkImports::FileDecompressionService.new(tmpdir: tmpdir, filename: compressed_filename)
- end
-
- def compressed_filename
- "#{filename}.gz"
- end
-
- def filename
- "#{self.class.relation}.json"
- end
-
- def json_decode(string)
- Gitlab::Json.parse(string)
- rescue JSON::ParserError => e
- Gitlab::ErrorTracking.log_exception(e)
-
- raise BulkImports::Error, 'Incorrect JSON format'
- end
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 557f6cb43c3..d0a3f1f6dc3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2640,6 +2640,18 @@ msgstr ""
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
+msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
+msgstr ""
+
+msgid "AdminSettings|Delete inactive projects"
+msgstr ""
+
+msgid "AdminSettings|Delete inactive projects that exceed"
+msgstr ""
+
+msgid "AdminSettings|Delete project after"
+msgstr ""
+
msgid "AdminSettings|Disable Elasticsearch until indexing completes."
msgstr ""
@@ -2706,6 +2718,9 @@ msgstr ""
msgid "AdminSettings|Import sources"
msgstr ""
+msgid "AdminSettings|Inactive project deletion"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2742,6 +2757,9 @@ msgstr ""
msgid "AdminSettings|Maximum number of runners registered per project"
msgstr ""
+msgid "AdminSettings|Minimum size must be at least 0."
+msgstr ""
+
msgid "AdminSettings|New CI/CD variables in projects and groups default to protected."
msgstr ""
@@ -2772,6 +2790,9 @@ msgstr ""
msgid "AdminSettings|Required pipeline configuration"
msgstr ""
+msgid "AdminSettings|Requires %{linkStart}email notifications%{linkEnd}"
+msgstr ""
+
msgid "AdminSettings|Restrict group access by IP address. %{link_start}Learn more%{link_end}."
msgstr ""
@@ -2790,6 +2811,12 @@ msgstr ""
msgid "AdminSettings|Select to disable public access for Pages sites, which requires users to sign in for access to the Pages sites in your instance. %{link_start}Learn more.%{link_end}"
msgstr ""
+msgid "AdminSettings|Send email to maintainers after project is inactive for"
+msgstr ""
+
+msgid "AdminSettings|Send warning email"
+msgstr ""
+
msgid "AdminSettings|Service ping is disabled in your configuration file, and cannot be enabled through this form. For more information, see the documentation on %{link_start}deactivating service ping%{link_end}."
msgstr ""
@@ -2808,6 +2835,9 @@ msgstr ""
msgid "AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
msgstr ""
+msgid "AdminSettings|Setting must be greater than 0."
+msgstr ""
+
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
@@ -2841,9 +2871,15 @@ msgstr ""
msgid "AdminSettings|When paused, GitLab still tracks the changes. This is useful for cluster/index migrations."
msgstr ""
+msgid "AdminSettings|When to delete inactive projects"
+msgstr ""
+
msgid "AdminSettings|You can enable Registration Features because Service Ping is enabled. To continue using Registration Features in the future, you will also need to register with GitLab via a new cloud licensing service."
msgstr ""
+msgid "AdminSettings|You can't delete projects before the warning email is sent."
+msgstr ""
+
msgid "AdminStatistics|Active Users"
msgstr ""
@@ -6028,6 +6064,9 @@ msgstr ""
msgid "Billings|Shared runners cannot be enabled until a valid credit card is on file."
msgstr ""
+msgid "Billings|The last owner cannot be removed from a seat."
+msgstr ""
+
msgid "Billings|To make this member active, you must first remove an existing active member, or toggle them to over limit."
msgstr ""
@@ -6049,6 +6088,9 @@ msgstr ""
msgid "Billings|You can't change the seat status of a user who was invited via a group or project."
msgstr ""
+msgid "Billings|You can't remove yourself from a seat, but you can leave the group."
+msgstr ""
+
msgid "Billings|You'll now be able to take advantage of free CI/CD minutes on shared runners."
msgstr ""
@@ -40764,6 +40806,9 @@ msgstr ""
msgid "UsageQuota|Code packages and container images."
msgstr ""
+msgid "UsageQuota|Container Registry"
+msgstr ""
+
msgid "UsageQuota|Current period usage"
msgstr ""
@@ -40779,6 +40824,9 @@ msgstr ""
msgid "UsageQuota|Git repository."
msgstr ""
+msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker Images."
+msgstr ""
+
msgid "UsageQuota|Includes artifacts, repositories, wiki, uploads, and other items."
msgstr ""
@@ -45154,6 +45202,9 @@ msgstr ""
msgid "missing"
msgstr ""
+msgid "months"
+msgstr ""
+
msgid "most recent deployment"
msgstr ""
diff --git a/qa/Dockerfile b/qa/Dockerfile
index 4fd44ba02df..da2b8a527d4 100644
--- a/qa/Dockerfile
+++ b/qa/Dockerfile
@@ -1,8 +1,9 @@
FROM registry.gitlab.com/gitlab-org/gitlab-build-images/debian-bullseye-ruby-2.7:bundler-2.3-git-2.33-lfs-2.9-chrome-99-docker-20.10.14-gcloud-383-kubectl-1.23
LABEL maintainer="GitLab Quality Department "
-ENV DEBIAN_FRONTEND="noninteractive" \
- BUNDLE_WITHOUT=development
+ENV DEBIAN_FRONTEND="noninteractive"
+# Override config path to make sure local config doesn't override it when building image locally
+ENV BUNDLE_APP_CONFIG=/home/gitlab/.bundle
##
# Install system libs
@@ -27,7 +28,8 @@ WORKDIR /home/gitlab/qa
# Install qa dependencies or fetch from cache if unchanged
#
COPY ./qa/Gemfile* /home/gitlab/qa/
-RUN bundle install --jobs=$(nproc) --retry=3
+RUN bundle config set --local without development \
+ && bundle install --retry=3
##
# Fetch chromedriver based on version of chrome
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index ceb4af03f89..fa454cfcc24 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -127,7 +127,7 @@ RSpec.describe 'Group' do
describe 'Mattermost team creation' do
before do
- stub_mattermost_setting(enabled: mattermost_enabled)
+ stub_mattermost_setting(enabled: mattermost_enabled, host: 'https://mattermost.test')
visit new_group_path
click_link 'Create group'
@@ -145,13 +145,14 @@ RSpec.describe 'Group' do
end
it 'updates the team URL on graph path update', :js do
- out_span = find('span[data-bind-out="create_chat_team"]', visible: false)
+ label = find('#group_create_chat_team ~ label[for=group_create_chat_team]')
+ url = 'https://mattermost.test/test-group'
- expect(out_span.text).to be_empty
+ expect(label.text).not_to match(url)
fill_in('group_path', with: 'test-group')
- expect(out_span.text).to eq('test-group')
+ expect(label.text).to match(url)
end
end
diff --git a/spec/frontend/admin/application_settings/inactive_project_deletion/components/form_spec.js b/spec/frontend/admin/application_settings/inactive_project_deletion/components/form_spec.js
new file mode 100644
index 00000000000..2db997942a7
--- /dev/null
+++ b/spec/frontend/admin/application_settings/inactive_project_deletion/components/form_spec.js
@@ -0,0 +1,148 @@
+import { GlFormCheckbox } from '@gitlab/ui';
+import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
+import SettingsForm from '~/admin/application_settings/inactive_project_deletion/components/form.vue';
+
+describe('Form component', () => {
+ let wrapper;
+
+ const findEnabledCheckbox = () => wrapper.findComponent(GlFormCheckbox);
+ const findProjectDeletionSettings = () =>
+ wrapper.findByTestId('inactive-project-deletion-settings');
+ const findMinSizeGroup = () => wrapper.findByTestId('min-size-group');
+ const findMinSizeInputGroup = () => wrapper.findByTestId('min-size-input-group');
+ const findMinSizeInput = () => wrapper.findByTestId('min-size-input');
+ const findDeleteAfterMonthsGroup = () => wrapper.findByTestId('delete-after-months-group');
+ const findDeleteAfterMonthsInputGroup = () =>
+ wrapper.findByTestId('delete-after-months-input-group');
+ const findDeleteAfterMonthsInput = () => wrapper.findByTestId('delete-after-months-input');
+ const findSendWarningEmailAfterMonthsGroup = () =>
+ wrapper.findByTestId('send-warning-email-after-months-group');
+ const findSendWarningEmailAfterMonthsInputGroup = () =>
+ wrapper.findByTestId('send-warning-email-after-months-input-group');
+ const findSendWarningEmailAfterMonthsInput = () =>
+ wrapper.findByTestId('send-warning-email-after-months-input');
+
+ const createComponent = (
+ mountFn = shallowMountExtended,
+ propsData = { deleteInactiveProjects: true },
+ ) => {
+ wrapper = mountFn(SettingsForm, { propsData });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('Enable inactive project deletion', () => {
+ it('has the checkbox', () => {
+ createComponent();
+
+ expect(findEnabledCheckbox().exists()).toBe(true);
+ });
+
+ it.each([[true], [false]])(
+ 'when the checkbox is %s then the project deletion settings visibility is set to %s',
+ (visible) => {
+ createComponent(shallowMountExtended, { deleteInactiveProjects: visible });
+
+ expect(findProjectDeletionSettings().exists()).toBe(visible);
+ },
+ );
+ });
+
+ describe('Minimum size for deletion', () => {
+ beforeEach(() => {
+ createComponent(mountExtended);
+ });
+
+ it('has the minimum size input', () => {
+ expect(findMinSizeInput().exists()).toBe(true);
+ });
+
+ it('has the field description', () => {
+ expect(findMinSizeGroup().text()).toContain('Delete inactive projects that exceed');
+ });
+
+ it('has the appended text on the field', () => {
+ expect(findMinSizeInputGroup().text()).toContain('MB');
+ });
+
+ it.each`
+ value | valid
+ ${'0'} | ${true}
+ ${'250'} | ${true}
+ ${'-1'} | ${false}
+ `(
+ 'when the minimum size input has a value of $value, then its validity should be $valid',
+ async ({ value, valid }) => {
+ await findMinSizeInput().find('input').setValue(value);
+
+ expect(findMinSizeGroup().classes('is-valid')).toBe(valid);
+ expect(findMinSizeInput().classes('is-valid')).toBe(valid);
+ },
+ );
+ });
+
+ describe('Delete project after', () => {
+ beforeEach(() => {
+ createComponent(mountExtended);
+ });
+
+ it('has the delete after months input', () => {
+ expect(findDeleteAfterMonthsInput().exists()).toBe(true);
+ });
+
+ it('has the appended text on the field', () => {
+ expect(findDeleteAfterMonthsInputGroup().text()).toContain('months');
+ });
+
+ it.each`
+ value | valid
+ ${'0'} | ${false}
+ ${'1'} | ${false /* Less than the default send warning email months */}
+ ${'2'} | ${true}
+ `(
+ 'when the delete after months input has a value of $value, then its validity should be $valid',
+ async ({ value, valid }) => {
+ await findDeleteAfterMonthsInput().find('input').setValue(value);
+
+ expect(findDeleteAfterMonthsGroup().classes('is-valid')).toBe(valid);
+ expect(findDeleteAfterMonthsInput().classes('is-valid')).toBe(valid);
+ },
+ );
+ });
+
+ describe('Send warning email', () => {
+ beforeEach(() => {
+ createComponent(mountExtended);
+ });
+
+ it('has the send warning email after months input', () => {
+ expect(findSendWarningEmailAfterMonthsInput().exists()).toBe(true);
+ });
+
+ it('has the field description', () => {
+ expect(findSendWarningEmailAfterMonthsGroup().text()).toContain(
+ 'Send email to maintainers after project is inactive for',
+ );
+ });
+
+ it('has the appended text on the field', () => {
+ expect(findSendWarningEmailAfterMonthsInputGroup().text()).toContain('months');
+ });
+
+ it.each`
+ value | valid
+ ${'2'} | ${true}
+ ${'0'} | ${false}
+ `(
+ 'when the minimum size input has a value of $value, then its validity should be $valid',
+ async ({ value, valid }) => {
+ await findSendWarningEmailAfterMonthsInput().find('input').setValue(value);
+
+ expect(findSendWarningEmailAfterMonthsGroup().classes('is-valid')).toBe(valid);
+ expect(findSendWarningEmailAfterMonthsInput().classes('is-valid')).toBe(valid);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
index af5723267f4..0581a40b6a2 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
@@ -1,4 +1,4 @@
-import { GlLink, GlPopover, GlSprintf } from '@gitlab/ui';
+import { GlIcon, GlLink, GlPopover, GlSprintf } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { helpPagePath } from '~/helpers/help_page_helper';
import CleanupStatus from '~/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue';
@@ -16,6 +16,7 @@ describe('cleanup_status', () => {
let wrapper;
const findMainIcon = () => wrapper.findByTestId('main-icon');
+ const findMainIconName = () => wrapper.findByTestId('main-icon').find(GlIcon);
const findExtraInfoIcon = () => wrapper.findByTestId('extra-info');
const findPopover = () => wrapper.findComponent(GlPopover);
@@ -61,6 +62,23 @@ describe('cleanup_status', () => {
expect(findMainIcon().exists()).toBe(true);
});
+
+ it.each`
+ status | visible | iconName
+ ${UNFINISHED_STATUS} | ${true} | ${'expire'}
+ ${SCHEDULED_STATUS} | ${true} | ${'clock'}
+ ${ONGOING_STATUS} | ${true} | ${'clock'}
+ ${UNSCHEDULED_STATUS} | ${false} | ${''}
+ `('matches "$iconName" when the status is "$status"', ({ status, visible, iconName }) => {
+ mountComponent({ status });
+
+ expect(findMainIcon().exists()).toBe(visible);
+ if (visible) {
+ const actualIcon = findMainIconName();
+ expect(actualIcon.exists()).toBe(true);
+ expect(actualIcon.props('name')).toBe(iconName);
+ }
+ });
});
describe('extra info icon', () => {
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
index f811468550d..a006de9f00c 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
@@ -93,7 +93,7 @@ describe('registry_header', () => {
expect(text.exists()).toBe(true);
expect(text.props()).toMatchObject({
text: EXPIRATION_POLICY_DISABLED_TEXT,
- icon: 'expire',
+ icon: 'clock',
size: 'xl',
});
});
diff --git a/spec/helpers/admin/application_settings/settings_helper_spec.rb b/spec/helpers/admin/application_settings/settings_helper_spec.rb
new file mode 100644
index 00000000000..9981e0d12bd
--- /dev/null
+++ b/spec/helpers/admin/application_settings/settings_helper_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe Admin::ApplicationSettings::SettingsHelper do
+ describe '#inactive_projects_deletion_data' do
+ let(:delete_inactive_projects) { true }
+ let(:inactive_projects_delete_after_months) { 2 }
+ let(:inactive_projects_min_size_mb) { 250 }
+ let(:inactive_projects_send_warning_email_after_months) { 1 }
+
+ let_it_be(:application_settings) { build(:application_setting) }
+
+ before do
+ stub_application_setting(delete_inactive_projects: delete_inactive_projects)
+ stub_application_setting(inactive_projects_delete_after_months: inactive_projects_delete_after_months)
+ stub_application_setting(inactive_projects_min_size_mb: inactive_projects_min_size_mb)
+ stub_application_setting(
+ inactive_projects_send_warning_email_after_months: inactive_projects_send_warning_email_after_months
+ )
+ end
+
+ subject(:result) { helper.inactive_projects_deletion_data(application_settings) }
+
+ it 'has the expected data' do
+ expect(result).to eq({
+ delete_inactive_projects: delete_inactive_projects.to_s,
+ inactive_projects_delete_after_months: inactive_projects_delete_after_months,
+ inactive_projects_min_size_mb: inactive_projects_min_size_mb,
+ inactive_projects_send_warning_email_after_months: inactive_projects_send_warning_email_after_months
+ })
+ end
+ end
+end
diff --git a/spec/lib/bulk_imports/projects/pipelines/project_attributes_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/project_attributes_pipeline_spec.rb
index aa9c7486c27..4320d5dc119 100644
--- a/spec/lib/bulk_imports/projects/pipelines/project_attributes_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/projects/pipelines/project_attributes_pipeline_spec.rb
@@ -54,17 +54,13 @@ RSpec.describe BulkImports::Projects::Pipelines::ProjectAttributesPipeline do
subject(:pipeline) { described_class.new(context) }
- before do
- allow(Dir).to receive(:mktmpdir).with('bulk_imports').and_return(tmpdir)
- end
-
- after do
- FileUtils.remove_entry(tmpdir) if Dir.exist?(tmpdir)
- end
-
describe '#run' do
before do
- allow(pipeline).to receive(:extract).and_return(BulkImports::Pipeline::ExtractedData.new(data: project_attributes))
+ allow_next_instance_of(BulkImports::Common::Extractors::JsonExtractor) do |extractor|
+ allow(extractor).to receive(:extract).and_return(
+ BulkImports::Pipeline::ExtractedData.new(data: project_attributes)
+ )
+ end
pipeline.run
end
@@ -84,46 +80,6 @@ RSpec.describe BulkImports::Projects::Pipelines::ProjectAttributesPipeline do
end
end
- describe '#extract' do
- before do
- file_download_service = instance_double("BulkImports::FileDownloadService")
- file_decompression_service = instance_double("BulkImports::FileDecompressionService")
-
- expect(BulkImports::FileDownloadService)
- .to receive(:new)
- .with(
- configuration: context.configuration,
- relative_url: "/#{entity.pluralized_name}/#{entity.source_full_path}/export_relations/download?relation=self",
- tmpdir: tmpdir,
- filename: 'self.json.gz')
- .and_return(file_download_service)
-
- expect(BulkImports::FileDecompressionService)
- .to receive(:new)
- .with(tmpdir: tmpdir, filename: 'self.json.gz')
- .and_return(file_decompression_service)
-
- expect(file_download_service).to receive(:execute)
- expect(file_decompression_service).to receive(:execute)
- end
-
- it 'downloads, decompresses & decodes json' do
- allow(pipeline).to receive(:json_attributes).and_return("{\"test\":\"test\"}")
-
- extracted_data = pipeline.extract(context)
-
- expect(extracted_data.data).to match_array([{ 'test' => 'test' }])
- end
-
- context 'when json parsing error occurs' do
- it 'raises an error' do
- allow(pipeline).to receive(:json_attributes).and_return("invalid")
-
- expect { pipeline.extract(context) }.to raise_error(BulkImports::Error)
- end
- end
- end
-
describe '#transform' do
it 'removes prohibited attributes from hash' do
input = { 'description' => 'description', 'issues' => [], 'milestones' => [], 'id' => 5 }
@@ -145,35 +101,13 @@ RSpec.describe BulkImports::Projects::Pipelines::ProjectAttributesPipeline do
end
end
- describe '#json_attributes' do
- it 'reads raw json from file' do
- filepath = File.join(tmpdir, 'self.json')
-
- FileUtils.touch(filepath)
- expect_file_read(filepath)
-
- pipeline.json_attributes
- end
- end
-
describe '#after_run' do
- it 'removes tmp dir' do
- allow(FileUtils).to receive(:remove_entry).and_call_original
- expect(FileUtils).to receive(:remove_entry).with(tmpdir).and_call_original
+ it 'calls extractor#remove_tmpdir' do
+ expect_next_instance_of(BulkImports::Common::Extractors::JsonExtractor) do |extractor|
+ expect(extractor).to receive(:remove_tmpdir)
+ end
pipeline.after_run(nil)
-
- expect(Dir.exist?(tmpdir)).to eq(false)
- end
-
- context 'when dir does not exist' do
- it 'does not attempt to remove tmpdir' do
- FileUtils.remove_entry(tmpdir)
-
- expect(FileUtils).not_to receive(:remove_entry).with(tmpdir)
-
- pipeline.after_run(nil)
- end
end
end
diff --git a/spec/requests/projects/usage_quotas_spec.rb b/spec/requests/projects/usage_quotas_spec.rb
index 6e449a21804..3de871823c4 100644
--- a/spec/requests/projects/usage_quotas_spec.rb
+++ b/spec/requests/projects/usage_quotas_spec.rb
@@ -35,5 +35,26 @@ RSpec.describe 'Project Usage Quotas' do
it_behaves_like 'response with 404 status'
end
+
+ context 'container_registry_project_statistics feature flag' do
+ subject(:body) { response.body }
+
+ before do
+ stub_feature_flags(container_registry_project_statistics: container_registry_project_statistics_enabled)
+ get project_usage_quotas_path(project)
+ end
+
+ context 'when disabled' do
+ let(:container_registry_project_statistics_enabled) { false }
+
+ it { is_expected.to have_pushed_frontend_feature_flags(containerRegistryProjectStatistics: false)}
+ end
+
+ context 'when enabled' do
+ let(:container_registry_project_statistics_enabled) { true }
+
+ it { is_expected.to have_pushed_frontend_feature_flags(containerRegistryProjectStatistics: true)}
+ end
+ end
end
end
diff --git a/spec/views/admin/application_settings/_repository_check.html.haml_spec.rb b/spec/views/admin/application_settings/_repository_check.html.haml_spec.rb
new file mode 100644
index 00000000000..fbabc890a8b
--- /dev/null
+++ b/spec/views/admin/application_settings/_repository_check.html.haml_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'admin/application_settings/_repository_check.html.haml' do
+ let_it_be(:user) { create(:admin) }
+ let_it_be(:application_setting) { build(:application_setting) }
+
+ before do
+ assign(:application_setting, application_setting)
+ allow(view).to receive(:current_user).and_return(user)
+ end
+
+ describe 'repository checks' do
+ it 'has the setting subsection' do
+ render
+
+ expect(rendered).to have_content('Repository checks')
+ end
+
+ it 'renders the correct setting subsection content' do
+ render
+
+ expect(rendered).to have_field('Enable repository checks')
+ expect(rendered).to have_link(
+ 'Clear all repository checks',
+ href: clear_repository_check_states_admin_application_settings_path
+ )
+ end
+ end
+
+ describe 'housekeeping' do
+ it 'has the setting subsection' do
+ render
+
+ expect(rendered).to have_content('Housekeeping')
+ end
+
+ it 'renders the correct setting subsection content' do
+ render
+
+ expect(rendered).to have_field('Enable automatic repository housekeeping')
+ expect(rendered).to have_field('Incremental repack period')
+ expect(rendered).to have_field('Full repack period')
+ expect(rendered).to have_field('Git GC period')
+ end
+ end
+
+ describe 'inactive project deletion' do
+ let_it_be(:application_setting) do
+ build(:application_setting,
+ delete_inactive_projects: true,
+ inactive_projects_delete_after_months: 2,
+ inactive_projects_min_size_mb: 250,
+ inactive_projects_send_warning_email_after_months: 1
+ )
+ end
+
+ it 'has the setting subsection' do
+ render
+
+ expect(rendered).to have_content('Inactive project deletion')
+ end
+
+ it 'renders the correct setting subsection content' do
+ render
+
+ expect(rendered).to have_selector('.js-inactive-project-deletion-form')
+ expect(rendered).to have_selector('[data-delete-inactive-projects="true"]')
+ expect(rendered).to have_selector('[data-inactive-projects-delete-after-months="2"]')
+ expect(rendered).to have_selector('[data-inactive-projects-min-size-mb="250"]')
+ expect(rendered).to have_selector('[data-inactive-projects-send-warning-email-after-months="1"]')
+ end
+ end
+end