Skip to content

Add curated beta pre-release channel (npm/PyPI/GitHub)#118

Closed
juangaitanv wants to merge 5 commits into
mainfrom
chore/beta-release-channel
Closed

Add curated beta pre-release channel (npm/PyPI/GitHub)#118
juangaitanv wants to merge 5 commits into
mainfrom
chore/beta-release-channel

Conversation

@juangaitanv

Copy link
Copy Markdown
Contributor

What

Adds a curated beta pre-release channel for the CLI. Tagging vX.Y.Z-beta.N (a maintainer bumps Cargo.toml to X.Y.Z-beta.N and tags it) publishes to three opt-in channels without disturbing stable users:

Channel Stable (vX.Y.Z) Beta (vX.Y.Z-beta.N)
npm dist-tag latest beta (latest never moves)
PyPI normal install only via pip install --pre corgea-cli
GitHub Release normal prerelease: true + beta disclaimer body

Changes

  • scripts/npm/publish.sh (new) — isolates the dist-tag decision, cross-the-streams safety guards, idempotency, dry-run, and RESOLVE_ONLY (testable with no network). Fixes a latent bug: the old idempotency check queried the unscoped corgea-cli (always 404 → dead); it now queries @corgea/cli.
  • .github/workflows/npm-publish.ymldry_run dispatch input; publishes via the script.
  • .github/workflows/release-binaries.ymlprerelease flag on asset uploads (race-safe bool); a single finalize-release job sets the prerelease disclaimer + auto release notes once (avoids a 6-way race).
  • .github/workflows/release.ymlversion-guard job fails a release if the tag ≠ Cargo.toml version (npm-uses-tag / PyPI-uses-Cargo.toml can't drift silently).
  • .github/workflows/test.ymlversion-bump-check (PR-only) fails a PR whose Cargo.toml version 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.md pointer, README beta section.
  • bin/corgea.js — fix reinstall hint corgea-cli@latest@corgea/cli@latest.

This PR publishes nothing

Machinery + docs only — no Cargo.toml beta bump, no tag. Every publish job is gated on refs/tags/ or a v-prefixed head branch, and npm-publish.yml runs only on workflow_run (after a v* build) or manual dispatch. The first real beta cut is a documented follow-up in RELEASING.md that the maintainer triggers.

Verification (local, before PR)

  • ./harness ci green — clippy/format/audit clean, 436 tests pass.
  • RESOLVE_ONLY=true PACKAGE_VERSION=1.10.0-beta.1 ./scripts/npm/publish.shdist-tag=beta; =1.9.1dist-tag=latest; a crossed state exits non-zero. (3 assertions.)
  • maturin normalization (isolated + reverted): Cargo.toml1.10.0-beta.1, maturin build → wheel corgea_cli-1.10.0b1-…whl. Confirms SemVer 1.10.0-beta.1 → PEP 440 1.10.0b1.
  • All five workflow YAMLs parse.
  • version-bump-check logic verified against live state: 1.9.1 (Cargo.toml) ≠ v1.9.0 (last tag) → pass; a stale 1.9.0 PR → fail.

What CI here proves (zero publishing)

  • test.yml./harness ci + version-bump-check.
  • release.yml builds all wheel + sdist artifacts; PyPI release job skipped (not a tag).
  • release-binaries.yml builds 6 binary zips as artifacts only (GH-release upload is tag-gated; npm-publish needs a v* head branch).

Dry-run rehearsal (no registry write)

gh workflow run npm-publish.yml --ref <branch> -f tag=v1.9.0 -f dry_run=true

Runs the new code path, downloads an existing release's zips, bundles them, and runs npm publish --dry-run.

Note: the CHANGELOG.md [Unreleased] compare link uses v1.9.0...HEAD (the latest released tag) rather than the plan's v1.9.1v1.9.1 is not tagged yet (Cargo.toml is at 1.9.1, unreleased), so v1.9.1...HEAD would 404.

Out of scope (separate repo): docs/cli.mdx beta section + stale release URLs — follow-up.

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.
Comment thread .github/workflows/release-binaries.yml
Comment thread .github/workflows/test.yml Outdated
Comment thread scripts/npm/publish.sh Outdated
Comment thread RELEASING.md Outdated
…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.
@juangaitanv juangaitanv marked this pull request as draft June 24, 2026 12:53
@juangaitanv

Copy link
Copy Markdown
Contributor Author

⏸ On hold — blocked on NPM_TOKEN (decision: land all three beta channels together)

Investigation found that npm CI publishing has never succeeded. The only npm-publish run that ever reached the publish step (v1.9.0, 2026-06-15) failed with:

npm error 404 Not Found - PUT https://registry.npmjs.org/@corgea%2fcli - Not found
npm error 404  '@corgea/cli@1.9.0' is not in this registry.

An E404 on a PUT to an existing scoped package is npm's vague way of saying this token isn't allowed to publish here. NPM_TOKEN is set but cannot publish @corgea/cli. Consequence: npm is two releases behind — PyPI + GitHub are at 1.9.0, npm is stuck at 1.8.7 (1.8.8 and 1.9.0 never landed; 1.8.8 was also a non-v tag this PR's guard now rejects).

The PyPI-beta and GitHub-prerelease legs of this PR work today; only the npm leg is blocked by the token. Per decision, we hold the whole PR until npm CI can publish, so one beta tag lights up all three channels at once.

Unblock checklist (needs npm-org + repo admin)

  1. From a @corgea/cli maintainer (npm owner ls @corgea/cli → ahmad / adam / ibrahim), mint a read-write token — a Granular token with read+write on @corgea/cli, or a classic Automation token (no expiry, bypasses publish-2FA). A granular token set at package creation (2026-03-03, ~90-day default) would have expired right before the 2026-06-15 attempt, which fits the timeline.
  2. Update the NPM_TOKEN repo secret.
  3. Verify the token authenticates as a maintainer (npm whoami; npm access list collaborators @corgea/cli), then prove end-to-end with a disposable beta tag → npm view @corgea/cli@<version>.
  4. Mark this PR ready and merge.

Fixing the token also resolves a live problem independent of this PR: npm users are stuck on 1.8.7 while PyPI/GitHub shipped 1.9.0 — the token fix is what lets 1.9.0 (and 1.8.8) finally reach npm.

Full diagnosis + runbook: RELEASING.md → "Troubleshooting: npm publish fails with E404."

Converting to draft to prevent premature merge; flip to ready once npm CI is green.

…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.
Comment thread scripts/ci/version_ahead.py
Comment thread scripts/ci/version_ahead.py Outdated
…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.
Comment thread scripts/ci/version_ahead.py Outdated
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.
@juangaitanv juangaitanv marked this pull request as ready for review June 24, 2026 14:06

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. scripts/ci/__pycache__/version_ahead.cpython-314.pyc is 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 is scripts/ci/version_ahead.py; .gitignore:1-11 also has no __pycache__/ or *.pyc ignore 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: remove scripts/ci/__pycache__/version_ahead.cpython-314.pyc from the branch and add __pycache__/ plus *.py[cod] to .gitignore.
Open in Web View Automation 

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"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@juangaitanv

Copy link
Copy Markdown
Contributor Author

closing in favor of streamline releases 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant