Skip to content

chore(repo): migrate from npm + semantic-release to pnpm + Changesets#94

Merged
designcode merged 6 commits into
mainfrom
dx/pnpm-and-changeset
May 9, 2026
Merged

chore(repo): migrate from npm + semantic-release to pnpm + Changesets#94
designcode merged 6 commits into
mainfrom
dx/pnpm-and-changeset

Conversation

@designcode
Copy link
Copy Markdown
Collaborator

@designcode designcode commented May 7, 2026

Summary

  • Replace npm workspaces with pnpm workspaces (pnpm-workspace.yaml, packageManager: pnpm@10.33.4).
  • Replace semantic-release with Changesets for releasing the five published packages (@tigrisdata/storage, iam, agent-kit, keyv-tigris, react). Independent versioning is preserved.
  • Cross-package dependencies switch from pinned ranges (^3.2.1, etc.) to workspace:^ so dependents develop against local source. pnpm rewrites the protocol to a real range at publish time.
  • Drop the next branch from release configuration. main is the single release branch; pre-releases use pnpm changeset pre enter <tag> on main when needed.

Tag and version preservation

  • Each package's package.json#version is seeded to its currently-published value so the next Changesets bump computes from real history rather than 0.0.1:
    • @tigrisdata/storage3.4.0
    • @tigrisdata/iam2.1.1
    • @tigrisdata/agent-kit0.1.3
    • @tigrisdata/keyv-tigris1.1.3
    • @tigrisdata/react1.2.3
  • Existing @tigrisdata/<pkg>@<version> tags are untouched. New tags use the same format (Changesets default for monorepos with fixed: [] / linked: []).
  • An empty .changeset/dx-pnpm-and-changeset.md is included so the migration PR itself satisfies the pnpm changeset status gate without bumping anything.

Release flow (post-merge)

  1. PRs opt into a release by adding a changeset (pnpm changeset).
  2. When PRs land on main, the release workflow opens a "Version Packages" PR that bumps versions and updates each package's CHANGELOG.md.
  3. Merging that PR runs changeset publish: publishes to npm via GitHub OIDC trusted publishing with provenance (NPM_CONFIG_PROVENANCE=true, no NPM_TOKEN), then creates @tigrisdata/<pkg>@<version> tags.

Other changes

  • Delete unused stub directories packages/agent-artifact-passport/ and packages/agent-artifacts/.
  • Update Husky hooks to use pnpm (pre-commitpnpm check, commit-msgpnpm exec commitlint).
  • Update AGENTS.md to reflect pnpm + Changesets workflow and remove the stale packages/cli reference.
  • Add pnpm.onlyBuiltDependencies for esbuild and sqlite3 (pnpm 10 disables install scripts by default).

Prerequisite before merging

Each of the five packages must have Trusted Publisher configured on npmjs.com (Settings → Trusted publisher → GitHub Actions, repo tigrisdata/storage, workflow release.yaml). Without this, changeset publish will 401 since there's no NPM_TOKEN.

Test plan

  • pnpm install (clean: removed package-lock.json, node_modules)
  • pnpm -r build — all 5 packages build
  • pnpm -r test — 237 tests pass (storage 144, react 44, keyv-tigris 38, agent-kit 11)
  • pnpm run lint (Biome) clean
  • pnpm -r publint — all 4 packages with publint script report "All good"
  • pnpm changeset status — clean (empty changeset present)
  • CI (pr.yaml) green on this PR
  • Trusted Publisher configured on npm for all 5 packages before merge
  • Post-merge: confirm release.yaml runs cleanly on push to main (no version PR opened — empty changeset only)
  • First subsequent feature PR adds a real changeset and the release workflow opens a "Version Packages" PR

🤖 Generated with Claude Code


Note

High Risk
Replaces the project’s CI/install and publishing automation (npm/semantic-release) with pnpm + Changesets, which can directly impact release correctness and npm publishing if misconfigured. Also updates Node version and enforces changeset presence on package-affecting PRs, potentially affecting contributor workflow and CI outcomes.

Overview
Migrates the repo’s tooling from npm + semantic-release to pnpm + Changesets by adding a .changeset/ config/README and wiring changesets/action@v1 into the release workflow to open version PRs and publish with provenance.

Updates PR and release GitHub Actions to use pnpm (install, lint, build, publint, tests) on Node 24, removes the next branch triggers, and adds a CI gate that requires a changeset when files under packages/ or shared/ change.

Adjusts developer workflow docs and git hooks to use pnpm (pnpm check, pnpm exec commitlint) and tweaks npm config via .npmrc.

Reviewed by Cursor Bugbot for commit 48fe93f. Bugbot is set up for automated code reviews on this repo. Configure here.

