feat: auto-generate changesets from PR descriptions#828
Conversation
|
Claude finished @binoy14's task in 2m 29s —— View job Code Review
|
📦 Bundle Stats —
|
| Metric | Value | vs main (8960e68) | 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 | 823ms | -10ms, -1.2% | +20ms, +2.5% |
bin:sanity
| Metric | Value | vs main (8960e68) | 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 | 1.92s | -3ms, -0.2% | +1.04s, +118.3% |
🗺️ 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 main (8960e68e) · v1.3.0 (npm)
| Metric | Value | vs main (8960e68) | 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 | 781ms | -3ms, -0.4% | +43ms, +5.9% |
🗺️ 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.
e3604c3 to
052d17c
Compare
4c59c39 to
356ecd4
Compare
356ecd4 to
b001dc7
Compare
052d17c to
b704592
Compare
4da6e80 to
d85643b
Compare
b704592 to
47677a0
Compare
d85643b to
11688f6
Compare
47677a0 to
e55bd40
Compare
7ba88aa to
7c58f23
Compare
7c58f23 to
ebdc691
Compare
f0c23cb to
22b23d0
Compare
chore: replace release-please with 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>
22b23d0 to
ee14154
Compare
…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>
📦 Bundle Stats —
|
| Metric | Value | vs main (8960e68) |
|---|---|---|
| Internal (raw) | 2.1 KB | - |
| Internal (gzip) | 799 B | - |
| Bundled (raw) | 10.95 MB | - |
| Bundled (gzip) | 2.06 MB | - |
| Import time | 829ms | -14ms, -1.6% |
bin:sanity
| Metric | Value | vs main (8960e68) |
|---|---|---|
| Internal (raw) | 975 B | - |
| Internal (gzip) | 460 B | - |
| Bundled (raw) | 9.84 MB | - |
| Bundled (gzip) | 1.77 MB | - |
| Import time | 1.97s | -40ms, -2.0% |
🗺️ 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 main (8960e68e)
| Metric | Value | vs main (8960e68) |
|---|---|---|
| Internal (raw) | 92.3 KB | - |
| Internal (gzip) | 21.6 KB | - |
| Bundled (raw) | 21.53 MB | - |
| Bundled (gzip) | 3.41 MB | - |
| Import time | 790ms | -8ms, -1.0% |
🗺️ 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 — create-sanity
Compared against main (8960e68e)
| Metric | Value | vs main (8960e68) |
|---|---|---|
| Internal (raw) | 976 B | - |
| Internal (gzip) | 507 B | - |
| Bundled (raw) | 50.7 KB | - |
| Bundled (gzip) | 12.6 KB | - |
| Import time | ❌ ChildProcess denied: node | - |
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.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Coverage DeltaNo covered files changed in this PR. Overall Coverage
|
* 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>

Summary
Auto-generate changeset files from PR descriptions so contributors never need to run
pnpm changesetmanually. Adds a PR description template and a workflow that parses it to create changesets automatically.Stacked on #827.
How It Works
When a PR is opened or updated, the
generate-changesetworkflow:feat:→ minor,fix:→ patch,feat!:→ major)packages/*/package.json.changeset/pr-<number>.md) to the PR branchThe changeset is kept in sync — if the PR title or description changes, the changeset is updated or removed accordingly.
feat:title + release notes filled infeat:title + release notes emptychore:/docs:/test:titleN/Achangesets-from-conventional-commits.ymlSecurity
Uses
pull_request_targetto get write access for pushing changesets to PR branches. The workflow YAML runs frommain(not the PR), and PR title/body are passed as environment variables — never interpolated into shell commands. No code from the PR is executed.