Commit 6cd7ce33 authored by Grzegorz Bizon's avatar Grzegorz Bizon
Browse files

Merge branch 'backstage/gb/move-some-pipelines-code-from-ee-to-ee' into 'master'

Move to CE some EE pipelines-related code that belongs to CE

Closes gitlab-ee#3616

See merge request gitlab-org/gitlab-ce!14699
......@@ -72,6 +72,13 @@
:title="pipeline.yaml_errors">
yaml invalid
</span>
<span
v-if="pipeline.flags.failure_reason"
v-tooltip
class="js-pipeline-url-failure label label-danger"
:title="pipeline.failure_reason">
error
</span>
<a
v-if="pipeline.flags.auto_devops"
tabindex="0"
......
......@@ -5,6 +5,7 @@ class Pipeline < ActiveRecord::Base
include Importable
include AfterCommitQueue
include Presentable
include Gitlab::OptimisticLocking
belongs_to :project
belongs_to :user
......@@ -58,6 +59,11 @@ class Pipeline < ActiveRecord::Base
auto_devops_source: 2
}
enum failure_reason: {
unknown_failure: 0,
config_error: 1
}
state_machine :status, initial: :created do
event :enqueue do
transition created: :pending
......@@ -109,6 +115,12 @@ class Pipeline < ActiveRecord::Base
pipeline.auto_canceled_by = nil
end
before_transition any => :failed do |pipeline, transition|
transition.args.first.try do |reason|
pipeline.failure_reason = reason
end
end
after_transition [:created, :pending] => :running do |pipeline|
pipeline.run_after_commit { PipelineMetricsWorker.perform_async(pipeline.id) }
end
......@@ -263,7 +275,7 @@ def auto_canceled?
end
def cancel_running
Gitlab::OptimisticLocking.retry_lock(cancelable_statuses) do |cancelable|
retry_optimistic_lock(cancelable_statuses) do |cancelable|
cancelable.find_each do |job|
yield(job) if block_given?
job.cancel
......@@ -312,6 +324,10 @@ def stage_seeds
@stage_seeds ||= config_processor.stage_seeds(self)
end
def seeds_size
@seeds_size ||= stage_seeds.sum(&:size)
end
def has_kubernetes_active?
project.kubernetes_service&.active?
end
......@@ -403,7 +419,7 @@ def process!
end
def update_status
Gitlab::OptimisticLocking.retry_lock(self) do
retry_optimistic_lock(self) do
case latest_builds_status
when 'pending' then enqueue
when 'running' then run
......
......@@ -81,6 +81,7 @@ def all_state_names
scope :canceled, -> { where(status: 'canceled') }
scope :skipped, -> { where(status: 'skipped') }
scope :manual, -> { where(status: 'manual') }
scope :alive, -> { where(status: [:created, :pending, :running]) }
scope :created_or_pending, -> { where(status: [:created, :pending]) }
scope :running_or_pending, -> { where(status: [:running, :pending]) }
scope :finished, -> { where(status: [:success, :failed, :canceled]) }
......
module Ci
class PipelinePresenter < Gitlab::View::Presenter::Delegated
FAILURE_REASONS = {
config_error: 'CI/CD YAML configuration error!'
}.freeze
presents :pipeline
def failure_reason
return unless pipeline.failure_reason?
FAILURE_REASONS[pipeline.failure_reason.to_sym] ||
pipeline.failure_reason
end
def status_title
if auto_canceled?
"Pipeline is redundant and is auto-canceled by Pipeline ##{auto_canceled_by_id}"
......
......@@ -20,6 +20,7 @@ class PipelineEntity < Grape::Entity
expose :has_yaml_errors?, as: :yaml_errors
expose :can_retry?, as: :retryable
expose :can_cancel?, as: :cancelable
expose :failure_reason?, as: :failure_reason
end
expose :details do
......@@ -44,6 +45,11 @@ class PipelineEntity < Grape::Entity
end
expose :commit, using: CommitEntity
expose :yaml_errors, if: -> (pipeline, _) { pipeline.has_yaml_errors? }
expose :failure_reason, if: -> (pipeline, _) { pipeline.failure_reason? } do |pipeline|
pipeline.present.failure_reason
end
expose :retry_path, if: -> (*) { can_retry? } do |pipeline|
retry_project_pipeline_path(pipeline.project, pipeline)
......@@ -53,8 +59,6 @@ class PipelineEntity < Grape::Entity
cancel_project_pipeline_path(pipeline.project, pipeline)
end
expose :yaml_errors, if: -> (pipeline, _) { pipeline.has_yaml_errors? }
private
alias_method :pipeline, :object
......
class AddFailureReasonToPipelines < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_pipelines, :failure_reason, :integer
end
end
......@@ -342,6 +342,7 @@
t.integer "source"
t.integer "config_source"
t.boolean "protected"
t.integer "failure_reason"
end
add_index "ci_pipelines", ["auto_canceled_by_id"], name: "index_ci_pipelines_on_auto_canceled_by_id", using: :btree
......
......@@ -13,7 +13,7 @@ def perform!
end
if @command.save_incompleted && @pipeline.has_yaml_errors?
@pipeline.drop
@pipeline.drop!(:config_error)
end
return error(@pipeline.yaml_errors)
......
......@@ -3,7 +3,9 @@ module Ci
module Stage
class Seed
attr_reader :pipeline
delegate :project, to: :pipeline
delegate :size, to: :@jobs
def initialize(pipeline, stage, jobs)
@pipeline = pipeline
......
......@@ -47,6 +47,7 @@
trait :invalid do
config(rspec: nil)
failure_reason :config_error
end
trait :blocked do
......
......@@ -162,6 +162,16 @@
expect(page).to have_selector(
%Q{span[data-original-title="#{pipeline.yaml_errors}"]})
end
it 'contains badge that indicates failure reason' do
expect(page).to have_content 'error'
end
it 'contains badge with tooltip which contains failure reason' do
expect(pipeline.failure_reason?).to eq true
expect(page).to have_selector(
%Q{span[data-original-title="#{pipeline.present.failure_reason}"]})
end
end
context 'with manual actions' do
......
......@@ -125,4 +125,23 @@ describe('Pipeline Url Component', () => {
component.$el.querySelector('.js-pipeline-url-autodevops').textContent.trim(),
).toEqual('Auto DevOps');
});
it('should render error badge when pipeline has a failure reason set', () => {
const component = new PipelineUrlComponent({
propsData: {
pipeline: {
id: 1,
path: 'foo',
flags: {
failure_reason: true,
},
failure_reason: 'some reason',
},
autoDevopsHelpPath: 'foo',
},
}).$mount();
expect(component.$el.querySelector('.js-pipeline-url-failure').textContent).toContain('error');
expect(component.$el.querySelector('.js-pipeline-url-failure').getAttribute('data-original-title')).toContain('some reason');
});
});
......@@ -55,6 +55,10 @@
it 'fails the pipeline' do
expect(pipeline.reload).to be_failed
end
it 'sets a config error failure reason' do
expect(pipeline.reload.config_error?).to eq true
end
end
context 'when saving incomplete pipeline is not allowed' do
......
......@@ -11,6 +11,12 @@
described_class.new(pipeline, 'test', builds)
end
describe '#size' do
it 'returns a number of jobs in the stage' do
expect(subject.size).to eq 2
end
end
describe '#stage' do
it 'returns hash attributes of a stage' do
expect(subject.stage).to be_a Hash
......
......@@ -224,6 +224,7 @@ Ci::Pipeline:
- auto_canceled_by_id
- pipeline_schedule_id
- config_source
- failure_reason
- protected
Ci::Stage:
- id
......
......@@ -238,7 +238,7 @@ def create_build(name, status)
describe '#stage_seeds' do
let(:pipeline) do
create(:ci_pipeline, config: { rspec: { script: 'rake' } })
build(:ci_pipeline, config: { rspec: { script: 'rake' } })
end
it 'returns preseeded stage seeds object' do
......@@ -247,6 +247,14 @@ def create_build(name, status)
end
end
describe '#seeds_size' do
let(:pipeline) { build(:ci_pipeline_with_one_job) }
it 'returns number of jobs in stage seeds' do
expect(pipeline.seeds_size).to eq 1
end
end
describe '#legacy_stages' do
subject { pipeline.legacy_stages }
......
......@@ -231,6 +231,18 @@
end
end
describe '.alive' do
subject { CommitStatus.alive }
%i[running pending created].each do |status|
it_behaves_like 'containing the job', status
end
%i[failed success].each do |status|
it_behaves_like 'not containing the job', status
end
end
describe '.created_or_pending' do
subject { CommitStatus.created_or_pending }
......
......@@ -51,4 +51,21 @@
end
end
end
context '#failure_reason' do
context 'when pipeline has failure reason' do
it 'represents a failure reason sentence' do
pipeline.failure_reason = :config_error
expect(presenter.failure_reason)
.to eq 'CI/CD YAML configuration error!'
end
end
context 'when pipeline does not have failure reason' do
it 'returns nil' do
expect(presenter.failure_reason).to be_nil
end
end
end
end
......@@ -108,5 +108,18 @@
expect(subject[:ref][:path]).to be_nil
end
end
context 'when pipeline has a failure reason set' do
let(:pipeline) { create(:ci_empty_pipeline) }
before do
pipeline.drop!(:config_error)
end
it 'has a correct failure reason' do
expect(subject[:failure_reason])
.to eq 'CI/CD YAML configuration error!'
end
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