Compare commits

..

1 Commits

Author SHA1 Message Date
Henry Mercer e6fd49ace1 Minify JS bundle on release branches 2026-05-20 17:16:57 +01:00
5 changed files with 74 additions and 103 deletions
+6 -8
View File
@@ -56,9 +56,8 @@ def run_command(*args):
# Rebuilds the action and commits any changes.
def rebuild_action():
# For backports, the only source-level change vs the source branch is the new version number,
# so we just need to refresh the version embedded in `lib/`.
run_command('npm', 'ci')
# We only expect changes to the JavaScript output, rebuilding e.g. the PR checks is unnecessary.
run_command('npm', 'run', 'build')
run_git('add', '--all')
@@ -450,12 +449,11 @@ def main():
run_git('add', 'CHANGELOG.md')
run_git('commit', '-m', f'Update changelog for v{version}')
if not is_primary_release:
if len(conflicted_files) == 0:
print('Rebuilding the Action.')
rebuild_action()
else:
print(f'Skipping automatic rebuild because the merge produced conflicts in {conflicted_files}.')
if len(conflicted_files) > 0:
print(f'Skipping automatic rebuild because the merge produced conflicts in {conflicted_files}.')
else:
print('Rebuilding the Action.')
rebuild_action()
run_git('push', ORIGIN, new_branch_name)
+12 -21
View File
@@ -105,10 +105,10 @@ jobs:
run: npx tsx --test
check-node-version:
if: github.triggering_actor != 'dependabot[bot]' && startsWith(github.head_ref, 'backport-')
name: Check Action Node versions for Backport
if: github.triggering_actor != 'dependabot[bot]'
name: Check Action Node versions
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 45
env:
BASE_REF: ${{ github.base_ref }}
@@ -116,40 +116,31 @@ jobs:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1
- uses: actions/checkout@v6
- id: head-version
name: Determine Node version for HEAD
name: Verify all Actions use the same Node version
run: |
if [[ ! -f ".nvmrc" ]]; then
echo "::error::Cannot find .nvmrc in the HEAD commit."
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."
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: |
if [[ ! -f ".nvmrc" ]]; then
echo "::error::Cannot find .nvmrc in the base commit."
exit 1
fi
BASE_VERSION=$(cat .nvmrc)
BASE_VERSION=$(find . -name "action.yml" -exec yq -e '.runs.using' {} \; | grep node | sort | uniq)
echo "HEAD_VERSION: ${HEAD_VERSION}"
echo "BASE_VERSION: ${BASE_VERSION}"
if [[ "$BASE_VERSION" != "$HEAD_VERSION" ]]; then
-1
View File
@@ -1 +0,0 @@
24
+1
View File
@@ -6,6 +6,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
- _Breaking change_: Bump the minimum required CodeQL bundle version to 2.19.4. [#3894](https://github.com/github/codeql-action/pull/3894)
- Add support for SHA-256 Git object IDs. [#3893](https://github.com/github/codeql-action/pull/3893)
- The JavaScript bundle shipped on release branches is now minified, reducing the size of the repository by around 20%. Bundles on `main` remain unminified to avoid merge conflicts between PRs. [#3920](https://github.com/github/codeql-action/pull/3920)
## 4.35.5 - 15 May 2026
+55 -73
View File
@@ -1,10 +1,10 @@
import { execFileSync } from "node:child_process";
import { copyFile, readFile, rm, writeFile } from "node:fs/promises";
import { basename, dirname, join } from "node:path";
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" };
@@ -14,6 +14,51 @@ const __dirname = dirname(__filename);
const SRC_DIR = join(__dirname, "src");
const OUT_DIR = join(__dirname, "lib");
/**
* Decide whether to minify the bundle.
*
* We deliberately do not minify by default to avoid making every PR's regenerated bundle conflict
* with every other PR. Instead, we minify only when building for a release branch so consumers of
* `github/codeql-action/<action>@vN` get the smaller bundle while day-to-day development on `main`
* stays low-churn.
*
* @returns {boolean}
*/
function shouldMinify() {
const override = process.env.CODEQL_ACTION_MINIFY;
if (override === "true") return true;
if (override === "false") return false;
// In `pull_request` and `merge_group` contexts, we can just look at the base ref.
if (process.env.GITHUB_BASE_REF) {
return process.env.GITHUB_BASE_REF.startsWith("releases/v");
}
// When running locally or in contexts without a base ref (e.g. `push`, `workflow_dispatch`),
// check whether we're running as part of the release automation by looking at the local branch
// name. Mergebacks target `main` and should not be minified, while update and backport branches
// target release branches and should be minified.
const localBranch = getLocalBranchName();
if (localBranch?.startsWith("mergeback/")) return false;
if (localBranch && /^(update|backport)-v\d/.test(localBranch)) return true;
// If we don't seem to be running as part of the release automation, then only minify if we're on
// a release branch.
const refName = process.env.GITHUB_REF_NAME || localBranch;
return !!refName && refName.startsWith("releases/v");
}
function getLocalBranchName() {
try {
return execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
encoding: "utf-8",
stdio: ["pipe", "pipe", "ignore"],
}).trim();
} catch {
return undefined;
}
}
/**
* Clean the output directory before building.
*
@@ -28,70 +73,6 @@ 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.
*
@@ -143,7 +124,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.
*
@@ -266,20 +247,21 @@ const entryPointsPlugin = {
},
};
const minify = shouldMinify();
if (minify) {
// eslint-disable-next-line no-console
console.log("Minification enabled for this build.");
}
const context = await esbuild.context({
entryPoints: [{ in: SHARED_ENTRYPOINT, out: SHARED_ENTRYPOINT }],
bundle: true,
format: "cjs",
minify,
outdir: OUT_DIR,
platform: "node",
external: ["./entry-points"],
plugins: [
cleanPlugin,
checkNodeVersionsPlugin,
copyDefaultsPlugin,
entryPointsPlugin,
onEndPlugin,
],
plugins: [cleanPlugin, copyDefaultsPlugin, entryPointsPlugin, onEndPlugin],
target: ["node20"],
define: {
__CODEQL_ACTION_VERSION__: JSON.stringify(pkg.version),