summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRémy Coutable <remy@rymai.me>2016-12-14 12:34:22 +0000
committerRémy Coutable <remy@rymai.me>2016-12-14 12:34:22 +0000
commit3e90aa1119fc4c77e92e6492f1906f252d90b64e (patch)
treef228f7cecd3f1a488034e4155bcd40a38dd1411d
parent3a90612660ab90225907ec6d79032905885c2507 (diff)
parent6757aaa120c375f15e09f4c428286e5dc1d95f84 (diff)
downloadgitlab-ce-3e90aa1119fc4c77e92e6492f1906f252d90b64e.tar.gz
Merge branch 'build-statuses' into 'master'
Detailed build statuses ## What does this MR do? Implements detailed statuses for `Ci::Builds` and `CommitStatus`. It also adds a new icon for manual build. ## Screenshots ![manual_builds_icon](/uploads/22b5c594350856c85398ef705a635f8b/manual_builds_icon.png) ## What are the relevant issue numbers? See #24273, closes #22642 See merge request !7989
-rw-r--r--app/helpers/ci_status_helper.rb20
-rw-r--r--app/models/ci/build.rb15
-rw-r--r--app/models/ci/pipeline.rb6
-rw-r--r--app/models/ci/stage.rb6
-rw-r--r--app/models/commit_status.rb6
-rw-r--r--app/views/admin/runners/show.html.haml2
-rw-r--r--app/views/ci/status/_badge.html.haml10
-rw-r--r--app/views/projects/builds/_header.html.haml2
-rw-r--r--app/views/projects/ci/builds/_build.html.haml5
-rw-r--r--app/views/projects/ci/pipelines/_pipeline.html.haml5
-rw-r--r--app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml5
-rw-r--r--app/views/projects/pipelines/_info.html.haml2
-rw-r--r--app/views/projects/stage/_graph.html.haml2
-rwxr-xr-xapp/views/shared/icons/_icon_status_manual.svg1
-rw-r--r--lib/gitlab/allowable.rb7
-rw-r--r--lib/gitlab/ci/status/build/cancelable.rb37
-rw-r--r--lib/gitlab/ci/status/build/common.rb19
-rw-r--r--lib/gitlab/ci/status/build/factory.rb18
-rw-r--r--lib/gitlab/ci/status/build/play.rb53
-rw-r--r--lib/gitlab/ci/status/build/retryable.rb37
-rw-r--r--lib/gitlab/ci/status/build/stop.rb49
-rw-r--r--lib/gitlab/ci/status/core.rb27
-rw-r--r--lib/gitlab/ci/status/extended.rb8
-rw-r--r--lib/gitlab/ci/status/factory.rb30
-rw-r--r--lib/gitlab/ci/status/pipeline/common.rb8
-rw-r--r--lib/gitlab/ci/status/pipeline/factory.rb8
-rw-r--r--lib/gitlab/ci/status/pipeline/success_with_warnings.rb4
-rw-r--r--lib/gitlab/ci/status/stage/common.rb10
-rw-r--r--lib/gitlab/ci/status/stage/factory.rb6
-rw-r--r--lib/gitlab/routing.rb6
-rw-r--r--spec/factories/ci/builds.rb13
-rw-r--r--spec/lib/gitlab/allowable_spec.rb27
-rw-r--r--spec/lib/gitlab/ci/status/build/cancelable_spec.rb86
-rw-r--r--spec/lib/gitlab/ci/status/build/common_spec.rb37
-rw-r--r--spec/lib/gitlab/ci/status/build/factory_spec.rb141
-rw-r--r--spec/lib/gitlab/ci/status/build/play_spec.rb82
-rw-r--r--spec/lib/gitlab/ci/status/build/retryable_spec.rb86
-rw-r--r--spec/lib/gitlab/ci/status/build/stop_spec.rb84
-rw-r--r--spec/lib/gitlab/ci/status/canceled_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/created_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/extended_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/factory_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/failed_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/pending_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/common_spec.rb33
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/factory_spec.rb9
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/running_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/skipped_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/stage/common_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/status/stage/factory_spec.rb15
-rw-r--r--spec/lib/gitlab/ci/status/success_spec.rb8
-rw-r--r--spec/lib/gitlab/routing_spec.rb23
-rw-r--r--spec/models/build_spec.rb91
-rw-r--r--spec/models/ci/pipeline_spec.rb20
-rw-r--r--spec/models/ci/stage_spec.rb4
-rw-r--r--spec/models/commit_status_spec.rb9
-rw-r--r--spec/models/generic_commit_status_spec.rb16
58 files changed, 1125 insertions, 170 deletions
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index 8e19752a8a1..d9f5e01f0dc 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -4,25 +4,7 @@ module CiStatusHelper
builds_namespace_project_commit_path(project.namespace, project, pipeline.sha)
end
- def ci_status_with_icon(status, target = nil)
- content = ci_icon_for_status(status) + ci_text_for_status(status)
- klass = "ci-status ci-#{status}"
-
- if target
- link_to content, target, class: klass
- else
- content_tag :span, content, class: klass
- end
- end
-
- def ci_text_for_status(status)
- if detailed_status?(status)
- status.text
- else
- status
- end
- end
-
+ # Is used by Commit and Merge Request Widget
def ci_label_for_status(status)
if detailed_status?(status)
return status.label
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 88c46076df6..e7cf606a7ae 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -100,6 +100,12 @@ module Ci
end
end
+ def detailed_status(current_user)
+ Gitlab::Ci::Status::Build::Factory
+ .new(self, current_user)
+ .fabricate!
+ end
+
def manual?
self.when == 'manual'
end
@@ -123,8 +129,13 @@ module Ci
end
end
+ def cancelable?
+ active?
+ end
+
def retryable?
- project.builds_enabled? && commands.present? && complete?
+ project.builds_enabled? && commands.present? &&
+ (success? || failed? || canceled?)
end
def retried?
@@ -148,7 +159,7 @@ module Ci
end
def environment_action
- self.options.fetch(:environment, {}).fetch(:action, 'start')
+ self.options.fetch(:environment, {}).fetch(:action, 'start') if self.options
end
def outdated_deployment?
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index fda8228a1e9..54f73171fd4 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -336,8 +336,10 @@ module Ci
.select { |merge_request| merge_request.head_pipeline.try(:id) == self.id }
end
- def detailed_status
- Gitlab::Ci::Status::Pipeline::Factory.new(self).fabricate!
+ def detailed_status(current_user)
+ Gitlab::Ci::Status::Pipeline::Factory
+ .new(self, current_user)
+ .fabricate!
end
private
diff --git a/app/models/ci/stage.rb b/app/models/ci/stage.rb
index d2a37c0a827..7ef59445d77 100644
--- a/app/models/ci/stage.rb
+++ b/app/models/ci/stage.rb
@@ -22,8 +22,10 @@ module Ci
@status ||= statuses.latest.status
end
- def detailed_status
- Gitlab::Ci::Status::Stage::Factory.new(self).fabricate!
+ def detailed_status(current_user)
+ Gitlab::Ci::Status::Stage::Factory
+ .new(self, current_user)
+ .fabricate!
end
def statuses
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index cf90475f4d4..31cd381dcd2 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -131,4 +131,10 @@ class CommitStatus < ActiveRecord::Base
def has_trace?
false
end
+
+ def detailed_status(current_user)
+ Gitlab::Ci::Status::Factory
+ .new(self, current_user)
+ .fabricate!
+ end
end
diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml
index 73038164056..ca503e35623 100644
--- a/app/views/admin/runners/show.html.haml
+++ b/app/views/admin/runners/show.html.haml
@@ -91,7 +91,7 @@
%strong ##{build.id}
%td.status
- = ci_status_with_icon(build.status)
+ = render 'ci/status/badge', status: build.detailed_status(current_user)
%td.status
- if project
diff --git a/app/views/ci/status/_badge.html.haml b/app/views/ci/status/_badge.html.haml
new file mode 100644
index 00000000000..f2135af2686
--- /dev/null
+++ b/app/views/ci/status/_badge.html.haml
@@ -0,0 +1,10 @@
+- status = local_assigns.fetch(:status)
+
+- if status.has_details?
+ = link_to status.details_path, class: "ci-status ci-#{status}" do
+ = custom_icon(status.icon)
+ = status.text
+- else
+ %span{ class: "ci-status ci-#{status}" }
+ = custom_icon(status.icon)
+ = status.text
diff --git a/app/views/projects/builds/_header.html.haml b/app/views/projects/builds/_header.html.haml
index f6aa20c4579..057a720a54a 100644
--- a/app/views/projects/builds/_header.html.haml
+++ b/app/views/projects/builds/_header.html.haml
@@ -1,6 +1,6 @@
.content-block.build-header
.header-content
- = ci_status_with_icon(@build.status)
+ = render 'ci/status/badge', status: @build.detailed_status(current_user)
Build
%strong ##{@build.id}
in pipeline
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index 18b3b04154f..f1cb0201032 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -9,10 +9,7 @@
%tr.build.commit{class: ('retried' if retried)}
%td.status
- - if can?(current_user, :read_build, build)
- = ci_status_with_icon(build.status, namespace_project_build_url(build.project.namespace, build.project, build))
- - else
- = ci_status_with_icon(build.status)
+ = render "ci/status/badge", status: build.detailed_status(current_user)
%td.branch-commit
- if can?(current_user, :read_build, build)
diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml
index b58dceb58c9..3f05a21990f 100644
--- a/app/views/projects/ci/pipelines/_pipeline.html.haml
+++ b/app/views/projects/ci/pipelines/_pipeline.html.haml
@@ -1,13 +1,10 @@
- status = pipeline.status
-- detailed_status = pipeline.detailed_status
- show_commit = local_assigns.fetch(:show_commit, true)
- show_branch = local_assigns.fetch(:show_branch, true)
%tr.commit
%td.commit-link
- = link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: "ci-status ci-#{detailed_status}" do
- = ci_icon_for_status(detailed_status)
- = ci_text_for_status(detailed_status)
+ = render 'ci/status/badge', status: pipeline.detailed_status(current_user)
%td
= link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id) do
diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
index 7f751d9ae2e..9f444f076c0 100644
--- a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
+++ b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
@@ -8,10 +8,7 @@
%tr.generic_commit_status{class: ('retried' if retried)}
%td.status
- - if can?(current_user, :read_commit_status, generic_commit_status) && generic_commit_status.target_url
- = ci_status_with_icon(generic_commit_status.status, generic_commit_status.target_url)
- - else
- = ci_status_with_icon(generic_commit_status.status)
+ = render 'ci/status/badge', status: generic_commit_status.detailed_status(current_user)
%td.generic_commit_status-link
- if can?(current_user, :read_commit_status, generic_commit_status) && generic_commit_status.target_url
diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml
index 229bdfb0e8d..b00ba2d5307 100644
--- a/app/views/projects/pipelines/_info.html.haml
+++ b/app/views/projects/pipelines/_info.html.haml
@@ -1,6 +1,6 @@
.page-content-header
.header-main-content
- = ci_status_with_icon(@pipeline.detailed_status)
+ = render 'ci/status/badge', status: @pipeline.detailed_status(current_user)
%strong Pipeline ##{@commit.pipelines.last.id}
triggered #{time_ago_with_tooltip(@commit.authored_date)} by
= author_avatar(@commit, size: 24)
diff --git a/app/views/projects/stage/_graph.html.haml b/app/views/projects/stage/_graph.html.haml
index 1d8fa10db0c..bf8c75b6e5c 100644
--- a/app/views/projects/stage/_graph.html.haml
+++ b/app/views/projects/stage/_graph.html.haml
@@ -19,4 +19,4 @@
%li.build
.curve
.dropdown.inline.build-content
- = render "projects/stage/in_stage_group", name: group_name, subject: grouped_statuses
+ = render 'projects/stage/in_stage_group', name: group_name, subject: grouped_statuses
diff --git a/app/views/shared/icons/_icon_status_manual.svg b/app/views/shared/icons/_icon_status_manual.svg
new file mode 100755
index 00000000000..c98839f51a9
--- /dev/null
+++ b/app/views/shared/icons/_icon_status_manual.svg
@@ -0,0 +1 @@
+<svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M10.5 7.63V6.37l-.787-.13c-.044-.175-.132-.349-.263-.61l.481-.652-.918-.913-.657.478a2.346 2.346 0 0 0-.612-.26L7.656 3.5H6.388l-.132.783c-.219.043-.394.13-.612.26l-.657-.478-.918.913.437.652c-.131.218-.175.392-.262.61l-.744.086v1.261l.787.13c.044.218.132.392.263.61l-.438.651.92.913.655-.434c.175.086.394.173.613.26l.131.783h1.313l.131-.783c.219-.043.394-.13.613-.26l.656.478.918-.913-.48-.652c.13-.218.218-.435.262-.61l.656-.13zM7 8.283a1.285 1.285 0 0 1-1.313-1.305c0-.739.57-1.304 1.313-1.304.744 0 1.313.565 1.313 1.304 0 .74-.57 1.305-1.313 1.305z"/></g></svg>
diff --git a/lib/gitlab/allowable.rb b/lib/gitlab/allowable.rb
new file mode 100644
index 00000000000..f48abcc86d5
--- /dev/null
+++ b/lib/gitlab/allowable.rb
@@ -0,0 +1,7 @@
+module Gitlab
+ module Allowable
+ def can?(user, action, subject)
+ Ability.allowed?(user, action, subject)
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/build/cancelable.rb b/lib/gitlab/ci/status/build/cancelable.rb
new file mode 100644
index 00000000000..a979fe7d573
--- /dev/null
+++ b/lib/gitlab/ci/status/build/cancelable.rb
@@ -0,0 +1,37 @@
+module Gitlab
+ module Ci
+ module Status
+ module Build
+ class Cancelable < SimpleDelegator
+ include Status::Extended
+
+ def has_action?
+ can?(user, :update_build, subject)
+ end
+
+ def action_icon
+ 'ban'
+ end
+
+ def action_path
+ cancel_namespace_project_build_path(subject.project.namespace,
+ subject.project,
+ subject)
+ end
+
+ def action_method
+ :post
+ end
+
+ def action_title
+ 'Cancel'
+ end
+
+ def self.matches?(build, user)
+ build.cancelable?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/build/common.rb b/lib/gitlab/ci/status/build/common.rb
new file mode 100644
index 00000000000..3fec2c5d4db
--- /dev/null
+++ b/lib/gitlab/ci/status/build/common.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Ci
+ module Status
+ module Build
+ module Common
+ def has_details?
+ can?(user, :read_build, subject)
+ end
+
+ def details_path
+ namespace_project_build_path(subject.project.namespace,
+ subject.project,
+ subject)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/build/factory.rb b/lib/gitlab/ci/status/build/factory.rb
new file mode 100644
index 00000000000..eee9a64120b
--- /dev/null
+++ b/lib/gitlab/ci/status/build/factory.rb
@@ -0,0 +1,18 @@
+module Gitlab
+ module Ci
+ module Status
+ module Build
+ class Factory < Status::Factory
+ def self.extended_statuses
+ [Status::Build::Stop, Status::Build::Play,
+ Status::Build::Cancelable, Status::Build::Retryable]
+ end
+
+ def self.common_helpers
+ Status::Build::Common
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/build/play.rb b/lib/gitlab/ci/status/build/play.rb
new file mode 100644
index 00000000000..5c506e6d59f
--- /dev/null
+++ b/lib/gitlab/ci/status/build/play.rb
@@ -0,0 +1,53 @@
+module Gitlab
+ module Ci
+ module Status
+ module Build
+ class Play < SimpleDelegator
+ include Status::Extended
+
+ def text
+ 'manual'
+ end
+
+ def label
+ 'manual play action'
+ end
+
+ def icon
+ 'icon_status_manual'
+ end
+
+ def has_action?
+ can?(user, :update_build, subject)
+ end
+
+ def action_icon
+ 'play'
+ end
+
+ def action_title
+ 'Play'
+ end
+
+ def action_class
+ 'ci-play-icon'
+ end
+
+ def action_path
+ play_namespace_project_build_path(subject.project.namespace,
+ subject.project,
+ subject)
+ end
+
+ def action_method
+ :post
+ end
+
+ def self.matches?(build, user)
+ build.playable? && !build.stops_environment?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/build/retryable.rb b/lib/gitlab/ci/status/build/retryable.rb
new file mode 100644
index 00000000000..8e38d6a8523
--- /dev/null
+++ b/lib/gitlab/ci/status/build/retryable.rb
@@ -0,0 +1,37 @@
+module Gitlab
+ module Ci
+ module Status
+ module Build
+ class Retryable < SimpleDelegator
+ include Status::Extended
+
+ def has_action?
+ can?(user, :update_build, subject)
+ end
+
+ def action_icon
+ 'refresh'
+ end
+
+ def action_title
+ 'Retry'
+ end
+
+ def action_path
+ retry_namespace_project_build_path(subject.project.namespace,
+ subject.project,
+ subject)
+ end
+
+ def action_method
+ :post
+ end
+
+ def self.matches?(build, user)
+ build.retryable?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/build/stop.rb b/lib/gitlab/ci/status/build/stop.rb
new file mode 100644
index 00000000000..f8ffa95cde4
--- /dev/null
+++ b/lib/gitlab/ci/status/build/stop.rb
@@ -0,0 +1,49 @@
+module Gitlab
+ module Ci
+ module Status
+ module Build
+ class Stop < SimpleDelegator
+ include Status::Extended
+
+ def text
+ 'manual'
+ end
+
+ def label
+ 'manual stop action'
+ end
+
+ def icon
+ 'icon_status_manual'
+ end
+
+ def has_action?
+ can?(user, :update_build, subject)
+ end
+
+ def action_icon
+ 'stop'
+ end
+
+ def action_title
+ 'Stop'
+ end
+
+ def action_path
+ play_namespace_project_build_path(subject.project.namespace,
+ subject.project,
+ subject)
+ end
+
+ def action_method
+ :post
+ end
+
+ def self.matches?(build, user)
+ build.playable? && build.stops_environment?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/core.rb b/lib/gitlab/ci/status/core.rb
index ce4108fdcf2..46fef8262c1 100644
--- a/lib/gitlab/ci/status/core.rb
+++ b/lib/gitlab/ci/status/core.rb
@@ -4,10 +4,14 @@ module Gitlab
# Base abstract class fore core status
#
class Core
- include Gitlab::Routing.url_helpers
+ include Gitlab::Routing
+ include Gitlab::Allowable
- def initialize(subject)
+ attr_reader :subject, :user
+
+ def initialize(subject, user)
@subject = subject
+ @user = user
end
def icon
@@ -18,10 +22,6 @@ module Gitlab
raise NotImplementedError
end
- def title
- "#{@subject.class.name.demodulize}: #{label}"
- end
-
# Deprecation warning: this method is here because we need to maintain
# backwards compatibility with legacy statuses. We often do something
# like "ci-status ci-status-#{status}" to set CSS class.
@@ -34,7 +34,7 @@ module Gitlab
end
def has_details?
- raise NotImplementedError
+ false
end
def details_path
@@ -42,16 +42,27 @@ module Gitlab
end
def has_action?
- raise NotImplementedError
+ false
end
def action_icon
raise NotImplementedError
end
+ def action_class
+ end
+
def action_path
raise NotImplementedError
end
+
+ def action_method
+ raise NotImplementedError
+ end
+
+ def action_title
+ raise NotImplementedError
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/extended.rb b/lib/gitlab/ci/status/extended.rb
index 6bfb5d38c1f..d367c9bda69 100644
--- a/lib/gitlab/ci/status/extended.rb
+++ b/lib/gitlab/ci/status/extended.rb
@@ -2,8 +2,12 @@ module Gitlab
module Ci
module Status
module Extended
- def matches?(_subject)
- raise NotImplementedError
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def matches?(_subject, _user)
+ raise NotImplementedError
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/factory.rb b/lib/gitlab/ci/status/factory.rb
index b2f896f2211..ae9ef895df4 100644
--- a/lib/gitlab/ci/status/factory.rb
+++ b/lib/gitlab/ci/status/factory.rb
@@ -2,10 +2,9 @@ module Gitlab
module Ci
module Status
class Factory
- attr_reader :subject
-
- def initialize(subject)
+ def initialize(subject, user)
@subject = subject
+ @user = user
end
def fabricate!
@@ -16,27 +15,32 @@ module Gitlab
end
end
+ def self.extended_statuses
+ []
+ end
+
+ def self.common_helpers
+ Module.new
+ end
+
private
- def subject_status
- @subject_status ||= subject.status
+ def simple_status
+ @simple_status ||= @subject.status || :created
end
def core_status
Gitlab::Ci::Status
- .const_get(subject_status.capitalize)
- .new(subject)
+ .const_get(simple_status.capitalize)
+ .new(@subject, @user)
+ .extend(self.class.common_helpers)
end
def extended_status
- @extended ||= extended_statuses.find do |status|
- status.matches?(subject)
+ @extended ||= self.class.extended_statuses.find do |status|
+ status.matches?(@subject, @user)
end
end
-
- def extended_statuses
- []
- end
end
end
end
diff --git a/lib/gitlab/ci/status/pipeline/common.rb b/lib/gitlab/ci/status/pipeline/common.rb
index 25e52bec3da..76bfd18bf40 100644
--- a/lib/gitlab/ci/status/pipeline/common.rb
+++ b/lib/gitlab/ci/status/pipeline/common.rb
@@ -4,13 +4,13 @@ module Gitlab
module Pipeline
module Common
def has_details?
- true
+ can?(user, :read_pipeline, subject)
end
def details_path
- namespace_project_pipeline_path(@subject.project.namespace,
- @subject.project,
- @subject)
+ namespace_project_pipeline_path(subject.project.namespace,
+ subject.project,
+ subject)
end
def has_action?
diff --git a/lib/gitlab/ci/status/pipeline/factory.rb b/lib/gitlab/ci/status/pipeline/factory.rb
index 4ac4ec671d0..16dcb326be9 100644
--- a/lib/gitlab/ci/status/pipeline/factory.rb
+++ b/lib/gitlab/ci/status/pipeline/factory.rb
@@ -3,14 +3,12 @@ module Gitlab
module Status
module Pipeline
class Factory < Status::Factory
- private
-
- def extended_statuses
+ def self.extended_statuses
[Pipeline::SuccessWithWarnings]
end
- def core_status
- super.extend(Status::Pipeline::Common)
+ def self.common_helpers
+ Status::Pipeline::Common
end
end
end
diff --git a/lib/gitlab/ci/status/pipeline/success_with_warnings.rb b/lib/gitlab/ci/status/pipeline/success_with_warnings.rb
index 4b040d60df8..a7c98f9e909 100644
--- a/lib/gitlab/ci/status/pipeline/success_with_warnings.rb
+++ b/lib/gitlab/ci/status/pipeline/success_with_warnings.rb
@@ -3,7 +3,7 @@ module Gitlab
module Status
module Pipeline
class SuccessWithWarnings < SimpleDelegator
- extend Status::Extended
+ include Status::Extended
def text
'passed'
@@ -21,7 +21,7 @@ module Gitlab
'success_with_warnings'
end
- def self.matches?(pipeline)
+ def self.matches?(pipeline, user)
pipeline.success? && pipeline.has_warnings?
end
end
diff --git a/lib/gitlab/ci/status/stage/common.rb b/lib/gitlab/ci/status/stage/common.rb
index 14c437d2b98..7852f492e1d 100644
--- a/lib/gitlab/ci/status/stage/common.rb
+++ b/lib/gitlab/ci/status/stage/common.rb
@@ -4,14 +4,14 @@ module Gitlab
module Stage
module Common
def has_details?
- true
+ can?(user, :read_pipeline, subject.pipeline)
end
def details_path
- namespace_project_pipeline_path(@subject.project.namespace,
- @subject.project,
- @subject.pipeline,
- anchor: @subject.name)
+ namespace_project_pipeline_path(subject.project.namespace,
+ subject.project,
+ subject.pipeline,
+ anchor: subject.name)
end
def has_action?
diff --git a/lib/gitlab/ci/status/stage/factory.rb b/lib/gitlab/ci/status/stage/factory.rb
index c6522d5ada1..689a5dd45bc 100644
--- a/lib/gitlab/ci/status/stage/factory.rb
+++ b/lib/gitlab/ci/status/stage/factory.rb
@@ -3,10 +3,8 @@ module Gitlab
module Status
module Stage
class Factory < Status::Factory
- private
-
- def core_status
- super.extend(Status::Stage::Common)
+ def self.common_helpers
+ Status::Stage::Common
end
end
end
diff --git a/lib/gitlab/routing.rb b/lib/gitlab/routing.rb
index 5132177de51..632e2d87500 100644
--- a/lib/gitlab/routing.rb
+++ b/lib/gitlab/routing.rb
@@ -1,5 +1,11 @@
module Gitlab
module Routing
+ extend ActiveSupport::Concern
+
+ included do
+ include Gitlab::Routing.url_helpers
+ end
+
# Returns the URL helpers Module.
#
# This method caches the output as Rails' "url_helpers" method creates an
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index c443af09075..62466c06194 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -12,12 +12,14 @@ FactoryGirl.define do
started_at 'Di 29. Okt 09:51:28 CET 2013'
finished_at 'Di 29. Okt 09:53:28 CET 2013'
commands 'ls -a'
+
options do
{
image: "ruby:2.1",
services: ["postgres"]
}
end
+
yaml_variables do
[
{ key: :DB_NAME, value: 'postgres', public: true }
@@ -60,15 +62,20 @@ FactoryGirl.define do
end
trait :teardown_environment do
- options do
- { environment: { action: 'stop' } }
- end
+ environment 'staging'
+ options environment: { name: 'staging',
+ action: 'stop' }
end
trait :allowed_to_fail do
allow_failure true
end
+ trait :playable do
+ skipped
+ manual
+ end
+
after(:build) do |build, evaluator|
build.project = build.pipeline.project
end
diff --git a/spec/lib/gitlab/allowable_spec.rb b/spec/lib/gitlab/allowable_spec.rb
new file mode 100644
index 00000000000..87733d53e92
--- /dev/null
+++ b/spec/lib/gitlab/allowable_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Gitlab::Allowable do
+ subject do
+ Class.new.include(described_class).new
+ end
+
+ describe '#can?' do
+ let(:user) { create(:user) }
+
+ context 'when user is allowed to do something' do
+ let(:project) { create(:empty_project, :public) }
+
+ it 'reports correct ability to perform action' do
+ expect(subject.can?(user, :read_project, project)).to be true
+ end
+ end
+
+ context 'when user is not allowed to do something' do
+ let(:project) { create(:empty_project, :private) }
+
+ it 'reports correct ability to perform action' do
+ expect(subject.can?(user, :read_project, project)).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
new file mode 100644
index 00000000000..9376bce17a1
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
@@ -0,0 +1,86 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Cancelable do
+ let(:status) { double('core status') }
+ let(:user) { double('user') }
+
+ subject do
+ described_class.new(status)
+ end
+
+ describe '#text' do
+ it 'does not override status text' do
+ expect(status).to receive(:text)
+
+ subject.text
+ end
+ end
+
+ describe '#icon' do
+ it 'does not override status icon' do
+ expect(status).to receive(:icon)
+
+ subject.icon
+ end
+ end
+
+ describe '#label' do
+ it 'does not override status label' do
+ expect(status).to receive(:label)
+
+ subject.label
+ end
+ end
+
+ describe 'action details' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ describe '#has_action?' do
+ context 'when user is allowed to update build' do
+ before { build.project.team << [user, :developer] }
+
+ it { is_expected.to have_action }
+ end
+
+ context 'when user is not allowed to update build' do
+ it { is_expected.not_to have_action }
+ end
+ end
+
+ describe '#action_path' do
+ it { expect(subject.action_path).to include "#{build.id}/cancel" }
+ end
+
+ describe '#action_icon' do
+ it { expect(subject.action_icon).to eq 'ban' }
+ end
+
+ describe '#action_title' do
+ it { expect(subject.action_title).to eq 'Cancel' }
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is cancelable' do
+ let(:build) do
+ create(:ci_build, :running)
+ end
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not cancelable' do
+ let(:build) { create(:ci_build, :success) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb
new file mode 100644
index 00000000000..40b96b1807b
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/common_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Common do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:project) { build.project }
+
+ subject do
+ Gitlab::Ci::Status::Core
+ .new(build, user)
+ .extend(described_class)
+ end
+
+ describe '#has_action?' do
+ it { is_expected.not_to have_action }
+ end
+
+ describe '#has_details?' do
+ context 'when user has access to read build' do
+ before { project.team << [user, :developer] }
+
+ it { is_expected.to have_details }
+ end
+
+ context 'when user does not have access to read build' do
+ before { project.update(public_builds: false) }
+
+ it { is_expected.not_to have_details }
+ end
+ end
+
+ describe '#details_path' do
+ it 'links to the build details page' do
+ expect(subject.details_path).to include "builds/#{build.id}"
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb
new file mode 100644
index 00000000000..dccb29b5ef6
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb
@@ -0,0 +1,141 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Factory do
+ let(:user) { create(:user) }
+ let(:project) { build.project }
+
+ subject { described_class.new(build, user) }
+ let(:status) { subject.fabricate! }
+
+ before { project.team << [user, :developer] }
+
+ context 'when build is successful' do
+ let(:build) { create(:ci_build, :success) }
+
+ it 'fabricates a retryable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'passed'
+ expect(status.icon).to eq 'icon_status_success'
+ expect(status.label).to eq 'passed'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is failed' do
+ let(:build) { create(:ci_build, :failed) }
+
+ it 'fabricates a retryable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'failed'
+ expect(status.icon).to eq 'icon_status_failed'
+ expect(status.label).to eq 'failed'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is a canceled' do
+ let(:build) { create(:ci_build, :canceled) }
+
+ it 'fabricates a retryable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'canceled'
+ expect(status.icon).to eq 'icon_status_canceled'
+ expect(status.label).to eq 'canceled'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is running' do
+ let(:build) { create(:ci_build, :running) }
+
+ it 'fabricates a canceable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Cancelable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'running'
+ expect(status.icon).to eq 'icon_status_running'
+ expect(status.label).to eq 'running'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is pending' do
+ let(:build) { create(:ci_build, :pending) }
+
+ it 'fabricates a cancelable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Cancelable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'pending'
+ expect(status.icon).to eq 'icon_status_pending'
+ expect(status.label).to eq 'pending'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is skipped' do
+ let(:build) { create(:ci_build, :skipped) }
+
+ it 'fabricates a core skipped status' do
+ expect(status).to be_a Gitlab::Ci::Status::Skipped
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'skipped'
+ expect(status.icon).to eq 'icon_status_skipped'
+ expect(status.label).to eq 'skipped'
+ expect(status).to have_details
+ expect(status).not_to have_action
+ end
+ end
+
+ context 'when build is a manual action' do
+ context 'when build is a play action' do
+ let(:build) { create(:ci_build, :playable) }
+
+ it 'fabricates a core skipped status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Play
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'manual'
+ expect(status.icon).to eq 'icon_status_manual'
+ expect(status.label).to eq 'manual play action'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is an environment stop action' do
+ let(:build) { create(:ci_build, :playable, :teardown_environment) }
+
+ it 'fabricates a core skipped status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Stop
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'manual'
+ expect(status.icon).to eq 'icon_status_manual'
+ expect(status.label).to eq 'manual stop action'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb
new file mode 100644
index 00000000000..4ddf04a8e11
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/play_spec.rb
@@ -0,0 +1,82 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Play do
+ let(:status) { double('core') }
+ let(:user) { double('user') }
+
+ subject { described_class.new(status) }
+
+ describe '#text' do
+ it { expect(subject.text).to eq 'manual' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'manual play action' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_manual' }
+ end
+
+ describe 'action details' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ describe '#has_action?' do
+ context 'when user is allowed to update build' do
+ before { build.project.team << [user, :developer] }
+
+ it { is_expected.to have_action }
+ end
+
+ context 'when user is not allowed to update build' do
+ it { is_expected.not_to have_action }
+ end
+ end
+
+ describe '#action_path' do
+ it { expect(subject.action_path).to include "#{build.id}/play" }
+ end
+
+ describe '#action_icon' do
+ it { expect(subject.action_icon).to eq 'play' }
+ end
+
+ describe '#action_title' do
+ it { expect(subject.action_title).to eq 'Play' }
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is playable' do
+ context 'when build stops an environment' do
+ let(:build) do
+ create(:ci_build, :playable, :teardown_environment)
+ end
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+
+ context 'when build does not stop an environment' do
+ let(:build) { create(:ci_build, :playable) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+ end
+
+ context 'when build is not playable' do
+ let(:build) { create(:ci_build) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
new file mode 100644
index 00000000000..d61e5bbaa6b
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
@@ -0,0 +1,86 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Retryable do
+ let(:status) { double('core status') }
+ let(:user) { double('user') }
+
+ subject do
+ described_class.new(status)
+ end
+
+ describe '#text' do
+ it 'does not override status text' do
+ expect(status).to receive(:text)
+
+ subject.text
+ end
+ end
+
+ describe '#icon' do
+ it 'does not override status icon' do
+ expect(status).to receive(:icon)
+
+ subject.icon
+ end
+ end
+
+ describe '#label' do
+ it 'does not override status label' do
+ expect(status).to receive(:label)
+
+ subject.label
+ end
+ end
+
+ describe 'action details' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ describe '#has_action?' do
+ context 'when user is allowed to update build' do
+ before { build.project.team << [user, :developer] }
+
+ it { is_expected.to have_action }
+ end
+
+ context 'when user is not allowed to update build' do
+ it { is_expected.not_to have_action }
+ end
+ end
+
+ describe '#action_path' do
+ it { expect(subject.action_path).to include "#{build.id}/retry" }
+ end
+
+ describe '#action_icon' do
+ it { expect(subject.action_icon).to eq 'refresh' }
+ end
+
+ describe '#action_title' do
+ it { expect(subject.action_title).to eq 'Retry' }
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is retryable' do
+ let(:build) do
+ create(:ci_build, :success)
+ end
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not retryable' do
+ let(:build) { create(:ci_build, :running) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb
new file mode 100644
index 00000000000..59a85b55f90
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb
@@ -0,0 +1,84 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Stop do
+ let(:status) { double('core status') }
+ let(:user) { double('user') }
+
+ subject do
+ described_class.new(status)
+ end
+
+ describe '#text' do
+ it { expect(subject.text).to eq 'manual' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'manual stop action' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_manual' }
+ end
+
+ describe 'action details' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ describe '#has_action?' do
+ context 'when user is allowed to update build' do
+ before { build.project.team << [user, :developer] }
+
+ it { is_expected.to have_action }
+ end
+
+ context 'when user is not allowed to update build' do
+ it { is_expected.not_to have_action }
+ end
+ end
+
+ describe '#action_path' do
+ it { expect(subject.action_path).to include "#{build.id}/play" }
+ end
+
+ describe '#action_icon' do
+ it { expect(subject.action_icon).to eq 'stop' }
+ end
+
+ describe '#action_title' do
+ it { expect(subject.action_title).to eq 'Stop' }
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is playable' do
+ context 'when build stops an environment' do
+ let(:build) do
+ create(:ci_build, :playable, :teardown_environment)
+ end
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build does not stop an environment' do
+ let(:build) { create(:ci_build, :playable) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+
+ context 'when build is not playable' do
+ let(:build) { create(:ci_build) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/canceled_spec.rb b/spec/lib/gitlab/ci/status/canceled_spec.rb
index 619ecbcba67..4639278ad45 100644
--- a/spec/lib/gitlab/ci/status/canceled_spec.rb
+++ b/spec/lib/gitlab/ci/status/canceled_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Canceled do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'canceled' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Canceled do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_canceled' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: canceled' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/created_spec.rb b/spec/lib/gitlab/ci/status/created_spec.rb
index 157302c65a8..2ce176a29d6 100644
--- a/spec/lib/gitlab/ci/status/created_spec.rb
+++ b/spec/lib/gitlab/ci/status/created_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Created do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'created' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Created do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_created' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: created' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/extended_spec.rb b/spec/lib/gitlab/ci/status/extended_spec.rb
index 120e121aae5..c2d74ca5cde 100644
--- a/spec/lib/gitlab/ci/status/extended_spec.rb
+++ b/spec/lib/gitlab/ci/status/extended_spec.rb
@@ -2,11 +2,11 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Extended do
subject do
- Class.new.extend(described_class)
+ Class.new.include(described_class)
end
it 'requires subclass to implement matcher' do
- expect { subject.matches?(double) }
+ expect { subject.matches?(double, double) }
.to raise_error(NotImplementedError)
end
end
diff --git a/spec/lib/gitlab/ci/status/factory_spec.rb b/spec/lib/gitlab/ci/status/factory_spec.rb
index d5bd7f7102b..f92a1c149bf 100644
--- a/spec/lib/gitlab/ci/status/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/factory_spec.rb
@@ -2,15 +2,17 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Factory do
subject do
- described_class.new(object)
+ described_class.new(resource, user)
end
+ let(:user) { create(:user) }
+
let(:status) { subject.fabricate! }
context 'when object has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do
- let(:object) { double(status: core_status) }
+ let(:resource) { double(status: core_status) }
it "fabricates a core status #{core_status}" do
expect(status).to be_a(
diff --git a/spec/lib/gitlab/ci/status/failed_spec.rb b/spec/lib/gitlab/ci/status/failed_spec.rb
index 0b3cb8168e6..9d527e6a7ef 100644
--- a/spec/lib/gitlab/ci/status/failed_spec.rb
+++ b/spec/lib/gitlab/ci/status/failed_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Failed do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'failed' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Failed do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_failed' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: failed' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/pending_spec.rb b/spec/lib/gitlab/ci/status/pending_spec.rb
index 57c901c1202..d03f595d3c7 100644
--- a/spec/lib/gitlab/ci/status/pending_spec.rb
+++ b/spec/lib/gitlab/ci/status/pending_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Pending do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'pending' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Pending do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_pending' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: pending' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
index 21adee3f8e7..d665674bf70 100644
--- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
@@ -1,23 +1,36 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Pipeline::Common do
- let(:pipeline) { create(:ci_pipeline) }
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project, :private) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
subject do
- Class.new(Gitlab::Ci::Status::Core)
- .new(pipeline).extend(described_class)
+ Gitlab::Ci::Status::Core
+ .new(pipeline, user)
+ .extend(described_class)
end
- it 'does not have action' do
- expect(subject).not_to have_action
+ describe '#has_action?' do
+ it { is_expected.not_to have_action }
end
- it 'has details' do
- expect(subject).to have_details
+ describe '#has_details?' do
+ context 'when user has access to read pipeline' do
+ before { project.team << [user, :developer] }
+
+ it { is_expected.to have_details }
+ end
+
+ context 'when user does not have access to read pipeline' do
+ it { is_expected.not_to have_details }
+ end
end
- it 'links to the pipeline details page' do
- expect(subject.details_path)
- .to include "pipelines/#{pipeline.id}"
+ describe '#details_path' do
+ it 'links to the pipeline details page' do
+ expect(subject.details_path)
+ .to include "pipelines/#{pipeline.id}"
+ end
end
end
diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
index d6243940f2e..d4a2dc7fcc1 100644
--- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
@@ -1,14 +1,21 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Pipeline::Factory do
+ let(:user) { create(:user) }
+ let(:project) { pipeline.project }
+
subject do
- described_class.new(pipeline)
+ described_class.new(pipeline, user)
end
let(:status) do
subject.fabricate!
end
+ before do
+ project.team << [user, :developer]
+ end
+
context 'when pipeline has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do
diff --git a/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb b/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
index 02e526e3de2..7e3383c307f 100644
--- a/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
@@ -29,13 +29,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
end
it 'is a correct match' do
- expect(described_class.matches?(pipeline)).to eq true
+ expect(described_class.matches?(pipeline, double)).to eq true
end
end
context 'when pipeline does not have warnings' do
it 'does not match' do
- expect(described_class.matches?(pipeline)).to eq false
+ expect(described_class.matches?(pipeline, double)).to eq false
end
end
end
@@ -51,13 +51,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
end
it 'does not match' do
- expect(described_class.matches?(pipeline)).to eq false
+ expect(described_class.matches?(pipeline, double)).to eq false
end
end
context 'when pipeline does not have warnings' do
it 'does not match' do
- expect(described_class.matches?(pipeline)).to eq false
+ expect(described_class.matches?(pipeline, double)).to eq false
end
end
end
diff --git a/spec/lib/gitlab/ci/status/running_spec.rb b/spec/lib/gitlab/ci/status/running_spec.rb
index c023f1872cc..9f47090d396 100644
--- a/spec/lib/gitlab/ci/status/running_spec.rb
+++ b/spec/lib/gitlab/ci/status/running_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Running do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'running' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Running do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_running' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: running' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/skipped_spec.rb b/spec/lib/gitlab/ci/status/skipped_spec.rb
index d4f7f4b3b70..94601648a8d 100644
--- a/spec/lib/gitlab/ci/status/skipped_spec.rb
+++ b/spec/lib/gitlab/ci/status/skipped_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Skipped do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'skipped' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Skipped do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_skipped' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: skipped' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/stage/common_spec.rb b/spec/lib/gitlab/ci/status/stage/common_spec.rb
index f3259c6f23e..8814a7614a0 100644
--- a/spec/lib/gitlab/ci/status/stage/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/common_spec.rb
@@ -1,26 +1,43 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Stage::Common do
- let(:pipeline) { create(:ci_empty_pipeline) }
- let(:stage) { build(:ci_stage, pipeline: pipeline, name: 'test') }
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
+
+ let(:stage) do
+ build(:ci_stage, pipeline: pipeline, name: 'test')
+ end
subject do
Class.new(Gitlab::Ci::Status::Core)
- .new(stage).extend(described_class)
+ .new(stage, user).extend(described_class)
end
it 'does not have action' do
expect(subject).not_to have_action
end
- it 'has details' do
- expect(subject).to have_details
- end
-
it 'links to the pipeline details page' do
expect(subject.details_path)
.to include "pipelines/#{pipeline.id}"
expect(subject.details_path)
.to include "##{stage.name}"
end
+
+ context 'when user has permission to read pipeline' do
+ before do
+ project.team << [user, :master]
+ end
+
+ it 'has details' do
+ expect(subject).to have_details
+ end
+ end
+
+ context 'when user does not have permission to read pipeline' do
+ it 'does not have details' do
+ expect(subject).not_to have_details
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
index 17929665c83..6f8721d30c2 100644
--- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
@@ -1,17 +1,26 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Stage::Factory do
- let(:pipeline) { create(:ci_empty_pipeline) }
- let(:stage) { build(:ci_stage, pipeline: pipeline, name: 'test') }
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
+
+ let(:stage) do
+ build(:ci_stage, pipeline: pipeline, name: 'test')
+ end
subject do
- described_class.new(stage)
+ described_class.new(stage, user)
end
let(:status) do
subject.fabricate!
end
+ before do
+ project.team << [user, :developer]
+ end
+
context 'when stage has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do
diff --git a/spec/lib/gitlab/ci/status/success_spec.rb b/spec/lib/gitlab/ci/status/success_spec.rb
index 9e261a3aa5f..90f9f615e0d 100644
--- a/spec/lib/gitlab/ci/status/success_spec.rb
+++ b/spec/lib/gitlab/ci/status/success_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Success do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'passed' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Success do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_success' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: passed' }
- end
end
diff --git a/spec/lib/gitlab/routing_spec.rb b/spec/lib/gitlab/routing_spec.rb
new file mode 100644
index 00000000000..01d5acfc15b
--- /dev/null
+++ b/spec/lib/gitlab/routing_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Gitlab::Routing do
+ context 'when module is included' do
+ subject do
+ Class.new.include(described_class).new
+ end
+
+ it 'makes it possible to access url helpers' do
+ expect(subject).to respond_to(:namespace_project_path)
+ end
+ end
+
+ context 'when module is not included' do
+ subject do
+ Class.new.include(described_class.url_helpers).new
+ end
+
+ it 'exposes url helpers module through a method' do
+ expect(subject).to respond_to(:namespace_project_path)
+ end
+ end
+end
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index d4970e38f7c..7f39aff7639 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -899,21 +899,87 @@ describe Ci::Build, models: true do
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
- context 'when build is running' do
- before do
- build.run!
+ 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
- it { expect(build).not_to be_retryable }
+ context 'when build is canceled' do
+ before do
+ build.cancel!
+ end
+
+ it { is_expected.to be_retryable }
+ end
end
- context 'when build is finished' do
- before do
- build.success!
+ 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
- it { expect(build).to be_retryable }
+ context 'when build is skipped' do
+ before do
+ build.skip!
+ end
+
+ it { is_expected.not_to be_retryable }
+ end
end
end
@@ -1180,4 +1246,13 @@ describe Ci::Build, models: true do
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
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 8158e71dd55..e78ae14b737 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -442,11 +442,15 @@ describe Ci::Pipeline, models: true do
end
describe '#detailed_status' do
+ let(:user) { create(:user) }
+
+ subject { pipeline.detailed_status(user) }
+
context 'when pipeline is created' do
let(:pipeline) { create(:ci_pipeline, status: :created) }
it 'returns detailed status for created pipeline' do
- expect(pipeline.detailed_status.text).to eq 'created'
+ expect(subject.text).to eq 'created'
end
end
@@ -454,7 +458,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :pending) }
it 'returns detailed status for pending pipeline' do
- expect(pipeline.detailed_status.text).to eq 'pending'
+ expect(subject.text).to eq 'pending'
end
end
@@ -462,7 +466,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :running) }
it 'returns detailed status for running pipeline' do
- expect(pipeline.detailed_status.text).to eq 'running'
+ expect(subject.text).to eq 'running'
end
end
@@ -470,7 +474,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :success) }
it 'returns detailed status for successful pipeline' do
- expect(pipeline.detailed_status.text).to eq 'passed'
+ expect(subject.text).to eq 'passed'
end
end
@@ -478,7 +482,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :failed) }
it 'returns detailed status for failed pipeline' do
- expect(pipeline.detailed_status.text).to eq 'failed'
+ expect(subject.text).to eq 'failed'
end
end
@@ -486,7 +490,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :canceled) }
it 'returns detailed status for canceled pipeline' do
- expect(pipeline.detailed_status.text).to eq 'canceled'
+ expect(subject.text).to eq 'canceled'
end
end
@@ -494,7 +498,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :skipped) }
it 'returns detailed status for skipped pipeline' do
- expect(pipeline.detailed_status.text).to eq 'skipped'
+ expect(subject.text).to eq 'skipped'
end
end
@@ -506,7 +510,7 @@ describe Ci::Pipeline, models: true do
end
it 'retruns detailed status for successful pipeline with warnings' do
- expect(pipeline.detailed_status.label).to eq 'passed with warnings'
+ expect(subject.label).to eq 'passed with warnings'
end
end
end
diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb
index f232761dba2..8fff38f7cda 100644
--- a/spec/models/ci/stage_spec.rb
+++ b/spec/models/ci/stage_spec.rb
@@ -68,7 +68,9 @@ describe Ci::Stage, models: true do
end
describe '#detailed_status' do
- subject { stage.detailed_status }
+ let(:user) { create(:user) }
+
+ subject { stage.detailed_status(user) }
context 'when build is created' do
let!(:stage_build) { create_job(:ci_build, status: :created) }
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 1ec08c2a9d0..701f3323c0f 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -234,4 +234,13 @@ describe CommitStatus, models: true do
end
end
end
+
+ describe '#detailed_status' do
+ let(:user) { create(:user) }
+
+ it 'returns a detailed status' do
+ expect(commit_status.detailed_status(user))
+ .to be_a Gitlab::Ci::Status::Success
+ end
+ end
end
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
index 615cfe3142b..6004bfdb7b7 100644
--- a/spec/models/generic_commit_status_spec.rb
+++ b/spec/models/generic_commit_status_spec.rb
@@ -1,8 +1,11 @@
require 'spec_helper'
describe GenericCommitStatus, models: true do
- let(:pipeline) { FactoryGirl.create :ci_pipeline }
- let(:generic_commit_status) { FactoryGirl.create :generic_commit_status, pipeline: pipeline }
+ let(:pipeline) { create(:ci_pipeline) }
+
+ let(:generic_commit_status) do
+ create(:generic_commit_status, pipeline: pipeline)
+ end
describe '#context' do
subject { generic_commit_status.context }
@@ -17,6 +20,15 @@ describe GenericCommitStatus, models: true do
it { is_expected.to eq([:external]) }
end
+ describe '#detailed_status' do
+ let(:user) { create(:user) }
+
+ it 'returns detailed status object' do
+ expect(generic_commit_status.detailed_status(user))
+ .to be_a Gitlab::Ci::Status::Success
+ end
+ end
+
describe 'set_default_values' do
before do
generic_commit_status.context = nil