diff --git a/app/views/projects/jobs/_empty_state.html.haml b/app/views/projects/jobs/_empty_state.html.haml index c66313bdbf3..311934d9c33 100644 --- a/app/views/projects/jobs/_empty_state.html.haml +++ b/app/views/projects/jobs/_empty_state.html.haml @@ -1,7 +1,7 @@ - illustration = local_assigns.fetch(:illustration) - illustration_size = local_assigns.fetch(:illustration_size) - title = local_assigns.fetch(:title) -- content = local_assigns.fetch(:content) +- content = local_assigns.fetch(:content, nil) - action = local_assigns.fetch(:action, nil) .row.empty-state @@ -11,7 +11,8 @@ .col-xs-12 .text-content %h4.text-center= title - %p= content + - if content + %p= content - if action .text-center = action diff --git a/app/views/projects/jobs/_empty_states.html.haml b/app/views/projects/jobs/_empty_states.html.haml new file mode 100644 index 00000000000..e5198d047df --- /dev/null +++ b/app/views/projects/jobs/_empty_states.html.haml @@ -0,0 +1,9 @@ +- detailed_status = @build.detailed_status(current_user) +- illustration = detailed_status.illustration + += render 'empty_state', + illustration: illustration[:image], + illustration_size: illustration[:size], + title: illustration[:title], + content: illustration[:content], + action: detailed_status.has_action? ? link_to(detailed_status.action_button_title, detailed_status.action_path, method: detailed_status.action_method, class: 'btn btn-primary', title: detailed_status.action_button_title) : nil diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml index dece4dfe167..8beb4ffef45 100644 --- a/app/views/projects/jobs/show.html.haml +++ b/app/views/projects/jobs/show.html.haml @@ -54,7 +54,8 @@ Job has been erased by #{link_to(@build.erased_by_name, user_path(@build.erased_by))} #{time_ago_with_tooltip(@build.erased_at)} - else Job has been erased #{time_ago_with_tooltip(@build.erased_at)} - - if @build.started? + + - if @build.has_trace? .build-trace-container.prepend-top-default .top-bar.js-top-bar .js-truncated-info.truncated-info.hidden-xs.pull-left.hidden< @@ -88,25 +89,9 @@ %pre.build-trace#build-trace %code.bash.js-build-output .build-loader-animation.js-build-refresh - - elsif @build.playable? - = render 'empty_state', - illustration: 'illustrations/manual_action.svg', - illustration_size: 'svg-394', - title: _('This job requires a manual action'), - content: _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments'), - action: ( link_to _('Trigger this manual action'), play_project_job_path(@project, @build), method: :post, class: 'btn btn-primary', title: _('Trigger this manual action') ) - - elsif @build.created? - = render 'empty_state', - illustration: 'illustrations/job_not_triggered.svg', - illustration_size: 'svg-306', - title: _('This job has not been triggered yet'), - content: _('This job depends on upstream jobs that need to succeed in order for this job to be triggered') - else - = render 'empty_state', - illustration: 'illustrations/pending_job_empty.svg', - illustration_size: 'svg-430', - title: _('This job has not started yet'), - content: _('This job is in pending state and is waiting to be picked by a runner') + = render "empty_states" + = render "sidebar", builds: @builds .js-build-options{ data: javascript_build_options } diff --git a/changelogs/unreleased/42568-pipeline-empty-state.yml b/changelogs/unreleased/42568-pipeline-empty-state.yml new file mode 100644 index 00000000000..d36edcf1b37 --- /dev/null +++ b/changelogs/unreleased/42568-pipeline-empty-state.yml @@ -0,0 +1,5 @@ +--- +title: Improve empty state for canceled job +merge_request: 17646 +author: +type: fixed diff --git a/features/steps/shared/builds.rb b/features/steps/shared/builds.rb index a3e4459f169..f5950145348 100644 --- a/features/steps/shared/builds.rb +++ b/features/steps/shared/builds.rb @@ -11,7 +11,7 @@ module SharedBuilds step 'project has a recent build' do @pipeline = create(:ci_empty_pipeline, project: @project, sha: @project.commit.sha, ref: 'master') - @build = create(:ci_build, :running, :coverage, pipeline: @pipeline) + @build = create(:ci_build, :running, :coverage, :trace_artifact, pipeline: @pipeline) end step 'recent build is successful' do diff --git a/lib/gitlab/ci/status/build/cancelable.rb b/lib/gitlab/ci/status/build/cancelable.rb index 2d9166d6bdd..024047d4983 100644 --- a/lib/gitlab/ci/status/build/cancelable.rb +++ b/lib/gitlab/ci/status/build/cancelable.rb @@ -23,6 +23,10 @@ module Gitlab 'Cancel' end + def action_button_title + _('Cancel this job') + end + def self.matches?(build, user) build.cancelable? end diff --git a/lib/gitlab/ci/status/build/canceled.rb b/lib/gitlab/ci/status/build/canceled.rb new file mode 100644 index 00000000000..c83e2734a73 --- /dev/null +++ b/lib/gitlab/ci/status/build/canceled.rb @@ -0,0 +1,21 @@ +module Gitlab + module Ci + module Status + module Build + class Canceled < Status::Extended + def illustration + { + image: 'illustrations/canceled-job_empty.svg', + size: 'svg-430', + title: _('This job has been canceled') + } + end + + def self.matches?(build, user) + build.canceled? + end + end + end + end + end +end diff --git a/lib/gitlab/ci/status/build/created.rb b/lib/gitlab/ci/status/build/created.rb new file mode 100644 index 00000000000..5be8e9de425 --- /dev/null +++ b/lib/gitlab/ci/status/build/created.rb @@ -0,0 +1,22 @@ +module Gitlab + module Ci + module Status + module Build + class Created < Status::Extended + def illustration + { + image: 'illustrations/job_not_triggered.svg', + size: 'svg-306', + title: _('This job has not been triggered yet'), + content: _('This job depends on upstream jobs that need to succeed in order for this job to be triggered') + } + end + + def self.matches?(build, user) + build.created? + end + end + end + end + end +end diff --git a/lib/gitlab/ci/status/build/erased.rb b/lib/gitlab/ci/status/build/erased.rb new file mode 100644 index 00000000000..3a5113b16b6 --- /dev/null +++ b/lib/gitlab/ci/status/build/erased.rb @@ -0,0 +1,21 @@ +module Gitlab + module Ci + module Status + module Build + class Erased < Status::Extended + def illustration + { + image: 'illustrations/skipped-job_empty.svg', + size: 'svg-430', + title: _('Job has been erased') + } + end + + def self.matches?(build, user) + build.erased? + end + end + end + end + end +end diff --git a/lib/gitlab/ci/status/build/factory.rb b/lib/gitlab/ci/status/build/factory.rb index 20a319caf86..2b26ebb45a1 100644 --- a/lib/gitlab/ci/status/build/factory.rb +++ b/lib/gitlab/ci/status/build/factory.rb @@ -4,7 +4,13 @@ module Gitlab module Build class Factory < Status::Factory def self.extended_statuses - [[Status::Build::Cancelable, + [[Status::Build::Erased, + Status::Build::Manual, + Status::Build::Canceled, + Status::Build::Created, + Status::Build::Pending, + Status::Build::Skipped], + [Status::Build::Cancelable, Status::Build::Retryable], [Status::Build::Failed], [Status::Build::FailedAllowed, diff --git a/lib/gitlab/ci/status/build/manual.rb b/lib/gitlab/ci/status/build/manual.rb new file mode 100644 index 00000000000..042da6392d3 --- /dev/null +++ b/lib/gitlab/ci/status/build/manual.rb @@ -0,0 +1,22 @@ +module Gitlab + module Ci + module Status + module Build + class Manual < Status::Extended + def illustration + { + image: 'illustrations/manual_action.svg', + size: 'svg-394', + title: _('This job requires a manual action'), + content: _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments') + } + end + + def self.matches?(build, user) + build.playable? + end + end + end + end + end +end diff --git a/lib/gitlab/ci/status/build/pending.rb b/lib/gitlab/ci/status/build/pending.rb new file mode 100644 index 00000000000..9dd9a27ad57 --- /dev/null +++ b/lib/gitlab/ci/status/build/pending.rb @@ -0,0 +1,22 @@ +module Gitlab + module Ci + module Status + module Build + class Pending < Status::Extended + def illustration + { + image: 'illustrations/pending_job_empty.svg', + size: 'svg-430', + title: _('This job has not started yet'), + content: _('This job is in pending state and is waiting to be picked by a runner') + } + end + + def self.matches?(build, user) + build.pending? + end + end + end + end + end +end diff --git a/lib/gitlab/ci/status/build/play.rb b/lib/gitlab/ci/status/build/play.rb index b7b45466d3b..a8b9ebf0803 100644 --- a/lib/gitlab/ci/status/build/play.rb +++ b/lib/gitlab/ci/status/build/play.rb @@ -19,6 +19,10 @@ module Gitlab 'Play' end + def action_button_title + _('Trigger this manual action') + end + def action_path play_project_job_path(subject.project, subject) end diff --git a/lib/gitlab/ci/status/build/retryable.rb b/lib/gitlab/ci/status/build/retryable.rb index 44ffe783e50..5aeb8e51480 100644 --- a/lib/gitlab/ci/status/build/retryable.rb +++ b/lib/gitlab/ci/status/build/retryable.rb @@ -15,6 +15,10 @@ module Gitlab 'Retry' end + def action_button_title + _('Retry this job') + end + def action_path retry_project_job_path(subject.project, subject) end diff --git a/lib/gitlab/ci/status/build/skipped.rb b/lib/gitlab/ci/status/build/skipped.rb new file mode 100644 index 00000000000..3e678d0baee --- /dev/null +++ b/lib/gitlab/ci/status/build/skipped.rb @@ -0,0 +1,21 @@ +module Gitlab + module Ci + module Status + module Build + class Skipped < Status::Extended + def illustration + { + image: 'illustrations/skipped-job_empty.svg', + size: 'svg-430', + title: _('This job has been skipped') + } + end + + def self.matches?(build, user) + build.skipped? + end + end + end + end + end +end diff --git a/lib/gitlab/ci/status/build/stop.rb b/lib/gitlab/ci/status/build/stop.rb index 46e730797e4..dea838bfa39 100644 --- a/lib/gitlab/ci/status/build/stop.rb +++ b/lib/gitlab/ci/status/build/stop.rb @@ -19,6 +19,10 @@ module Gitlab 'Stop' end + def action_button_title + _('Stop this environment') + end + def action_path play_project_job_path(subject.project, subject) end diff --git a/lib/gitlab/ci/status/core.rb b/lib/gitlab/ci/status/core.rb index daab6bb2de5..9d6a2f51c11 100644 --- a/lib/gitlab/ci/status/core.rb +++ b/lib/gitlab/ci/status/core.rb @@ -22,6 +22,10 @@ module Gitlab raise NotImplementedError end + def illustration + raise NotImplementedError + end + def label raise NotImplementedError end @@ -58,6 +62,10 @@ module Gitlab raise NotImplementedError end + def action_button_title + raise NotImplementedError + end + # Hint that appears on all the pipeline graph tooltips and builds on the right sidebar in Job detail view def status_tooltip label diff --git a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb index a43ba05c64c..fd1629746ef 100644 --- a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb +++ b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb @@ -9,6 +9,7 @@ describe 'Merge request < User sees mini pipeline graph', :js do before do build.run + build.trace.set('hello') sign_in(user) visit_merge_request end @@ -26,15 +27,15 @@ describe 'Merge request < User sees mini pipeline graph', :js do let(:artifacts_file2) { fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } before do - create(:ci_build, pipeline: pipeline, legacy_artifacts_file: artifacts_file1) - create(:ci_build, pipeline: pipeline, when: 'manual') + create(:ci_build, :success, :trace_artifact, pipeline: pipeline, legacy_artifacts_file: artifacts_file1) + create(:ci_build, :manual, pipeline: pipeline, when: 'manual') end it 'avoids repeated database queries' do before = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') } - create(:ci_build, pipeline: pipeline, legacy_artifacts_file: artifacts_file2) - create(:ci_build, pipeline: pipeline, when: 'manual') + create(:ci_build, :success, :trace_artifact, pipeline: pipeline, legacy_artifacts_file: artifacts_file2) + create(:ci_build, :manual, pipeline: pipeline, when: 'manual') after = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') } diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index b7eee39052a..bff5bbe99af 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -1,16 +1,15 @@ require 'spec_helper' describe 'User browses a job', :js do - let!(:build) { create(:ci_build, :running, :coverage, pipeline: pipeline) } - let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } - let(:project) { create(:project, :repository, namespace: user.namespace) } let(:user) { create(:user) } + let(:user_access_level) { :developer } + let(:project) { create(:project, :repository, namespace: user.namespace) } + let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } + let!(:build) { create(:ci_build, :success, :trace_artifact, :coverage, pipeline: pipeline) } before do project.add_master(user) project.enable_ci - build.success - build.trace.set('job trace') sign_in(user) @@ -21,7 +20,9 @@ describe 'User browses a job', :js do expect(page).to have_content("Job ##{build.id}") expect(page).to have_css('#build-trace') - accept_confirm { click_link('Erase') } + # scroll to the top of the page first + execute_script "window.scrollTo(0,0)" + accept_confirm { find('.js-erase-link').click } expect(page).to have_no_css('.artifacts') expect(build).not_to have_trace @@ -36,7 +37,7 @@ describe 'User browses a job', :js do end context 'with a failed job' do - let!(:build) { create(:ci_build, :failed, pipeline: pipeline) } + let!(:build) { create(:ci_build, :failed, :trace_artifact, pipeline: pipeline) } it 'displays the failure reason' do within('.builds-container') do @@ -47,7 +48,7 @@ describe 'User browses a job', :js do end context 'when a failed job has been retried' do - let!(:build) { create(:ci_build, :failed, :retried, pipeline: pipeline) } + let!(:build) { create(:ci_build, :failed, :retried, :trace_artifact, pipeline: pipeline) } it 'displays the failure reason and retried label' do within('.builds-container') do diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 5d311f2dde3..749a1b81872 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -113,7 +113,7 @@ feature 'Jobs' do describe "GET /:project/jobs/:id" do context "Job from project" do - let(:job) { create(:ci_build, :success, pipeline: pipeline) } + let(:job) { create(:ci_build, :success, :trace_live, pipeline: pipeline) } before do visit project_job_path(project, job) @@ -136,7 +136,7 @@ feature 'Jobs' do end context 'when job is not running', :js do - let(:job) { create(:ci_build, :success, pipeline: pipeline) } + let(:job) { create(:ci_build, :success, :trace_artifact, pipeline: pipeline) } before do visit project_job_path(project, job) @@ -153,7 +153,7 @@ feature 'Jobs' do end context 'if job failed' do - let(:job) { create(:ci_build, :failed, pipeline: pipeline) } + let(:job) { create(:ci_build, :failed, :trace_artifact, pipeline: pipeline) } before do visit project_job_path(project, job) @@ -339,7 +339,7 @@ feature 'Jobs' do context 'job is successfull and has deployment' do let(:deployment) { create(:deployment) } - let(:job) { create(:ci_build, :success, environment: environment.name, deployments: [deployment], pipeline: pipeline) } + let(:job) { create(:ci_build, :success, :trace_artifact, environment: environment.name, deployments: [deployment], pipeline: pipeline) } it 'shows a link for the job' do visit project_job_path(project, job) @@ -349,7 +349,7 @@ feature 'Jobs' do end context 'job is complete and not successful' do - let(:job) { create(:ci_build, :failed, environment: environment.name, pipeline: pipeline) } + let(:job) { create(:ci_build, :failed, :trace_artifact, environment: environment.name, pipeline: pipeline) } it 'shows a link for the job' do visit project_job_path(project, job) @@ -360,7 +360,7 @@ feature 'Jobs' do context 'job creates a new deployment' do let!(:deployment) { create(:deployment, environment: environment, sha: project.commit.id) } - let(:job) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) } + let(:job) { create(:ci_build, :success, :trace_artifact, environment: environment.name, pipeline: pipeline) } it 'shows a link to latest deployment' do visit project_job_path(project, job) @@ -379,6 +379,7 @@ feature 'Jobs' do end it 'shows manual action empty state' do + expect(page).to have_content(job.detailed_status(user).illustration[:title]) expect(page).to have_content('This job requires a manual action') expect(page).to have_content('This job depends on a user to trigger its process. Often they are used to deploy code to production environments') expect(page).to have_link('Trigger this manual action') @@ -402,6 +403,7 @@ feature 'Jobs' do end it 'shows empty state' do + expect(page).to have_content(job.detailed_status(user).illustration[:title]) expect(page).to have_content('This job has not been triggered yet') expect(page).to have_content('This job depends on upstream jobs that need to succeed in order for this job to be triggered') end @@ -415,10 +417,53 @@ feature 'Jobs' do end it 'shows pending empty state' do + expect(page).to have_content(job.detailed_status(user).illustration[:title]) expect(page).to have_content('This job has not started yet') expect(page).to have_content('This job is in pending state and is waiting to be picked by a runner') end end + + context 'Canceled job' do + context 'with log' do + let(:job) { create(:ci_build, :canceled, :trace_artifact, pipeline: pipeline) } + + before do + visit project_job_path(project, job) + end + + it 'renders job log' do + expect(page).to have_selector('.js-build-output') + end + end + + context 'without log' do + let(:job) { create(:ci_build, :canceled, pipeline: pipeline) } + + before do + visit project_job_path(project, job) + end + + it 'renders empty state' do + expect(page).to have_content(job.detailed_status(user).illustration[:title]) + expect(page).not_to have_selector('.js-build-output') + expect(page).to have_content('This job has been canceled') + end + end + end + + context 'Skipped job' do + let(:job) { create(:ci_build, :skipped, pipeline: pipeline) } + + before do + visit project_job_path(project, job) + end + + it 'renders empty state' do + expect(page).to have_content(job.detailed_status(user).illustration[:title]) + expect(page).not_to have_selector('.js-build-output') + expect(page).to have_content('This job has been skipped') + end + end end describe "POST /:project/jobs/:id/cancel", :js do diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb index 3ef0b6817e9..78d6fa65b5a 100644 --- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb @@ -90,6 +90,10 @@ describe Gitlab::Ci::Status::Build::Cancelable do describe '#action_title' do it { expect(subject.action_title).to eq 'Cancel' } end + + describe '#action_button_title' do + it { expect(subject.action_button_title).to eq 'Cancel this job' } + end end describe '.matches?' do diff --git a/spec/lib/gitlab/ci/status/build/canceled_spec.rb b/spec/lib/gitlab/ci/status/build/canceled_spec.rb new file mode 100644 index 00000000000..c6b5cc68770 --- /dev/null +++ b/spec/lib/gitlab/ci/status/build/canceled_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Build::Canceled do + let(:user) { create(:user) } + + subject do + described_class.new(double('subject')) + end + + describe '#illustration' do + it { expect(subject.illustration).to include(:image, :size, :title) } + end + + describe '.matches?' do + subject {described_class.matches?(build, user) } + + context 'when build is canceled' do + let(:build) { create(:ci_build, :canceled) } + + it 'is a correct match' do + expect(subject).to be true + end + end + + context 'when build is not canceled' 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/created_spec.rb b/spec/lib/gitlab/ci/status/build/created_spec.rb new file mode 100644 index 00000000000..8bdfe6ef7a2 --- /dev/null +++ b/spec/lib/gitlab/ci/status/build/created_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Build::Created do + let(:user) { create(:user) } + + subject do + described_class.new(double('subject')) + end + + describe '#illustration' do + it { expect(subject.illustration).to include(:image, :size, :title, :content) } + end + + describe '.matches?' do + subject {described_class.matches?(build, user) } + + context 'when build is created' do + let(:build) { create(:ci_build, :created) } + + it 'is a correct match' do + expect(subject).to be true + end + end + + context 'when build is not created' 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/erased_spec.rb b/spec/lib/gitlab/ci/status/build/erased_spec.rb new file mode 100644 index 00000000000..0acd271e375 --- /dev/null +++ b/spec/lib/gitlab/ci/status/build/erased_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Build::Erased do + let(:user) { create(:user) } + + subject do + described_class.new(double('subject')) + end + + describe '#illustration' do + it { expect(subject.illustration).to include(:image, :size, :title) } + end + + describe '.matches?' do + subject { described_class.matches?(build, user) } + + context 'when build is erased' do + let(:build) { create(:ci_build, :success, :erased) } + + it 'is a correct match' do + expect(subject).to be true + end + end + + context 'when build is not erased' do + let(:build) { create(:ci_build, :success, :trace_artifact) } + + it 'does not match' do + expect(subject).to be false + end + 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 index bbfa60169a1..6d5b73bb01b 100644 --- a/spec/lib/gitlab/ci/status/build/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb @@ -13,7 +13,7 @@ describe Gitlab::Ci::Status::Build::Factory do end context 'when build is successful' do - let(:build) { create(:ci_build, :success) } + let(:build) { create(:ci_build, :success, :trace_artifact) } it 'matches correct core status' do expect(factory.core_status).to be_a Gitlab::Ci::Status::Success @@ -38,6 +38,33 @@ describe Gitlab::Ci::Status::Build::Factory do end end + context 'when build is erased' do + let(:build) { create(:ci_build, :success, :erased) } + + it 'matches correct core status' do + expect(factory.core_status).to be_a Gitlab::Ci::Status::Success + end + + it 'matches correct extended statuses' do + expect(factory.extended_statuses) + .to eq [Gitlab::Ci::Status::Build::Erased, + Gitlab::Ci::Status::Build::Retryable] + end + + 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 'status_success' + expect(status.favicon).to eq 'favicon_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 context 'when build is not allowed to fail' do let(:build) { create(:ci_build, :failed) } @@ -106,7 +133,7 @@ describe Gitlab::Ci::Status::Build::Factory do it 'matches correct extended statuses' do expect(factory.extended_statuses) - .to eq [Gitlab::Ci::Status::Build::Retryable] + .to eq [Gitlab::Ci::Status::Build::Canceled, Gitlab::Ci::Status::Build::Retryable] end it 'fabricates a retryable build status' do @@ -117,6 +144,7 @@ describe Gitlab::Ci::Status::Build::Factory do expect(status.text).to eq 'canceled' expect(status.icon).to eq 'status_canceled' expect(status.favicon).to eq 'favicon_status_canceled' + expect(status.illustration).to include(:image, :size, :title) expect(status.label).to eq 'canceled' expect(status).to have_details expect(status).to have_action @@ -158,7 +186,7 @@ describe Gitlab::Ci::Status::Build::Factory do it 'matches correct extended statuses' do expect(factory.extended_statuses) - .to eq [Gitlab::Ci::Status::Build::Cancelable] + .to eq [Gitlab::Ci::Status::Build::Pending, Gitlab::Ci::Status::Build::Cancelable] end it 'fabricates a cancelable build status' do @@ -169,6 +197,7 @@ describe Gitlab::Ci::Status::Build::Factory do expect(status.text).to eq 'pending' expect(status.icon).to eq 'status_pending' expect(status.favicon).to eq 'favicon_status_pending' + expect(status.illustration).to include(:image, :size, :title, :content) expect(status.label).to eq 'pending' expect(status).to have_details expect(status).to have_action @@ -182,18 +211,19 @@ describe Gitlab::Ci::Status::Build::Factory do expect(factory.core_status).to be_a Gitlab::Ci::Status::Skipped end - it 'does not match extended statuses' do - expect(factory.extended_statuses).to be_empty + it 'matches correct extended statuses' do + expect(factory.extended_statuses).to eq [Gitlab::Ci::Status::Build::Skipped] end - it 'fabricates a core skipped status' do - expect(status).to be_a Gitlab::Ci::Status::Skipped + it 'fabricates a skipped build status' do + expect(status).to be_a Gitlab::Ci::Status::Build::Skipped end it 'fabricates status with correct details' do expect(status.text).to eq 'skipped' expect(status.icon).to eq 'status_skipped' expect(status.favicon).to eq 'favicon_status_skipped' + expect(status.illustration).to include(:image, :size, :title) expect(status.label).to eq 'skipped' expect(status).to have_details expect(status).not_to have_action @@ -210,7 +240,8 @@ describe Gitlab::Ci::Status::Build::Factory do it 'matches correct extended statuses' do expect(factory.extended_statuses) - .to eq [Gitlab::Ci::Status::Build::Play, + .to eq [Gitlab::Ci::Status::Build::Manual, + Gitlab::Ci::Status::Build::Play, Gitlab::Ci::Status::Build::Action] end @@ -223,6 +254,7 @@ describe Gitlab::Ci::Status::Build::Factory do expect(status.group).to eq 'manual' expect(status.icon).to eq 'status_manual' expect(status.favicon).to eq 'favicon_status_manual' + expect(status.illustration).to include(:image, :size, :title, :content) expect(status.label).to include 'manual play action' expect(status).to have_details expect(status.action_path).to include 'play' @@ -257,7 +289,8 @@ describe Gitlab::Ci::Status::Build::Factory do it 'matches correct extended statuses' do expect(factory.extended_statuses) - .to eq [Gitlab::Ci::Status::Build::Stop, + .to eq [Gitlab::Ci::Status::Build::Manual, + Gitlab::Ci::Status::Build::Stop, Gitlab::Ci::Status::Build::Action] end diff --git a/spec/lib/gitlab/ci/status/build/manual_spec.rb b/spec/lib/gitlab/ci/status/build/manual_spec.rb new file mode 100644 index 00000000000..6386296f992 --- /dev/null +++ b/spec/lib/gitlab/ci/status/build/manual_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Build::Manual do + let(:user) { create(:user) } + + subject do + build = create(:ci_build, :manual) + described_class.new(Gitlab::Ci::Status::Core.new(build, user)) + end + + describe '#illustration' do + it { expect(subject.illustration).to include(:image, :size, :title, :content) } + end + + describe '.matches?' do + subject {described_class.matches?(build, user) } + + context 'when build is manual' do + let(:build) { create(:ci_build, :manual) } + + it 'is a correct match' do + expect(subject).to be true + end + end + + context 'when build is not manual' 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/pending_spec.rb b/spec/lib/gitlab/ci/status/build/pending_spec.rb new file mode 100644 index 00000000000..4cf70828e53 --- /dev/null +++ b/spec/lib/gitlab/ci/status/build/pending_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Build::Pending do + let(:user) { create(:user) } + + subject do + described_class.new(double('subject')) + end + + describe '#illustration' do + it { expect(subject.illustration).to include(:image, :size, :title, :content) } + end + + describe '.matches?' do + subject {described_class.matches?(build, user) } + + context 'when build is pending' do + let(:build) { create(:ci_build, :pending) } + + it 'is a correct match' do + expect(subject).to be true + end + end + + context 'when build is not pending' 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/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb index 35e47cd2526..f128c1d4ca4 100644 --- a/spec/lib/gitlab/ci/status/build/play_spec.rb +++ b/spec/lib/gitlab/ci/status/build/play_spec.rb @@ -69,6 +69,10 @@ describe Gitlab::Ci::Status::Build::Play do it { expect(subject.action_title).to eq 'Play' } end + describe '#action_button_title' do + it { expect(subject.action_button_title).to eq 'Trigger this manual action' } + end + describe '.matches?' do subject { described_class.matches?(build, user) } diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb index 0c5099b7da5..84d98588f2d 100644 --- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb @@ -90,6 +90,10 @@ describe Gitlab::Ci::Status::Build::Retryable do describe '#action_title' do it { expect(subject.action_title).to eq 'Retry' } end + + describe '#action_button_title' do + it { expect(subject.action_button_title).to eq 'Retry this job' } + end end describe '.matches?' do diff --git a/spec/lib/gitlab/ci/status/build/skipped_spec.rb b/spec/lib/gitlab/ci/status/build/skipped_spec.rb new file mode 100644 index 00000000000..46f6933025a --- /dev/null +++ b/spec/lib/gitlab/ci/status/build/skipped_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Gitlab::Ci::Status::Build::Skipped do + let(:user) { create(:user) } + + subject do + described_class.new(double('subject')) + end + + describe '#illustration' do + it { expect(subject.illustration).to include(:image, :size, :title) } + end + + describe '.matches?' do + subject {described_class.matches?(build, user) } + + context 'when build is skipped' do + let(:build) { create(:ci_build, :skipped) } + + it 'is a correct match' do + expect(subject).to be true + end + end + + context 'when build is not skipped' 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/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb index f16fc5c9205..5b7534c96c1 100644 --- a/spec/lib/gitlab/ci/status/build/stop_spec.rb +++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb @@ -44,6 +44,10 @@ describe Gitlab::Ci::Status::Build::Stop do describe '#action_title' do it { expect(subject.action_title).to eq 'Stop' } end + + describe '#action_button_title' do + it { expect(subject.action_button_title).to eq 'Stop this environment' } + end end describe '.matches?' do diff --git a/spec/views/projects/jobs/show.html.haml_spec.rb b/spec/views/projects/jobs/show.html.haml_spec.rb index 9e692159bd0..c93152b88e3 100644 --- a/spec/views/projects/jobs/show.html.haml_spec.rb +++ b/spec/views/projects/jobs/show.html.haml_spec.rb @@ -21,7 +21,7 @@ describe 'projects/jobs/show' do describe 'environment info in job view' do context 'job with latest deployment' do let(:build) do - create(:ci_build, :success, environment: 'staging') + create(:ci_build, :success, :trace_artifact, environment: 'staging') end before do @@ -40,11 +40,11 @@ describe 'projects/jobs/show' do context 'job with outdated deployment' do let(:build) do - create(:ci_build, :success, environment: 'staging', pipeline: pipeline) + create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) end let(:second_build) do - create(:ci_build, :success, environment: 'staging', pipeline: pipeline) + create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) end let(:environment) do @@ -70,7 +70,7 @@ describe 'projects/jobs/show' do context 'job failed to deploy' do let(:build) do - create(:ci_build, :failed, environment: 'staging', pipeline: pipeline) + create(:ci_build, :failed, :trace_artifact, environment: 'staging', pipeline: pipeline) end let!(:environment) do @@ -88,7 +88,7 @@ describe 'projects/jobs/show' do context 'job will deploy' do let(:build) do - create(:ci_build, :running, environment: 'staging', pipeline: pipeline) + create(:ci_build, :running, :trace_live, environment: 'staging', pipeline: pipeline) end context 'when environment exists' do @@ -136,7 +136,7 @@ describe 'projects/jobs/show' do context 'job that failed to deploy and environment has not been created' do let(:build) do - create(:ci_build, :failed, environment: 'staging', pipeline: pipeline) + create(:ci_build, :failed, :trace_artifact, environment: 'staging', pipeline: pipeline) end let!(:environment) do @@ -154,7 +154,7 @@ describe 'projects/jobs/show' do context 'job that will deploy and environment has not been created' do let(:build) do - create(:ci_build, :running, environment: 'staging', pipeline: pipeline) + create(:ci_build, :running, :trace_live, environment: 'staging', pipeline: pipeline) end let!(:environment) do @@ -174,8 +174,9 @@ describe 'projects/jobs/show' do end context 'when job is running' do + let(:build) { create(:ci_build, :trace_live, :running, pipeline: pipeline) } + before do - build.run! render end