Repository navigation
ci(release): stop CHANGELOG.md gaining a blank line at every release #690
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
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
1c4661e
ci(release): stop CHANGELOG.md gaining a blank line at every release
aliasunder f80b14e
ci(release): insert a release that replaces [Unreleased] the same way…
aliasunder 068d350
docs: collapse the double blank lines between older CHANGELOG.md entries
aliasunder 4b4bbb1
ci(release): give an empty CHANGELOG.md the same title as a missing one
aliasunder b15b6dd
ci(release): keep one blank line around an entry with empty notes
aliasunder 28b467d
fix(review): end CHANGELOG.md with one newline after removing a trail…
aliasunder f2106ea
style(release): gather update-changelog.sh's blank-line handling in o…
aliasunder e5cc501
ci(release): read and write the changelog as UTF-8 whatever the locale
aliasunder 0d38547
test(release): cover update-changelog.sh's entry placement and blank …
aliasunder 117d471
ci(release): let update-changelog.sh read its notes from /dev/stdin
aliasunder 3a9f5a2
test(release): feed /dev/stdin from a file so the test holds on Linux
aliasunder 3e82002
test(release): cover a changelog that has no final newline
aliasunder 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 |
|---|---|---|
| @@ -1,45 +1,50 @@ | ||
| #!/usr/bin/env bash | ||
| # Update CHANGELOG.md with release notes for a given version. | ||
| # Update CHANGELOG.md in the current directory with release notes for a | ||
| # given version. | ||
| # Usage: update-changelog.sh <version> <notes-file> | ||
| # Replaces [Unreleased] section if present, otherwise inserts after header. | ||
| # The entry goes above the newest version entry, replacing an [Unreleased] | ||
| # section if there is one. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| VERSION="${1:?Usage: update-changelog.sh <version> <notes-file>}" | ||
| NOTES_FILE="${2:?Usage: update-changelog.sh <version> <notes-file>}" | ||
|
|
||
| NOTES=$(cat "$NOTES_FILE") | ||
| DATE=$(date +%Y-%m-%d) | ||
|
|
||
| python3 - "$VERSION" "$DATE" "$NOTES" << 'PYTHON' | ||
| import sys, re, os | ||
|
|
||
| version, date, notes = sys.argv[1], sys.argv[2], sys.argv[3] | ||
| entry = f"## [{version}] — {date}\n\n{notes}" | ||
|
|
||
| changelog_path = "CHANGELOG.md" | ||
| if os.path.exists(changelog_path): | ||
| with open(changelog_path) as f: | ||
| text = f.read() | ||
| # Replace [Unreleased] section if present | ||
| if re.search(r'^## \[Unreleased\]', text, re.MULTILINE): | ||
| text = re.sub( | ||
| r'## \[Unreleased\].*?(?=\n## \[|$)', | ||
| entry, | ||
| text, count=1, flags=re.DOTALL | ||
| ) | ||
| else: | ||
| # Insert before the first version entry (## [x.y.z]) | ||
| lines = text.split('\n') | ||
| insert_at = next( | ||
| (i for i in range(len(lines)) if lines[i].startswith('## [')), | ||
| len(lines) | ||
| ) | ||
| lines.insert(insert_at, f"\n{entry}\n") | ||
| text = '\n'.join(lines) | ||
| else: | ||
| text = f"# Changelog\n\n{entry}\n" | ||
|
|
||
| with open(changelog_path, 'w') as f: | ||
| f.write(text) | ||
| # Python reads this program from fd 3, not stdin, so a notes file of | ||
| # /dev/stdin still reads the caller's stdin. | ||
| python3 /dev/fd/3 "$VERSION" "$DATE" "$NOTES_FILE" 3<< 'PYTHON' | ||
| import sys, re | ||
| from pathlib import Path | ||
|
|
||
| # From an "## [Unreleased]" heading up to the next "## [" heading or the end | ||
| # of the file, the section's trailing blank lines included. | ||
| UNRELEASED_SECTION = re.compile( | ||
| r'^## \[Unreleased\].*?(?=^## \[|\Z)', re.DOTALL | re.MULTILINE | ||
| ) | ||
| # An entry heading: any line starting "## [". | ||
| ENTRY_HEADING = re.compile(r'^## \[', re.MULTILINE) | ||
|
|
||
| version, date, notes_file = sys.argv[1:] | ||
| notes = Path(notes_file).read_text(encoding="utf-8") | ||
|
|
||
| changelog = Path("CHANGELOG.md") | ||
| text = changelog.read_text(encoding="utf-8") if changelog.exists() else "" | ||
| # Remove an [Unreleased] section rather than replace it with the entry: | ||
| # re.sub reads backslashes in a replacement string as escapes. | ||
| text = UNRELEASED_SECTION.sub('', text, count=1) | ||
|
|
||
| first_entry = ENTRY_HEADING.search(text) | ||
| header_end = first_entry.start() if first_entry else len(text) | ||
|
|
||
| # With no text above the first entry, the header is a "# Changelog" title. | ||
| header = text[:header_end].rstrip() or "# Changelog" | ||
| entry = f"## [{version}] — {date}\n\n{notes}".rstrip() | ||
| earlier_entries = text[header_end:].rstrip() | ||
|
|
||
| # Every part is rstripped, so the join leaves exactly one blank line between | ||
| # parts and a single newline at the end of the file. | ||
| parts = [header, entry, earlier_entries] | ||
| changelog.write_text("\n\n".join(part for part in parts if part) + "\n", encoding="utf-8") | ||
| PYTHON | ||
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
Oops, something went wrong.
Oops, something went wrong.
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.