Commit fdc50f26 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch 'cicd-plan-limits-ui' into 'master'

Allow administrators to change plan limits via the UI

See merge request gitlab-org/gitlab!82521
parents 2c1bad6b 8ed789d5
......@@ -38,6 +38,13 @@ class Admin::PlanLimitsController < Admin::ApplicationController
pypi_max_file_size
terraform_module_max_file_size
generic_packages_max_file_size
ci_pipeline_size
ci_active_jobs
ci_project_subscriptions
ci_pipeline_schedules
ci_needs_size_limit
ci_registered_group_runners
ci_registered_project_runners
])
end
end
= form_for @application_setting, url: ci_cd_admin_application_settings_path(anchor: 'js-ci-cd-settings'), html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
.settings-content
= form_for @application_setting, url: ci_cd_admin_application_settings_path(anchor: 'js-ci-cd-settings'), html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.form-check
= f.check_box :auto_devops_enabled, class: 'form-check-input'
= f.label :auto_devops_enabled, class: 'form-check-label' do
= s_('CICD|Default to Auto DevOps pipeline for all projects')
%fieldset
.form-group
.form-check
= f.check_box :auto_devops_enabled, class: 'form-check-input'
= f.label :auto_devops_enabled, class: 'form-check-label' do
= s_('CICD|Default to Auto DevOps pipeline for all projects')
.form-text.text-muted
= s_('CICD|The Auto DevOps pipeline runs by default in all projects with no CI/CD configuration file.')
= link_to _('What is Auto DevOps?'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer'
.form-group
= f.label :auto_devops_domain, s_('AdminSettings|Auto DevOps domain'), class: 'label-bold'
= f.text_field :auto_devops_domain, class: 'form-control gl-form-input', placeholder: 'example.com'
.form-text.text-muted
= s_('CICD|The Auto DevOps pipeline runs by default in all projects with no CI/CD configuration file.')
= link_to _('What is Auto DevOps?'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer'
.form-group
= f.label :auto_devops_domain, s_('AdminSettings|Auto DevOps domain'), class: 'label-bold'
= f.text_field :auto_devops_domain, class: 'form-control gl-form-input', placeholder: 'example.com'
.form-text.text-muted
= s_("AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects.")
= link_to _('Learn more.'), help_page_path('topics/autodevops/stages.md', anchor: 'auto-review-apps'), target: '_blank', rel: 'noopener noreferrer'
= s_("AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects.")
= link_to _('Learn more.'), help_page_path('topics/autodevops/stages.md', anchor: 'auto-review-apps'), target: '_blank', rel: 'noopener noreferrer'
.form-group
.form-check
= f.check_box :shared_runners_enabled, class: 'form-check-input'
= f.label :shared_runners_enabled, class: 'form-check-label' do
= s_("AdminSettings|Enable shared runners for new projects")
.form-text.text-muted
= s_("AdminSettings|All new projects can use the instance's shared runners by default.")
.form-group
.form-check
= f.check_box :shared_runners_enabled, class: 'form-check-input'
= f.label :shared_runners_enabled, class: 'form-check-label' do
= s_("AdminSettings|Enable shared runners for new projects")
.form-text.text-muted
= s_("AdminSettings|All new projects can use the instance's shared runners by default.")
= render_if_exists 'admin/application_settings/shared_runners_minutes_setting', form: f
= render_if_exists 'admin/application_settings/shared_runners_minutes_setting', form: f
.form-group
= f.label :shared_runners_text, _('Shared runners details'), class: 'label-bold'
= f.text_area :shared_runners_text, class: 'form-control gl-form-input', rows: 4
.form-text.text-muted= _("Add a custom message with details about the instance's shared runners. The message is visible in group and project CI/CD settings, in the Runners section. Markdown is supported.")
.form-group
= f.label :max_artifacts_size, _('Maximum artifacts size (MB)'), class: 'label-bold'
= f.number_field :max_artifacts_size, class: 'form-control gl-form-input'
.form-text.text-muted
= _("The maximum file size for job artifacts.")
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size')
.form-group
= f.label :default_artifacts_expire_in, _('Default artifacts expiration'), class: 'label-bold'
= f.text_field :default_artifacts_expire_in, class: 'form-control gl-form-input'
.form-text.text-muted
= html_escape(_("Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration')
.form-group
.form-check
= f.check_box :keep_latest_artifact, class: 'form-check-input'
= f.label :keep_latest_artifact, class: 'form-check-label' do
= s_('AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines')
.form-group
= f.label :shared_runners_text, _('Shared runners details'), class: 'label-bold'
= f.text_area :shared_runners_text, class: 'form-control gl-form-input', rows: 4
.form-text.text-muted= _("Add a custom message with details about the instance's shared runners. The message is visible in group and project CI/CD settings, in the Runners section. Markdown is supported.")
.form-group
= f.label :max_artifacts_size, _('Maximum artifacts size (MB)'), class: 'label-bold'
= f.number_field :max_artifacts_size, class: 'form-control gl-form-input'
.form-text.text-muted
= s_('AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire.')
.form-group
= f.label :archive_builds_in_human_readable, _('Archive jobs'), class: 'label-bold'
= f.text_field :archive_builds_in_human_readable, class: 'form-control gl-form-input'
.form-text.text-muted
= html_escape(_("Jobs older than the configured time are considered expired and are archived. Archived jobs can no longer be retried. Leave empty to never archive jobs automatically. The default unit is in days, but you can use other units, for example %{code_open}15 days%{code_close}, %{code_open}1 month%{code_close}, %{code_open}2 years%{code_close}. Minimum value is 1 day.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'archive-jobs')
.form-group
.form-check
= f.check_box :protected_ci_variables, class: 'form-check-input'
= f.label :protected_ci_variables, class: 'form-check-label' do
= s_('AdminSettings|Protect CI/CD variables by default')
= _("The maximum file size for job artifacts.")
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size')
.form-group
= f.label :default_artifacts_expire_in, _('Default artifacts expiration'), class: 'label-bold'
= f.text_field :default_artifacts_expire_in, class: 'form-control gl-form-input'
.form-text.text-muted
= s_('AdminSettings|New CI/CD variables in projects and groups default to protected.')
.form-group
= f.label :ci_config_path, _('Default CI/CD configuration file'), class: 'label-bold'
= f.text_field :default_ci_config_path, class: 'form-control gl-form-input', placeholder: '.gitlab-ci.yml'
%p.form-text.text-muted
= _("The default CI/CD configuration file and path for new projects.").html_safe
= link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'specify-a-custom-cicd-configuration-file'), target: '_blank', rel: 'noopener noreferrer'
.form-group
.form-check
= f.check_box :suggest_pipeline_enabled, class: 'form-check-input'
= f.label :suggest_pipeline_enabled, class: 'form-check-label' do
= s_('AdminSettings|Enable pipeline suggestion banner')
= html_escape(_("Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration')
.form-group
.form-check
= f.check_box :keep_latest_artifact, class: 'form-check-input'
= f.label :keep_latest_artifact, class: 'form-check-label' do
= s_('AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines')
.form-text.text-muted
= s_('AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire.')
.form-group
= f.label :archive_builds_in_human_readable, _('Archive jobs'), class: 'label-bold'
= f.text_field :archive_builds_in_human_readable, class: 'form-control gl-form-input'
.form-text.text-muted
= s_('AdminSettings|Display a banner on merge requests in projects with no pipelines to initiate steps to add a .gitlab-ci.yml file.')
= html_escape(_("Jobs older than the configured time are considered expired and are archived. Archived jobs can no longer be retried. Leave empty to never archive jobs automatically. The default unit is in days, but you can use other units, for example %{code_open}15 days%{code_close}, %{code_open}1 month%{code_close}, %{code_open}2 years%{code_close}. Minimum value is 1 day.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'archive-jobs')
.form-group
.form-check
= f.check_box :protected_ci_variables, class: 'form-check-input'
= f.label :protected_ci_variables, class: 'form-check-label' do
= s_('AdminSettings|Protect CI/CD variables by default')
.form-text.text-muted
= s_('AdminSettings|New CI/CD variables in projects and groups default to protected.')
.form-group
= f.label :ci_config_path, _('Default CI/CD configuration file'), class: 'label-bold'
= f.text_field :default_ci_config_path, class: 'form-control gl-form-input', placeholder: '.gitlab-ci.yml'
%p.form-text.text-muted
= _("The default CI/CD configuration file and path for new projects.").html_safe
= link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'specify-a-custom-cicd-configuration-file'), target: '_blank', rel: 'noopener noreferrer'
.form-group
.form-check
= f.check_box :suggest_pipeline_enabled, class: 'form-check-input'
= f.label :suggest_pipeline_enabled, class: 'form-check-label' do
= s_('AdminSettings|Enable pipeline suggestion banner')
.form-text.text-muted
= s_('AdminSettings|Display a banner on merge requests in projects with no pipelines to initiate steps to add a .gitlab-ci.yml file.')
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
.settings-content
%h4
= s_('AdminSettings|CI/CD limits')
%p
= s_('AdminSettings|Set limit to 0 to disable it.')
.scrolling-tabs-container.inner-page-scroll-tabs
- if @plans.size > 1
%ul.nav-links.scrolling-tabs.mobile-separator.nav.nav-tabs.gl-mb-5
- @plans.each_with_index do |plan, index|
%li
= link_to admin_plan_limits_path(anchor: 'js-ci-cd-settings'), data: { target: "div#plan#{index}", action: "plan#{index}", toggle: 'tab'}, class: index == 0 ? 'active': '' do
= plan.name.capitalize
.tab-content.gl-tab-content
- @plans.each_with_index do |plan, index|
.tab-pane{ :id => "plan#{index}", class: index == 0 ? 'active': '' }
= form_for plan.actual_limits, url: admin_plan_limits_path(anchor: 'js-ci-cd-settings'), html: { class: 'fieldset-form' }, method: :post do |f|
= form_errors(plan)
%fieldset
= f.hidden_field(:plan_id, value: plan.id)
.form-group
= f.label :ci_pipeline_size, s_('AdminSettings|Maximum number of jobs in a single pipeline')
= f.number_field :ci_pipeline_size, class: 'form-control gl-form-input'
.form-group
= f.label :ci_active_jobs, s_('AdminSettings|Total number of jobs in currently active pipelines')
= f.number_field :ci_active_jobs, class: 'form-control gl-form-input'
.form-group
= f.label :ci_project_subscriptions, s_('AdminSettings|Maximum number of pipeline subscriptions to and from a project')
= f.number_field :ci_project_subscriptions, class: 'form-control gl-form-input'
.form-group
= f.label :ci_pipeline_schedules, s_('AdminSettings|Maximum number of pipeline schedules')
= f.number_field :ci_pipeline_schedules, class: 'form-control gl-form-input'
.form-group
= f.label :ci_needs_size_limit, s_('AdminSettings|Maximum number of DAG dependencies that a job can have')
= f.number_field :ci_needs_size_limit, class: 'form-control gl-form-input'
.form-group
= f.label :ci_registered_group_runners, s_('AdminSettings|Maximum number of runners registered per group')
= f.number_field :ci_registered_group_runners, class: 'form-control gl-form-input'
.form-group
= f.label :ci_registered_project_runners, s_('AdminSettings|Maximum number of runners registered per project')
= f.number_field :ci_registered_project_runners, class: 'form-control gl-form-input'
= f.submit s_('AdminSettings|Save %{name} limits').html_safe % { name: plan.name.capitalize }, class: 'btn gl-button btn-confirm'
......@@ -20,8 +20,7 @@
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Customize CI/CD settings, including Auto DevOps, shared runners, and job artifacts.')
.settings-content
= render 'ci_cd'
= render 'ci_cd'
= render_if_exists 'admin/application_settings/required_instance_ci_setting', expanded: expanded_by_default?
......
......@@ -2609,6 +2609,9 @@ msgstr ""
msgid "AdminSettings|Auto DevOps domain"
msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
......@@ -2648,6 +2651,24 @@ msgstr ""
msgid "AdminSettings|Maximum duration of a session for Git operations when 2FA is enabled."
msgstr ""
msgid "AdminSettings|Maximum number of DAG dependencies that a job can have"
msgstr ""
msgid "AdminSettings|Maximum number of jobs in a single pipeline"
msgstr ""
msgid "AdminSettings|Maximum number of pipeline schedules"
msgstr ""
msgid "AdminSettings|Maximum number of pipeline subscriptions to and from a project"
msgstr ""
msgid "AdminSettings|Maximum number of runners registered per group"
msgstr ""
msgid "AdminSettings|Maximum number of runners registered per project"
msgstr ""
msgid "AdminSettings|New CI/CD variables in projects and groups default to protected."
msgstr ""
......@@ -2663,6 +2684,9 @@ msgstr ""
msgid "AdminSettings|Required pipeline configuration"
msgstr ""
msgid "AdminSettings|Save %{name} limits"
msgstr ""
msgid "AdminSettings|Select a CI/CD template"
msgstr ""
......@@ -2678,6 +2702,9 @@ msgstr ""
msgid "AdminSettings|Set a CI/CD template as the required pipeline configuration for all projects in the instance. Project CI/CD configuration merges into the required pipeline configuration when the pipeline runs. %{link_start}What is a required pipeline configuration?%{link_end}"
msgstr ""
msgid "AdminSettings|Set limit to 0 to disable it."
msgstr ""
msgid "AdminSettings|Set the initial name and protections for the default branch of new repositories created in the instance."
msgstr ""
......@@ -2699,6 +2726,9 @@ msgstr ""
msgid "AdminSettings|The template for the required pipeline configuration can be one of the GitLab-provided templates, or a custom template added to an instance template repository. %{link_start}How do I create an instance template repository?%{link_end}"
msgstr ""
msgid "AdminSettings|Total number of jobs in currently active pipelines"
msgstr ""
msgid "AdminStatistics|Active Users"
msgstr ""
......
......@@ -311,7 +311,9 @@ RSpec.describe 'Admin updates settings' do
end
context 'CI/CD page' do
it 'change CI/CD settings' do
let_it_be(:default_plan) { create(:default_plan) }
it 'changes CI/CD settings' do
visit ci_cd_admin_application_settings_path
page.within('.as-ci-cd') do
......@@ -329,6 +331,31 @@ RSpec.describe 'Admin updates settings' do
expect(page).to have_content "Application settings saved successfully"
end
it 'changes CI/CD limits', :aggregate_failures do
visit ci_cd_admin_application_settings_path
page.within('.as-ci-cd') do
fill_in 'plan_limits_ci_pipeline_size', with: 10
fill_in 'plan_limits_ci_active_jobs', with: 20
fill_in 'plan_limits_ci_project_subscriptions', with: 30
fill_in 'plan_limits_ci_pipeline_schedules', with: 40
fill_in 'plan_limits_ci_needs_size_limit', with: 50
fill_in 'plan_limits_ci_registered_group_runners', with: 60
fill_in 'plan_limits_ci_registered_project_runners', with: 70
click_button 'Save Default limits'
end
limits = default_plan.reload.limits
expect(limits.ci_pipeline_size).to eq(10)
expect(limits.ci_active_jobs).to eq(20)
expect(limits.ci_project_subscriptions).to eq(30)
expect(limits.ci_pipeline_schedules).to eq(40)
expect(limits.ci_needs_size_limit).to eq(50)
expect(limits.ci_registered_group_runners).to eq(60)
expect(limits.ci_registered_project_runners).to eq(70)
expect(page).to have_content 'Application limits saved successfully'
end
context 'Runner Registration' do
context 'when feature is enabled' do
before do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'admin/application_settings/_ci_cd' do
let_it_be(:admin) { create(:admin) }
let_it_be(:application_setting) { build(:application_setting) }
let_it_be(:limits_attributes) do
{
ci_pipeline_size: 10,
ci_active_jobs: 20,
ci_project_subscriptions: 30,
ci_pipeline_schedules: 40,
ci_needs_size_limit: 50,
ci_registered_group_runners: 60,
ci_registered_project_runners: 70
}
end
let_it_be(:default_plan_limits) { create(:plan_limits, :default_plan, **limits_attributes) }
let(:page) { Capybara::Node::Simple.new(rendered) }
before do
assign(:application_setting, application_setting)
allow(view).to receive(:current_user) { admin }
allow(view).to receive(:expanded) { true }
end
subject { render partial: 'admin/application_settings/ci_cd' }
context 'limits' do
before do
assign(:plans, [default_plan_limits.plan])
end
it 'has fields for CI/CD limits', :aggregate_failures do
subject
expect(rendered).to have_field('Maximum number of jobs in a single pipeline', type: 'number')
expect(page.find_field('Maximum number of jobs in a single pipeline').value).to eq('10')
expect(rendered).to have_field('Total number of jobs in currently active pipelines', type: 'number')
expect(page.find_field('Total number of jobs in currently active pipelines').value).to eq('20')
expect(rendered).to have_field('Maximum number of pipeline subscriptions to and from a project', type: 'number')
expect(page.find_field('Maximum number of pipeline subscriptions to and from a project').value).to eq('30')
expect(rendered).to have_field('Maximum number of pipeline schedules', type: 'number')
expect(page.find_field('Maximum number of pipeline schedules').value).to eq('40')
expect(rendered).to have_field('Maximum number of DAG dependencies that a job can have', type: 'number')
expect(page.find_field('Maximum number of DAG dependencies that a job can have').value).to eq('50')
expect(rendered).to have_field('Maximum number of runners registered per group', type: 'number')
expect(page.find_field('Maximum number of runners registered per group').value).to eq('60')
expect(rendered).to have_field('Maximum number of runners registered per project', type: 'number')
expect(page.find_field('Maximum number of runners registered per project').value).to eq('70')
end
it 'does not display the plan name when there is only one plan' do
subject
expect(page).not_to have_selector('a[data-action="plan0"]')
end
end
context 'with multiple plans' do
let_it_be(:plan) { create(:plan, name: 'Ultimate') }
let_it_be(:ultimate_plan_limits) { create(:plan_limits, plan: plan, **limits_attributes) }
before do
assign(:plans, [default_plan_limits.plan, ultimate_plan_limits.plan])
end
it 'displays the plan name when there is more than one plan' do
subject
expect(page).to have_content('Default')
expect(page).to have_content('Ultimate')
expect(page).to have_selector('a[data-action="plan0"]')
expect(page).to have_selector('a[data-action="plan1"]')
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment