|
2 | 2 |
|
3 | 3 | set -euo pipefail |
4 | 4 |
|
| 5 | +echo "Generating changelog for version: $VERSION" |
| 6 | + |
5 | 7 | # Ensure gh CLI available |
6 | 8 | if ! command -v gh &> /dev/null; then |
7 | 9 | echo "gh CLI is required but not installed." >&2 |
8 | 10 | exit 1 |
9 | 11 | fi |
10 | 12 |
|
| 13 | +RELEASE_NOTES_TO_JSON_SCRIPT="$(realpath "$(dirname $0)/release-notes-to-json.sh")" |
11 | 14 | cd $(dirname "$0")/../../ |
12 | 15 |
|
13 | 16 | LATEST_RELEASE_TAG=$(gh release list --json tagName,isLatest --jq '.[] | select(.isLatest)|.tagName') |
14 | 17 | if [[ -z "$LATEST_RELEASE_TAG" ]]; then # first release? |
15 | 18 | LATEST_RELEASE_TAG=$(git rev-list --max-parents=0 HEAD) # first commit in the branch. |
16 | 19 | fi |
17 | 20 |
|
18 | | -GIT_LOG_OUTPUT=$(git log "$LATEST_RELEASE_TAG"..HEAD --oneline --pretty=format:"%s" main) |
| 21 | +GIT_LOG_OUTPUT=$(git log "$LATEST_RELEASE_TAG"..HEAD --oneline --pretty=format:"%s") |
19 | 22 | PR_COMMITS=$(echo "$GIT_LOG_OUTPUT" | grep -oE "#[0-9]+" || true | tr -d '#' | sort -u) |
20 | 23 |
|
21 | 24 | CHANGELOG_FILE=./CHANGELOG.md |
|
43 | 46 |
|
44 | 47 | for PR_NUMBER in $PR_COMMITS; do |
45 | 48 | PR_JSON=$(gh pr view "$PR_NUMBER" --json number,title,body,url,author) |
| 49 | + echo -n "Checking PR $PR_NUMBER" |
46 | 50 |
|
47 | | - IS_BOT=$(echo "$PR_JSON" | jq -r '.author.is_bot') |
| 51 | + IS_BOT=$(jq -r '.author.is_bot' <<< "$PR_JSON") |
48 | 52 | if [[ "$IS_BOT" == "true" ]]; then |
| 53 | + echo " [skipping bot PR"] |
49 | 54 | continue |
50 | 55 | fi |
51 | 56 |
|
52 | | - PR_TITLE=$(echo "$PR_JSON" | jq -r '.title') |
53 | | - PR_URL=$(echo "$PR_JSON" | jq -r '.url') |
54 | | - PR_BODY=$(echo "$PR_JSON" | jq -r '.body') |
| 57 | + PR_TITLE=$(jq -r '.title' <<< "$PR_JSON") |
| 58 | + PR_URL=$(jq -r '.url' <<< "$PR_JSON") |
| 59 | + PR_BODY=$(jq -r '.body' <<< "$PR_JSON") |
| 60 | + echo " - $PR_TITLE" |
55 | 61 |
|
56 | 62 | # Determine type from conventional commit (assumes title like "type(scope): message" or "type: message") |
57 | 63 | TYPE=$(echo "$PR_TITLE" | grep -oE '^[a-z]+' || echo "feat") |
58 | 64 | CLEAN_TITLE=$(echo "$PR_TITLE" | sed -E 's/^[a-z]+(\([^)]+\))?(!)?:[[:space:]]+//') |
59 | 65 |
|
60 | 66 | # Extract release note block, this contains the release notes and the release notes headers. |
61 | | - RELEASE_NOTE_BLOCK=$(echo "$PR_BODY" | sed -n '/\*\*Release note\*\*:/,$p' | sed -n '/^```.*$/,/^```$/p') |
| 67 | + # The last sed call is required to remove the carriage return characters (Github seems to use \r\n for new lines in PR bodies). |
| 68 | + RELEASE_NOTE_BLOCK=$(echo "$PR_BODY" | sed -n '/\*\*Release note\*\*:/,$p' | sed -n '/^```.*$/,/^```$/p' | sed 's/\r//g') |
62 | 69 | # Extract release notes body |
63 | | - RELEASE_NOTE=$(echo "$RELEASE_NOTE_BLOCK" | sed '1d;$d' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') |
| 70 | + RELEASE_NOTE_JSON=$("$RELEASE_NOTES_TO_JSON_SCRIPT" <<< "$RELEASE_NOTE_BLOCK") |
| 71 | + |
| 72 | + # skip PRs without release notes |
| 73 | + if [[ "$RELEASE_NOTE_JSON" == "[]" ]]; then |
| 74 | + echo " [ignoring PR without release notes]" |
| 75 | + continue |
| 76 | + fi |
| 77 | + |
| 78 | + # Format release notes |
| 79 | + # Updating NOTE_ENTRY in the loop does not work because it is executed in a subshell, therefore this workaround via echo. |
| 80 | + NOTE_ENTRY="$( |
| 81 | + jq -rc 'sort_by(.audience, .type) | .[]' <<< "$RELEASE_NOTE_JSON" | while IFS= read -r note; do |
| 82 | + NOTE_TYPE=$(jq -r '.type' <<< "$note" | tr '[:lower:]' '[:upper:]') |
| 83 | + NOTE_AUDIENCE=$(jq -r '.audience' <<< "$note" | tr '[:lower:]' '[:upper:]') |
| 84 | + NOTE_BODY=$(jq -r '.body' <<< "$note") |
| 85 | + echo -en "\n - **[$NOTE_AUDIENCE][$NOTE_TYPE]** $NOTE_BODY" |
| 86 | + done |
| 87 | + )" |
64 | 88 |
|
65 | 89 | # Format entry |
66 | 90 | ENTRY="- $CLEAN_TITLE [#${PR_NUMBER}](${PR_URL})" |
67 | 91 |
|
68 | | - if [[ -z "$RELEASE_NOTE" || "$RELEASE_NOTE" == "NONE" ]]; then |
69 | | - ENTRY+="." |
70 | | - else |
71 | | - # Extract and format the release note headers. |
72 | | - HEADERS=$(echo "$PR_BODY" | sed -n '/\*\*Release note\*\*:/,$p' | sed -n '/^```.*$/,/^```$/p'| head -n 1 | sed 's/^```//') |
73 | | - FORMATED_HEADERS=$(echo "$HEADERS" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//; s/\s\+/ /g' | sed 's/\(\S\+\)/[\1]/g') |
| 92 | + # Extract and format the release note headers. |
| 93 | + HEADERS=$(echo "$PR_BODY" | sed -n '/\*\*Release note\*\*:/,$p' | sed -n '/^```.*$/,/^```$/p'| head -n 1 | sed 's/^```//') |
| 94 | + FORMATED_HEADERS=$(echo "$HEADERS" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//; s/\s\+/ /g' | sed 's/\(\S\+\)/[\1]/g') |
74 | 95 |
|
75 | | - ENTRY="- ${FORMATED_HEADERS} ${CLEAN_TITLE} [#${PR_NUMBER}](${PR_URL}): ${RELEASE_NOTE}" |
76 | | - fi |
77 | | - ENTRY+="\n" |
| 96 | + ENTRY="- ${CLEAN_TITLE} [${PR_NUMBER}](${PR_URL})${NOTE_ENTRY}\n" |
78 | 97 |
|
79 | 98 | # Append to appropriate section |
80 | 99 | if [[ -n "${PR_ENTRIES[$TYPE]+x}" ]]; then |
|
0 commit comments