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
This commit is contained in:
commit
3e90aa1119
58 changed files with 1126 additions and 171 deletions
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
10
app/views/ci/status/_badge.html.haml
Normal file
10
app/views/ci/status/_badge.html.haml
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
1
app/views/shared/icons/_icon_status_manual.svg
Executable file
1
app/views/shared/icons/_icon_status_manual.svg
Executable file
|
@ -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>
|
After Width: | Height: | Size: 787 B |
7
lib/gitlab/allowable.rb
Normal file
7
lib/gitlab/allowable.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
module Gitlab
|
||||
module Allowable
|
||||
def can?(user, action, subject)
|
||||
Ability.allowed?(user, action, subject)
|
||||
end
|
||||
end
|
||||
end
|
37
lib/gitlab/ci/status/build/cancelable.rb
Normal file
37
lib/gitlab/ci/status/build/cancelable.rb
Normal file
|
@ -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
|
19
lib/gitlab/ci/status/build/common.rb
Normal file
19
lib/gitlab/ci/status/build/common.rb
Normal file
|
@ -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
|
18
lib/gitlab/ci/status/build/factory.rb
Normal file
18
lib/gitlab/ci/status/build/factory.rb
Normal file
|
@ -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
|
53
lib/gitlab/ci/status/build/play.rb
Normal file
53
lib/gitlab/ci/status/build/play.rb
Normal file
|
@ -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
|
37
lib/gitlab/ci/status/build/retryable.rb
Normal file
37
lib/gitlab/ci/status/build/retryable.rb
Normal file
|
@ -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
|
49
lib/gitlab/ci/status/build/stop.rb
Normal file
49
lib/gitlab/ci/status/build/stop.rb
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
27
spec/lib/gitlab/allowable_spec.rb
Normal file
27
spec/lib/gitlab/allowable_spec.rb
Normal file
|
@ -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
|
86
spec/lib/gitlab/ci/status/build/cancelable_spec.rb
Normal file
86
spec/lib/gitlab/ci/status/build/cancelable_spec.rb
Normal file
|
@ -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
|
37
spec/lib/gitlab/ci/status/build/common_spec.rb
Normal file
37
spec/lib/gitlab/ci/status/build/common_spec.rb
Normal file
|
@ -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
|
141
spec/lib/gitlab/ci/status/build/factory_spec.rb
Normal file
141
spec/lib/gitlab/ci/status/build/factory_spec.rb
Normal file
|
@ -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
|
82
spec/lib/gitlab/ci/status/build/play_spec.rb
Normal file
82
spec/lib/gitlab/ci/status/build/play_spec.rb
Normal file
|
@ -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
|
86
spec/lib/gitlab/ci/status/build/retryable_spec.rb
Normal file
86
spec/lib/gitlab/ci/status/build/retryable_spec.rb
Normal file
|
@ -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
|
84
spec/lib/gitlab/ci/status/build/stop_spec.rb
Normal file
84
spec/lib/gitlab/ci/status/build/stop_spec.rb
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
23
spec/lib/gitlab/routing_spec.rb
Normal file
23
spec/lib/gitlab/routing_spec.rb
Normal file
|
@ -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
|
|
@ -899,21 +899,87 @@ describe Ci::Build, models: true do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#retryable?' do
|
||||
context 'when build is running' do
|
||||
before do
|
||||
build.run!
|
||||
describe '#cancelable?' do
|
||||
subject { build }
|
||||
|
||||
context 'when build is cancelable' do
|
||||
context 'when build is pending' do
|
||||
it { is_expected.to be_cancelable }
|
||||
end
|
||||
|
||||
it { expect(build).not_to be_retryable }
|
||||
context 'when build is running' do
|
||||
before do
|
||||
build.run!
|
||||
end
|
||||
|
||||
it { is_expected.to be_cancelable }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when build is finished' do
|
||||
before do
|
||||
build.success!
|
||||
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
|
||||
|
||||
it { expect(build).to be_retryable }
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue