diff --git a/.github/workflows/release.lib.yaml b/.github/workflows/release.lib.yaml index 8170560..e890815 100644 --- a/.github/workflows/release.lib.yaml +++ b/.github/workflows/release.lib.yaml @@ -28,6 +28,8 @@ jobs: fetch-depth: 0 submodules: recursive + - name: test-action + run: cd hack/common; git status - name: Install Task uses: arduino/setup-task@v2 with: @@ -85,36 +87,8 @@ jobs: done - name: Build Changelog - id: github_release - uses: mikepenz/release-changelog-builder-action@5fb6e51e44d4aea73f66549f425aa3ed5008109e # v5 - with: - mode: "PR" - configurationJson: | - { - "template": "#{{CHANGELOG}}", - "pr_template": "- #{{TITLE}}: ##{{NUMBER}}", - "categories": [ - { - "title": "## Feature", - "labels": ["feat", "feature"] - }, - { - "title": "## Fix", - "labels": ["fix", "bug"] - }, - { - "title": "## Other", - "labels": [] - } - ], - "label_extractor": [ - { - "pattern": "^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\\([\\w\\-\\.]+\\))?(!)?: ([\\w ])+([\\s\\S]*)", - "on_property": "title", - "target": "$1" - } - ] - } + id: github_release + run: task r:generate-changelog env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -124,7 +98,7 @@ jobs: with: tag_name: ${{ env.version }} name: Release ${{ env.version }} - body: ${{steps.github_release.outputs.changelog}} + body: CHANGELOG.md draft: true prerelease: false env: diff --git a/generate-changelog.sh b/generate-changelog.sh new file mode 100755 index 0000000..d7d2f96 --- /dev/null +++ b/generate-changelog.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +set -euo pipefail + +# Ensure gh CLI available +if ! command -v gh &> /dev/null; then + echo "gh CLI is required but not installed." >&2 + exit 1 +fi + +cd $(dirname "$0")/../../ + +LATEST_RELEASE_TAG=$(gh release list --json tagName,isLatest --jq '.[] | select(.isLatest)|.tagName') +if [[ -e $LATEST_RELEASE_TAG ]]; then # first release? + LATEST_RELEASE_TAG=$(git rev-list --max-parents=0 HEAD) # first commit in the branch. +fi + +PR_COMMITS=$(git log "$LATEST_RELEASE_TAG"..HEAD --oneline --pretty=format:"%s" main | grep -oE "#[0-9]+" | tr -d '#' | sort -u) + +CHANGELOG_FILE=./CHANGELOG.md +# File header Header +echo "# Changes included in $VERSION:" > "$CHANGELOG_FILE" +echo "" >> "$CHANGELOG_FILE" + +declare -A SECTIONS +SECTIONS=( + [feat]="### 🚀 Features" + [fix]="### 🐛 Fixes" + [chore]="### 🔧 Chores" + [docs]="### 📚 Documentation" + [refactor]="### 🔨 Refactoring" + [test]="### ✅ Tests" + [perf]="### ⚡ Performance" + [ci]="### 🔁 CI" +) + +# Prepare section buffers +declare -A PR_ENTRIES +for key in "${!SECTIONS[@]}"; do + PR_ENTRIES[$key]="" +done + +for PR_NUMBER in $PR_COMMITS; do + PR_JSON=$(gh pr view "$PR_NUMBER" --json number,title,body,url,author) + + IS_BOT=$(echo "$PR_JSON" | jq -r '.author.is_bot') + if [[ "$IS_BOT" == "true" ]]; then + continue + fi + + TITLE=$(echo "$PR_JSON" | jq -r '.title') + URL=$(echo "$PR_JSON" | jq -r '.url') + BODY=$(echo "$PR_JSON" | jq -r '.body') + + # Determine type from conventional commit (assumes title like "type(scope): message" or "type: message") + TYPE=$(echo "$TITLE" | grep -oE '^[a-z]+' || echo "feat") + CLEAN_TITLE=$(echo "$TITLE" | sed -E 's/^[a-z]+(\([^)]+\))?(!)?:[[:space:]]+//') + + # Extract release note block, we only extract the "user" related notes. + RELEASE_NOTE=$(echo "$BODY" | awk '/^```[[:space:]]*(breaking|feature|bugfix|doc|other)[[:space:]]+user[[:space:]]*$/ {flag=1; next} /^```[[:space:]]*$/ {flag=0} flag' || true) + + # Format entry + ENTRY="- $CLEAN_TITLE [#${PR_NUMBER}](${URL})" + if [[ -n "$RELEASE_NOTE" || "$RELEASE_NOTE" != "NONE" ]]; then + ENTRY+=": $RELEASE_NOTE" + else + ENTRY+="." + fi + ENTRY+="\n" + + # Append to appropriate section + if [[ -n "${PR_ENTRIES[$TYPE]+x}" ]]; then + PR_ENTRIES[$TYPE]+="$ENTRY" + else + PR_ENTRIES[chore]+="$ENTRY" + fi +done + +# Output sections +for key in "${!SECTIONS[@]}"; do + if [[ -n "${PR_ENTRIES[$key]}" ]]; then + echo "${SECTIONS[$key]}" >> "$CHANGELOG_FILE" + echo -e "${PR_ENTRIES[$key]}" >> "$CHANGELOG_FILE" + echo "" >> "$CHANGELOG_FILE" + fi +done + +cat "$CHANGELOG_FILE" diff --git a/tasks_rls.yaml b/tasks_rls.yaml index e9f41b2..49238b7 100644 --- a/tasks_rls.yaml +++ b/tasks_rls.yaml @@ -139,3 +139,13 @@ tasks: desc: "List all nested modules in the project." cmds: - cmd: 'echo "{{.NESTED_MODULES}}"' + + generate-changelog: + desc: " Generates an automated release changelog based on conventional-commits PR titles in CHANGELOG.md file." + run: once + requires: + vars: + - VERSION + cmds: + - 'VERSION={{.VERSION}} {{.TASKFILE_DIR2}}/generate-changelog.sh' + \ No newline at end of file