11name : Release Drafter
22
33on :
4+ push :
5+ branches :
6+ - main
47 workflow_dispatch :
58
69jobs :
@@ -10,8 +13,119 @@ jobs:
1013 contents : write
1114 pull-requests : write
1215 steps :
13- - uses : release-drafter/release-drafter@v6
16+ - id : drafter
17+ uses : release-drafter/release-drafter@v6
1418 with :
1519 config-name : release-drafter.yml
1620 env :
17- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
21+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
22+
23+ - name : Add direct commits
24+ if : steps.drafter.outputs.id != ''
25+ env :
26+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
27+ RELEASE_ID : ${{ steps.drafter.outputs.id }}
28+ HEAD_SHA : ${{ github.sha }}
29+ run : |
30+ set -euo pipefail
31+
32+ latest_tag="$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name' 2>/dev/null || true)"
33+
34+ if [ -n "$latest_tag" ]; then
35+ commits_json="$(gh api "repos/${GITHUB_REPOSITORY}/compare/${latest_tag}...${HEAD_SHA}" --jq '.commits')"
36+ else
37+ commits_json="$(gh api "repos/${GITHUB_REPOSITORY}/commits?sha=${HEAD_SHA}&per_page=100")"
38+ fi
39+
40+ direct_commits="$(mktemp)"
41+ printf '%s\n' "$commits_json" \
42+ | jq -r '.[] | [.sha, (.commit.message | split("\n")[0]), (.author.login // .commit.author.name)] | @tsv' \
43+ > "$direct_commits"
44+
45+ features=()
46+ fixes=()
47+ refactors=()
48+ docs=()
49+ maintenance=()
50+
51+ while IFS=$'\t' read -r sha subject author; do
52+ if [[ -z "$sha" || "$subject" =~ ^Merge[[:space:]] ]]; then
53+ continue
54+ fi
55+
56+ prs="$(gh api \
57+ -H "Accept: application/vnd.github+json" \
58+ "repos/${GITHUB_REPOSITORY}/commits/${sha}/pulls" \
59+ --jq 'length')"
60+
61+ if [ "$prs" -gt 0 ]; then
62+ continue
63+ fi
64+
65+ short_sha="${sha:0:7}"
66+ line="- ${short_sha} ${subject} @${author}"
67+ type="${subject%%:*}"
68+ type="${type%%(*}"
69+ type="${type%!}"
70+
71+ if [ "$type" = "feat" ]; then
72+ features+=("$line")
73+ elif [ "$type" = "fix" ]; then
74+ fixes+=("$line")
75+ elif [ "$type" = "refactor" ]; then
76+ refactors+=("$line")
77+ elif [ "$type" = "docs" ]; then
78+ docs+=("$line")
79+ elif [[ "$type" = "chore" || "$type" = "ci" || "$type" = "build" ]]; then
80+ maintenance+=("$line")
81+ fi
82+ done < "$direct_commits"
83+
84+ direct_notes="$(mktemp)"
85+ {
86+ echo "## Direct Commits"
87+ echo
88+
89+ if [ "${#features[@]}" -gt 0 ]; then
90+ echo "### 🚀 Features"
91+ printf '%s\n' "${features[@]}"
92+ echo
93+ fi
94+
95+ if [ "${#fixes[@]}" -gt 0 ]; then
96+ echo "### 🐛 Bug Fixes"
97+ printf '%s\n' "${fixes[@]}"
98+ echo
99+ fi
100+
101+ if [ "${#refactors[@]}" -gt 0 ]; then
102+ echo "### 📦 Code Refactoring"
103+ printf '%s\n' "${refactors[@]}"
104+ echo
105+ fi
106+
107+ if [ "${#docs[@]}" -gt 0 ]; then
108+ echo "### 📄 Documentation"
109+ printf '%s\n' "${docs[@]}"
110+ echo
111+ fi
112+
113+ if [ "${#maintenance[@]}" -gt 0 ]; then
114+ echo "### 🧰 Maintenance"
115+ printf '%s\n' "${maintenance[@]}"
116+ echo
117+ fi
118+ } > "$direct_notes"
119+
120+ if [ "$(wc -l < "$direct_notes")" -le 2 ]; then
121+ exit 0
122+ fi
123+
124+ body="$(gh api "repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}" --jq '.body')"
125+ body_without_direct="$(printf '%s\n' "$body" | sed '/^## Direct Commits$/,$d')"
126+ new_body="$(printf '%s\n\n%s\n' "$body_without_direct" "$(cat "$direct_notes")")"
127+
128+ gh api \
129+ --method PATCH \
130+ "repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}" \
131+ -f body="$new_body"
0 commit comments