Commit d3b7250c authored by Kamil Trzcinski's avatar Kamil Trzcinski

Merge branch 'build-statuses' into 22604-manual-actions

parents fc57b314 c1db5b91
class Ability class Ability
module Allowable
def can?(user, action, subject)
Ability.allowed?(user, action, subject)
end
end
class << self class << self
# Given a list of users and a project this method returns the users that can # Given a list of users and a project this method returns the users that can
# read the given project. # read the given project.
......
...@@ -3,10 +3,10 @@ module Gitlab ...@@ -3,10 +3,10 @@ module Gitlab
module Status module Status
module Status module Status
class Cancelable < SimpleDelegator class Cancelable < SimpleDelegator
extend Status::Extended include Status::Extended
def has_action?(current_user) def has_action?
can?(current_user, :update_build, subject) can?(user, :update_build, subject)
end end
def action_icon def action_icon
...@@ -14,14 +14,16 @@ module Gitlab ...@@ -14,14 +14,16 @@ module Gitlab
end end
def action_path def action_path
cancel_namespace_project_build_path(subject.project.namespace, subject.project, subject) cancel_namespace_project_build_path(subject.project.namespace,
subject.project,
subject)
end end
def action_method def action_method
:post :post
end end
def self.matches?(build) def self.matches?(build, user)
build.cancelable? build.cancelable?
end end
end end
......
...@@ -3,14 +3,14 @@ module Gitlab ...@@ -3,14 +3,14 @@ module Gitlab
module Status module Status
module Build module Build
module Common module Common
def has_details?(current_user) def has_details?
can?(current_user, :read_build, subject) can?(user, :read_build, subject)
end end
def details_path def details_path
namespace_project_build_path(@subject.project.namespace, namespace_project_build_path(subject.project.namespace,
@subject.project, subject.project,
@subject.pipeline) subject.pipeline)
end end
end end
end end
......
...@@ -3,14 +3,13 @@ module Gitlab ...@@ -3,14 +3,13 @@ module Gitlab
module Status module Status
module Build module Build
class Factory < Status::Factory class Factory < Status::Factory
private def self.extended_statuses
[Status::Build::Stop, Status::Build::Play,
def extended_statuses Status::Build::Cancelable, Status::Build::Retryable]
[Stop, Play, Cancelable, Retryable]
end end
def core_status def self.common_helpers
super.extend(Status::Build::Common) Status::Build::Common
end end
end end
end end
......
...@@ -3,7 +3,7 @@ module Gitlab ...@@ -3,7 +3,7 @@ module Gitlab
module Status module Status
module Status module Status
class Play < SimpleDelegator class Play < SimpleDelegator
extend Status::Extended include Status::Extended
def text def text
'play' 'play'
...@@ -13,8 +13,8 @@ module Gitlab ...@@ -13,8 +13,8 @@ module Gitlab
'play' 'play'
end end
def has_action?(current_user) def has_action?
can?(current_user, :update_build, subject) can?(user, :update_build, subject)
end end
def action_icon def action_icon
...@@ -22,14 +22,16 @@ module Gitlab ...@@ -22,14 +22,16 @@ module Gitlab
end end
def action_path def action_path
play_namespace_project_build_path(subject.project.namespace, subject.project, subject) play_namespace_project_build_path(subject.project.namespace,
subject.project,
subject)
end end
def action_method def action_method
:post :post
end end
def self.matches?(build) def self.matches?(build, user)
build.playable? && !build.stops_environment? build.playable? && !build.stops_environment?
end end
end end
......
...@@ -3,10 +3,10 @@ module Gitlab ...@@ -3,10 +3,10 @@ module Gitlab
module Status module Status
module Status module Status
class Retryable < SimpleDelegator class Retryable < SimpleDelegator
extend Status::Extended include Status::Extended
def has_action?(current_user) def has_action?
can?(current_user, :update_build, subject) can?(user, :update_build, subject)
end end
def action_icon def action_icon
...@@ -14,14 +14,16 @@ module Gitlab ...@@ -14,14 +14,16 @@ module Gitlab
end end
def action_path def action_path
retry_namespace_project_build_path(subject.project.namespace, subject.project, subject) retry_namespace_project_build_path(subject.project.namespace,
subject.project,
subject)
end end
def action_method def action_method
:post :post
end end
def self.matches?(build) def self.matches?(build, user)
build.retryable? build.retryable?
end end
end end
......
...@@ -3,7 +3,7 @@ module Gitlab ...@@ -3,7 +3,7 @@ module Gitlab
module Status module Status
module Status module Status
class Play < SimpleDelegator class Play < SimpleDelegator
extend Status::Extended include Status::Extended
def text def text
'stop' 'stop'
...@@ -21,8 +21,8 @@ module Gitlab ...@@ -21,8 +21,8 @@ module Gitlab
'stop' 'stop'
end end
def has_action?(current_user) def has_action?
can?(current_user, :update_build, subject) can?(user, :update_build, subject)
end end
def action_icon def action_icon
...@@ -30,14 +30,16 @@ module Gitlab ...@@ -30,14 +30,16 @@ module Gitlab
end end
def action_path def action_path
play_namespace_project_build_path(subject.project.namespace, subject.project, subject) play_namespace_project_build_path(subject.project.namespace,
subject.project,
subject)
end end
def action_method def action_method
:post :post
end end
def self.matches?(build) def self.matches?(build, user)
build.playable? && build.stops_environment? build.playable? && build.stops_environment?
end end
end end
......
...@@ -5,9 +5,13 @@ module Gitlab ...@@ -5,9 +5,13 @@ module Gitlab
# #
class Core class Core
include Gitlab::Routing.url_helpers include Gitlab::Routing.url_helpers
include Ability::Allowable
def initialize(subject) attr_reader :subject, :user
def initialize(subject, user)
@subject = subject @subject = subject
@user = user
end end
def icon def icon
...@@ -18,10 +22,6 @@ module Gitlab ...@@ -18,10 +22,6 @@ module Gitlab
raise NotImplementedError raise NotImplementedError
end end
def title
"#{@subject.class.name.demodulize}: #{label}"
end
# Deprecation warning: this method is here because we need to maintain # Deprecation warning: this method is here because we need to maintain
# backwards compatibility with legacy statuses. We often do something # backwards compatibility with legacy statuses. We often do something
# like "ci-status ci-status-#{status}" to set CSS class. # like "ci-status ci-status-#{status}" to set CSS class.
...@@ -33,7 +33,7 @@ module Gitlab ...@@ -33,7 +33,7 @@ module Gitlab
self.class.name.demodulize.downcase.underscore self.class.name.demodulize.downcase.underscore
end end
def has_details?(_user = nil) def has_details?
false false
end end
...@@ -41,7 +41,7 @@ module Gitlab ...@@ -41,7 +41,7 @@ module Gitlab
raise NotImplementedError raise NotImplementedError
end end
def has_action?(_user = nil) def has_action?
false false
end end
......
...@@ -2,8 +2,12 @@ module Gitlab ...@@ -2,8 +2,12 @@ module Gitlab
module Ci module Ci
module Status module Status
module Extended module Extended
def matches?(_subject) extend ActiveSupport::Concern
raise NotImplementedError
class_methods do
def matches?(_subject, _user)
raise NotImplementedError
end
end end
end end
end end
......
...@@ -2,10 +2,9 @@ module Gitlab ...@@ -2,10 +2,9 @@ module Gitlab
module Ci module Ci
module Status module Status
class Factory class Factory
attr_reader :subject def initialize(subject, user)
def initialize(subject)
@subject = subject @subject = subject
@user = user
end end
def fabricate! def fabricate!
...@@ -16,27 +15,32 @@ module Gitlab ...@@ -16,27 +15,32 @@ module Gitlab
end end
end end
def self.extended_statuses
[]
end
def self.common_helpers
Module.new
end
private private
def subject_status def simple_status
@subject_status ||= subject.status @simple_status ||= @subject.status || :created
end end
def core_status def core_status
Gitlab::Ci::Status Gitlab::Ci::Status
.const_get(subject_status.capitalize) .const_get(simple_status.capitalize)
.new(subject) .new(@subject, @user)
.extend(self.class.common_helpers)
end end
def extended_status def extended_status
@extended ||= extended_statuses.find do |status| @extended ||= self.class.extended_statuses.find do |status|
status.matches?(subject) status.matches?(@subject, @user)
end end
end end
def extended_statuses
[]
end
end end
end end
end end
......
...@@ -3,14 +3,14 @@ module Gitlab ...@@ -3,14 +3,14 @@ module Gitlab
module Status module Status
module Pipeline module Pipeline
module Common module Common
def has_details?(current_user) def has_details?
can?(current_user, :read_pipeline, subject) can?(user, :read_pipeline, subject)
end end
def details_path def details_path
namespace_project_pipeline_path(@subject.project.namespace, namespace_project_pipeline_path(subject.project.namespace,
@subject.project, subject.project,
@subject) subject)
end end
def has_action? def has_action?
......
...@@ -3,14 +3,12 @@ module Gitlab ...@@ -3,14 +3,12 @@ module Gitlab
module Status module Status
module Pipeline module Pipeline
class Factory < Status::Factory class Factory < Status::Factory
private def self.extended_statuses
def extended_statuses
[Pipeline::SuccessWithWarnings] [Pipeline::SuccessWithWarnings]
end end
def core_status def self.common_helpers
super.extend(Status::Pipeline::Common) Status::Pipeline::Common
end end
end end
end end
......
...@@ -3,7 +3,7 @@ module Gitlab ...@@ -3,7 +3,7 @@ module Gitlab
module Status module Status
module Pipeline module Pipeline
class SuccessWithWarnings < SimpleDelegator class SuccessWithWarnings < SimpleDelegator
extend Status::Extended include Status::Extended
def text def text
'passed' 'passed'
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
'success_with_warnings' 'success_with_warnings'
end end
def self.matches?(pipeline) def self.matches?(pipeline, user)
pipeline.success? && pipeline.has_warnings? pipeline.success? && pipeline.has_warnings?
end end
end end
......
...@@ -3,15 +3,15 @@ module Gitlab ...@@ -3,15 +3,15 @@ module Gitlab
module Status module Status
module Stage module Stage
module Common module Common
def has_details?(current_user) def has_details?
can?(current_user, :read_pipeline, subject) can?(user, :read_pipeline, subject.pipeline)
end end
def details_path def details_path
namespace_project_pipeline_path(@subject.project.namespace, namespace_project_pipeline_path(subject.project.namespace,
@subject.project, subject.project,
@subject.pipeline, subject.pipeline,
anchor: @subject.name) anchor: subject.name)
end end
def has_action? def has_action?
......
...@@ -3,10 +3,8 @@ module Gitlab ...@@ -3,10 +3,8 @@ module Gitlab
module Status module Status
module Stage module Stage
class Factory < Status::Factory class Factory < Status::Factory
private def self.common_helpers
Status::Stage::Common
def core_status
super.extend(Status::Stage::Common)
end end
end end
end end
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Canceled do 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 describe '#text' do
it { expect(subject.label).to eq 'canceled' } it { expect(subject.label).to eq 'canceled' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Canceled do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Canceled do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_canceled' } it { expect(subject.icon).to eq 'icon_status_canceled' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: canceled' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Created do 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 describe '#text' do
it { expect(subject.label).to eq 'created' } it { expect(subject.label).to eq 'created' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Created do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Created do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_created' } it { expect(subject.icon).to eq 'icon_status_created' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: created' }
end
end end
...@@ -2,11 +2,11 @@ require 'spec_helper' ...@@ -2,11 +2,11 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Extended do describe Gitlab::Ci::Status::Extended do
subject do subject do
Class.new.extend(described_class) Class.new.include(described_class)
end end
it 'requires subclass to implement matcher' do it 'requires subclass to implement matcher' do
expect { subject.matches?(double) } expect { subject.matches?(double, double) }
.to raise_error(NotImplementedError) .to raise_error(NotImplementedError)
end end
end end
...@@ -2,15 +2,17 @@ require 'spec_helper' ...@@ -2,15 +2,17 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Factory do describe Gitlab::Ci::Status::Factory do
subject do subject do
described_class.new(object) described_class.new(resource, user)
end end
let(:user) { create(:user) }
let(:status) { subject.fabricate! } let(:status) { subject.fabricate! }
context 'when object has a core status' do context 'when object has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status| HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do 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 it "fabricates a core status #{core_status}" do
expect(status).to be_a( expect(status).to be_a(
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Failed do 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 describe '#text' do
it { expect(subject.label).to eq 'failed' } it { expect(subject.label).to eq 'failed' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Failed do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Failed do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_failed' } it { expect(subject.icon).to eq 'icon_status_failed' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: failed' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Pending do 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 describe '#text' do
it { expect(subject.label).to eq 'pending' } it { expect(subject.label).to eq 'pending' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Pending do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Pending do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_pending' } it { expect(subject.icon).to eq 'icon_status_pending' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: pending' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Pipeline::Common do describe Gitlab::Ci::Status::Pipeline::Common do
let(:pipeline) { create(:ci_pipeline) } let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
subject do subject do
Class.new(Gitlab::Ci::Status::Core) Class.new(Gitlab::Ci::Status::Core)
.new(pipeline).extend(described_class) .new(pipeline, user)
.extend(described_class)
end
before do
project.team << [user, :developer]
end end
it 'does not have action' do it 'does not have action' do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Pipeline::Factory do describe Gitlab::Ci::Status::Pipeline::Factory do
let(:user) { create(:user) }
let(:project) { pipeline.project }
subject do subject do
described_class.new(pipeline) described_class.new(pipeline, user)
end end
let(:status) do let(:status) do
subject.fabricate! subject.fabricate!
end end
before do
project.team << [user, :developer]
end
context 'when pipeline has a core status' do context 'when pipeline has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status| HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do context "when core status is #{core_status}" do
......
...@@ -29,13 +29,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do ...@@ -29,13 +29,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
end end
it 'is a correct match' do 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
end end
context 'when pipeline does not have warnings' do context 'when pipeline does not have warnings' do
it 'does not match' 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 end
end end
...@@ -51,13 +51,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do ...@@ -51,13 +51,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
end end
it 'does not match' 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 end
context 'when pipeline does not have warnings' do context 'when pipeline does not have warnings' do
it 'does not match' 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 end
end end
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Running do 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 describe '#text' do
it { expect(subject.label).to eq 'running' } it { expect(subject.label).to eq 'running' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Running do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Running do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_running' } it { expect(subject.icon).to eq 'icon_status_running' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: running' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Skipped do 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 describe '#text' do
it { expect(subject.label).to eq 'skipped' } it { expect(subject.label).to eq 'skipped' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Skipped do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Skipped do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_skipped' } it { expect(subject.icon).to eq 'icon_status_skipped' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: skipped' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Stage::Common do describe Gitlab::Ci::Status::Stage::Common do
let(:pipeline) { create(:ci_empty_pipeline) } let(:user) { create(:user) }
let(:stage) { build(:ci_stage, pipeline: pipeline, name: 'test') } 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 subject do
Class.new(Gitlab::Ci::Status::Core) Class.new(Gitlab::Ci::Status::Core)
.new(stage).extend(described_class) .new(stage, user).extend(described_class)
end end
it 'does not have action' do it 'does not have action' do
expect(subject).not_to have_action expect(subject).not_to have_action
end end
it 'has details' do
expect(subject).to have_details
end
it 'links to the pipeline details page' do it 'links to the pipeline details page' do
expect(subject.details_path) expect(subject.details_path)
.to include "pipelines/#{pipeline.id}" .to include "pipelines/#{pipeline.id}"
expect(subject.details_path) expect(subject.details_path)
.to include "##{stage.name}" .to include "##{stage.name}"
end 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 end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Stage::Factory do describe Gitlab::Ci::Status::Stage::Factory do
let(:pipeline) { create(:ci_empty_pipeline) } let(:user) { create(:user) }
let(:stage) { build(:ci_stage, pipeline: pipeline, name: 'test') } 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 subject do
described_class.new(stage) described_class.new(stage, user)
end end
let(:status) do let(:status) do
subject.fabricate! subject.fabricate!
end end
before do
project.team << [user, :developer]
end
context 'when stage has a core status' do context 'when stage has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status| HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do context "when core status is #{core_status}" do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Success do 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 describe '#text' do
it { expect(subject.label).to eq 'passed' } it { expect(subject.label).to eq 'passed' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Success do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Success do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_success' } it { expect(subject.icon).to eq 'icon_status_success' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: passed' }
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment