putitoutthere 0.2.21 → 0.2.22

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
@@ -12,6 +12,7 @@ are prefixed `**BREAKING**` and link to the matching section in
12
12
 
13
13
  ### Added
14
14
 
15
+ - **Reusable workflow `.github/workflows/check.yml` (`workflow_call`).** PR-time config-sanity gate. Wires into a consumer's `pull_request:` CI in one line: `uses: thekevinscott/putitoutthere/.github/workflows/check.yml@v0`. Drives the same `putitoutthere check` engine entry the publish path already uses (no parallel diagnostic code path — the operative rule from the [refreshed non-goal #8](./notes/design-commitments.md#non-goals)), so the consumer-observable check list is whatever `check` reports: `putitoutthere.toml` parse + schema + common-mistakes detector, unique package names, `depends_on` cycle / dangling-ref detection, `[[package]].path` directory exists, `globs` match a tracked file, `tag_format` collisions, npm `repository` field, crates `description` / `license`, pypi `pyproject.toml` + `bundle_cli` binary declaration, npm target triple mapping. Findings are aggregated into one round-trip rather than failing on the first. A few seconds per PR, no per-target build, no `setup-python` / `setup-rust`. Permissions: `contents: read` only — the workflow holds no publishable artifact and cannot mint a registry token. Complementary to `build.yml`: `check.yml` is the cheap config-sanity gate, `build.yml` is the heavier per-target build gate; wire both. See [README → check](./README.md#1b-recommended-drop-in-githubworkflowscheckyml) and [MIGRATIONS.md](./MIGRATIONS.md#new-checkyml-reusable-workflow-for-pr-time-config-sanity). #317 (workflow shell) + #319 (check list, shipped via #321).
15
16
  - **Internal-only: first-publish e2e coverage via Verdaccio.** A new `js-vanilla-first-publish` fixture and matrix row in `.github/workflows/e2e-fixture.yml` exercises the empty-packument path (`npm view <name>` returns 404 before publish) that consumer-reported bugs cluster around. `e2e-fixture-job.yml`'s publish job now runs an in-job Verdaccio service container (`verdaccio/verdaccio:5`); per-fixture job isolation gives per-scenario wipe implicitly. The new fixture carries a `-placeholder` suffix on its package name that the workflow rewrites to `-${run_id}-${run_attempt}` at materialize time, so each scenario publishes against a packument that's truly empty. The post-publish tarball-verification step is now registry-agnostic — `REGISTRY_URL` env steers `npm view` at either real npm or Verdaccio with adapted retry/backoff. **No consumer surface changes**: `PIOT_NPM_REGISTRY` is an internal e2e seam read by `src/handlers/npm.ts` and `src/handlers/npm-platform.ts`; setting it bypasses provenance and the bootstrap-hint path. Steady-state e2e fixtures and consumer `release.yml` flows are untouched. See [MIGRATIONS.md](./MIGRATIONS.md#internal-verdaccio-e2e-coverage). #304 (parent #293).
16
17
  - **`[package.bundle_cli]` accepts `features` and `no_default_features` for crates that gate the CLI behind a Cargo feature.** The lib-with-optional-CLI pattern — `[[bin]] required-features = ["cli"]` so `cargo add <name>` doesn't drag the CLI's deps onto library consumers — is the standard shape for crates that fit `bundle_cli`'s use case (ruff, uv, pydantic-core, biome, swc, dirsql). v0.2.0's wiring shipped `cargo build --release --target $TARGET --bin $BIN` with no `--features` path, which made the recipe inert for exactly the consumers it targets. The reusable workflow's cargo build step now appends `--features <comma-list>` when the schema's new `features: list[string]` is non-empty and `--no-default-features` when the new `no_default_features: bool` is true. Defaults are `[]` and `false`, so existing `[package.bundle_cli]` blocks keep building byte-identically. Empty-string entries inside `features` are rejected at config load. The "crates that gate the CLI behind a Cargo feature are not currently supported" caveat in the v0.2.0 MIGRATIONS note has been corrected. See [README → Recipes → Rust CLI inside a PyPI wheel](./README.md#rust-cli-inside-a-pypi-wheel) and [MIGRATIONS.md](./MIGRATIONS.md#bundle_cli-features-and-no_default_features). #300.
17
18
  - **Reusable workflow accepts a caller-provided `NPM_TOKEN` via `secrets:`.** OIDC trusted publishers remain the default and recommended path, but Trusted Publishing on npm binds to an *already-published* package — so the first publish of a brand-new npm package has no OIDC path available, and consumers were forced into a manual 6+ package `0.0.0-bootstrap` stub bootstrap (documented nowhere, only discoverable by reading commit history of dirsql or by hitting the failure). The `workflow_call` surface now declares an optional `NPM_TOKEN` secret; when set AND the planned matrix contains an npm row, the secret is exported to `$GITHUB_ENV` as `NODE_AUTH_TOKEN` and the npm CLI prefers the long-lived token over the OIDC path. Callers without a token keep the OIDC path unchanged. For bundled-cli / napi families the same secret authenticates publishes of all per-platform sub-packages on first publish; once those exist, each one needs its own Trusted Publisher registration (the bypass is a one-time bootstrap, not a permanent path). Mirrors the #283 crates fallback in shape. Hit in the wild on the maintainer's own dirsql project (first version of `@dirsql/cli-linux-x64-gnu` on npm is `0.0.0-bootstrap`, 2026-04-30; real `0.2.8` lands the next day) and on `darkfactory`'s first publish. See [README → Trusted publishers → npm](./README.md#npm) and [MIGRATIONS.md](./MIGRATIONS.md#npm-token-fallback). #302.
package/MIGRATIONS.md CHANGED
@@ -21,6 +21,58 @@ Each section covers five things, in order:
21
21
 
22
22
  ## Unreleased
23
23
 
24
+ ### New `check.yml` reusable workflow for PR-time config sanity
25
+
26
+ **Summary.** `putitoutthere` now ships a third reusable workflow,
27
+ `.github/workflows/check.yml`, that drives the engine's `check`
28
+ subcommand at PR time. The subcommand aggregates every pre-merge
29
+ check (`putitoutthere.toml` parse + schema, common-mistakes
30
+ detector, unique-name guard, `depends_on` cycle / dangling-ref
31
+ detection, `[[package]].path` existence, `globs` matching a
32
+ tracked file, `tag_format` collisions, npm `repository` field,
33
+ crates `description` / `license`, pypi `pyproject.toml` +
34
+ `bundle_cli` binary declaration, npm target triple mapping)
35
+ and reports findings in one round-trip. Where `release.yml` is
36
+ the release-time phase and `build.yml` is the heavier per-target
37
+ build gate, `check.yml` is the cheap config-sanity gate — a few
38
+ seconds per PR, no `setup-python` / `setup-rust`, no per-target
39
+ compile. Shipped per the "no release surprises" goal added in
40
+ #316: anything checkable from the consumer's repo state alone
41
+ surfaces at PR time, not at release time. Issue #317 (workflow
42
+ shell) + issue #319 (check list, shipped via #321).
43
+
44
+ **Required changes.** Additive. Existing consumers do nothing.
45
+ Recommended: add a one-line PR-CI workflow.
46
+
47
+ ```yaml
48
+ # .github/workflows/check.yml ← new file in your repo, optional
49
+ name: putitoutthere check
50
+
51
+ on:
52
+ pull_request: {}
53
+
54
+ jobs:
55
+ putitoutthere-check:
56
+ uses: thekevinscott/putitoutthere/.github/workflows/check.yml@v0
57
+ ```
58
+
59
+ The new workflow accepts no `with:` inputs, no `secrets:`, no
60
+ `permissions:` requirements beyond the default `contents: read` it
61
+ sets internally. The integration line is the entire surface.
62
+
63
+ **Deprecations removed.** None.
64
+
65
+ **Behavior changes without code changes.** None. Existing release
66
+ runs are unaffected — the new workflow is opt-in PR-time CI; the
67
+ release path is unchanged.
68
+
69
+ **Verification.** Open a PR that introduces a typo in
70
+ `putitoutthere.toml` (e.g. `[[packages]]` instead of `[[package]]`).
71
+ Without `check.yml` wired, the failure surfaces at release time
72
+ in a red `plan` step. With `check.yml` wired, the PR fails red at
73
+ review time with the same diagnosable error message, before the
74
+ merge.
75
+
24
76
  ### Internal Verdaccio e2e coverage
25
77
 
26
78
  **Summary.** Internal change with no consumer-observable impact. Adds a
package/README.md CHANGED
@@ -81,13 +81,46 @@ Optional inputs — `with:` block at the call site:
81
81
  | `node_version` | `24` | You need a specific Node version for `kind = "npm"` build steps. |
82
82
  | `python_version` | `3.12` | You need a specific Python version for `kind = "pypi"` build steps. |
83
83
 
84
- ### 1b. Recommended: drop in `.github/workflows/build-check.yml`
84
+ ### 1b. Recommended: drop in `.github/workflows/check.yml`
85
+
86
+ Run every pre-merge config check the engine knows about on every
87
+ PR. The fastest gate against a malformed `putitoutthere.toml`, a
88
+ duplicate package name, a `depends_on` cycle, a missing
89
+ `[[package]].path` directory, globs that match no tracked files,
90
+ a `tag_format` collision, a missing `repository` field on an
91
+ `npm` package, missing `description` / `license` on a `crates`
92
+ package, or a `bundle_cli` binary the crate doesn't declare — a
93
+ couple of seconds per PR, no per-target build, no `setup-python`
94
+ / `setup-rust`. Findings are aggregated into one report so you
95
+ fix everything in one push instead of chasing errors across re-
96
+ runs.
97
+
98
+ ```yaml
99
+ name: putitoutthere check
100
+
101
+ on:
102
+ pull_request: {}
103
+
104
+ jobs:
105
+ putitoutthere-check:
106
+ uses: thekevinscott/putitoutthere/.github/workflows/check.yml@v0
107
+ ```
108
+
109
+ Green here = "a release run from this commit would not surface
110
+ configuration-level surprises." `check.yml` does not build anything,
111
+ does not run `setup-node` against your sources, and never holds a
112
+ publishable artifact in memory; its `permissions:` block is
113
+ `contents: read` only.
114
+
115
+ ### 1c. Recommended: drop in `.github/workflows/build-check.yml`
85
116
 
86
117
  Run the same plan + build matrix on every PR, with the publish step
87
- structurally absent. This is the cheapest way to catch a malformed
88
- `putitoutthere.toml`, missing `repository` field, or per-target build
89
- break **before** the merge — by the time the release workflow runs,
90
- the merge has already happened and the only recourse is a fix-up PR.
118
+ structurally absent. Slower than `check.yml` (it actually compiles
119
+ every per-target wheel and binary) but catches the bugs `check.yml`
120
+ can't observe — a per-target build break, a missing `repository`
121
+ field that the build process surfaces, an `aarch64-apple-darwin`
122
+ linker incompatibility. Wire both: `check.yml` catches the cheap
123
+ mistakes in seconds, `build.yml` catches the rest before the merge.
91
124
 
92
125
  ```yaml
93
126
  name: Build check
package/action.yml CHANGED
@@ -4,7 +4,7 @@ author: 'Kevin Scott'
4
4
 
5
5
  inputs:
6
6
  command:
7
- description: 'Which CLI subcommand to run. Canonical values are `plan`, `publish`, and `write-version`.'
7
+ description: 'Which CLI subcommand to run. Canonical values are `plan`, `publish`, `write-version`, and `check`.'
8
8
  required: false
9
9
  default: 'plan'
10
10
  working_directory:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "putitoutthere",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
4
4
  "description": "Polyglot release orchestrator for crates.io, PyPI, and npm",
5
5
  "license": "MIT",
6
6
  "repository": {