summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-11-01 12:06:26 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-11-01 12:06:26 +0000
commitdeed6022efe0149d88c57ef1df736c83465643f9 (patch)
tree4cf4c7c1ce765e83547129607b6bd3881c0fad6b
parentf7a13c56bf0ed7ff9591bf4cbf9e50487255c4bc (diff)
downloadgitlab-ce-deed6022efe0149d88c57ef1df736c83465643f9.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/controllers/users_controller.rb10
-rw-r--r--config/routes/user.rb1
-rw-r--r--doc/administration/gitaly/praefect.md47
-rw-r--r--doc/administration/integration/plantuml.md2
-rw-r--r--lib/gitlab/ci/config/entry/job.rb6
-rw-r--r--lib/gitlab/ci/config/entry/need.rb44
-rw-r--r--lib/gitlab/ci/config/entry/needs.rb55
-rw-r--r--lib/gitlab/ci/yaml_processor.rb16
-rw-r--r--lib/gitlab/config/entry/configurable.rb29
-rw-r--r--lib/gitlab/config/entry/node.rb4
-rw-r--r--lib/gitlab/config/entry/simplifiable.rb11
-rw-r--r--lib/gitlab/config/entry/validatable.rb21
-rw-r--r--spec/controllers/users_controller_spec.rb42
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb17
-rw-r--r--spec/lib/gitlab/ci/config/entry/need_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/config/entry/needs_spec.rb84
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb15
17 files changed, 151 insertions, 289 deletions
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index c3c227b08c5..06374736dcf 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -16,7 +16,7 @@ class UsersController < ApplicationController
skip_before_action :authenticate_user!
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
- before_action :user, except: [:exists]
+ before_action :user, except: [:exists, :suggests]
before_action :authorize_read_user_profile!,
only: [:calendar, :calendar_activities, :groups, :projects, :contributed_projects, :starred_projects, :snippets]
@@ -114,6 +114,14 @@ class UsersController < ApplicationController
render json: { exists: !!Namespace.find_by_path_or_name(params[:username]) }
end
+ def suggests
+ namespace_path = params[:username]
+ exists = !!Namespace.find_by_path_or_name(namespace_path)
+ suggestions = exists ? [Namespace.clean_path(namespace_path)] : []
+
+ render json: { exists: exists, suggests: suggestions }
+ end
+
private
def user
diff --git a/config/routes/user.rb b/config/routes/user.rb
index 6e277f18e36..31af321d2b2 100644
--- a/config/routes/user.rb
+++ b/config/routes/user.rb
@@ -55,6 +55,7 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
get :starred, as: :starred_projects
get :snippets
get :exists
+ get :suggests
get :activity
get '/', to: redirect('%{username}'), as: nil
end
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index 9038675a28f..1973ed39b89 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -50,10 +50,9 @@ In their own machine, configure the Gitaly server as described in the
#### Praefect
-Next, Praefect has to be enabled on its own node. Disable all other services,
-and add each Gitaly node that will be connected to Praefect. In the example below,
-the Gitaly nodes are named `praefect-git-X`. Note that one node is designated as
-primary, by setting the primary to `true`:
+Next, Praefect has to be enabled on its own node.
+
+##### Disable other services
```ruby
# /etc/gitlab/gitlab.rb
@@ -67,27 +66,36 @@ unicorn['enable'] = false
sidekiq['enable'] = false
gitlab_workhorse['enable'] = false
gitaly['enable'] = false
+```
+
+##### Set up Praefect and its Gitaly nodes
+
+In the example below, the Gitaly nodes are named `praefect-git-X`. Note that one node is designated as
+primary, by setting the primary to `true`:
+
+```ruby
+# /etc/gitlab/gitlab.rb
# virtual_storage_name must match the same storage name given to praefect in git_data_dirs
praefect['virtual_storage_name'] = 'praefect'
-praefect['auth_token'] = 'super_secret_abc'
+praefect['auth_token'] = 'abc123secret'
praefect['enable'] = true
praefect['storage_nodes'] = [
{
'storage' => 'praefect-git-1',
'address' => 'tcp://praefect-git-1.internal',
- 'token' => 'token1',
+ 'token' => 'xyz123secret',
'primary' => true
},
{
'storage' => 'praefect-git-2',
'address' => 'tcp://praefect-git-2.internal',
- 'token' => 'token2'
+ 'token' => 'xyz456secret',
},
{
'storage' => 'praefect-git-3',
'address' => 'tcp://praefect-git-3.internal',
- 'token' => 'token3'
+ 'token' => 'xyz789secret',
}
]
```
@@ -97,7 +105,28 @@ Save the file and [reconfigure Praefect](../restart_gitlab.md#omnibus-gitlab-rec
#### GitLab
When Praefect is running, it should be exposed as a storage to GitLab. This
-is done through setting the `git_data_dirs`. Assuming the default storage
+is done through setting the `git_data_dirs`.
+
+##### On a fresh GitLab installation
+
+On a fresh Gitlab installation, set up the `default` storage to point to praefect:
+
+```ruby
+git_data_dirs({
+ "default" => {
+ "gitaly_address" => "tcp://praefect.internal:2305"
+ },
+})
+```
+
+##### On an existing GitLab instance
+
+On an existing GitLab instance, the `default` storage is already being served by a
+Gitaly node, so an additional storage can be added. `praefect` is chosen in the example
+below, but it can be any name as long as it matches the `virtual_storage_name` in the
+praefect attributes above.
+
+Assuming the default storage
configuration is used, there would be two storages available to GitLab:
```ruby
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index e595c640aac..23803b82543 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -96,7 +96,7 @@ To enable the redirection, add the following line in `/etc/gitlab/gitlab.rb`:
nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n proxy_cache off; \n proxy_pass http://plantuml:8080/; \n}\n"
# Built from source
-nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n proxy_cache off; \n proxy_pass http://127.0.0.1:8080/plantuml/; \n}\n"
+nginx['custom_gitlab_server_config'] = "location /-/plantuml { \n rewrite ^/-/(plantuml.*) /$1 break;\n proxy_cache off; \n proxy_pass http://localhost:8080/plantuml; \n}\n"
```
To activate the changes, run the following command:
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index 2d5981a4255..1298e2d3462 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -50,6 +50,7 @@ module Gitlab
validates :timeout, duration: { limit: ChronicDuration.output(Project::MAX_BUILD_TIMEOUT) }
validates :dependencies, array_of_strings: true
+ validates :needs, array_of_strings: true
validates :extends, array_of_strings_or_string: true
validates :rules, array_of_hashes: true
end
@@ -113,11 +114,6 @@ module Gitlab
description: 'List of evaluable Rules to determine job inclusion.',
inherit: false
- entry :needs, Entry::Needs,
- description: 'Needs configuration for this job.',
- metadata: { allowed_needs: %i[job] },
- inherit: false
-
entry :variables, Entry::Variables,
description: 'Environment variables available for this job.',
inherit: false
diff --git a/lib/gitlab/ci/config/entry/need.rb b/lib/gitlab/ci/config/entry/need.rb
deleted file mode 100644
index b6db546d8ff..00000000000
--- a/lib/gitlab/ci/config/entry/need.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Ci
- class Config
- module Entry
- class Need < ::Gitlab::Config::Entry::Simplifiable
- strategy :Job, if: -> (config) { config.is_a?(String) }
-
- class Job < ::Gitlab::Config::Entry::Node
- include ::Gitlab::Config::Entry::Validatable
-
- validations do
- validates :config, presence: true
- validates :config, type: String
- end
-
- def type
- :job
- end
-
- def value
- { name: @config }
- end
- end
-
- class UnknownStrategy < ::Gitlab::Config::Entry::Node
- def type
- end
-
- def value
- end
-
- def errors
- ["#{location} has an unsupported type"]
- end
- end
- end
- end
- end
- end
-end
-
-::Gitlab::Ci::Config::Entry::Need.prepend_if_ee('::EE::Gitlab::Ci::Config::Entry::Need')
diff --git a/lib/gitlab/ci/config/entry/needs.rb b/lib/gitlab/ci/config/entry/needs.rb
deleted file mode 100644
index 28452aaaa16..00000000000
--- a/lib/gitlab/ci/config/entry/needs.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Ci
- class Config
- module Entry
- ##
- # Entry that represents a set of needs dependencies.
- #
- class Needs < ::Gitlab::Config::Entry::Node
- include ::Gitlab::Config::Entry::Validatable
-
- validations do
- validates :config, presence: true
-
- validate do
- unless config.is_a?(Hash) || config.is_a?(Array)
- errors.add(:config, 'can only be a Hash or an Array')
- end
- end
-
- validate on: :composed do
- extra_keys = value.keys - opt(:allowed_needs)
- if extra_keys.any?
- errors.add(:config, "uses invalid types: #{extra_keys.join(', ')}")
- end
- end
- end
-
- def compose!(deps = nil)
- super(deps) do
- [@config].flatten.each_with_index do |need, index|
- @entries[index] = ::Gitlab::Config::Entry::Factory.new(Entry::Need)
- .value(need)
- .with(key: "need", parent: self, description: "need definition.") # rubocop:disable CodeReuse/ActiveRecord
- .create!
- end
-
- @entries.each_value do |entry|
- entry.compose!(deps)
- end
- end
- end
-
- def value
- values = @entries.values.select(&:type)
- values.group_by(&:type).transform_values do |values|
- values.map(&:value)
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb
index c2a55fa8b1b..f6a3abefcfb 100644
--- a/lib/gitlab/ci/yaml_processor.rb
+++ b/lib/gitlab/ci/yaml_processor.rb
@@ -40,7 +40,7 @@ module Gitlab
environment: job[:environment_name],
coverage_regex: job[:coverage],
yaml_variables: yaml_variables(name),
- needs_attributes: job.dig(:needs, :job),
+ needs_attributes: job[:needs]&.map { |need| { name: need } },
interruptible: job[:interruptible],
rules: job[:rules],
options: {
@@ -59,7 +59,7 @@ module Gitlab
instance: job[:instance],
start_in: job[:start_in],
trigger: job[:trigger],
- bridge_needs: job.dig(:needs, :bridge)&.first
+ bridge_needs: job[:needs]
}.compact }.compact
end
@@ -159,19 +159,17 @@ module Gitlab
end
def validate_job_needs!(name, job)
- return unless job.dig(:needs, :job)
+ return unless job[:needs]
stage_index = @stages.index(job[:stage])
- job.dig(:needs, :job).each do |need|
- need_job_name = need[:name]
+ job[:needs].each do |need|
+ raise ValidationError, "#{name} job: undefined need: #{need}" unless @jobs[need.to_sym]
- raise ValidationError, "#{name} job: undefined need: #{need_job_name}" unless @jobs[need_job_name.to_sym]
-
- needs_stage_index = @stages.index(@jobs[need_job_name.to_sym][:stage])
+ needs_stage_index = @stages.index(@jobs[need.to_sym][:stage])
unless needs_stage_index.present? && needs_stage_index < stage_index
- raise ValidationError, "#{name} job: need #{need_job_name} is not defined in prior stages"
+ raise ValidationError, "#{name} job: need #{need} is not defined in prior stages"
end
end
end
diff --git a/lib/gitlab/config/entry/configurable.rb b/lib/gitlab/config/entry/configurable.rb
index bda84dc2cff..b7ec4b7c4f8 100644
--- a/lib/gitlab/config/entry/configurable.rb
+++ b/lib/gitlab/config/entry/configurable.rb
@@ -29,24 +29,22 @@ module Gitlab
def compose!(deps = nil)
return unless valid?
- super do
- self.class.nodes.each do |key, factory|
- # If we override the config type validation
- # we can end with different config types like String
- next unless config.is_a?(Hash)
+ self.class.nodes.each do |key, factory|
+ # If we override the config type validation
+ # we can end with different config types like String
+ next unless config.is_a?(Hash)
- factory
- .value(config[key])
- .with(key: key, parent: self)
+ factory
+ .value(config[key])
+ .with(key: key, parent: self)
- entries[key] = factory.create!
- end
+ entries[key] = factory.create!
+ end
- yield if block_given?
+ yield if block_given?
- entries.each_value do |entry|
- entry.compose!(deps)
- end
+ entries.each_value do |entry|
+ entry.compose!(deps)
end
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -69,13 +67,12 @@ module Gitlab
private
# rubocop: disable CodeReuse/ActiveRecord
- def entry(key, entry, description: nil, default: nil, inherit: nil, reserved: nil, metadata: {})
+ def entry(key, entry, description: nil, default: nil, inherit: nil, reserved: nil)
factory = ::Gitlab::Config::Entry::Factory.new(entry)
.with(description: description)
.with(default: default)
.with(inherit: inherit)
.with(reserved: reserved)
- .metadata(metadata)
(@nodes ||= {}).merge!(key.to_sym => factory)
end
diff --git a/lib/gitlab/config/entry/node.rb b/lib/gitlab/config/entry/node.rb
index 84d3409ed91..e014f15fbd8 100644
--- a/lib/gitlab/config/entry/node.rb
+++ b/lib/gitlab/config/entry/node.rb
@@ -112,10 +112,6 @@ module Gitlab
@aspects ||= []
end
- def self.with_aspect(blk)
- self.aspects.append(blk)
- end
-
private
attr_reader :entries
diff --git a/lib/gitlab/config/entry/simplifiable.rb b/lib/gitlab/config/entry/simplifiable.rb
index 315f1947e2c..d58aba07d15 100644
--- a/lib/gitlab/config/entry/simplifiable.rb
+++ b/lib/gitlab/config/entry/simplifiable.rb
@@ -4,11 +4,11 @@ module Gitlab
module Config
module Entry
class Simplifiable < SimpleDelegator
- EntryStrategy = Struct.new(:name, :klass, :condition)
+ EntryStrategy = Struct.new(:name, :condition)
attr_reader :subject
- def initialize(config, **metadata, &blk)
+ def initialize(config, **metadata)
unless self.class.const_defined?(:UnknownStrategy)
raise ArgumentError, 'UndefinedStrategy not available!'
end
@@ -19,13 +19,14 @@ module Gitlab
entry = self.class.entry_class(strategy)
- @subject = entry.new(config, metadata, &blk)
+ @subject = entry.new(config, metadata)
+ yield(@subject) if block_given?
super(@subject)
end
def self.strategy(name, **opts)
- EntryStrategy.new(name, opts.dig(:class), opts.fetch(:if)).tap do |strategy|
+ EntryStrategy.new(name, opts.fetch(:if)).tap do |strategy|
strategies.append(strategy)
end
end
@@ -36,7 +37,7 @@ module Gitlab
def self.entry_class(strategy)
if strategy.present?
- strategy.klass || self.const_get(strategy.name, false)
+ self.const_get(strategy.name, false)
else
self::UnknownStrategy
end
diff --git a/lib/gitlab/config/entry/validatable.rb b/lib/gitlab/config/entry/validatable.rb
index 45b852dc2e0..1c88c68c11c 100644
--- a/lib/gitlab/config/entry/validatable.rb
+++ b/lib/gitlab/config/entry/validatable.rb
@@ -7,27 +7,14 @@ module Gitlab
extend ActiveSupport::Concern
def self.included(node)
- node.with_aspect -> do
- validate(:new)
+ node.aspects.append -> do
+ @validator = self.class.validator.new(self)
+ @validator.validate(:new)
end
end
- def validator
- @validator ||= self.class.validator.new(self)
- end
-
- def validate(context = nil)
- validator.validate(context)
- end
-
- def compose!(deps = nil, &blk)
- super(deps, &blk)
-
- validate(:composed)
- end
-
def errors
- validator.messages + descendants.flat_map(&:errors)
+ @validator.messages + descendants.flat_map(&:errors) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
class_methods do
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 5566df0c216..fa057dc5b07 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -348,6 +348,48 @@ describe UsersController do
end
end
+ describe 'GET #suggests' do
+ context 'when user exists' do
+ it 'returns JSON indicating the user exists and a suggestion' do
+ get :suggests, params: { username: user.username }
+
+ expected_json = { exists: true, suggests: ["#{user.username}1"] }.to_json
+ expect(response.body).to eq(expected_json)
+ end
+
+ context 'when the casing is different' do
+ let(:user) { create(:user, username: 'CamelCaseUser') }
+
+ it 'returns JSON indicating the user exists and a suggestion' do
+ get :suggests, params: { username: user.username.downcase }
+
+ expected_json = { exists: true, suggests: ["#{user.username.downcase}1"] }.to_json
+ expect(response.body).to eq(expected_json)
+ end
+ end
+ end
+
+ context 'when the user does not exist' do
+ it 'returns JSON indicating the user does not exist' do
+ get :suggests, params: { username: 'foo' }
+
+ expected_json = { exists: false, suggests: [] }.to_json
+ expect(response.body).to eq(expected_json)
+ end
+
+ context 'when a user changed their username' do
+ let(:redirect_route) { user.namespace.redirect_routes.create(path: 'old-username') }
+
+ it 'returns JSON indicating a user by that username does not exist' do
+ get :suggests, params: { username: 'old-username' }
+
+ expected_json = { exists: false, suggests: [] }.to_json
+ expect(response.body).to eq(expected_json)
+ end
+ end
+ end
+ end
+
describe '#ensure_canonical_path' do
before do
sign_in(user)
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 9fe18caf689..d3eb5a9663f 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -23,7 +23,7 @@ describe Gitlab::Ci::Config::Entry::Job do
let(:result) do
%i[before_script script stage type after_script cache
- image services only except rules needs variables artifacts
+ image services only except rules variables artifacts
environment coverage retry]
end
@@ -384,6 +384,21 @@ describe Gitlab::Ci::Config::Entry::Job do
end
context 'when has needs' do
+ context 'that are not a array of strings' do
+ let(:config) do
+ {
+ stage: 'test',
+ script: 'echo',
+ needs: 'build-job'
+ }
+ end
+
+ it 'returns error about invalid type' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include 'job needs should be an array of strings'
+ end
+ end
+
context 'when have dependencies that are not subset of needs' do
let(:config) do
{
diff --git a/spec/lib/gitlab/ci/config/entry/need_spec.rb b/spec/lib/gitlab/ci/config/entry/need_spec.rb
deleted file mode 100644
index d119e604900..00000000000
--- a/spec/lib/gitlab/ci/config/entry/need_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe ::Gitlab::Ci::Config::Entry::Need do
- subject(:need) { described_class.new(config) }
-
- context 'when job is specified' do
- let(:config) { 'job_name' }
-
- describe '#valid?' do
- it { is_expected.to be_valid }
- end
-
- describe '#value' do
- it 'returns job needs configuration' do
- expect(need.value).to eq(name: 'job_name')
- end
- end
- end
-
- context 'when need is empty' do
- let(:config) { '' }
-
- describe '#valid?' do
- it { is_expected.not_to be_valid }
- end
-
- describe '#errors' do
- it 'is returns an error about an empty config' do
- expect(need.errors)
- .to contain_exactly("job config can't be blank")
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/ci/config/entry/needs_spec.rb b/spec/lib/gitlab/ci/config/entry/needs_spec.rb
deleted file mode 100644
index f4a76b52d30..00000000000
--- a/spec/lib/gitlab/ci/config/entry/needs_spec.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe ::Gitlab::Ci::Config::Entry::Needs do
- subject(:needs) { described_class.new(config) }
-
- before do
- needs.metadata[:allowed_needs] = %i[job]
- end
-
- describe 'validations' do
- before do
- needs.compose!
- end
-
- context 'when entry config value is correct' do
- let(:config) { ['job_name'] }
-
- describe '#valid?' do
- it { is_expected.to be_valid }
- end
- end
-
- context 'when config value has wrong type' do
- let(:config) { 123 }
-
- describe '#valid?' do
- it { is_expected.not_to be_valid }
- end
-
- describe '#errors' do
- it 'returns error about incorrect type' do
- expect(needs.errors)
- .to include('needs config can only be a hash or an array')
- end
- end
- end
-
- context 'when wrong needs type is used' do
- let(:config) { [123] }
-
- describe '#valid?' do
- it { is_expected.not_to be_valid }
- end
-
- describe '#errors' do
- it 'returns error about incorrect type' do
- expect(needs.errors).to contain_exactly(
- 'need has an unsupported type')
- end
- end
- end
- end
-
- describe '.compose!' do
- context 'when valid job entries composed' do
- let(:config) { %w[first_job_name second_job_name] }
-
- before do
- needs.compose!
- end
-
- describe '#value' do
- it 'returns key value' do
- expect(needs.value).to eq(
- job: [
- { name: 'first_job_name' },
- { name: 'second_job_name' }
- ]
- )
- end
- end
-
- describe '#descendants' do
- it 'creates valid descendant nodes' do
- expect(needs.descendants.count).to eq 2
- expect(needs.descendants)
- .to all(be_an_instance_of(::Gitlab::Ci::Config::Entry::Need))
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index c7ea6ed9ddb..c747ea670bb 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -1293,7 +1293,7 @@ module Gitlab
end
end
- describe "Job Needs" do
+ describe "Needs" do
let(:needs) { }
let(:dependencies) { }
@@ -1333,7 +1333,12 @@ module Gitlab
stage: "test",
stage_idx: 2,
name: "test1",
- options: { script: ["test"] },
+ options: {
+ script: ["test"],
+ # This does not make sense, there is a follow-up:
+ # https://gitlab.com/gitlab-org/gitlab-foss/issues/65569
+ bridge_needs: %w[build1 build2]
+ },
needs_attributes: [
{ name: "build1" },
{ name: "build2" }
@@ -1345,6 +1350,12 @@ module Gitlab
end
end
+ context 'needs two builds defined as symbols' do
+ let(:needs) { [:build1, :build2] }
+
+ it { expect { subject }.not_to raise_error }
+ end
+
context 'undefined need' do
let(:needs) { ['undefined'] }