248248run () {
249249 if $DRY_RUN ; then
250250 echo " [dry-run] $* "
251+ return 0
252+ fi
253+
254+ " $@ "
255+ }
256+
257+ # Portable in-place sed (BSD/macOS vs GNU/Linux)
258+ # - macOS/BSD sed requires: sed -i '' -E 's/.../.../' file
259+ # - GNU sed requires: sed -i -E 's/.../.../' file
260+ sed_inplace () {
261+ local expr=" $1 "
262+ local file=" $2 "
263+
264+ if sed --version > /dev/null 2>&1 ; then
265+ # GNU sed
266+ sed -i -E " $expr " " $file "
251267 else
252- eval " $@ "
268+ # BSD/macOS sed
269+ sed -i ' ' -E " $expr " " $file "
253270 fi
254271}
255272
256273# Ensure we're in the project root (parent of scripts directory)
257274cd " $( dirname " $0 " ) /.."
258275
259- # Check if working directory is clean
260- if ! git diff-index --quiet HEAD --; then
261- echo " ❌ Error: Working directory is not clean."
262- echo " Please commit or stash your changes before creating a release."
263- exit 1
276+ # Check if working directory is clean (only enforced for real runs)
277+ if ! $DRY_RUN ; then
278+ if ! git diff-index --quiet HEAD --; then
279+ echo " ❌ Error: Working directory is not clean."
280+ echo " Please commit or stash your changes before creating a release."
281+ exit 1
282+ fi
283+ else
284+ if ! git diff-index --quiet HEAD --; then
285+ echo " ⚠️ Dry-run: working directory is not clean (continuing)."
286+ fi
264287fi
265288
266289# Check if package.json already has this version (from previous attempt)
@@ -276,23 +299,25 @@ if [[ "$SKIP_VERSION_UPDATE" == "false" ]]; then
276299 # Version update
277300 echo " "
278301 echo " 🔧 Setting version to $VERSION ..."
279- run " npm version \ "$VERSION \ " --no-git-tag-version"
302+ run npm version " $VERSION " --no-git-tag-version
280303
281304 # README update
282305 echo " "
283306 echo " 📝 Updating version in README.md..."
284307 # Update version references in code examples using extended regex for precise semver matching
285- run " sed -i '' -E 's/@[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+\.[0-9]+)?(-[a-zA-Z0-9]+\.[0-9]+)*(-[a-zA-Z0-9]+)?/@'" $VERSION " '/g' README.md"
308+ README_AT_SEMVER_REGEX=' @[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+\.[0-9]+)?(-[a-zA-Z0-9]+\.[0-9]+)*(-[a-zA-Z0-9]+)?'
309+ run sed_inplace " s/${README_AT_SEMVER_REGEX} /@${VERSION} /g" README.md
286310
287311 # Update URL-encoded version references in shield links
288312 echo " 📝 Updating version in README.md shield links..."
289- run " sed -i '' -E 's/npm%3Axcodebuildmcp%40[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+\.[0-9]+)?(-[a-zA-Z0-9]+\.[0-9]+)*(-[a-zA-Z0-9]+)?/npm%3Axcodebuildmcp%40'" $VERSION " '/g' README.md"
313+ README_URLENCODED_NPM_AT_SEMVER_REGEX=' npm%3Axcodebuildmcp%40[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+\.[0-9]+)?(-[a-zA-Z0-9]+\.[0-9]+)*(-[a-zA-Z0-9]+)?'
314+ run sed_inplace " s/${README_URLENCODED_NPM_AT_SEMVER_REGEX} /npm%3Axcodebuildmcp%40${VERSION} /g" README.md
290315
291316 # server.json update
292317 echo " "
293318 if [[ -f server.json ]]; then
294319 echo " 📝 Updating server.json version to $VERSION ..."
295- run " node -e \ " const fs=require('fs');const f='server.json';const j=JSON.parse(fs.readFileSync(f,'utf8'));j.version='$VERSION ';if(Array.isArray(j.packages)){j.packages=j.packages.map(p=>({...p,version:'$VERSION '}));}fs.writeFileSync(f,JSON.stringify(j,null,2)+'\n');\" "
320+ run node -e " const fs=require('fs');const f='server.json';const j=JSON.parse(fs.readFileSync(f,'utf8'));j.version='${ VERSION} ';if(Array.isArray(j.packages)){j.packages=j.packages.map(p=>({...p,version:'${ VERSION} '}));}fs.writeFileSync(f,JSON.stringify(j,null,2)+'\n');"
296321 else
297322 echo " ⚠️ server.json not found; skipping update"
298323 fi
@@ -301,32 +326,39 @@ if [[ "$SKIP_VERSION_UPDATE" == "false" ]]; then
301326 echo " "
302327 echo " 📦 Committing version changes..."
303328 if [[ -f server.json ]]; then
304- run " git add package.json README.md server.json"
329+ run git add package.json README.md server.json
305330 else
306- run " git add package.json README.md"
331+ run git add package.json README.md
307332 fi
308- run " git commit -m \ " Release v$VERSION \" "
333+ run git commit -m " Release v$VERSION "
309334else
310335 echo " ⏭️ Skipping version update (already done)"
311336 # Ensure server.json still matches the desired version (in case of a partial previous run)
312337 if [[ -f server.json ]]; then
313338 CURRENT_SERVER_VERSION=$( node -e " console.log(JSON.parse(require('fs').readFileSync('server.json','utf8')).version||'')" )
314339 if [[ " $CURRENT_SERVER_VERSION " != " $VERSION " ]]; then
315340 echo " 📝 Aligning server.json to $VERSION ..."
316- run " node -e \ " const fs=require('fs');const f='server.json';const j=JSON.parse(fs.readFileSync(f,'utf8'));j.version='$VERSION ';if(Array.isArray(j.packages)){j.packages=j.packages.map(p=>({...p,version:'$VERSION '}));}fs.writeFileSync(f,JSON.stringify(j,null,2)+'\\ n');\" "
317- run " git add server.json"
318- run " git commit -m \ " Align server.json for v$VERSION \" "
341+ run node -e " const fs=require('fs');const f='server.json';const j=JSON.parse(fs.readFileSync(f,'utf8'));j.version='${ VERSION} ';if(Array.isArray(j.packages)){j.packages=j.packages.map(p=>({...p,version:'${ VERSION} '}));}fs.writeFileSync(f,JSON.stringify(j,null,2)+'\n');"
342+ run git add server.json
343+ run git commit -m " Align server.json for v$VERSION "
319344 fi
320345 fi
321346fi
322347
323348# Create or recreate tag at current HEAD
324349echo " 🏷️ Creating tag v$VERSION ..."
325- run " git tag -f \ " v$VERSION \" "
350+ run git tag -f " v$VERSION "
326351
327352echo " "
328353echo " 🚀 Pushing to origin..."
329- run " git push origin $BRANCH --tags"
354+ run git push origin " $BRANCH " --tags
355+
356+ # In dry-run, stop here (don't monitor workflows, and don't claim a release happened).
357+ if $DRY_RUN ; then
358+ echo " "
359+ echo " ℹ️ Dry-run: skipping GitHub Actions workflow monitoring."
360+ exit 0
361+ fi
330362
331363# Monitor the workflow and handle failures
332364echo " "
0 commit comments