Compare commits

..

6 Commits

Author SHA1 Message Date
Michael B. Gale 95152f814a Address review 2026-05-21 10:54:04 +01:00
Michael B. Gale f34cadbf2a Update check-node-version to compare .nvmrc 2026-05-21 00:13:03 +01:00
Michael B. Gale dda23c79a8 Write .nvmrc file in build.mjs 2026-05-21 00:09:15 +01:00
Michael B. Gale 5fb81ae73e Add .nvmrc 2026-05-21 00:06:40 +01:00
Michael B. Gale eeaa56bdbb Add some extra validation for runs.using 2026-05-21 00:00:51 +01:00
Michael B. Gale bee9891358 Add build plugin to check Node versions 2026-05-20 12:02:42 +01:00
14 changed files with 116 additions and 70 deletions
+1 -1
View File
@@ -59,7 +59,7 @@ jobs:
use-all-platform-bundle: 'false'
setup-kotlin: 'true'
- name: Set up Ruby
uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1.307.0
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration
@@ -9,10 +9,6 @@ on:
# by other workflows.
types: [opened, synchronize, reopened, ready_for_review]
concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
group: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
@@ -24,10 +24,6 @@ on:
- cron: '0 5 * * *'
workflow_dispatch:
concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
group: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
@@ -20,10 +20,6 @@ on:
- cron: '0 5 * * *'
workflow_dispatch:
concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
group: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
@@ -19,10 +19,6 @@ on:
- cron: '0 5 * * *'
workflow_dispatch:
concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
group: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
+21 -16
View File
@@ -10,10 +10,6 @@ on:
types: [checks_requested]
workflow_dispatch:
concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
group: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
@@ -109,10 +105,10 @@ jobs:
run: npx tsx --test
check-node-version:
if: github.triggering_actor != 'dependabot[bot]'
name: Check Action Node versions
if: github.triggering_actor != 'dependabot[bot]' && startsWith(github.head_ref, 'backport-')
name: Check Action Node versions for Backport
runs-on: ubuntu-latest
timeout-minutes: 45
timeout-minutes: 5
env:
BASE_REF: ${{ github.base_ref }}
@@ -120,31 +116,40 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v6
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1
- id: head-version
name: Verify all Actions use the same Node version
name: Determine Node version for HEAD
run: |
NODE_VERSION=$(find . -name "action.yml" -exec yq -e '.runs.using' {} \; | grep node | sort | uniq)
echo "NODE_VERSION: ${NODE_VERSION}"
if [[ $(echo "$NODE_VERSION" | wc -l) -gt 1 ]]; then
echo "::error::More than one node version used in 'action.yml' files."
if [[ ! -f ".nvmrc" ]]; then
echo "::error::Cannot find .nvmrc in the HEAD commit."
exit 1
fi
NODE_VERSION=$(cat .nvmrc)
echo "NODE_VERSION: ${NODE_VERSION}"
echo "node_version=${NODE_VERSION}" >> $GITHUB_OUTPUT
- id: checkout-base
name: 'Backport: Check out base ref'
if: ${{ startsWith(github.head_ref, 'backport-') }}
uses: actions/checkout@v6
with:
ref: ${{ env.BASE_REF }}
fetch-depth: 1
- name: 'Backport: Verify Node versions unchanged'
if: steps.checkout-base.outcome == 'success'
env:
HEAD_VERSION: ${{ steps.head-version.outputs.node_version }}
run: |
BASE_VERSION=$(find . -name "action.yml" -exec yq -e '.runs.using' {} \; | grep node | sort | uniq)
if [[ ! -f ".nvmrc" ]]; then
echo "::error::Cannot find .nvmrc in the base commit."
exit 1
fi
BASE_VERSION=$(cat .nvmrc)
echo "HEAD_VERSION: ${HEAD_VERSION}"
echo "BASE_VERSION: ${BASE_VERSION}"
if [[ "$BASE_VERSION" != "$HEAD_VERSION" ]]; then
-4
View File
@@ -14,10 +14,6 @@ on:
- cron: '0 0 * * 1'
workflow_dispatch:
concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
group: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
-4
View File
@@ -17,10 +17,6 @@ on:
- cron: '0 5 * * *'
workflow_dispatch:
concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
group: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
@@ -18,11 +18,6 @@ on:
schedule:
- cron: '0 5 * * *'
workflow_dispatch:
concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
group: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
+1
View File
@@ -0,0 +1 @@
24
+73 -2
View File
@@ -4,6 +4,7 @@ import { fileURLToPath } from "node:url";
import * as esbuild from "esbuild";
import { globSync } from "glob";
import * as yaml from "js-yaml";
import pkg from "./package.json" with { type: "json" };
@@ -27,6 +28,70 @@ const cleanPlugin = {
},
};
/** A plugin that checks that the Node versions in all `action.yml` files are the same. */
const checkNodeVersionsPlugin = {
name: "check-node-versions",
setup(build) {
build.onStart(async () => {
// Find all the `action.yml` files. We don't care about the stub in the repository root,
// since that is a `composite` action.
const actionSpecifications = globSync("*/action.yml");
// Track the Node versions we find for each file.
const nodeVersions = {};
// We will store the first Node version we find and use it to compare against the others.
// If there's any disagreement, we set `versionMismatch` to `true` and throw an error
// that includes all the discovered Node versions at the end.
let nodeVersion = undefined;
let versionMismatch = false;
for (const actionSpecification of actionSpecifications) {
// Read the contents of the action.yml file.
const contents = await readFile(actionSpecification, "utf-8");
const specification = yaml.load(contents);
// Find the `runs.using` value in the specification.
const using = specification.runs.using;
if (using === undefined || using === null) {
throw new Error(
`Couldn't find 'runs.using' in ${actionSpecification}`,
);
}
if (typeof using !== "string" || !using.startsWith("node")) {
throw new Error(
`Expected 'runs.using' to be a string starting with 'node' in ${actionSpecification}`,
);
}
if (nodeVersion === undefined) {
// First one we found: set it as the baseline.
nodeVersion = using;
} else if (nodeVersion !== using) {
// Disagreement: set `versionMismatch` to indicate that we should throw an error later.
versionMismatch = true;
}
nodeVersions[actionSpecification] = using;
}
// Throw an error if there was a version mismatch.
if (versionMismatch) {
throw new Error(
`More than one node version used in 'action.yml' files: ${JSON.stringify(nodeVersions)}`,
);
}
// Write the node version to `.nvmrc`.
await writeFile(
join(__dirname, ".nvmrc"),
nodeVersion.substring("node".length) + "\n",
"utf-8",
);
});
},
};
/**
* Copy defaults.json to the output directory since other projects depend on it.
*
@@ -78,7 +143,7 @@ const UPLOAD_LIB_SRC = "./src/upload-lib";
*
* The virtual module additionally re-exports `upload-lib` under the `uploadLib` namespace so that
* external consumers can access it via the small `lib/upload-lib.js` stub emitted below.
*
*
* A tiny stub file is emitted for each Action entrypoint, and one for `upload-lib`. Each stub
* imports the shared bundle and calls/re-exports from the respective entry point.
*
@@ -208,7 +273,13 @@ const context = await esbuild.context({
outdir: OUT_DIR,
platform: "node",
external: ["./entry-points"],
plugins: [cleanPlugin, copyDefaultsPlugin, entryPointsPlugin, onEndPlugin],
plugins: [
cleanPlugin,
checkNodeVersionsPlugin,
copyDefaultsPlugin,
entryPointsPlugin,
onEndPlugin,
],
target: ["node20"],
define: {
__CODEQL_ACTION_VERSION__: JSON.stringify(pkg.version),
+10 -12
View File
@@ -31025,15 +31025,13 @@ var require_brace_expansion = __commonJS({
parts.push.apply(parts, p);
return parts;
}
function expandTop(str2, options) {
function expandTop(str2) {
if (!str2)
return [];
options = options || {};
var max = options.max == null ? Infinity : options.max;
if (str2.substr(0, 2) === "{}") {
str2 = "\\{\\}" + str2.substr(2);
}
return expand2(escapeBraces(str2), max, true).map(unescapeBraces);
return expand2(escapeBraces(str2), true).map(unescapeBraces);
}
function embrace(str2) {
return "{" + str2 + "}";
@@ -31047,7 +31045,7 @@ var require_brace_expansion = __commonJS({
function gte6(i, y) {
return i >= y;
}
function expand2(str2, max, isTop) {
function expand2(str2, isTop) {
var expansions = [];
var m = balanced("{", "}", str2);
if (!m || /\$$/.test(m.pre)) return [str2];
@@ -31058,7 +31056,7 @@ var require_brace_expansion = __commonJS({
if (!isSequence && !isOptions) {
if (m.post.match(/,(?!,).*\}/)) {
str2 = m.pre + "{" + m.body + escClose + m.post;
return expand2(str2, max, true);
return expand2(str2);
}
return [str2];
}
@@ -31068,9 +31066,9 @@ var require_brace_expansion = __commonJS({
} else {
n = parseCommaParts(m.body);
if (n.length === 1) {
n = expand2(n[0], max, false).map(embrace);
n = expand2(n[0], false).map(embrace);
if (n.length === 1) {
var post = m.post.length ? expand2(m.post, max, false) : [""];
var post = m.post.length ? expand2(m.post, false) : [""];
return post.map(function(p) {
return m.pre + n[0] + p;
});
@@ -31078,7 +31076,7 @@ var require_brace_expansion = __commonJS({
}
}
var pre = m.pre;
var post = m.post.length ? expand2(m.post, max, false) : [""];
var post = m.post.length ? expand2(m.post, false) : [""];
var N;
if (isSequence) {
var x = numeric(n[0]);
@@ -31116,11 +31114,11 @@ var require_brace_expansion = __commonJS({
}
} else {
N = concatMap(n, function(el) {
return expand2(el, max, false);
return expand2(el, false);
});
}
for (var j = 0; j < N.length; j++) {
for (var k = 0; k < post.length && expansions.length < max; k++) {
for (var k = 0; k < post.length; k++) {
var expansion = pre + N[j] + post[k];
if (!isTop || isSequence || expansion)
expansions.push(expansion);
@@ -102246,7 +102244,7 @@ var require_commonjs19 = __commonJS({
}
const pad = n.some(isPadded);
N = [];
for (let i = x; test(i, y) && N.length < max; i += incr) {
for (let i = x; test(i, y); i += incr) {
let c;
if (isAlphaSequence) {
c = String.fromCharCode(i);
+9 -9
View File
@@ -3795,9 +3795,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
"integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -5122,9 +5122,9 @@
}
},
"node_modules/eslint-plugin-import-x/node_modules/brace-expansion": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6078,9 +6078,9 @@
}
},
"node_modules/glob/node_modules/brace-expansion": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
+1 -1
View File
@@ -5,7 +5,7 @@ versions:
- default
steps:
- name: Set up Ruby
uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1.307.0
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration