diff --git a/.github/workflows/release-from-commits.yml b/.github/workflows/release-from-commits.yml new file mode 100644 index 0000000..bc6bc90 --- /dev/null +++ b/.github/workflows/release-from-commits.yml @@ -0,0 +1,76 @@ +name: Release notes from commits + +on: + release: + types: [published] + +permissions: + contents: write + +jobs: + generate-notes: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # fetch all tags/commits for range and logs + + - name: Compute previous tag + id: prev + env: + CURRENT_TAG: ${{ github.event.release.tag_name }} + shell: bash + run: | + set -e + git fetch --tags --force + if [ -z "$CURRENT_TAG" ]; then + echo "No current tag found from release payload" 1>&2 + exit 1 + fi + # Sort by version, pick the latest tag that is not the current tag + PREV_TAG=$(git tag --sort=-v:refname | grep -v "^${CURRENT_TAG}$" | head -n 1 || true) + echo "Previous tag: $PREV_TAG" + echo "prev_tag=$PREV_TAG" >> "$GITHUB_OUTPUT" + + - name: Generate release notes from commits + id: gen + env: + CURRENT_TAG: ${{ github.event.release.tag_name }} + PREV_TAG: ${{ steps.prev.outputs.prev_tag }} + REPO: ${{ github.repository }} + shell: bash + run: | + set -e + if [ -n "$PREV_TAG" ]; then + RANGE="$PREV_TAG..$CURRENT_TAG" + echo "# Release $CURRENT_TAG" > RELEASE_NOTES.md + echo >> RELEASE_NOTES.md + echo "[Full Changelog](https://github.com/$REPO/compare/$PREV_TAG...$CURRENT_TAG)" >> RELEASE_NOTES.md + echo >> RELEASE_NOTES.md + else + RANGE="$CURRENT_TAG" + echo "# Release $CURRENT_TAG" > RELEASE_NOTES.md + echo >> RELEASE_NOTES.md + fi + + echo "## Changes" >> RELEASE_NOTES.md + echo >> RELEASE_NOTES.md + # Use commit subjects; skip merge commits for clarity + git log --no-merges --pretty=format:'- %s (%h) by %an' $RANGE >> RELEASE_NOTES.md || true + + echo "Generated notes:" && echo "-----" && cat RELEASE_NOTES.md && echo "-----" + + - name: Update GitHub Release body + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const notes = fs.readFileSync('RELEASE_NOTES.md', 'utf8'); + const releaseId = context.payload.release.id; + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: releaseId, + body: notes, + });