--- name: publish-package-cicd description: CI/CD publishing workflow for npm packages using Changesets + npm Trusted Publishers (OIDC). Use when setting up automated npm publishing for monorepos, configuring GitHub Actions for releases, troubleshooting workspace:* protocol resolution issues, fixing "Cannot find module" errors in published packages, or debugging npm OIDC authentication. Covers Bun + Turborepo + Changesets + npm Trusted Publishers with workspace protocol resolution. --- # Publish Package CI/CD Automated npm publishing for Bun monorepos using Changesets + npm Trusted Publishers (OIDC). No npm tokens needed - GitHub Actions authenticates via OIDC. ## Core Workflow ### 1. Create Changeset (Manual File Creation) **CRITICAL: Never run `bunx changeset` interactively.** Create changeset files manually to avoid the interactive CLI: ```bash cat > .changeset/your-change-name.md << 'EOF' --- "package-name": patch --- Description of the change EOF ``` **Version bump types:** - `patch` - Bug fixes, minor updates (0.0.x) - `minor` - New features, backwards compatible (0.x.0) - `major` - Breaking changes (x.0.0) ### 2. Commit and Push ```bash git add .changeset/your-change-name.md git commit -m "feat: your feature description" git push origin main ``` ### 3. Automated Release Flow 1. **Changesets Action** (`.github/workflows/ci.yml`) detects changeset file 2. Creates/updates "chore: release packages" PR with version bumps + CHANGELOG 3. **On PR merge** → triggers publish workflow (`.github/workflows/publish.yml`) 4. Publishes to npm via OIDC (no npm token) ## Trusted Publishers (OIDC) Setup ### Initial Package Setup (One-Time) For each package to publish: 1. **Publish v0.1.0 manually:** ```bash cd packages/your-package npm publish --access public ``` 2. **Configure Trusted Publisher:** - Go to https://www.npmjs.com/package/your-package/access - Click "Trusted Publishers" → "Add" - Fill in: - Organization: `your-github-org` - Repository: `your-repo-name` - Workflow: `publish.yml` - Save 3. **Future releases:** Fully automated via GitHub Actions ### How OIDC Works - No `NPM_TOKEN` secret required - GitHub Actions has `id-token: write` permission - npm packages configured with Trusted Publisher pointing to repo + workflow - npm CLI 11.5.1+ auto-detects OIDC environment - Provenance attestations generated automatically ## workspace:* Protocol Resolution **Problem:** `workspace:*` in package.json dependencies doesn't resolve during `npm publish`, causing "Cannot find module" errors for consumers. **Solution:** Use custom publish script with two-step process: ```bash # 1. Sync lockfile (resolves workspace:* from lockfile) bun install # 2. Pack tarball (resolves workspace:* to actual versions) bun pm pack # 3. Publish tarball (supports npm OIDC) npm publish ``` **Why not `bun publish`?** Bun resolves workspace protocols but doesn't support npm OIDC - requires `npm login`. See `references/publish-script.ts` for full implementation. ## Ignored Packages (Non-Published) Exclude packages from publishing in `.changeset/config.json`: ```json { "ignore": ["@swarmtools/web", "docs-app"] } ``` **Important:** Changeset ignore only affects versioning, NOT builds. Must also exclude from turbo: ```bash # In CI, exclude ignored packages from build bun turbo build --filter='!@swarmtools/web' ``` ## Common Issues ### CLI Bin Script "Cannot find module" **Symptom:** Published package works, but CLI bin script fails with `Cannot find module '@clack/prompts'`. **Root cause:** Bin script imports are runtime dependencies, not devDependencies. **Fix:** Move ALL bin script imports to `dependencies` in package.json: ```json { "dependencies": { "@clack/prompts": "^0.7.0", // Used by bin/cli.ts "commander": "^11.0.0" // Used by bin/cli.ts } } ``` ### Lockfile Stale After Changeset Bump **Symptom:** Publish picks up old versions of `workspace:*` dependencies. **Root cause:** `bun pm pack` resolves from lockfile, which is stale after version bumps. **Fix:** Run `bun install` BEFORE `bun pm pack`: ```bash bun install # Sync lockfile with new versions bun pm pack # Now packs with correct versions npm publish ``` See `references/publish-script.ts` - automatically handles this. ### Local `bunx changeset version` Fails **Symptom:** `Error: GITHUB_TOKEN not found` **Root cause:** Changesets needs GitHub API access for PR/changelog generation. Works in CI (has GITHUB_TOKEN), fails locally. **Fix:** Don't run `bunx changeset version` or `bunx changeset publish` locally. Let CI handle it: 1. Create changeset file manually 2. Push to main 3. CI creates release PR 4. Merge PR → auto-publishes ### Bun Publish vs npm Publish **Avoid `bun publish`** - doesn't support npm OIDC (requires `npm login`). **Use `npm publish `** - supports OIDC + resolves workspace protocols when publishing tarball created by `bun pm pack`. ## Reference Files - **references/publish-workflow.yml** - Full GitHub Actions workflow with OIDC + workspace resolution - **references/changeset-config.json** - Changeset configuration with ignored packages - **references/publish-script.ts** - Custom publish script handling workspace:* resolution ## Commands Reference ```bash # Create changeset (manual file creation) cat > .changeset/fix-thing.md << 'EOF' --- "pkg-name": patch --- Fixed the thing EOF # Preview version bumps (optional, informational only) bunx changeset status # Build packages (exclude ignored) bun turbo build --filter='!@swarmtools/web' # Publish (in CI only, via publish.yml) bun install # Sync lockfile bun pm pack # Create tarball with resolved workspace:* npm publish # Publish with OIDC ``` ## Tracking Issues - **Bun native npm token support:** https://github.com/oven-sh/bun/issues/15601 - When resolved, can switch to `bun publish` directly - Currently must use `npm publish` for OIDC support