From d2d30cff552e08c4b7ec2b5e23acced8eb29cbcb Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 14 Feb 2017 18:00:37 +0800 Subject: [PATCH 01/23] Initial implementation for default artifacts expiration TODO: Add tests and screenshots --- .../admin/application_settings_controller.rb | 1 + app/models/application_setting.rb | 19 ++++++++++++-- app/models/ci/build.rb | 11 ++++++++ .../application_settings/_form.html.haml | 9 ++++++- ...acts_expiration_to_application_settings.rb | 11 ++++++++ .../settings/continuous_integration.md | 26 ++++++++++++++++--- lib/api/settings.rb | 7 +++-- lib/ci/api/builds.rb | 2 +- spec/models/ci/build_spec.rb | 2 +- 9 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index b0f5d4a9933..0559b5fa1bd 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -83,6 +83,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :akismet_api_key, :akismet_enabled, :container_registry_token_expire_delay, + :default_artifacts_expiration, :default_branch_protection, :default_group_visibility, :default_project_visibility, diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 74b358d8c40..a871dc9e5b9 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -76,6 +76,14 @@ class ApplicationSetting < ActiveRecord::Base presence: true, numericality: { only_integer: true, greater_than: 0 } + validates :max_artifacts_size, + presence: true, + numericality: { only_integer: true, greater_than: 0 } + + validates :default_artifacts_expiration, + presence: true, + numericality: { only_integer: true, greater_than_or_equal_to: 0 } + validates :container_registry_token_expire_delay, presence: true, numericality: { only_integer: true, greater_than: 0 } @@ -168,6 +176,7 @@ class ApplicationSetting < ActiveRecord::Base after_sign_up_text: nil, akismet_enabled: false, container_registry_token_expire_delay: 5, + default_artifacts_expiration: 30, default_branch_protection: Settings.gitlab['default_branch_protection'], default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], default_projects_limit: Settings.gitlab['default_projects_limit'], @@ -201,9 +210,9 @@ class ApplicationSetting < ActiveRecord::Base sign_in_text: nil, signin_enabled: Settings.gitlab['signin_enabled'], signup_enabled: Settings.gitlab['signup_enabled'], + terminal_max_session_time: 0, two_factor_grace_period: 48, - user_default_external: false, - terminal_max_session_time: 0 + user_default_external: false } end @@ -282,6 +291,12 @@ class ApplicationSetting < ActiveRecord::Base sidekiq_throttling_enabled end + def default_artifacts_expire_in + if default_artifacts_expiration.nonzero? + "#{default_artifacts_expiration} days" + end + end + private def check_repository_storages diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 8c1b076c2d7..77f027d17b6 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -513,6 +513,17 @@ module Ci end end + def set_artifacts_expire_in(expire_in) + value = + if expire_in + expire_in + else + ApplicationSetting.current.default_artifacts_expire_in + end + + self.artifacts_expire_in = value + end + def has_expiring_artifacts? artifacts_expire_at.present? end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 816035ec442..86ce534ea18 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -212,8 +212,15 @@ .col-sm-10 = f.number_field :max_artifacts_size, class: 'form-control' .help-block - Set the maximum file size each jobs's artifacts can have + Set the maximum file size for each job's artifacts = link_to "(?)", help_page_path("user/admin_area/settings/continuous_integration", anchor: "maximum-artifacts-size") + .form-group + = f.label :default_artifacts_expiration, 'Default artifacts expiration (days)', class: 'control-label col-sm-2' + .col-sm-10 + = f.number_field :default_artifacts_expiration, class: 'form-control' + .help-block + Set the default expiration time for each job's artifacts (0 as never expired) + = link_to "(?)", help_page_path("user/admin_area/settings/continuous_integration", anchor: "default-artifacts-expiration") - if Gitlab.config.registry.enabled %fieldset diff --git a/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb b/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb new file mode 100644 index 00000000000..728d581251c --- /dev/null +++ b/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb @@ -0,0 +1,11 @@ +class AddDefaultArtifactsExpirationToApplicationSettings < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + add_column :application_settings, + :default_artifacts_expiration, + :integer, default: 0, null: false + end +end diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md index 34e2e557f89..0455881ebf2 100644 --- a/doc/user/admin_area/settings/continuous_integration.md +++ b/doc/user/admin_area/settings/continuous_integration.md @@ -2,19 +2,37 @@ ## Maximum artifacts size -The maximum size of the [build artifacts][art-yml] can be set in the Admin area -of your GitLab instance. The value is in MB and the default is 100MB. Note that -this setting is set for each build. +The maximum size of the [build artifacts][art-yml] can be set in the Admin +area of your GitLab instance. The value is in *MB* and the default is 100MB. +Note that this setting is set for each job. 1. Go to **Admin area > Settings** (`/admin/application_settings`). ![Admin area settings button](img/admin_area_settings_button.png) -1. Change the value of the maximum artifacts size (in MB): +1. Change the value of maximum artifacts size (in MB): ![Admin area maximum artifacts size](img/admin_area_maximum_artifacts_size.png) 1. Hit **Save** for the changes to take effect. +[art-yml]: ../../../administration/build_artifacts.md + +## Default artifacts expiration time + +The default expiration time of the [build artifacts][art-yml] can be set in +the Admin area of your GitLab instance. The value is in *days* and the +default is 30 days. Note that this setting is set for each job. Set it to +0 as never expired by default. + +1. Go to **Admin area > Settings** (`/admin/application_settings`). + + ![Admin area settings button](img/admin_area_settings_button.png) + +1. Change the value of default expiration time (in days): + + ![Admin area default artifacts expiration](img/admin_area_default_artifacts_expiration.png) + +1. Hit **Save** for the changes to take effect. [art-yml]: ../../../administration/build_artifacts.md diff --git a/lib/api/settings.rb b/lib/api/settings.rb index 747ceb4e3e0..dabe6281755 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -56,7 +56,8 @@ module API given shared_runners_enabled: ->(val) { val } do requires :shared_runners_text, type: String, desc: 'Shared runners text ' end - optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size each build's artifacts can have" + optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts" + optional :default_artifacts_expiration, type: Integer, desc: "Set the default expiration time for each job's artifacts" optional :max_pages_size, type: Integer, desc: 'Maximum size of pages in MB' optional :container_registry_token_expire_delay, type: Integer, desc: 'Authorization token duration (minutes)' optional :metrics_enabled, type: Boolean, desc: 'Enable the InfluxDB metrics' @@ -117,7 +118,9 @@ module API :send_user_confirmation_email, :domain_whitelist, :domain_blacklist_enabled, :after_sign_up_text, :signin_enabled, :require_two_factor_authentication, :home_page_url, :after_sign_out_path, :sign_in_text, :help_page_text, - :shared_runners_enabled, :max_artifacts_size, :max_pages_size, :container_registry_token_expire_delay, + :shared_runners_enabled, :max_artifacts_size, + :default_artifacts_expiration, :max_pages_size, + :container_registry_token_expire_delay, :metrics_enabled, :sidekiq_throttling_enabled, :recaptcha_enabled, :akismet_enabled, :admin_notification_email, :sentry_enabled, :repository_storage, :repository_checks_enabled, :koding_enabled, :plantuml_enabled, diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index 8b939663ffd..7aad6c50b7b 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -167,7 +167,7 @@ module Ci build.artifacts_file = artifacts build.artifacts_metadata = metadata - build.artifacts_expire_in = params['expire_in'] + build.set_artifacts_expire_in(params['expire_in']) if build.save present(build, with: Entities::BuildDetails) diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 4080092405d..1e88dc9d468 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -161,7 +161,7 @@ describe Ci::Build, :models do is_expected.to be_nil end - it 'when resseting value' do + it 'when resetting value' do build.artifacts_expire_in = nil is_expected.to be_nil From 696a5da7fd78093567ae2bc7a795a38462dd7b3d Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 14 Feb 2017 19:17:36 +0800 Subject: [PATCH 02/23] ApplicationSetting.current doesn't work well in tests Therefore we prefer `Gitlab::CurrentSettings.current_application_settings` and fix the tests by setting default_artifacts_expire_in to 0 to restore the original behaviour. --- app/models/ci/build.rb | 3 ++- spec/requests/ci/api/builds_spec.rb | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 77f027d17b6..d14f025aeaa 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -518,7 +518,8 @@ module Ci if expire_in expire_in else - ApplicationSetting.current.default_artifacts_expire_in + Gitlab::CurrentSettings.current_application_settings + .default_artifacts_expire_in end self.artifacts_expire_in = value diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index d85afdeab42..44f69bff30d 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -638,6 +638,8 @@ describe Ci::API::Builds do end before do + stub_application_setting(default_artifacts_expiration: 0) + post(post_url, post_data, headers_with_token) end From 3e158beca4f9e7e7887d7301e1ea97bef7eade84 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 14 Feb 2017 19:24:57 +0800 Subject: [PATCH 03/23] Add changelog entry --- .../unreleased/27762-add-default-artifacts-expiration.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/27762-add-default-artifacts-expiration.yml diff --git a/changelogs/unreleased/27762-add-default-artifacts-expiration.yml b/changelogs/unreleased/27762-add-default-artifacts-expiration.yml new file mode 100644 index 00000000000..27fa77ed04d --- /dev/null +++ b/changelogs/unreleased/27762-add-default-artifacts-expiration.yml @@ -0,0 +1,4 @@ +--- +title: Add admin setting for default artifacts expiration +merge_request: 9219 +author: From ac872078486145f43e8a42dbd60ed47be70a301f Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 14 Feb 2017 19:34:07 +0800 Subject: [PATCH 04/23] Test build API if expire_in not set, set to app default --- spec/requests/ci/api/builds_spec.rb | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 44f69bff30d..0f2c6f2dc69 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -630,6 +630,7 @@ describe Ci::API::Builds do context 'with an expire date' do let!(:artifacts) { file_upload } + let(:default_artifacts_expiration) { 0 } let(:post_data) do { 'file.path' => artifacts.path, @@ -638,7 +639,8 @@ describe Ci::API::Builds do end before do - stub_application_setting(default_artifacts_expiration: 0) + stub_application_setting( + default_artifacts_expiration: default_artifacts_expiration) post(post_url, post_data, headers_with_token) end @@ -650,7 +652,8 @@ describe Ci::API::Builds do build.reload expect(response).to have_http_status(201) expect(json_response['artifacts_expire_at']).not_to be_empty - expect(build.artifacts_expire_at).to be_within(5.minutes).of(Time.now + 7.days) + expect(build.artifacts_expire_at). + to be_within(5.minutes).of(7.days.from_now) end end @@ -663,6 +666,18 @@ describe Ci::API::Builds do expect(json_response['artifacts_expire_at']).to be_nil expect(build.artifacts_expire_at).to be_nil end + + context 'with application default' do + let(:default_artifacts_expiration) { 5 } + + it 'sets to application default' do + build.reload + expect(response).to have_http_status(201) + expect(json_response['artifacts_expire_at']).not_to be_empty + expect(build.artifacts_expire_at). + to be_within(5.minutes).of(5.days.from_now) + end + end end end From 53c94f9ea25c9d6a25b58a01db5f855f0719dbf4 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 14 Feb 2017 22:54:46 +0800 Subject: [PATCH 05/23] Use the same syntax for default expiration Feedback: * https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_23343951 * https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_23344036 * https://gitlab.com/gitlab-org/gitlab-ce/issues/27762#note_23344797 --- .../admin/application_settings_controller.rb | 2 +- app/models/application_setting.rb | 20 +++++++++---------- app/models/ci/build.rb | 12 ----------- .../application_settings/_form.html.haml | 10 +++++----- ...acts_expiration_to_application_settings.rb | 4 ++-- lib/api/settings.rb | 4 ++-- lib/ci/api/builds.rb | 5 ++++- spec/requests/ci/api/builds_spec.rb | 6 +++--- 8 files changed, 27 insertions(+), 36 deletions(-) diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 0559b5fa1bd..d807e6263ee 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -83,7 +83,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :akismet_api_key, :akismet_enabled, :container_registry_token_expire_delay, - :default_artifacts_expiration, + :default_artifacts_expire_in, :default_branch_protection, :default_group_visibility, :default_project_visibility, diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index a871dc9e5b9..2b97027c018 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -80,9 +80,7 @@ class ApplicationSetting < ActiveRecord::Base presence: true, numericality: { only_integer: true, greater_than: 0 } - validates :default_artifacts_expiration, - presence: true, - numericality: { only_integer: true, greater_than_or_equal_to: 0 } + validate :check_default_artifacts_expire_in validates :container_registry_token_expire_delay, presence: true, @@ -176,7 +174,7 @@ class ApplicationSetting < ActiveRecord::Base after_sign_up_text: nil, akismet_enabled: false, container_registry_token_expire_delay: 5, - default_artifacts_expiration: 30, + default_artifacts_expire_in: '30 days', default_branch_protection: Settings.gitlab['default_branch_protection'], default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], default_projects_limit: Settings.gitlab['default_projects_limit'], @@ -291,12 +289,6 @@ class ApplicationSetting < ActiveRecord::Base sidekiq_throttling_enabled end - def default_artifacts_expire_in - if default_artifacts_expiration.nonzero? - "#{default_artifacts_expiration} days" - end - end - private def check_repository_storages @@ -304,4 +296,12 @@ class ApplicationSetting < ActiveRecord::Base errors.add(:repository_storages, "can't include: #{invalid.join(", ")}") unless invalid.empty? end + + def check_default_artifacts_expire_in + ChronicDuration.parse(default_artifacts_expire_in) + true + rescue ChronicDuration::DurationParseError => e + errors.add(:default_artifacts_expire_in, ": #{e.message}") + false + end end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index d14f025aeaa..8c1b076c2d7 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -513,18 +513,6 @@ module Ci end end - def set_artifacts_expire_in(expire_in) - value = - if expire_in - expire_in - else - Gitlab::CurrentSettings.current_application_settings - .default_artifacts_expire_in - end - - self.artifacts_expire_in = value - end - def has_expiring_artifacts? artifacts_expire_at.present? end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 86ce534ea18..f96ddc38af1 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -213,14 +213,14 @@ = f.number_field :max_artifacts_size, class: 'form-control' .help-block Set the maximum file size for each job's artifacts - = link_to "(?)", help_page_path("user/admin_area/settings/continuous_integration", anchor: "maximum-artifacts-size") + = link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size') .form-group - = f.label :default_artifacts_expiration, 'Default artifacts expiration (days)', class: 'control-label col-sm-2' + = f.label :default_artifacts_expire_in, 'Default artifacts expiration', class: 'control-label col-sm-2' .col-sm-10 - = f.number_field :default_artifacts_expiration, class: 'form-control' + = f.text_field :default_artifacts_expire_in, class: 'form-control' .help-block - Set the default expiration time for each job's artifacts (0 as never expired) - = link_to "(?)", help_page_path("user/admin_area/settings/continuous_integration", anchor: "default-artifacts-expiration") + Set the default expiration time for each job's artifacts + = link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration') - if Gitlab.config.registry.enabled %fieldset diff --git a/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb b/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb index 728d581251c..34905570739 100644 --- a/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb +++ b/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb @@ -5,7 +5,7 @@ class AddDefaultArtifactsExpirationToApplicationSettings < ActiveRecord::Migrati def change add_column :application_settings, - :default_artifacts_expiration, - :integer, default: 0, null: false + :default_artifacts_expire_in, + :string, null: true end end diff --git a/lib/api/settings.rb b/lib/api/settings.rb index dabe6281755..f46e7e0bcf1 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -57,7 +57,7 @@ module API requires :shared_runners_text, type: String, desc: 'Shared runners text ' end optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts" - optional :default_artifacts_expiration, type: Integer, desc: "Set the default expiration time for each job's artifacts" + optional :default_artifacts_expire_in, type: Integer, desc: "Set the default expiration time for each job's artifacts" optional :max_pages_size, type: Integer, desc: 'Maximum size of pages in MB' optional :container_registry_token_expire_delay, type: Integer, desc: 'Authorization token duration (minutes)' optional :metrics_enabled, type: Boolean, desc: 'Enable the InfluxDB metrics' @@ -119,7 +119,7 @@ module API :after_sign_up_text, :signin_enabled, :require_two_factor_authentication, :home_page_url, :after_sign_out_path, :sign_in_text, :help_page_text, :shared_runners_enabled, :max_artifacts_size, - :default_artifacts_expiration, :max_pages_size, + :default_artifacts_expire_in, :max_pages_size, :container_registry_token_expire_delay, :metrics_enabled, :sidekiq_throttling_enabled, :recaptcha_enabled, :akismet_enabled, :admin_notification_email, :sentry_enabled, diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index 7aad6c50b7b..2018191c4bd 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -167,7 +167,10 @@ module Ci build.artifacts_file = artifacts build.artifacts_metadata = metadata - build.set_artifacts_expire_in(params['expire_in']) + build.artifacts_expire_in = + params['expire_in'] || + Gitlab::CurrentSettings.current_application_settings + .default_artifacts_expire_in if build.save present(build, with: Entities::BuildDetails) diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 0f2c6f2dc69..f2385da8c13 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -630,7 +630,7 @@ describe Ci::API::Builds do context 'with an expire date' do let!(:artifacts) { file_upload } - let(:default_artifacts_expiration) { 0 } + let(:default_artifacts_expire_in) {} let(:post_data) do { 'file.path' => artifacts.path, @@ -640,7 +640,7 @@ describe Ci::API::Builds do before do stub_application_setting( - default_artifacts_expiration: default_artifacts_expiration) + default_artifacts_expire_in: default_artifacts_expire_in) post(post_url, post_data, headers_with_token) end @@ -668,7 +668,7 @@ describe Ci::API::Builds do end context 'with application default' do - let(:default_artifacts_expiration) { 5 } + let(:default_artifacts_expire_in) { '5 days' } it 'sets to application default' do build.reload From a1b06a82eac888024dc0d4c77f7c93f6053a3815 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 14 Feb 2017 23:44:05 +0800 Subject: [PATCH 06/23] rubocop: Align the operands of an expression C: Style/MultilineOperationIndentation: Align the operands of an expression in an assignment spanning multiple lines. --- lib/ci/api/builds.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index 2018191c4bd..0e17ac24d5a 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -169,8 +169,8 @@ module Ci build.artifacts_metadata = metadata build.artifacts_expire_in = params['expire_in'] || - Gitlab::CurrentSettings.current_application_settings - .default_artifacts_expire_in + Gitlab::CurrentSettings.current_application_settings + .default_artifacts_expire_in if build.save present(build, with: Entities::BuildDetails) From 4eff5eb89fc6eec5692f4119b2fc3c9622d1b3e3 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 14 Feb 2017 23:47:23 +0800 Subject: [PATCH 07/23] Check default_artifacts_expire_in only if existed --- app/models/application_setting.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 2b97027c018..818223dcc86 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -298,7 +298,8 @@ class ApplicationSetting < ActiveRecord::Base end def check_default_artifacts_expire_in - ChronicDuration.parse(default_artifacts_expire_in) + ChronicDuration.parse(default_artifacts_expire_in) if + default_artifacts_expire_in true rescue ChronicDuration::DurationParseError => e errors.add(:default_artifacts_expire_in, ": #{e.message}") From 602f3b84c08c06cd132a8c53c7bcbb3a139cebfd Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 15 Feb 2017 00:19:36 +0800 Subject: [PATCH 08/23] Add a few more tests and make sure empty value sets to nil --- app/models/application_setting.rb | 8 ++++++++ spec/models/application_setting_spec.rb | 22 ++++++++++++++++++++++ spec/requests/api/settings_spec.rb | 11 +++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 818223dcc86..17193036fb6 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -269,6 +269,14 @@ class ApplicationSetting < ActiveRecord::Base self.repository_storages = [value] end + def default_artifacts_expire_in=(value) + if value.present? + super(value.strip) + else + super(nil) + end + end + # Choose one of the available repository storage options. Currently all have # equal weighting. def pick_repository_storage diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index b950fcdd81a..15632bac094 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -29,6 +29,28 @@ describe ApplicationSetting, models: true do it { is_expected.not_to allow_value(['test']).for(:disabled_oauth_sign_in_sources) } end + describe 'default_artifacts_expire_in' do + it 'sets an error if it is invalid' do + setting.update(default_artifacts_expire_in: 'a') + + expect(setting).to be_invalid + end + + it 'sets the value if it is valid' do + setting.update(default_artifacts_expire_in: '30 days') + + expect(setting).to be_valid + expect(setting.default_artifacts_expire_in).to eq('30 days') + end + + it 'does not set it if it is blank' do + setting.update(default_artifacts_expire_in: ' ') + + expect(setting).to be_valid + expect(setting.default_artifacts_expire_in).to be_nil + end + end + it { is_expected.to validate_presence_of(:max_attachment_size) } it do diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 91e3c333a02..411905edb49 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -30,8 +30,14 @@ describe API::Settings, 'Settings', api: true do it "updates application settings" do put api("/application/settings", admin), - default_projects_limit: 3, signin_enabled: false, repository_storage: 'custom', koding_enabled: true, koding_url: 'http://koding.example.com', - plantuml_enabled: true, plantuml_url: 'http://plantuml.example.com' + default_projects_limit: 3, + signin_enabled: false, + repository_storage: 'custom', + koding_enabled: true, + koding_url: 'http://koding.example.com', + plantuml_enabled: true, + plantuml_url: 'http://plantuml.example.com', + default_artifacts_expire_in: '2 days' expect(response).to have_http_status(200) expect(json_response['default_projects_limit']).to eq(3) expect(json_response['signin_enabled']).to be_falsey @@ -41,6 +47,7 @@ describe API::Settings, 'Settings', api: true do expect(json_response['koding_url']).to eq('http://koding.example.com') expect(json_response['plantuml_enabled']).to be_truthy expect(json_response['plantuml_url']).to eq('http://plantuml.example.com') + expect(json_response['default_artifacts_expire_in']).to eq('2 days') end end From cfd839d6f5092be2f5224eddc155f6cf05cd1be6 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 15 Feb 2017 15:31:25 +0800 Subject: [PATCH 09/23] Fix tests and disallow 0 to make it consistent with .gitlab-ci.yml --- app/models/application_setting.rb | 12 +++++++++--- lib/api/entities.rb | 1 + lib/api/settings.rb | 2 +- spec/models/application_setting_spec.rb | 6 ++++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 17193036fb6..19af40eacb4 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -306,9 +306,15 @@ class ApplicationSetting < ActiveRecord::Base end def check_default_artifacts_expire_in - ChronicDuration.parse(default_artifacts_expire_in) if - default_artifacts_expire_in - true + return true unless default_artifacts_expire_in + + if ChronicDuration.parse(default_artifacts_expire_in).nil? + errors.add(:default_artifacts_expire_in, + "can't be 0. Leave it blank for unlimited") + false + else + true + end rescue ChronicDuration::DurationParseError => e errors.add(:default_artifacts_expire_in, ": #{e.message}") false diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 2a071e649fa..fb0584539db 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -559,6 +559,7 @@ module API expose :default_project_visibility expose :default_snippet_visibility expose :default_group_visibility + expose :default_artifacts_expire_in expose :domain_whitelist expose :domain_blacklist_enabled expose :domain_blacklist diff --git a/lib/api/settings.rb b/lib/api/settings.rb index f46e7e0bcf1..936c7e0930b 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -57,7 +57,7 @@ module API requires :shared_runners_text, type: String, desc: 'Shared runners text ' end optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts" - optional :default_artifacts_expire_in, type: Integer, desc: "Set the default expiration time for each job's artifacts" + optional :default_artifacts_expire_in, type: String, desc: "Set the default expiration time for each job's artifacts" optional :max_pages_size, type: Integer, desc: 'Maximum size of pages in MB' optional :container_registry_token_expire_delay, type: Integer, desc: 'Authorization token duration (minutes)' optional :metrics_enabled, type: Boolean, desc: 'Enable the InfluxDB metrics' diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 15632bac094..9629f858609 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -36,6 +36,12 @@ describe ApplicationSetting, models: true do expect(setting).to be_invalid end + it 'does not allow 0' do + setting.update(default_artifacts_expire_in: '0') + + expect(setting).to be_invalid + end + it 'sets the value if it is valid' do setting.update(default_artifacts_expire_in: '30 days') From b72f00c7cfdc854640cbb118c741a116ae4fd8ba Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 15 Feb 2017 16:03:58 +0800 Subject: [PATCH 10/23] Update docs to reflect current behaviour --- app/models/application_setting.rb | 2 +- app/views/admin/application_settings/_form.html.haml | 4 +++- .../admin_area/settings/continuous_integration.md | 11 ++++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 19af40eacb4..6d5f02a1011 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -310,7 +310,7 @@ class ApplicationSetting < ActiveRecord::Base if ChronicDuration.parse(default_artifacts_expire_in).nil? errors.add(:default_artifacts_expire_in, - "can't be 0. Leave it blank for unlimited") + "can't be 0. Leave it blank for no expiration") false else true diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index f96ddc38af1..3004f32f1f2 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -220,7 +220,9 @@ = f.text_field :default_artifacts_expire_in, class: 'form-control' .help-block Set the default expiration time for each job's artifacts - = link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration') + = surround '(', ')' do + = link_to 'syntax', help_page_path('ci/yaml/README', anchor: 'artifactsexpire_in') + = link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration-time') - if Gitlab.config.registry.enabled %fieldset diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md index 0455881ebf2..295e0adec45 100644 --- a/doc/user/admin_area/settings/continuous_integration.md +++ b/doc/user/admin_area/settings/continuous_integration.md @@ -16,14 +16,14 @@ Note that this setting is set for each job. 1. Hit **Save** for the changes to take effect. -[art-yml]: ../../../administration/build_artifacts.md +[art-yml]: ../../../administration/build_artifacts ## Default artifacts expiration time The default expiration time of the [build artifacts][art-yml] can be set in -the Admin area of your GitLab instance. The value is in *days* and the -default is 30 days. Note that this setting is set for each job. Set it to -0 as never expired by default. +the Admin area of your GitLab instance. The syntax of duration is described +in [artifacts:expire_in][duration-syntax]. The default is `30 days`. Note that +this setting is set for each job. Leave it blank for no default expiration. 1. Go to **Admin area > Settings** (`/admin/application_settings`). @@ -35,4 +35,5 @@ default is 30 days. Note that this setting is set for each job. Set it to 1. Hit **Save** for the changes to take effect. -[art-yml]: ../../../administration/build_artifacts.md +[art-yml]: ../../../administration/build_artifacts +[duration-syntax]: ../../../ci/yaml/README#artifactsexpire_in From 3acf4fbe3b6e96ac4bc438e24030fde076832b51 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 16 Feb 2017 11:00:35 +0000 Subject: [PATCH 11/23] Update schema --- db/schema.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/db/schema.rb b/db/schema.rb index 52672406ec6..b11792d14f5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -111,6 +111,7 @@ ActiveRecord::Schema.define(version: 20170214111112) do t.boolean "plantuml_enabled" t.integer "max_pages_size", default: 100, null: false t.integer "terminal_max_session_time", default: 0, null: false + t.string "default_artifacts_expire_in", limit: 255 end create_table "audit_events", force: :cascade do |t| From 46082f4b652cac097c72354b394881a128fd3a5f Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 16 Feb 2017 19:27:37 +0800 Subject: [PATCH 12/23] Use static error message and don't give booleans in validation. Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_23437431 https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_23437868 --- app/models/application_setting.rb | 13 ++++--------- spec/models/application_setting_spec.rb | 4 ++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 6d5f02a1011..e865da0ce7a 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -306,17 +306,12 @@ class ApplicationSetting < ActiveRecord::Base end def check_default_artifacts_expire_in - return true unless default_artifacts_expire_in - - if ChronicDuration.parse(default_artifacts_expire_in).nil? - errors.add(:default_artifacts_expire_in, + if default_artifacts_expire_in && + ChronicDuration.parse(default_artifacts_expire_in).nil? + errors.add(:default_artifacts_expiration, "can't be 0. Leave it blank for no expiration") - false - else - true end rescue ChronicDuration::DurationParseError => e - errors.add(:default_artifacts_expire_in, ": #{e.message}") - false + errors.add(:default_artifacts_expiration, "is invalid") end end diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 9629f858609..719eda9b5b3 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -34,12 +34,16 @@ describe ApplicationSetting, models: true do setting.update(default_artifacts_expire_in: 'a') expect(setting).to be_invalid + expect(setting.errors.messages) + .to have_key(:default_artifacts_expiration) end it 'does not allow 0' do setting.update(default_artifacts_expire_in: '0') expect(setting).to be_invalid + expect(setting.errors.messages) + .to have_key(:default_artifacts_expiration) end it 'sets the value if it is valid' do From 36afa43e4da5c7e5804880401f2ef52c1119ba7c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 16 Feb 2017 19:33:30 +0800 Subject: [PATCH 13/23] Use squish to also compact the string Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_23436980 --- app/models/application_setting.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index e865da0ce7a..3a2f69fde97 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -271,7 +271,7 @@ class ApplicationSetting < ActiveRecord::Base def default_artifacts_expire_in=(value) if value.present? - super(value.strip) + super(value.squish) else super(nil) end From 9096647ff66029e188562ff36331342220ab1c1b Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 16 Feb 2017 19:34:50 +0800 Subject: [PATCH 14/23] Wordings change, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_23437712 --- doc/user/admin_area/settings/continuous_integration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md index 81247786173..d7b598b7506 100644 --- a/doc/user/admin_area/settings/continuous_integration.md +++ b/doc/user/admin_area/settings/continuous_integration.md @@ -23,7 +23,8 @@ that this setting is set for each job. The default expiration time of the [build artifacts][art-yml] can be set in the Admin area of your GitLab instance. The syntax of duration is described in [artifacts:expire_in][duration-syntax]. The default is `30 days`. Note that -this setting is set for each job. Leave it blank for no default expiration. +this setting is set for each job. Leave it blank if you don't want to set +default expiration time. 1. Go to **Admin area > Settings** (`/admin/application_settings`). From 37cc3aaefb65e775bd3baa93dd7dec218a76a23c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 16 Feb 2017 22:29:29 +0800 Subject: [PATCH 15/23] The exception was no longer used --- app/models/application_setting.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 3a2f69fde97..d64a847d487 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -311,7 +311,7 @@ class ApplicationSetting < ActiveRecord::Base errors.add(:default_artifacts_expiration, "can't be 0. Leave it blank for no expiration") end - rescue ChronicDuration::DurationParseError => e + rescue ChronicDuration::DurationParseError errors.add(:default_artifacts_expiration, "is invalid") end end From eede4ab1a2509ef4aa14d21527386224c4116adc Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 16 Feb 2017 23:40:13 +0800 Subject: [PATCH 16/23] 0 for unlimited, disallow blank, feedback: https://gitlab.com/gitlab-org/gitlab-ce/issues/27762#note_23520780 --- app/models/application_setting.rb | 16 +++--------- app/models/ci/build.rb | 2 +- .../application_settings/_form.html.haml | 5 ++-- ...acts_expiration_to_application_settings.rb | 4 +-- db/schema.rb | 4 +-- .../settings/continuous_integration.md | 8 +++--- spec/models/application_setting_spec.rb | 26 ++++++++++--------- spec/models/ci/build_spec.rb | 6 +++++ 8 files changed, 36 insertions(+), 35 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index d64a847d487..36832185b6f 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -269,14 +269,6 @@ class ApplicationSetting < ActiveRecord::Base self.repository_storages = [value] end - def default_artifacts_expire_in=(value) - if value.present? - super(value.squish) - else - super(nil) - end - end - # Choose one of the available repository storage options. Currently all have # equal weighting. def pick_repository_storage @@ -306,10 +298,10 @@ class ApplicationSetting < ActiveRecord::Base end def check_default_artifacts_expire_in - if default_artifacts_expire_in && - ChronicDuration.parse(default_artifacts_expire_in).nil? - errors.add(:default_artifacts_expiration, - "can't be 0. Leave it blank for no expiration") + if default_artifacts_expire_in.blank? + errors.add(:default_artifacts_expiration, "is not presented") + else + ChronicDuration.parse(default_artifacts_expire_in) end rescue ChronicDuration::DurationParseError errors.add(:default_artifacts_expiration, "is invalid") diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 8c1b076c2d7..60655bf2ea7 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -509,7 +509,7 @@ module Ci def artifacts_expire_in=(value) self.artifacts_expire_at = if value - Time.now + ChronicDuration.parse(value) + ChronicDuration.parse(value)&.seconds&.from_now end end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 3004f32f1f2..12b12fd248b 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -219,10 +219,11 @@ .col-sm-10 = f.text_field :default_artifacts_expire_in, class: 'form-control' .help-block - Set the default expiration time for each job's artifacts + Set the default expiration time for each job's artifacts. + 0 for unlimited. = surround '(', ')' do = link_to 'syntax', help_page_path('ci/yaml/README', anchor: 'artifactsexpire_in') - = link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration-time') + = link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration') - if Gitlab.config.registry.enabled %fieldset diff --git a/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb b/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb index 34905570739..e0e3ff8957a 100644 --- a/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb +++ b/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb @@ -5,7 +5,7 @@ class AddDefaultArtifactsExpirationToApplicationSettings < ActiveRecord::Migrati def change add_column :application_settings, - :default_artifacts_expire_in, - :string, null: true + :default_artifacts_expire_in, :string, + null: false, default: '0' end end diff --git a/db/schema.rb b/db/schema.rb index b11792d14f5..29ba7167bfa 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -111,7 +111,7 @@ ActiveRecord::Schema.define(version: 20170214111112) do t.boolean "plantuml_enabled" t.integer "max_pages_size", default: 100, null: false t.integer "terminal_max_session_time", default: 0, null: false - t.string "default_artifacts_expire_in", limit: 255 + t.string "default_artifacts_expire_in", default: '0', null: false end create_table "audit_events", force: :cascade do |t| @@ -1352,4 +1352,4 @@ ActiveRecord::Schema.define(version: 20170214111112) do add_foreign_key "timelogs", "merge_requests", name: "fk_timelogs_merge_requests_merge_request_id", on_delete: :cascade add_foreign_key "trending_projects", "projects", on_delete: :cascade add_foreign_key "u2f_registrations", "users" -end \ No newline at end of file +end diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md index d7b598b7506..0fd165fc095 100644 --- a/doc/user/admin_area/settings/continuous_integration.md +++ b/doc/user/admin_area/settings/continuous_integration.md @@ -18,13 +18,13 @@ that this setting is set for each job. [art-yml]: ../../../administration/build_artifacts -## Default artifacts expiration time +## Default artifacts expiration -The default expiration time of the [build artifacts][art-yml] can be set in +The default expiration time of the [job artifacts][art-yml] can be set in the Admin area of your GitLab instance. The syntax of duration is described in [artifacts:expire_in][duration-syntax]. The default is `30 days`. Note that -this setting is set for each job. Leave it blank if you don't want to set -default expiration time. +this setting is set for each job. Set it to 0 if you don't want default +expiration. 1. Go to **Admin area > Settings** (`/admin/application_settings`). diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 719eda9b5b3..f8c38ed8569 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -30,20 +30,16 @@ describe ApplicationSetting, models: true do end describe 'default_artifacts_expire_in' do - it 'sets an error if it is invalid' do + it 'sets an error if it cannot parse' do setting.update(default_artifacts_expire_in: 'a') - expect(setting).to be_invalid - expect(setting.errors.messages) - .to have_key(:default_artifacts_expiration) + expect_invalid end - it 'does not allow 0' do - setting.update(default_artifacts_expire_in: '0') + it 'sets an error if it is blank' do + setting.update(default_artifacts_expire_in: ' ') - expect(setting).to be_invalid - expect(setting.errors.messages) - .to have_key(:default_artifacts_expiration) + expect_invalid end it 'sets the value if it is valid' do @@ -53,11 +49,17 @@ describe ApplicationSetting, models: true do expect(setting.default_artifacts_expire_in).to eq('30 days') end - it 'does not set it if it is blank' do - setting.update(default_artifacts_expire_in: ' ') + it 'sets the value if it is 0' do + setting.update(default_artifacts_expire_in: '0') expect(setting).to be_valid - expect(setting.default_artifacts_expire_in).to be_nil + expect(setting.default_artifacts_expire_in).to eq('0') + end + + def expect_invalid + expect(setting).to be_invalid + expect(setting.errors.messages) + .to have_key(:default_artifacts_expiration) end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 1e88dc9d468..a4edabfbc5b 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -166,6 +166,12 @@ describe Ci::Build, :models do is_expected.to be_nil end + + it 'when setting to 0' do + build.artifacts_expire_in = '0' + + is_expected.to be_nil + end end describe '#commit' do From 962f9efeb470afd0627f509621de4ff87124d656 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 21 Feb 2017 02:25:35 +0800 Subject: [PATCH 17/23] Update error message and check with presence: true Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_23762243 https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_23762268 --- app/models/application_setting.rb | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 36832185b6f..b5ffc5f9ca9 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -80,6 +80,7 @@ class ApplicationSetting < ActiveRecord::Base presence: true, numericality: { only_integer: true, greater_than: 0 } + validates :default_artifacts_expire_in, presence: true validate :check_default_artifacts_expire_in validates :container_registry_token_expire_delay, @@ -222,6 +223,14 @@ class ApplicationSetting < ActiveRecord::Base create(defaults) end + def self.human_attribute_name(attr, _options = {}) + if attr == :default_artifacts_expire_in + 'Default artifacts expiration' + else + super + end + end + def home_page_url_column_exist ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url) end @@ -298,12 +307,8 @@ class ApplicationSetting < ActiveRecord::Base end def check_default_artifacts_expire_in - if default_artifacts_expire_in.blank? - errors.add(:default_artifacts_expiration, "is not presented") - else - ChronicDuration.parse(default_artifacts_expire_in) - end + ChronicDuration.parse(default_artifacts_expire_in) rescue ChronicDuration::DurationParseError - errors.add(:default_artifacts_expiration, "is invalid") + errors.add(:default_artifacts_expiration, "is not a correct duration") end end From ad44252424280857e3735a5e931413f4e99e9d5f Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 21 Feb 2017 02:28:21 +0800 Subject: [PATCH 18/23] Add screenshot for default artifacts expiration, and update screenshot for maximum artifacts size. --- ...dmin_area_default_artifacts_expiration.png | Bin 0 -> 16484 bytes .../img/admin_area_maximum_artifacts_size.png | Bin 3447 -> 12917 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.png diff --git a/doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.png b/doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.png new file mode 100644 index 0000000000000000000000000000000000000000..c6425ad32cd991ff361a9d40c4147d237e37ec82 GIT binary patch literal 16484 zcmcJ$b980P)(0AOY@3}h)f~bh#PY@8Wi;sIrXvmNM4hxwF5D?fh69EAkQ2_yB z8Cxqu6LSL)5RstRI4F5J6U_eh`zbu?Ofi^Nr^6|;uRiw3v5_+TF!acL=7I3x9m+B& zKMeQ+iZ%*nDnYW8u_5r3q4beu`Z|3I3P!-=Dym%_?@!)Slb<xaMD!e*lqlyQCi+*P#E)*0p7>M{d=DQ4utDjx=H%=+^Y~UM z&hX9#y{e6V)sg(ds5lTZUPasjN8uMguyW&R+5fKiGfUe90i$QY#tq4{XPDSkF*Wjp zT;FoWbe(*!0_zHkO=<(Brl$mb|AO3*QKKbJITCrNp-1BFsx?I(uz`9V{pxqy7*yQq zcbkpFA1-BspuB}0j;9yIxD6%{#}3f2;5m*QvB)}ggv2fr@)5Gwj@xV182 z*etj2lMB^7GUZ7C!RZ!dsGaYx#};`C9ZAisb=&u#vo4^Rs@KJu{0_L<7BDY=-IjoN z^9=-R1GXh91kuL}rUIm|104vGK64QIXobs0am{kcUTITkFT67&IE|wo=S{fUGq3>W z^~l)p5WJ2+lR_;5+m0_D0;Y{|Nf~cjxV(~)WD}lZ6Y=ZF+LnN z(4tNgYfL6zxD0T0@OnO?1|&jX5;|B-?{62NBmBs}e7_=N{Pv3>b`Zg0@TMZ+9Kg8p zf61i#iW=0@55> ztt-3&3m>}NS8p@S`b!G;w7=gi}ZT#`6X83v3zy6di`#?Uj8Db!1n`PT6^PS)8C5kOQ;7%LyA?ttya z2Xi-+HcU?#Pbgmhbn-xy8JIZ;EwJQ@po)0w-xGiaNo?{F)ZU;ZK{Z`s`m_dLWr-3B zO>!QRHnJ!Y%Fo}Ya8UzdgebqHl4wvMMDs+E4{+!k*+QuBtqGKo)<+ZlUYGrfjt~q^ zp7L94QJ^qWJ(DZj4Lvg$JCIIrfpl3&Oejh4EU*QWJg_K)Be)D}6rCECo5DrS{%0t0 z9?2e6ANukaManr!7Gf4^DGXN3dkkq*TI6z!b`l;M@92q0>sW2^9g&pC22y%{Az6jO zF?mb}irde(lnycexh7NCH9%FKQ>M~*7V>W-jXxQb83d~2ud;R`(Z$3Bf=Ob()+!y9 z%zzh;Pr*)wPfboW=N{*ti;NGHMA}3K#SKQAL^jf1tHjY9QzjEPYt^aT72>N(30sD# zH?7z-7TZRDH~wy}SfRL6%GSIU#YI(4c23)_^7hLu;-$tX%cmJkdNZ&K!%tM`n-Ekl zu-7*@9-ShlK+I7LKi5|*K2~#z{4o4R(1pG=geRA({3Me~hDPa3Ax&XY9_HtuqKS-i zk(hj~e3&eE!BQbdZeGq_cAZeE)M*sQkJX>tQm+**^-rPxd4Rw^nlQsK8%Z2Vf5SY( z)IBun;JDT~Kq+jg>yomC_$kDx-jX{c-Bjg6jlEQV7|FBvVBD;-yTH_5h&)|NA4Y!kCnxG9P*2AC_DC)VxO2{_s} zi!>9R`k%y}Cf;G(jT6WdEFi`r>V+?bUxw%7YjNVRU#8-w8m5${)^pT1XQ;1eT&cTg zkgNNui>s$M7B=)Y%{EFlCO29+THSX5fzBuQ*xFy|ltXd*V)Fg=6~}34tCYNyg68e4 z2&~$il95if5A8bk2TgBhS7t}sI^s87JMIh9^VR|FT65a-52fEUuDjM3JVQL4K$x`! z_$)dC`0_hiy(4^Ud?0?Lc4l>=bTW4`lF*R&kqBh^XQ~NU`3?Hnbg6dPY<6zOZcdwN z%oD0|;_6^V;azH{?lpxvu+9yaN~?R?_#Qy+`P)S$3`7nr4bVzx8Gf?k2u5*WG7a7x z;TUo0b<`%(mlj+GU;!d}7y8iqLi?Bc2m@0Ct0TS#C-1P?iLqI2ac>Q88KJtN6`}5- z3ZUZsz7UNPEmeoH1grn9LeEatn4Uj8yo+E_vj#NYMqdxnN(9R-5jPRdCFz!m;1j<{ z)n*%|DP=m;+9nG2Ojt&%&UY$*T-$!Gcy4$mJgHyT()g;G zpu%R`vClXCCRO{%bwmmg)bQ$XG9?pbu#~oRPAbrb;X(giI*xZ%en??Y$)j{j z5kcWu$!S)3W@ct+{;bsZ7{UQ9pH%8L)scPmXStTv8u4tTCu9mriu0r0&N$MTOX?|? zk#pHw%hO|a*i2u`mjV;HX?Z*KYZ-B6anE8SGoxflwQX9+c6kk%HW?S$tF1Nh9&z^g zJsKm;G|T;3X~!PNPT5MgZbR;{_N3RP1+%qf`{gZ1@pJ_(wfCYoai^1W`xS>q*HgmnwbJL}^Lt)s7dkd% zdOD^7LVVAJhl|nd8sX}Q>NM@N9c~O))f0`NY{{ppg2GlX5@|EWyC@Y2X(1`GBPBgkB+tq7z(7YfM`MO?HMNT@3kqC zj`DzIymoJy^U%`kzc~#sR59G2!MMP_DR_bckw0-DXhLU$fPki$$Sd0`OGk6Q}^dmUn+g}J322auceKP@;u?*A0ik`n)?iM<&&sj{RD zv4EAW0WmWT6Ac|H4=gb;F_*2rA;(Wa!2ifUp14Vk?d`2OXlb3CoM@aFX{>CGXzAJ6 z*=gw*Xc-u&KUz@RIa}K60I4nQ$o|XZFFt|>c6zoZ*7hb=mc)Pf>gZZI*mIMT{t@)| z^@XNc*5!u^oNx{*0zDSimf7A#3SVMG4@XHI4p6-}!Z@%NLe% zZsQDyQ992jPn%)gyre9XO7P_qx&a^>_-Q=Bx}wU5o>GB;HN^s;(?pe1wEgQfD^@;C zB`>Ja=KFUv#1cA(+IQD=*PU%v6Y+5JRHFnpxAQjF@yFE&r?b|5O^w<#fNfnudCxS^7`m*C`1diT zI=%o67GQs#bX(fz`r`cTn%g& z;o*TvRZXq>eR+BE$T4%6HwY-n(nFc|ytH|IulE~r$z`Eo&=@%Y(T@SJGo%aMdDwe9 zJ}@gJQI#FZT&#$au0BFvvo-Bu|M*1D#O?`0fS-Ku$z z<$c)j?V9q7`zmxc-1If21bQbA7UHclef!U1)iDY8!dp=o+P}x8Iy*!W-Ny2!`I2`N z0cV9?02)m>(j;;iyu|cC1uaAj!?Wkud1? z_4LKP!=cgBOJ~aD{9^`DC%#kg=P%FCC{mbRAyQA9vwg0Sm-olAZ(TAiRjBg>ku*aG zM@Q3Scg2bw7`R6Wbm|t*R8;7V<)| zznvI)y)(&FiD7h9i5&oIG)PqU2w6%cmCd`&um3CE5K6kzy0IjD6*g>= z_^BzOtvKYQsv5iZdRSsUybyw{G;pk3RPfM+A!k?y%U~!kO7G_w|T)9M1Qo-iyyqr7h(5z{f6Qa?16;=XM7NazU3Dtwe5FAzXG1aaX6% zwx1N)>g<{y-%1c4v6rJn*ZyvxY0CK2fz@t^CV|75Vog2kp=`$vSD0lw(f2Y-sZ*#8 zb@+^sJ_+@JoK8CKutR(&*rznR99M%`29go4m!(O;?0k(^OMWv~&Lqc#xyYs%_TLxv zE}OhHK4-Gwb53%Kya?iEInj`tpM`nd?fq0TQ8;pTRwjQr63~ZDC^jKgl4XbYZhX$W z)%D_Fx@=;|E5KiBEu9dh=r%SGrl{agKNAR;Xw{2KO>p!LfHk{JTJ!G6l-=f;#@UTD zEo9mcP&MHb`o^gd09MMjbD!zJRHXae_A~vFX@1#B3>~lkk~ayF15&TUg5nTGeku zKpi8k{_Y^al$W#J(e!MVSuNPCoF{iDjbUf5=}evT>WKYWz|71@^Q(3w?K0eBRT^*W z-BEGA`DKclYjBm?ld&de`cTwvE;v#dH&A~Jm?xNoL^#~1(lH*ll-LL!^VnG{w+OGo z>2RW>>B`hSym7y=Gy~Vqbg!3B)hd15vgEu$uI7=Z!pZ;W#Pjr9YWD_xo8j6cjJ~MF z{bHb)1t#!xrr3;q@%czjVt9IR8%MOoG;*$lgn>Hdcy9%hgqZlx#5HWb6@7sdWb&+8b|Vr|zdO z21%v&P@A3HFfTr*I=8dSH{T_fCVu?(xA#lFdz;a=foq4h7wt!Xe^G|tmWiYR<=~eZ z4{+X6oy@Lrc&P!HmCANBeZdl5Jw)Th*(-2Cy#%WBI#&`E&ka}%LLY5xL0`K8lPuZ3 zi+tG*48TbMPhGST4Yywc2sp@NY%A!^ISXr`sgDW$%5TJuBD)=AbC1XA5u-@lL26eb zPi0>^Oq;NLrTm>2?Tyv=9QJ+1kE9&Sl7_~SRfS#^33t61;BT#zqTMIWUB;NhO=c#i z1mazR_x488qzyHhn(tIU9~-6g!<4{w(x`i2d}St7Yqhk+iZjK2RYfN$+B7E(mezDZ zGLh~3ZhU6}b3jyaZSuE@mWyfaeNyo3p2D2e6bG4mrP&Bc2PPX9!A7Q1+x$f0mz$9D z^prm1dhzDcP8LkfFxB3n_~qrXmk=XD+GJk!2xM(*PvfZFuCRxf&*|GIfaptLs@(1^ z@=6(&XLN?j!dtPw8dpI1b!(_(%IGq{+(4RVyFzJ`r(Aj4lCmhx4BRU3d zkJR5y-4=ThtZG$hjEX(V1vu^zAQrA#E6=}@%o%kviv?|%pXMjee%6>sIgx)l?3*cb z8XH8B{S+hc_jYXo8B8IxW0~r++%I5Y-v%j^<=WwxpJFEE{Gr#POp?F|Y^K8O5QhbBp;#na%13Cf~ zHy*xSF!dADOOdX$m?}mrifrZFGcM-z#J-oJkhYgN`^KzNYvtKO4&tNtNS8F%$!Qzz zLADe_{6;ONuBK*2vI|NU0|-_2s;U78*qf;HJ+KK;+`H-0kP0gh#!;bKo_Y*i^#=UB z-MvxCtQp#;d?=ta^{){_s~DxCeB~HfrXDsb-CWdliTUjVC+A6y(OLwSkY*{oWm)d& zif+;FG|IwLrBzMF{KnE8Pn3hYQJ#fbnlYLY;xEmVS4IKJWXIZz3HIB_>F}!E=UiGE zqE%D{h)GYp5DIas&HfLp$W4<;)C}<70{-3F={CYjWLm-h7u#1vAqhT(U0xx@z?O$b$K^bajToz3^V|`T*H0Cv~_Y!bp zQpY^>=_7TbLjAS7XalFA-3;n96Jy}Fw`fa?^WPv~V^jXo&a**~x} zJFe+8iw#jTv9|d{>)((aD$cFnVz)LKhiBDlb zw8@)lidpPbS(jS7masHNt4ZP;U}aOV7iAYSRTFj-_o&)ItYpEqy?8ix#fT?Gi*sV= zS3rZfOyDiwYbR5$*kKS)^|ivjPdi?MqCsFa&Ueu>&7M!)C0+-X)N#-1p(RJzgHo~O zU!5uradlJXWQE?m4v&63WRk=&()_B$+0$`cQCoF~Hgj%JLlNGN0Cxk0PTjRT(Coiw~H#mVZ`d=zSX{a%kI}y=Df0I31_4&^h;V4N;KP-E+wGrUdD1=+D+l? z^D9$KiojRlyhFzlQiX#Ip~7cQq?) zbR@3Ma0m;*jHU8->&u$S&&!)bT-f2HiyggYq~%Vk4y+}%l6<9lo!uHN{8o!yt?q#l zhtm5MuYasoIAYWQOAK?ERznjG%WcnVaf67NR@b0WVRxx)zgxOhyO>jKW92Fb6MQ_C zM@unUj`r)CVhhy3y9naDdY#Z!KxH~_ZrWnw-As!6A*)qN_DJ1T>D9fTtzTtHj;-9^ zJ}-#vP&o3wJwX;xPfq1a@w}aev-&!pYgldO(75CId|Gew@taS>*XRjN^lid#_iz;~ z#?MsJ30?gBoEpY1?H|Bq*VRtJ=gFEJFy8n1OC>DmU(u8TT0`AYB&u~X@2ex_$vYM-&9KN zpK!nSTB+vW;lA#la9E%CI1QcIX#7% zhb16jHaW|~ezvA!zCSbmS+GH-~;85to{oOAg^8deEe`JA7`hphzrQ>q+hmOmP>q2IK zb?u*OZ%MI_l!RoG4QbuqtM7+C9e1BUQWAF~PLryC53-M(ly)@ghijt^Qv#{~*7-xj z3hqCy<-XRa!36t<%!QmkuKlC7)*-}C2g&kzIq54I? zyyCZQE3X<=u72AB$f^?zp7F)yK`&uvzvts)4oBb){UAl}IOEn6nYoZ){({bJk){(Ayv8mjpp!E2 zhc9^K9{KTK=#Vom2~|3#Y-^=s14HAdhh?dHz6yMynYF>`?g}t`r6$7^CrcGk9L-5^ ztegOzg@i*cp@M&5xe$s=H>7M7B#6-g9zM!T^mmz=;1gkYJP1O=iBq1A+I%Ku3qJYcn2x_#mt{O{&1C(;bA4Fm7@=xpO7sQTiyYCx`)@+ z=L#fV-tXAZbo@P>Sc;dSq~N277$b)Wca?p0eTOVM$2*%Sl^k0^+$Xo|gRgNVRAv!i`>qxw8+;MEg^_rx!)OXJC4p zGh*Q^(v7D>Sy`d$EcWHR;Z!Wz$6%fF?qK)=#>nRj_15n)Ikl0|If%0D4Z`mY1B^Hm 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 literal 0 HcmV?d00001 diff --git a/doc/user/admin_area/settings/img/admin_area_maximum_artifacts_size.png b/doc/user/admin_area/settings/img/admin_area_maximum_artifacts_size.png index b7d6671902ad980d5eb7497626fffa08d3fe68e0..33fd29e2039a20adb0f2e49b3c7313fe4b957e87 100644 GIT binary patch literal 12917 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 MEG<;=UDyBr09N;4;s5{u literal 3447 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 V0?ErWe;z6!{YTIAN_1^M{Ra#8fHeRB From 0d0842a42203edd3f9ff341f538c9cf3e92ad957 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 21 Feb 2017 02:36:11 +0800 Subject: [PATCH 19/23] Update doc according to the new syntax --- doc/user/admin_area/settings/continuous_integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md index 0fd165fc095..64df7ee48bd 100644 --- a/doc/user/admin_area/settings/continuous_integration.md +++ b/doc/user/admin_area/settings/continuous_integration.md @@ -30,7 +30,7 @@ expiration. ![Admin area settings button](img/admin_area_settings_button.png) -1. Change the value of default expiration time (in days): +1. Change the value of default expiration time ([syntax][duration-syntax]): ![Admin area default artifacts expiration](img/admin_area_default_artifacts_expiration.png) From 2b0426a4971480c6d9868ac6865d3827485fe8d1 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 21 Feb 2017 18:46:52 +0800 Subject: [PATCH 20/23] Fix tests due to error key changed --- app/models/application_setting.rb | 2 +- spec/models/application_setting_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index b5ffc5f9ca9..1349587fb0a 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -309,6 +309,6 @@ class ApplicationSetting < ActiveRecord::Base def check_default_artifacts_expire_in ChronicDuration.parse(default_artifacts_expire_in) rescue ChronicDuration::DurationParseError - errors.add(:default_artifacts_expiration, "is not a correct duration") + errors.add(:default_artifacts_expire_in, "is not a correct duration") end end diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index f8c38ed8569..b3eb206612e 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -59,7 +59,7 @@ describe ApplicationSetting, models: true do def expect_invalid expect(setting).to be_invalid expect(setting.errors.messages) - .to have_key(:default_artifacts_expiration) + .to have_key(:default_artifacts_expire_in) end end From 91965cefebfa6b2199b9b48e79752bf62cd67305 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 22 Feb 2017 23:48:49 +0800 Subject: [PATCH 21/23] Remove syntax help link and update screenshot Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_23943262 --- .../application_settings/_form.html.haml | 2 -- ...dmin_area_default_artifacts_expiration.png | Bin 16484 -> 14656 bytes 2 files changed, 2 deletions(-) diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 0287533ab23..057b584e1bc 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -221,8 +221,6 @@ .help-block Set the default expiration time for each job's artifacts. 0 for unlimited. - = surround '(', ')' do - = link_to 'syntax', help_page_path('ci/yaml/README', anchor: 'artifactsexpire_in') = link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration') - if Gitlab.config.registry.enabled diff --git a/doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.png b/doc/user/admin_area/settings/img/admin_area_default_artifacts_expiration.png index c6425ad32cd991ff361a9d40c4147d237e37ec82..50a86ede56ba0a2ca1268bdd1e748c84f51e8c7a 100644 GIT binary patch delta 11606 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 delta 13448 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 OKVrhtLL~xPUjGN Date: Fri, 24 Feb 2017 17:15:25 +0800 Subject: [PATCH 22/23] Test against default to '0', it should not set --- spec/requests/ci/api/builds_spec.rb | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index c7284be09b7..9948d1a9ea0 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -668,14 +668,28 @@ describe Ci::API::Builds do end context 'with application default' do - let(:default_artifacts_expire_in) { '5 days' } + context 'default to 5 days' do + let(:default_artifacts_expire_in) { '5 days' } - it 'sets to application default' do - build.reload - expect(response).to have_http_status(201) - expect(json_response['artifacts_expire_at']).not_to be_empty - expect(build.artifacts_expire_at). - to be_within(5.minutes).of(5.days.from_now) + it 'sets to application default' do + build.reload + expect(response).to have_http_status(201) + expect(json_response['artifacts_expire_at']) + .not_to be_empty + expect(build.artifacts_expire_at) + .to be_within(5.minutes).of(5.days.from_now) + end + end + + context 'default to 0' do + let(:default_artifacts_expire_in) { '0' } + + it 'does not set expire_in' do + build.reload + expect(response).to have_http_status(201) + expect(json_response['artifacts_expire_at']).to be_nil + expect(build.artifacts_expire_at).to be_nil + end end end end From 728b0a5fe073f1f2f088f9d2c6ce9a4a050e1fcf Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 24 Feb 2017 17:28:24 +0800 Subject: [PATCH 23/23] Introduce DurationValidator, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9219#note_24032923 --- app/models/application_setting.rb | 9 +-------- app/validators/duration_validator.rb | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 app/validators/duration_validator.rb diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 99759ec4cae..dc36c754438 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -80,8 +80,7 @@ class ApplicationSetting < ActiveRecord::Base presence: true, numericality: { only_integer: true, greater_than: 0 } - validates :default_artifacts_expire_in, presence: true - validate :check_default_artifacts_expire_in + validates :default_artifacts_expire_in, presence: true, duration: true validates :container_registry_token_expire_delay, presence: true, @@ -305,10 +304,4 @@ class ApplicationSetting < ActiveRecord::Base errors.add(:repository_storages, "can't include: #{invalid.join(", ")}") unless invalid.empty? end - - def check_default_artifacts_expire_in - ChronicDuration.parse(default_artifacts_expire_in) - rescue ChronicDuration::DurationParseError - errors.add(:default_artifacts_expire_in, "is not a correct duration") - end end diff --git a/app/validators/duration_validator.rb b/app/validators/duration_validator.rb new file mode 100644 index 00000000000..10ff44031c6 --- /dev/null +++ b/app/validators/duration_validator.rb @@ -0,0 +1,17 @@ +# DurationValidator +# +# Validate the format conforms with ChronicDuration +# +# Example: +# +# class ApplicationSetting < ActiveRecord::Base +# validates :default_artifacts_expire_in, presence: true, duration: true +# end +# +class DurationValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + ChronicDuration.parse(value) + rescue ChronicDuration::DurationParseError + record.errors.add(attribute, "is not a correct duration") + end +end