featmigrate action to native ESM and upgrade @actions/* to ESM majors#2
Closed
featmigrate action to native ESM and upgrade @actions/* to ESM majors#2
Conversation
Migrate the action from CommonJS to native ESM so that it can consume the ESM-only majors of the `@actions/*` toolkit packages (and any future ESM-only dependencies) without a transpile-to-CJS step. Tooling changes: - Set `"type": "module"` and emit ESM throughout. - Replace `@vercel/ncc` (which cannot emit ESM) with Rollup (`@rollup/plugin-typescript`, `-node-resolve`, `-commonjs`, `-json`, `-terser`). Output is still `lib/main/index.js` so `action.yml` is unchanged. - Drop `ts-node`/`tsx` in favour of Node 24's native TypeScript type-stripping (`.ts` files execute directly under `node`). Mocha invokes tests without any TypeScript loader. - Replace `nyc` + `@istanbuljs/nyc-config-typescript` with `c8` for coverage, which needs no source instrumentation under ESM. `.nycrc.json` is retained as the config file (c8 reads it natively for nyc compatibility). - Switch relative imports throughout src/, test/, and misc/ to use `.ts` extensions and set `allowImportingTsExtensions` + `rewriteRelativeImportExtensions` in `tsconfig.json` so both Node and Rollup resolve them directly. - Update `misc/generate-docs.ts` to ESM (JSON import attribute, `import.meta.url` in place of `__dirname`). Source-code adjustments to keep sinon stubbing working under ESM: - Modules that expose runtime values used from other modules now `export default` a plain object alongside their named exports, and call sites use `import foo from './foo.ts'; foo.bar()`. ES module named-export bindings are read-only and cannot be rebound by sinon, so stubbing has to operate on a shared mutable object. - `@actions/*` packages are imported via default (`import core from '@actions/core'`) rather than as a namespace (`import * as core`). The default import resolves to the underlying CJS `module.exports` (mutable and stub-friendly), whereas a namespace import is a frozen snapshot that doesn't reflect sinon mutations. - `node:fs` / `node:fs/promises` are imported as defaults for the same reason. Docs: - Update `.github/copilot-instructions.md` to describe the new toolchain (Rollup, Node 24 native TS, c8) and document the ESM stubbing patterns. BREAKING CHANGE: The action is now an ESM module and targets Node 24. Consumers pinning the action via commit SHA will need to re-pin; consumers using `@v3` or later will continue to work unchanged. Local development now requires Node 24+ (previously Node 20+). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bump the `@actions/*` toolkit to the latest majors, all of which are now published as native ESM (see `actions/toolkit` release notes for each package): - `@actions/core`: `^1.11.1` → `^3.0.0` - `@actions/exec`: `^1.1.1` → `^3.0.0` - `@actions/glob`: `^0.5.0` → `^0.6.1` - `@actions/http-client`: `^2.2.3` → `^4.0.0` - `@actions/io`: `^1.1.3` → `^3.0.2` - `@actions/tool-cache`: `^2.0.2` → `^4.0.0` Because the upgraded packages are true ESM (rather than ESM-wrapped CJS), their named exports are now non-configurable and cannot be stubbed directly via `sinon.stub(ns)`. Add `src/actions.ts`, which re-exports each `@actions/*` package as a plain mutable object (typed back to the original module type). Both source code and tests now import from `src/actions.ts`, giving sinon a single shared object to stub while preserving the full upstream API surface. Update `.github/copilot-instructions.md` to describe the new wrapper module and refresh the guidance that was previously written for the CJS shape of the toolkit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Migrate the action to native ESM on Node 24 so it can consume the ESM-only majors of the
@actions/*toolkit (and any future ESM-only dependencies) without a transpile-to-CJS step. This supersedes Dependabot PR tediousjs#206, which cannot be merged against the current CJS build.Changes
Two atomic commits:
1.
feat!: rewrite as an ESM moduleTooling:
"type": "module"; emit ESM throughout.@vercel/ncc→ Rollup (@rollup/plugin-typescript,-node-resolve,-commonjs,-json,-terser). Output is stilllib/main/index.jssoaction.ymlis unchanged.ts-node/tsx→ Node 24 native TypeScript type-stripping..tsfiles execute directly undernode; mocha runs with no TS loader.nyc+@istanbuljs/nyc-config-typescript→ c8..nycrc.jsonis retained as the config file (c8 reads it natively)..tsextensions throughout;tsconfig.jsonsetsallowImportingTsExtensions+rewriteRelativeImportExtensions.misc/generate-docs.tsESM-ified (JSON import attribute,import.meta.url).Source adjustments to keep sinon stubbing working: modules that expose runtime values now
export defaulta plain object alongside their named exports; call-sites useimport foo from './foo.ts'; foo.bar(). This is required because ES-module named-export bindings are read-only and cannot be rebound by sinon.2.
feat!: upgrade @actions/* toolkit to v3/v4 ESM majorsBumps matching Dependabot tediousjs#206:
@actions/core^1.11.1^3.0.0@actions/exec^1.1.1^3.0.0@actions/glob^0.5.0^0.6.1@actions/http-client^2.2.3^4.0.0@actions/io^1.1.3^3.0.2@actions/tool-cache^2.0.2^4.0.0Because these are now true ESM (rather than ESM-wrapped CJS), their named exports are non-configurable and cannot be stubbed directly. A new
src/actions.tswrapper re-exports each@actions/*package as a plain mutable object (typed back to the original module type). Both source and tests import from this wrapper so sinon has a single shared object to stub.Verification
npm run build— clean build via Rollup.npm test— 82 passing, 0 failing.npm run test:coverage— 99.48% statements / 98.81% branches / 100% functions / 100% lines.npm run lint— clean.BREAKING CHANGE
The action is now an ESM module and targets Node 24. Consumers using
@v3or later will continue to work unchanged at the action-invocation level, but this warrants a major version bump (hencefeat!). Local development now requires Node 24+ (previously Node 20+).Closes tediousjs#206.