Commit 057c0d7a authored by Lin Jen-Shin's avatar Lin Jen-Shin

Also track auto-cancelling in jobs, detail:

Not only tracking auto-cancelling in pipelines,
we'll also track this in jobs because pipelines
could be retried and the information would get lost
when this happened. Also erase auto-cancelling
relation for pipelines when they're retried.
parent 98a4aca6
......@@ -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)
......
......@@ -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
......
......@@ -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
......
......@@ -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
......@@ -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
......
class AddAutoCanceledByIdToCiBuilds < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_builds, :auto_canceled_by_id, :integer
end
end
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
......@@ -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
......
......@@ -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:
......
......@@ -224,6 +224,7 @@ CommitStatus:
- token
- lock_version
- coverage_regex
- auto_canceled_by_id
Ci::Variable:
- id
- project_id
......
......@@ -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,
......
......@@ -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 }
......
......@@ -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
......
......@@ -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
......
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