Skip to content

Commit

Permalink
add v1 of docs and implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
wechuli committed Feb 1, 2024
1 parent f882d7a commit 62a2202
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 17 deletions.
130 changes: 117 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ any of the checks are still in progress, pending or queued when the workflow is

## How it works

When the workflow is triggered, the action will poll the GitHub API every 1 minute (default) for 10 tries (default).
When the workflow is triggered, the action will poll the GitHub API every 1 minute (default) for 10 tries (default) -
you can change these to your liking.
If all the checks are successful, the action will succeed. If any of the checks are still in progress, pending or
queued, the action fails

Expand All @@ -48,40 +49,143 @@ jobs:
### Exclude certain checks from causing a failure
You can exclude certain checks from causing a failure by using the `exclude_checks` input:
You can exclude certain checks from causing a failure by using the `exclude_checks` input. The input accepts a comma
separated string of values:

```yaml
jobs:
allchecks:
runs-on: ubuntu-latest
permissions:
checks: read
contents: read
steps:
- uses: wechuli/allcheckspassed@v1
with:
exclude_checks: 'CodeQL'
exclude_checks: 'CodeQL,lint,cosmetic'
```

You might want to do this to allow certain checks to fail, such as a code quality check, but still require that all
other checks pass.

The `exclude_checks` and `include_checks` inputs support Regular Expressions. For example, if you want to exclude all
checks have the word `lint` somewhere in the string, you don't have to list them all out, you can use the following:

```yaml
steps:
- uses: wechuli/allcheckspassed@v1
with:
exclude_checks: '.*lint.*'
```

### Include only certain checks

You can choose to include only specific checks for evaluation and ignore others. This is not the primary use case
for this action, but it is possible. If you want the check to always be included, you might consider using the native
repository rulesets or branch protection rules. You can't provide both `include_checks` and `exclude_checks` at the same
time.

```yaml
steps:
- uses: wechuli/allcheckspassed@v1
with:
include_checks: 'CodeQL'
```

### What should be considered as passing

At the moment, checks with `success`, `neutral` and `skipped` are considered passing by GitHub. This action will
default to this behavior as well but you can change this if you want to.

```yaml
steps:
- uses: wechuli/allcheckspassed@v1
with:
treat_skipped_as_passed: false
treat_neutral_as_passed: false
```

In the above configuration, the action will fail if any of the checks are skipped or neutral.

### Missing checks

If you define one or more checks in the `include_checks` input, the action will output a warning if any of the checks
are missing. You can choose instead to fail the action if any of the checks are missing:

```yaml
steps:
- uses: wechuli/allcheckspassed@v1
with:
fail_on_missing_checks: true
```

### Time

The default behavior of this action is that is delays its execution for 1 minute (default) and polls the API 10 times (
retries) with a delay
between each poll of 1 minute (default). You can change these values to your liking:

```yaml
steps:
- uses: wechuli/allcheckspassed@v1
with:
delay: '5'
retries: '3'
polling_interval: '3'
```

When the step with the action runs, it will wait for 5 minutes before polling the API for the first time. It will then
poll the API 3 times with a delay of 3 minutes between each poll.

You also don't have to poll, you can just run the action once and get the result.

```yaml
steps:
- uses: wechuli/allcheckspassed@v1
with:
poll: false
```

## Setup with environments

This action is essentially a workflow run that will consume your GitHub Actions minutes. You may want to delay the
execution of the action to give enough time for your checks to run. GitHub provides the environments feature
that has a protection rule to allow you to delay the execution of job for a specified amount of time after the job is
triggered:

https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#wait-timer

This will save you some minutes if you have a lot of checks that run and you don't want to poll the API for a long time.

```yaml
jobs:
allchecks:
runs-on: ubuntu-latest
permissions:
checks: read
contents: read
environment: delayenv
steps:
- uses: wechuli/allcheckspassed@v1
with:
include_checks: 'CodeQL'
poll: false
```

![Image](https://github.com/wechuli/allcheckspassed/assets/15605874/abb794ff-f008-409f-9760-160c24b6c45c)

Unfortunately, this feature is only available on private/internal repositories for Enterprise plans. All public
repositories
have access to this feature.

A downside of using environments is that it creates deployments which will show up on your pull request's timeline,
these
can sometimes be confusing, there is no way to prevent that.

## Setup with repository rulesets/branch protection rules

You want to require the check that is created to always pass in your repository rulesets or branch protection rules.
Where possible prefer to configure repository rulesets
to branch protection rules as they are more flexible.

## Limitations

Ultimately this is a temporary workaround for a missing feature, ensure all checks that run pass. GitHub may implement
this as some point, at which point you will not need the action anymore.

- The action is not checking for commit statuses, which uses a different API. If you need this, please open an issue.
- Unfortunately, you'll need to poll the API to get the state of the checks. The action itself is consuming GitHub
Actions minutes doing this polling
- If you are polling too quickly, you may hit the API rate limit
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ inputs:
description: "The number of times to retry the API call to get the checks, if the API call fails"
required: false
default: "10"
fail_on_missing_checks:
description: "If set to true, the action will fail if one or more checks defined on the checks_include input are not found on the commit"
required: false
default: "false"

outputs:
checks:
Expand Down
24 changes: 21 additions & 3 deletions src/checks/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default class Checks {
private checksInclude: ICheckInput[];
private treatSkippedAsPassed: boolean;
private treatNeutralAsPassed: boolean;
private failOnMissingChecks: boolean;
private poll: boolean;
private retries: number;
private pollingInterval: number;
Expand All @@ -48,6 +49,7 @@ export default class Checks {
this.checksInclude = props.checksInclude;
this.treatSkippedAsPassed = props.treatSkippedAsPassed;
this.treatNeutralAsPassed = props.treatNeutralAsPassed;
this.failOnMissingChecks = props.failOnMissingChecks;
this.poll = props.poll;
this.pollingInterval = props.pollingInterval;
this.retries = props.retries;
Expand Down Expand Up @@ -159,7 +161,7 @@ export default class Checks {
let missingChecks: ICheckInput[] = [];
let filteredChecksExcludingOwnCheck: ICheck[] = [];

while (iteration < this.retries) {
do {
iteration++;
let result = await this.iterate();
allChecksPass = result["allChecksPass"];
Expand All @@ -174,7 +176,7 @@ export default class Checks {
break;
}
await sleep(this.pollingInterval * 1000 * 60);
}
} while (iteration < this.retries);

// create table with results of filtered checks

Expand Down Expand Up @@ -205,8 +207,24 @@ export default class Checks {

if (missingChecks.length > 0) {
core.warning("Some checks were not found, please check the workflow run summary to get the details");
let missingChecksSummaryHeader = [{data: 'name', header: true}, {data: 'app.id', header: true}];
let missingChecksSummary = missingChecks.map(check => {
return [check.name, check.app_id.toString()]
});

await core.summary.addHeading("Missing Checks").addTable([

missingChecksSummaryHeader,
...missingChecksSummary

]).write();

// fail if the user wants us to fail on missing checks
if (this.failOnMissingChecks) {
core.setFailed("Failing due to missing checks");
}
}

}


Expand Down
5 changes: 4 additions & 1 deletion src/utils/inputsExtractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface IInputs {
delay: number;
pollingInterval: number;
retries: number;
failOnMissingChecks: boolean;
}

function inputsParser(): IInputs {
Expand All @@ -36,6 +37,7 @@ function inputsParser(): IInputs {
const treatSkippedAsPassed: boolean =
core.getInput("treat_skipped_as_passed") == "true";
const treatNeutralAsPassed: boolean = core.getInput("treat_neutral_as_passed") == "true";
const failOnMissingChecks: boolean = core.getInput("fail_on_missing_checks") == "true";
const poll: boolean = core.getInput("poll") == "true";
const delay: number = validateIntervalValues(
parseInt(core.getInput("delay"))
Expand All @@ -55,7 +57,8 @@ function inputsParser(): IInputs {
poll,
delay,
pollingInterval,
retries
retries,
failOnMissingChecks
};
}

Expand Down

0 comments on commit 62a2202

Please sign in to comment.