Implement allowed-skips input
This change lets the end-users mark certain jobs as allowed to be non- voting when skipped only but their failures will affect the outcome. Resolves #1
This commit is contained in:
@@ -78,6 +78,7 @@ jobs:
|
||||
uses: re-actors/alls-green@release/v1
|
||||
with:
|
||||
allowed-failures: docs, linters
|
||||
allowed-skips: non-voting-flaky-job
|
||||
jobs: ${{ toJSON(needs) }}
|
||||
...
|
||||
```
|
||||
@@ -85,10 +86,13 @@ jobs:
|
||||
|
||||
## Options
|
||||
|
||||
There are two options — `allowed-failures` and `jobs`. The former is
|
||||
optional but the later is mandatory. `allowed-failures` tells the action
|
||||
which jobs should not affect the outcome, by default all the jobs will
|
||||
be "voting". `jobs` is an object representing the jobs that should
|
||||
There are three options — `allowed-failures`, `allowed-skips` and
|
||||
`jobs`. The first two are optional but `jobs` is mandatory.
|
||||
`allowed-failures` tells the action which jobs should not affect the
|
||||
outcome if they don't succeed, by default all the jobs will
|
||||
be "voting". Same goes for `allowed-skips` — it won't allow the listed
|
||||
jobs to affect the outcome if they are skipped but are still "voting" in
|
||||
case they run. `jobs` is an object representing the jobs that should
|
||||
affect the decision of whether the pipeline failed or not, it is
|
||||
important to pass a JSON-serialized `needs` context to this argument.
|
||||
|
||||
|
||||
+11
@@ -23,6 +23,13 @@ inputs:
|
||||
Job names that are allowed to fail and not affect the outcome,
|
||||
as a comma-separated list or serialized as a JSON string
|
||||
required: false
|
||||
allowed-skips:
|
||||
default: >-
|
||||
[]
|
||||
description: >-
|
||||
Job names that are allowed to be skipped and not affect the
|
||||
outcome, as a comma-separated list or serialized as a JSON string
|
||||
required: false
|
||||
|
||||
outputs:
|
||||
failure:
|
||||
@@ -48,6 +55,10 @@ runs:
|
||||
${{ inputs.allowed-failures }}
|
||||
EOM
|
||||
)" \
|
||||
"$(cat << EOM
|
||||
${{ inputs.allowed-skips }}
|
||||
EOM
|
||||
)" \
|
||||
"$(cat << EOM
|
||||
${{ inputs.jobs }}
|
||||
EOM
|
||||
|
||||
@@ -35,13 +35,14 @@ def parse_as_list(input_text):
|
||||
return [s.strip() for s in input_text.split(',')]
|
||||
|
||||
|
||||
def parse_inputs(raw_allowed_failures, raw_jobs):
|
||||
def parse_inputs(raw_allowed_failures, raw_allowed_skips, raw_jobs):
|
||||
"""Normalize the action inputs by turning them into data."""
|
||||
allowed_failures_input = parse_as_list(raw_allowed_failures)
|
||||
|
||||
allowed_skips_input = parse_as_list(raw_allowed_skips)
|
||||
|
||||
return {
|
||||
'allowed_failures': allowed_failures_input,
|
||||
'allowed_skips': allowed_skips_input,
|
||||
'jobs': json.loads(raw_jobs),
|
||||
}
|
||||
|
||||
@@ -49,7 +50,9 @@ def parse_inputs(raw_allowed_failures, raw_jobs):
|
||||
def log_decision_details(
|
||||
job_matrix_succeeded,
|
||||
jobs_allowed_to_fail,
|
||||
jobs_allowed_to_be_skipped,
|
||||
allowed_to_fail_jobs_succeeded,
|
||||
allowed_to_be_skipped_jobs_succeeded,
|
||||
jobs,
|
||||
):
|
||||
"""Record the decisions made into console output."""
|
||||
@@ -73,27 +76,46 @@ def log_decision_details(
|
||||
)
|
||||
|
||||
|
||||
if jobs_allowed_to_be_skipped and allowed_to_be_skipped_jobs_succeeded:
|
||||
print_to_stderr(
|
||||
'🛈 All of the allowed to be skipped dependency jobs succeeded.',
|
||||
)
|
||||
elif jobs_allowed_to_fail:
|
||||
print_to_stderr(
|
||||
'🛈 Some of the allowed to be skipped jobs did not succeed.',
|
||||
)
|
||||
|
||||
|
||||
print_to_stderr('📝 Job statuses:')
|
||||
for name, job in jobs.items():
|
||||
print_to_stderr(
|
||||
'📝 {name} → {emoji} {result} [{status}]'.
|
||||
format(
|
||||
emoji='✓' if job['result'] == 'success' else '❌',
|
||||
emoji='✓' if job['result'] == 'success'
|
||||
else '❌' if job['result'] == 'failure'
|
||||
else '⬜',
|
||||
name=name,
|
||||
result=job['result'],
|
||||
status='allowed to fail' if name in jobs_allowed_to_fail
|
||||
else 'required to succeed',
|
||||
else 'required to succeed'
|
||||
if name not in jobs_allowed_to_be_skipped
|
||||
else 'required to succeed or be skipped',
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def main(argv):
|
||||
"""Decide whether the needed jobs got satisfactory results."""
|
||||
inputs = parse_inputs(raw_allowed_failures=argv[1], raw_jobs=argv[2])
|
||||
inputs = parse_inputs(
|
||||
raw_allowed_failures=argv[1],
|
||||
raw_allowed_skips=argv[2],
|
||||
raw_jobs=argv[3],
|
||||
)
|
||||
|
||||
|
||||
jobs = inputs['jobs'] or {}
|
||||
jobs_allowed_to_fail = inputs['allowed_failures'] or []
|
||||
jobs_allowed_to_fail = set(inputs['allowed_failures'] or [])
|
||||
jobs_allowed_to_be_skipped = set(inputs['allowed_skips'] or [])
|
||||
|
||||
if not jobs:
|
||||
sys.exit(
|
||||
@@ -104,7 +126,10 @@ def main(argv):
|
||||
|
||||
job_matrix_succeeded = all(
|
||||
job['result'] == 'success' for name, job in jobs.items()
|
||||
if name not in jobs_allowed_to_fail
|
||||
if name not in (jobs_allowed_to_fail | jobs_allowed_to_be_skipped)
|
||||
) and all(
|
||||
job['result'] in {'skipped', 'success'} for name, job in jobs.items()
|
||||
if name in jobs_allowed_to_be_skipped
|
||||
)
|
||||
set_final_result_outputs(job_matrix_succeeded)
|
||||
|
||||
@@ -115,10 +140,18 @@ def main(argv):
|
||||
)
|
||||
|
||||
|
||||
allowed_to_be_skipped_jobs_succeeded = all(
|
||||
job['result'] == 'success' for name, job in jobs.items()
|
||||
if name in jobs_allowed_to_be_skipped
|
||||
)
|
||||
|
||||
|
||||
log_decision_details(
|
||||
job_matrix_succeeded,
|
||||
jobs_allowed_to_fail,
|
||||
jobs_allowed_to_be_skipped,
|
||||
allowed_to_fail_jobs_succeeded,
|
||||
allowed_to_be_skipped_jobs_succeeded,
|
||||
jobs,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user