putitoutthere 0.2.14 → 0.2.15

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.
package/CHANGELOG.md CHANGED
@@ -34,6 +34,8 @@ are prefixed `**BREAKING**` and link to the matching section in
34
34
 
35
35
  - **Bundled-CLI / napi npm consumers' `npm run build` step now sees `TARGET` and `BUILD` env vars on every matrix row.** The reusable workflow's `_matrix.yml` and `release.yml` previously ran the npm build step with no env block, so consumers' build scripts that read `process.env.TARGET` to know which triple to cross-compile saw `undefined` and either crashed or silently no-oped. Every per-platform matrix row then uploaded an empty `build/<triple>/` directory and `actions/upload-artifact@v7` flagged `No files were found with the provided path: ...`. The internal `e2e-fixture-job.yml` already passed `TARGET` / `BUILD` correctly — meaning the fixture suite passed but a real consumer's first publish still failed; an integration-tier divergence rather than a behavior bug per se. Both the build matrix step and the publish-job rebuild step in `release.yml` now set the env block. `_matrix.yml` exposes `TARGET=${{ matrix.target }}` / `BUILD=${{ matrix.build }}` per row; `release.yml`'s rebuild loop sets `TARGET=main BUILD=` per iteration (the publish-time rebuild only fires for the main package's row, since per-platform sub-packages stage from `artifacts/` via the engine's npm-platform handler). The README's [Bundled-CLI npm family](./README.md#bundled-cli-npm-family) recipe gained the consumer-side build-script contract that was previously missing — TARGET/BUILD vocabulary and a minimal `scripts/build.cjs` covering the simple single-workspace case. Hit in the wild on `thekevinscott/darkfactory`'s first release; tracked at #287. See [MIGRATIONS.md](./MIGRATIONS.md#npm-build-step-target-build-env-vars).
36
36
 
37
+ - **First-publish bundled-cli / napi npm builds no longer fail on lockfile drift.** Consumers of the bundled-cli / napi shape declare `optionalDependencies` for `<name>-<triple>@<version>` platform packages that this pipeline publishes. On the very first publish those entries 404 on the registry; pnpm 10 silently drops 404'd optionals from the lockfile when it is regenerated locally; a subsequent CI run with `pnpm install --frozen-lockfile` (or `npm ci`) refuses because lockfile and `package.json` disagree. Both install steps in the reusable workflow — `_matrix.yml`'s build-matrix install and `release.yml`'s publish-job rebuild step (added in #256) — now self-heal: a failed strict install falls back to its non-strict form (`pnpm install --no-frozen-lockfile` / `npm install`) with a `::warning::` line in the run log naming the recovery. No consumer-side change required; lockfiles can stay committed and `optionalDependencies` can stay declared. Hit in the wild on `thekevinscott/darkfactory`'s first release (#integration-2026-05-bundled-cli). The README's [Bundled-CLI npm family](./README.md#bundled-cli-npm-family) recipe grew a `[!NOTE]` callout documenting the chicken-and-egg and the workflow's transparent recovery. See [MIGRATIONS.md](./MIGRATIONS.md#first-publish-bundled-cli-lockfile-self-heal).
38
+
37
39
  - **pypi/maturin `[package.bundle_cli]` now actually ships the bundled binary inside published wheels.** The recipe was advertised as shipped in v0.2.0 (#217) — config parsing accepted `[package.bundle_cli]`, the planner attached it to per-target wheel rows, and `MIGRATIONS.md` named the two scaffolded build steps consumers should expect. None of those steps existed in `.github/workflows/_matrix.yml`. Consumers who declared the block (us, in `thekevinscott/dirsql`) shipped wheels missing the binary; `pip install <pkg> && <pkg> ...` failed at runtime with `FileNotFoundError`. The reusable workflow's build job now, for every per-target wheel row that carries `matrix.bundle_cli`: (1) `rustup target add ${{ matrix.target }}`, (2) `cargo build --release --target ${{ matrix.target }} --bin ${{ matrix.bundle_cli.bin }}` against `crate_path`, (3) copies the resulting binary into `${{ matrix.path }}/${{ matrix.bundle_cli.stage_to }}/` so maturin's `[tool.maturin].include` glob picks it up as wheel data, and (4) runs a permanent post-build wheel-content guard that opens the produced `.whl` and refuses to upload-artifact if `<stage_to>/<bin>` is missing. The guard is independent of staging — it catches any future regression where the cross-compile silently routes the binary to the wrong path. Consumers do not need to change their existing `[package.bundle_cli]` config or their `[tool.maturin].include` glob; the recipe just starts working. The cross-compile assumes the binary is buildable with a vanilla `cargo build --release --bin <bin>` (no `--features`, no env, no special flags); crates that gate the CLI behind a Cargo feature are not yet supported. The `.exe` suffix on Windows is handled. See [README → Recipes → Rust CLI inside a PyPI wheel](./README.md#rust-cli-inside-a-pypi-wheel) and [MIGRATIONS.md](./MIGRATIONS.md#bundle_cli-now-actually-stages-the-binary). #282.
38
40
 
39
41
  - **`putitoutthere.toml` validation now names common typos in the failure message.** A consumer integration shipped a config with `version` at the file root, `[[packages]]` (plural), `registry =` instead of `kind =`, and `files =` instead of `globs =`. The raw zod errors (`Invalid input: expected object, received undefined; ...; Unrecognized keys: "version", "packages"`) were opaque enough that the engine source had to be re-read to recover. A pre-pass in `parseConfig` now detects each of those four mistakes by name and emits a hint that pairs the wrong shape with the right one, e.g. `top-level table is \`[[packages]]\` (plural) but should be \`[[package]]\` (singular)`. README's [Drop in `putitoutthere.toml`](./README.md#2-drop-in-putitoutthere-toml) section grew a four-row "wrong → right" table covering the same four traps so the docs and the engine name them the same way; a new `[!IMPORTANT]` callout in [Drop in `.github/workflows/release.yml`](./README.md#1-drop-in-githubworkflowsreleaseyml) warns consumers off `push: branches: [main]` triggers on lane CI workflows (which fire duplicate runs against the merge commit and contend for runners with `release.yml`); `1b.` was promoted from "Optional" to "Recommended" since `build.yml` is the cheapest place to catch a malformed config before merge. See [MIGRATIONS.md](./MIGRATIONS.md#friendly-config-error-hints).
package/MIGRATIONS.md CHANGED
@@ -72,6 +72,55 @@ artifacts: each `<pkg>-npm-<triple>` upload contains
72
72
  `build/<triple>/<bin-name>`. The release run's `Upload artifact`
73
73
  step no longer logs `No files were found with the provided path`
74
74
  for any npm row.
75
+ ### First-publish bundled-cli lockfile self-heal
76
+
77
+ **Summary.** The reusable workflow's npm install steps —
78
+ `_matrix.yml`'s build-matrix install and `release.yml`'s
79
+ publish-job rebuild (#256) — both ran strict installs (`npm ci`
80
+ or `pnpm install --frozen-lockfile`) and refused on any drift
81
+ between the committed lockfile and `package.json`. For consumers
82
+ of the bundled-cli / napi shape, drift is the *expected* state on
83
+ the first publish: `package.json` declares
84
+ `optionalDependencies` for `<name>-<triple>@<version>` platform
85
+ packages that this pipeline produces, those packages don't exist
86
+ on the registry yet, pnpm 10 silently drops 404'd optionals from
87
+ the lockfile when it is regenerated locally, and the next CI run
88
+ sees lockfile and `package.json` disagree. Hit in the wild on
89
+ `thekevinscott/darkfactory`'s first release.
90
+
91
+ Both install steps now fall back from the strict form to its
92
+ non-strict counterpart on failure (`pnpm install --no-frozen-lockfile`
93
+ / `npm install`) and emit a `::warning::` line in the run log
94
+ naming the recovery. The README's
95
+ [Bundled-CLI npm family](./README.md#bundled-cli-npm-family)
96
+ recipe grew a `[!NOTE]` callout documenting the chicken-and-egg
97
+ and the workflow's transparent recovery.
98
+
99
+ **Required changes.** None. Consumers who were working around
100
+ the failure by gitignoring the lockfile, by suppressing
101
+ `optionalDependencies` from `package.json`, or by pinning to
102
+ older lockfile-tolerant pnpm versions can revert those
103
+ workarounds; the workflow now handles the bootstrap state on
104
+ its own.
105
+
106
+ **Deprecations removed.** None.
107
+
108
+ **Behavior changes without code changes.** Strict installs that
109
+ previously failed red on lockfile drift now succeed via the
110
+ non-strict fallback path. The build artifact is unchanged
111
+ (installs the deps `package.json` declares); only the strictness
112
+ of *how* it gets there relaxes. Healthy lockfiles still take
113
+ the strict path with no observable difference. The new
114
+ `::warning::` lines are visible in the run log on the GitHub
115
+ Actions UI but do not fail the run.
116
+
117
+ **Verification.** A bundled-cli / napi consumer's first-publish
118
+ release run completes the build matrix without manual lockfile
119
+ fiddling. The run log contains a single
120
+ `::warning::pnpm-lock.yaml drift ...` line per affected install
121
+ step (one in the build matrix, one in the publish-job rebuild)
122
+ when the strict install fails; healthy installs see no
123
+ warning.
75
124
 
76
125
  ### `[package.bundle_cli]` now actually stages the binary
77
126
 
package/README.md CHANGED
@@ -546,6 +546,25 @@ Each per-platform sub-package needs its own npm trusted-publisher
546
546
  registration (a policy on `my-cli` does not cover
547
547
  `my-cli-x86_64-unknown-linux-gnu`).
548
548
 
549
+ > [!NOTE]
550
+ > **First-publish lockfile chicken-and-egg.** Some scaffolding will
551
+ > populate `optionalDependencies` in your top-level `package.json`
552
+ > with entries for `my-cli-<triple>@<version>` ahead of the first
553
+ > publish. Those packages don't exist on the registry yet — the
554
+ > engine publishes them as part of *this* run — so a locally-generated
555
+ > `package-lock.json` / `pnpm-lock.yaml` either fails to install or
556
+ > silently drops the entries (pnpm 10 does the silent drop). On the
557
+ > next CI run, the strict installs (`npm ci`,
558
+ > `pnpm install --frozen-lockfile`) refuse because lockfile and
559
+ > `package.json` disagree.
560
+ >
561
+ > The reusable workflow handles this transparently: every strict
562
+ > install in the build matrix and the publish-job rebuild step
563
+ > falls back to its non-strict form on failure (with a
564
+ > `::warning::` line in the run log so the recovery is visible).
565
+ > No consumer-side change is required; you can keep the lockfile
566
+ > committed and the `optionalDependencies` declared.
567
+
549
568
  ### Multi-mode npm family
550
569
 
551
570
  For a package that is both a napi-rs Node addon (a `.node` library) **and**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "putitoutthere",
3
- "version": "0.2.14",
3
+ "version": "0.2.15",
4
4
  "description": "Polyglot release orchestrator for crates.io, PyPI, and npm",
5
5
  "license": "MIT",
6
6
  "repository": {