diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..efaee21fa --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,86 @@ +name: Weekly Release + +on: + # TODO(sambhav-jain-16): enable the schedule after testing manually + # schedule: + # - cron: '0 0 * * 1' # Every Monday at 00:00 UTC + workflow_dispatch: + inputs: + release_type: + description: 'Bump type for this run. auto = scan commit messages since last tag for release-type: minor/major markers (present in squash-merge commit bodies), falling back to patch.' + required: false + type: choice + options: + - auto + - patch + - minor + - major + default: auto + +permissions: + contents: write + +env: + RELEASE_TYPE: ${{ github.event.inputs.release_type || 'auto' }} + +concurrency: + group: release + cancel-in-progress: false + +jobs: + release: + name: Create Release + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/master' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Compute release git context + id: release_context + run: make -s release-context >> "$GITHUB_OUTPUT" + + # Auto path: scan commit messages since last tag for release-type markers. + # Markers in PR bodies are included in squash-merge commit messages. + - name: Bump version and create tag + id: tag_auto + if: steps.release_context.outputs.has_changes == 'true' && env.RELEASE_TYPE == 'auto' + uses: mathieudutour/github-tag-action@v6.2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + default_bump: patch + major_string_token: 'release-type: major' + minor_string_token: 'release-type: minor' + patch_string_token: 'release-type: patch' + release_branches: master + + # Explicit path: manual override, bypass keyword detection. + - name: Compute next version + id: next_version + if: steps.release_context.outputs.has_changes == 'true' && github.event_name == 'workflow_dispatch' && env.RELEASE_TYPE != 'auto' + uses: actions-ecosystem/action-bump-semver@v1 + with: + current_version: ${{ steps.release_context.outputs.base_version }} + level: ${{ env.RELEASE_TYPE }} + + - name: Create tag for manual override + id: tag_explicit + if: steps.release_context.outputs.has_changes == 'true' && github.event_name == 'workflow_dispatch' && env.RELEASE_TYPE != 'auto' + uses: mathieudutour/github-tag-action@v6.2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + custom_tag: ${{ steps.next_version.outputs.new_version }} + release_branches: master + + - name: Create GitHub release + if: steps.release_context.outputs.has_changes == 'true' + uses: softprops/action-gh-release@v3 + with: + tag_name: ${{ steps.tag_auto.outputs.new_tag || steps.tag_explicit.outputs.new_tag }} + name: Release ${{ steps.tag_auto.outputs.new_tag || steps.tag_explicit.outputs.new_tag }} + generate_release_notes: true + + - name: No new commits, skipping release + if: steps.release_context.outputs.has_changes == 'false' + run: echo "Skipping - no commits since last tag." diff --git a/Makefile b/Makefile index 4b2d8c06f..20cc831a0 100644 --- a/Makefile +++ b/Makefile @@ -176,6 +176,28 @@ TOOLS = \ .PHONY: tools tools: $(NATIVE_TOOLS) +# Computes release git context. +.PHONY: release-context +release-context: + @set -eu; \ + latest_tag=$$(git describe --tags --abbrev=0 2>/dev/null || true); \ + if [ -n "$$latest_tag" ]; then \ + base_version="$$latest_tag"; \ + commit_count=$$(git rev-list "$$latest_tag"..HEAD --count); \ + else \ + base_version="v0.0.0"; \ + commit_count=$$(git rev-list HEAD --count); \ + fi; \ + if [ -z "$$latest_tag" ] || [ "$$commit_count" -gt 0 ]; then \ + has_changes=true; \ + else \ + has_changes=false; \ + fi; \ + printf 'latest_tag=%s\n' "$$latest_tag"; \ + printf 'base_version=%s\n' "$$base_version"; \ + printf 'commit_count=%s\n' "$$commit_count"; \ + printf 'has_changes=%s\n' "$$has_changes" + # Creates a release summary containing the build revisions of each component # for the specified version. releases/%: