Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
a4ae95ad
Commit
a4ae95ad
authored
Jan 18, 2017
by
Kamil Trzcinski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve EE compatibility
parent
c264fc76
Changes
18
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
384 additions
and
1620 deletions
+384
-1620
app/controllers/admin/groups_controller.rb
app/controllers/admin/groups_controller.rb
+2
-2
app/controllers/groups/pipeline_quota_controller.rb
app/controllers/groups/pipeline_quota_controller.rb
+1
-1
app/models/ci/build.rb
app/models/ci/build.rb
+1
-10
app/models/ee/build.rb
app/models/ee/build.rb
+13
-0
app/models/ee/namespace.rb
app/models/ee/namespace.rb
+31
-0
app/models/ee/project.rb
app/models/ee/project.rb
+31
-0
app/models/namespace.rb
app/models/namespace.rb
+1
-20
app/models/project.rb
app/models/project.rb
+7
-15
app/views/projects/builds/_shared_runner_limit_warning.html.haml
...ws/projects/builds/_shared_runner_limit_warning.html.haml
+6
-5
app/workers/build_finished_worker.rb
app/workers/build_finished_worker.rb
+1
-0
db/schema.rb
db/schema.rb
+2
-2
lib/gitlab/visibility_level.rb
lib/gitlab/visibility_level.rb
+1
-0
spec/models/build_spec.rb
spec/models/build_spec.rb
+0
-1366
spec/models/ee/ci/build_spec.rb
spec/models/ee/ci/build_spec.rb
+56
-0
spec/models/ee/namespace_spec.rb
spec/models/ee/namespace_spec.rb
+136
-0
spec/models/ee/project_spec.rb
spec/models/ee/project_spec.rb
+93
-0
spec/models/namespace_spec.rb
spec/models/namespace_spec.rb
+0
-130
spec/models/project_spec.rb
spec/models/project_spec.rb
+2
-69
No files found.
app/controllers/admin/groups_controller.rb
View file @
a4ae95ad
...
...
@@ -72,14 +72,14 @@ class Admin::GroupsController < Admin::ApplicationController
:name
,
:path
,
:request_access_enabled
,
:shared_runners_minutes_limit
,
:visibility_level
]
end
def
group_params_ee
[
:repository_size_limit
:repository_size_limit
,
:shared_runners_minutes_limit
]
end
end
app/controllers/groups/pipeline_quota_controller.rb
View file @
a4ae95ad
...
...
@@ -4,6 +4,6 @@ class Groups::PipelineQuotaController < Groups::ApplicationController
layout
'group_settings'
def
index
@projects
=
@group
.
projects
.
w
here
(
shared_runners_enabled:
true
)
.
page
(
params
[
:page
])
@projects
=
@group
.
projects
.
w
ith_shared_runners
.
page
(
params
[
:page
])
end
end
app/models/ci/build.rb
View file @
a4ae95ad
...
...
@@ -2,6 +2,7 @@ module Ci
class
Build
<
CommitStatus
include
TokenAuthenticatable
include
AfterCommitQueue
include
EE
::
Build
belongs_to
:runner
belongs_to
:trigger_request
...
...
@@ -103,12 +104,6 @@ module Ci
end
end
after_transition
any
=>
[
:success
,
:failed
,
:canceled
]
do
|
build
|
build
.
run_after_commit
do
UpdateBuildMinutesService
.
new
(
project
,
nil
).
execute
(
self
)
end
end
after_transition
any
=>
[
:success
]
do
|
build
|
build
.
run_after_commit
do
BuildSuccessWorker
.
perform_async
(
id
)
...
...
@@ -539,10 +534,6 @@ module Ci
Gitlab
::
Ci
::
Build
::
Credentials
::
Factory
.
new
(
self
).
create!
end
def
shared_runners_minutes_quota?
runner
&&
runner
.
shared?
&&
project
.
shared_runners_minutes_quota?
end
private
def
update_artifacts_size
...
...
app/models/ee/build.rb
0 → 100644
View file @
a4ae95ad
module
EE
# Build EE mixin
#
# This module is intended to encapsulate EE-specific model logic
# and be included in the `Build` model
module
Build
extend
ActiveSupport
::
Concern
def
shared_runners_minutes_quota?
runner
&&
runner
.
shared?
&&
project
.
shared_runners_minutes_quota?
end
end
end
app/models/ee/namespace.rb
0 → 100644
View file @
a4ae95ad
module
EE
# Namespace EE mixin
#
# This module is intended to encapsulate EE-specific model logic
# and be included in the `Namespace` model
module
Namespace
extend
ActiveSupport
::
Concern
included
do
has_one
:namespace_metrics
,
dependent: :destroy
delegate
:shared_runners_minutes
,
:shared_runners_minutes_last_reset
,
to: :namespace_metrics
,
allow_nil:
true
end
def
actual_shared_runners_minutes_limit
shared_runners_minutes_limit
||
current_application_settings
.
shared_runners_minutes
end
def
shared_runners_minutes_limit_enabled?
shared_runners_enabled?
&&
actual_shared_runners_minutes_limit
.
nonzero?
end
def
shared_runners_minutes_used?
shared_runners_minutes_limit_enabled?
&&
shared_runners_minutes
.
to_i
>=
actual_shared_runners_minutes_limit
end
end
end
app/models/ee/project.rb
0 → 100644
View file @
a4ae95ad
module
EE
# Project EE mixin
#
# This module is intended to encapsulate EE-specific model logic
# and be included in the `Project` model
module
Project
extend
ActiveSupport
::
Concern
included
do
delegate
:shared_runners_minutes
,
:shared_runners_minutes_last_reset
,
to: :project_metrics
,
allow_nil:
true
delegate
:shared_runners_minutes_limit_enabled?
,
:actual_shared_runners_minutes_limit
,
:shared_runners_minutes_used?
,
to: :namespace
has_one
:project_metrics
,
dependent: :destroy
end
def
shared_runners_minutes_quota?
!
public
?
&&
shared_runners_enabled?
end
def
shared_runners
if
shared_runners_enabled?
&&
!
namespace
.
shared_runners_minutes_used?
Ci
::
Runner
.
shared
else
Ci
::
Runner
.
none
end
end
end
end
app/models/namespace.rb
View file @
a4ae95ad
class
Namespace
<
ActiveRecord
::
Base
acts_as_paranoid
include
EE
::
Namespace
include
CacheMarkdownField
include
Sortable
include
Gitlab
::
ShellAdapter
...
...
@@ -10,8 +11,6 @@ class Namespace < ActiveRecord::Base
cache_markdown_field
:description
,
pipeline: :description
has_many
:projects
,
dependent: :destroy
has_one
:namespace_metrics
,
dependent: :destroy
has_many
:project_statistics
belongs_to
:owner
,
class_name:
"User"
...
...
@@ -40,9 +39,6 @@ class Namespace < ActiveRecord::Base
before_destroy
(
prepend:
true
)
{
@old_repository_storage_paths
=
repository_storage_paths
}
after_destroy
:rm_dir
delegate
:shared_runners_minutes
,
:shared_runners_minutes_last_reset
,
to: :namespace_metrics
,
allow_nil:
true
scope
:root
,
->
{
where
(
'type IS NULL'
)
}
scope
:with_statistics
,
->
do
...
...
@@ -189,21 +185,6 @@ class Namespace < ActiveRecord::Base
projects
.
where
(
shared_runners_enabled:
true
).
any?
end
def
actual_shared_runners_minutes_limit
shared_runners_minutes_limit
||
current_application_settings
.
shared_runners_minutes
end
def
shared_runners_minutes_limit_enabled?
shared_runners_enabled?
&&
actual_shared_runners_minutes_limit
.
nonzero?
end
def
shared_runners_minutes_used?
shared_runners_minutes_limit_enabled?
&&
shared_runners_minutes
.
to_i
>=
actual_shared_runners_minutes_limit
end
def
full_name
@full_name
||=
if
parent
...
...
app/models/project.rb
View file @
a4ae95ad
...
...
@@ -18,6 +18,7 @@ class Project < ActiveRecord::Base
include
SelectForProjectAuthorization
include
Routable
prepend
EE
::
GeoAwareAvatar
include
EE
::
Project
extend
Gitlab
::
ConfigHelper
...
...
@@ -29,12 +30,6 @@ class Project < ActiveRecord::Base
:merge_requests_enabled?
,
:issues_enabled?
,
to: :project_feature
,
allow_nil:
true
delegate
:shared_runners_minutes
,
:shared_runners_minutes_last_reset
,
to: :project_metrics
,
allow_nil:
true
delegate
:shared_runners_minutes_limit_enabled?
,
:actual_shared_runners_minutes_limit
,
:shared_runners_minutes_used?
,
to: :namespace
default_value_for
:archived
,
false
default_value_for
:visibility_level
,
gitlab_config_features
.
visibility_level
default_value_for
:container_registry_enabled
,
gitlab_config_features
.
container_registry
...
...
@@ -82,8 +77,6 @@ class Project < ActiveRecord::Base
belongs_to
:namespace
belongs_to
:mirror_user
,
foreign_key:
'mirror_user_id'
,
class_name:
'User'
has_one
:project_metrics
,
dependent: :destroy
has_one
:push_rule
,
dependent: :destroy
has_one
:last_event
,
->
{
order
'events.created_at DESC'
},
class_name:
'Event'
has_many
:boards
,
dependent: :destroy
...
...
@@ -253,6 +246,7 @@ class Project < ActiveRecord::Base
scope
:with_project_feature
,
->
{
joins
(
'LEFT JOIN project_features ON projects.id = project_features.project_id'
)
}
scope
:with_statistics
,
->
{
includes
(
:statistics
)
}
scope
:with_shared_runners_limit_enabled
,
->
{
where
(
shared_runners_enabled:
true
).
non_public_only
}
# "enabled" here means "not disabled". It includes private features!
scope
:with_feature_enabled
,
->
(
feature
)
{
...
...
@@ -1247,14 +1241,16 @@ class Project < ActiveRecord::Base
project_feature
.
update_attribute
(
:builds_access_level
,
ProjectFeature
::
ENABLED
)
end
def
shared_runners
shared_runners_enabled?
?
Ci
::
Runner
.
shared
:
Ci
::
Runner
.
none
end
unless
defined?
(
:shared_runners
)
def
any_runners?
(
&
block
)
if
runners
.
active
.
any?
(
&
block
)
return
true
end
shared_runners_enabled?
&&
!
namespace
.
shared_runners_minutes_used?
&&
Ci
::
Runner
.
shared
.
active
.
any?
(
&
block
)
shared_runners
.
active
.
any?
(
&
block
)
end
def
valid_runners_token?
(
token
)
...
...
@@ -1569,10 +1565,6 @@ class Project < ActiveRecord::Base
end
end
def
shared_runners_minutes_quota?
!
public
?
&&
shared_runners_enabled?
end
private
# Check if a reference is being done cross-project
...
...
app/views/projects/builds/_shared_runner_limit_warning.html.haml
View file @
a4ae95ad
...
...
@@ -5,6 +5,7 @@
%p
You have used all your shared runner minutes
=
"(
#{
quota_used
}
of
#{
quota_limit
}
)."
-
if
can?
(
current_user
,
:admin_build
,
@project
)
%br
For more information, go to the
=
succeed
"."
do
...
...
app/workers/build_finished_worker.rb
View file @
a4ae95ad
...
...
@@ -4,6 +4,7 @@ class BuildFinishedWorker
def
perform
(
build_id
)
Ci
::
Build
.
find_by
(
id:
build_id
).
try
do
|
build
|
UpdateBuildMinutesService
.
new
(
build
.
project
,
nil
).
execute
(
build
)
BuildCoverageWorker
.
new
.
perform
(
build
.
id
)
BuildHooksWorker
.
new
.
perform
(
build
.
id
)
end
...
...
db/schema.rb
View file @
a4ae95ad
...
...
@@ -863,8 +863,8 @@ ActiveRecord::Schema.define(version: 20170106172224) do
add_index
"namespaces"
,
[
"deleted_at"
],
name:
"index_namespaces_on_deleted_at"
,
using: :btree
add_index
"namespaces"
,
[
"ldap_sync_last_successful_update_at"
],
name:
"index_namespaces_on_ldap_sync_last_successful_update_at"
,
using: :btree
add_index
"namespaces"
,
[
"ldap_sync_last_update_at"
],
name:
"index_namespaces_on_ldap_sync_last_update_at"
,
using: :btree
add_index
"namespaces"
,
[
"name"
],
name:
"index_namespaces_on_name"
,
unique:
true
,
using: :btree
add_index
"namespaces"
,
[
"name"
,
"parent_id"
],
name:
"index_namespaces_on_name_and_parent_id"
,
unique:
true
,
using: :btree
add_index
"namespaces"
,
[
"name"
],
name:
"index_namespaces_on_name"
,
unique:
true
,
using: :btree
add_index
"namespaces"
,
[
"name"
],
name:
"index_namespaces_on_name_trigram"
,
using: :gin
,
opclasses:
{
"name"
=>
"gin_trgm_ops"
}
add_index
"namespaces"
,
[
"owner_id"
],
name:
"index_namespaces_on_owner_id"
,
using: :btree
add_index
"namespaces"
,
[
"parent_id"
,
"id"
],
name:
"index_namespaces_on_parent_id_and_id"
,
unique:
true
,
using: :btree
...
...
@@ -1522,8 +1522,8 @@ ActiveRecord::Schema.define(version: 20170106172224) do
add_foreign_key
"project_authorizations"
,
"projects"
,
on_delete: :cascade
add_foreign_key
"project_authorizations"
,
"users"
,
on_delete: :cascade
add_foreign_key
"project_metrics"
,
"projects"
,
on_delete: :cascade
add_foreign_key
"protected_branch_merge_access_levels"
,
"namespaces"
,
column:
"group_id"
add_foreign_key
"project_statistics"
,
"projects"
,
on_delete: :cascade
add_foreign_key
"protected_branch_merge_access_levels"
,
"namespaces"
,
column:
"group_id"
add_foreign_key
"protected_branch_merge_access_levels"
,
"protected_branches"
add_foreign_key
"protected_branch_merge_access_levels"
,
"users"
add_foreign_key
"protected_branch_push_access_levels"
,
"namespaces"
,
column:
"group_id"
...
...
lib/gitlab/visibility_level.rb
View file @
a4ae95ad
...
...
@@ -11,6 +11,7 @@ module Gitlab
included
do
scope
:public_only
,
->
{
where
(
visibility_level:
PUBLIC
)
}
scope
:public_and_internal_only
,
->
{
where
(
visibility_level:
[
PUBLIC
,
INTERNAL
]
)
}
scope
:non_public_only
,
->
{
where
.
not
(
visibility_level:
PUBLIC
)
}
scope
:public_to_user
,
->
(
user
)
{
user
&&
!
user
.
external
?
public_and_internal_only
:
public_only
}
end
...
...
spec/models/build_spec.rb
deleted
100644 → 0
View file @
c264fc76
require
'spec_helper'
describe
Ci
::
Build
,
models:
true
do
let
(
:project
)
{
create
(
:project
)
}
let
(
:pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
,
ref:
project
.
default_branch
,
status:
'success'
)
end
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
it
{
is_expected
.
to
validate_presence_of
:ref
}
it
{
is_expected
.
to
respond_to
:trace_html
}
describe
'#first_pending'
do
let!
(
:first
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
status:
'pending'
,
created_at:
Date
.
yesterday
)
}
let!
(
:second
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
status:
'pending'
)
}
subject
{
Ci
::
Build
.
first_pending
}
it
{
is_expected
.
to
be_a
(
Ci
::
Build
)
}
it
(
'returns with the first pending build'
)
{
is_expected
.
to
eq
(
first
)
}
end
describe
'#create_from'
do
before
do
build
.
status
=
'success'
build
.
save
end
let
(
:create_from_build
)
{
Ci
::
Build
.
create_from
build
}
it
'exists a pending task'
do
expect
(
Ci
::
Build
.
pending
.
count
(
:all
)).
to
eq
0
create_from_build
expect
(
Ci
::
Build
.
pending
.
count
(
:all
)).
to
be
>
0
end
end
describe
'#failed_but_allowed?'
do
subject
{
build
.
failed_but_allowed?
}
context
'when build is not allowed to fail'
do
before
do
build
.
allow_failure
=
false
end
context
'and build.status is success'
do
before
do
build
.
status
=
'success'
end
it
{
is_expected
.
to
be_falsey
}
end
context
'and build.status is failed'
do
before
do
build
.
status
=
'failed'
end
it
{
is_expected
.
to
be_falsey
}
end
end
context
'when build is allowed to fail'
do
before
do
build
.
allow_failure
=
true
end
context
'and build.status is success'
do
before
do
build
.
status
=
'success'
end
it
{
is_expected
.
to
be_falsey
}
end
context
'and build.status is failed'
do
before
do
build
.
status
=
'failed'
end
it
{
is_expected
.
to
be_truthy
}
end
end
end
describe
'#persisted_environment'
do
before
do
@environment
=
create
(
:environment
,
project:
project
,
name:
"foo-
#{
project
.
default_branch
}
"
)
end
subject
{
build
.
persisted_environment
}
context
'referenced literally'
do
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
environment:
"foo-
#{
project
.
default_branch
}
"
)
}
it
{
is_expected
.
to
eq
(
@environment
)
}
end
context
'referenced with a variable'
do
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
environment:
"foo-$CI_BUILD_REF_NAME"
)
}
it
{
is_expected
.
to
eq
(
@environment
)
}
end
end
describe
'#trace'
do
it
{
expect
(
build
.
trace
).
to
be_nil
}
context
'when build.trace contains text'
do
let
(
:text
)
{
'example output'
}
before
do
build
.
trace
=
text
end
it
{
expect
(
build
.
trace
).
to
eq
(
text
)
}
end
context
'when build.trace hides runners token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
update
(
trace:
token
)
build
.
project
.
update
(
runners_token:
token
)
end
it
{
expect
(
build
.
trace
).
not_to
include
(
token
)
}
it
{
expect
(
build
.
raw_trace
).
to
include
(
token
)
}
end
context
'when build.trace hides build token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
update
(
trace:
token
)
build
.
update
(
token:
token
)
end
it
{
expect
(
build
.
trace
).
not_to
include
(
token
)
}
it
{
expect
(
build
.
raw_trace
).
to
include
(
token
)
}
end
end
describe
'#raw_trace'
do
subject
{
build
.
raw_trace
}
context
'when build.trace hides runners token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
project
.
update
(
runners_token:
token
)
build
.
update
(
trace:
token
)
end
it
{
is_expected
.
not_to
include
(
token
)
}
end
context
'when build.trace hides build token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
update
(
token:
token
)
build
.
update
(
trace:
token
)
end
it
{
is_expected
.
not_to
include
(
token
)
}
end
end
context
'#append_trace'
do
subject
{
build
.
trace_html
}
context
'when build.trace hides runners token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
project
.
update
(
runners_token:
token
)
build
.
append_trace
(
token
,
0
)
end
it
{
is_expected
.
not_to
include
(
token
)
}
end
context
'when build.trace hides build token'
do
let
(
:token
)
{
'my_secret_token'
}
before
do
build
.
update
(
token:
token
)
build
.
append_trace
(
token
,
0
)
end
it
{
is_expected
.
not_to
include
(
token
)
}
end
end
# TODO: build timeout
# describe :timeout do
# subject { build.timeout }
#
# it { is_expected.to eq(pipeline.project.timeout) }
# end
describe
'#options'
do
let
(
:options
)
do
{
image:
"ruby:2.1"
,
services:
[
"postgres"
]
}
end
subject
{
build
.
options
}
it
{
is_expected
.
to
eq
(
options
)
}
end
# TODO: allow_git_fetch
# describe :allow_git_fetch do
# subject { build.allow_git_fetch }
#
# it { is_expected.to eq(project.allow_git_fetch) }
# end
describe
'#project'
do
subject
{
build
.
project
}
it
{
is_expected
.
to
eq
(
pipeline
.
project
)
}
end
describe
'#project_id'
do
subject
{
build
.
project_id
}
it
{
is_expected
.
to
eq
(
pipeline
.
project_id
)
}
end
describe
'#project_name'
do
subject
{
build
.
project_name
}
it
{
is_expected
.
to
eq
(
project
.
name
)
}
end
describe
'#extract_coverage'
do
context
'valid content & regex'
do
subject
{
build
.
extract_coverage
(
'Coverage 1033 / 1051 LOC (98.29%) covered'
,
'\(\d+.\d+\%\) covered'
)
}
it
{
is_expected
.
to
eq
(
98.29
)
}
end
context
'valid content & bad regex'
do
subject
{
build
.
extract_coverage
(
'Coverage 1033 / 1051 LOC (98.29%) covered'
,
'very covered'
)
}
it
{
is_expected
.
to
be_nil
}
end
context
'no coverage content & regex'
do
subject
{
build
.
extract_coverage
(
'No coverage for today :sad:'
,
'\(\d+.\d+\%\) covered'
)
}
it
{
is_expected
.
to
be_nil
}
end
context
'multiple results in content & regex'
do
subject
{
build
.
extract_coverage
(
' (98.39%) covered. (98.29%) covered'
,
'\(\d+.\d+\%\) covered'
)
}
it
{
is_expected
.
to
eq
(
98.29
)
}
end
context
'using a regex capture'
do
subject
{
build
.
extract_coverage
(
'TOTAL 9926 3489 65%'
,
'TOTAL\s+\d+\s+\d+\s+(\d{1,3}\%)'
)
}
it
{
is_expected
.
to
eq
(
65
)
}
end
end
describe
'#ref_slug'
do
{
'master'
=>
'master'
,
'1-foo'
=>
'1-foo'
,
'fix/1-foo'
=>
'fix-1-foo'
,
'fix-1-foo'
=>
'fix-1-foo'
,
'a'
*
63
=>
'a'
*
63
,
'a'
*
64
=>
'a'
*
63
,
'FOO'
=>
'foo'
,
}.
each
do
|
ref
,
slug
|
it
"transforms
#{
ref
}
to
#{
slug
}
"
do
build
.
ref
=
ref
expect
(
build
.
ref_slug
).
to
eq
(
slug
)
end
end
end
describe
'#variables'
do
let
(
:container_registry_enabled
)
{
false
}
let
(
:predefined_variables
)
do
[
{
key:
'CI'
,
value:
'true'
,
public:
true
},
{
key:
'GITLAB_CI'
,
value:
'true'
,
public:
true
},
{
key:
'CI_BUILD_ID'
,
value:
build
.
id
.
to_s
,
public:
true
},
{
key:
'CI_BUILD_TOKEN'
,
value:
build
.
token
,
public:
false
},
{
key:
'CI_BUILD_REF'
,
value:
build
.
sha
,
public:
true
},
{
key:
'CI_BUILD_BEFORE_SHA'
,
value:
build
.
before_sha
,
public:
true
},
{
key:
'CI_BUILD_REF_NAME'
,
value:
'master'
,
public:
true
},
{
key:
'CI_BUILD_REF_SLUG'
,
value:
'master'
,
public:
true
},
{
key:
'CI_BUILD_NAME'
,
value:
'test'
,
public:
true
},
{
key:
'CI_BUILD_STAGE'
,
value:
'test'
,
public:
true
},
{
key:
'CI_SERVER_NAME'
,
value:
'GitLab'
,
public:
true
},
{
key:
'CI_SERVER_VERSION'
,
value:
Gitlab
::
VERSION
,
public:
true
},
{
key:
'CI_SERVER_REVISION'
,
value:
Gitlab
::
REVISION
,
public:
true
},
{
key:
'CI_PROJECT_ID'
,
value:
project
.
id
.
to_s
,
public:
true
},
{
key:
'CI_PROJECT_NAME'
,
value:
project
.
path
,
public:
true
},
{
key:
'CI_PROJECT_PATH'
,
value:
project
.
path_with_namespace
,
public:
true
},
{
key:
'CI_PROJECT_NAMESPACE'
,
value:
project
.
namespace
.
path
,
public:
true
},
{
key:
'CI_PROJECT_URL'
,
value:
project
.
web_url
,
public:
true
},
{
key:
'CI_PIPELINE_ID'
,
value:
pipeline
.
id
.
to_s
,
public:
true
}
]
end
before
do
stub_container_registry_config
(
enabled:
container_registry_enabled
,
host_port:
'registry.example.com'
)
end
subject
{
build
.
variables
}
context
'returns variables'
do
before
do
build
.
yaml_variables
=
[]
end
it
{
is_expected
.
to
eq
(
predefined_variables
)
}
end
context
'when build has user'
do
let
(
:user
)
{
create
(
:user
,
username:
'starter'
)
}
let
(
:user_variables
)
do
[
{
key:
'GITLAB_USER_ID'
,
value:
user
.
id
.
to_s
,
public:
true
},
{
key:
'GITLAB_USER_EMAIL'
,
value:
user
.
email
,
public:
true
}
]
end
before
do
build
.
update_attributes
(
user:
user
)
end
it
{
user_variables
.
each
{
|
v
|
is_expected
.
to
include
(
v
)
}
}
end
context
'when build has an environment'
do
before
do
build
.
update
(
environment:
'production'
)
create
(
:environment
,
project:
build
.
project
,
name:
'production'
,
slug:
'prod-slug'
)
end
let
(
:environment_variables
)
do
[
{
key:
'CI_ENVIRONMENT_NAME'
,
value:
'production'
,
public:
true
},
{
key:
'CI_ENVIRONMENT_SLUG'
,
value:
'prod-slug'
,
public:
true
}
]
end
it
{
environment_variables
.
each
{
|
v
|
is_expected
.
to
include
(
v
)
}
}
end
context
'when build started manually'
do
before
do
build
.
update_attributes
(
when: :manual
)
end
let
(
:manual_variable
)
do
{
key:
'CI_BUILD_MANUAL'
,
value:
'true'
,
public:
true
}
end
it
{
is_expected
.
to
include
(
manual_variable
)
}
end
context
'when build is for tag'
do
let
(
:tag_variable
)
do
{
key:
'CI_BUILD_TAG'
,
value:
'master'
,
public:
true
}
end
before
do
build
.
update_attributes
(
tag:
true
)
end
it
{
is_expected
.
to
include
(
tag_variable
)
}
end
context
'when secure variable is defined'
do
let
(
:secure_variable
)
do
{
key:
'SECRET_KEY'
,
value:
'secret_value'
,
public:
false
}
end
before
do
build
.
project
.
variables
<<
Ci
::
Variable
.
new
(
key:
'SECRET_KEY'
,
value:
'secret_value'
)
end
it
{
is_expected
.
to
include
(
secure_variable
)
}
end
context
'when build is for triggers'
do
let
(
:trigger
)
{
create
(
:ci_trigger
,
project:
project
)
}
let
(
:trigger_request
)
{
create
(
:ci_trigger_request_with_variables
,
pipeline:
pipeline
,
trigger:
trigger
)
}
let
(
:user_trigger_variable
)
do
{
key: :TRIGGER_KEY_1
,
value:
'TRIGGER_VALUE_1'
,
public:
false
}
end
let
(
:predefined_trigger_variable
)
do
{
key:
'CI_BUILD_TRIGGERED'
,
value:
'true'
,
public:
true
}
end
before
do
build
.
trigger_request
=
trigger_request
end
it
{
is_expected
.
to
include
(
user_trigger_variable
)
}
it
{
is_expected
.
to
include
(
predefined_trigger_variable
)
}
end
context
'when yaml_variables are undefined'
do
before
do
build
.
yaml_variables
=
nil
end
context
'use from gitlab-ci.yml'
do
before
do
stub_ci_pipeline_yaml_file
(
config
)
end
context
'when config is not found'
do
let
(
:config
)
{
nil
}
it
{
is_expected
.
to
eq
(
predefined_variables
)
}
end
context
'when config does not have a questioned job'
do
let
(
:config
)
do
YAML
.
dump
({
test_other:
{
script:
'Hello World'
}
})
end
it
{
is_expected
.
to
eq
(
predefined_variables
)
}
end
context
'when config has variables'
do
let
(
:config
)
do
YAML
.
dump
({
test:
{
script:
'Hello World'
,
variables:
{
KEY
:
'value'
}
}
})
end
let
(
:variables
)
do
[{
key: :KEY
,
value:
'value'
,
public:
true
}]
end
it
{
is_expected
.
to
eq
(
predefined_variables
+
variables
)
}
end
end
end
context
'when container registry is enabled'
do
let
(
:container_registry_enabled
)
{
true
}
let
(
:ci_registry
)
do
{
key:
'CI_REGISTRY'
,
value:
'registry.example.com'
,
public:
true
}
end
let
(
:ci_registry_image
)
do
{
key:
'CI_REGISTRY_IMAGE'
,
value:
project
.
container_registry_repository_url
,
public:
true
}
end
context
'and is disabled for project'
do
before
do
project
.
update
(
container_registry_enabled:
false
)
end
it
{
is_expected
.
to
include
(
ci_registry
)
}
it
{
is_expected
.
not_to
include
(
ci_registry_image
)
}
end
context
'and is enabled for project'
do
before
do
project
.
update
(
container_registry_enabled:
true
)
end
it
{
is_expected
.
to
include
(
ci_registry
)
}
it
{
is_expected
.
to
include
(
ci_registry_image
)
}
end
end
context
'when runner is assigned to build'
do
let
(
:runner
)
{
create
(
:ci_runner
,
description:
'description'
,
tag_list:
[
'docker'
,
'linux'
])
}
before
do
build
.
update
(
runner:
runner
)
end
it
{
is_expected
.
to
include
({
key:
'CI_RUNNER_ID'
,
value:
runner
.
id
.
to_s
,
public:
true
})
}
it
{
is_expected
.
to
include
({
key:
'CI_RUNNER_DESCRIPTION'
,
value:
'description'
,
public:
true
})
}
it
{
is_expected
.
to
include
({
key:
'CI_RUNNER_TAGS'
,
value:
'docker, linux'
,
public:
true
})
}
end
context
'when build is for a deployment'
do
let
(
:deployment_variable
)
{
{
key:
'KUBERNETES_TOKEN'
,
value:
'TOKEN'
,
public:
false
}
}
before
do
build
.
environment
=
'production'
allow
(
project
).
to
receive
(
:deployment_variables
).
and_return
([
deployment_variable
])
end
it
{
is_expected
.
to
include
(
deployment_variable
)
}
end
context
'returns variables in valid order'
do
before
do
allow
(
build
).
to
receive
(
:predefined_variables
)
{
[
'predefined'
]
}
allow
(
project
).
to
receive
(
:predefined_variables
)
{
[
'project'
]
}
allow
(
pipeline
).
to
receive
(
:predefined_variables
)
{
[
'pipeline'
]
}
allow
(
build
).
to
receive
(
:yaml_variables
)
{
[
'yaml'
]
}
allow
(
project
).
to
receive
(
:secret_variables
)
{
[
'secret'
]
}
end
it
{
is_expected
.
to
eq
(
%w[predefined project pipeline yaml secret]
)
}
end
end
describe
'#has_tags?'
do
context
'when build has tags'
do
subject
{
create
(
:ci_build
,
tag_list:
[
'tag'
])
}
it
{
is_expected
.
to
have_tags
}
end
context
'when build does not have tags'
do
subject
{
create
(
:ci_build
,
tag_list:
[])
}
it
{
is_expected
.
not_to
have_tags
}
end
end
describe
'#any_runners_online?'
do
subject
{
build
.
any_runners_online?
}
context
'when no runners'
do
it
{
is_expected
.
to
be_falsey
}
end
context
'when there are runners'
do
let
(
:runner
)
{
create
(
:ci_runner
)
}
before
do
build
.
project
.
runners
<<
runner
runner
.
update_attributes
(
contacted_at:
1
.
second
.
ago
)
end
it
{
is_expected
.
to
be_truthy
}
it
'that is inactive'
do
runner
.
update_attributes
(
active:
false
)
is_expected
.
to
be_falsey
end
it
'that is not online'
do
runner
.
update_attributes
(
contacted_at:
nil
)
is_expected
.
to
be_falsey
end
it
'that cannot handle build'
do
expect_any_instance_of
(
Ci
::
Runner
).
to
receive
(
:can_pick?
).
and_return
(
false
)
is_expected
.
to
be_falsey
end
end
end
describe
'#stuck?'
do
subject
{
build
.
stuck?
}
context
"when commit_status.status is pending"
do
before
do
build
.
status
=
'pending'
end
it
{
is_expected
.
to
be_truthy
}
context
"and there are specific runner"
do
let
(
:runner
)
{
create
(
:ci_runner
,
contacted_at:
1
.
second
.
ago
)
}
before
do
build
.
project
.
runners
<<
runner
runner
.
save
end
it
{
is_expected
.
to
be_falsey
}
end
end
%w[success failed canceled running]
.
each
do
|
state
|
context
"when commit_status.status is
#{
state
}
"
do
before
do
build
.
status
=
state
end
it
{
is_expected
.
to
be_falsey
}
end
end
end
describe
'#artifacts?'
do
subject
{
build
.
artifacts?
}
context
'artifacts archive does not exist'
do
before
do
build
.
update_attributes
(
artifacts_file:
nil
)
end
it
{
is_expected
.
to
be_falsy
}
end
context
'artifacts archive exists'
do
let
(
:build
)
{
create
(
:ci_build
,
:artifacts
)
}
it
{
is_expected
.
to
be_truthy
}
context
'is expired'
do
before
{
build
.
update
(
artifacts_expire_at:
Time
.
now
-
7
.
days
)
}
it
{
is_expected
.
to
be_falsy
}
end
context
'is not expired'
do
before
{
build
.
update
(
artifacts_expire_at:
Time
.
now
+
7
.
days
)
}
it
{
is_expected
.
to
be_truthy
}
end
end
end
describe
'#artifacts_expired?'
do
subject
{
build
.
artifacts_expired?
}
context
'is expired'
do
before
{
build
.
update
(
artifacts_expire_at:
Time
.
now
-
7
.
days
)
}
it
{
is_expected
.
to
be_truthy
}
end
context
'is not expired'
do
before
{
build
.
update
(
artifacts_expire_at:
Time
.
now
+
7
.
days
)
}
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#artifacts_metadata?'
do
subject
{
build
.
artifacts_metadata?
}
context
'artifacts metadata does not exist'
do
it
{
is_expected
.
to
be_falsy
}
end
context
'artifacts archive is a zip file and metadata exists'
do
let
(
:build
)
{
create
(
:ci_build
,
:artifacts
)
}
it
{
is_expected
.
to
be_truthy
}
end
end
describe
'#repo_url'
do
let
(
:build
)
{
create
(
:ci_build
)
}
let
(
:project
)
{
build
.
project
}
subject
{
build
.
repo_url
}
it
{
is_expected
.
to
be_a
(
String
)
}
it
{
is_expected
.
to
end_with
(
".git"
)
}
it
{
is_expected
.
to
start_with
(
project
.
web_url
[
0
..
6
])
}
it
{
is_expected
.
to
include
(
build
.
token
)
}
it
{
is_expected
.
to
include
(
'gitlab-ci-token'
)
}
it
{
is_expected
.
to
include
(
project
.
web_url
[
7
..-
1
])
}
end
describe
'#artifacts_expire_in'
do
subject
{
build
.
artifacts_expire_in
}
it
{
is_expected
.
to
be_nil
}
context
'when artifacts_expire_at is specified'
do
let
(
:expire_at
)
{
Time
.
now
+
7
.
days
}
before
{
build
.
artifacts_expire_at
=
expire_at
}
it
{
is_expected
.
to
be_within
(
5
).
of
(
expire_at
-
Time
.
now
)
}
end
end
describe
'#artifacts_expire_in='
do
subject
{
build
.
artifacts_expire_in
}
it
'when assigning valid duration'
do
build
.
artifacts_expire_in
=
'7 days'
is_expected
.
to
be_within
(
10
).
of
(
7
.
days
.
to_i
)
end
it
'when assigning invalid duration'
do
expect
{
build
.
artifacts_expire_in
=
'7 elephants'
}.
to
raise_error
(
ChronicDuration
::
DurationParseError
)
is_expected
.
to
be_nil
end
it
'when resseting value'
do
build
.
artifacts_expire_in
=
nil
is_expected
.
to
be_nil
end
end
describe
'#keep_artifacts!'
do
let
(
:build
)
{
create
(
:ci_build
,
artifacts_expire_at:
Time
.
now
+
7
.
days
)
}
it
'to reset expire_at'
do
build
.
keep_artifacts!
expect
(
build
.
artifacts_expire_at
).
to
be_nil
end
end
describe
'#depends_on_builds'
do
let!
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'build'
,
stage_idx:
0
,
stage:
'build'
)
}
let!
(
:rspec_test
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'rspec'
,
stage_idx:
1
,
stage:
'test'
)
}
let!
(
:rubocop_test
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'rubocop'
,
stage_idx:
1
,
stage:
'test'
)
}
let!
(
:staging
)
{
create
(
:ci_build
,
pipeline:
pipeline
,
name:
'staging'
,
stage_idx:
2
,
stage:
'deploy'
)
}
it
'expects to have no dependents if this is first build'
do
expect
(
build
.
depends_on_builds
).
to
be_empty
end
it
'expects to have one dependent if this is test'
do
expect
(
rspec_test
.
depends_on_builds
.
map
(
&
:id
)).
to
contain_exactly
(
build
.
id
)
end
it
'expects to have all builds from build and test stage if this is last'
do
expect
(
staging
.
depends_on_builds
.
map
(
&
:id
)).
to
contain_exactly
(
build
.
id
,
rspec_test
.
id
,
rubocop_test
.
id
)
end
it
'expects to have retried builds instead the original ones'
do
retried_rspec
=
Ci
::
Build
.
retry
(
rspec_test
)
expect
(
staging
.
depends_on_builds
.
map
(
&
:id
)).
to
contain_exactly
(
build
.
id
,
retried_rspec
.
id
,
rubocop_test
.
id
)
end
end
def
create_mr
(
build
,
pipeline
,
factory: :merge_request
,
created_at:
Time
.
now
)
create
(
factory
,
source_project_id:
pipeline
.
gl_project_id
,
target_project_id:
pipeline
.
gl_project_id
,
source_branch:
build
.
ref
,
created_at:
created_at
)
end
describe
'#merge_request'
do
context
'when a MR has a reference to the pipeline'
do
before
do
@merge_request
=
create_mr
(
build
,
pipeline
,
factory: :merge_request
)
commits
=
[
double
(
id:
pipeline
.
sha
)]
allow
(
@merge_request
).
to
receive
(
:commits
).
and_return
(
commits
)
allow
(
MergeRequest
).
to
receive_message_chain
(
:includes
,
:where
,
:reorder
).
and_return
([
@merge_request
])
end
it
'returns the single associated MR'
do
expect
(
build
.
merge_request
.
id
).
to
eq
(
@merge_request
.
id
)
end
end
context
'when there is not a MR referencing the pipeline'
do
it
'returns nil'
do
expect
(
build
.
merge_request
).
to
be_nil
end
end
context
'when more than one MR have a reference to the pipeline'
do
before
do
@merge_request
=
create_mr
(
build
,
pipeline
,
factory: :merge_request
)
@merge_request
.
close!
@merge_request2
=
create_mr
(
build
,
pipeline
,
factory: :merge_request
)
commits
=
[
double
(
id:
pipeline
.
sha
)]
allow
(
@merge_request
).
to
receive
(
:commits
).
and_return
(
commits
)
allow
(
@merge_request2
).
to
receive
(
:commits
).
and_return
(
commits
)
allow
(
MergeRequest
).
to
receive_message_chain
(
:includes
,
:where
,
:reorder
).
and_return
([
@merge_request
,
@merge_request2
])
end
it
'returns the first MR'
do
expect
(
build
.
merge_request
.
id
).
to
eq
(
@merge_request
.
id
)
end
end
context
'when a Build is created after the MR'
do
before
do
@merge_request
=
create_mr
(
build
,
pipeline
,
factory: :merge_request_with_diffs
)
pipeline2
=
create
(
:ci_pipeline
,
project:
project
)
@build2
=
create
(
:ci_build
,
pipeline:
pipeline2
)
allow
(
@merge_request
).
to
receive
(
:commits_sha
).
and_return
([
pipeline
.
sha
,
pipeline2
.
sha
])
allow
(
MergeRequest
).
to
receive_message_chain
(
:includes
,
:where
,
:reorder
).
and_return
([
@merge_request
])
end
it
'returns the current MR'
do
expect
(
@build2
.
merge_request
.
id
).
to
eq
(
@merge_request
.
id
)
end
end
end
describe
'build erasable'
do
shared_examples
'erasable'
do
it
'removes artifact file'
do
expect
(
build
.
artifacts_file
.
exists?
).
to
be_falsy
end
it
'removes artifact metadata file'
do
expect
(
build
.
artifacts_metadata
.
exists?
).
to
be_falsy
end
it
'erases build trace in trace file'
do
expect
(
build
.
trace
).
to
be_empty
end
it
'sets erased to true'
do
expect
(
build
.
erased?
).
to
be
true
end
it
'sets erase date'
do
expect
(
build
.
erased_at
).
not_to
be_falsy
end
end
context
'build is not erasable'
do
let!
(
:build
)
{
create
(
:ci_build
)
}
describe
'#erase'
do
subject
{
build
.
erase
}
it
{
is_expected
.
to
be
false
}
end
describe
'#erasable?'
do
subject
{
build
.
erasable?
}
it
{
is_expected
.
to
eq
false
}
end
end
context
'build is erasable'
do
let!
(
:build
)
{
create
(
:ci_build
,
:trace
,
:success
,
:artifacts
)
}
describe
'#erase'
do
before
do
build
.
erase
(
erased_by:
user
)
end
context
'erased by user'
do
let!
(
:user
)
{
create
(
:user
,
username:
'eraser'
)
}
include_examples
'erasable'
it
'records user who erased a build'
do
expect
(
build
.
erased_by
).
to
eq
user
end
end
context
'erased by system'
do
let
(
:user
)
{
nil
}
include_examples
'erasable'
it
'does not set user who erased a build'
do
expect
(
build
.
erased_by
).
to
be_nil
end
end
end
describe
'#erasable?'
do
subject
{
build
.
erasable?
}
it
{
is_expected
.
to
be_truthy
}
end
describe
'#erased?'
do
let!
(
:build
)
{
create
(
:ci_build
,
:trace
,
:success
,
:artifacts
)
}
subject
{
build
.
erased?
}
context
'build has not been erased'
do
it
{
is_expected
.
to
be_falsey
}
end
context
'build has been erased'
do
before
do
build
.
erase
end
it
{
is_expected
.
to
be_truthy
}
end
end
context
'metadata and build trace are not available'
do
let!
(
:build
)
{
create
(
:ci_build
,
:success
,
:artifacts
)
}
before
do
build
.
remove_artifacts_metadata!
end
describe
'#erase'
do
it
'does not raise error'
do
expect
{
build
.
erase
}.
not_to
raise_error
end
end
end
end
end
describe
'#commit'
do
it
'returns commit pipeline has been created for'
do
expect
(
build
.
commit
).
to
eq
project
.
commit
end
end
describe
'#when'
do
subject
{
build
.
when
}
context
'when `when` is undefined'
do
before
do
build
.
when
=
nil
end
context
'use from gitlab-ci.yml'
do
before
do
stub_ci_pipeline_yaml_file
(
config
)
end
context
'when config is not found'
do
let
(
:config
)
{
nil
}
it
{
is_expected
.
to
eq
(
'on_success'
)
}
end
context
'when config does not have a questioned job'
do
let
(
:config
)
do
YAML
.
dump
({
test_other:
{
script:
'Hello World'
}
})
end
it
{
is_expected
.
to
eq
(
'on_success'
)
}
end
context
'when config has `when`'
do
let
(
:config
)
do
YAML
.
dump
({
test:
{
script:
'Hello World'
,
when:
'always'
}
})
end
it
{
is_expected
.
to
eq
(
'always'
)
}
end
end
end
end
describe
'#cancelable?'
do
subject
{
build
}
context
'when build is cancelable'
do
context
'when build is pending'
do
it
{
is_expected
.
to
be_cancelable
}
end
context
'when build is running'
do
before
do
build
.
run!
end
it
{
is_expected
.
to
be_cancelable
}
end
end
context
'when build is not cancelable'
do
context
'when build is successful'
do
before
do
build
.
success!
end
it
{
is_expected
.
not_to
be_cancelable
}
end
context
'when build is failed'
do
before
do
build
.
drop!
end
it
{
is_expected
.
not_to
be_cancelable
}
end
end
end
describe
'#retryable?'
do
subject
{
build
}
context
'when build is retryable'
do
context
'when build is successful'
do
before
do
build
.
success!
end
it
{
is_expected
.
to
be_retryable
}
end
context
'when build is failed'
do
before
do
build
.
drop!
end
it
{
is_expected
.
to
be_retryable
}
end
context
'when build is canceled'
do
before
do
build
.
cancel!
end
it
{
is_expected
.
to
be_retryable
}
end
end
context
'when build is not retryable'
do
context
'when build is running'
do
before
do
build
.
run!
end
it
{
is_expected
.
not_to
be_retryable
}
end
context
'when build is skipped'
do
before
do
build
.
skip!
end
it
{
is_expected
.
not_to
be_retryable
}
end
end
end
describe
'#manual?'
do
before
do
build
.
update
(
when:
value
)
end
subject
{
build
.
manual?
}
context
'when is set to manual'
do
let
(
:value
)
{
'manual'
}
it
{
is_expected
.
to
be_truthy
}
end
context
'when set to something else'
do
let
(
:value
)
{
'something else'
}
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#other_actions'
do
let
(
:build
)
{
create
(
:ci_build
,
:manual
,
pipeline:
pipeline
)
}
let!
(
:other_build
)
{
create
(
:ci_build
,
:manual
,
pipeline:
pipeline
,
name:
'other action'
)
}
subject
{
build
.
other_actions
}
it
'returns other actions'
do
is_expected
.
to
contain_exactly
(
other_build
)
end
context
'when build is retried'
do
let!
(
:new_build
)
{
Ci
::
Build
.
retry
(
build
)
}
it
'does not return any of them'
do
is_expected
.
not_to
include
(
build
,
new_build
)
end
end
context
'when other build is retried'
do
let!
(
:retried_build
)
{
Ci
::
Build
.
retry
(
other_build
)
}
it
'returns a retried build'
do
is_expected
.
to
contain_exactly
(
retried_build
)
end
end
end
describe
'#play'
do
let
(
:build
)
{
create
(
:ci_build
,
:manual
,
pipeline:
pipeline
)
}
subject
{
build
.
play
}
it
'enqueues a build'
do
is_expected
.
to
be_pending
is_expected
.
to
eq
(
build
)
end
context
'for successful build'
do
before
do
build
.
update
(
status:
'success'
)
end
it
'creates a new build'
do
is_expected
.
to
be_pending
is_expected
.
not_to
eq
(
build
)
end
end
end
describe
'#when'
do
subject
{
build
.
when
}
context
'when `when` is undefined'
do
before
do
build
.
when
=
nil
end
context
'use from gitlab-ci.yml'
do
before
do
stub_ci_pipeline_yaml_file
(
config
)
end
context
'when config is not found'
do
let
(
:config
)
{
nil
}
it
{
is_expected
.
to
eq
(
'on_success'
)
}
end
context
'when config does not have a questioned job'
do
let
(
:config
)
do
YAML
.
dump
({
test_other:
{
script:
'Hello World'
}
})
end
it
{
is_expected
.
to
eq
(
'on_success'
)
}
end
context
'when config has when'
do
let
(
:config
)
do
YAML
.
dump
({
test:
{
script:
'Hello World'
,
when:
'always'
}
})
end
it
{
is_expected
.
to
eq
(
'always'
)
}
end
end
end
end
describe
'#retryable?'
do
context
'when build is running'
do
before
{
build
.
run!
}
it
'returns false'
do
expect
(
build
).
not_to
be_retryable
end
end
context
'when build is finished'
do
before
do
build
.
success!
end
it
'returns true'
do
expect
(
build
).
to
be_retryable
end
end
end
describe
'#has_environment?'
do
subject
{
build
.
has_environment?
}
context
'when environment is defined'
do
before
do
build
.
update
(
environment:
'review'
)
end
it
{
is_expected
.
to
be_truthy
}
end
context
'when environment is not defined'
do
before
do
build
.
update
(
environment:
nil
)
end
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#starts_environment?'
do
subject
{
build
.
starts_environment?
}
context
'when environment is defined'
do
before
do
build
.
update
(
environment:
'review'
)
end
context
'no action is defined'
do
it
{
is_expected
.
to
be_truthy
}
end
context
'and start action is defined'
do
before
do
build
.
update
(
options:
{
environment:
{
action:
'start'
}
}
)
end
it
{
is_expected
.
to
be_truthy
}
end
end
context
'when environment is not defined'
do
before
do
build
.
update
(
environment:
nil
)
end
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#stops_environment?'
do
subject
{
build
.
stops_environment?
}
context
'when environment is defined'
do
before
do
build
.
update
(
environment:
'review'
)
end
context
'no action is defined'
do
it
{
is_expected
.
to
be_falsey
}
end
context
'and stop action is defined'
do
before
do
build
.
update
(
options:
{
environment:
{
action:
'stop'
}
}
)
end
it
{
is_expected
.
to
be_truthy
}
end
end
context
'when environment is not defined'
do
before
do
build
.
update
(
environment:
nil
)
end
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#last_deployment'
do
subject
{
build
.
last_deployment
}
context
'when multiple deployments are created'
do
let!
(
:deployment1
)
{
create
(
:deployment
,
deployable:
build
)
}
let!
(
:deployment2
)
{
create
(
:deployment
,
deployable:
build
)
}
it
'returns the latest one'
do
is_expected
.
to
eq
(
deployment2
)
end
end
end
describe
'#outdated_deployment?'
do
subject
{
build
.
outdated_deployment?
}
context
'when build succeeded'
do
let
(
:build
)
{
create
(
:ci_build
,
:success
)
}
let!
(
:deployment
)
{
create
(
:deployment
,
deployable:
build
)
}
context
'current deployment is latest'
do
it
{
is_expected
.
to
be_falsey
}
end
context
'current deployment is not latest on environment'
do
let!
(
:deployment2
)
{
create
(
:deployment
,
environment:
deployment
.
environment
)
}
it
{
is_expected
.
to
be_truthy
}
end
end
context
'when build failed'
do
let
(
:build
)
{
create
(
:ci_build
,
:failed
)
}
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#expanded_environment_name'
do
subject
{
build
.
expanded_environment_name
}
context
'when environment uses variables'
do
let
(
:build
)
{
create
(
:ci_build
,
ref:
'master'
,
environment:
'review/$CI_BUILD_REF_NAME'
)
}
it
{
is_expected
.
to
eq
(
'review/master'
)
}
end
end
describe
'#detailed_status'
do
let
(
:user
)
{
create
(
:user
)
}
it
'returns a detailed status'
do
expect
(
build
.
detailed_status
(
user
))
.
to
be_a
Gitlab
::
Ci
::
Status
::
Build
::
Cancelable
end
end
describe
'#shared_runners_minutes_quota?'
do
subject
{
build
.
shared_runners_minutes_quota?
}
context
'for shared runner'
do
before
do
build
.
runner
=
create
(
:ci_runner
,
:shared
)
end
it
do
expect
(
build
.
project
).
to
receive
(
:shared_runners_minutes_quota?
).
and_return
(
true
)
is_expected
.
to
be_truthy
end
end
context
'with specific runner'
do
before
do
build
.
runner
=
create
(
:ci_runner
,
:specific
)
end
it
{
is_expected
.
to
be_falsey
}
end
context
'without runner'
do
it
{
is_expected
.
to
be_falsey
}
end
end
context
'updates build minutes'
do
let
(
:build
)
{
create
(
:ci_build
,
:running
,
pipeline:
pipeline
)
}
%w(success drop cancel)
.
each
do
|
event
|
it
"for event
#{
event
}
"
do
expect
(
UpdateBuildMinutesService
).
to
receive
(
:new
).
and_call_original
build
.
public_send
(
event
)
end
end
end
end
spec/models/ee/ci/build_spec.rb
0 → 100644
View file @
a4ae95ad
require
'spec_helper'
describe
Ci
::
Build
,
models:
true
do
let
(
:project
)
{
create
(
:project
)
}
let
(
:pipeline
)
do
create
(
:ci_pipeline
,
project:
project
,
sha:
project
.
commit
.
id
,
ref:
project
.
default_branch
,
status:
'success'
)
end
let
(
:build
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
describe
'#shared_runners_minutes_quota?'
do
subject
{
build
.
shared_runners_minutes_quota?
}
context
'for shared runner'
do
before
do
build
.
runner
=
create
(
:ci_runner
,
:shared
)
end
it
do
expect
(
build
.
project
).
to
receive
(
:shared_runners_minutes_quota?
).
and_return
(
true
)
is_expected
.
to
be_truthy
end
end
context
'with specific runner'
do
before
do
build
.
runner
=
create
(
:ci_runner
,
:specific
)
end
it
{
is_expected
.
to
be_falsey
}
end
context
'without runner'
do
it
{
is_expected
.
to
be_falsey
}
end
end
context
'updates build minutes'
do
let
(
:build
)
{
create
(
:ci_build
,
:running
,
pipeline:
pipeline
)
}
%w(success drop cancel)
.
each
do
|
event
|
it
"for event
#{
event
}
"
do
expect
(
UpdateBuildMinutesService
).
to
receive
(
:new
).
and_call_original
build
.
public_send
(
event
)
end
end
end
end
spec/models/ee/namespace_spec.rb
0 → 100644
View file @
a4ae95ad
require
'spec_helper'
describe
Namespace
,
models:
true
do
let!
(
:namespace
)
{
create
(
:namespace
)
}
it
{
is_expected
.
to
have_one
(
:namespace_metrics
).
dependent
(
:destroy
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes
).
to
(
:namespace_metrics
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes_last_reset
).
to
(
:namespace_metrics
)
}
describe
'#shared_runners_enabled?'
do
subject
{
namespace
.
shared_runners_enabled?
}
context
'without projects'
do
it
{
is_expected
.
to
be_falsey
}
end
context
'with project'
do
context
'and disabled shared runners'
do
let!
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
false
)
end
it
{
is_expected
.
to
be_falsey
}
end
context
'and enabled shared runners'
do
let!
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
true
)
end
it
{
is_expected
.
to
be_truthy
}
end
end
end
describe
'#actual_shared_runners_minutes_limit'
do
subject
{
namespace
.
actual_shared_runners_minutes_limit
}
context
'when no limit defined'
do
it
{
is_expected
.
to
be_zero
}
end
context
'when application settings limit is set'
do
before
do
stub_application_setting
(
shared_runners_minutes:
1000
)
end
it
'returns global limit'
do
is_expected
.
to
eq
(
1000
)
end
context
'when namespace limit is set'
do
before
do
namespace
.
shared_runners_minutes_limit
=
500
end
it
'returns namespace limit'
do
is_expected
.
to
eq
(
500
)
end
end
end
end
describe
'#shared_runners_minutes_limit_enabled?'
do
subject
{
namespace
.
shared_runners_minutes_limit_enabled?
}
context
'with project'
do
let!
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
true
)
end
context
'when no limit defined'
do
it
{
is_expected
.
to
be_falsey
}
end
context
'when limit is defined'
do
before
do
namespace
.
shared_runners_minutes_limit
=
500
end
it
{
is_expected
.
to
be_truthy
}
end
end
context
'without project'
do
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#shared_runners_minutes_used?'
do
subject
{
namespace
.
shared_runners_minutes_used?
}
context
'with project'
do
let!
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
true
)
end
context
'when limit is defined'
do
context
'when limit is used'
do
let
(
:namespace
)
{
create
(
:namespace
,
:with_used_build_minutes_limit
)
}
it
{
is_expected
.
to
be_truthy
}
end
context
'when limit not yet used'
do
let
(
:namespace
)
{
create
(
:namespace
,
:with_not_used_build_minutes_limit
)
}
it
{
is_expected
.
to
be_falsey
}
end
context
'when minutes are not yet set'
do
it
{
is_expected
.
to
be_falsey
}
end
end
context
'without limit'
do
let
(
:namespace
)
{
create
(
:namespace
,
:with_build_minutes_limit
)
}
it
{
is_expected
.
to
be_falsey
}
end
end
context
'without project'
do
it
{
is_expected
.
to
be_falsey
}
end
end
end
spec/models/ee/project_spec.rb
0 → 100644
View file @
a4ae95ad
require
'spec_helper'
describe
Project
,
models:
true
do
describe
'associations'
do
it
{
is_expected
.
to
have_one
(
:project_metrics
).
dependent
(
:destroy
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes
).
to
(
:project_metrics
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes_last_reset
).
to
(
:project_metrics
)
}
it
{
is_expected
.
to
delegate_method
(
:actual_shared_runners_minutes_limit
).
to
(
:namespace
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes_limit_enabled?
).
to
(
:namespace
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes_used?
).
to
(
:namespace
)
}
end
describe
'#any_runners_limit'
do
let
(
:project
)
{
create
(
:empty_project
,
shared_runners_enabled:
shared_runners_enabled
)
}
let
(
:specific_runner
)
{
create
(
:ci_runner
)
}
let
(
:shared_runner
)
{
create
(
:ci_runner
,
:shared
)
}
context
'for shared runners enabled'
do
let
(
:shared_runners_enabled
)
{
true
}
before
do
shared_runner
end
it
'has a shared runner'
do
expect
(
project
.
any_runners?
).
to
be_truthy
end
it
'checks the presence of shared runner'
do
expect
(
project
.
any_runners?
{
|
runner
|
runner
==
shared_runner
}).
to
be_truthy
end
context
'with used build minutes'
do
let
(
:namespace
)
{
create
(
:namespace
,
:with_used_build_minutes_limit
)
}
let
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
shared_runners_enabled
)
end
it
'does not have a shared runner'
do
expect
(
project
.
any_runners?
).
to
be_falsey
end
end
end
end
describe
'#shared_runners_minutes_quota?'
do
let
(
:project
)
{
create
(
:empty_project
)
}
subject
{
project
.
shared_runners_minutes_quota?
}
context
'with shared runners enabled'
do
before
do
project
.
shared_runners_enabled
=
true
end
context
'for public project'
do
before
do
project
.
visibility_level
=
Project
::
PUBLIC
end
it
{
is_expected
.
to
be_falsey
}
end
context
'for internal project'
do
before
do
project
.
visibility_level
=
Project
::
INTERNAL
end
it
{
is_expected
.
to
be_truthy
}
end
context
'for private project'
do
before
do
project
.
visibility_level
=
Project
::
INTERNAL
end
it
{
is_expected
.
to
be_truthy
}
end
end
context
'without shared runners'
do
before
do
project
.
shared_runners_enabled
=
false
end
it
{
is_expected
.
to
be_falsey
}
end
end
end
spec/models/namespace_spec.rb
View file @
a4ae95ad
...
...
@@ -4,7 +4,6 @@ describe Namespace, models: true do
let!
(
:namespace
)
{
create
(
:namespace
)
}
it
{
is_expected
.
to
have_many
:projects
}
it
{
is_expected
.
to
have_one
(
:namespace_metrics
).
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
:project_statistics
}
it
{
is_expected
.
to
validate_presence_of
(
:name
)
}
...
...
@@ -18,9 +17,6 @@ describe Namespace, models: true do
it
{
is_expected
.
to
validate_presence_of
(
:owner
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes
).
to
(
:namespace_metrics
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes_last_reset
).
to
(
:namespace_metrics
)
}
describe
"Respond to"
do
it
{
is_expected
.
to
respond_to
(
:human_name
)
}
it
{
is_expected
.
to
respond_to
(
:to_param
)
}
...
...
@@ -190,132 +186,6 @@ describe Namespace, models: true do
it
{
expect
(
nested_group
.
full_path
).
to
eq
(
"
#{
group
.
path
}
/
#{
nested_group
.
path
}
"
)
}
end
describe
'#shared_runners_enabled?'
do
subject
{
namespace
.
shared_runners_enabled?
}
context
'without projects'
do
it
{
is_expected
.
to
be_falsey
}
end
context
'with project'
do
context
'and disabled shared runners'
do
let!
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
false
)
end
it
{
is_expected
.
to
be_falsey
}
end
context
'and enabled shared runners'
do
let!
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
true
)
end
it
{
is_expected
.
to
be_truthy
}
end
end
end
describe
'#actual_shared_runners_minutes_limit'
do
subject
{
namespace
.
actual_shared_runners_minutes_limit
}
context
'when no limit defined'
do
it
{
is_expected
.
to
be_zero
}
end
context
'when application settings limit is set'
do
before
do
stub_application_setting
(
shared_runners_minutes:
1000
)
end
it
'returns global limit'
do
is_expected
.
to
eq
(
1000
)
end
context
'when namespace limit is set'
do
before
do
namespace
.
shared_runners_minutes_limit
=
500
end
it
'returns namespace limit'
do
is_expected
.
to
eq
(
500
)
end
end
end
end
describe
'#shared_runners_minutes_limit_enabled?'
do
subject
{
namespace
.
shared_runners_minutes_limit_enabled?
}
context
'with project'
do
let!
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
true
)
end
context
'when no limit defined'
do
it
{
is_expected
.
to
be_falsey
}
end
context
'when limit is defined'
do
before
do
namespace
.
shared_runners_minutes_limit
=
500
end
it
{
is_expected
.
to
be_truthy
}
end
end
context
'without project'
do
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#shared_runners_minutes_used?'
do
subject
{
namespace
.
shared_runners_minutes_used?
}
context
'with project'
do
let!
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
true
)
end
context
'when limit is defined'
do
context
'when limit is used'
do
let
(
:namespace
)
{
create
(
:namespace
,
:with_used_build_minutes_limit
)
}
it
{
is_expected
.
to
be_truthy
}
end
context
'when limit not yet used'
do
let
(
:namespace
)
{
create
(
:namespace
,
:with_not_used_build_minutes_limit
)
}
it
{
is_expected
.
to
be_falsey
}
end
context
'when minutes are not yet set'
do
it
{
is_expected
.
to
be_falsey
}
end
end
context
'without limit'
do
let
(
:namespace
)
{
create
(
:namespace
,
:with_build_minutes_limit
)
}
it
{
is_expected
.
to
be_falsey
}
end
end
context
'without project'
do
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#full_name'
do
let
(
:group
)
{
create
(
:group
)
}
let
(
:nested_group
)
{
create
(
:group
,
parent:
group
)
}
...
...
spec/models/project_spec.rb
View file @
a4ae95ad
...
...
@@ -5,7 +5,6 @@ describe Project, models: true do
it
{
is_expected
.
to
belong_to
(
:group
)
}
it
{
is_expected
.
to
belong_to
(
:namespace
)
}
it
{
is_expected
.
to
belong_to
(
:creator
).
class_name
(
'User'
)
}
it
{
is_expected
.
to
have_one
(
:project_metrics
).
dependent
(
:destroy
)
}
it
{
is_expected
.
to
have_many
(
:users
)
}
it
{
is_expected
.
to
have_many
(
:services
)
}
it
{
is_expected
.
to
have_many
(
:events
).
dependent
(
:destroy
)
}
...
...
@@ -75,13 +74,6 @@ describe Project, models: true do
it
{
is_expected
.
to
have_many
(
:forks
).
through
(
:forked_project_links
)
}
it
{
is_expected
.
to
have_many
(
:approver_groups
).
dependent
(
:destroy
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes
).
to
(
:project_metrics
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes_last_reset
).
to
(
:project_metrics
)
}
it
{
is_expected
.
to
delegate_method
(
:actual_shared_runners_minutes_limit
).
to
(
:namespace
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes_limit_enabled?
).
to
(
:namespace
)
}
it
{
is_expected
.
to
delegate_method
(
:shared_runners_minutes_used?
).
to
(
:namespace
)
}
context
'after initialized'
do
it
"has a project_feature"
do
project
=
FactoryGirl
.
build
(
:project
)
...
...
@@ -1114,30 +1106,15 @@ describe Project, models: true do
context
'for shared runners enabled'
do
let
(
:shared_runners_enabled
)
{
true
}
before
do
shared_runner
end
it
'has a shared runner'
do
shared_runner
expect
(
project
.
any_runners?
).
to
be_truthy
end
it
'checks the presence of shared runner'
do
shared_runner
expect
(
project
.
any_runners?
{
|
runner
|
runner
==
shared_runner
}).
to
be_truthy
end
context
'with used build minutes'
do
let
(
:namespace
)
{
create
(
:namespace
,
:with_used_build_minutes_limit
)
}
let
(
:project
)
do
create
(
:empty_project
,
namespace:
namespace
,
shared_runners_enabled:
shared_runners_enabled
)
end
it
'does not have a shared runner'
do
expect
(
project
.
any_runners?
).
to
be_falsey
end
end
end
end
...
...
@@ -2119,50 +2096,6 @@ describe Project, models: true do
end
end
describe
'#shared_runners_minutes_quota?'
do
let
(
:project
)
{
create
(
:empty_project
)
}
subject
{
project
.
shared_runners_minutes_quota?
}
context
'with shared runners enabled'
do
before
do
project
.
shared_runners_enabled
=
true
end
context
'for public project'
do
before
do
project
.
visibility_level
=
Project
::
PUBLIC
end
it
{
is_expected
.
to
be_falsey
}
end
context
'for internal project'
do
before
do
project
.
visibility_level
=
Project
::
INTERNAL
end
it
{
is_expected
.
to
be_truthy
}
end
context
'for private project'
do
before
do
project
.
visibility_level
=
Project
::
INTERNAL
end
it
{
is_expected
.
to
be_truthy
}
end
end
context
'without shared runners'
do
before
do
project
.
shared_runners_enabled
=
false
end
it
{
is_expected
.
to
be_falsey
}
end
end
describe
'#update_project_statistics'
do
let
(
:project
)
{
create
(
:empty_project
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment