name: release on: push: tags: - "v*" workflow_dispatch: permissions: contents: write jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true - name: Generate changelog id: changelog run: | set -euo pipefail TAG="${GITHUB_REF_NAME}" REPO="${GITHUB_REPOSITORY}" # previous tag (parent of this tag) PREV_TAG="$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")" if [ -z "$PREV_TAG" ]; then RANGE="HEAD" echo "No previous tag, using all history" else RANGE="${PREV_TAG}..HEAD" echo "Range: $RANGE" fi FEATS="" FIXES="" # %H = hash, %s = subject (first line) while IFS= read -r line; do [ -z "$line" ] && continue sha="${line%% *}" subject="${line#* }" # match conventional commits: feat, fix (with optional scope and breaking !) if echo "$subject" | grep -qE '^(feat|fix)(\([^)]+\))?!?: '; then type="$(echo "$subject" | sed -E 's/^([a-z]+)(\([^)]+\))?!?:.*/\1/')" # strip type prefix for display, keep rest as title title="$(echo "$subject" | sed -E 's/^[a-z]+(\([^)]+\))?!?: //')" short="$(echo "$sha" | cut -c1-7)" url="https://github.com/${REPO}/commit/${sha}" entry="- ${title} ([\`${short}\`](${url}))" if [ "$type" = "feat" ]; then FEATS="${FEATS}${entry}"$'\n' elif [ "$type" = "fix" ]; then FIXES="${FIXES}${entry}"$'\n' fi fi done < <(git log "$RANGE" --format="%H %s" --no-merges) { echo "# ${TAG}" echo "" if [ -n "$FEATS" ]; then echo "## Features" echo "" printf "%s" "$FEATS" echo "" fi if [ -n "$FIXES" ]; then echo "## Fixes" echo "" printf "%s" "$FIXES" echo "" fi if [ -z "$FEATS" ] && [ -z "$FIXES" ]; then echo "_No relevant conventional commits (feat/fix) in this release._" echo "" fi echo "---" echo "" if [ -n "$PREV_TAG" ]; then echo "**Full diff:** [\`${PREV_TAG}...${TAG}\`](https://github.com/${REPO}/compare/${PREV_TAG}...${TAG})" else echo "**Full history up to ${TAG}**" fi } > /tmp/notes.md cat /tmp/notes.md # multiline output for next step { echo "notes<> "$GITHUB_OUTPUT" - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} name: ${{ github.ref_name }} body: ${{ steps.changelog.outputs.notes }} generate_release_notes: false