Add curated beta pre-release channel (npm/PyPI/GitHub)#118
Conversation
Machinery + docs only — no Cargo.toml bump, so merging publishes nothing. Tagging vX.Y.Z-beta.N publishes to three opt-in channels (npm dist-tag beta, PyPI --pre, GitHub prerelease) without touching stable installs. - scripts/npm/publish.sh: isolates the dist-tag decision, cross-the-streams safety guards, idempotency, dry-run, and RESOLVE_ONLY. Fixes the dead idempotency check that queried the unscoped corgea-cli (always 404) instead of @corgea/cli. - npm-publish.yml: dry_run dispatch input; publish via the script. - release-binaries.yml: prerelease flag on uploads; finalize-release job sets the prerelease disclaimer + auto release notes once (no 6-way race). - release.yml: version-guard fails a release if the tag != Cargo.toml version. - test.yml: version-bump-check fails a PR whose Cargo.toml version still equals the latest released tag. - CHANGELOG.md (Keep a Changelog), RELEASING.md, README beta section, AGENTS.md pointer. - bin/corgea.js: fix reinstall hint to @corgea/cli@latest.
…n idempotency Follow-up to the beta-channel PR, prompted by finding that @corgea/cli@1.9.0 never published to npm (the one real npm-publish run failed with an E404 token-scope error, buried in a downstream workflow_run). - publish.sh: after publishing, re-read the public registry and fail unless the version is live under the expected dist-tag (catches publishes that exit 0 but aren't actually visible). DRY_RUN now bypasses the idempotency early-exit so a dry-run always exercises the real publish path instead of short-circuiting. - release.yml / release-binaries.yml: reject non-v tags. A non-v tag (e.g. the stray 1.8.8) ships to PyPI + GitHub but is skipped by npm-publish (v*-only), drifting the channels apart. - RELEASING.md: document the post-publish gate, the v* guards, and an npm-token/E404 troubleshooting section. CHANGELOG: note the additions.
⏸ On hold — blocked on
|
…st-tag verify, dry-run doc Resolves the four cursor[bot] review comments on PR #118. - release-binaries.yml: add the tag==Cargo.toml guard (after checkout) so a mistag can't ship npm + GitHub artifacts built from a different source while only PyPI is blocked by release.yml's version-guard. A mismatch now fails the build before upload, so the workflow_run never succeeds and npm-publish skips. - test.yml + scripts/ci/version_ahead.py: replace the equality-only bump check with a SemVer-precedence comparison (new, unit-tested helper). Now blocks a regression too (e.g. 1.8.9 vs last 1.9.0), and gets pre-release ordering right so the 1.10.0-beta.1 -> 1.10.0 bump still passes (which sort -V gets wrong). - publish.sh: the already-published path now flows into the dist-tag verification instead of exiting early, so dist-tag drift is caught rather than reported as a clean skip. Verify-not-repair: an `npm dist-tag add` here would regress `latest` if the job were re-dispatched against an older tag. - RELEASING.md: correct the dry-run dispatch contract — the publish job checks out the tag's tree and runs that tag's publish.sh, so the rehearsal only works against tags that already contain the script (not v1.9.0); document the local RESOLVE_ONLY + npm pack alternative before the first such tag exists.
…tag filter Addresses the Corgea scanner review on scripts/ci/version_ahead.py:44 — an unhandled ValueError from int() on a non-numeric core crashed CI with a raw traceback. Now precedence_key() raises a clear ValueError on a non-numeric core, main() catches it and emits a clean ::error:: with exit 2, and version-bump-check only considers v[0-9]* tags as the last release so a stray tag like `vfoo` can't reach the comparator in the first place.
Addresses the Corgea scanner follow-up: precedence_key accepted >3 core parts (e.g. 1.2.3.4) and padded <3, deviating from SemVer 2.0.0. Now requires exactly three numeric parts (our Cargo.toml/tag inputs always are), which also drops the padding loop. Malformed cores raise a clear ValueError -> clean ::error:: exit 2.
There was a problem hiding this comment.
scripts/ci/__pycache__/version_ahead.cpython-314.pycis committed as a generated binary artifact (added file, no source line). Evidence: the PR creates a 3,427-byte CPython 3.14.pyc, while the actual source isscripts/ci/version_ahead.py;.gitignore:1-11also has no__pycache__/or*.pycignore rule. Impact: interpreter-specific generated bytecode gets shipped in the repo/source artifacts and will create noisy churn on future local Python runs, but CI never uses it. Concrete fix: removescripts/ci/__pycache__/version_ahead.cpython-314.pycfrom the branch and add__pycache__/plus*.py[cod]to.gitignore.
Sent by Cursor Automation: pr-flow
| # SemVer precedence (not string equality): blocks an unchanged version | ||
| # AND a regression, and gets pre-release ordering right (e.g. the | ||
| # 1.10.0-beta.1 -> 1.10.0 bump must pass). See scripts/ci/version_ahead.py. | ||
| python3 scripts/ci/version_ahead.py "$CARGO_VER" "$LAST_VER" |
There was a problem hiding this comment.
This only exercises version_ahead.py once against the current Cargo.toml and whatever tag happens to be latest in the live repo. The PR is adding release-critical behavior with several non-obvious cases: beta-to-final ordering (1.10.0-beta.1 < 1.10.0), beta increments, regressions, malformed versions, and scripts/npm/publish.sh's - => beta / stable => latest mapping. None of those cases are covered by CI, so a future regression can still merge and first show up during a real tag publish. Add table-driven tests for scripts/ci/version_ahead.py and a CI step that runs RESOLVE_ONLY=true PACKAGE_VERSION=1.10.0-beta.1 ./scripts/npm/publish.sh expecting dist-tag=beta, plus the stable latest case.
|
closing in favor of streamline releases 🚀 |


What
Adds a curated beta pre-release channel for the CLI. Tagging
vX.Y.Z-beta.N(a maintainer bumpsCargo.tomltoX.Y.Z-beta.Nand tags it) publishes to three opt-in channels without disturbing stable users:vX.Y.Z)vX.Y.Z-beta.N)latestbeta(latestnever moves)pip install --pre corgea-cliprerelease: true+ beta disclaimer bodyChanges
scripts/npm/publish.sh(new) — isolates the dist-tag decision, cross-the-streams safety guards, idempotency, dry-run, andRESOLVE_ONLY(testable with no network). Fixes a latent bug: the old idempotency check queried the unscopedcorgea-cli(always 404 → dead); it now queries@corgea/cli..github/workflows/npm-publish.yml—dry_rundispatch input; publishes via the script..github/workflows/release-binaries.yml—prereleaseflag on asset uploads (race-safe bool); a singlefinalize-releasejob sets the prerelease disclaimer + auto release notes once (avoids a 6-way race)..github/workflows/release.yml—version-guardjob fails a release if the tag ≠Cargo.tomlversion (npm-uses-tag / PyPI-uses-Cargo.toml can't drift silently)..github/workflows/test.yml—version-bump-check(PR-only) fails a PR whoseCargo.tomlversion still equals the latest released tag, so a stale version can't merge. The first PR after each release must bump.CHANGELOG.md(new, Keep a Changelog),RELEASING.md(new) +AGENTS.mdpointer, README beta section.bin/corgea.js— fix reinstall hintcorgea-cli@latest→@corgea/cli@latest.This PR publishes nothing
Machinery + docs only — no
Cargo.tomlbeta bump, no tag. Every publish job is gated onrefs/tags/or av-prefixed head branch, andnpm-publish.ymlruns only onworkflow_run(after av*build) or manual dispatch. The first real beta cut is a documented follow-up inRELEASING.mdthat the maintainer triggers.Verification (local, before PR)
./harness cigreen — clippy/format/audit clean, 436 tests pass.RESOLVE_ONLY=true PACKAGE_VERSION=1.10.0-beta.1 ./scripts/npm/publish.sh→dist-tag=beta;=1.9.1→dist-tag=latest; a crossed state exits non-zero. (3 assertions.)Cargo.toml→1.10.0-beta.1,maturin build→ wheelcorgea_cli-1.10.0b1-…whl. Confirms SemVer1.10.0-beta.1→ PEP 4401.10.0b1.version-bump-checklogic verified against live state:1.9.1(Cargo.toml) ≠v1.9.0(last tag) → pass; a stale1.9.0PR → fail.What CI here proves (zero publishing)
test.yml→./harness ci+version-bump-check.release.ymlbuilds all wheel + sdist artifacts; PyPIreleasejob skipped (not a tag).release-binaries.ymlbuilds 6 binary zips as artifacts only (GH-release upload is tag-gated; npm-publish needs av*head branch).Dry-run rehearsal (no registry write)
Runs the new code path, downloads an existing release's zips, bundles them, and runs
npm publish --dry-run.Out of scope (separate repo):
docs/cli.mdxbeta section + stale release URLs — follow-up.