Skip to content

archive-on-merge.js (CommonJS) breaks when the consumer repo sets "type": "module" #124

Description

@vaibhavkumar-deriv

Summary

.github/actions/archive_on_merge/archive-on-merge.js is authored as CommonJS (require("child_process"), require("fs"), module.exports, require.main === module). It ships with no package.json of its own inside .github/actions/archive_on_merge/, and the reusable workflow (archive-on-merge.yml) checks it out via sparse-checkout into the consumer repo's own workspace, then runs it with plain node.

Node decides whether a .js file is CommonJS or ESM by walking up the directory tree from that file's location, looking for the nearest package.json and reading its "type" field. Since nothing sits between the checked-out script and the consumer repo's root, that walk finds the consumer's own root package.json — not anything belonging to shared-actions.

If the consumer repo's package.json contains "type": "module" (increasingly common — ESM-first Node projects, mcp/tooling packages, etc.), Node misreads the checked-out CommonJS script as an ES module, and it fails immediately:

ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and
'<consumer-repo>/package.json' contains "type": "module".

This is not a consumer-repo misconfiguration — declaring "type": "module" is completely standard, and the consumer repo has no reason to expect it will affect a third-party script sparse-checked-out into a subdirectory of its own workspace.

Why this doesn't show up today

It only manifests in a consumer repo whose root package.json sets "type": "module". A consumer whose package.json omits "type" (defaulting to CommonJS) — or has no root package.json at all — never triggers it, because the walk-up resolution lands on a CommonJS-compatible context by coincidence, not because anything in this workflow accounted for it.

That means the current safety of any given consumer is incidental to that repo's own module convention, not a property of this workflow. The same consumer would start failing the moment it adopts "type": "module" — a routine, increasingly common migration — with no change on this workflow's side.

Reproduction

  1. A repo with a root package.json containing "type": "module" adopts the caller pattern from this repo's README (uses: deriv-com/shared-actions/.github/workflows/archive-on-merge.yml@master).
  2. Merge any PR into that repo's base branch.
  3. The Detect + archive completed changes step fails with the ReferenceError above, regardless of whether there is actually an OpenSpec change to archive — the crash happens before main() runs at all.

Suggested fix

Either of these removes the dependency on the consumer's module-type ambient resolution entirely:

  • Rename archive-on-merge.jsarchive-on-merge.cjs, and update the run: line in archive-on-merge.yml to match. The .cjs extension is always treated as CommonJS by Node regardless of any ancestor package.json — simplest fix, no logic changes.
  • Or add a package.json (with no "type" field, or explicit "type": "commonjs") inside .github/actions/archive_on_merge/, so Node's walk-up stops there instead of continuing into the consumer's tree.

The .cjs rename is the smaller, more explicit change and doesn't rely on Node's directory-walk semantics being understood correctly by future maintainers.

Impact if unaddressed

Any consumer repo that is or becomes "type": "module" gets a hard failure on this workflow's core step, every time it runs, with no OpenSpec-side workaround available from the caller side — the reusable workflow's inputs: (base_branch, node_version, openspec_version, action_ref) offer no way to override module resolution or insert a step between the checkout and the run: line.

Happy to open a PR with the .cjs rename if that's the preferred fix — flagging first since I don't have write access to this repo.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions