Skip to content

Commit 1958a92

Browse files
authored
Mark workflow as failed when trigger fails (#740)
1 parent 4b663a8 commit 1958a92

File tree

8 files changed

+117
-2
lines changed

8 files changed

+117
-2
lines changed

app/components/live_release/build_component.rb

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class LiveRelease::BuildComponent < BaseComponent
1010
unavailable: {text: "Build unavailable", status: :failure},
1111
started: {text: "Workflow running", status: :ongoing, kind: :spinner_pill},
1212
failed: {text: "Workflow failed", status: :failure},
13+
trigger_failed: {text: "Failed to trigger workflow", status: :failure},
1314
halted: {text: "Workflow halted", status: :failure},
1415
finished: {text: "Workflow finished", status: :ongoing},
1516
cancelled: {text: "Workflow cancelled", status: :inert},

app/components/live_release/pre_prod_release/current_release_component.html.erb

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@
6262
<%= render BadgeComponent.new(**status) %>
6363
</div>
6464

65+
<% if workflow_run.trigger_failed? %>
66+
<div class="self-start">
67+
<%= render AlertComponent.new(type: :error, title: raw(workflow_run.trigger_failed_reason), full_screen: false) %>
68+
</div>
69+
<% end %>
70+
6571
<% if build.present? %>
6672
<%= render LiveRelease::BuildComponent.new(build) %>
6773
<% end %>

app/jobs/workflow_runs/trigger_job.rb

+11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
class WorkflowRuns::TriggerJob < ApplicationJob
22
queue_as :high
33

4+
TRIGGER_FAILED_REASONS = [
5+
:workflow_parameter_not_provided,
6+
:workflow_dispatch_missing
7+
]
8+
49
def perform(workflow_run_id, retrigger = false)
510
workflow_run = WorkflowRun.find(workflow_run_id)
611
return unless workflow_run.active?
712
return unless workflow_run.may_initiated?
813

914
workflow_run.trigger!(retrigger:)
15+
rescue Installations::Error => err
16+
if err.reason.in?(TRIGGER_FAILED_REASONS)
17+
workflow_run.trigger_failed!(err)
18+
else
19+
raise
20+
end
1021
end
1122
end

app/libs/coordinators.rb

+4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ def self.beta_release_is_finished!(build)
8080
def self.production_release_is_complete!(release_platform_run)
8181
Coordinators::FinishPlatformRun.call(release_platform_run)
8282
end
83+
84+
def self.workflow_run_trigger_failed!(workflow_run)
85+
workflow_run.triggering_release.fail!
86+
end
8387
end
8488

8589
module Actions

app/libs/installations/github/error.rb

+8
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ class Github::Error < Installations::Error
5858
{
5959
message_matcher: /Merge conflict/i,
6060
decorated_reason: :merge_conflict
61+
},
62+
{
63+
message_matcher: /Required input\s+.?\w+.?\s+not provided/,
64+
decorated_reason: :workflow_parameter_not_provided
65+
},
66+
{
67+
message_matcher: /Workflow does not have 'workflow_dispatch' trigger/,
68+
decorated_reason: :workflow_dispatch_missing
6169
}
6270
]
6371

app/models/workflow_run.rb

+19-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class WorkflowRun < ApplicationRecord
4141
failed
4242
halted
4343
finished
44+
trigger_failed
4445
]
4546

4647
KINDS = {
@@ -52,6 +53,7 @@ class WorkflowRun < ApplicationRecord
5253
created: "created",
5354
triggering: "triggering",
5455
triggered: "triggered",
56+
trigger_failed: "trigger_failed",
5557
unavailable: "unavailable",
5658
started: "started",
5759
failed: "failed",
@@ -64,8 +66,8 @@ class WorkflowRun < ApplicationRecord
6466

6567
NOT_STARTED = [:created]
6668
IN_PROGRESS = [:triggering, :triggered, :started]
67-
WORKFLOW_IMMUTABLE = %w[unavailable failed halted finished cancelled cancelling cancelled_before_start]
68-
FAILED_STATES = %w[failed halted unavailable cancelled cancelled_before_start cancelling]
69+
WORKFLOW_IMMUTABLE = %w[unavailable failed halted finished cancelled cancelling cancelled_before_start trigger_failed]
70+
FAILED_STATES = %w[failed halted unavailable cancelled cancelled_before_start cancelling trigger_failed]
6971

7072
enum :status, STATES
7173
enum :kind, KINDS
@@ -111,6 +113,10 @@ class WorkflowRun < ApplicationRecord
111113
transitions from: NOT_STARTED, to: :cancelled_before_start
112114
transitions from: :cancelling, to: :cancelled
113115
end
116+
117+
event :trigger_failed, after_commit: :on_trigger_fail! do
118+
transitions from: :triggering, to: :trigger_failed
119+
end
114120
end
115121

116122
def self.create_and_trigger!(workflow_config, triggering_release, commit, release_platform_run)
@@ -198,6 +204,11 @@ def notification_params
198204
)
199205
end
200206

207+
def trigger_failed_reason
208+
last_error = passports.where(reason: :trigger_failed, kind: :error).last
209+
last_error&.message
210+
end
211+
201212
private
202213

203214
def trigger_external_run!
@@ -266,6 +277,12 @@ def on_fail!
266277
notify!("The workflow run has failed!", :workflow_run_failed, notification_params)
267278
end
268279

280+
def on_trigger_fail!(error)
281+
event_stamp!(reason: :trigger_failed, kind: :error, data: stamp_data.merge(error_message: error.message, error_reason: error.reason))
282+
notify!("Failed to trigger the workflow run!", :workflow_trigger_failed, notification_params)
283+
Signal.workflow_run_trigger_failed!(self)
284+
end
285+
269286
def on_halt!
270287
event_stamp!(reason: :halted, kind: :error, data: stamp_data)
271288
notify!("The workflow run has been halted!", :workflow_run_halted, notification_params)

config/locales/passport/en.yml

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ en:
3939
halted_html: 'The %{kind} workflow run <a class="emphasize-link" href="%{url}">#%{ref}</a> was halted for <a class="emphasize-link" href="%{commit_url}">#%{commit_sha}</a> to build <span class="emphasize">%{version_name} (%{build_number})</span>'
4040
unavailable_html: 'The %{kind} workflow run could not be found for <a class="emphasize-link" href="%{commit_url}">#%{commit_sha}</a> to build <span class="emphasize">%{version_name} (%{build_number})</span>'
4141
finished_html: 'The %{kind} workflow run <a class="emphasize-link" href="%{url}">#%{ref}</a> completed for <a class="emphasize-link" href="%{commit_url}">#%{commit_sha}</a> to build <span class="emphasize">%{version_name} (%{build_number})</span>'
42+
trigger_failed_html: 'The %{kind} workflow run could not be triggered for <a class="emphasize-link" href="%{commit_url}">#%{commit_sha}</a> to build <span class="emphasize">%{version_name} (%{build_number})</span>. Error: <span class="emphasize">%{error_message}.</span>'
4243
google_firebase_submission:
4344
triggered_html: 'Sending <span class="emphasize">%{version} (%{build_number})</span> to Google Firebase groups <span class="emphasize">%{channels}</span>'
4445
finished_html: 'Sent <span class="emphasize">%{version} (%{build_number})</span> to Google Firebase groups <span class="emphasize">%{channels}</span>'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# frozen_string_literal: true
2+
3+
require "rails_helper"
4+
5+
RSpec.describe WorkflowRuns::TriggerJob do
6+
let(:workflow_run) { create(:workflow_run, :triggering) }
7+
8+
before do
9+
allow(WorkflowRun).to receive(:find).and_return(workflow_run)
10+
end
11+
12+
context "when trigger does not cause error" do
13+
before do
14+
allow(workflow_run).to receive(:trigger!)
15+
end
16+
17+
it "triggers successfully" do
18+
described_class.new.perform(workflow_run.id)
19+
expect(workflow_run).to have_received(:trigger!)
20+
end
21+
end
22+
23+
context "when trigger results in error" do
24+
let(:workflow_run) { create(:workflow_run, :triggering) }
25+
26+
shared_examples "with known error" do |error|
27+
before do
28+
allow(workflow_run).to receive(:trigger!).and_raise(error)
29+
end
30+
31+
context "when error is #{error.message}" do
32+
it "changes state of workflow_run to trigger_failed" do
33+
described_class.new.perform(workflow_run.id)
34+
expect(workflow_run.reload.status).to eq("trigger_failed")
35+
end
36+
end
37+
end
38+
39+
include_examples "with known error", Installations::Github::Error.new(
40+
OpenStruct.new(
41+
response_body: {message: "Workflow does not have 'workflow_dispatch' trigger"}.to_json
42+
)
43+
)
44+
include_examples "with known error", Installations::Github::Error.new(
45+
OpenStruct.new(
46+
response_body: {message: "Required input 'parameter_X' not provided"}.to_json
47+
)
48+
)
49+
50+
context "when error is unknown" do
51+
before do
52+
err = Installations::Error.new("Some Error", reason: :unknown_failure)
53+
allow(workflow_run).to receive(:trigger!).and_raise(err)
54+
end
55+
56+
it "does not change state of workflow_run to trigger_failed" do
57+
begin
58+
described_class.new.perform(workflow_run.id)
59+
rescue Installations::Error
60+
nil
61+
end
62+
63+
expect(workflow_run.reload.status).not_to eq("trigger_failed")
64+
end
65+
end
66+
end
67+
end

0 commit comments

Comments
 (0)