44 push :
55 branches :
66 - main
7- paths :
8- - ' packages/**'
9- - ' .github/workflows/release.yml'
107 workflow_dispatch :
11- inputs :
12- force_release :
13- description : ' Force release of packages (comma-separated, e.g. "mcp,test-utils")'
14- required : false
15- type : string
16- force_version :
17- description : ' Force specific version (leave empty to auto-increment)'
18- required : false
19- type : string
208
219jobs :
2210 release :
11+ name : Release
12+ runs-on : ubuntu-latest
2313 permissions :
2414 contents : write
2515 packages : write
26- id-token : write
27- timeout-minutes : 15
28- runs-on : ubuntu-latest
16+ pull-requests : write
2917 steps :
3018 - name : Checkout
3119 uses : actions/checkout@v4
3220 with :
3321 fetch-depth : 0
34- token : ${{ secrets.GITHUB_TOKEN }}
35-
22+
3623 - name : Setup Node.js
3724 uses : actions/setup-node@v4
3825 with :
3926 node-version : ' 22'
4027 cache : ' yarn'
4128 registry-url : ' https://registry.npmjs.org'
4229
43- - name : Install dependencies
44- run : yarn install --frozen-lockfile
45-
4630 - name : Configure npm
4731 run : |
4832 echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
4933 npm config set access public
5034
35+ - name : Install dependencies
36+ run : yarn install --frozen-lockfile
37+
5138 - name : Build packages
5239 run : yarn build
5340
5441 - name : Test packages
5542 run : yarn test
56-
57- - name : Detect changed packages
58- id : changed_packages
59- run : |
60- # Create a JSON array of packages
61- PACKAGES_JSON=$(find packages -type f -name "package.json" -not -path "*/node_modules/*" |
62- grep -o 'packages/[^/]*' |
63- sort |
64- uniq |
65- jq -R -s -c 'split("\n")[:-1]')
66- echo "packages=$PACKAGES_JSON" >> $GITHUB_OUTPUT
67-
68- # Also create a space-separated list for shell usage
69- CHANGED_PACKAGES=$(find packages -type f -name "package.json" -not -path "*/node_modules/*" |
70- grep -o 'packages/[^/]*' |
71- sort |
72- uniq)
7343
74- # Format for summary
75- echo "## Packages to be released" >> $GITHUB_STEP_SUMMARY
76- echo "" >> $GITHUB_STEP_SUMMARY
77- for PKG in $CHANGED_PACKAGES; do
78- echo "- $PKG" >> $GITHUB_STEP_SUMMARY
79- done
80- echo "" >> $GITHUB_STEP_SUMMARY
81-
82- - name : Setup Git
83- run : |
84- git config --global user.name 'github-actions[bot]'
85- git config --global user.email 'github-actions[bot]@users.noreply.github.com'
86-
87- - name : Release with semantic-release
44+ - name : Create Release Pull Request or Publish to npm
45+ id : changesets
46+ uses : changesets/action@v1
47+ with :
48+ publish : yarn changeset publish
49+ commit : " chore(release): version packages"
50+ title : " chore(release): version packages"
8851 env :
89- NPM_TOKEN : ${{ secrets.NPM_TOKEN }}
90- NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
9152 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
92- CHANGED_PACKAGES : ${{ steps.changed_packages.outputs.packages }}
93- FORCE_RELEASE : ${{ github.event.inputs.force_release }}
94- FORCE_VERSION : ${{ github.event.inputs.force_version }}
95- run : |
96- # Convert JSON array back to space-separated list for shell processing
97- PACKAGES_LIST=$(echo '${{ steps.changed_packages.outputs.packages }}' | jq -r 'join(" ")')
98-
99- # Release each changed package
100- RELEASE_SUMMARY=""
101- for PKG in $PACKAGES_LIST; do
102- echo "Publishing package: $PKG"
103- cd $PKG
104-
105- # Extract package name from package.json
106- PACKAGE_NAME=$(node -p "require('./package.json').name")
107- # Get current version
108- CURRENT_VERSION=$(node -p "require('./package.json').version")
109-
110- # Check if .releaserc.json exists, create if not
111- if [ ! -f .releaserc.json ]; then
112- echo "Creating .releaserc.json from template"
113- cp ../../.github/release-template.json .releaserc.json
114- fi
115-
116- # Check if this package is in the FORCE_RELEASE list
117- PACKAGE_SHORT_NAME=$(echo $PKG | sed 's|packages/||')
118- FORCE_THIS_PACKAGE=false
119- if [[ -n "$FORCE_RELEASE" && "$FORCE_RELEASE" == *"$PACKAGE_SHORT_NAME"* ]]; then
120- FORCE_THIS_PACKAGE=true
121- echo "Force release enabled for $PACKAGE_NAME"
122- fi
123-
124- # Unified versioning logic for all packages
125- # Check if package exists on npm yet
126- PACKAGE_EXISTS=$(npm view $PACKAGE_NAME version 2>/dev/null || echo "")
127-
128- if [[ -z "$PACKAGE_EXISTS" || "$FORCE_THIS_PACKAGE" == "true" ]]; then
129- # First-time publishing or forced release
130- if [[ -n "$FORCE_VERSION" ]]; then
131- # Use forced version if provided
132- NEW_VERSION="$FORCE_VERSION"
133- npm version $NEW_VERSION --no-git-tag-version --allow-same-version
134- echo "Forcing version $NEW_VERSION for $PACKAGE_NAME"
135- elif [[ "$CURRENT_VERSION" == 0.* ]]; then
136- # For packages starting with 0.x.x, extract and increment the patch version
137- MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1)
138- MINOR=$(echo $CURRENT_VERSION | cut -d. -f2)
139- PATCH=$(echo $CURRENT_VERSION | cut -d. -f3)
140- NEXT_PATCH=$((PATCH + 1))
141- NEW_VERSION="$MAJOR.$MINOR.$NEXT_PATCH"
142- npm version $NEW_VERSION --no-git-tag-version
143- echo "Incrementing version to $NEW_VERSION for $PACKAGE_NAME"
144- else
145- # For packages with version >= 1.0.0, increment patch
146- MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1)
147- MINOR=$(echo $CURRENT_VERSION | cut -d. -f2)
148- PATCH=$(echo $CURRENT_VERSION | cut -d. -f3)
149- NEXT_PATCH=$((PATCH + 1))
150- NEW_VERSION="$MAJOR.$MINOR.$NEXT_PATCH"
151- npm version $NEW_VERSION --no-git-tag-version
152- echo "Incrementing version to $NEW_VERSION for $PACKAGE_NAME"
153- fi
154-
155- if [[ "$FORCE_THIS_PACKAGE" == "true" ]]; then
156- # Force publish without checking for changes
157- echo "Running semantic-release with force flag for $PACKAGE_NAME"
158- RELEASE_OUTPUT=$(npx semantic-release --branches main --no-ci 2>&1 || true)
159- else
160- # First-time publishing
161- echo "First-time publishing $PACKAGE_NAME at version $CURRENT_VERSION"
162- RELEASE_OUTPUT=$(npx semantic-release --branches main --no-ci --first-release 2>&1 || true)
163- fi
164- else
165- # Package exists - determine version increment
166- # Get existing versions
167- PREV_RELEASE=$(npm view $PACKAGE_NAME versions --json 2>/dev/null || echo "[]")
168-
169- # Determine if we need to bump version based on commit history
170- BUMP_TYPE=$(npx semantic-release --dry-run --branches main 2>&1 | grep -o "The next release version is" | wc -l)
171-
172- if [[ $BUMP_TYPE -gt 0 || "$FORCE_THIS_PACKAGE" == "true" ]]; then
173- # Changes detected or force flag enabled
174- if [[ -n "$FORCE_VERSION" ]]; then
175- # Use forced version if provided
176- NEW_VERSION="$FORCE_VERSION"
177- else
178- # Try to get recommended bump type based on commits
179- NEXT_VERSION_TYPE=$(npx semantic-release --dry-run --branches main 2>&1 | grep -o "release type: \\w\\+" | cut -d " " -f 3 || echo "patch")
180-
181- # Default to patch if we couldn't determine the type
182- if [[ -z "$NEXT_VERSION_TYPE" ]]; then
183- NEXT_VERSION_TYPE="patch"
184- fi
185-
186- # Current version components
187- CURRENT_MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1)
188- CURRENT_MINOR=$(echo $CURRENT_VERSION | cut -d. -f2)
189- CURRENT_PATCH=$(echo $CURRENT_VERSION | cut -d. -f3)
190-
191- # Calculate next version properly depending on current major version
192- if [[ "$CURRENT_MAJOR" == "0" ]]; then
193- # For 0.x versions
194- if [[ "$NEXT_VERSION_TYPE" == "major" || "$NEXT_VERSION_TYPE" == "minor" || "$FORCE_THIS_PACKAGE" == "true" ]]; then
195- # For a major or minor bump in 0.x, increment the minor (0.x.y -> 0.[x+1].0)
196- NEXT_MINOR=$((CURRENT_MINOR + 1))
197- NEW_VERSION="0.$NEXT_MINOR.0"
198- else
199- # For a patch bump, increment patch (0.x.y -> 0.x.[y+1])
200- NEXT_PATCH=$((CURRENT_PATCH + 1))
201- NEW_VERSION="0.$CURRENT_MINOR.$NEXT_PATCH"
202- fi
203- else
204- # For 1.x and above, follow standard semver
205- if [[ "$NEXT_VERSION_TYPE" == "major" ]]; then
206- NEXT_MAJOR=$((CURRENT_MAJOR + 1))
207- NEW_VERSION="$NEXT_MAJOR.0.0"
208- elif [[ "$NEXT_VERSION_TYPE" == "minor" ]]; then
209- NEXT_MINOR=$((CURRENT_MINOR + 1))
210- NEW_VERSION="$CURRENT_MAJOR.$NEXT_MINOR.0"
211- else
212- NEXT_PATCH=$((CURRENT_PATCH + 1))
213- NEW_VERSION="$CURRENT_MAJOR.$CURRENT_MINOR.$NEXT_PATCH"
214- fi
215- fi
216- fi
217-
218- # Set this version in package.json
219- npm version $NEW_VERSION --no-git-tag-version --allow-same-version
220- echo "Bumping $PACKAGE_NAME version to $NEW_VERSION"
221- RELEASE_OUTPUT=$(npx semantic-release --branches main --no-ci 2>&1 || true)
222- else
223- # No changes requiring version bump and not forcing
224- echo "No changes detected requiring version bump for $PACKAGE_NAME"
225- RELEASE_OUTPUT="No changes requiring release detected"
226- fi
227- fi
228- echo "$RELEASE_OUTPUT"
229-
230- # Extract new version if available
231- if echo "$RELEASE_OUTPUT" | grep -q "Publishing version"; then
232- NEW_VERSION=$(echo "$RELEASE_OUTPUT" | grep "Publishing version" | sed -E 's/.*Publishing version ([0-9]+\.[0-9]+\.[0-9]+).*/\1/')
233- echo "Successfully published $PKG@$NEW_VERSION (was $CURRENT_VERSION)"
234- RELEASE_SUMMARY="$RELEASE_SUMMARY\n### $PKG\n- Published: v$NEW_VERSION (was v$CURRENT_VERSION)\n"
235- else
236- echo "No new version to release for $PKG"
237- RELEASE_SUMMARY="$RELEASE_SUMMARY\n### $PKG\n- No release needed (current: v$CURRENT_VERSION)\n"
238- fi
239-
240- cd ../../
241- done
242-
243- # Output summary
244- echo -e "$RELEASE_SUMMARY" >> $GITHUB_STEP_SUMMARY
245-
246- - name : Output release status
247- run : |
248- echo "✅ Release process completed" >> $GITHUB_STEP_SUMMARY
249- echo "" >> $GITHUB_STEP_SUMMARY
250- echo "Packages have been published to npm." >> $GITHUB_STEP_SUMMARY
53+ NPM_TOKEN : ${{ secrets.NPM_TOKEN }}
0 commit comments