Commit 0ba82568 authored by Maxime Orefice's avatar Maxime Orefice Committed by Shinya Maeda

Prevents pipeline creation for builds with more than 50 tags

parent 4ba24381
---
name: ci_build_tags_limit
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68380
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338929
milestone: '14.2'
type: development
group: group::pipeline execution
default_enabled: false
...@@ -1885,6 +1885,9 @@ variables: ...@@ -1885,6 +1885,9 @@ variables:
- echo "Hello runner selector feature" - echo "Hello runner selector feature"
``` ```
NOTE:
In [GitLab 14.3](https://gitlab.com/gitlab-org/gitlab/-/issues/338479) and later, the number of tags must be less than `50`.
### `allow_failure` ### `allow_failure`
Use `allow_failure` when you want to let a job fail without impacting the rest of the CI Use `allow_failure` when you want to let a job fail without impacting the rest of the CI
......
...@@ -53,7 +53,7 @@ module Gitlab ...@@ -53,7 +53,7 @@ module Gitlab
description: 'Set retry default value.', description: 'Set retry default value.',
inherit: false inherit: false
entry :tags, ::Gitlab::Config::Entry::ArrayOfStrings, entry :tags, Entry::Tags,
description: 'Set the default tags.', description: 'Set the default tags.',
inherit: false inherit: false
......
...@@ -85,7 +85,7 @@ module Gitlab ...@@ -85,7 +85,7 @@ module Gitlab
description: 'Retry configuration for this job.', description: 'Retry configuration for this job.',
inherit: true inherit: true
entry :tags, ::Gitlab::Config::Entry::ArrayOfStrings, entry :tags, Entry::Tags,
description: 'Set the tags.', description: 'Set the tags.',
inherit: true inherit: true
......
# frozen_string_literal: true
module Gitlab
module Ci
class Config
module Entry
##
# Entry that represents an array of tags.
#
class Tags < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
TAGS_LIMIT = 50
validations do
validates :config, array_of_strings: true
validate do
next unless ::Feature.enabled?(:ci_build_tags_limit, default_enabled: :yaml)
if config.is_a?(Array) && config.size >= TAGS_LIMIT
errors.add(:config, _("must be less than the limit of %{tag_limit} tags") % { tag_limit: TAGS_LIMIT })
end
end
end
end
end
end
end
end
...@@ -39962,6 +39962,9 @@ msgstr "" ...@@ -39962,6 +39962,9 @@ msgstr ""
msgid "must be inside the fork network" msgid "must be inside the fork network"
msgstr "" msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
msgid "must be unique by status and elapsed time within a policy" msgid "must be unique by status and elapsed time within a policy"
msgstr "" msgstr ""
......
...@@ -618,6 +618,29 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do ...@@ -618,6 +618,29 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
end end
end end
end end
context 'when job is using tags' do
context 'when limit is reached' do
let(:tags) { Array.new(100) { |i| "tag-#{i}" } }
let(:config) { { tags: tags, script: 'test' } }
it 'returns error', :aggregate_failures do
expect(entry).not_to be_valid
expect(entry.errors)
.to include "tags config must be less than the limit of #{Gitlab::Ci::Config::Entry::Tags::TAGS_LIMIT} tags"
end
end
context 'when limit is not reached' do
let(:config) { { tags: %w[tag1 tag2], script: 'test' } }
it 'returns a valid entry', :aggregate_failures do
expect(entry).to be_valid
expect(entry.errors).to be_empty
expect(entry.tags).to eq(%w[tag1 tag2])
end
end
end
end end
describe '#manual_action?' do describe '#manual_action?' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::Entry::Tags do
let(:entry) { described_class.new(config) }
describe 'validation' do
context 'when tags config value is correct' do
let(:config) { %w[tag1 tag2] }
describe '#value' do
it 'returns tags configuration' do
expect(entry.value).to eq config
end
end
describe '#valid?' do
it 'is valid' do
expect(entry).to be_valid
end
end
end
context 'when entry value is not correct' do
describe '#errors' do
context 'when tags config is not an array of strings' do
let(:config) { [1, 2] }
it 'reports error' do
expect(entry.errors)
.to include 'tags config should be an array of strings'
end
end
context 'when tags limit is reached' do
let(:config) { Array.new(50) {|i| "tag-#{i}" } }
context 'when ci_build_tags_limit is enabled' do
before do
stub_feature_flags(ci_build_tags_limit: true)
end
it 'reports error' do
expect(entry.errors)
.to include "tags config must be less than the limit of #{described_class::TAGS_LIMIT} tags"
end
end
context 'when ci_build_tags_limit is disabled' do
before do
stub_feature_flags(ci_build_tags_limit: false)
end
it 'does not report an error' do
expect(entry.errors).to be_empty
end
end
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService do
describe 'tags:' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.owner }
let(:ref) { 'refs/heads/master' }
let(:source) { :push }
let(:service) { described_class.new(project, user, { ref: ref }) }
let(:pipeline) { service.execute(source).payload }
before do
stub_ci_pipeline_yaml_file(config)
end
context 'with valid config' do
let(:config) { YAML.dump({ test: { script: 'ls', tags: %w[tag1 tag2] } }) }
it 'creates a pipeline', :aggregate_failures do
expect(pipeline).to be_created_successfully
expect(pipeline.builds.first.tag_list).to eq(%w[tag1 tag2])
end
end
context 'with too many tags' do
let(:tags) { Array.new(50) {|i| "tag-#{i}" } }
let(:config) { YAML.dump({ test: { script: 'ls', tags: tags } }) }
it 'creates a pipeline without builds', :aggregate_failures do
expect(pipeline).not_to be_created_successfully
expect(pipeline.builds).to be_empty
expect(pipeline.yaml_errors).to eq("jobs:test:tags config must be less than the limit of #{Gitlab::Ci::Config::Entry::Tags::TAGS_LIMIT} tags")
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment