Skip to content

Commit 9d49f88

Browse files
author
Leon Silcott
committed
- Remove the document checking action.
- Add actions to handle releases. - Include specific actions for releases. - Update the documentation to explain the reason for forking. - Add a binaries (linux ARM64 AMD64). - Update the action to use Node.js instead of Docker. - Change to utilize `invoke-binary.js`
1 parent 12e1af4 commit 9d49f88

File tree

1,439 files changed

+591840
-57
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,439 files changed

+591840
-57
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!-- action-docs-header source="action.yml" -->
2+
3+
<!-- action-docs-header source="action.yml" -->
4+
5+
<!-- action-docs-description source="action.yml" -->
6+
## Description
7+
8+
Manages GitHub Action releases by validating changes and creating release PRs
9+
<!-- action-docs-description source="action.yml" -->
10+
11+
<!-- action-docs-runs source="action.yml" -->
12+
## Runs
13+
14+
This action is a `composite` action.
15+
<!-- action-docs-runs source="action.yml" -->
16+
17+
<!-- action-docs-inputs source="action.yml" -->
18+
## Inputs
19+
20+
| name | description | required | default |
21+
| --- | --- | --- | --- |
22+
| `mode` | <p>Operation mode: check (for PR validation) or release (for creating releases)</p> | `true` | `""` |
23+
| `base_branch` | <p>Base branch to create a version branch from when the version branch does not exist</p> | `false` | `main` |
24+
| `main_branch` | <p>Main default branch of the repository</p> | `false` | `main` |
25+
<!-- action-docs-inputs source="action.yml" -->
26+
27+
<!-- action-docs-outputs source="action.yml" -->
28+
29+
<!-- action-docs-outputs source="action.yml" -->
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
name: 'Action Release Manager'
2+
description: 'Manages GitHub Action releases by validating changes and creating release PRs'
3+
4+
inputs:
5+
mode:
6+
description: 'Operation mode: check (for PR validation) or release (for creating releases)'
7+
required: true
8+
base_branch:
9+
description: 'Base branch to create a version branch from when the version branch does not exist'
10+
required: false
11+
default: 'main'
12+
main_branch:
13+
description: 'Main default branch of the repository'
14+
required: false
15+
default: 'main'
16+
17+
runs:
18+
using: "composite"
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Get changed files
26+
id: changed-files
27+
uses: tj-actions/changed-files@v45
28+
29+
- name: Setup Node.js
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: 20
33+
34+
- name: Install Semver
35+
shell: bash
36+
run: |
37+
mkdir -p /tmp/action_node_modules
38+
npm install semver --prefix /tmp/action_node_modules
39+
echo "NODE_PATH=/tmp/action_node_modules/node_modules" >> $GITHUB_ENV
40+
41+
- name: Find and validate action directory
42+
id: find-action
43+
uses: ./.github/actions/github-actions/validate-return-modified-action
44+
with:
45+
changed_files: ${{ steps.changed-files.outputs.all_modified_files }}
46+
47+
- name: Handle action directory validation failure
48+
if: failure()
49+
uses: actions/github-script@v7
50+
with:
51+
script: |
52+
const errorMsg = '${{ steps.find-action.outputs.error }}' || 'Action validation failed';
53+
if ('${{ inputs.mode }}' === 'check') {
54+
await github.rest.pulls.createReview({
55+
owner: context.repo.owner,
56+
repo: context.repo.repo,
57+
pull_number: context.issue.number,
58+
body: errorMsg,
59+
event: 'REQUEST_CHANGES'
60+
});
61+
}
62+
63+
core.setFailed(errorMsg);
64+
process.exit();
65+
66+
- name: Dismiss PR change requests if all OK
67+
if: inputs.mode == 'check' && steps.find-action.outputs.error == ''
68+
uses: actions/github-script@v7
69+
with:
70+
script: |
71+
const reviews = await github.rest.pulls.listReviews({
72+
owner: context.repo.owner,
73+
repo: context.repo.repo,
74+
pull_number: context.issue.number
75+
});
76+
77+
const reviewsToDismiss = reviews.data.filter(r => r.user.login === 'github-actions[bot]' && r.state === 'CHANGES_REQUESTED');
78+
79+
for (const review of reviewsToDismiss) {
80+
await github.rest.pulls.dismissReview({
81+
owner: context.repo.owner,
82+
repo: context.repo.repo,
83+
pull_number: context.issue.number,
84+
review_id: review.id,
85+
message: 'Dismissing review as it is resolved by a subsequent commit'
86+
});
87+
}
88+
89+
- name: Determine release info
90+
if: inputs.mode == 'release' && steps.find-action.outputs.modified_action != ''
91+
id: release-info
92+
uses: actions/github-script@v7
93+
with:
94+
script: |
95+
const { execSync } = require('child_process');
96+
97+
let modifiedActions;
98+
try {
99+
modifiedActions = JSON.parse('${{ steps.find-action.outputs.modified_action }}');
100+
} catch (e) {
101+
console.log('No actions to release');
102+
process.exit();
103+
}
104+
105+
if (modifiedActions.length === 0) {
106+
console.log('No actions to release');
107+
process.exit();
108+
}
109+
110+
const releaseInfo = modifiedActions.map(action => {
111+
let releaseType;
112+
try {
113+
execSync(`git show "origin/${action.version}:${action.action}"`, { stdio: 'ignore' });
114+
releaseType = "update";
115+
} catch {
116+
releaseType = "release";
117+
}
118+
119+
return {
120+
action_path: action.action,
121+
version: action.version,
122+
release_type: releaseType,
123+
branch_name: `${action.version}-${releaseType}-${action.action.replace('/', '-').replace('\\', '-')}`
124+
};
125+
});
126+
127+
core.setOutput('release_info', JSON.stringify(releaseInfo));
128+
129+
- name: Create version and release branches
130+
if: inputs.mode == 'release' && steps.find-action.outputs.modified_action != ''
131+
shell: bash
132+
run: |
133+
release_info=$(echo '${{ steps.release-info.outputs.release_info }}' | jq -c '.[]')
134+
for info in $release_info; do
135+
version=$(echo $info | jq -r '.version')
136+
branch_name=$(echo $info | jq -r '.branch_name')
137+
action_path=$(echo $info | jq -r '.action_path')
138+
release_type=$(echo $info | jq -r '.release_type')
139+
if ! git show-ref --quiet refs/heads/$version; then
140+
if ! git show-ref --quiet origin/$version; then
141+
git checkout -b ${{ inputs.base_branch }} origin/${{ inputs.base_branch }}
142+
git pull
143+
git checkout -b $version origin/$version
144+
git push origin $version
145+
else
146+
echo "Version branch $version exists remotely, checking out"
147+
git checkout -b $version origin/$version
148+
git pull
149+
fi
150+
else
151+
echo "Version branch $version already exists locally, skipping creation."
152+
git checkout $version
153+
git pull
154+
fi
155+
156+
git config user.name 'Action Release Bot'
157+
git config user.email 'action-release-bot@users.noreply.github.com'
158+
git branch -a
159+
git fetch origin ${{ inputs.main_branch }}
160+
git checkout -b $branch_name
161+
git checkout origin/${{ inputs.main_branch }} -- $action_path
162+
git add .
163+
git commit -m "[$release_type] $version for $action_path"
164+
git push origin $branch_name
165+
done
166+
167+
- name: Create pull requests
168+
if: inputs.mode == 'release' && steps.find-action.outputs.modified_action != ''
169+
shell: bash
170+
env:
171+
GITHUB_TOKEN: ${{ github.token }}
172+
run: |
173+
release_info=$(echo '${{ steps.release-info.outputs.release_info }}' | jq -c '.[]')
174+
for info in $release_info; do
175+
version=$(echo $info | jq -r '.version')
176+
branch_name=$(echo $info | jq -r '.branch_name')
177+
action_path=$(echo $info | jq -r '.action_path')
178+
release_type=$(echo $info | jq -r '.release_type')
179+
180+
gh pr create \
181+
--base "$version" \
182+
--title "[$release_type] $version $release_type for $action_path" \
183+
--head "$branch_name" \
184+
--body "## What has been done:
185+
186+
- $version $release_type for $action_path"
187+
done
188+
189+
git checkout ${{ inputs.main_branch }}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "release-action",
3+
"version": "0.0.2-beta",
4+
"description": "Manages GitHub Action releases by validating changes and creating release PRs"
5+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!-- action-docs-header source="action.yml" -->
2+
3+
<!-- action-docs-header source="action.yml" -->
4+
5+
<!-- action-docs-description source="action.yml" -->
6+
## Description
7+
8+
Finds the GitHub Action directory that was modified in the provided list of changed files
9+
<!-- action-docs-description source="action.yml" -->
10+
11+
<!-- action-docs-runs source="action.yml" -->
12+
## Runs
13+
14+
This action is a `composite` action.
15+
<!-- action-docs-runs source="action.yml" -->
16+
17+
<!-- action-docs-inputs source="action.yml" -->
18+
## Inputs
19+
20+
| name | description | required | default |
21+
| --- | --- | --- | --- |
22+
| `changed_files` | <p>List of changed files</p> | `true` | `""` |
23+
<!-- action-docs-inputs source="action.yml" -->
24+
25+
<!-- action-docs-outputs source="action.yml" -->
26+
## Outputs
27+
28+
| name | description |
29+
| --- | --- |
30+
| `modified_action` | <p>Path to the modified action directory</p> |
31+
| `error` | <p>Error message if the action directory validation failed</p> |
32+
<!-- action-docs-outputs source="action.yml" -->
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
name: 'Find Modified Action'
2+
description: 'Finds the GitHub Action directory that was modified in the provided list of changed files'
3+
4+
inputs:
5+
changed_files:
6+
description: 'List of changed files'
7+
required: true
8+
9+
outputs:
10+
modified_action:
11+
description: 'Path to the modified action directory'
12+
value: ${{ steps.find-action.outputs.modified_action }}
13+
14+
error:
15+
description: 'Error message if the action directory validation failed'
16+
value: ${{ steps.find-action.outputs.error }}
17+
18+
runs:
19+
using: "composite"
20+
steps:
21+
- name: Setup Node.js
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: 20
25+
26+
- name: Install Semver
27+
shell: bash
28+
run: |
29+
# Install semver in a separate directory to avoid polluting the git branch
30+
mkdir -p /tmp/action_node_modules
31+
npm install semver --prefix /tmp/action_node_modules
32+
echo "NODE_PATH=/tmp/action_node_modules/node_modules" >> $GITHUB_ENV
33+
34+
- name: Find and validate action directory
35+
id: find-action
36+
uses: actions/github-script@v7
37+
env:
38+
NODE_PATH: /tmp/action_node_modules/node_modules
39+
with:
40+
script: |
41+
const fs = require('fs');
42+
const path = require('path');
43+
const semver = require('semver');
44+
45+
function findModifiedActionDir(changedFiles) {
46+
/* For all changed files, find if they are part of an action directory
47+
and return the set of all unique action directories */
48+
49+
const modifiedActionDirs = new Set();
50+
changedFiles.forEach(file => {
51+
let currentDir = path.dirname(file);
52+
53+
// Walk up directory tree until we find action.yml/yaml or reach root
54+
while (currentDir !== '.' && currentDir !== '/') {
55+
if (
56+
fs.existsSync(path.join(currentDir, 'action.yml')) ||
57+
fs.existsSync(path.join(currentDir, 'action.yaml'))
58+
) {
59+
modifiedActionDirs.add(currentDir);
60+
break;
61+
}
62+
currentDir = path.dirname(currentDir);
63+
}
64+
});
65+
66+
return modifiedActionDirs;
67+
}
68+
69+
function validateActionDir(actionDir) {
70+
/* Validate action directory's package.json */
71+
72+
// Validate package.json exists
73+
if (!fs.existsSync(path.join(actionDir, 'package.json'))) {
74+
throw new Error('The action directory does not contain package.json file');
75+
}
76+
77+
// Validate package.json content
78+
try {
79+
const packageJson = JSON.parse(fs.readFileSync(path.join(actionDir, 'package.json'), 'utf8'));
80+
if (!packageJson.version) {
81+
throw new Error('The package.json file does not contain a version field');
82+
}
83+
if (!semver.valid(packageJson.version)) {
84+
throw new Error('The package.json file contains an invalid version field');
85+
}
86+
} catch (error) {
87+
throw new Error(`Package.json validation failed: ${error.message}`);
88+
}
89+
}
90+
91+
let changedFiles = `${{ inputs.changed_files }}`.split(' ');
92+
93+
const modifiedActionDirs = findModifiedActionDir(changedFiles);
94+
// Exit if there are no modified action directories
95+
if (modifiedActionDirs.size === 0) {
96+
console.log('No action to release');
97+
return;
98+
}
99+
100+
for (const targetActionDir of modifiedActionDirs) {
101+
try {
102+
validateActionDir(targetActionDir);
103+
} catch (error) {
104+
core.setFailed(error.message);
105+
core.setOutput('error', error.message);
106+
return;
107+
}
108+
}
109+
110+
// Get the action directory and version
111+
const actionDirsOutput = Array.from(modifiedActionDirs).map(
112+
dir => {
113+
const packageJson = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
114+
return {
115+
"action": dir,
116+
"version": semver.prerelease(packageJson.version) ? semver.prerelease(packageJson.version)[0] : "v" + semver.major(packageJson.version)
117+
}
118+
}
119+
);
120+
121+
// Set the output
122+
core.setOutput('modified_action', JSON.stringify(actionDirsOutput));
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "validate-return-modified-action",
3+
"version": "0.0.2-beta",
4+
"description": "Finds the GitHub Action directory that was modified in the provided list of changed files"
5+
}

0 commit comments

Comments
 (0)