fix(gha): bundle action with esbuild - #454
Conversation
Bumps [@aws-sdk/client-ssm](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-ssm) from 3.1084.0 to 3.1092.0. - [Release notes](https://github.com/aws/aws-sdk-js-v3/releases) - [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-ssm/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.1092.0/clients/client-ssm) --- updated-dependencies: - dependency-name: "@aws-sdk/client-ssm" dependency-version: 3.1092.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [typescript](https://github.com/microsoft/TypeScript) from 6.0.3 to 7.0.2. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/commits) --- updated-dependencies: - dependency-name: typescript dependency-version: 7.0.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
…s-sdk/client-ssm-3.1092.0
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ks/nodejs/aws-sdk/client-ssm-3.1092.0' into macalbert-fix-dependabot-pipelines
…pt-7.0.2' into macalbert-fix-dependabot-pipelines
TypeScript 7 removes the compiler API required by ncc and ts-node. Compile first, bundle with esbuild, and use tsx for scripts that run TypeScript directly. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
WalkthroughThe PR documents and implements an esbuild-based GitHub Action bundle, updates related ADR and changelog entries, and replaces ts-node-based TypeScript execution with tsx in packaging, E2E, and CDK workflows. ChangesGitHub Action and TypeScript tooling
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Checkov (3.3.8)src/iac/cdk.jsonTraceback (most recent call last): src/iac/package.jsonTraceback (most recent call last): Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/build-github-action.mjs`:
- Around line 1-14: Update the GitHub Actions workflow that invokes the
composite action to add an actions/setup-node step with node-version set to 22
before the node command runs github-action/dist/index.js. Keep the existing
esbuild target in the build script unchanged; the runtime version must be pinned
in the workflow execution path.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 0c93addb-bbd8-4c7e-99ed-34f85fe40d60
⛔ Files ignored due to path filters (7)
.github/copilot-instructions.mdis excluded by none and included by none.github/skills/common-security/SKILL.mdis excluded by none and included by noneCONTRIBUTING.mdis excluded by none and included by nonegithub-action/dist/index.jsis excluded by!**/dist/**,!github-action/dist/**and included by nonepackage.jsonis excluded by none and included by nonepnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yamland included by nonepnpm-workspace.yamlis excluded by none and included by none
📒 Files selected for processing (9)
docs/adr/0006-monorepo-structure.mddocs/adr/0010-github-action-bundler.mddocs/changelogs/gha.mde2e/cli.test.tsscripts/README.mdscripts/build-github-action.mjsscripts/pack-and-install.tssrc/iac/cdk.jsonsrc/iac/package.json
| import { build } from 'esbuild'; | ||
|
|
||
| await build({ | ||
| entryPoints: ['lib/envilder/apps/gha/entry/Index.js'], | ||
| bundle: true, | ||
| platform: 'node', | ||
| format: 'esm', | ||
| target: 'node22', | ||
| minify: true, | ||
| outfile: 'github-action/dist/index.js', | ||
| banner: { | ||
| js: "import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);", | ||
| }, | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
files="$(fd -a -t f . | rg '(^|/)(action\.ya?ml|package\.json)$')"
printf '%s\n' "$files"
printf '%s\n' "$files" | xargs -r rg -n '"type"\s*:|using:|main:'Repository: macalbert/envilder
Length of output: 1084
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '--- github-action/action.yml ---\n'
sed -n '1,80p' github-action/action.yml
printf '\n--- scripts/build-github-action.mjs ---\n'
sed -n '1,80p' scripts/build-github-action.mjs
printf '\n--- root package.json relevant fields ---\n'
python3 - <<'PY'
import json
from pathlib import Path
p=Path('package.json')
data=json.loads(p.read_text())
for key in ['name','version','type','engines','scripts','devDependencies','dependencies']:
if key in data:
print(f'{key}: {json.dumps(data[key], indent=2)}')
PY
printf '\n--- other action files ---\n'
fd -a -t f '^\.(github|devcontainer|scripts)/?|action\.(ya?ml|json)$' github-action .github .devcontainer . 2>/dev/null | sed -n '1,80p'Repository: macalbert/envilder
Length of output: 247
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- github-action/action.yml ---'
sed -n '1,80p' github-action/action.yml
printf '%s\n' ''
printf '%s\n' '--- scripts/build-github-action.mjs ---'
sed -n '1,80p' scripts/build-github-action.mjs
printf '%s\n' ''
printf '%s\n' '--- root package.json relevant fields ---'
python3 - <<'PY'
import json
from pathlib import Path
p=Path('package.json')
data=json.loads(p.read_text())
for key in ['name','version','type','engines','scripts','devDependencies','dependencies']:
if key in data:
print(f'{key}: {json.dumps(data[key], indent=2)}')
PY
printf '%s\n' ''
printf '%s\n' '--- action/package boundary files ---'
fd -a -t f '^\.(github|devcontainer|scripts)/?|action\.(ya?ml|json)$' . | rg '(^|/)github-action/|^\.github/|^\.devcontainer/|(^|/)package\.json$' || trueRepository: macalbert/envilder
Length of output: 4829
🌐 Web query:
GitHub Actions composite action step shell node runner image Node version GHA Node 22
💡 Result:
GitHub Actions composite actions do not have a dedicated runs: using: 'node22' runtime configuration. The 'runs: using' syntax is specifically for JavaScript actions (which execute code directly), whereas composite actions use 'runs: using: "composite"' and consist of a sequence of steps [1][2][3][4]. To use Node.js 22 within a composite action, you must explicitly set up the Node.js environment as a step within your action using the actions/setup-node action [4][5]. Example implementation: runs: using: "composite" steps: - name: Setup Node.js 22 uses: actions/setup-node@v6 with: node-version: '22' - name: Run script shell: bash run: node your-script.js Key considerations: 1. Shell Requirement: In composite actions, every 'run' step must explicitly define a 'shell' (e.g., 'shell: bash'), as there is no default shell provided [2][4]. 2. Node.js Environment: As of July 2026, Node.js 22 is a supported and common version on GitHub Actions runners, with many runners having transitioned to it as a default [6]. You can verify the availability and manage specific versions via actions/setup-node [7][8]. 3. JavaScript Actions vs. Composite: If you are creating a 'JavaScript action' (using 'runs: using: nodeXX'), you are limited to the specific Node versions supported by the runner's underlying action engine (often node20 or node24) [9][10]. Composite actions provide more flexibility because they execute steps in the runner's shell environment [2][4].
Citations:
- 1: https://github.com/github/docs/blob/main/content/actions/tutorials/create-actions/create-a-composite-action.md
- 2: https://github.com/actions/runner/blob/main/docs/adrs/0549-composite-run-steps.md
- 3: https://docs.github.com/actions/creating-actions/creating-a-composite-action
- 4: https://nerdleveltech.com/github-actions-reusable-workflow-vs-composite-action
- 5: https://stackoverflow.com/questions/78982275/accessing-node-modules-in-composite-action-on-github
- 6: [All OS] Default Node.js version will be changed from 20 to 22 and Node.js 20 will be removed from runner images actions/runner-images#14029
- 7: https://github.com/actions/setup-node
- 8: https://github.com/actions/setup-node/tree/refs/heads/main
- 9: Support node22 in runs.using for JavaScript actions actions/runner#3600
- 10: Support node22 in runs.using for JavaScript actions actions/runner#3600
🌐 Web query:
GitHub Actions composite run steps node runtime default runner node20 node command commonjs esm
💡 Result:
In GitHub Actions, composite actions and JavaScript actions are distinct types with different configurations [1]. Composite Actions: Composite actions use using: composite in their action.yml file [2][3]. They do not have a built-in Node.js runtime environment; instead, they define a sequence of steps that run using specified shells (e.g., bash, powershell) [2][4][3]. To use Node.js within a composite action, you must explicitly include a step that installs it, typically using actions/setup-node [5][6][7]. Because composite actions rely on the shell environment, they are not directly affected by the runs.using node version configuration, but rather by the Node.js version installed in the runner's path [5][3]. JavaScript Actions: JavaScript actions use runs.using (e.g., node20, node24) to specify the runtime [1][8]. As of July 2026, Node24 is the standard runtime, with Node20 undergoing deprecation [8]. JavaScript actions execute an entry JavaScript file defined in the main field [1]. CommonJS vs. ESM: GitHub Actions runners support both CommonJS (CJS) and ECMAScript Modules (ESM) [7][9]. - For JavaScript actions, your build tool (like ncc) can be configured to produce either format, though you must ensure the main file is compatible with the specified runtime version [9]. - For composite actions, because you are executing scripts or commands (e.g., node index.js) via a shell, you can use ESM by either setting "type": "module" in your package.json or by using the .mjs extension [7][9]. If using actions/github-script within a composite action, you can load ESM modules dynamically using the await import() syntax [7][10][9]. Key Technical Notes: - The shell attribute is required for every run step in a composite action [2][4]. - Node20 reached its end-of-life in April 2026, and runners began defaulting to Node24 in June 2026 [8]. To continue using older runtimes temporarily, users may need to set environment variables like ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true [8][11]. - steps are not valid for node20 or node24 runtimes; they are specific to using: composite [1].
Citations:
- 1: RunsUsing.NODE_20 with steps generates invalid action.yml — steps is not valid for node20 runner projen/projen#4579
- 2: https://github.com/actions/runner/blob/main/docs/adrs/0549-composite-run-steps.md
- 3: https://docs.github.com/en/actions/tutorials/create-actions/create-a-composite-action
- 4: https://github.com/actions/runner/blob/main/docs/adrs/1144-composite-actions.md
- 5: https://github.com/actions/setup-node/tree/refs/heads/main
- 6: https://github.com/marketplace/actions/setup-node-js-environment
- 7: Feature: Support for ECMAScript Modules (ESM) in GitHub Actions - "actions/github-scripts" actions/github-script#457
- 8: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
- 9: feat!: migrate action to ESM, bump @actions/* to v9/v3 (closes #958, #959) nearform-actions/github-action-notify-release#975
- 10: Support importing ESM files actions/github-script#168
- 11: Composite Actions using Node 20 don't work with CentOS 7 actions/runner#2906
🌐 Web query:
GitHub Actions node command shell Bash ESM files import module .js CommonJS detection
💡 Result:
When executing Node.js files within a GitHub Actions Bash shell, Node.js uses standard detection rules to determine whether a file should be treated as an ECMAScript Module (ESM) or CommonJS (CJS) [1][2]. Detection Rules Node.js identifies the module format based on the following hierarchy [1][3]: 1. Explicit Markers: - File Extension: Files ending in.mjs are always treated as ESM; files ending in.cjs are always treated as CJS [1][2][3]. - Package Configuration: If the nearest parent package.json contains a "type" field set to "module", all.js files in that directory and its subdirectories are treated as ESM. If the field is set to "commonjs" or is missing,.js files are treated as CJS [1][2][3]. 2. Ambiguous Detection: - For.js files without an explicit "type" setting in a package.json, Node.js attempts to parse the code as CommonJS first [2]. If the parser encounters ESM-specific syntax (e.g., import, export, import.meta) that is invalid in CommonJS, Node.js will treat the file as an ESM module [1][2][4]. GitHub Actions Considerations - Running Scripts: You can execute Node.js scripts in your workflow using the run keyword (e.g., run: node script.js) [5][6]. Ensure your environment is configured by using the actions/setup-node action to specify the desired Node.js version [7][5]. - github-script Action: The official actions/github-script action historically relied on CommonJS, which limited direct ESM imports [8][9]. For modern workflows requiring ESM, it is recommended to either: - Use dynamic import within your script: await import('${{ github.workspace }}/your-script.js') [10][9]. - Bundle your code (e.g., using vercel/ncc) to produce a single, compatible CJS file [8]. - Use standard node commands in a Bash step rather than the actions/github-script wrapper if you require full native ESM support for your project files [6]. Note that require can only load CommonJS modules [9]. If you are working in an ESM-defined context, you must use import statements [1][9].
Citations:
- 1: https://nodejs.org/api/esm.html
- 2: https://nodejs.org/api/packages.html
- 3: https://www.typescriptlang.org/docs/handbook/modules/theory.html
- 4: nodejs/node@e375063e01
- 5: https://docs.github.com/en/actions/tutorials/build-and-test-code/nodejs
- 6: https://docs.github.com/actions/writing-workflows/choosing-what-your-workflow-does/adding-scripts-to-your-workflow
- 7: https://github.com/actions/setup-node?tab=readme-ov-file
- 8: Feature: Support for ECMAScript Modules (ESM) in GitHub Actions - "actions/github-scripts" actions/github-script#457
- 9: Support importing ESM files actions/github-script#168
- 10: https://github.com/actions/github-script?tab=readme-ov-file
Pin the GitHub Actions Node runtime explicitly.
The composite action only calls node "${{ github.action_path }}/dist/index.js"; the runner image’s Node version defaults to what the workflow matrix specifies, not the bundled target: 'node22'. Add an actions/setup-node step with node-version: '22' before running this action so the ESM bundle gets a compatible runtime.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/build-github-action.mjs` around lines 1 - 14, Update the GitHub
Actions workflow that invokes the composite action to add an actions/setup-node
step with node-version set to 22 before the node command runs
github-action/dist/index.js. Keep the existing esbuild target in the build
script unchanged; the runtime version must be pinned in the workflow execution
path.
There was a problem hiding this comment.
Pull request overview
This PR updates the GitHub Action build pipeline to support TypeScript 7 by replacing @vercel/ncc/ts-node with an esbuild bundling step plus tsx for TypeScript script execution, while keeping the action distributed as a single committed bundle.
Changes:
- Replace GHA bundling from
ncc buildtotscoutput + esbuild bundling (scripts/build-github-action.mjs,package.json). - Replace
ts-nodeexecution withtsxacross CDK, local install tooling, and E2E setup (src/iac/*,scripts/*,e2e/cli.test.ts). - Update docs/ADRs/changelogs to reflect the new bundler/tooling and commit the updated lockfile/catalog changes.
Reviewed changes
Copilot reviewed 14 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/iac/package.json | Swap IaC dev script runner from ts-node to tsx. |
| src/iac/cdk.json | Run CDK app via pnpm exec tsx instead of npx ts-node. |
| scripts/README.md | Update contributor docs to reference esbuild + tsx. |
| scripts/pack-and-install.ts | Update script shebang to tsx runner. |
| scripts/build-github-action.mjs | New esbuild bundling script for github-action/dist/index.js. |
| pnpm-workspace.yaml | Catalog updates: TypeScript 7 + tsx, remove ts-node. |
| pnpm-lock.yaml | Lockfile updates for TypeScript 7 / tsx / esbuild and removals. |
| package.json | Wire build:gha to esbuild script; add esbuild; swap local:install to tsx. |
| e2e/cli.test.ts | Use pnpm exec tsx for pack-and-install during E2E setup. |
| docs/changelogs/gha.md | Add Unreleased changelog entry documenting bundler/tooling changes. |
| docs/adr/0010-github-action-bundler.md | New ADR documenting the esbuild bundler decision. |
| docs/adr/0006-monorepo-structure.md | Update monorepo ADR to state GHA uses esbuild bundling. |
| CONTRIBUTING.md | Update contributor commands list for esbuild-based build:gha. |
| .github/skills/common-security/SKILL.md | Update security guidance to reflect esbuild bundling. |
| .github/copilot-instructions.md | Update Copilot instructions to reflect esbuild bundling. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Comments suppressed due to low confidence (1)
docs/adr/0010-github-action-bundler.md:43
- The reconsideration trigger mentions a Node.js 22 runtime requirement, but the action currently runs using the runner-provided
nodewithout enforcing a specific version. This should be phrased in terms of the actual runtime contract (either enforce Node 22 in the action, or describe the supported Node baseline).
Reconsider if esbuild no longer bundles a GitHub Action dependency correctly,
or if GitHub Action runtime requirements change from Node.js 22.
| platform: 'node', | ||
| format: 'esm', | ||
| target: 'node22', | ||
| minify: true, | ||
| outfile: 'github-action/dist/index.js', | ||
| banner: { | ||
| js: "import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);", | ||
| }, |
| The `build:gha` command compiles the TypeScript source first, preserving | ||
| decorator metadata required by Inversify. The esbuild configuration emits an | ||
| ES module targeted at Node.js 22 and provides `createRequire` for dependencies | ||
| that dynamically load Node.js built-ins. |
Summary
Updates TypeScript to 7.0.2 and replaces the incompatible GitHub Action build tooling.
The action remains a single committed bundle, while TypeScript continues to type-check sources and emit decorator metadata before esbuild packages the compiled output.
Changes
@vercel/nccwith esbuild for the GitHub Action bundle.ts-nodewithtsxin direct TypeScript execution paths.github-action/dist/index.jsand update the dependency lockfile.Testing
pnpm build:gha,pnpm verify:gha, and the GitHub Action bundle smoke checkpnpm lint, the website build, the CDK build, and focused GHA and website testspnpm test-- Docker is unavailable locally for Testcontainers acceptance testsRelated
#422
Summary by CodeRabbit
Changed
Documentation