diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-09 18:08:16 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-09 18:08:16 +0000 |
commit | 4da595a071829d1046f921e402f3978eeca15d93 (patch) | |
tree | f792687f66b20dacfd5f48cae4ba42961bddddd7 /app | |
parent | c87924a358cab4283e48f7c3ffd27b07320b9f62 (diff) | |
download | gitlab-ce-4da595a071829d1046f921e402f3978eeca15d93.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
24 files changed, 234 insertions, 99 deletions
diff --git a/app/assets/javascripts/access_tokens/components/expires_at_field.vue b/app/assets/javascripts/access_tokens/components/expires_at_field.vue index 1fec186f2fa..561b2617c5f 100644 --- a/app/assets/javascripts/access_tokens/components/expires_at_field.vue +++ b/app/assets/javascripts/access_tokens/components/expires_at_field.vue @@ -1,15 +1,31 @@ <script> -import { GlDatepicker, GlFormInput } from '@gitlab/ui'; +import { GlDatepicker, GlFormInput, GlFormGroup } from '@gitlab/ui'; + +import { __ } from '~/locale'; export default { name: 'ExpiresAtField', - components: { GlDatepicker, GlFormInput }, + i18n: { + label: __('Expiration date'), + }, + components: { + GlDatepicker, + GlFormInput, + GlFormGroup, + MaxExpirationDateMessage: () => + import('ee_component/access_tokens/components/max_expiration_date_message.vue'), + }, props: { inputAttrs: { type: Object, required: false, default: () => ({}), }, + maxDate: { + type: Date, + required: false, + default: () => null, + }, }, data() { return { @@ -20,13 +36,18 @@ export default { </script> <template> - <gl-datepicker :target="null" :min-date="minDate"> - <gl-form-input - v-bind="inputAttrs" - class="datepicker gl-datepicker-input" - autocomplete="off" - inputmode="none" - data-qa-selector="expiry_date_field" - /> - </gl-datepicker> + <gl-form-group :label="$options.i18n.label" :label-for="inputAttrs.id"> + <gl-datepicker :target="null" :min-date="minDate" :max-date="maxDate"> + <gl-form-input + v-bind="inputAttrs" + class="datepicker gl-datepicker-input" + autocomplete="off" + inputmode="none" + data-qa-selector="expiry_date_field" + /> + </gl-datepicker> + <template #description> + <max-expiration-date-message :max-date="maxDate" /> + </template> + </gl-form-group> </template> diff --git a/app/assets/javascripts/access_tokens/index.js b/app/assets/javascripts/access_tokens/index.js index 9a1e7d877f8..c59bd445539 100644 --- a/app/assets/javascripts/access_tokens/index.js +++ b/app/assets/javascripts/access_tokens/index.js @@ -17,6 +17,7 @@ export const initExpiresAtField = () => { } const { expiresAt: inputAttrs } = parseRailsFormFields(el); + const { maxDate } = el.dataset; return new Vue({ el, @@ -24,6 +25,7 @@ export const initExpiresAtField = () => { return h(ExpiresAtField, { props: { inputAttrs, + maxDate: maxDate ? new Date(maxDate) : undefined, }, }); }, diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue index 29c181f04fb..ab0418388cd 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue @@ -4,6 +4,7 @@ import { sprintf, n__, s__ } from '~/locale'; import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue'; import TitleArea from '~/vue_shared/components/registry/title_area.vue'; import timeagoMixin from '~/vue_shared/mixins/timeago'; +import { numberToHumanSize } from '~/lib/utils/number_utils'; import { UPDATED_AT, CLEANUP_UNSCHEDULED_TEXT, @@ -23,7 +24,7 @@ import { ROOT_IMAGE_TOOLTIP, } from '../../constants/index'; -import getContainerRepositoryTagsCountQuery from '../../graphql/queries/get_container_repository_tags_count.query.graphql'; +import getContainerRepositoryMetadata from '../../graphql/queries/get_container_repository_metadata.query.graphql'; export default { name: 'DetailsHeader', @@ -50,7 +51,7 @@ export default { }, apollo: { containerRepository: { - query: getContainerRepositoryTagsCountQuery, + query: getContainerRepositoryMetadata, variables() { return { id: this.image.id, @@ -101,6 +102,10 @@ export default { imageName() { return this.imageDetails.name || ROOT_IMAGE_TEXT; }, + formattedSize() { + const { size } = this.imageDetails; + return size ? numberToHumanSize(Number(size)) : null; + }, }, }; </script> @@ -119,10 +124,15 @@ export default { :aria-label="rootImageTooltip" /> </template> + <template #metadata-tags-count> <metadata-item icon="tag" :text="tagCountText" data-testid="tags-count" /> </template> + <template v-if="formattedSize" #metadata-size> + <metadata-item icon="disk" :text="formattedSize" data-testid="image-size" /> + </template> + <template #metadata-cleanup> <metadata-item icon="expire" diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags_count.query.graphql b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_metadata.query.graphql index 9092a71edb0..f1f67b98407 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags_count.query.graphql +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_metadata.query.graphql @@ -1,6 +1,7 @@ -query getContainerRepositoryTagsCount($id: ID!) { +query getContainerRepositoryMetadata($id: ID!) { containerRepository(id: $id) { id tagsCount + size } } diff --git a/app/assets/javascripts/security_configuration/components/training_provider_list.vue b/app/assets/javascripts/security_configuration/components/training_provider_list.vue index 5bccd91e55e..4b40e5a1e1d 100644 --- a/app/assets/javascripts/security_configuration/components/training_provider_list.vue +++ b/app/assets/javascripts/security_configuration/components/training_provider_list.vue @@ -27,6 +27,17 @@ const i18n = { primaryTraining: s__('SecurityTraining|Primary Training'), }; +// Fetch the svg path from the GraphQL query once this issue is resolved +// https://gitlab.com/gitlab-org/gitlab/-/issues/346899 +const TEMP_PROVIDER_LOGOS = { + 'gid://gitlab/Security::TrainingProvider/1': { + svg: '/assets/illustrations/vulnerability/kontra-logo.svg', + }, + 'gid://gitlab/Security::TrainingProvider/2': { + svg: '/assets/illustrations/vulnerability/scw-logo.svg', + }, +}; + export default { components: { GlAlert, @@ -187,6 +198,7 @@ export default { }, }, i18n, + TEMP_PROVIDER_LOGOS, }; </script> @@ -215,7 +227,10 @@ export default { label-position="hidden" @change="toggleProvider(provider)" /> - <div class="gl-ml-5"> + <div v-if="$options.TEMP_PROVIDER_LOGOS[provider.id]" class="gl-ml-4"> + <img :src="$options.TEMP_PROVIDER_LOGOS[provider.id].svg" width="18" /> + </div> + <div class="gl-ml-3"> <h3 class="gl-font-lg gl-m-0 gl-mb-2">{{ provider.name }}</h3> <p> {{ provider.description }} diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue index 157068b2c0f..389f2ca8ac2 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue @@ -78,7 +78,7 @@ export default { return { searchKey: '', recentSuggestions: this.config.recentSuggestionsStorageKey - ? getRecentlyUsedSuggestions(this.config.recentSuggestionsStorageKey) + ? getRecentlyUsedSuggestions(this.config.recentSuggestionsStorageKey) ?? [] : [], }; }, diff --git a/app/helpers/access_tokens_helper.rb b/app/helpers/access_tokens_helper.rb index 1d38262159f..d8d44601327 100644 --- a/app/helpers/access_tokens_helper.rb +++ b/app/helpers/access_tokens_helper.rb @@ -27,4 +27,10 @@ module AccessTokensHelper } }.to_json end + + def expires_at_field_data + {} + end end + +AccessTokensHelper.prepend_mod diff --git a/app/helpers/container_registry_helper.rb b/app/helpers/container_registry_helper.rb index 1b77b639ce1..255b8183164 100644 --- a/app/helpers/container_registry_helper.rb +++ b/app/helpers/container_registry_helper.rb @@ -2,8 +2,7 @@ module ContainerRegistryHelper def container_registry_expiration_policies_throttling? - Feature.enabled?(:container_registry_expiration_policies_throttling) && - ContainerRegistry::Client.supports_tag_delete? + Feature.enabled?(:container_registry_expiration_policies_throttling, default_enabled: :yaml) end def container_repository_gid_prefix diff --git a/app/models/concerns/integrations/has_issue_tracker_fields.rb b/app/models/concerns/integrations/has_issue_tracker_fields.rb new file mode 100644 index 00000000000..b1def38d019 --- /dev/null +++ b/app/models/concerns/integrations/has_issue_tracker_fields.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Integrations + module HasIssueTrackerFields + extend ActiveSupport::Concern + + included do + field :project_url, + required: true, + storage: :data_fields, + title: -> { _('Project URL') }, + help: -> { s_('IssueTracker|The URL to the project in the external issue tracker.') } + + field :issues_url, + required: true, + storage: :data_fields, + title: -> { s_('IssueTracker|Issue URL') }, + help: -> do + format s_('IssueTracker|The URL to view an issue in the external issue tracker. Must contain %{colon_id}.'), + colon_id: '<code>:id</code>'.html_safe + end + + field :new_issue_url, + required: true, + storage: :data_fields, + title: -> { s_('IssueTracker|New issue URL') }, + help: -> { s_('IssueTracker|The URL to create an issue in the external issue tracker.') } + end + end +end diff --git a/app/models/integration.rb b/app/models/integration.rb index fb44d90139a..3cf71f46420 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -122,6 +122,39 @@ class Integration < ApplicationRecord scope :alert_hooks, -> { where(alert_events: true, active: true) } scope :deployment, -> { where(category: 'deployment') } + class << self + private + + attr_writer :field_storage + + def field_storage + @field_storage || :properties + end + end + + # :nocov: Tested on subclasses. + def self.field(name, storage: field_storage, **attrs) + fields << ::Integrations::Field.new(name: name, **attrs) + + case storage + when :properties + prop_accessor(name) + when :data_fields + data_field(name) + else + raise ArgumentError, "Unknown field storage: #{storage}" + end + end + # :nocov: + + def self.fields + @fields ||= [] + end + + def fields + self.class.fields + end + # Provide convenient accessor methods for each serialized property. # Also keep track of updated properties in a similar way as ActiveModel::Dirty def self.prop_accessor(*args) @@ -395,11 +428,6 @@ class Integration < ApplicationRecord self.class.to_param end - def fields - # implement inside child - [] - end - def sections [] end diff --git a/app/models/integrations/base_issue_tracker.rb b/app/models/integrations/base_issue_tracker.rb index 71329f34dc1..458d0199e7a 100644 --- a/app/models/integrations/base_issue_tracker.rb +++ b/app/models/integrations/base_issue_tracker.rb @@ -4,10 +4,6 @@ module Integrations class BaseIssueTracker < Integration validate :one_issue_tracker, if: :activated?, on: :manual_change - # TODO: we can probably just delegate as part of - # https://gitlab.com/gitlab-org/gitlab/issues/29404 - data_field :project_url, :issues_url, :new_issue_url - default_value_for :category, 'issue_tracker' before_validation :handle_properties @@ -72,14 +68,6 @@ module Integrations issue_url(iid) end - def fields - [ - { type: 'text', name: 'project_url', title: _('Project URL'), help: s_('IssueTracker|The URL to the project in the external issue tracker.'), required: true }, - { type: 'text', name: 'issues_url', title: s_('IssueTracker|Issue URL'), help: s_('IssueTracker|The URL to view an issue in the external issue tracker. Must contain %{colon_id}.') % { colon_id: '<code>:id</code>'.html_safe }, required: true }, - { type: 'text', name: 'new_issue_url', title: s_('IssueTracker|New issue URL'), help: s_('IssueTracker|The URL to create an issue in the external issue tracker.'), required: true } - ] - end - def initialize_properties {} end diff --git a/app/models/integrations/bugzilla.rb b/app/models/integrations/bugzilla.rb index 1b711264e10..74e282f6848 100644 --- a/app/models/integrations/bugzilla.rb +++ b/app/models/integrations/bugzilla.rb @@ -2,6 +2,8 @@ module Integrations class Bugzilla < BaseIssueTracker + include Integrations::HasIssueTrackerFields + validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? def title diff --git a/app/models/integrations/custom_issue_tracker.rb b/app/models/integrations/custom_issue_tracker.rb index 0299a50605f..3770e813eaa 100644 --- a/app/models/integrations/custom_issue_tracker.rb +++ b/app/models/integrations/custom_issue_tracker.rb @@ -2,6 +2,8 @@ module Integrations class CustomIssueTracker < BaseIssueTracker + include HasIssueTrackerFields + validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? def title diff --git a/app/models/integrations/ewm.rb b/app/models/integrations/ewm.rb index c6ea989a03f..1b86ef73c85 100644 --- a/app/models/integrations/ewm.rb +++ b/app/models/integrations/ewm.rb @@ -2,6 +2,8 @@ module Integrations class Ewm < BaseIssueTracker + include HasIssueTrackerFields + validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? def self.reference_pattern(only_long: true) diff --git a/app/models/integrations/field.rb b/app/models/integrations/field.rb new file mode 100644 index 00000000000..49ab97677db --- /dev/null +++ b/app/models/integrations/field.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Integrations + class Field + SENSITIVE_NAME = %r/token|key|password|passphrase|secret/.freeze + + ATTRIBUTES = %i[ + section type placeholder required choices value checkbox_label + title help + non_empty_password_help + non_empty_password_title + api_only + ].freeze + + attr_reader :name + + def initialize(name:, type: 'text', api_only: false, **attributes) + @name = name.to_s.freeze + + attributes[:type] = SENSITIVE_NAME.match?(@name) ? 'password' : type + attributes[:api_only] = api_only + @attributes = attributes.freeze + end + + def [](key) + return name if key == :name + + value = @attributes[key] + return value.call if value.respond_to?(:call) + + value + end + + def sensitive? + @attributes[:type] == 'password' + end + + ATTRIBUTES.each do |name| + define_method(name) { self[name] } + end + end +end diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb index 8fc0a3461f7..7308c731bb0 100644 --- a/app/models/integrations/jira.rb +++ b/app/models/integrations/jira.rb @@ -28,11 +28,6 @@ module Integrations # We should use username/password for Jira Server and email/api_token for Jira Cloud, # for more information check: https://gitlab.com/gitlab-org/gitlab-foss/issues/49936. - # TODO: we can probably just delegate as part of - # https://gitlab.com/gitlab-org/gitlab/issues/29404 - data_field :username, :password, :url, :api_url, :jira_issue_transition_automatic, :jira_issue_transition_id, :project_key, :issues_enabled, - :vulnerabilities_enabled, :vulnerabilities_issuetype - before_validation :reset_password after_commit :update_deployment_type, on: [:create, :update], if: :update_deployment_type? @@ -41,6 +36,44 @@ module Integrations all_details: 2 } + self.field_storage = :data_fields + + field :url, + section: SECTION_TYPE_CONNECTION, + required: true, + title: -> { s_('JiraService|Web URL') }, + help: -> { s_('JiraService|Base URL of the Jira instance.') }, + placeholder: 'https://jira.example.com' + + field :api_url, + section: SECTION_TYPE_CONNECTION, + title: -> { s_('JiraService|Jira API URL') }, + help: -> { s_('JiraService|If different from Web URL.') } + + field :username, + section: SECTION_TYPE_CONNECTION, + required: true, + title: -> { s_('JiraService|Username or Email') }, + help: -> { s_('JiraService|Use a username for server version and an email for cloud version.') } + + field :password, + section: SECTION_TYPE_CONNECTION, + required: true, + title: -> { s_('JiraService|Password or API token') }, + non_empty_password_title: -> { s_('JiraService|Enter new password or API token') }, + non_empty_password_help: -> { s_('JiraService|Leave blank to use your current password or API token.') }, + help: -> { s_('JiraService|Use a password for server version and an API token for cloud version.') } + + # TODO: we can probably just delegate as part of + # https://gitlab.com/gitlab-org/gitlab/issues/29404 + # These fields are API only, so no field definition is required. + data_field :jira_issue_transition_automatic + data_field :jira_issue_transition_id + data_field :project_key + data_field :issues_enabled + data_field :vulnerabilities_enabled + data_field :vulnerabilities_issuetype + # When these are false GitLab does not create cross reference # comments on Jira except when an issue gets transitioned. def self.supported_events @@ -127,45 +160,6 @@ module Integrations 'jira' end - def fields - [ - { - section: SECTION_TYPE_CONNECTION, - type: 'text', - name: 'url', - title: s_('JiraService|Web URL'), - placeholder: 'https://jira.example.com', - help: s_('JiraService|Base URL of the Jira instance.'), - required: true - }, - { - section: SECTION_TYPE_CONNECTION, - type: 'text', - name: 'api_url', - title: s_('JiraService|Jira API URL'), - help: s_('JiraService|If different from Web URL.') - }, - { - section: SECTION_TYPE_CONNECTION, - type: 'text', - name: 'username', - title: s_('JiraService|Username or Email'), - help: s_('JiraService|Use a username for server version and an email for cloud version.'), - required: true - }, - { - section: SECTION_TYPE_CONNECTION, - type: 'password', - name: 'password', - title: s_('JiraService|Password or API token'), - non_empty_password_title: s_('JiraService|Enter new password or API token'), - non_empty_password_help: s_('JiraService|Leave blank to use your current password or API token.'), - help: s_('JiraService|Use a password for server version and an API token for cloud version.'), - required: true - } - ] - end - def sections [ { @@ -194,17 +188,12 @@ module Integrations url.to_s end - override :project_url - def project_url - web_url - end + alias_method :project_url, :web_url - override :issues_url def issues_url web_url('browse/:id') end - override :new_issue_url def new_issue_url web_url('secure/CreateIssue!default.jspa') end diff --git a/app/models/integrations/redmine.rb b/app/models/integrations/redmine.rb index 3812033c388..bc2a64b0848 100644 --- a/app/models/integrations/redmine.rb +++ b/app/models/integrations/redmine.rb @@ -2,6 +2,8 @@ module Integrations class Redmine < BaseIssueTracker + include Integrations::HasIssueTrackerFields + validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? def title diff --git a/app/models/integrations/youtrack.rb b/app/models/integrations/youtrack.rb index 254f0c6c69a..ab6e1da27f8 100644 --- a/app/models/integrations/youtrack.rb +++ b/app/models/integrations/youtrack.rb @@ -2,6 +2,8 @@ module Integrations class Youtrack < BaseIssueTracker + include Integrations::HasIssueTrackerFields + validates :project_url, :issues_url, presence: true, public_url: true, if: :activated? # {PROJECT-KEY}-{NUMBER} Examples: YT-1, PRJ-1, gl-030 diff --git a/app/services/projects/container_repository/cleanup_tags_service.rb b/app/services/projects/container_repository/cleanup_tags_service.rb index e15ab1b037b..72f3fddb4c3 100644 --- a/app/services/projects/container_repository/cleanup_tags_service.rb +++ b/app/services/projects/container_repository/cleanup_tags_service.rb @@ -152,7 +152,7 @@ module Projects end def throttling_enabled? - Feature.enabled?(:container_registry_expiration_policies_throttling) + Feature.enabled?(:container_registry_expiration_policies_throttling, default_enabled: :yaml) end def max_list_size diff --git a/app/services/projects/container_repository/gitlab/delete_tags_service.rb b/app/services/projects/container_repository/gitlab/delete_tags_service.rb index 589aac5c3ac..f109cb0ca20 100644 --- a/app/services/projects/container_repository/gitlab/delete_tags_service.rb +++ b/app/services/projects/container_repository/gitlab/delete_tags_service.rb @@ -54,7 +54,7 @@ module Projects def throttling_enabled? strong_memoize(:feature_flag) do - Feature.enabled?(:container_registry_expiration_policies_throttling) + Feature.enabled?(:container_registry_expiration_policies_throttling, default_enabled: :yaml) end end diff --git a/app/views/groups/_shared_projects.html.haml b/app/views/groups/_shared_projects.html.haml index bfd056ccdd2..ef6410ad439 100644 --- a/app/views/groups/_shared_projects.html.haml +++ b/app/views/groups/_shared_projects.html.haml @@ -4,5 +4,4 @@ %ul.content-list{ data: { hide_projects: 'false', group_id: group.id, path: group_path(group) } } .js-groups-list-holder - .loading-container.text-center.prepend-top-20 - .gl-spinner.gl-spinner-md + = gl_loading_icon diff --git a/app/views/shared/access_tokens/_form.html.haml b/app/views/shared/access_tokens/_form.html.haml index 7e6e8e06397..0b68cfe65e5 100644 --- a/app/views/shared/access_tokens/_form.html.haml +++ b/app/views/shared/access_tokens/_form.html.haml @@ -24,14 +24,9 @@ %span.form-text.text-muted.col-md-12#access_token_help_text= _("For example, the application using the token or the purpose of the token. Do not give sensitive information for the name of the token, as it will be visible to all %{resource_type} members.") % { resource_type: resource_type } .row - .form-group.col-md-6 - = f.label :expires_at, _('Expiration date'), class: 'label-bold' - .input-icon-wrapper - - = render_if_exists 'personal_access_tokens/callout_max_personal_access_token_lifetime' - - .js-access-tokens-expires-at - = f.text_field :expires_at, class: 'datepicker gl-datepicker-input form-control gl-form-input', placeholder: 'YYYY-MM-DD', autocomplete: 'off', data: { js_name: 'expiresAt' } + .col + .js-access-tokens-expires-at{ data: expires_at_field_data } + = f.text_field :expires_at, class: 'datepicker gl-datepicker-input form-control gl-form-input', placeholder: 'YYYY-MM-DD', autocomplete: 'off', data: { js_name: 'expiresAt' } - if resource .row diff --git a/app/workers/container_expiration_policies/cleanup_container_repository_worker.rb b/app/workers/container_expiration_policies/cleanup_container_repository_worker.rb index 7f7a77d0524..cd3ed5d4c9b 100644 --- a/app/workers/container_expiration_policies/cleanup_container_repository_worker.rb +++ b/app/workers/container_expiration_policies/cleanup_container_repository_worker.rb @@ -123,7 +123,7 @@ module ContainerExpirationPolicies end def throttling_enabled? - Feature.enabled?(:container_registry_expiration_policies_throttling) + Feature.enabled?(:container_registry_expiration_policies_throttling, default_enabled: :yaml) end def max_cleanup_execution_time diff --git a/app/workers/container_expiration_policy_worker.rb b/app/workers/container_expiration_policy_worker.rb index 16ac61976eb..308ccfe2cb3 100644 --- a/app/workers/container_expiration_policy_worker.rb +++ b/app/workers/container_expiration_policy_worker.rb @@ -99,7 +99,7 @@ class ContainerExpirationPolicyWorker # rubocop:disable Scalability/IdempotentWo end def throttling_enabled? - Feature.enabled?(:container_registry_expiration_policies_throttling) + Feature.enabled?(:container_registry_expiration_policies_throttling, default_enabled: :yaml) end def lease_timeout |