diff --git a/.github/workflows/publish-js.yml b/.github/workflows/publish-js.yml index a5f2e097..e45280e7 100644 --- a/.github/workflows/publish-js.yml +++ b/.github/workflows/publish-js.yml @@ -424,3 +424,17 @@ jobs: working-directory: crates/bashkit-js env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Verify npm publish + run: | + sleep 10 + PKG_VERSION=$(node -p "require('./package.json').version") + ACTUAL=$(npm view @everruns/bashkit version 2>/dev/null || echo "not found") + if [ "$ACTUAL" = "$PKG_VERSION" ]; then + echo "✓ @everruns/bashkit@$ACTUAL published to npm (latest)" + else + echo "✗ expected $PKG_VERSION on npm latest, got $ACTUAL" + echo "::error::npm publish verification failed" + exit 1 + fi + working-directory: crates/bashkit-js diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d89166b5..b543a83f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -39,20 +39,27 @@ jobs: fi - name: Strip git-only dependencies for publishing - # monty is a git dep (not yet on crates.io) — remove before publish + # monty is a git dep (not yet on crates.io) — remove before publish. + # Must strip from both bashkit AND bashkit-cli because cargo resolves + # the whole workspace when publishing a single crate. run: | + # --- bashkit core --- TOML=crates/bashkit/Cargo.toml - # Remove monty dependency line sed -i '/^monty = .*/d' "$TOML" - # Remove python feature that references monty sed -i '/^python = \["dep:monty"\]/d' "$TOML" - # Remove python_scripts example block (requires python feature) sed -i '/^\[\[example\]\]/{N;N;/python_scripts/d}' "$TOML" - echo "--- Cargo.toml after stripping ---" + echo "--- bashkit Cargo.toml after stripping ---" cat "$TOML" + # --- bashkit-cli (workspace resolution requires this too) --- + CLI_TOML=crates/bashkit-cli/Cargo.toml + sed -i '/^python = \["bashkit\/python"\]/d' "$CLI_TOML" + sed -i 's/default = \["python"\]/default = []/' "$CLI_TOML" + echo "--- bashkit-cli Cargo.toml after stripping ---" + cat "$CLI_TOML" + - name: Publish bashkit to crates.io - run: cargo publish -p bashkit --allow-dirty 2>&1 || echo "::warning::bashkit publish failed (may already exist)" + run: cargo publish -p bashkit --allow-dirty env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} @@ -84,3 +91,37 @@ jobs: run: cargo publish -p bashkit-cli --allow-dirty env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + + # ============================================================================ + # Verify all packages were published successfully + # ============================================================================ + verify-publish: + name: Verify published versions + runs-on: ubuntu-latest + needs: [publish-bashkit, publish-bashkit-cli] + steps: + - uses: actions/checkout@v6 + + - name: Wait for crates.io propagation + run: sleep 60 + + - name: Verify crates.io versions + run: | + EXPECTED=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "Expected version: $EXPECTED" + PASS=true + + for CRATE in bashkit bashkit-cli; do + ACTUAL=$(curl -s "https://crates.io/api/v1/crates/$CRATE" | python3 -c "import sys,json; print(json.load(sys.stdin)['crate']['max_version'])") + if [ "$ACTUAL" = "$EXPECTED" ]; then + echo "✓ $CRATE@$ACTUAL on crates.io" + else + echo "✗ $CRATE: expected $EXPECTED, got $ACTUAL" + PASS=false + fi + done + + if [ "$PASS" = "false" ]; then + echo "::error::Some crates.io packages were not published correctly" + exit 1 + fi diff --git a/specs/008-release-process.md b/specs/008-release-process.md index d35750b7..03e44a93 100644 --- a/specs/008-release-process.md +++ b/specs/008-release-process.md @@ -76,9 +76,9 @@ When asked to create a release, the agent: - Extracts release notes from CHANGELOG.md - Creates GitHub Release with tag `vX.Y.Z` -**On GitHub Release published** (publish.yml): -- Publishes to crates.io in dependency order -- Note: No verification step - CI already ran when PR merged to main +**On GitHub Release published** (publish.yml, publish-js.yml, publish-python.yml): +- Publishes to crates.io, npm, and PyPI +- Each publish workflow includes a verification step that checks the published version matches expectations ## Pre-Release Checklist @@ -199,7 +199,7 @@ brew install everruns/tap/bashkit ### publish.yml - **Trigger**: GitHub Release published -- **Actions**: Publishes to crates.io (no verification - CI ran on merge) +- **Actions**: Publishes to crates.io in dependency order, then verifies published versions - **File**: `.github/workflows/publish.yml` - **Secret required**: `CARGO_REGISTRY_TOKEN` @@ -294,6 +294,28 @@ Done. PR created: https://github.com/everruns/bashkit/pull/XX Please review and merge to trigger the release. ``` +## Post-Release Verification + +Each publish workflow includes automated verification. After a release, the agent (or human) should also verify manually: + +```bash +# crates.io +cargo search bashkit # Should show latest version +cargo search bashkit-cli # Should show latest version + +# npm +npm view @everruns/bashkit version # Should show latest version +npm dist-tags ls @everruns/bashkit # "latest" should point to new version + +# PyPI +pip index versions bashkit # Should show latest version + +# GitHub +gh release view --repo everruns/bashkit # Should show latest tag +``` + +If any registry is missing the new version, check the corresponding publish workflow run for errors. + ## Hotfix Releases For urgent fixes: