codacus commited on
Commit
4844db8
Β·
unverified Β·
1 Parent(s): 7eee038

ci: improved change-log generation script and cleaner release ci action (#896)

Browse files

* build: improved-changelog

* added a better change log script

* improved changelog script

* improved change log script

.github/scripts/generate-changelog.sh ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ # Ensure we're running in bash
4
+ if [ -z "$BASH_VERSION" ]; then
5
+ echo "This script requires bash. Please run with: bash $0" >&2
6
+ exit 1
7
+ fi
8
+
9
+ # Ensure we're using bash 4.0 or later for associative arrays
10
+ if ((BASH_VERSINFO[0] < 4)); then
11
+ echo "This script requires bash version 4 or later" >&2
12
+ echo "Current bash version: $BASH_VERSION" >&2
13
+ exit 1
14
+ fi
15
+
16
+ # Set default values for required environment variables if not in GitHub Actions
17
+ if [ -z "$GITHUB_ACTIONS" ]; then
18
+ : "${GITHUB_SERVER_URL:=https://github.com}"
19
+ : "${GITHUB_REPOSITORY:=stackblitz-labs/bolt.diy}"
20
+ : "${GITHUB_OUTPUT:=/tmp/github_output}"
21
+ touch "$GITHUB_OUTPUT"
22
+
23
+ # Running locally
24
+ echo "Running locally - checking for upstream remote..."
25
+ MAIN_REMOTE="origin"
26
+ if git remote -v | grep -q "upstream"; then
27
+ MAIN_REMOTE="upstream"
28
+ fi
29
+ MAIN_BRANCH="main" # or "master" depending on your repository
30
+
31
+ # Ensure we have latest tags
32
+ git fetch ${MAIN_REMOTE} --tags
33
+
34
+ # Use the remote reference for git log
35
+ GITLOG_REF="${MAIN_REMOTE}/${MAIN_BRANCH}"
36
+ else
37
+ # Running in GitHub Actions
38
+ GITLOG_REF="HEAD"
39
+ fi
40
+
41
+ # Get the latest tag
42
+ LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
43
+
44
+ # Start changelog file
45
+ echo "# πŸš€ Release v${NEW_VERSION}" > changelog.md
46
+ echo "" >> changelog.md
47
+ echo "## What's Changed 🌟" >> changelog.md
48
+ echo "" >> changelog.md
49
+
50
+ if [ -z "$LATEST_TAG" ]; then
51
+ echo "### πŸŽ‰ First Release" >> changelog.md
52
+ echo "" >> changelog.md
53
+ echo "Exciting times! This marks our first release. Thanks to everyone who contributed! πŸ™Œ" >> changelog.md
54
+ echo "" >> changelog.md
55
+ COMPARE_BASE="$(git rev-list --max-parents=0 HEAD)"
56
+ else
57
+ echo "### πŸ”„ Changes since $LATEST_TAG" >> changelog.md
58
+ echo "" >> changelog.md
59
+ COMPARE_BASE="$LATEST_TAG"
60
+ fi
61
+
62
+ # Function to extract conventional commit type and associated emoji
63
+ get_commit_type() {
64
+ local msg="$1"
65
+ if [[ $msg =~ ^feat(\(.+\))?:|^feature(\(.+\))?: ]]; then echo "✨ Features"
66
+ elif [[ $msg =~ ^fix(\(.+\))?: ]]; then echo "πŸ› Bug Fixes"
67
+ elif [[ $msg =~ ^docs(\(.+\))?: ]]; then echo "πŸ“š Documentation"
68
+ elif [[ $msg =~ ^style(\(.+\))?: ]]; then echo "πŸ’Ž Styles"
69
+ elif [[ $msg =~ ^refactor(\(.+\))?: ]]; then echo "♻️ Code Refactoring"
70
+ elif [[ $msg =~ ^perf(\(.+\))?: ]]; then echo "⚑ Performance Improvements"
71
+ elif [[ $msg =~ ^test(\(.+\))?: ]]; then echo "πŸ§ͺ Tests"
72
+ elif [[ $msg =~ ^build(\(.+\))?: ]]; then echo "πŸ› οΈ Build System"
73
+ elif [[ $msg =~ ^ci(\(.+\))?: ]]; then echo "βš™οΈ CI"
74
+ elif [[ $msg =~ ^chore(\(.+\))?: ]]; then echo "" # Skip chore commits
75
+ else echo "πŸ” Other Changes" # Default category with emoji
76
+ fi
77
+ }
78
+
79
+ # Initialize associative arrays
80
+ declare -A CATEGORIES
81
+ declare -A COMMITS_BY_CATEGORY
82
+ declare -A ALL_AUTHORS
83
+ declare -A NEW_CONTRIBUTORS
84
+
85
+ # Get all historical authors before the compare base
86
+ while IFS= read -r author; do
87
+ ALL_AUTHORS["$author"]=1
88
+ done < <(git log "${COMPARE_BASE}" --pretty=format:"%ae" | sort -u)
89
+
90
+ # Process all commits since last tag
91
+ while IFS= read -r commit_line; do
92
+ if [[ ! $commit_line =~ ^[a-f0-9]+\| ]]; then
93
+ echo "WARNING: Skipping invalid commit line format: $commit_line" >&2
94
+ continue
95
+ fi
96
+
97
+ HASH=$(echo "$commit_line" | cut -d'|' -f1)
98
+ COMMIT_MSG=$(echo "$commit_line" | cut -d'|' -f2)
99
+ BODY=$(echo "$commit_line" | cut -d'|' -f3)
100
+ # Skip if hash doesn't match the expected format
101
+ if [[ ! $HASH =~ ^[a-f0-9]{40}$ ]]; then
102
+ continue
103
+ fi
104
+
105
+ HASH=$(echo "$commit_line" | cut -d'|' -f1)
106
+ COMMIT_MSG=$(echo "$commit_line" | cut -d'|' -f2)
107
+ BODY=$(echo "$commit_line" | cut -d'|' -f3)
108
+
109
+
110
+ # Validate hash format
111
+ if [[ ! $HASH =~ ^[a-f0-9]{40}$ ]]; then
112
+ echo "WARNING: Invalid commit hash format: $HASH" >&2
113
+ continue
114
+ fi
115
+
116
+ # Check if it's a merge commit
117
+ if [[ $COMMIT_MSG =~ Merge\ pull\ request\ #([0-9]+) ]]; then
118
+ # echo "Processing as merge commit" >&2
119
+ PR_NUM="${BASH_REMATCH[1]}"
120
+
121
+ # Extract the PR title from the merge commit body
122
+ PR_TITLE=$(echo "$BODY" | grep -v "^Merge pull request" | head -n 1)
123
+
124
+ # Only process if it follows conventional commit format
125
+ CATEGORY=$(get_commit_type "$PR_TITLE")
126
+
127
+ if [ -n "$CATEGORY" ]; then # Only process if it's a conventional commit
128
+ # Get PR author's GitHub username
129
+ GITHUB_USERNAME=$(gh pr view "$PR_NUM" --json author --jq '.author.login')
130
+
131
+ if [ -n "$GITHUB_USERNAME" ]; then
132
+ # Check if this is a first-time contributor
133
+ AUTHOR_EMAIL=$(git show -s --format='%ae' "$HASH")
134
+ if [ -z "${ALL_AUTHORS[$AUTHOR_EMAIL]}" ]; then
135
+ NEW_CONTRIBUTORS["$GITHUB_USERNAME"]=1
136
+ ALL_AUTHORS["$AUTHOR_EMAIL"]=1
137
+ fi
138
+
139
+ CATEGORIES["$CATEGORY"]=1
140
+ COMMITS_BY_CATEGORY["$CATEGORY"]+="* ${PR_TITLE#*: } ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM)) by [@$GITHUB_USERNAME](https://github.com/$GITHUB_USERNAME)"$'\n'
141
+ else
142
+ COMMITS_BY_CATEGORY["$CATEGORY"]+="* ${PR_TITLE#*: } ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM))"$'\n'
143
+ fi
144
+ fi
145
+ # Check if it's a squash merge by looking for (#NUMBER) pattern
146
+ elif [[ $COMMIT_MSG =~ \(#([0-9]+)\) ]]; then
147
+ # echo "Processing as squash commit" >&2
148
+ PR_NUM="${BASH_REMATCH[1]}"
149
+
150
+ # Only process if it follows conventional commit format
151
+ CATEGORY=$(get_commit_type "$COMMIT_MSG")
152
+
153
+ if [ -n "$CATEGORY" ]; then # Only process if it's a conventional commit
154
+ # Get PR author's GitHub username
155
+ GITHUB_USERNAME=$(gh pr view "$PR_NUM" --json author --jq '.author.login')
156
+
157
+ if [ -n "$GITHUB_USERNAME" ]; then
158
+ # Check if this is a first-time contributor
159
+ AUTHOR_EMAIL=$(git show -s --format='%ae' "$HASH")
160
+ if [ -z "${ALL_AUTHORS[$AUTHOR_EMAIL]}" ]; then
161
+ NEW_CONTRIBUTORS["$GITHUB_USERNAME"]=1
162
+ ALL_AUTHORS["$AUTHOR_EMAIL"]=1
163
+ fi
164
+
165
+ CATEGORIES["$CATEGORY"]=1
166
+ COMMIT_TITLE=${COMMIT_MSG%% (#*} # Remove the PR number suffix
167
+ COMMIT_TITLE=${COMMIT_TITLE#*: } # Remove the type prefix
168
+ COMMITS_BY_CATEGORY["$CATEGORY"]+="* $COMMIT_TITLE ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM)) by [@$GITHUB_USERNAME](https://github.com/$GITHUB_USERNAME)"$'\n'
169
+ else
170
+ COMMIT_TITLE=${COMMIT_MSG%% (#*} # Remove the PR number suffix
171
+ COMMIT_TITLE=${COMMIT_TITLE#*: } # Remove the type prefix
172
+ COMMITS_BY_CATEGORY["$CATEGORY"]+="* $COMMIT_TITLE ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM))"$'\n'
173
+ fi
174
+ fi
175
+
176
+ else
177
+ # echo "Processing as regular commit" >&2
178
+ # Process conventional commits without PR numbers
179
+ CATEGORY=$(get_commit_type "$COMMIT_MSG")
180
+
181
+ if [ -n "$CATEGORY" ]; then # Only process if it's a conventional commit
182
+ # Get commit author info
183
+ AUTHOR_EMAIL=$(git show -s --format='%ae' "$HASH")
184
+
185
+ # Try to get GitHub username using gh api
186
+ if [ -n "$GITHUB_ACTIONS" ] || command -v gh >/dev/null 2>&1; then
187
+ GITHUB_USERNAME=$(gh api "/repos/${GITHUB_REPOSITORY}/commits/${HASH}" --jq '.author.login' 2>/dev/null)
188
+ fi
189
+
190
+ if [ -n "$GITHUB_USERNAME" ]; then
191
+ # If we got GitHub username, use it
192
+ if [ -z "${ALL_AUTHORS[$AUTHOR_EMAIL]}" ]; then
193
+ NEW_CONTRIBUTORS["$GITHUB_USERNAME"]=1
194
+ ALL_AUTHORS["$AUTHOR_EMAIL"]=1
195
+ fi
196
+
197
+ CATEGORIES["$CATEGORY"]=1
198
+ COMMIT_TITLE=${COMMIT_MSG#*: } # Remove the type prefix
199
+ COMMITS_BY_CATEGORY["$CATEGORY"]+="* $COMMIT_TITLE (${HASH:0:7}) by [@$GITHUB_USERNAME](https://github.com/$GITHUB_USERNAME)"$'\n'
200
+ else
201
+ # Fallback to git author name if no GitHub username found
202
+ AUTHOR_NAME=$(git show -s --format='%an' "$HASH")
203
+
204
+ if [ -z "${ALL_AUTHORS[$AUTHOR_EMAIL]}" ]; then
205
+ NEW_CONTRIBUTORS["$AUTHOR_NAME"]=1
206
+ ALL_AUTHORS["$AUTHOR_EMAIL"]=1
207
+ fi
208
+
209
+ CATEGORIES["$CATEGORY"]=1
210
+ COMMIT_TITLE=${COMMIT_MSG#*: } # Remove the type prefix
211
+ COMMITS_BY_CATEGORY["$CATEGORY"]+="* $COMMIT_TITLE (${HASH:0:7}) by $AUTHOR_NAME"$'\n'
212
+ fi
213
+ fi
214
+ fi
215
+
216
+ done < <(git log "${COMPARE_BASE}..${GITLOG_REF}" --pretty=format:"%H|%s|%b" --reverse --first-parent)
217
+
218
+ # Write categorized commits to changelog with their emojis
219
+ for category in "✨ Features" "πŸ› Bug Fixes" "πŸ“š Documentation" "πŸ’Ž Styles" "♻️ Code Refactoring" "⚑ Performance Improvements" "πŸ§ͺ Tests" "πŸ› οΈ Build System" "βš™οΈ CI" "πŸ” Other Changes"; do
220
+ if [ -n "${COMMITS_BY_CATEGORY[$category]}" ]; then
221
+ echo "### $category" >> changelog.md
222
+ echo "" >> changelog.md
223
+ echo "${COMMITS_BY_CATEGORY[$category]}" >> changelog.md
224
+ echo "" >> changelog.md
225
+ fi
226
+ done
227
+
228
+ # Add first-time contributors section if there are any
229
+ if [ ${#NEW_CONTRIBUTORS[@]} -gt 0 ]; then
230
+ echo "## ✨ First-time Contributors" >> changelog.md
231
+ echo "" >> changelog.md
232
+ echo "A huge thank you to our amazing new contributors! Your first contribution marks the start of an exciting journey! 🌟" >> changelog.md
233
+ echo "" >> changelog.md
234
+ # Use readarray to sort the keys
235
+ readarray -t sorted_contributors < <(printf '%s\n' "${!NEW_CONTRIBUTORS[@]}" | sort)
236
+ for github_username in "${sorted_contributors[@]}"; do
237
+ echo "* 🌟 [@$github_username](https://github.com/$github_username)" >> changelog.md
238
+ done
239
+ echo "" >> changelog.md
240
+ fi
241
+
242
+ # Add compare link if not first release
243
+ if [ -n "$LATEST_TAG" ]; then
244
+ echo "## πŸ“ˆ Stats" >> changelog.md
245
+ echo "" >> changelog.md
246
+ echo "**Full Changelog**: [\`$LATEST_TAG..v${NEW_VERSION}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/$LATEST_TAG...v${NEW_VERSION})" >> changelog.md
247
+ fi
248
+
249
+ # Output the changelog content
250
+ CHANGELOG_CONTENT=$(cat changelog.md)
251
+ {
252
+ echo "content<<EOF"
253
+ echo "$CHANGELOG_CONTENT"
254
+ echo "EOF"
255
+ } >> "$GITHUB_OUTPUT"
256
+
257
+ # Also print to stdout for local testing
258
+ echo "Generated changelog:"
259
+ echo "==================="
260
+ cat changelog.md
261
+ echo "==================="
.github/workflows/update-stable.yml CHANGED
@@ -80,83 +80,15 @@ jobs:
80
  NEW_VERSION=${{ steps.bump_version.outputs.new_version }}
81
  pnpm version $NEW_VERSION --no-git-tag-version --allow-same-version
82
 
 
 
 
 
83
  - name: Generate Changelog
84
  id: changelog
85
- run: |
86
- # Get the latest tag
87
- LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
88
-
89
- # Start changelog file
90
- echo "# Release v${{ steps.bump_version.outputs.new_version }}" > changelog.md
91
- echo "" >> changelog.md
92
-
93
- if [ -z "$LATEST_TAG" ]; then
94
- echo "### πŸŽ‰ First Release" >> changelog.md
95
- echo "" >> changelog.md
96
- COMPARE_BASE="$(git rev-list --max-parents=0 HEAD)"
97
- else
98
- echo "### πŸ”„ Changes since $LATEST_TAG" >> changelog.md
99
- echo "" >> changelog.md
100
- COMPARE_BASE="$LATEST_TAG"
101
- fi
102
-
103
- # Function to extract conventional commit type
104
- get_commit_type() {
105
- if [[ $1 =~ ^feat:|^feature: ]]; then echo "✨ Features";
106
- elif [[ $1 =~ ^fix: ]]; then echo "πŸ› Bug Fixes";
107
- elif [[ $1 =~ ^docs: ]]; then echo "πŸ“š Documentation";
108
- elif [[ $1 =~ ^style: ]]; then echo "πŸ’Ž Styles";
109
- elif [[ $1 =~ ^refactor: ]]; then echo "♻️ Code Refactoring";
110
- elif [[ $1 =~ ^perf: ]]; then echo "⚑️ Performance Improvements";
111
- elif [[ $1 =~ ^test: ]]; then echo "βœ… Tests";
112
- elif [[ $1 =~ ^build: ]]; then echo "πŸ› οΈ Build System";
113
- elif [[ $1 =~ ^ci: ]]; then echo "βš™οΈ CI";
114
- elif [[ $1 =~ ^chore: ]]; then echo "πŸ”§ Chores";
115
- else echo "πŸ” Other Changes";
116
- fi
117
- }
118
-
119
- # Generate categorized changelog
120
- declare -A CATEGORIES
121
- declare -A COMMITS_BY_CATEGORY
122
-
123
- # Get commits since last tag or all commits if no tag exists
124
- while IFS= read -r commit_line; do
125
- HASH=$(echo "$commit_line" | cut -d'|' -f1)
126
- MSG=$(echo "$commit_line" | cut -d'|' -f2)
127
- PR_NUM=$(echo "$commit_line" | cut -d'|' -f3)
128
-
129
- CATEGORY=$(get_commit_type "$MSG")
130
- CATEGORIES["$CATEGORY"]=1
131
-
132
- # Format commit message with PR link if available
133
- if [ -n "$PR_NUM" ]; then
134
- COMMITS_BY_CATEGORY["$CATEGORY"]+="- ${MSG#*: } ([#$PR_NUM](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/$PR_NUM))"$'\n'
135
- else
136
- COMMITS_BY_CATEGORY["$CATEGORY"]+="- ${MSG#*: }"$'\n'
137
- fi
138
- done < <(git log "${COMPARE_BASE}..HEAD" --pretty=format:"%H|%s|%(trailers:key=PR-Number,valueonly)" --reverse)
139
-
140
- # Write categorized commits to changelog
141
- for category in "✨ Features" "πŸ› Bug Fixes" "πŸ“š Documentation" "πŸ’Ž Styles" "♻️ Code Refactoring" "⚑️ Performance Improvements" "βœ… Tests" "πŸ› οΈ Build System" "βš™οΈ CI" "πŸ”§ Chores" "πŸ” Other Changes"; do
142
- if [ -n "${COMMITS_BY_CATEGORY[$category]}" ]; then
143
- echo "#### $category" >> changelog.md
144
- echo "" >> changelog.md
145
- echo "${COMMITS_BY_CATEGORY[$category]}" >> changelog.md
146
- echo "" >> changelog.md
147
- fi
148
- done
149
-
150
- # Add compare link if not first release
151
- if [ -n "$LATEST_TAG" ]; then
152
- echo "**Full Changelog**: [\`$LATEST_TAG..v${{ steps.bump_version.outputs.new_version }}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/$LATEST_TAG...v${{ steps.bump_version.outputs.new_version }})" >> changelog.md
153
- fi
154
-
155
- # Save changelog content for the release
156
- CHANGELOG_CONTENT=$(cat changelog.md)
157
- echo "content<<EOF" >> $GITHUB_OUTPUT
158
- echo "$CHANGELOG_CONTENT" >> $GITHUB_OUTPUT
159
- echo "EOF" >> $GITHUB_OUTPUT
160
 
161
  - name: Get the latest commit hash and version tag
162
  run: |
 
80
  NEW_VERSION=${{ steps.bump_version.outputs.new_version }}
81
  pnpm version $NEW_VERSION --no-git-tag-version --allow-same-version
82
 
83
+
84
+ - name: Prepare changelog script
85
+ run: chmod +x .github/scripts/generate-changelog.sh
86
+
87
  - name: Generate Changelog
88
  id: changelog
89
+ env:
90
+ NEW_VERSION: ${{ steps.bump_version.outputs.new_version }}
91
+ run: .github/scripts/generate-changelog.sh
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
  - name: Get the latest commit hash and version tag
94
  run: |