Replaces npm workspaces with pnpm workspaces and semantic-release with
Changesets. Cross-package dependencies now use the workspace:^ protocol
so dependent packages develop against local source instead of stale
published versions. Single main branch is now the source of truth for
releases; the next branch is dropped.

Each package.json version is seeded to the currently-published value
(storage 3.4.0, iam 2.1.1, agent-kit 0.1.3, keyv-tigris 1.1.3,
react 1.2.3) so Changesets bumps from real history. Existing
@tigrisdata/<pkg>@<version> tags are preserved unchanged.

Release workflow uses changesets/action with GitHub OIDC trusted
publishing (no NPM_TOKEN) and provenance enabled.

Assisted-by: Claude Opus 4.7 (1M context) via Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 7, 2026

Greptile Summary

Migrates the monorepo from npm workspaces + semantic-release to pnpm workspaces + Changesets, updating CI workflows, Husky hooks, and developer docs to match. All five packages have their versions seeded to currently-published values and their cross-package deps switched to workspace:^.

  • pnpm workspace setup: pnpm-workspace.yaml added, packageManager field set in root package.json, package-lock.json replaced with pnpm-lock.yaml, and all root scripts updated to pnpm -r.
  • CI overhaul: pr.yaml and release.yaml now use pnpm/action-setup@v4 and changesets/action@v1; the release pipeline uses GitHub OIDC trusted publishing (id-token: write + NPM_CONFIG_PROVENANCE=true) instead of an NPM_TOKEN secret.
  • Release tooling: scripts/release.sh and all per-package release.config.cjs files deleted; a changeset status gate added to PR checks; Changesets manages versioning and CHANGELOG generation going forward.

Confidence Score: 3/5

The core migration is structurally sound, but the release workflow has two gaps that could silently break on the first real publish, and the PR check gate will block every infrastructure contributor who forgets to add a changeset.

The workflow files carry two gaps that are only exercised at publish or CI time: the changeset status gate in pr.yaml has no escape hatch, so any future CI/docs PR will fail unless the author remembers to add an empty changeset; and the release.yaml publish step omits NODE_AUTH_TOKEN, relying entirely on npm OIDC without making that intent explicit — if the trusted publisher config on npmjs.com is absent or misconfigured, the publish will 401 with no clear diagnostic.

.github/workflows/release.yaml and .github/workflows/pr.yaml both need attention — the publish env and the changeset gate are where real breakage is most likely.

Important Files Changed

Filename Overview
.github/workflows/release.yaml Replaces semantic-release script with changesets/action@v1; NODE_AUTH_TOKEN is absent and the action is not pinned to a SHA.
.github/workflows/pr.yaml Migrates CI to pnpm and adds a changeset status --since=origin/main gate with no escape hatch for non-package PRs.
package.json Replaces npm workspace scripts with pnpm equivalents, adds packageManager field, and swaps semantic-release deps for Changesets.
pnpm-workspace.yaml New workspace manifest pointing to all packages/*; straightforward.
.changeset/config.json Changesets config with independent versioning, public access, and GitHub changelog generation.
scripts/release.sh Deleted — replaced entirely by changesets/action in the release workflow.
AGENTS.md Updated developer guide to reflect pnpm, Biome, and Changesets; removes stale packages/cli reference.

Comments Outside Diff (1)

  1. .github/workflows/release.yaml, line 55-64 (link)

    P2 NODE_AUTH_TOKEN absent from the publish step's env

    actions/setup-node with registry-url writes an .npmrc that expands ${NODE_AUTH_TOKEN} at publish time. In this workflow NODE_AUTH_TOKEN is never set, so the token in .npmrc will be empty. npm's OIDC provenance flow (id-token: write + NPM_CONFIG_PROVENANCE=true) should override this and authenticate via OIDC anyway, but the behaviour depends on npm's internal order of operations and may silently 401 if the trusted publisher configuration is missing or misconfigured on npmjs.com. Adding an explicit env key (e.g. NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}) as a no-op placeholder makes it clear the omission is intentional and avoids surprising failures.

Reviews (1): Last reviewed commit: "chore(repo): migrate from npm + semantic..." | Re-trigger Greptile

Comment thread .github/workflows/pr.yaml
Comment thread .github/workflows/release.yaml
Comment thread .github/workflows/release.yaml Outdated
… pnpm

shared/ imports dotenv, @aws-crypto/sha256-js, and @smithy/signature-v4.
Under npm workspaces those resolved via root hoisting; under pnpm's
strict isolation they can't, so iam (and any other package whose tsconfig
includes shared/**/*) failed to build in CI.

