name: Bump version + release on: push: branches: [master] paths-ignore: - "packages/electron/package.json" - "*.md" workflow_dispatch: concurrency: group: bump-version cancel-in-progress: false permissions: contents: write actions: write jobs: bump: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Check for new commits since last tag id: check run: | LAST_TAG=$(git tag --sort=-v:refname | grep '^v' | head -1 || echo "") if [ -z "$LAST_TAG" ]; then echo "No previous tag, skipping" echo "skip=true" >> "$GITHUB_OUTPUT" exit 0 fi # Count non-merge, non-chore commits since last tag NEW_COMMITS=$(git log "${LAST_TAG}..HEAD" --no-merges \ --pretty=format:"%s" | grep -cvE "^(chore|docs|ci)" || true) if [ "$NEW_COMMITS" -eq 0 ]; then echo "No meaningful commits since $LAST_TAG, skipping" echo "skip=true" >> "$GITHUB_OUTPUT" exit 0 fi echo "Found $NEW_COMMITS new commit(s) since $LAST_TAG" echo "skip=false" >> "$GITHUB_OUTPUT" echo "last_tag=$LAST_TAG" >> "$GITHUB_OUTPUT" - name: Bump version + tag id: bump if: steps.check.outputs.skip != 'true' run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" LAST_TAG="${{ steps.check.outputs.last_tag }}" CURRENT="${LAST_TAG#v}" IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT" NEW_PATCH=$((PATCH + 1)) NEW_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}" NEW_TAG="v${NEW_VERSION}" # Check tag doesn't already exist if git rev-parse "$NEW_TAG" >/dev/null 2>&1; then echo "Tag $NEW_TAG already exists, skipping" exit 0 fi # Bump both root and electron package versions node -e " const fs = require('fs'); for (const p of ['package.json', 'packages/electron/package.json']) { const pkg = JSON.parse(fs.readFileSync(p, 'utf-8')); pkg.version = '${NEW_VERSION}'; fs.writeFileSync(p, JSON.stringify(pkg, null, 2) + '\n'); } " git add package.json packages/electron/package.json git commit -m "chore: bump version to ${NEW_VERSION} [skip ci]" git tag -a "$NEW_TAG" -m "Release ${NEW_TAG}" # Retry push with rebase on conflict (other workflows may push concurrently) for i in 1 2 3; do if git push origin master --follow-tags; then echo "Bumped to $NEW_VERSION, tagged $NEW_TAG" echo "new_tag=$NEW_TAG" >> "$GITHUB_OUTPUT" exit 0 fi echo "Push failed (attempt $i/3), rebasing and retrying..." git tag -d "$NEW_TAG" git pull --rebase origin master git tag -a "$NEW_TAG" -m "Release ${NEW_TAG}" sleep 2 done echo "::error::Push failed after 3 attempts" exit 1 - name: Trigger release workflow if: steps.bump.outputs.new_tag run: | echo "Dispatching release for $NEW_TAG" gh workflow run release.yml -f tag="$NEW_TAG" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} NEW_TAG: ${{ steps.bump.outputs.new_tag }}