diff options
-rw-r--r-- | app/models/ci/pipeline.rb | 19 | ||||
-rw-r--r-- | app/models/commit_status.rb | 5 | ||||
-rw-r--r-- | app/presenters/ci/build_presenter.rb | 4 | ||||
-rw-r--r-- | app/presenters/ci/pipeline_presenter.rb | 4 | ||||
-rw-r--r-- | app/services/ci/create_pipeline_service.rb | 3 | ||||
-rw-r--r-- | db/migrate/20170406114958_add_auto_canceled_by_id_to_ci_builds.rb | 9 | ||||
-rw-r--r-- | db/migrate/20170406115029_add_auto_canceled_by_id_foreign_key_to_ci_builds.rb | 22 | ||||
-rw-r--r-- | db/schema.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/all_models.yml | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/safe_model_attributes.yml | 1 | ||||
-rw-r--r-- | spec/models/ci/pipeline_spec.rb | 37 | ||||
-rw-r--r-- | spec/models/commit_status_spec.rb | 26 | ||||
-rw-r--r-- | spec/presenters/ci/build_presenter_spec.rb | 34 | ||||
-rw-r--r-- | spec/presenters/ci/pipeline_presenter_spec.rb | 2 |
14 files changed, 143 insertions, 27 deletions
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 8aad149519e..e03def25755 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -11,6 +11,8 @@ module Ci belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline' has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id' + has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id' + has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id has_many :builds, foreign_key: :commit_id has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id @@ -93,6 +95,10 @@ module Ci PipelineNotificationWorker.perform_async(pipeline.id) end end + + after_transition :canceled => any - [:canceled] do |pipeline| + pipeline.update(auto_canceled_by: nil) + end end # ref can't be HEAD or SHA, can only be branch/tag name @@ -226,10 +232,21 @@ module Ci def cancel_running Gitlab::OptimisticLocking.retry_lock( statuses.cancelable) do |cancelable| - cancelable.find_each(&:cancel) + cancelable.find_each do |job| + yield(job) if block_given? + job.cancel + end end end + def auto_cancel_running(pipeline) + update(auto_canceled_by: pipeline) + + cancel_running do |job| + job.auto_canceled_by = pipeline + end + end + def retry_failed(current_user) Ci::RetryPipelineService.new(project, current_user) .execute(self) diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 17b322b5ae3..2c4033146bf 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -7,6 +7,7 @@ class CommitStatus < ActiveRecord::Base belongs_to :project belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id + belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline' belongs_to :user delegate :commit, to: :pipeline @@ -137,6 +138,10 @@ class CommitStatus < ActiveRecord::Base false end + def auto_canceled? + canceled? && auto_canceled_by_id? + end + # Added in 9.0 to keep backward compatibility for projects exported in 8.17 # and prior. def gl_project_id diff --git a/app/presenters/ci/build_presenter.rb b/app/presenters/ci/build_presenter.rb index d9970396cc6..c495c3f39bb 100644 --- a/app/presenters/ci/build_presenter.rb +++ b/app/presenters/ci/build_presenter.rb @@ -13,8 +13,8 @@ module Ci end def status_title - if canceled? && pipeline.auto_canceled? - "Job is redundant and is auto-canceled by Pipeline ##{pipeline.auto_canceled_by_id}" + if auto_canceled? + "Job is redundant and is auto-canceled by Pipeline ##{auto_canceled_by_id}" end end end diff --git a/app/presenters/ci/pipeline_presenter.rb b/app/presenters/ci/pipeline_presenter.rb index b8e74bf5509..a542bdd8295 100644 --- a/app/presenters/ci/pipeline_presenter.rb +++ b/app/presenters/ci/pipeline_presenter.rb @@ -3,7 +3,9 @@ module Ci presents :pipeline def status_title - "Pipeline is redundant and is auto-canceled by Pipeline ##{auto_canceled_by_id}" if auto_canceled? + if auto_canceled? + "Pipeline is redundant and is auto-canceled by Pipeline ##{auto_canceled_by_id}" + end end end end diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index f944c869922..21350be5557 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -68,8 +68,7 @@ module Ci def cancel_pending_pipelines Gitlab::OptimisticLocking.retry_lock(auto_cancelable_pipelines) do |cancelables| cancelables.find_each do |cancelable| - cancelable.cancel_running - cancelable.update_attributes(auto_canceled_by_id: pipeline.id) + cancelable.auto_cancel_running(pipeline) end end end diff --git a/db/migrate/20170406114958_add_auto_canceled_by_id_to_ci_builds.rb b/db/migrate/20170406114958_add_auto_canceled_by_id_to_ci_builds.rb new file mode 100644 index 00000000000..c1d803b4308 --- /dev/null +++ b/db/migrate/20170406114958_add_auto_canceled_by_id_to_ci_builds.rb @@ -0,0 +1,9 @@ +class AddAutoCanceledByIdToCiBuilds < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + add_column :ci_builds, :auto_canceled_by_id, :integer + end +end diff --git a/db/migrate/20170406115029_add_auto_canceled_by_id_foreign_key_to_ci_builds.rb b/db/migrate/20170406115029_add_auto_canceled_by_id_foreign_key_to_ci_builds.rb new file mode 100644 index 00000000000..3004683933b --- /dev/null +++ b/db/migrate/20170406115029_add_auto_canceled_by_id_foreign_key_to_ci_builds.rb @@ -0,0 +1,22 @@ +class AddAutoCanceledByIdForeignKeyToCiBuilds < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + on_delete = + if Gitlab::Database.mysql? + :nullify + else + 'SET NULL' + end + + add_concurrent_foreign_key :ci_builds, :ci_pipelines, column: :auto_canceled_by_id, on_delete: on_delete + end + + def down + remove_foreign_key :ci_builds, column: :auto_canceled_by_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 59dbe9fd69a..afc67dba702 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -223,6 +223,7 @@ ActiveRecord::Schema.define(version: 20170405080720) do t.string "token" t.integer "lock_version" t.string "coverage_regex" + t.integer "auto_canceled_by_id" end add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree @@ -1300,6 +1301,7 @@ ActiveRecord::Schema.define(version: 20170405080720) do add_foreign_key "boards", "projects" add_foreign_key "chat_teams", "namespaces", on_delete: :cascade + add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify add_foreign_key "ci_triggers", "users", column: "owner_id", name: "fk_e8e10d1964", on_delete: :cascade add_foreign_key "issue_metrics", "issues", on_delete: :cascade diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 8aa8e3fc1cd..5f3a83d5792 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -91,10 +91,12 @@ pipelines: - trigger_requests - auto_canceled_by - auto_canceled_pipelines +- auto_canceled_jobs statuses: - project - pipeline - user +- auto_canceled_by variables: - project triggers: diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 15b8fa07040..50154a67908 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -224,6 +224,7 @@ CommitStatus: - token - lock_version - coverage_regex +- auto_canceled_by_id Ci::Variable: - id - project_id diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 38d3be926aa..3595601a72d 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -136,6 +136,43 @@ describe Ci::Pipeline, models: true do end end + describe '#auto_canceled?' do + subject { pipeline.auto_canceled? } + + context 'when it is canceled' do + before do + pipeline.cancel + end + + context 'when there is auto_canceled_by' do + before do + pipeline.update(auto_canceled_by: create(:ci_empty_pipeline)) + end + + it 'is auto canceled' do + is_expected.to be_truthy + end + end + + context 'when there is no auto_canceled_by' do + it 'is not auto canceled' do + is_expected.to be_falsey + end + end + + context 'when it is retried and canceled manually' do + before do + pipeline.enqueue + pipeline.cancel + end + + it 'is not auto canceled' do + is_expected.to be_falsey + end + end + end + end + describe 'pipeline stages' do before do create(:commit_status, pipeline: pipeline, diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index 7343b735a74..3bffb8dba72 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -101,6 +101,32 @@ describe CommitStatus, :models do end end + describe '#auto_canceled?' do + subject { commit_status.auto_canceled? } + + context 'when it is canceled' do + before do + commit_status.cancel + end + + context 'when there is auto_canceled_by' do + before do + commit_status.update(auto_cancel_by: create(:ci_empty_pipeline)) + end + + it 'is auto canceled' do + is_expected.to be_truthy + end + end + + context 'when there is no auto_canceled_by' do + it 'is not auto canceled' do + is_expected.to be_falsey + end + end + end + end + describe '#duration' do subject { commit_status.duration } diff --git a/spec/presenters/ci/build_presenter_spec.rb b/spec/presenters/ci/build_presenter_spec.rb index a9a8df1550d..ebb599bb48c 100644 --- a/spec/presenters/ci/build_presenter_spec.rb +++ b/spec/presenters/ci/build_presenter_spec.rb @@ -58,33 +58,27 @@ describe Ci::BuildPresenter do end describe '#status_title' do - context 'when build is canceled' do + context 'when build is auto-canceled' do before do - expect(presenter).to receive(:canceled?).and_return(true) + expect(build).to receive(:auto_canceled?).and_return(true) + expect(build).to receive(:auto_canceled_by_id).and_return(1) end - context 'when pipeline is auto-canceled' do - before do - expect(pipeline).to receive(:auto_canceled?).and_return(true) - expect(pipeline).to receive(:auto_canceled_by_id).and_return(1) - end + it 'shows that the job is auto-canceled' do + status_title = presenter.status_title - it 'shows that the job is auto-canceled' do - status_title = presenter.status_title - - expect(status_title).to include('auto-canceled') - expect(status_title).to include('Pipeline #1') - end + expect(status_title).to include('auto-canceled') + expect(status_title).to include('Pipeline #1') end + end - context 'when pipeline is not auto-canceled' do - before do - expect(pipeline).to receive(:auto_canceled?).and_return(false) - end + context 'when build is not auto-canceled' do + before do + expect(build).to receive(:auto_canceled?).and_return(false) + end - it 'shows that the job is auto-canceled' do - expect(presenter.status_title).to be_nil - end + it 'does not have a status title' do + expect(presenter.status_title).to be_nil end end end diff --git a/spec/presenters/ci/pipeline_presenter_spec.rb b/spec/presenters/ci/pipeline_presenter_spec.rb index 449e45c1f4c..9134d1cc31c 100644 --- a/spec/presenters/ci/pipeline_presenter_spec.rb +++ b/spec/presenters/ci/pipeline_presenter_spec.rb @@ -46,7 +46,7 @@ describe Ci::PipelinePresenter do expect(pipeline).to receive(:auto_canceled?).and_return(false) end - it 'shows that the job is auto-canceled' do + it 'does not have a status title' do expect(presenter.status_title).to be_nil end end |