Adding shared/package.json (private, name @tigrisdata/shared) and listing
it in pnpm-workspace.yaml makes pnpm install those deps into
shared/node_modules/, where tsc + tsup can resolve them. No consumer
configs or source files change — the existing @shared/* TS path alias
and tsup esbuild alias still point at ../../shared and continue to work.

Also:
- Path-gate the 'Verify changeset present' step in pr.yaml so non-package
  PRs (CI, docs) aren't forced to add empty changesets.
- Use a clearer Changesets release commit title:
  'chore(release): bump versions and update changelogs'.
  Scoped to satisfy commitlint's scope-empty rule.

Assisted-by: Claude Opus 4.7 (1M context) via Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@designcode
Copy link
Copy Markdown
Collaborator Author

Pushed 0bde2a1 with three fixes:

  1. CI build failure (root cause). iam's build failed because shared/ imports dotenv, @aws-crypto/sha256-js, and @smithy/signature-v4, but those weren't resolvable under pnpm's strict isolation (npm workspaces had hoisted them; pnpm doesn't). Made shared/ a private workspace package — added shared/package.json declaring its own deps and listed shared in pnpm-workspace.yaml. pnpm now installs the deps into shared/node_modules/, where tsc + tsup can resolve them. Zero source files or per-package configs change — the existing @shared/* TS path alias and tsup esbuild alias still point at ../../shared and continue to work.

  2. [Cursor] Changesets commit message scope. Updated release.yaml to use chore(release): bump versions and update changelogs so the commit message passes commitlint's scope-empty rule when Husky's commit-msg hook fires in CI.

  3. [Greptile] Changeset-status gate. Path-gated pnpm changeset status in pr.yaml to only run when packages/** or shared/** changed. Non-package PRs (CI, docs, tooling) no longer have to carry an empty changeset.

On NODE_AUTH_TOKEN (Greptile P2): Skipping. With OIDC trusted publishing, npm/pnpm exchanges the GitHub OIDC token for a publish token directly — no NODE_AUTH_TOKEN is needed. Setting NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} as a placeholder would actually be wrong: npm rejects GITHUB_TOKEN as auth, masking real OIDC failures behind a confusing 401. The trusted publisher must be configured on npmjs.com per package — that's already called out as a prerequisite in the PR body.

On SHA-pinning changesets/action@v1 (Greptile P2): Keeping @v1. It's the recommendation in the action's README and the practice across the Changesets/pnpm ecosystems. SHA pinning is a repo-wide supply-chain policy decision (would also apply to actions/checkout, actions/setup-node, pnpm/action-setup); out of scope for this PR.

Locally: pnpm install (clean), pnpm -r build, pnpm -r test (237 pass), pnpm -r publint (all good), pnpm changeset status (clean).

Comment thread .github/workflows/release.yaml Outdated
Comment thread .github/workflows/pr.yaml
designcode and others added 3 commits May 8, 2026 09:29
storage source imports HttpRequest/HttpResponse from @aws-sdk/types in
8 files but only declares @aws-sdk/client-s3 et al., relying on
@aws-sdk/types being a transitive. Under npm's hoisted layout that
resolved at the root node_modules; under pnpm's isolated layout it
doesn't, so tsc in CI fails with TS2307. Local passed because tsc was
resolving the type module from a stray ~/node_modules copy that CI
runners don't have.

Pinned to ^3.973.8 to match what @aws-sdk/client-s3 itself requests.

Assisted-by: Claude Opus 4.7 (1M context) via Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
vitest.config.base.ts at the repo root imports dotenv to load .env
before tests, but the root package.json never declared it — it was
relying on dotenv being hoisted from a workspace package's transitive
closure. Under pnpm strict isolation, root files only see deps declared
in the root package.json, so vitest config loading failed in CI with
ERR_MODULE_NOT_FOUND. Local was again masked by a stray ~/node_modules
copy.

Assisted-by: Claude Opus 4.7 (1M context) via Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pnpm 10.x's publish shells out to npm publish for the actual upload.
Node 22 ships npm 10.9.7, but OIDC trusted publishing requires npm
>= 11.5.1, so the first real release would 401. Node 24 (LTS since
2025-10) ships npm 11.12.1, which has the required OIDC support.

Applied the same version bump in pr.yaml so PR checks run against the
same Node we'll publish from.

Assisted-by: Claude Opus 4.7 (1M context) via Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fd4ce3a. Configure here.

Comment thread .github/workflows/release.yaml
setup-node's registry-url input exists specifically to wire up
NODE_AUTH_TOKEN-based publish — it writes a project-level .npmrc with
//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN} and exports a
placeholder NODE_AUTH_TOKEN. With OIDC trusted publishing we don't want
that path: the placeholder beats OIDC's token discovery and the publish
fails. The npm registry is the default for both npm and pnpm without
any .npmrc configuration, so dropping the input is the cleanest fix.

Assisted-by: Claude Opus 4.7 (1M context) via Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@designcode designcode merged commit 3e3fec2 into main May 9, 2026
2 of 3 checks passed
@designcode designcode deleted the dx/pnpm-and-changeset branch May 9, 2026 13:12
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.

2 participants