diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index dab2ec9e92d..8ff48c96947 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -229,7 +229,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab /doc/administration/index.md @axil /doc/administration/instance_limits.md @axil /doc/administration/instance_review.md @kpaizee -/doc/administration/integration/kroki.md @kpaizee +/doc/administration/integration/kroki.md @msedlakjakubowski /doc/administration/integration/mailgun.md @kpaizee /doc/administration/integration/plantuml.md @aqualls /doc/administration/integration/terminal.md @kpaizee diff --git a/.rubocop_todo/layout/hash_alignment.yml b/.rubocop_todo/layout/hash_alignment.yml index 32c4ddbced4..2125c032437 100644 --- a/.rubocop_todo/layout/hash_alignment.yml +++ b/.rubocop_todo/layout/hash_alignment.yml @@ -483,7 +483,6 @@ Layout/HashAlignment: - 'lib/backup/gitaly_backup.rb' - 'lib/banzai/filter/references/abstract_reference_filter.rb' - 'lib/banzai/reference_redactor.rb' - - 'lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb' - 'lib/gitlab/abuse.rb' - 'lib/gitlab/access.rb' - 'lib/gitlab/application_rate_limiter.rb' diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index 2461040324f..d3a8e5f70f6 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -3314,7 +3314,6 @@ Layout/LineLength: - 'lib/bulk_imports/common/pipelines/wiki_pipeline.rb' - 'lib/bulk_imports/common/transformers/prohibited_attributes_transformer.rb' - 'lib/bulk_imports/groups/loaders/group_loader.rb' - - 'lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb' - 'lib/bulk_imports/projects/pipelines/project_pipeline.rb' - 'lib/bulk_imports/projects/pipelines/repository_pipeline.rb' - 'lib/bulk_imports/projects/transformers/project_attributes_transformer.rb' @@ -4794,7 +4793,6 @@ Layout/LineLength: - 'spec/lib/bulk_imports/pipeline_spec.rb' - 'spec/lib/bulk_imports/projects/pipelines/external_pull_requests_pipeline_spec.rb' - 'spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb' - - 'spec/lib/bulk_imports/projects/pipelines/project_attributes_pipeline_spec.rb' - 'spec/lib/bulk_imports/projects/pipelines/project_feature_pipeline_spec.rb' - 'spec/lib/bulk_imports/projects/pipelines/project_pipeline_spec.rb' - 'spec/lib/bulk_imports/projects/pipelines/protected_branches_pipeline_spec.rb' diff --git a/.rubocop_todo/rspec/expect_in_hook.yml b/.rubocop_todo/rspec/expect_in_hook.yml index a015db8ae36..09a6f5e6192 100644 --- a/.rubocop_todo/rspec/expect_in_hook.yml +++ b/.rubocop_todo/rspec/expect_in_hook.yml @@ -188,7 +188,6 @@ RSpec/ExpectInHook: - 'spec/lib/backup/manager_spec.rb' - 'spec/lib/banzai/reference_redactor_spec.rb' - 'spec/lib/bulk_imports/ndjson_pipeline_spec.rb' - - 'spec/lib/bulk_imports/projects/pipelines/project_attributes_pipeline_spec.rb' - 'spec/lib/container_registry/gitlab_api_client_spec.rb' - 'spec/lib/file_size_validator_spec.rb' - 'spec/lib/gitlab/alert_management/fingerprint_spec.rb' diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 0304e8020fc..f1af25946ec 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -080f9fb5c6d7e1e5e3c3e2a5202b3f0a83ddd180 +94055b253d05bc04f533c977be892b0cd6f225ea diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index df249f48ebc..e4ce12fcfb6 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -14.6.0 +14.6.1 diff --git a/app/assets/javascripts/admin/application_settings/inactive_project_deletion/components/form.vue b/app/assets/javascripts/admin/application_settings/inactive_project_deletion/components/form.vue new file mode 100644 index 00000000000..ef4a5319eec --- /dev/null +++ b/app/assets/javascripts/admin/application_settings/inactive_project_deletion/components/form.vue @@ -0,0 +1,249 @@ + + diff --git a/app/assets/javascripts/admin/application_settings/inactive_project_deletion/index.js b/app/assets/javascripts/admin/application_settings/inactive_project_deletion/index.js new file mode 100644 index 00000000000..43e6902885c --- /dev/null +++ b/app/assets/javascripts/admin/application_settings/inactive_project_deletion/index.js @@ -0,0 +1,36 @@ +import Vue from 'vue'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import Form from './components/form.vue'; + +export default () => { + const el = document.querySelector('.js-inactive-project-deletion-form'); + + if (!el) { + return false; + } + + const { + deleteInactiveProjects, + inactiveProjectsDeleteAfterMonths, + inactiveProjectsMinSizeMb, + inactiveProjectsSendWarningEmailAfterMonths, + } = el.dataset; + + return new Vue({ + el, + name: 'InactiveProjectDeletion', + render(createElement) { + return createElement(Form, { + props: { + deleteInactiveProjects: parseBoolean(deleteInactiveProjects), + inactiveProjectsDeleteAfterMonths: parseInt(inactiveProjectsDeleteAfterMonths, 10), + inactiveProjectsMinSizeMb: parseInt(inactiveProjectsMinSizeMb, 10), + inactiveProjectsSendWarningEmailAfterMonths: parseInt( + inactiveProjectsSendWarningEmailAfterMonths, + 10, + ), + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue index 3ae69731537..56da8e88b7a 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue @@ -56,6 +56,9 @@ export default { calculatedTimeTilNextRun() { return timeTilRun(this.expirationPolicy?.next_run); }, + expireIconName() { + return this.failedDelete ? 'expire' : 'clock'; + }, }, statusPopoverOptions: { triggers: 'hover', @@ -75,7 +78,7 @@ export default { class="gl-display-inline-flex gl-align-items-center" >
- +
{{ 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