-
Notifications
You must be signed in to change notification settings - Fork 0
feat(release): generate conventional-commit release notes (epic 005 T013/T014) #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+304
−2
Merged
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| #!/usr/bin/env bash | ||
| # Generates release-notes body text for <current_tag> (FR-006). Groups | ||
| # commit subjects in previous_release_tag..current_tag by conventional- | ||
| # commit prefix (feat/fix/docs/chore), with a fallback bucket for anything | ||
| # else (FR-007). previous_release_tag comes from T005's | ||
| # previous-release-tag.sh (FR-011); when it's empty (first release, no | ||
| # previous tag), falls back to the full history reachable from | ||
| # current_tag (FR-009). | ||
| # | ||
| # No bash arrays: macOS's default /usr/bin/env bash resolves to bash 3.2, | ||
| # which raises "unbound variable" on an empty array expansion under | ||
| # `set -u`. Buckets are plain temp files instead -- portable across bash | ||
| # 3.2 (local/macOS) and the GitHub Actions runner's bash 5. | ||
| set -euo pipefail | ||
|
|
||
| usage() { | ||
| echo "usage: $0 <current_tag>" >&2 | ||
| exit 2 | ||
| } | ||
|
|
||
| [ $# -ge 1 ] || usage | ||
| current_tag="$1" | ||
|
|
||
| script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| previous_tag="$("$script_dir/previous-release-tag.sh" "$current_tag")" | ||
|
|
||
| if [ -n "$previous_tag" ]; then | ||
| range="${previous_tag}..${current_tag}" | ||
| else | ||
| range="$current_tag" | ||
| fi | ||
|
|
||
| tmp="$(mktemp -d)" | ||
| trap 'rm -rf "$tmp"' EXIT | ||
|
|
||
| : > "$tmp/feat" | ||
| : > "$tmp/fix" | ||
| : > "$tmp/docs" | ||
| : > "$tmp/chore" | ||
| : > "$tmp/other" | ||
|
|
||
| # `--`: without it, a first-release history that happens to collide with a | ||
| # path in the working tree (e.g. a tag "v1.0.0" and a directory | ||
| # "v1.0.0/") makes git treat the argument as ambiguous and fail; `--` | ||
| # forces it to be read as a revision. The previous..current range form is | ||
| # immune (a `..` argument is never path-ambiguous) but costs nothing to | ||
| # guard uniformly. | ||
| # | ||
| # `!` variants (feat!:, fix(scope)!:, ...) are Conventional Commits' | ||
| # breaking-change marker -- grouped with their non-breaking counterparts | ||
| # rather than a fallback bucket, since they're still feat/fix/etc in | ||
| # intent; `${line#*: }` already strips the `!` along with the rest of the | ||
| # prefix correctly. | ||
| git log --format=%s "$range" -- | while IFS= read -r line; do | ||
| [ -z "$line" ] && continue | ||
| case "$line" in | ||
| feat:*|feat\(*\):*|feat!:*|feat\(*\)!:*) echo "- ${line#*: }" >> "$tmp/feat" ;; | ||
| fix:*|fix\(*\):*|fix!:*|fix\(*\)!:*) echo "- ${line#*: }" >> "$tmp/fix" ;; | ||
| docs:*|docs\(*\):*|docs!:*|docs\(*\)!:*) echo "- ${line#*: }" >> "$tmp/docs" ;; | ||
| chore:*|chore\(*\):*|chore!:*|chore\(*\)!:*) echo "- ${line#*: }" >> "$tmp/chore" ;; | ||
| *) echo "- $line" >> "$tmp/other" ;; | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
|
||
| esac | ||
| done | ||
|
|
||
| print_section() { | ||
| local title="$1" file="$2" | ||
| [ -s "$file" ] || return 0 | ||
| echo "### $title" | ||
| cat "$file" | ||
| echo | ||
| } | ||
|
|
||
| if [ ! -s "$tmp/feat" ] && [ ! -s "$tmp/fix" ] && [ ! -s "$tmp/docs" ] \ | ||
| && [ ! -s "$tmp/chore" ] && [ ! -s "$tmp/other" ]; then | ||
| echo "No changes since the previous release." | ||
| exit 0 | ||
| fi | ||
|
|
||
| print_section "Features" "$tmp/feat" | ||
| print_section "Fixes" "$tmp/fix" | ||
| print_section "Documentation" "$tmp/docs" | ||
| print_section "Chores" "$tmp/chore" | ||
| print_section "Other Changes" "$tmp/other" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| #!/usr/bin/env bash | ||
| # Fixture-based tests for release-notes.sh (T013/T014). Builds a throwaway | ||
| # git repo with a known commit/tag history rather than touching the real | ||
| # repo's history. Run manually: | ||
| # bash .github/scripts/tests/test-release-notes.sh | ||
|
rsenna marked this conversation as resolved.
|
||
| set -euo pipefail | ||
|
|
||
| script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| script="$script_dir/../release-notes.sh" | ||
|
|
||
| tmp="$(mktemp -d)" | ||
| trap 'rm -rf "$tmp"' EXIT | ||
|
|
||
| pass=0 | ||
| fail=0 | ||
|
|
||
| check_contains() { | ||
| local desc="$1" haystack="$2" needle="$3" | ||
| if printf '%s' "$haystack" | grep -qF -- "$needle"; then | ||
| pass=$((pass + 1)) | ||
| else | ||
| fail=$((fail + 1)) | ||
| echo "FAIL: $desc (expected to find '$needle')" | ||
| fi | ||
| } | ||
|
|
||
| check_not_contains() { | ||
| local desc="$1" haystack="$2" needle="$3" | ||
| if printf '%s' "$haystack" | grep -qF -- "$needle"; then | ||
| fail=$((fail + 1)) | ||
| echo "FAIL: $desc (unexpectedly found '$needle')" | ||
| else | ||
| pass=$((pass + 1)) | ||
| fi | ||
| } | ||
|
|
||
| ( | ||
| cd "$tmp" | ||
| git init -q | ||
| git config user.email "test@example.com" | ||
| git config user.name "Test" | ||
| git config tag.gpgsign false | ||
| tag() { git -c tag.gpgsign=false tag "$1"; } | ||
|
|
||
| echo "one" >file.txt | ||
| git add file.txt | ||
| git commit -q -m "chore: repo init" | ||
| tag v1.0.0 | ||
|
|
||
| echo "two" >file.txt | ||
| git commit -q -am "feat: add substrate boundary" | ||
| echo "three" >file.txt | ||
| git commit -q -am "fix: correct rollback semantics" | ||
| echo "four" >file.txt | ||
| git commit -q -am "docs: update AGENTS.md" | ||
| echo "five" >file.txt | ||
| git commit -q -am "chore: bump toolchain" | ||
| echo "six" >file.txt | ||
| git commit -q -am "tidy up variable names" | ||
| tag v1.1.0 | ||
| ) | ||
|
|
||
| # --- conventional-commit-prefix grouping (feat/fix/docs/chore), FR-007 --- | ||
| out="$(cd "$tmp" && bash "$script" v1.1.0)" | ||
| check_contains "feat commit grouped under Features" "$out" "### Features" | ||
| check_contains "feat commit message present" "$out" "add substrate boundary" | ||
| check_contains "fix commit grouped under Fixes" "$out" "### Fixes" | ||
| check_contains "fix commit message present" "$out" "correct rollback semantics" | ||
| check_contains "docs commit grouped under Documentation" "$out" "### Documentation" | ||
| check_contains "docs commit message present" "$out" "update AGENTS.md" | ||
| check_contains "chore commit grouped under Chores" "$out" "### Chores" | ||
| check_contains "chore commit message present" "$out" "bump toolchain" | ||
|
|
||
| # --- fallback bucket for unmatched commit subjects, FR-007 --- | ||
| check_contains "non-conventional commit grouped under Other Changes" "$out" "### Other Changes" | ||
| check_contains "non-conventional commit message present verbatim" "$out" "tidy up variable names" | ||
|
|
||
| # --- only commits in previous_tag..current_tag are included, not the | ||
| # tagging commit itself (v1.0.0's "chore: repo init" must NOT appear) --- | ||
| check_not_contains "v1.0.0's own commit is excluded from v1.1.0's notes" "$out" "repo init" | ||
|
|
||
| # --- first-release fallback path when no previous tag exists, FR-009 --- | ||
| out_first="$(cd "$tmp" && bash "$script" v1.0.0)" | ||
| check_contains "first release includes its own commit (full-history fallback)" "$out_first" "repo init" | ||
|
|
||
| # --- breaking-change marker (feat!:, fix(scope)!:) groups with its | ||
| # non-breaking counterpart, not the fallback bucket --- | ||
| ( | ||
| cd "$tmp" | ||
| echo "seven" >file.txt | ||
| git commit -q -am "feat!: drop deprecated flag" | ||
| echo "eight" >file.txt | ||
| git commit -q -am "fix(cli)!: change exit code semantics" | ||
| git -c tag.gpgsign=false tag v1.2.0 | ||
| ) | ||
| out_breaking="$(cd "$tmp" && bash "$script" v1.2.0)" | ||
| check_contains "feat! groups under Features" "$out_breaking" "### Features" | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
|
||
| check_contains "feat! message stripped of prefix" "$out_breaking" "drop deprecated flag" | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
|
||
| check_contains "fix(scope)! groups under Fixes" "$out_breaking" "### Fixes" | ||
| check_contains "fix(scope)! message stripped of prefix" "$out_breaking" "change exit code semantics" | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| echo "----" | ||
| echo "pass=$pass fail=$fail" | ||
| [ "$fail" -eq 0 ] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.