putitoutthere 0.2.12 → 0.2.14
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 +2 -0
- package/MIGRATIONS.md +52 -0
- package/README.md +59 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -32,6 +32,8 @@ are prefixed `**BREAKING**` and link to the matching section in
|
|
|
32
32
|
|
|
33
33
|
### Fixed
|
|
34
34
|
|
|
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
|
+
|
|
35
37
|
- **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.
|
|
36
38
|
|
|
37
39
|
- **`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
|
@@ -21,6 +21,58 @@ Each section covers five things, in order:
|
|
|
21
21
|
|
|
22
22
|
## Unreleased
|
|
23
23
|
|
|
24
|
+
### npm build step: TARGET / BUILD env vars
|
|
25
|
+
|
|
26
|
+
**Summary.** The reusable workflow's `_matrix.yml` and `release.yml`
|
|
27
|
+
now set `TARGET=${{ matrix.target }}` and `BUILD=${{ matrix.build }}`
|
|
28
|
+
on the `matrix.kind == 'npm'` build step (and `TARGET=main BUILD=`
|
|
29
|
+
on `release.yml`'s publish-job rebuild loop, which only ever runs
|
|
30
|
+
for the main package's row). Bundled-CLI / napi consumers' build
|
|
31
|
+
scripts read these env vars to know which triple to cross-compile
|
|
32
|
+
and which build mode is active; without them, every per-platform
|
|
33
|
+
matrix row produced an empty `build/<triple>/` directory and
|
|
34
|
+
`actions/upload-artifact@v7` reported
|
|
35
|
+
`No files were found with the provided path: ...`. The internal
|
|
36
|
+
`e2e-fixture-job.yml` already passed `TARGET` / `BUILD` for the
|
|
37
|
+
`js-bundled-cli` fixture, so the fixture suite was green while the
|
|
38
|
+
shape it advertised was broken for real consumers. Tracked at #287;
|
|
39
|
+
hit in the wild on `thekevinscott/darkfactory`'s first release.
|
|
40
|
+
|
|
41
|
+
The README's [Bundled-CLI npm family](./README.md#bundled-cli-npm-family)
|
|
42
|
+
recipe gained the consumer-side build-script contract that was
|
|
43
|
+
previously missing: a documented `scripts/build.cjs` template
|
|
44
|
+
that reads `TARGET`, runs `rustup target add` + `cargo build`
|
|
45
|
+
+ stage-into-`build/<triple>/`, and no-ops on
|
|
46
|
+
`TARGET=main`. Without that section, consumers had to read the
|
|
47
|
+
`js-bundled-cli` test fixture or experiment to discover the
|
|
48
|
+
contract.
|
|
49
|
+
|
|
50
|
+
**Required changes.** None for consumers whose existing build
|
|
51
|
+
script either ignored `TARGET` or used a different env var name —
|
|
52
|
+
those scripts now get the `TARGET` / `BUILD` exports too but
|
|
53
|
+
nothing forces them to read. To start using the contract, mirror
|
|
54
|
+
the README's `scripts/build.cjs` shape and reference it from
|
|
55
|
+
`package.json`'s `scripts.build` field. Existing fixtures and
|
|
56
|
+
the engine's contract are unchanged.
|
|
57
|
+
|
|
58
|
+
**Deprecations removed.** None.
|
|
59
|
+
|
|
60
|
+
**Behavior changes without code changes.** The npm build step
|
|
61
|
+
now runs with `TARGET` and `BUILD` set in its environment.
|
|
62
|
+
Build scripts that previously saw `undefined` and either crashed
|
|
63
|
+
or silently no-oped will now see a defined string. Vanilla npm
|
|
64
|
+
consumers (no `build = "bundled-cli" | "napi"`) see
|
|
65
|
+
`TARGET=main BUILD=` (or `BUILD=undefined` on rows that don't
|
|
66
|
+
declare a build mode); their build scripts that don't read either
|
|
67
|
+
var are unaffected.
|
|
68
|
+
|
|
69
|
+
**Verification.** A bundled-cli consumer following the README
|
|
70
|
+
recipe sees their per-platform matrix rows produce non-empty
|
|
71
|
+
artifacts: each `<pkg>-npm-<triple>` upload contains
|
|
72
|
+
`build/<triple>/<bin-name>`. The release run's `Upload artifact`
|
|
73
|
+
step no longer logs `No files were found with the provided path`
|
|
74
|
+
for any npm row.
|
|
75
|
+
|
|
24
76
|
### `[package.bundle_cli]` now actually stages the binary
|
|
25
77
|
|
|
26
78
|
**Summary.** Wheels published from a maturin pypi package that
|
package/README.md
CHANGED
|
@@ -483,6 +483,65 @@ const result = spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
|
483
483
|
process.exit(result.status ?? 1);
|
|
484
484
|
```
|
|
485
485
|
|
|
486
|
+
You also author a `build` script in `package.json` that does the
|
|
487
|
+
cross-compile. The reusable workflow runs the build matrix once
|
|
488
|
+
per `(target × main)` row, sets `TARGET=<triple>` /
|
|
489
|
+
`BUILD=bundled-cli` on the build step, and expects the script to
|
|
490
|
+
stage the compiled binary under `build/<triple>/<bin-name>` (with
|
|
491
|
+
`.exe` suffix on Windows). For every per-target row the engine
|
|
492
|
+
then packages `build/<triple>/` as the platform sub-package's
|
|
493
|
+
artifact; the `main` row is a no-op for the build script (the
|
|
494
|
+
launcher above is committed source). A minimal `package.json`:
|
|
495
|
+
|
|
496
|
+
```json
|
|
497
|
+
{
|
|
498
|
+
"name": "my-cli",
|
|
499
|
+
"scripts": {
|
|
500
|
+
"build": "node scripts/build.cjs"
|
|
501
|
+
},
|
|
502
|
+
"bin": { "my-cli": "bin/my-cli.js" }
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
`scripts/build.cjs`:
|
|
507
|
+
|
|
508
|
+
```js
|
|
509
|
+
const { execFileSync, spawnSync } = require('node:child_process');
|
|
510
|
+
const { mkdirSync, copyFileSync } = require('node:fs');
|
|
511
|
+
const { join } = require('node:path');
|
|
512
|
+
const pkg = require('../package.json');
|
|
513
|
+
|
|
514
|
+
const target = process.env.TARGET;
|
|
515
|
+
// `target === 'main'` is the top-level row: nothing to compile,
|
|
516
|
+
// the launcher is committed source.
|
|
517
|
+
if (!target || target === 'main' || target === 'noarch') process.exit(0);
|
|
518
|
+
|
|
519
|
+
const binName = Object.keys(pkg.bin || {})[0] || pkg.name;
|
|
520
|
+
const ext = target.includes('windows') ? '.exe' : '';
|
|
521
|
+
|
|
522
|
+
execFileSync('rustup', ['target', 'add', target], { stdio: 'inherit' });
|
|
523
|
+
execFileSync(
|
|
524
|
+
'cargo',
|
|
525
|
+
['build', '--release', '--target', target, '--bin', binName],
|
|
526
|
+
{ cwd: '../../crates/my-cli', stdio: 'inherit' },
|
|
527
|
+
);
|
|
528
|
+
|
|
529
|
+
const dir = join('build', target);
|
|
530
|
+
mkdirSync(dir, { recursive: true });
|
|
531
|
+
copyFileSync(
|
|
532
|
+
join('../../crates/my-cli/target', target, 'release', binName + ext),
|
|
533
|
+
join(dir, binName + ext),
|
|
534
|
+
);
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
The build is consumer-owned because `cargo build` flags
|
|
538
|
+
(`--features`, env vars, alternate manifests, Zig-cc cross
|
|
539
|
+
toolchains) vary too much across crates to bake into the
|
|
540
|
+
workflow. For the simple "single workspace member, default
|
|
541
|
+
features" case the script above is the entire integration; tweak
|
|
542
|
+
it as your crate demands. `TARGET` and `BUILD` are the only env
|
|
543
|
+
vars the workflow guarantees.
|
|
544
|
+
|
|
486
545
|
Each per-platform sub-package needs its own npm trusted-publisher
|
|
487
546
|
registration (a policy on `my-cli` does not cover
|
|
488
547
|
`my-cli-x86_64-unknown-linux-gnu`).
|