Skip to content

refactor: replace inline bash with node script in generate-changeset workflow#861

Merged
binoy14 merged 6 commits intochore/auto-changeset-from-prfrom
chore/generate-changeset-node-script
Apr 1, 2026
Merged

refactor: replace inline bash with node script in generate-changeset workflow#861
binoy14 merged 6 commits intochore/auto-changeset-from-prfrom
chore/generate-changeset-node-script

Conversation

@binoy14
Copy link
Copy Markdown
Contributor

@binoy14 binoy14 commented Mar 31, 2026

Summary

  • Moves the changeset generation logic from a ~130-line inline bash script to .github/scripts/generate-changeset.mjs
  • Adds setup-node step with Node 24
  • Identical behavior, much easier to read and maintain

Test plan

  • Verify workflow triggers correctly on a PR with conventional commit title
  • Verify changeset is generated with correct bump type and release notes
  • Verify changeset removal works for non-bump types (e.g. chore:)
  • Verify N/A release notes opt-out works

🤖 Generated with Claude Code

@binoy14 binoy14 requested a review from a team as a code owner March 31, 2026 19:53
@binoy14 binoy14 requested review from mariuslundgard and removed request for a team March 31, 2026 19:53
@claude
Copy link
Copy Markdown

claude bot commented Mar 31, 2026

Claude finished @binoy14's task in 1m 49s —— View job


Review

  • Read changed files
  • Review for issues

Two issues worth fixing:

1. spawnSync null status not handled — .github/scripts/generate-changeset.mjs:192

spawnSync returns status: null when the process is killed by a signal. The current check if (status === 0) would fall through to git commit in that case, causing a confusing error instead of propagating the real failure.

// current
if (status === 0) {
  console.log('No changes to changeset file')
  process.exit(0)
}

// fix
if (status !== 1) {
  // status 0 = no diff, null = signal-killed; either way don't commit
  console.log('No changes to changeset file')
  process.exit(status ?? 1)
}

Fix this →


2. git config sets global config instead of local — .github/scripts/generate-changeset.mjs:27-28

Without --local, git config user.name/email writes to the global ~/.gitconfig. On a shared or reused runner this could bleed into other jobs. Use --local to scope it to the repo.

git('config', '--local', 'user.name', 'ecospark[bot]')
git('config', '--local', 'user.email', 'ecospark[bot]@users.noreply.github.com')

Fix this →

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

📦 Bundle Stats — @sanity/cli

Compared against chore/auto-changeset-from-pr (22b23d00) · v6.3.1 (npm)

@sanity/cli

Metric Value vs chore/auto-changeset-from-pr (22b23d0) vs v6.3.1
Internal (raw) 2.1 KB - -
Internal (gzip) 799 B - -
Bundled (raw) 10.95 MB - +9.01 MB, +464.9%
Bundled (gzip) 2.06 MB - +1.58 MB, +331.9%
Import time 876ms +16ms, +1.9% +33ms, +3.9%

bin:sanity

Metric Value vs chore/auto-changeset-from-pr (22b23d0) vs v6.3.1
Internal (raw) 975 B - -
Internal (gzip) 460 B - -
Bundled (raw) 9.84 MB - +9.13 MB, +1287.6%
Bundled (gzip) 1.77 MB - +1.60 MB, +940.8%
Import time 2.06s +40ms, +2.0% +1.14s, +122.7% ⚠️

🗺️ View treemap · Artifacts

Details
  • Import time regressions over 10% are flagged with ⚠️
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

📦 Bundle Stats — @sanity/cli-core

Compared against chore/auto-changeset-from-pr (22b23d00) · v1.3.0 (npm)

Metric Value vs chore/auto-changeset-from-pr (22b23d0) vs v1.3.0
Internal (raw) 92.3 KB - +93 B, +0.1%
Internal (gzip) 21.6 KB - +28 B, +0.1%
Bundled (raw) 21.53 MB - +9.02 MB, +72.0%
Bundled (gzip) 3.41 MB - +1.58 MB, +85.9%
Import time 830ms +10ms, +1.2% +45ms, +5.7%

🗺️ View treemap · Artifacts

Details
  • Import time regressions over 10% are flagged with ⚠️
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

@binoy14 binoy14 marked this pull request as draft March 31, 2026 19:55
@socket-security
Copy link
Copy Markdown

socket-security bot commented Mar 31, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedgithub/​actions/​setup-node@​49933ea5288caeca8642d1e84afbd3f7d68200209910010010080

View full report

@github-actions
Copy link
Copy Markdown
Contributor

Coverage Delta

No covered files changed in this PR.

Overall Coverage

Metric Coverage
Statements 83.1% (±0%)
Branches 72.9% (±0%)
Functions 83.3% (±0%)
Lines 83.5% (±0%)

@binoy14 binoy14 force-pushed the chore/auto-changeset-from-pr branch from f0c23cb to 22b23d0 Compare April 1, 2026 04:01
@binoy14 binoy14 force-pushed the chore/generate-changeset-node-script branch from 10246fc to c0dff4b Compare April 1, 2026 04:02
binoy14 and others added 6 commits April 1, 2026 00:03
…workflow

Move the changeset generation logic from an inline bash script to
.github/scripts/generate-changeset.mjs for readability and maintainability.
Add setup-node step with Node 24.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Lazy git configuration: only write token to .git/config when actually
  pushing, not on early-exit paths
