Skip to content

Commit e183d72

Browse files
authored
fix/wait for check discovery (#139)
1 parent 8ad3eaf commit e183d72

5 files changed

Lines changed: 88 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
## Unreleased
44

5+
## v1.5.1 - 2026-03-25
6+
7+
### Added
8+
9+
- Add `checks-discovery-timeout` option to poll for checks that haven't been created yet (e.g. jobs with `needs` dependencies) (#137)
10+
511
## v1.5.0 - 2026-01-25
612

713
### Added

action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ inputs:
4444
description: "Fail the action if no checks match the check-name or check-regexp filters"
4545
required: false
4646
default: true
47+
checks-discovery-timeout:
48+
description: "Seconds to wait for checks to be discovered before failing (useful for jobs with needs dependencies)"
49+
required: false
50+
default: "60"
4751

4852
runs:
4953
using: "composite"
@@ -72,6 +76,7 @@ runs:
7276
RUNNING_WORKFLOW_NAME: ${{ inputs.running-workflow-name }}
7377
API_ENDPOINT: ${{ inputs.api-endpoint }}
7478
FAIL_ON_NO_CHECKS: ${{ inputs.fail-on-no-checks }}
79+
CHECKS_DISCOVERY_TIMEOUT: ${{ inputs.checks-discovery-timeout }}
7580

7681
branding:
7782
icon: "check-circle"

app/services/github_checks_verifier.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class GithubChecksVerifier < ApplicationService
2020
config_accessor(:fail_on_no_checks) { true }
2121
config_accessor(:ignore_checks) { [] }
2222
config_accessor(:verbose) { true }
23+
config_accessor(:discovery_timeout) { 60 }
2324
config_accessor(:wait) { 30 }
2425
config_accessor(:workflow_name) { '' }
2526

@@ -73,6 +74,18 @@ def apply_regexp_filter(checks)
7374
checks.select! { |check| check.name[Regexp.new(check_regexp)] } if check_regexp.present?
7475
end
7576

77+
def wait_for_check_discovery(all_checks)
78+
return all_checks unless filters_present? && all_checks.blank? && fail_on_no_checks
79+
80+
wait_until = Time.now + discovery_timeout
81+
while all_checks.blank? && Time.now < wait_until
82+
puts "Matching checks have not been found yet, will check again in #{wait} seconds. " \
83+
"(Limit: #{discovery_timeout}s)"
84+
all_checks = (sleep(wait) && query_check_status)
85+
end
86+
all_checks
87+
end
88+
7689
def all_checks_complete(checks)
7790
checks.all? { |check| check.status == 'completed' }
7891
end
@@ -110,8 +123,7 @@ def show_checks_conclusion_message(checks)
110123
end
111124

112125
def wait_for_checks
113-
all_checks = query_check_status
114-
126+
all_checks = wait_for_check_discovery(query_check_status)
115127
fail_if_requested_check_never_run(all_checks)
116128

117129
until all_checks_complete(all_checks)

entrypoint.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
api_endpoint = ENV.fetch('API_ENDPOINT', '')
1717
ignore_checks = ENV.fetch('IGNORE_CHECKS', nil)
1818
fail_on_no_checks = ENV.fetch('FAIL_ON_NO_CHECKS', 'true')
19+
discovery_timeout = ENV.fetch('CHECKS_DISCOVERY_TIMEOUT', '60')
1920

2021
GithubChecksVerifier.configure do |config|
2122
config.allowed_conclusions = allowed_conclusions.split(',').map(&:strip)
@@ -31,6 +32,7 @@
3132
config.wait = wait.to_i
3233
config.workflow_name = workflow_name
3334
config.fail_on_no_checks = fail_on_no_checks == 'true'
35+
config.discovery_timeout = discovery_timeout.to_i
3436
end
3537

3638
GithubChecksVerifier.call

spec/services/github_checks_verifier_spec.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
describe '#fail_if_requested_check_never_run' do
107107
it 'raises an exception if check_name is not empty and all_checks is' do
108108
service.config.check_name = 'test'
109+
service.config.discovery_timeout = 0
109110

110111
all_checks = []
111112
allow(service).to receive(:query_check_status).and_return all_checks
@@ -149,6 +150,7 @@
149150
it 'raises an exception when check_regexp is set and no checks match' do
150151
service.config.check_regexp = 'non-matching-regexp'
151152
service.config.fail_on_no_checks = true
153+
service.config.discovery_timeout = 0
152154

153155
all_checks = []
154156
allow(service).to receive(:query_check_status).and_return all_checks
@@ -160,6 +162,7 @@
160162
it 'raises an exception when check_name is set and no checks match' do
161163
service.config.check_name = 'non-existing-check'
162164
service.config.fail_on_no_checks = true
165+
service.config.discovery_timeout = 0
163166

164167
all_checks = []
165168
allow(service).to receive(:query_check_status).and_return all_checks
@@ -170,6 +173,64 @@
170173
end
171174
end
172175

176+
describe '#wait_for_check_discovery' do
177+
before do
178+
service.config.ref = '_'
179+
service.config.client.access_token = '_'
180+
end
181+
182+
it 'polls until checks are found within the timeout' do
183+
service.config.check_name = 'delayed-check'
184+
service.config.fail_on_no_checks = true
185+
service.config.discovery_timeout = 30
186+
service.wait = 0
187+
188+
completed_check = [Helpers::CheckRun.new(name: 'delayed-check', status: 'completed', conclusion: 'success')]
189+
call_count = 0
190+
allow(service).to receive(:query_check_status) do
191+
call_count += 1
192+
call_count < 3 ? [] : completed_check
193+
end
194+
195+
output = with_captured_stdout { service.call }
196+
expect(output).to include('Matching checks have not been found yet')
197+
end
198+
199+
it 'logs discovery message when fail_on_no_checks is false' do
200+
service.config.check_name = 'non-existing-check'
201+
service.config.fail_on_no_checks = false
202+
service.config.discovery_timeout = 30
203+
204+
allow(service).to receive(:query_check_status).and_return []
205+
206+
output = with_captured_stdout { service.call }
207+
expect(output).not_to include('Matching checks have not been found yet')
208+
end
209+
210+
it 'succeeds immediately when fail_on_no_checks is false' do
211+
service.config.check_name = 'non-existing-check'
212+
service.config.fail_on_no_checks = false
213+
service.config.discovery_timeout = 30
214+
215+
allow(service).to receive(:query_check_status).and_return []
216+
217+
output = with_captured_stdout { service.call }
218+
expect(output).to include('No checks found matching the filter, but fail-on-no-checks is false')
219+
end
220+
221+
it 'fails after discovery timeout is exceeded' do
222+
service.config.check_name = 'never-found-check'
223+
service.config.fail_on_no_checks = true
224+
service.config.discovery_timeout = 0
225+
service.wait = 0
226+
227+
allow(service).to receive(:query_check_status).and_return []
228+
229+
expected_msg = 'The requested check was never run against this ref, exiting...'
230+
expect { service.call }.to raise_error(SystemExit).and output(/#{expected_msg}/).to_stdout
231+
end
232+
end
233+
173234
describe '#fail_unless_all_conclusions_allowed' do
174235
it 'raises an exception if some check conclusion is not allowed' do
175236
all_checks = [

0 commit comments

Comments
 (0)