Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-05-29 15:08:36 +00:00
parent c3fe9f5215
commit 5b9b518d9f
27 changed files with 434 additions and 180 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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'

View File

@ -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'

View File

@ -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;
# safe_format('In &lt; hour & more')
# # => 'In &lt; hour &amp; more'
# # => "See &lt;b&gt;bold&lt;/b&gt"
#
def safe_format(format, **args)
# safe_format('In &lt; hour & more')
# # => "In &lt; hour &amp; more"
#
# @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

View File

@ -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'

View File

@ -113,8 +113,6 @@
- 2
- - chat_notification
- 2
- - ci_batch_reset_minutes
- 1
- - ci_cancel_pipeline
- 1
- - ci_cancel_redundant_pipelines

View File

@ -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

View File

@ -0,0 +1 @@
c312816ffabb9442b57d826a9e8c2214ae7672bf03938a911ddae490309fe87d

View File

@ -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**.

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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|

View File

@ -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

View File

@ -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

View File

@ -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."
msgid "SharedRunnersMinutesSettings|Reset compute usage"
msgstr ""
msgid "SharedRunnersMinutesSettings|Reset pipeline minutes"
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 ""

View File

@ -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', '%{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}' }
let(:args) { { open: '<b>'.html_safe, close: '</b>'.html_safe } }
let(:result) { '<b>strong</b>' }
end
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', '&quot;air&quot;',
args: {},
result: '&quot;air&quot;'
it_behaves_like 'safe formatting' do
let(:format) { '&quot;air&quot;' }
let(:args) { {} }
let(:result) { '&quot;air&quot;' }
end
it_behaves_like 'safe formatting', 'Mix & match &gt; all',
args: {},
result: 'Mix &amp; match &gt; all'
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
let(:tag) { plain_tag.html_safe }
let(:open_name) { :tag_open }
let(:close_name) { :tag_close }
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

View File

@ -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)) }

View File

@ -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

View File

@ -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'

View File

@ -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,