- Auto-discover scoped package dirs under packages/ instead of
  hardcoding @sanity and @repo

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Wrap readdirSync('packages') with existsSync check
- Remove GITHUB_REPOSITORY from workflow env block (already a default
  GitHub Actions env var)
- Remove it from the required env var check accordingly

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sparse-checkout the script from the base branch so that fork PRs
cannot replace generate-changeset.mjs to exfiltrate the token.

Also replace try/catch control flow with spawnSync exit code check
for the git diff --cached --quiet guard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace all execSync calls with execFileSync argument arrays to avoid
shell interpretation of untrusted input (PR_REPO is fork-controlled).
Also restore GITHUB_REPOSITORY validation and remove unused scope field.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
spawnSync returns status: null when killed by a signal. The previous
check (status === 0) would fall through to git commit in that case.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@binoy14 binoy14 force-pushed the chore/generate-changeset-node-script branch from c0dff4b to ee25bcf Compare April 1, 2026 04:03
@binoy14 binoy14 force-pushed the chore/auto-changeset-from-pr branch from 22b23d0 to ee14154 Compare April 1, 2026 04:03
@binoy14 binoy14 marked this pull request as ready for review April 1, 2026 04:10
@binoy14 binoy14 requested a review from joshuaellis April 1, 2026 04:10
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Coverage Delta

No covered files changed in this PR.

Overall Coverage

Metric Coverage
Statements 83.1% (±0%)
Branches 72.9% (±0%)
Functions 83.3% (±0%)
Lines 83.5% (±0%)

@joshuaellis
Copy link
Copy Markdown
Member

nice.

@binoy14 binoy14 merged commit 3e61406 into chore/auto-changeset-from-pr Apr 1, 2026
5 checks passed
@binoy14 binoy14 deleted the chore/generate-changeset-node-script branch April 1, 2026 12:55
binoy14 added a commit that referenced this pull request Apr 8, 2026
* feat: auto-generate changesets from PR descriptions

chore: replace release-please with changesets

* fix: allow renovate to rebase PRs with auto-generated changesets

Add ecospark[bot] to gitIgnoredAuthors so Renovate doesn't treat
changeset commits as foreign modifications that block rebasing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: replace inline bash with node script in generate-changeset workflow (#861)

* refactor: replace inline bash with node script in generate-changeset workflow

Move the changeset generation logic from an inline bash script to
.github/scripts/generate-changeset.mjs for readability and maintainability.
Add setup-node step with Node 24.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review feedback

- Lazy git configuration: only write token to .git/config when actually
  pushing, not on early-exit paths
- Auto-discover scoped package dirs under packages/ instead of
  hardcoding @sanity and @repo

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: guard readdirSync and drop redundant GITHUB_REPOSITORY env

- Wrap readdirSync('packages') with existsSync check
- Remove GITHUB_REPOSITORY from workflow env block (already a default
  GitHub Actions env var)
- Remove it from the required env var check accordingly

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent fork code execution with pull_request_target

Sparse-checkout the script from the base branch so that fork PRs
cannot replace generate-changeset.mjs to exfiltrate the token.

Also replace try/catch control flow with spawnSync exit code check
for the git diff --cached --quiet guard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: eliminate shell injection by using execFileSync

Replace all execSync calls with execFileSync argument arrays to avoid
shell interpretation of untrusted input (PR_REPO is fork-controlled).
Also restore GITHUB_REPOSITORY validation and remove unused scope field.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: handle signal-killed status in spawnSync diff check

spawnSync returns status: null when killed by a signal. The previous
check (status === 0) would fall through to git commit in that case.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Binoy Patel <me@binoy.io>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
joshuaellis added a commit that referenced this pull request Apr 9, 2026
* feat: auto-generate changesets from PR descriptions

chore: replace release-please with changesets

* fix: allow renovate to rebase PRs with auto-generated changesets

Add ecospark[bot] to gitIgnoredAuthors so Renovate doesn't treat
changeset commits as foreign modifications that block rebasing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: replace inline bash with node script in generate-changeset workflow (#861)

* refactor: replace inline bash with node script in generate-changeset workflow

Move the changeset generation logic from an inline bash script to
.github/scripts/generate-changeset.mjs for readability and maintainability.
Add setup-node step with Node 24.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review feedback

- Lazy git configuration: only write token to .git/config when actually
  pushing, not on early-exit paths
- Auto-discover scoped package dirs under packages/ instead of
  hardcoding @sanity and @repo

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: guard readdirSync and drop redundant GITHUB_REPOSITORY env

- Wrap readdirSync('packages') with existsSync check
- Remove GITHUB_REPOSITORY from workflow env block (already a default
  GitHub Actions env var)
- Remove it from the required env var check accordingly

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent fork code execution with pull_request_target

Sparse-checkout the script from the base branch so that fork PRs
cannot replace generate-changeset.mjs to exfiltrate the token.

Also replace try/catch control flow with spawnSync exit code check
for the git diff --cached --quiet guard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: eliminate shell injection by using execFileSync

Replace all execSync calls with execFileSync argument arrays to avoid
shell interpretation of untrusted input (PR_REPO is fork-controlled).
Also restore GITHUB_REPOSITORY validation and remove unused scope field.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: handle signal-killed status in spawnSync diff check

spawnSync returns status: null when killed by a signal. The previous
check (status === 0) would fall through to git commit in that case.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Binoy Patel <me@binoy.io>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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