@effected/github-actions 0.20.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@ import { digestFileHex } from "./internal/digest.js";
4
4
  import { isWindowsRunner } from "./internal/runner.js";
5
5
  import { typeAt } from "./internal/fsProbe.js";
6
6
  import { PNPM_EXE_PREFIX, detectMusl, isNodeScript, pnpmExeTarget, strongestSri } from "./internal/pnpmExe.js";
7
+ import { cmdShim, gitBashShim, posixShim } from "./internal/shim.js";
7
8
  import { ToolInstaller } from "./ToolInstaller.js";
8
9
  import { Context, Effect, FileSystem, Layer, Option, Path, Schema } from "effect";
9
10
  import { ChildProcess, ChildProcessSpawner } from "effect/process";
@@ -100,8 +101,10 @@ var AmbientPackageManager = class extends Schema.Class("AmbientPackageManager")(
100
101
  * `binDir` is the directory a consumer hands to `ActionOutputs.addPath` to
101
102
  * make the manager invokable by name in subsequent workflow steps. For the
102
103
  * npm-registry managers it is the entry's `.bin` directory of executable
103
- * shims this installer writes (`#!/bin/sh` exec wrappers, or `.cmd` wrappers
104
- * on Windows); for bun it is the entry directory itself, because the cached
104
+ * shims this installer writes (`#!/bin/sh` exec wrappers; on Windows a
105
+ * `.cmd` wrapper plus an extensionless Git Bash sibling per bin, because
106
+ * Git Bash does not apply `PATHEXT` and never resolves the `.cmd` by the
107
+ * bare name); for bun it is the entry directory itself, because the cached
105
108
  * `bun` binary is directly executable and a shim would add nothing but a
106
109
  * fork. `bins` still maps each published bin name to the underlying entry —
107
110
  * a Node script to run with `node` for npm, yarn and pnpm 11 and earlier; an
@@ -150,17 +153,6 @@ var CachedPackageManager = class extends Schema.Class("CachedPackageManager")({
150
153
  const InstalledPackageManager = Schema.Union([AmbientPackageManager, CachedPackageManager]);
151
154
  /** The shim directory name inside a cached npm-registry-manager entry. */
152
155
  const SHIM_DIR = ".bin";
153
- /**
154
- * The POSIX shim body: an `exec` wrapper so the shim's process *becomes* the
155
- * target, and `"$@"` so arguments survive quoting intact. A Node script
156
- * (`.js`/`.mjs`/`.cjs`) runs under `node`; anything else — pnpm 12's native
157
- * binary, its `#!/bin/sh` alias scripts — is exec'd directly, because handing
158
- * a shell script or a Mach-O to node is exactly the "Invalid or unexpected
159
- * token" failure this rule exists to prevent.
160
- */
161
- const posixShim = (target) => isNodeScript(target) ? `#!/bin/sh\nexec node "${target}" "$@"\n` : `#!/bin/sh\nexec "${target}" "$@"\n`;
162
- /** The Windows shim body, CRLF-terminated as cmd expects; same node-vs-direct rule. */
163
- const cmdShim = (target) => isNodeScript(target) ? `@echo off\r\nnode "${target}" %*\r\n` : `@echo off\r\n"${target}" %*\r\n`;
164
156
  /** The bin names pnpm's wrapper publishes, every one of which becomes the native binary on Windows. */
165
157
  const PNPM_NATIVE_BIN_NAMES = [
166
158
  "pnpm",
@@ -229,8 +221,16 @@ const make = Effect.gen(function* () {
229
221
  const windows = yield* isWindowsRunner(env);
230
222
  const musl = detectMusl();
231
223
  const bunBinaryName = windows ? "bun.exe" : "bun";
232
- const shimFileName = (name) => windows ? `${name}.cmd` : name;
233
- const shimBody = windows ? cmdShim : posixShim;
224
+ /**
225
+ * The shim files one bin gets, as file-name/body pairs: the extensionless
226
+ * `#!/bin/sh` exec wrapper on POSIX; on Windows the `.cmd` wrapper for
227
+ * `cmd.exe` and PowerShell PLUS the extensionless Git Bash sibling — Git
228
+ * Bash does not apply `PATHEXT`, so a bare name never resolves to the
229
+ * `.cmd`. Both flavours derive from the same target, so every distinction
230
+ * the `.cmd` applies (pnpm 12's native binary vs its aliases, node-vs-
231
+ * direct dispatch) the sibling applies identically.
232
+ */
233
+ const shimFiles = (name, target) => windows ? [[`${name}.cmd`, cmdShim(target)], [name, gitBashShim(target)]] : [[name, posixShim(target)]];
234
234
  const errorFor = (pin) => (fields) => new PackageManagerInstallerError({
235
235
  name: pin.name,
236
236
  version: pin.version.toString(),
@@ -363,8 +363,9 @@ const make = Effect.gen(function* () {
363
363
  })), Effect.orElseSucceed(() => false));
364
364
  const rootBins = (bins, directory) => Object.fromEntries(Object.entries(bins).map(([name, relative]) => [name, path.join(directory, relative)]));
365
365
  /**
366
- * Write one executable shim per bin into `<into>/.bin`, each invoking
367
- * `node <finalDirectory>/<relative>`.
366
+ * Write the shim files of every bin into `<into>/.bin`, each naming
367
+ * `<finalDirectory>/<relative>` — the POSIX exec wrapper, or on Windows
368
+ * BOTH the `.cmd` wrapper and its extensionless Git Bash sibling.
368
369
  *
369
370
  * @remarks
370
371
  * `into` and `finalDirectory` are DIFFERENT on the install path on purpose:
@@ -372,8 +373,9 @@ const make = Effect.gen(function* () {
372
373
  * ToolInstaller renames into place (the cache only ever contains complete
373
374
  * entries), while their contents must name the *final* cache path the entry
374
375
  * is about to land at. On the cache-hit regeneration path the two coincide.
375
- * When `skipExisting` is set, a shim already present is left untouched — the
376
- * regeneration path must not rewrite a shared cache entry another writer owns.
376
+ * When `skipExisting` is set, a shim file already present is left untouched,
377
+ * file by file — the regeneration path must not rewrite what another writer
378
+ * owns, but it does add a sibling a previous version never wrote.
377
379
  */
378
380
  const writeShims = (pin, into, finalDirectory, bins, options) => Effect.gen(function* () {
379
381
  const shimDir = path.join(into, SHIM_DIR);
@@ -383,12 +385,12 @@ const make = Effect.gen(function* () {
383
385
  cause
384
386
  });
385
387
  yield* fs.makeDirectory(shimDir, { recursive: true }).pipe(Effect.mapError(cacheError(shimDir)));
386
- for (const [name, relative] of Object.entries(bins)) {
387
- const shim = path.join(shimDir, shimFileName(name));
388
+ for (const [name, relative] of Object.entries(bins)) for (const [file, body] of shimFiles(name, path.join(finalDirectory, relative))) {
389
+ const shim = path.join(shimDir, file);
388
390
  if (options.skipExisting) {
389
391
  if ((yield* typeAt(fs, shim)) === "File") continue;
390
392
  }
391
- yield* fs.writeFileString(shim, shimBody(path.join(finalDirectory, relative))).pipe(Effect.mapError(cacheError(shim)));
393
+ yield* fs.writeFileString(shim, body).pipe(Effect.mapError(cacheError(shim)));
392
394
  if (!windows) yield* fs.chmod(shim, 493).pipe(Effect.mapError(cacheError(shim)));
393
395
  }
394
396
  });
package/index.d.ts CHANGED
@@ -4838,8 +4838,10 @@ declare const CachedPackageManager_base: Schema.Class<CachedPackageManager, Sche
4838
4838
  * `binDir` is the directory a consumer hands to `ActionOutputs.addPath` to
4839
4839
  * make the manager invokable by name in subsequent workflow steps. For the
4840
4840
  * npm-registry managers it is the entry's `.bin` directory of executable
4841
- * shims this installer writes (`#!/bin/sh` exec wrappers, or `.cmd` wrappers
4842
- * on Windows); for bun it is the entry directory itself, because the cached
4841
+ * shims this installer writes (`#!/bin/sh` exec wrappers; on Windows a
4842
+ * `.cmd` wrapper plus an extensionless Git Bash sibling per bin, because
4843
+ * Git Bash does not apply `PATHEXT` and never resolves the `.cmd` by the
4844
+ * bare name); for bun it is the entry directory itself, because the cached
4843
4845
  * `bun` binary is directly executable and a shim would add nothing but a
4844
4846
  * fork. `bins` still maps each published bin name to the underlying entry —
4845
4847
  * a Node script to run with `node` for npm, yarn and pnpm 11 and earlier; an
@@ -0,0 +1,30 @@
1
+ import { isNodeScript } from "./pnpmExe.js";
2
+
3
+ //#region src/internal/shim.ts
4
+ /**
5
+ * The POSIX shim body: an `exec` wrapper so the shim's process *becomes* the
6
+ * target, and `"$@"` so arguments survive quoting intact. A Node script
7
+ * (`.js`/`.mjs`/`.cjs`) runs under `node`; anything else — pnpm 12's native
8
+ * binary, its `#!/bin/sh` alias scripts — is exec'd directly, because handing
9
+ * a shell script or a Mach-O to node is exactly the "Invalid or unexpected
10
+ * token" failure this rule exists to prevent.
11
+ */
12
+ const posixShim = (target) => isNodeScript(target) ? `#!/bin/sh\nexec node "${target}" "$@"\n` : `#!/bin/sh\nexec "${target}" "$@"\n`;
13
+ /** The Windows shim body, CRLF-terminated as cmd expects; same node-vs-direct rule. */
14
+ const cmdShim = (target) => isNodeScript(target) ? `@echo off\r\nnode "${target}" %*\r\n` : `@echo off\r\n"${target}" %*\r\n`;
15
+ /**
16
+ * The Git Bash shim body written beside every Windows `.cmd` shim: the POSIX
17
+ * wrapper's own shape — same shebang, same `exec`, same `"$@"`, same
18
+ * node-vs-direct rule — with the target rendered in forward slashes. Inside
19
+ * double quotes `/bin/sh` consumes a backslash only before `$`, a backtick,
20
+ * `"`, another `\` or a newline, and a trailing backslash would escape the
21
+ * closing quote — enough to mangle a verbatim Windows path (a doubled UNC
22
+ * lead, a segment before `$`), while Git Bash resolves `C:/…` paths as-is.
23
+ * Git Bash does not apply `PATHEXT`, so a bare name never finds the `.cmd`
24
+ * twin on its own; npm's global installs write the same extensionless sibling
25
+ * for the same reason.
26
+ */
27
+ const gitBashShim = (target) => posixShim(target.replaceAll("\\", "/"));
28
+
29
+ //#endregion
30
+ export { cmdShim, gitBashShim, posixShim };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effected/github-actions",
3
- "version": "0.20.0",
3
+ "version": "0.20.1",
4
4
  "private": false,
5
5
  "description": "The GitHub Actions runtime: env, inputs, outputs, state, logging, cache, artifacts, blob storage, OIDC and the token bridge.",
6
6
  "keywords": [
@@ -39,12 +39,12 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@azure/storage-blob": "^12.33.0",
42
- "@effected/github": "^0.15.0",
43
- "@effected/github-commands": "^0.1.0",
42
+ "@effected/github": "^0.15.1",
43
+ "@effected/github-commands": "^0.2.0",
44
44
  "@effected/glob": "^0.10.0",
45
- "@effected/markdown": "^0.15.0",
45
+ "@effected/markdown": "^0.15.1",
46
46
  "@effected/npm": "^0.20.0",
47
- "@effected/sbom": "^0.10.0",
47
+ "@effected/sbom": "^0.10.1",
48
48
  "@effected/semver": "^0.11.0",
49
49
  "@effected/templates": "^0.10.0",
50
50
  "@effected/walker": "^0.15.0"