Skip to content

Commit 757d1f1

Browse files
SONARIAC-2113 Add "Check Releasability" Github Action (#4)
* add 'Check releasability status' action * add readme * fix review issues
1 parent 261ccb8 commit 757d1f1

File tree

3 files changed

+143
-1
lines changed

3 files changed

+143
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ A centralized collection of reusable GitHub Actions designed to streamline and a
44

55
## Available Actions
66

7-
* [**Create Jira Release Ticket**](create-jira-release-ticket/README.md): Automates the creation of an "Ask for release" ticket in Jira.
7+
* [**Create Jira Release Ticket**](create-jira-release-ticket/README.md): Automates the creation of an "Ask for release" ticket in Jira.
8+
* [**Check Releasability Status**](check-releasability-status/README.md): Checks the releasability status of the master branch and extracts the version if successful.

check-releasability-status/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Check Releasability Status Action
2+
3+
This GitHub Action checks the releasability status of the master branch. If the check was successful, it extracts the version number from its annotation. It's important to note that this action doesn't run the releasability status check itself but rather finds previous runs. The action is designed to be a prerequisite step in a release workflow, ensuring that a version is ready to be released before proceeding.
4+
5+
The action is self-contained and uses the `actions/github-script` toolkit to interact with the GitHub Checks API.
6+
7+
## Prerequisites
8+
9+
The action requires that the workflow has `checks: read` permissions for the `GITHUB_TOKEN` to be able to access the Checks API.
10+
11+
## Inputs
12+
13+
The following inputs can be configured for the action:
14+
15+
| Input | Description | Required | Default |
16+
|----------------|------------------------------------|----------|--------------------------|
17+
| `check-name` | The name of the check run to find. | `false` | `'Releasability status'` |
18+
| `github-token` | The GitHub token for API calls. | `true` | `${{ github.token }}` |
19+
20+
## Outputs
21+
22+
| Output | Description |
23+
|-----------|-----------------------------------------------------------------------------------------------------------------|
24+
| `version` | The extracted version string from the check annotation if the check was successful and an annotation was found. |
25+
26+
## Example Usage
27+
28+
Here is an example of how to use this action in a workflow. This workflow can be triggered manually. The first job checks the releasability status and exposes the found version as an output. A second job then consumes this version to perform a subsequent step, such as creating a release.
29+
30+
```yaml
31+
name: Check Releasability and Use Version
32+
33+
on:
34+
workflow_dispatch:
35+
36+
jobs:
37+
check_releasability:
38+
name: Check Releasability Status
39+
runs-on: ubuntu-latest
40+
outputs:
41+
release_version: ${{ steps.check_status.outputs.version }}
42+
43+
steps:
44+
- name: Check Releasability Status
45+
id: check_status
46+
uses: SonarSource/release-github-actions/check-releasability-status@master
47+
48+
use_the_version:
49+
name: Use the Extracted Version
50+
runs-on: ubuntu-latest
51+
needs: check_releasability
52+
53+
steps:
54+
- name: Echo the version
55+
if: needs.check_releasability.outputs.release_version
56+
run: |
57+
echo "The releasable version is ${{ needs.check_releasability.outputs.release_version }}"

check-releasability-status/action.yml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: 'Check releasability status'
2+
description: 'Gets the status of the latest releasability check on the master branch and returns the version if it succeeded.'
3+
4+
inputs:
5+
check-name:
6+
description: 'The name of the check run to find.'
7+
required: false
8+
default: 'Releasability status'
9+
github-token:
10+
description: 'The GitHub token for API calls.'
11+
required: true
12+
default: ${{ github.token }}
13+
14+
outputs:
15+
version:
16+
description: 'The extracted version string from the check annotation.'
17+
value: ${{ steps.check_releasability_script.outputs.version }}
18+
19+
runs:
20+
using: 'composite'
21+
steps:
22+
- name: Check releasability status
23+
id: check_releasability_script
24+
uses: actions/github-script@v7
25+
with:
26+
github-token: ${{ inputs.github-token }}
27+
script: |
28+
const { owner, repo } = context.repo;
29+
const check_name = '${{ inputs.check-name }}';
30+
31+
console.log(`Searching for check runs on the "master" branch.`);
32+
const { data: { check_runs } } = await github.rest.checks.listForRef({
33+
owner,
34+
repo,
35+
ref: 'master',
36+
per_page: 50
37+
});
38+
39+
console.log(`Filtering for the first non-skipped check named "${check_name}".`);
40+
const targetCheck = check_runs.find(check => check.name === check_name && check.conclusion !== 'skipped');
41+
42+
if (!targetCheck) {
43+
core.setFailed(`Could not find a recent, non-skipped check named "${check_name}" on the master branch.`);
44+
return;
45+
}
46+
47+
console.log(`Found latest relevant check run #${targetCheck.id} (Conclusion: ${targetCheck.conclusion}) on commit ${targetCheck.head_sha}.`);
48+
49+
if (targetCheck.conclusion !== 'success') {
50+
core.setFailed(`The check run "${check_name}" did not succeed. Conclusion: ${targetCheck.conclusion}.`);
51+
return;
52+
}
53+
54+
console.log('Check was successful. Fetching annotations...');
55+
const { data: annotations } = await github.rest.checks.listAnnotations({
56+
owner,
57+
repo,
58+
check_run_id: targetCheck.id
59+
});
60+
61+
if (annotations.length === 0) {
62+
core.setFailed('Found the successful check, but it has no annotations.');
63+
return;
64+
}
65+
66+
const firstAnnotation = annotations[0];
67+
68+
if (firstAnnotation.annotation_level === 'failure') {
69+
core.setFailed(`The check annotation indicates a failure: "${firstAnnotation.message}"`);
70+
return;
71+
}
72+
73+
const annotationMessage = firstAnnotation.message;
74+
console.log(`Found annotation message: "${annotationMessage}"`);
75+
76+
const match = annotationMessage.match(/of ([\d\.]+)/);
77+
if (!match || !match[1]) {
78+
core.setFailed(`Could not parse version from annotation message: "${annotationMessage}"`);
79+
return;
80+
}
81+
82+
const version = match[1];
83+
console.log(`✅ Extracted version from annotation: ${version}`);
84+
core.setOutput('version', version);

0 commit comments

Comments
 (0)