diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 5dbf66173de..7c9899334ad 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -67,7 +67,7 @@ module Ci environment: build.environment, status_event: 'enqueue' ) - MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build) + MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build.pipeline) build.pipeline.mark_as_processable_after_stage(build.stage_idx) new_build end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 663c5b1e231..da0b9d83e1d 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -73,6 +73,14 @@ module Ci after_transition do |pipeline, transition| pipeline.execute_hooks unless transition.loopback? end + + after_transition [:created, :pending, :running] => :success do |pipeline| + MergeRequests::MergeWhenBuildSucceedsService.new(pipeline.project, nil).trigger(pipeline) + end + + after_transition any => :failed do |pipeline| + MergeRequests::AddTodoWhenBuildFailsService.new(pipeline.project, nil).execute(pipeline) + end end # ref can't be HEAD or SHA, can only be branch/tag name @@ -251,9 +259,8 @@ module Ci Ci::ProcessPipelineService.new(project, user).execute(self) end - def build_updated + def update_status with_lock do - reload case latest_builds_status when 'pending' then enqueue when 'running' then run diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 736db1ab0f6..3d5e449f403 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -74,10 +74,6 @@ class CommitStatus < ActiveRecord::Base true end - after_transition do |commit_status, transition| - commit_status.pipeline.try(:build_updated) unless transition.loopback? - end - after_transition [:created, :pending, :running] => :success do |commit_status| MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status) end @@ -85,6 +81,16 @@ class CommitStatus < ActiveRecord::Base after_transition any => :failed do |commit_status| MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.pipeline.project, nil).execute(commit_status) end + + after_transition do |commit_status, transition| + if commit_status.pipeline && !transition.loopback? + ProcessPipelineWorker.perform_async( + commit_status.pipeline.id, + process: HasStatus.COMPLETED_STATUSES.include?(commit_status.status)) + end + + true + end end delegate :sha, :short_sha, to: :pipeline diff --git a/app/services/merge_requests/add_todo_when_build_fails_service.rb b/app/services/merge_requests/add_todo_when_build_fails_service.rb index 566049525cb..45c73789886 100644 --- a/app/services/merge_requests/add_todo_when_build_fails_service.rb +++ b/app/services/merge_requests/add_todo_when_build_fails_service.rb @@ -1,15 +1,15 @@ module MergeRequests class AddTodoWhenBuildFailsService < MergeRequests::BaseService # Adds a todo to the parent merge_request when a CI build fails - def execute(commit_status) - each_merge_request(commit_status) do |merge_request| + def execute(pipeline) + each_merge_request(pipeline) do |merge_request| todo_service.merge_request_build_failed(merge_request) end end # Closes any pending build failed todos for the parent MRs when a build is retried - def close(commit_status) - each_merge_request(commit_status) do |merge_request| + def close(pipeline) + each_merge_request(pipeline) do |merge_request| todo_service.merge_request_build_retried(merge_request) end end diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index d0d155b7ee1..95b4f0ff733 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -42,11 +42,11 @@ module MergeRequests super(:merge_request) end - def merge_request_from(commit_status) - branches = commit_status.ref + def merge_request_from(pipeline) + branches = pipeline.ref # This is for ref-less builds - branches ||= @project.repository.branch_names_contains(commit_status.sha) + branches ||= @project.repository.branch_names_contains(pipeline.sha) return [] if branches.blank? @@ -56,14 +56,11 @@ module MergeRequests merge_requests.uniq.select(&:source_project) end - def each_merge_request(commit_status) + def each_merge_request(pipeline) merge_request_from(commit_status).each do |merge_request| - pipeline = merge_request.pipeline + next unless pipeline == merge_request.pipeline - next unless pipeline - next unless pipeline.sha == commit_status.sha - - yield merge_request, pipeline + yield merge_request end end end diff --git a/app/services/merge_requests/merge_when_build_succeeds_service.rb b/app/services/merge_requests/merge_when_build_succeeds_service.rb index 4ad5fb08311..60d6085f9eb 100644 --- a/app/services/merge_requests/merge_when_build_succeeds_service.rb +++ b/app/services/merge_requests/merge_when_build_succeeds_service.rb @@ -19,11 +19,12 @@ module MergeRequests end # Triggers the automatic merge of merge_request once the build succeeds - def trigger(commit_status) - each_merge_request(commit_status) do |merge_request, pipeline| + def trigger(pipeline) + return unless pipeline.success? + + each_merge_request(pipeline) do |merge_request| next unless merge_request.merge_when_build_succeeds? next unless merge_request.mergeable? - next unless pipeline.success? MergeWorker.perform_async(merge_request.id, merge_request.merge_user_id, merge_request.merge_params) end diff --git a/app/workers/process_pipeline_worker.rb b/app/workers/process_pipeline_worker.rb new file mode 100644 index 00000000000..fb59a1efb7a --- /dev/null +++ b/app/workers/process_pipeline_worker.rb @@ -0,0 +1,17 @@ +class ProcessPipelineWorker + include Sidekiq::Worker + + sidekiq_options queue: :default + + def perform(pipeline_id, params) + begin + pipeline = Ci::Pipeline.find(pipeline_id) + rescue ActiveRecord::RecordNotFound + return + end + + pipeline.process! if params[:process] + + pipeline.update_status + end +end