Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-05-29 18:08:36 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-29 18:08:36 +0300
commit5b9b518d9f152eb5b88ef58512355fe2dbc8c032 (patch)
treee932397afdf40ab3175c22a327d3acd223f8d367
parentc3fe9f52152cd57f6790d30efc2d5e4b9dbf54dd (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/CODEOWNERS1
-rw-r--r--.gitlab/ci/package-and-test-nightly/main.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/package-and-test/main.gitlab-ci.yml5
-rw-r--r--.gitlab/ci/qa-common/main.gitlab-ci.yml21
-rw-r--r--.gitlab/ci/qa.gitlab-ci.yml9
-rw-r--r--.gitlab/ci/test-on-gdk/main.gitlab-ci.yml6
-rw-r--r--.rubocop_todo/gitlab/namespaced_class.yml1
-rw-r--r--.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml2
-rw-r--r--app/helpers/safe_format_helper.rb62
-rw-r--r--config/initializers/1_settings.rb3
-rw-r--r--config/sidekiq_queues.yml2
-rw-r--r--db/migrate/20230509013743_remove_clear_shared_runners_minutes_worker_job_instances.rb14
-rw-r--r--db/schema_migrations/202305090137431
-rw-r--r--doc/ci/pipelines/cicd_minutes.md30
-rw-r--r--doc/ci/runners/runners_scope.md2
-rw-r--r--doc/development/documentation/index.md4
-rw-r--r--doc/development/i18n/externalization.md6
-rw-r--r--lib/gitlab/ci/config/external/file/base.rb3
-rw-r--r--lib/gitlab/ci/config/yaml.rb45
-rw-r--r--lib/gitlab/ci/config/yaml/interpolator.rb (renamed from lib/gitlab/ci/config/external/interpolator.rb)4
-rw-r--r--lib/gitlab/ci/config/yaml/loader.rb54
-rw-r--r--locale/gitlab.pot40
-rw-r--r--spec/helpers/safe_format_helper_spec.rb135
-rw-r--r--spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb (renamed from spec/lib/gitlab/ci/config/external/interpolator_spec.rb)2
-rw-r--r--spec/lib/gitlab/ci/config/yaml/loader_spec.rb153
-rw-r--r--spec/support/rspec_order_todo.yml2
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb1
27 files changed, 433 insertions, 179 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 0face29d47d..b6ab141a649 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -1300,7 +1300,6 @@ lib/gitlab/checks/**
/ee/app/views/ci_minutes_usage_mailer/
/ee/app/views/projects/pipelines/
/ee/app/views/projects/settings/ci_cd/
-/ee/app/workers/clear_shared_runners_minutes_worker.rb
/ee/lib/api/merge_trains.rb
/ee/lib/ee/api/entities/merge_train.rb
diff --git a/.gitlab/ci/package-and-test-nightly/main.gitlab-ci.yml b/.gitlab/ci/package-and-test-nightly/main.gitlab-ci.yml
index b76f6f85193..bcd63e4f7ec 100644
--- a/.gitlab/ci/package-and-test-nightly/main.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test-nightly/main.gitlab-ci.yml
@@ -122,10 +122,6 @@ export-test-metrics:
extends:
- .export-test-metrics
-relate-test-failures:
- extends:
- - .relate-test-failures
-
generate-test-session:
extends:
- .generate-test-session
diff --git a/.gitlab/ci/package-and-test/main.gitlab-ci.yml b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
index 0f3884ef5f1..9b127728615 100644
--- a/.gitlab/ci/package-and-test/main.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
@@ -689,11 +689,6 @@ export-test-metrics:
- .export-test-metrics
- .rules:report:process-results
-relate-test-failures:
- extends:
- - .relate-test-failures
- - .rules:report:process-results
-
generate-test-session:
extends:
- .generate-test-session
diff --git a/.gitlab/ci/qa-common/main.gitlab-ci.yml b/.gitlab/ci/qa-common/main.gitlab-ci.yml
index 51f19a8ee0d..67b341ee760 100644
--- a/.gitlab/ci/qa-common/main.gitlab-ci.yml
+++ b/.gitlab/ci/qa-common/main.gitlab-ci.yml
@@ -205,27 +205,6 @@ stages:
script:
- bundle exec rake "ci:export_test_metrics[$QA_METRICS_REPORT_FILE_PATTERN]"
-.relate-test-failures:
- extends:
- - .qa-install
- - .ruby-image
- stage: report
- when: always
- variables:
- QA_RSPEC_JSON_FILE_PATTERN: "${CI_PROJECT_DIR}/gitlab-qa-run-*/**/rspec-*.json"
- script:
- - |
- if [ "$SUITE_FAILED" != "true" ] && [ "$SUITE_RAN" == "true" ]; then
- echo "Test suite passed. Exiting..."
- exit 0
- fi
- - bundle exec update-screenshot-paths --input-files "${CI_PROJECT_DIR}/gitlab-qa-run-*/**/rspec-*.xml"
- - |
- bundle exec relate-failure-issue \
- --input-files "${QA_RSPEC_JSON_FILE_PATTERN}" \
- --project "gitlab-org/gitlab" \
- --token "${QA_RELATE_FAILURE_ISSUE_TOKEN}"
-
.generate-test-session:
extends:
- .qa-install
diff --git a/.gitlab/ci/qa.gitlab-ci.yml b/.gitlab/ci/qa.gitlab-ci.yml
index e8d7115badb..d74adde8860 100644
--- a/.gitlab/ci/qa.gitlab-ci.yml
+++ b/.gitlab/ci/qa.gitlab-ci.yml
@@ -70,15 +70,6 @@ qa:master-auto-quarantine-dequarantine:
- bundle exec confiner -r .confiner/master.yml
allow_failure: true
-qa:nightly-auto-quarantine-dequarantine:
- extends:
- - .qa-job-base
- rules:
- - if: '$QA_TRIGGER_AUTO_QUARANTINE =~ /true|yes|1/i'
- script:
- - bundle exec confiner -r .confiner/nightly.yml
- allow_failure: true
-
qa:update-qa-cache:
extends:
- .qa-job-base
diff --git a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
index f55950d56b4..51f88cdfddf 100644
--- a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
+++ b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
@@ -149,12 +149,10 @@ export-test-metrics:
variables:
QA_METRICS_REPORT_FILE_PATTERN: $CI_PROJECT_DIR/qa/tmp/test-metrics-*.json
-relate-test-failures:
- extends:
- - .relate-test-failures
- - .rules:report:process-results
+.gitlab-qa-report:
variables:
QA_RSPEC_JSON_FILE_PATTERN: $CI_PROJECT_DIR/qa/tmp/rspec-*.json
+ QA_SYSTEM_LOG_FILE_PATTERN: $CI_PROJECT_DIR/test_output/logs
generate-test-session:
extends:
diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml
index 6d4904ee4c1..6082bf1c0f1 100644
--- a/.rubocop_todo/gitlab/namespaced_class.yml
+++ b/.rubocop_todo/gitlab/namespaced_class.yml
@@ -1033,7 +1033,6 @@ Gitlab/NamespacedClass:
- 'ee/app/workers/adjourned_project_deletion_worker.rb'
- 'ee/app/workers/adjourned_projects_deletion_cron_worker.rb'
- 'ee/app/workers/admin_emails_worker.rb'
- - 'ee/app/workers/clear_shared_runners_minutes_worker.rb'
- 'ee/app/workers/create_github_webhook_worker.rb'
- 'ee/app/workers/elastic_association_indexer_worker.rb'
- 'ee/app/workers/elastic_cluster_reindexing_cron_worker.rb'
diff --git a/.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml b/.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml
index a7311c1c6df..e9cc851be52 100644
--- a/.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml
+++ b/.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml
@@ -325,12 +325,10 @@ SidekiqLoadBalancing/WorkerDataConsistency:
- 'ee/app/workers/arkose/blocked_users_report_worker.rb'
- 'ee/app/workers/auth/saml_group_sync_worker.rb'
- 'ee/app/workers/automation/execute_rule_worker.rb'
- - 'ee/app/workers/ci/batch_reset_minutes_worker.rb'
- 'ee/app/workers/ci/minutes/refresh_cached_data_worker.rb'
- 'ee/app/workers/ci/minutes/update_project_and_namespace_usage_worker.rb'
- 'ee/app/workers/ci/sync_reports_to_report_approval_rules_worker.rb'
- 'ee/app/workers/ci/upstream_projects_subscriptions_cleanup_worker.rb'
- - 'ee/app/workers/clear_shared_runners_minutes_worker.rb'
- 'ee/app/workers/compliance_management/chain_of_custody_report_worker.rb'
- 'ee/app/workers/compliance_management/merge_requests/compliance_violations_consistency_worker.rb'
- 'ee/app/workers/compliance_management/merge_requests/compliance_violations_worker.rb'
diff --git a/app/helpers/safe_format_helper.rb b/app/helpers/safe_format_helper.rb
index 96124e98d4e..d39a972f3f3 100644
--- a/app/helpers/safe_format_helper.rb
+++ b/app/helpers/safe_format_helper.rb
@@ -1,23 +1,67 @@
# frozen_string_literal: true
module SafeFormatHelper
- # Returns a HTML-safe string where
- # * +format+ is escaped via `html_escape_once`
- # * +args+ are escaped via `html_escape` if they are not marked as HTML-safe
+ # Returns a HTML-safe String.
#
- # Example:
- # safe_format('Some %{open}bold%{close} text.', open: '<strong>'.html_safe, close: '</strong>'.html_safe)
- # # => 'Some <strong>bold</strong>'
+ # @param [String] format is escaped via `html_escape_once`
+ # @param [Array<Hash>] args are escaped via `html_escape` if they are not marked as HTML-safe
+ #
+ # @example
# safe_format('See %{user_input}', user_input: '<b>bold</b>')
- # # => 'See &lt;b&gt;bold&lt;/b&gt;
+ # # => "See &lt;b&gt;bold&lt;/b&gt"
+ #
# safe_format('In &lt; hour & more')
- # # => 'In &lt; hour &amp; more'
+ # # => "In &lt; hour &amp; more"
#
- def safe_format(format, **args)
+ # @example With +tag_pair+ support
+ # safe_format('Some %{open}bold%{close} text.', tag_pair(tag.strong, :open, :close))
+ # # => "Some <strong>bold</strong> text."
+ # safe_format('Some %{open}bold%{close} %{italicStart}text%{italicEnd}.',
+ # tag_pair(tag.strong, :open, :close),
+ # tag_pair(tag.i, :italicStart, :italicEnd))
+ # # => "Some <strong>bold</strong> <i>text</i>.
+ def safe_format(format, *args)
+ args = args.inject({}, &:merge)
+
# Use `Kernel.format` to avoid conflicts with ViewComponent's `format`.
Kernel.format(
html_escape_once(format),
args.transform_values { |value| html_escape(value) }
).html_safe
end
+
+ # Returns a Hash containing a pair of +open+ and +close+ tag parts extracted
+ # from HTML-safe +tag+. The values are HTML-safe.
+ #
+ # Returns an empty Hash if +tag+ is not a valid paired tag (e.g. <p>foo</p>).
+ # an empty Hash is returned.
+ #
+ # @param [String] tag is a HTML-safe output from tag helper
+ # @param [Symbol,Object] open_name name of opening tag
+ # @param [Symbol,Object] close_name name of closing tag
+ # @raise [ArgumentError] if +tag+ is not HTML-safe
+ #
+ # @example
+ # tag_pair(tag.strong, :open, :close)
+ # # => { open: '<strong>', close: '</strong>' }
+ # tag_pair(link_to('', '/'), :open, :close)
+ # # => { open: '<a href="/">', close: '</a>' }
+ def tag_pair(html_tag, open_name, close_name)
+ raise ArgumentError, 'Argument `tag` must be `html_safe`!' unless html_tag.html_safe?
+ return {} unless html_tag.start_with?('<')
+
+ # end of opening tag: <p>foo</p>
+ # ^
+ open_index = html_tag.index('>')
+ # start of closing tag: <p>foo</p>
+ # ^^
+ close_index = html_tag.rindex('</')
+
+ return {} unless open_index && close_index
+
+ {
+ open_name => html_tag[0, open_index + 1],
+ close_name => html_tag[close_index, html_tag.size]
+ }
+ end
end
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index f7d3b12d7e9..ff034460120 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -702,9 +702,6 @@ Gitlab.ee do
Settings.cron_jobs['adjourned_group_deletion_worker'] ||= {}
Settings.cron_jobs['adjourned_group_deletion_worker']['cron'] ||= '0 2 * * *'
Settings.cron_jobs['adjourned_group_deletion_worker']['job_class'] = 'AdjournedGroupDeletionWorker'
- Settings.cron_jobs['clear_shared_runners_minutes_worker'] ||= {}
- Settings.cron_jobs['clear_shared_runners_minutes_worker']['cron'] ||= '0 0 1 * *'
- Settings.cron_jobs['clear_shared_runners_minutes_worker']['job_class'] = 'ClearSharedRunnersMinutesWorker'
Settings.cron_jobs['adjourned_projects_deletion_cron_worker'] ||= {}
Settings.cron_jobs['adjourned_projects_deletion_cron_worker']['cron'] ||= '0 7 * * *'
Settings.cron_jobs['adjourned_projects_deletion_cron_worker']['job_class'] = 'AdjournedProjectsDeletionCronWorker'
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 0e10fe312e9..970df2d4465 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -113,8 +113,6 @@
- 2
- - chat_notification
- 2
-- - ci_batch_reset_minutes
- - 1
- - ci_cancel_pipeline
- 1
- - ci_cancel_redundant_pipelines
diff --git a/db/migrate/20230509013743_remove_clear_shared_runners_minutes_worker_job_instances.rb b/db/migrate/20230509013743_remove_clear_shared_runners_minutes_worker_job_instances.rb
new file mode 100644
index 00000000000..b7202521fce
--- /dev/null
+++ b/db/migrate/20230509013743_remove_clear_shared_runners_minutes_worker_job_instances.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class RemoveClearSharedRunnersMinutesWorkerJobInstances < Gitlab::Database::Migration[2.1]
+ DEPRECATED_JOB_CLASSES = %w[
+ ClearSharedRunnersMinutesWorker
+ Ci::BatchResetMinutesWorker
+ ]
+ disable_ddl_transaction!
+ def up
+ sidekiq_remove_jobs(job_klasses: DEPRECATED_JOB_CLASSES)
+ end
+
+ def down; end
+end
diff --git a/db/schema_migrations/20230509013743 b/db/schema_migrations/20230509013743
new file mode 100644
index 00000000000..776ec9d19a6
--- /dev/null
+++ b/db/schema_migrations/20230509013743
@@ -0,0 +1 @@
+c312816ffabb9442b57d826a9e8c2214ae7672bf03938a911ddae490309fe87d \ No newline at end of file
diff --git a/doc/ci/pipelines/cicd_minutes.md b/doc/ci/pipelines/cicd_minutes.md
index 29d847ecd08..2da3c773004 100644
--- a/doc/ci/pipelines/cicd_minutes.md
+++ b/doc/ci/pipelines/cicd_minutes.md
@@ -33,17 +33,17 @@ On self-managed GitLab instances:
- CI/CD minutes quotas are disabled by default.
- When enabled, CI/CD minutes quotas apply to private projects only.
-- Administrators can [assign more CI/CD minutes](#set-the-quota-of-cicd-minutes-for-a-specific-namespace)
+- Administrators can [assign more CI/CD minutes](#set-the-compute-quota-for-a-specific-namespace)
if a namespace uses all the CI/CD minutes in its monthly quota.
[Project runners](../runners/runners_scope.md#project-runners) are not subject to a quota of CI/CD minutes.
-## Set the quota of CI/CD minutes for all namespaces
+## Set the compute quota for all namespaces
> [Moved](https://about.gitlab.com/blog/2021/01/26/new-gitlab-product-subscription-model/) to GitLab Premium in 13.9.
-By default, GitLab instances do not have a quota of CI/CD minutes.
-The default value for the quota is `0`, which grants unlimited CI/CD minutes.
+By default, GitLab instances do not have a compute quota.
+The default value for the quota is `0`, which is unlimited.
However, you can change this default value.
Prerequisite:
@@ -55,35 +55,35 @@ To change the default quota that applies to all namespaces:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **Continuous Integration and Deployment**.
-1. In the **Quota of CI/CD minutes** box, enter the maximum number of CI/CD minutes.
+1. In the **Compute quota** box, enter a limit.
1. Select **Save changes**.
If a quota is already defined for a specific namespace, this value does not change that quota.
-## Set the quota of CI/CD minutes for a specific namespace
+## Set the compute quota for a specific namespace
> [Moved](https://about.gitlab.com/blog/2021/01/26/new-gitlab-product-subscription-model/) to GitLab Premium in 13.9.
-You can override the global value and set a quota of CI/CD minutes
+You can override the global value and set a compute quota
for a specific namespace.
Prerequisite:
- You must be a GitLab administrator.
-To set a quota of CI/CD minutes for a namespace:
+To set a compute quota for a namespace:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Overview > Groups**.
1. For the group you want to update, select **Edit**.
-1. In the **Quota of CI/CD minutes** box, enter the maximum number of CI/CD minutes.
+1. In the **Compute quota** box, enter the maximum number of CI/CD minutes.
1. Select **Save changes**.
You can also use the [update group API](../../api/groups.md#update-group) or the
[update user API](../../api/users.md#user-modification) instead.
NOTE:
-You can set a quota of CI/CD minutes for only top-level groups or user namespaces.
+You can set a compute quota for only top-level groups or user namespaces.
If you set a quota for a subgroup, it is not used.
## View CI/CD minutes
@@ -348,18 +348,18 @@ consumption for contributor fork projects, enabling more contributions.
See our [pipeline efficiency guide](pipeline_efficiency.md) for more details.
-## Reset CI/CD minutes used **(PREMIUM SELF)**
+## Reset compute usage **(PREMIUM SELF)**
An administrator can reset the number of minutes used by a namespace for the current month.
-### Reset minutes for a personal namespace
+### Reset usage for a personal namespace
1. Find the [user in the admin area](../../user/admin_area/index.md#administering-users).
1. Select **Edit**.
-1. In **Limits**, select **Reset pipeline minutes**.
+1. In **Limits**, select **Reset compute usage**.
-### Reset minutes for a group namespace
+### Reset usage for a group namespace
1. Find the [group in the admin area](../../user/admin_area/index.md#administering-groups).
1. Select **Edit**.
-1. In **Permissions and group features**, select **Reset pipeline minutes**.
+1. In **Permissions and group features**, select **Reset compute usage**.
diff --git a/doc/ci/runners/runners_scope.md b/doc/ci/runners/runners_scope.md
index e36d57108ab..7334260b8c5 100644
--- a/doc/ci/runners/runners_scope.md
+++ b/doc/ci/runners/runners_scope.md
@@ -29,7 +29,7 @@ If you are using a self-managed instance of GitLab:
and selecting **Show runner installation instructions**.
These instructions are also available [in the documentation](https://docs.gitlab.com/runner/install/index.html).
- The administrator can also configure a maximum number of shared runner
- [CI/CD minutes for each group](../pipelines/cicd_minutes.md#set-the-quota-of-cicd-minutes-for-a-specific-namespace).
+ [CI/CD minutes for each group](../pipelines/cicd_minutes.md#set-the-compute-quota-for-a-specific-namespace).
If you are using GitLab.com:
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index 2ab94207269..761dde839c1 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -259,8 +259,8 @@ is inside `_()` so it can be translated:
link:
```haml
- - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/permissions') }
- %p= safe_format(_("This is a text describing the option/feature in a sentence. %{link_start}Learn more.%{link_end}"), link_start: link_start, link_end: '</a>'.html_safe)
+ - link = link_to('', help_page_path('user/permissions'), target: '_blank', rel: 'noopener noreferrer')
+ %p= safe_format(_("This is a text describing the option/feature in a sentence. %{link_start}Learn more.%{link_end}"), tag_pair(link, :link_start, :link_end))
```
- Using a button link. Useful in places where text would be out of context with
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index 0ca943a39c9..12ef454d234 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -561,7 +561,7 @@ To include formatting in the translated string, you can do the following:
- In Ruby/HAML:
```ruby
- safe_format(_('Some %{strongOpen}bold%{strongClose} text.'), strongOpen: '<strong>'.html_safe, strongClose: '</strong>'.html_safe)
+ safe_format(_('Some %{strongOpen}bold%{strongClose} text.'), tag_pair(tag.strong, :strongOpen, :strongClose))
# => 'Some <strong>bold</strong> text.'
```
@@ -800,8 +800,8 @@ translatable in certain languages.
```haml
- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
- - zones_link_start = safe_format('<a href="%{url}" target="_blank" rel="noopener noreferrer">', url: zones_link_url)
- = safe_format(s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}'), zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe)
+ - zones_link = link_to('', zones_link_url, target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}'), tag_pair(zones_link, :zones_link_start, :zones_link_end))
```
- In Vue, instead of:
diff --git a/lib/gitlab/ci/config/external/file/base.rb b/lib/gitlab/ci/config/external/file/base.rb
index 6b635cdf33b..61d95c8d4e6 100644
--- a/lib/gitlab/ci/config/external/file/base.rb
+++ b/lib/gitlab/ci/config/external/file/base.rb
@@ -130,8 +130,7 @@ module Gitlab
strong_memoize_attr :content_hash
def interpolator
- External::Interpolator
- .new(content_result, content_inputs, context)
+ Yaml::Interpolator.new(content_result, content_inputs, context)
end
strong_memoize_attr :interpolator
diff --git a/lib/gitlab/ci/config/yaml.rb b/lib/gitlab/ci/config/yaml.rb
index 729e7e3ac05..f74ef95a832 100644
--- a/lib/gitlab/ci/config/yaml.rb
+++ b/lib/gitlab/ci/config/yaml.rb
@@ -4,51 +4,6 @@ module Gitlab
module Ci
class Config
module Yaml
- AVAILABLE_TAGS = [Config::Yaml::Tags::Reference].freeze
- MAX_DOCUMENTS = 2
-
- class Loader
- def initialize(content, project: nil)
- @content = content
- @project = project
- end
-
- def load!
- ensure_custom_tags
-
- if project.present? && ::Feature.enabled?(:ci_multi_doc_yaml, project)
- ::Gitlab::Config::Loader::MultiDocYaml.new(
- content,
- max_documents: MAX_DOCUMENTS,
- additional_permitted_classes: AVAILABLE_TAGS,
- reject_empty: true
- ).load!
- else
- ::Gitlab::Config::Loader::Yaml
- .new(content, additional_permitted_classes: AVAILABLE_TAGS)
- .load!
- end
- end
-
- def to_result
- Yaml::Result.new(config: load!, error: nil)
- rescue ::Gitlab::Config::Loader::FormatError => e
- Yaml::Result.new(error: e)
- end
-
- private
-
- attr_reader :content, :project
-
- def ensure_custom_tags
- @ensure_custom_tags ||= begin
- AVAILABLE_TAGS.each { |klass| Psych.add_tag(klass.tag, klass) }
-
- true
- end
- end
- end
-
class << self
def load!(content, project: nil)
Loader.new(content, project: project).to_result.then do |result|
diff --git a/lib/gitlab/ci/config/external/interpolator.rb b/lib/gitlab/ci/config/yaml/interpolator.rb
index f8af77fb246..4ae191dfedf 100644
--- a/lib/gitlab/ci/config/external/interpolator.rb
+++ b/lib/gitlab/ci/config/yaml/interpolator.rb
@@ -3,9 +3,9 @@
module Gitlab
module Ci
class Config
- module External
+ module Yaml
##
- # Config::External::Interpolation perform includable file interpolation, and surfaces all possible interpolation
+ # Config::Yaml::Interpolation performs includable file interpolation, and surfaces all possible interpolation
# errors. It is designed to provide an external file's validation context too.
#
class Interpolator
diff --git a/lib/gitlab/ci/config/yaml/loader.rb b/lib/gitlab/ci/config/yaml/loader.rb
new file mode 100644
index 00000000000..7277981f1e3
--- /dev/null
+++ b/lib/gitlab/ci/config/yaml/loader.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Yaml
+ class Loader
+ AVAILABLE_TAGS = [Config::Yaml::Tags::Reference].freeze
+ MAX_DOCUMENTS = 2
+
+ def initialize(content, project: nil)
+ @content = content
+ @project = project
+ end
+
+ def to_result
+ Yaml::Result.new(config: load!, error: nil)
+ rescue ::Gitlab::Config::Loader::FormatError => e
+ Yaml::Result.new(error: e)
+ end
+
+ private
+
+ attr_reader :content, :project
+
+ def ensure_custom_tags
+ @ensure_custom_tags ||= begin
+ AVAILABLE_TAGS.each { |klass| Psych.add_tag(klass.tag, klass) }
+
+ true
+ end
+ end
+
+ def load!
+ ensure_custom_tags
+
+ if project.present? && ::Feature.enabled?(:ci_multi_doc_yaml, project)
+ ::Gitlab::Config::Loader::MultiDocYaml.new(
+ content,
+ max_documents: MAX_DOCUMENTS,
+ additional_permitted_classes: AVAILABLE_TAGS,
+ reject_empty: true
+ ).load!
+ else
+ ::Gitlab::Config::Loader::Yaml
+ .new(content, additional_permitted_classes: AVAILABLE_TAGS)
+ .load!
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 9642fa1dad5..0db8fd09f38 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3725,6 +3725,9 @@ msgstr ""
msgid "AdminUsers|Cohorts"
msgstr ""
+msgid "AdminUsers|Compute quota"
+msgstr ""
+
msgid "AdminUsers|Confirm user"
msgstr ""
@@ -3830,9 +3833,6 @@ msgstr ""
msgid "AdminUsers|Private profile"
msgstr ""
-msgid "AdminUsers|Quota of CI/CD minutes"
-msgstr ""
-
msgid "AdminUsers|Reactivating a user will:"
msgstr ""
@@ -3872,7 +3872,7 @@ msgstr ""
msgid "AdminUsers|Sort by"
msgstr ""
-msgid "AdminUsers|The maximum number of CI/CD minutes on shared runners that a group can use each month. Set 0 for unlimited. Set empty to inherit the global setting of %{minutes}"
+msgid "AdminUsers|The maximum units of compute that jobs in this namespace can use on shared runners each month. Set 0 for unlimited. Set empty to inherit the global setting of %{minutes}"
msgstr ""
msgid "AdminUsers|The user can't access git repositories."
@@ -5030,6 +5030,9 @@ msgstr ""
msgid "An error occurred while reordering issues."
msgstr ""
+msgid "An error occurred while resetting the compute usage."
+msgstr ""
+
msgid "An error occurred while retrieving calendar activity"
msgstr ""
@@ -11614,6 +11617,9 @@ msgstr ""
msgid "Components must have a 'name'"
msgstr ""
+msgid "Compute quota"
+msgstr ""
+
msgid "Confidence"
msgstr ""
@@ -37265,9 +37271,6 @@ msgstr ""
msgid "Quick range"
msgstr ""
-msgid "Quota of CI/CD minutes"
-msgstr ""
-
msgid "Quota of CI/CD minutes:"
msgstr ""
@@ -42201,13 +42204,10 @@ msgstr ""
msgid "Shared runners help link"
msgstr ""
-msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
-msgstr ""
-
-msgid "SharedRunnersMinutesSettings|Reset pipeline minutes"
+msgid "SharedRunnersMinutesSettings|Reset compute usage"
msgstr ""
-msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
+msgid "SharedRunnersMinutesSettings|When you reset the compute usage for this namespace, the compute usage changes to zero."
msgstr ""
msgid "Shimo|Go to Shimo Workspace"
@@ -44075,6 +44075,9 @@ msgstr ""
msgid "Successfully removed email."
msgstr ""
+msgid "Successfully reset compute usage for namespace."
+msgstr ""
+
msgid "Successfully scheduled a pipeline to run. Go to the %{pipelines_link_start}Pipelines page%{pipelines_link_end} for details."
msgstr ""
@@ -45524,10 +45527,10 @@ msgstr ""
msgid "The maximum file size is %{size}."
msgstr ""
-msgid "The maximum number of CI/CD minutes on shared runners that a group can use each month. 0 for unlimited."
+msgid "The maximum number of tags that a single worker accepts for cleanup. If the number of tags goes above this limit, the list of tags to delete is truncated to this number. To remove this limit, set it to 0."
msgstr ""
-msgid "The maximum number of tags that a single worker accepts for cleanup. If the number of tags goes above this limit, the list of tags to delete is truncated to this number. To remove this limit, set it to 0."
+msgid "The maximum units of compute that jobs in a namespace can use on shared runners each month. 0 for unlimited."
msgstr ""
msgid "The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally."
@@ -46040,9 +46043,6 @@ msgstr ""
msgid "There was an error removing the e-mail."
msgstr ""
-msgid "There was an error resetting user pipeline minutes."
-msgstr ""
-
msgid "There was an error retrieving LDAP groups. Please try again."
msgstr ""
@@ -50858,9 +50858,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are CI/CD minutes?"
-msgstr ""
-
msgid "What are group audit events?"
msgstr ""
@@ -50885,6 +50882,9 @@ msgstr ""
msgid "What is Markdown?"
msgstr ""
+msgid "What is a compute quota?"
+msgstr ""
+
msgid "What is listed here?"
msgstr ""
diff --git a/spec/helpers/safe_format_helper_spec.rb b/spec/helpers/safe_format_helper_spec.rb
index 3639494060d..b5db623f14d 100644
--- a/spec/helpers/safe_format_helper_spec.rb
+++ b/spec/helpers/safe_format_helper_spec.rb
@@ -4,31 +4,73 @@ require 'spec_helper'
RSpec.describe SafeFormatHelper, feature_category: :shared do
describe '#safe_format' do
- shared_examples 'safe formatting' do |format, args:, result:|
- subject { helper.safe_format(format, **args) }
+ shared_examples 'safe formatting' do
+ subject { helper.safe_format(format, args) }
it { is_expected.to eq(result) }
it { is_expected.to be_html_safe }
end
- it_behaves_like 'safe formatting', '', args: {}, result: ''
- it_behaves_like 'safe formatting', 'Foo', args: {}, result: 'Foo'
+ it_behaves_like 'safe formatting' do
+ let(:format) { '' }
+ let(:args) { {} }
+ let(:result) { '' }
+ end
- it_behaves_like 'safe formatting', '<b>strong</b>', args: {},
- result: '&lt;b&gt;strong&lt;/b&gt;'
+ it_behaves_like 'safe formatting' do
+ let(:format) { 'Foo' }
+ let(:args) { {} }
+ let(:result) { 'Foo' }
+ end
- it_behaves_like 'safe formatting', '%{open}strong%{close}',
- args: { open: '<b>'.html_safe, close: '</b>'.html_safe },
- result: '<b>strong</b>'
+ it_behaves_like 'safe formatting' do
+ let(:format) { '<b>strong</b>' }
+ let(:args) { {} }
+ let(:result) { '&lt;b&gt;strong&lt;/b&gt;' }
+ end
+
+ it_behaves_like 'safe formatting' do
+ let(:format) { '%{open}strong%{close}' }
+ let(:args) { { open: '<b>'.html_safe, close: '</b>'.html_safe } }
+ let(:result) { '<b>strong</b>' }
+ end
- it_behaves_like 'safe formatting', '%{open}strong%{close} %{user_input}',
- args: { open: '<b>'.html_safe, close: '</b>'.html_safe,
- user_input: '<a href="">link</a>' },
- result: '<b>strong</b> &lt;a href=&quot;&quot;&gt;link&lt;/a&gt;'
+ it_behaves_like 'safe formatting' do
+ let(:format) { '%{open}strong%{close} %{user_input}' }
+
+ let(:args) do
+ { open: '<b>'.html_safe, close: '</b>'.html_safe,
+ user_input: '<a href="">link</a>' }
+ end
+
+ let(:result) { '<b>strong</b> &lt;a href=&quot;&quot;&gt;link&lt;/a&gt;' }
+ end
context 'when format is marked as html_safe' do
- it_behaves_like 'safe formatting', '<b>strong</b>'.html_safe, args: {},
- result: '&lt;b&gt;strong&lt;/b&gt;'
+ it_behaves_like 'safe formatting' do
+ let(:format) { '<b>strong</b>'.html_safe }
+ let(:args) { {} }
+ let(:result) { '&lt;b&gt;strong&lt;/b&gt;' }
+ end
+ end
+
+ context 'with multiple args' do
+ it_behaves_like 'safe formatting' do
+ let(:format) { '%{a}c%{b} %{x}z%{y}' }
+
+ let(:args) do
+ [
+ { a: '<a>'.html_safe, b: '</a>'.html_safe },
+ # Demonstrate shadowing
+ { x: '<XX>'.html_safe, y: '</XX>'.html_safe },
+ { x: '<x>'.html_safe, y: '</x>'.html_safe }
+ ]
+ end
+
+ let(:result) { '<a>c</a> <x>z</x>' }
+
+ subject { helper.safe_format(format, *args) }
+ end
end
context 'with a view component' do
@@ -49,17 +91,62 @@ RSpec.describe SafeFormatHelper, feature_category: :shared do
end
context 'with format containing escaped entities' do
- it_behaves_like 'safe formatting', 'In &lt; hour',
- args: {},
- result: 'In &lt; hour'
+ it_behaves_like 'safe formatting' do
+ let(:format) { 'In &lt; hour' }
+ let(:args) { {} }
+ let(:result) { 'In &lt; hour' }
+ end
+
+ it_behaves_like 'safe formatting' do
+ let(:format) { '&quot;air&quot;' }
+ let(:args) { {} }
+ let(:result) { '&quot;air&quot;' }
+ end
+
+ it_behaves_like 'safe formatting' do
+ let(:format) { 'Mix & match &gt; all' }
+ let(:args) { {} }
+ let(:result) { 'Mix &amp; match &gt; all' }
+ end
+ end
+ end
+
+ describe '#tag_pair' do
+ using RSpec::Parameterized::TableSyntax
- it_behaves_like 'safe formatting', '&quot;air&quot;',
- args: {},
- result: '&quot;air&quot;'
+ let(:tag) { plain_tag.html_safe }
+ let(:open_name) { :tag_open }
+ let(:close_name) { :tag_close }
- it_behaves_like 'safe formatting', 'Mix & match &gt; all',
- args: {},
- result: 'Mix &amp; match &gt; all'
+ subject(:result) { tag_pair(tag, open_name, close_name) }
+
+ where(:plain_tag, :open, :close) do
+ '' | nil | nil
+ 'a' | nil | nil
+ '<a' | nil | nil
+ '<a>' | nil | nil
+ '<a><a>' | nil | nil
+ '<input/>' | nil | nil
+ '<a></a>' | '<a>' | '</a>'
+ '<a href="">x</a>' | '<a href="">' | '</a>'
+ end
+
+ with_them do
+ if params[:open] && params[:close]
+ it { is_expected.to eq({ open_name => open, close_name => close }) }
+ specify { expect(result.values).to be_all(&:html_safe?) }
+ else
+ it { is_expected.to eq({}) }
+ end
+ end
+
+ context 'when tag is not html_safe' do
+ # `to_str` turns a html_safe string into a plain String.
+ let(:tag) { helper.tag.strong.to_str }
+
+ it 'raises an ArgumentError' do
+ expect { result }.to raise_error ArgumentError, 'Argument `tag` must be `html_safe`!'
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/interpolator_spec.rb b/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb
index fe6f97a66a5..726ed6d95a0 100644
--- a/spec/lib/gitlab/ci/config/external/interpolator_spec.rb
+++ b/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::External::Interpolator, feature_category: :pipeline_composition do
+RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeline_composition do
let_it_be(:project) { create(:project) }
let(:ctx) { instance_double(Gitlab::Ci::Config::External::Context, project: project, user: build(:user, id: 1234)) }
diff --git a/spec/lib/gitlab/ci/config/yaml/loader_spec.rb b/spec/lib/gitlab/ci/config/yaml/loader_spec.rb
new file mode 100644
index 00000000000..1e417bcd8af
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/yaml/loader_spec.rb
@@ -0,0 +1,153 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Config::Yaml::Loader, feature_category: :pipeline_composition do
+ describe '#to_result' do
+ let_it_be(:project) { create(:project) }
+
+ subject(:result) { described_class.new(yaml, project: project).to_result }
+
+ context 'when syntax is invalid' do
+ let(:yaml) { 'some: invalid: syntax' }
+
+ it 'returns an invalid result object' do
+ expect(result).not_to be_valid
+ expect(result.error).to be_a ::Gitlab::Config::Loader::FormatError
+ end
+ end
+
+ context 'when the first document is a header' do
+ context 'with explicit document start marker' do
+ let(:yaml) do
+ <<~YAML
+ ---
+ spec:
+ ---
+ b: 2
+ YAML
+ end
+
+ it 'considers the first document as header and the second as content' do
+ expect(result).to be_valid
+ expect(result.error).to be_nil
+ expect(result.header).to eq({ spec: nil })
+ expect(result.content).to eq({ b: 2 })
+ end
+ end
+ end
+
+ context 'when first document is empty' do
+ let(:yaml) do
+ <<~YAML
+ ---
+ ---
+ b: 2
+ YAML
+ end
+
+ it 'considers the first document as header and the second as content' do
+ expect(result).not_to have_header
+ end
+ end
+
+ context 'when first document is an empty hash' do
+ let(:yaml) do
+ <<~YAML
+ {}
+ ---
+ b: 2
+ YAML
+ end
+
+ it 'returns second document as a content' do
+ expect(result).not_to have_header
+ expect(result.content).to eq({ b: 2 })
+ end
+ end
+
+ context 'when first an array' do
+ let(:yaml) do
+ <<~YAML
+ ---
+ - a
+ - b
+ ---
+ b: 2
+ YAML
+ end
+
+ it 'considers the first document as header and the second as content' do
+ expect(result).not_to have_header
+ end
+ end
+
+ context 'when the first document is not a header' do
+ let(:yaml) do
+ <<~YAML
+ a: 1
+ ---
+ b: 2
+ YAML
+ end
+
+ it 'considers the first document as content for backwards compatibility' do
+ expect(result).to be_valid
+ expect(result.error).to be_nil
+ expect(result).not_to have_header
+ expect(result.content).to eq({ a: 1 })
+ end
+
+ context 'with explicit document start marker' do
+ let(:yaml) do
+ <<~YAML
+ ---
+ a: 1
+ ---
+ b: 2
+ YAML
+ end
+
+ it 'considers the first document as content for backwards compatibility' do
+ expect(result).to be_valid
+ expect(result.error).to be_nil
+ expect(result).not_to have_header
+ expect(result.content).to eq({ a: 1 })
+ end
+ end
+ end
+
+ context 'when the first document is not a header and second document is empty' do
+ let(:yaml) do
+ <<~YAML
+ a: 1
+ ---
+ YAML
+ end
+
+ it 'considers the first document as content' do
+ expect(result).to be_valid
+ expect(result.error).to be_nil
+ expect(result).not_to have_header
+ expect(result.content).to eq({ a: 1 })
+ end
+
+ context 'with explicit document start marker' do
+ let(:yaml) do
+ <<~YAML
+ ---
+ a: 1
+ ---
+ YAML
+ end
+
+ it 'considers the first document as content' do
+ expect(result).to be_valid
+ expect(result.error).to be_nil
+ expect(result).not_to have_header
+ expect(result.content).to eq({ a: 1 })
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 01875aadacb..a94ceb98741 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -3125,7 +3125,6 @@
- './ee/spec/workers/audit_events/audit_event_streaming_worker_spec.rb'
- './ee/spec/workers/audit_events/user_impersonation_event_create_worker_spec.rb'
- './ee/spec/workers/auth/saml_group_sync_worker_spec.rb'
-- './ee/spec/workers/ci/batch_reset_minutes_worker_spec.rb'
- './ee/spec/workers/ci/initial_pipeline_process_worker_spec.rb'
- './ee/spec/workers/ci/minutes/refresh_cached_data_worker_spec.rb'
- './ee/spec/workers/ci/minutes/update_project_and_namespace_usage_worker_spec.rb'
@@ -3133,7 +3132,6 @@
- './ee/spec/workers/ci/sync_reports_to_report_approval_rules_worker_spec.rb'
- './ee/spec/workers/ci/trigger_downstream_subscriptions_worker_spec.rb'
- './ee/spec/workers/ci/upstream_projects_subscriptions_cleanup_worker_spec.rb'
-- './ee/spec/workers/clear_shared_runners_minutes_worker_spec.rb'
- './ee/spec/workers/compliance_management/chain_of_custody_report_worker_spec.rb'
- './ee/spec/workers/compliance_management/merge_requests/compliance_violations_worker_spec.rb'
- './ee/spec/workers/concerns/elastic/indexing_control_spec.rb'
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index 3c9324a5258..8a0e05e6fb6 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -151,7 +151,6 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'Chaos::SleepWorker' => 3,
'ChatNotificationWorker' => false,
'Ci::ArchiveTraceWorker' => 3,
- 'Ci::BatchResetMinutesWorker' => 10,
'Ci::BuildFinishedWorker' => 3,
'Ci::BuildPrepareWorker' => 3,
'Ci::BuildScheduleWorker' => 3,