Skip to content

test: make the prepare-release fixture Windows-safe - #89

Merged
btspoony merged 1 commit into
omdsh-dev:mainfrom
PerryLink:fix/prepare-release-windows
Sep 21, 2026
Merged

btspoony merged 1 commit into
omdsh-dev:mainfrom
PerryLink:fix/prepare-release-windows

Conversation

@PerryLink

Copy link
Copy Markdown
Contributor

What

pnpm run test is red on Windows at 72fee95: 17 of the 20 cases in tests/prepare-release.test.ts
fail
, i.e. 17 of 380 tests overall. Everything else is green (tsc --noEmit clean, all 17 other test
files pass). The failures are all the same shape — the spawned script's git call dies, so the assertion
lands on the process status instead of on the behaviour under test:

FAIL  tests/prepare-release.test.ts > scripts/prepare-release.mjs > auto patch bump: 0.1.0 -> 0.1.1, …
AssertionError: expected 1 to be +0 // Object.is equality
 ❯ tests/prepare-release.test.ts:119:20
    119|     expect(status).toBe(0)

FAIL  tests/prepare-release.test.ts > … > existing tag is rejected: exit 1 + stderr message, …
AssertionError: expected 'node:internal/errors:986\r\n  const e…' to contain 'already exists'
 ❯ tests/prepare-release.test.ts:146:20

and the underlying crash, visible in the captured stderr:

Error: Command failed: git log --oneline --first-parent HEAD
    at resolveReleaseNotes (…/scripts/prepare-release.mjs:159:17)
  status: 128,
  stderr: null

Why

The fixture controls git with an extensionless #!/bin/sh shim written to <fixture>/bin/git
(tests/prepare-release.test.ts:88) and put on PATH. Two Windows-only defects stop that from working:

  1. PATH is built with a hardcoded : (:100). path.delimiter is ; on win32, so the shim
    directory is not added as a PATH entry at all — it is glued onto the front of the first real entry:

    first real PATH entry the child sees:
    "C:\…\repro-prepare-release-9tRAYN\bin:D:\Projects\dsh\toolchain\node24"
    
  2. Windows cannot execute that shim even when it is on PATH. Node's PATH search needs a PATHEXT
    extension, so spawnSync('git', …) skips the extensionless file and runs the real git.exe:

    spawnSync("git --version") status : 0
      stdout: "git version 2.54.0.windows.1"
      => shim executed? NO (real git ran)
    

    prepare-release.mjs uses execFileSync('git', …) (:24), which never goes through a shell, so a
    .cmd shim does not help either — spawnSync('git.cmd', …) returns EINVAL. Inside the fixture,
    which is deliberately not a repository, the real git then exits 128.

Three cases currently pass on Windows only because version validation rejects the input before any git
call is reached; the other 17 fail, and one of them passes the expected 1 half of its assertion for the
wrong reason.

Change

  • Build PATH with path.delimiter instead of ':' (:100). On POSIX this produces a byte-identical
    string, so Linux CI is unaffected.
  • Wrap the describe in describe.skipIf(process.platform === 'win32') with a comment explaining why the
    fixture cannot run there, instead of reporting 17 failures that say nothing about the script.

Why the whole file and not 17 cases

All 20 cases call the same runScript() fixture, so there is no sub-set that avoids the broken shim:
the 3 that currently pass on Windows do so because version validation rejects the input before
prepare-release.mjs reaches git, not because they use a different seam. A per-case skip would draw a
line that does not exist in the code.

No coverage is lost in CI either: all three workflows in this repository run on ubuntu-latest only, and
process.platform is linux there, so skipIf is a no-op and those 3 cases keep running. The skip only
stops a local Windows run from reporting 17 failures that describe the fixture rather than the script.

Restoring real Windows coverage needs a non-PATH seam — for example letting scripts/prepare-release.mjs
read the git command from an environment variable, with the fixture pointing it at a Node script. That
touches shipped code, so I did not assume it here.

Validation (Windows 11, Node v24.21.0, pnpm 12.5.1)

before:  Test Files  1 failed | 17 passed (18)      Tests  17 failed | 363 passed (380)
after:   Test Files  17 passed | 1 skipped (18)     Tests  360 passed | 20 skipped (380)
npx tsc -p tsconfig.spec.json --noEmit   ->  exit 0

The two Windows mechanisms above were reproduced standalone with a throwaway fixture that mirrors
makeFixture/runScript exactly.

@btspoony
btspoony merged commit fced467 into omdsh-dev:main Sep 21, 2026
1 check passed
@btspoony btspoony mentioned this pull request Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants