Skip to content

Commit f35ff1c

Browse files
committed
chore: Replace manual publish with changesets
- Add @changesets/cli for per-package versioning - Replace workflow_dispatch release.yml with changesets/action (Version Packages PR on push to main → publish on merge) - releaseType input is replaced by changeset files: pnpm changeset picks which packages + what bump - Only packages with pending changesets get published
1 parent ced2c3f commit f35ff1c

6 files changed

Lines changed: 712 additions & 44 deletions

File tree

‎.changeset/README.md‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Changesets
2+
3+
This project uses [changesets](https://github.com/changesets/changesets) for per-package versioning and publishing.
4+
5+
## Creating a changeset
6+
7+
When you make a change that needs a version bump, run:
8+
9+
```bash
10+
pnpm changeset
11+
```
12+
13+
You'll be prompted to:
14+
1. **Select packages** — pick which packages changed (space to select, enter to confirm)
15+
2. **Choose bump** — `patch`, `minor`, or `major` per package
16+
3. **Describe the change** — a short summary that becomes the CHANGELOG entry
17+
18+
A markdown file is created in `.changeset/`. Commit it with your PR.
19+
20+
## How releases work
21+
22+
1. **PRs land on `main`** with their changeset files.
23+
2. The **Release workflow** detects changesets on `main` and opens (or updates) a "Version Packages" PR.
24+
3. That PR consumes the changesets, bumps the affected `package.json` versions, and writes per-package `CHANGELOG.md` entries.
25+
4. **Merge the Version Packages PR** → the same workflow builds and runs `pnpm -r publish` for every package whose version isn't on the registry.
26+
27+
Only the packages with pending changesets get bumped and published — not everything.
28+
29+
## Config
30+
31+
`.changeset/config.json` — `access: public`, tracks all non-private workspace packages.
32+
`.github/workflows/release.yml` — `changesets/action` handles the PR → version → publish cycle.

‎.changeset/changeset-gen.sh‎

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/bin/bash
2+
# Generate a changeset file from conventional commits since the last tag.
3+
# Usage: ./.changeset/changeset-gen.sh <package> [bump]
4+
#
5+
# package: npm name, e.g. @wdio/elements
6+
# bump: major | minor | patch (inferred from commits if omitted)
7+
#
8+
# Commits are filtered to only those that touched the package's directory.
9+
# Inferred bumps: feat/feature → minor, BREAKING CHANGE → major, else patch.
10+
# Changelog body groups commits by type (Features / Fixes / Improvements).
11+
# chore, ci, test, build, and deps commits are excluded from the body.
12+
13+
set -euo pipefail
14+
15+
PACKAGE="${1:-}"
16+
BUMP="${2:-}"
17+
18+
if [ -z "$PACKAGE" ]; then
19+
echo "Usage: $0 <package> [bump]"
20+
echo " package: npm name, e.g. @wdio/elements"
21+
echo " bump: major | minor | patch (inferred from commits if omitted)"
22+
exit 1
23+
fi
24+
25+
# ---- Resolve package name to directory ----
26+
PKG_DIR=""
27+
for d in packages/*/package.json; do
28+
if [ "$(jq -r '.name' "$d")" = "$PACKAGE" ]; then
29+
PKG_DIR="$(dirname "$d")"
30+
break
31+
fi
32+
done
33+
34+
if [ -z "$PKG_DIR" ]; then
35+
echo "❌ Package '$PACKAGE' not found in packages/*/package.json"
36+
exit 1
37+
fi
38+
39+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null) || { echo "No git tags found"; exit 1; }
40+
COMMITS=$(git log "$LAST_TAG"..HEAD --format="%s" --no-merges -- "$PKG_DIR")
41+
42+
if [ -z "$COMMITS" ]; then
43+
echo "No commits touching $PKG_DIR since $LAST_TAG"
44+
exit 0
45+
fi
46+
47+
# ---- Infer bump type ----
48+
if [ -z "$BUMP" ]; then
49+
if echo "$COMMITS" | grep -q "BREAKING CHANGE"; then
50+
BUMP="major"
51+
elif echo "$COMMITS" | grep -qiE "^(feat|feature)[(:]"; then
52+
BUMP="minor"
53+
else
54+
BUMP="patch"
55+
fi
56+
fi
57+
58+
# ---- Group commits by type, stripping the conventional prefix ----
59+
# Include: feat, fix, refactor, perf, revert
60+
# Exclude: chore, ci, test, build, docs, style, deps
61+
62+
strip_prefix() { sed -E 's/^[a-z]+(\([^)]*\))?:\s*//i'; }
63+
64+
FEATS=$(echo "$COMMITS" | grep -iE "^(feat|feature)[(:]" | strip_prefix || true)
65+
FIXES=$(echo "$COMMITS" | grep -iE "^(fix)[(:]" | strip_prefix || true)
66+
PERF=$(echo "$COMMITS" | grep -iE "^(perf|performance)[(:]" | strip_prefix || true)
67+
REFAC=$(echo "$COMMITS" | grep -iE "^(refactor)[(:]" | strip_prefix || true)
68+
REVERT=$(echo "$COMMITS" | grep -iE "^(revert)[(:]" | strip_prefix || true)
69+
70+
# ---- Generate the changeset file ----
71+
SLUG=$(date +%s)-$(($$ % 10000))-$(openssl rand -hex 2 2>/dev/null || echo "$RANDOM")
72+
OUT=".changeset/$SLUG.md"
73+
74+
{
75+
echo "---"
76+
echo "\"$PACKAGE\": $BUMP"
77+
echo "---"
78+
echo ""
79+
80+
if [ -n "$FEATS" ]; then
81+
echo "### 🚀 Features"
82+
while IFS= read -r line; do [ -n "$line" ] && echo "- $line"; done <<< "$FEATS"
83+
echo ""
84+
fi
85+
86+
if [ -n "$FIXES" ]; then
87+
echo "### 🐛 Fixes"
88+
while IFS= read -r line; do [ -n "$line" ] && echo "- $line"; done <<< "$FIXES"
89+
echo ""
90+
fi
91+
92+
if [ -n "$PERF" ] || [ -n "$REFAC" ]; then
93+
echo "### ⚡ Improvements"
94+
while IFS= read -r line; do [ -n "$line" ] && echo "- $line"; done <<< "$PERF"
95+
while IFS= read -r line; do [ -n "$line" ] && echo "- $line"; done <<< "$REFAC"
96+
echo ""
97+
fi
98+
99+
if [ -n "$REVERT" ]; then
100+
echo "### ↩ Reverts"
101+
while IFS= read -r line; do [ -n "$line" ] && echo "- $line"; done <<< "$REVERT"
102+
echo ""
103+
fi
104+
105+
} > "$OUT"
106+
107+
echo "✅ $OUT (bump: $BUMP, scope: $PKG_DIR)"
108+
echo ""
109+
echo "--- Preview ---"
110+
cat "$OUT"

‎.changeset/config.json‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json",
3+
"changelog": "@changesets/cli/changelog",
4+
"commit": true,
5+
"fixed": [],
6+
"linked": [],
7+
"access": "public",
8+
"baseBranch": "main",
9+
"updateInternalDependencies": "patch",
10+
"ignore": []
11+
}

‎.github/workflows/release.yml‎

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,10 @@ name: Manual NPM Publish
33
on:
44
workflow_dispatch:
55
inputs:
6-
releaseType:
7-
description: "Release Type"
8-
required: true
9-
type: choice
10-
default: "patch"
11-
options:
12-
- patch
13-
- minor
14-
- major
156
distTag:
167
description: 'NPM tag (e.g. use "next" to release a test version)'
17-
required: true
8+
required: false
9+
type: string
1810
default: 'latest'
1911

2012
env:
@@ -47,7 +39,13 @@ jobs:
4739
run: pnpm install
4840
- name: Build
4941
run: pnpm -r build
50-
- name: Release
51-
run: pnpm -r publish --access public --no-git-checks
42+
- name: Consume changesets and publish
43+
run: |
44+
npx changeset version
45+
npx changeset publish --tag "$DIST_TAG"
46+
git push origin main --follow-tags
5247
env:
5348
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
49+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
50+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
51+
DIST_TAG: ${{ inputs.distTag }}

‎package.json‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"test:ui": "vitest --ui",
1515
"test:debug": "node --inspect-brk ./node_modules/.bin/vitest run",
1616
"lint": "pnpm --parallel lint",
17-
"watch": "pnpm build --watch"
17+
"watch": "pnpm build --watch",
18+
"changeset:gen": "bash .changeset/changeset-gen.sh"
1819
},
1920
"pnpm": {
2021
"overrides": {
@@ -27,6 +28,7 @@
2728
]
2829
},
2930
"devDependencies": {
31+
"@changesets/cli": "^2.31.0",
3032
"@eslint/js": "^10.0.1",
3133
"@types/node": "25.9.3",
3234
"@typescript-eslint/eslint-plugin": "^8.60.1",

0 commit comments

Comments
 (0)