Skip to content

[Refactor]: use pnpm changeset status instead of git diff for release detection #385

Description

@martyy-code

Problem It Solves

The Detect changesets step in publish.yml uses:

git diff --name-only HEAD~1 HEAD \
  | grep -E '^.changeset/.*.md$' \
  | grep -v 'README.md$' \
  | wc -l

This is fragile for several cases:

  1. Multiple commits in a single PR merge: with squash merge, HEAD~1 is the previous main commit, but HEAD is the squash-commit. The diff correctly shows the squash-commit files. But with rebase merge or merge commit, HEAD~1 is one of the merge commits, not the overall diff against main.
  2. CHANGELOG.md updates: a Changesets bump modifies CHANGELOG.md, which is under packages/fp/, not .changeset/. The current detection ignores this and correctly doesn't double-count — but it also relies on pnpm changeset version having not yet run.
  3. Changeset .md files in nested packages: with monorepos and pnpm, a changeset can be at .changeset/*.md at the root OR in a per-package directory depending on config. The grep anchors the root only.

Proposed Solution

Replace the Detect changesets step with a Changesets-native call. Use pnpm changeset status (or equivalent CLI flag depending on Changesets v3 vs v2) to query the Changesets state machine directly. This is the same tool that the release.yml job eventually calls to perform pnpm changeset version, so we know the result is consistent.

Implementation sketch:

- name: Detect changesets
  id: detect
  run: |
    # Tag pushes and manual workflow_dispatch always proceed.
    if [ "\${{ github.event_name }}" = "push" ] && \
       [ "\${{ github.ref_type }}" = "tag" ]; then
      echo "has_changesets=true" >> "$GITHUB_OUTPUT"
      echo "Tag push detected — proceeding."
      exit 0
    fi
    if [ "\${{ github.event_name }}" = "workflow_dispatch" ]; then
      echo "has_changesets=true" >> "$GITHUB_OUTPUT"
      echo "Manual dispatch — proceeding."
      exit 0
    fi
    # PR merge: query Changesets directly.
    if pnpm changeset status --since=origin/staging --output=json 2>/dev/null | grep -q '"published": false'; then
      echo "has_changesets=true" >> "$GITHUB_OUTPUT"
    else
      echo "has_changesets=false" >> "$GITHUB_OUTPUT"
    fi

Current state

The Detect changesets step in publish.yml uses git diff --name-only HEAD~1 HEAD. Worked on the e2e test of @deessejs/fp@1.1.0 because the merge was a single-commit squash merge. Will break or under-detect on multi-commit merges.

Acceptance criteria

  • Detection produces the same result as git diff HEAD~1 HEAD on a single-commit squash merge (no regression).
  • Detection correctly identifies changesets in a multi-commit squash merge.
  • Detection correctly returns false on a merge that contains no .changeset/*.md additions.
  • Detection correctly returns true on a merge that contains a new changeset file (even if mixed with other file changes).
  • The Detect changesets step logs which signal it used.
  • Manual workflow_dispatch and tag push paths are unchanged.

Alternatives Considered

  • git diff --first-parent HEAD~1 HEAD: keeps the git-based approach but restricts the diff to the first parent of merge commits. Slightly more robust for merge commit strategy but still bypasses Changesets' own state model.
  • Continue with current git diff HEAD~1 HEAD: accept the fragility on multi-commit merges. Not recommended.

Related

  • Plan: docs/engineering/plans/release-pipeline.md §6.2.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    refactorCode cleanuptriageNeeds evaluation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions