Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Also required (npm enforces it): `id-token: write` on BOTH the parent job (the `
- Trusted-publisher config is **web-UI only**, no API/CLI, and **passkey/2FA-gated per save**. With N packages it's N manual saves. This monorepo has **17 publishable packages** (`packages/*` minus `docs`, which is `private: true`), so it's 17 saves. Do them back-to-back to ride the authenticator's warm-credential window.
- **Each package has exactly one trusted publisher** — no org-level or account-level setting applies to all at once. Changing the filename means re-saving all 17.
- Tradeoff: registering `release-please.yml` means a manual `workflow_dispatch` of `release.yml` (entry = release.yml) will STOP matching. The automated flow is the one that matters, so that's the right trade; treat manual dispatch as admin-only.
- **Corollary discovered 2026-06-11 (the no-recovery-path trap):** registering ONLY `release-please.yml` means there is **no working manual recovery** when the automated chain fails to publish. If release-please's `release_created` comes back false (e.g. it aborts with "untagged, merged release PRs outstanding" after a tag-scheme change), you cannot rescue the release by `gh release create` (entry = release.yml → `release: published` → OIDC 404) NOR by `workflow_dispatch` of release.yml (entry = release.yml → 404). Both manual paths carry `release.yml` as the entry and fail the trusted-publisher match. The fix: **register BOTH `release-please.yml` AND `release.yml`** as trusted publishers for the package. After collapse this is only ONE package (`@opencodehub/cli`), so it's 2 saves total — cheap insurance that makes `workflow_dispatch`-based recovery work. Symptom that you're in this trap: tag + GitHub Release exist for the version, but `npm view <pkg> version` is behind and every manual republish 404s on the OIDC token exchange.

## Why not just add a PAT instead?

Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -383,5 +383,22 @@ jobs:
- uses: jdx/mise-action@dba19683ed58901619b14f395a24841710cb4925 # v4.1.0
- run: pnpm install --frozen-lockfile
- run: pnpm --filter '!@opencodehub/docs' -r build
# Idempotency guard: a stuck/retried release (e.g. the automated chain
# failed mid-publish and is re-run) must not hard-fail because the version
# already exists on npm. `pnpm publish` errors on a duplicate version, so
# short-circuit when the registry already serves this exact version.
- name: Skip if version already published
id: published
run: |
set -euo pipefail
NAME=$(node -p "require('./packages/cli/package.json').name")
VER=$(node -p "require('./packages/cli/package.json').version")
if npm view "${NAME}@${VER}" version >/dev/null 2>&1; then
echo "already=true" >> "$GITHUB_OUTPUT"
echo "::notice::${NAME}@${VER} already on npm — skipping publish (idempotent re-run)."
else
echo "already=false" >> "$GITHUB_OUTPUT"
fi
- name: Publish to npm
if: steps.published.outputs.already == 'false'
run: pnpm --filter '!@opencodehub/docs' -r publish --provenance --access public --no-git-checks
Loading