docs: add a changelog and the release notes flow
This commit is contained in:
1 parent
d2b04f66ea
commit
b4038baf5b
3 files changed
+330
No files matched your search
Executable
+136
@@ -0,0 +1,136 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Builds the GitHub release notes for a tag, the way big projects such as
|
||||||
|
# Immich lay them out: the hand-written entry from CHANGELOG.md (a welcome,
|
||||||
|
# the highlights), a support section, then every commit since the last
|
||||||
|
# release, sorted by kind, and a link to the full changelog.
|
||||||
|
#
|
||||||
|
# .github/release-notes.sh v1.2.0 the notes
|
||||||
|
# .github/release-notes.sh --title v1.2.0 the title (checks the entry exists)
|
||||||
|
#
|
||||||
|
# Commit authors come from the GitHub API through gh. Without it the list
|
||||||
|
# goes without them.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||||
|
|
||||||
|
title=0
|
||||||
|
if [[ ${1:-} == --title ]]; then
|
||||||
|
title=1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
tag="${1:?usage: release-notes.sh [--title] vX.Y.Z}"
|
||||||
|
|
||||||
|
if ! grep -qx "## $tag" CHANGELOG.md; then
|
||||||
|
echo "CHANGELOG.md has no entry for $tag. Add \"## $tag\" first." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if (( title )); then
|
||||||
|
printf '%s\n' "$tag"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo="${GITHUB_REPOSITORY:-$(git remote get-url origin | sed -E 's#^.*github\.com[:/]##; s#\.git$##')}"
|
||||||
|
name="${repo#*/}"
|
||||||
|
|
||||||
|
# The entry: up to the next one, without the date line (GitHub shows the
|
||||||
|
# date), one heading level up, outside code blocks.
|
||||||
|
entry="$(awk -v h="## $tag" '
|
||||||
|
$0 == h { on = 1; next }
|
||||||
|
on && /^## / { exit }
|
||||||
|
!on { next }
|
||||||
|
/^```/ { code = !code }
|
||||||
|
!code && /^_[0-9]{4}-[0-9]{2}-[0-9]{2}_$/ { next }
|
||||||
|
!code && /^###/ { sub(/^#/, "") }
|
||||||
|
{ print }
|
||||||
|
' CHANGELOG.md | sed -e '/./,$!d')"
|
||||||
|
|
||||||
|
# The commits: from the last release, or from the start. A tag that does not
|
||||||
|
# exist yet is a preview of what HEAD would become.
|
||||||
|
if git rev-parse -q --verify "refs/tags/$tag" > /dev/null; then
|
||||||
|
target="$tag"
|
||||||
|
prev="$(git describe --tags --abbrev=0 --match 'v[0-9]*' "$tag^" 2>/dev/null || true)"
|
||||||
|
else
|
||||||
|
target="$(git rev-parse HEAD)"
|
||||||
|
prev="$(git describe --tags --abbrev=0 --match 'v[0-9]*' HEAD 2>/dev/null || true)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -A login=()
|
||||||
|
if command -v gh > /dev/null; then
|
||||||
|
if [[ -n $prev ]]; then
|
||||||
|
api=(api "repos/$repo/compare/$prev...$target" --jq '.commits[] | [.sha, (.author.login // "")] | @tsv')
|
||||||
|
else
|
||||||
|
api=(api --paginate "repos/$repo/commits?sha=$target&per_page=100" --jq '.[] | [.sha, (.author.login // "")] | @tsv')
|
||||||
|
fi
|
||||||
|
while IFS=$'\t' read -r sha who; do
|
||||||
|
[[ -n $who ]] && login[$sha]="$who"
|
||||||
|
done < <(gh "${api[@]}" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -A list=()
|
||||||
|
count_maint=0
|
||||||
|
while IFS=$'\t' read -r sha subject body; do
|
||||||
|
# Version bumps say nothing a reader needs.
|
||||||
|
[[ $subject =~ ^(chore:\ )?($name\ )?v?[0-9]+\.[0-9]+\.[0-9]+$ ]] && continue
|
||||||
|
|
||||||
|
case "$subject" in
|
||||||
|
*!:*) kind=breaking ;;
|
||||||
|
feat:* | feat\(*) kind=feat ;;
|
||||||
|
fix:* | fix\(*) kind=fix ;;
|
||||||
|
perf:* | perf\(*) kind=enh ;;
|
||||||
|
docs:* | docs\(*) kind=docs ;;
|
||||||
|
chore* | ci:* | ci\(* | build* | refactor* | test* | style*) kind=maint ;;
|
||||||
|
# Older commits without a prefix, sorted by what they say.
|
||||||
|
*README* | *readme* | *Readme*) kind=docs ;;
|
||||||
|
Add\ * | Put\ * | Introduce\ *) kind=feat ;;
|
||||||
|
Fix\ * | Repair\ * | Recover\ * | Stop\ *) kind=fix ;;
|
||||||
|
*\ *) kind=enh ;;
|
||||||
|
*) kind=maint ;;
|
||||||
|
esac
|
||||||
|
[[ $body == *"BREAKING CHANGE"* ]] && kind=breaking
|
||||||
|
[[ $subject == "Initial commit" ]] && kind=maint
|
||||||
|
|
||||||
|
line="* $subject"
|
||||||
|
[[ -n ${login[$sha]:-} ]] && line+=" by @${login[$sha]}"
|
||||||
|
line+=" in https://github.com/$repo/commit/$sha"
|
||||||
|
list[$kind]+="$line"$'\n'
|
||||||
|
[[ $kind == maint ]] && count_maint=$((count_maint + 1))
|
||||||
|
done < <(git log --reverse --no-merges --format='%H%x09%s%x09%b%x1e' "${prev:+$prev..}$target" | tr '\n\036' ' \n' | sed 's/^ //')
|
||||||
|
|
||||||
|
changes=''
|
||||||
|
for pair in "breaking:🚨 Breaking Changes" "feat:🚀 Features" "enh:🌟 Enhancements" "fix:🐛 Bug fixes" "docs:📚 Documentation"; do
|
||||||
|
kind="${pair%%:*}"
|
||||||
|
[[ -n ${list[$kind]:-} ]] || continue
|
||||||
|
changes+="### ${pair#*:}"$'\n'"${list[$kind]}"
|
||||||
|
done
|
||||||
|
if [[ -n ${list[maint]:-} ]]; then
|
||||||
|
changes+=$'\n'"<details><summary>🧰 Maintenance ($count_maint)</summary>"$'\n\n'"${list[maint]}"$'\n'"</details>"$'\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n $prev ]]; then
|
||||||
|
full="**Full Changelog**: https://github.com/$repo/compare/$prev...$tag"
|
||||||
|
else
|
||||||
|
full="**Full Changelog**: https://github.com/$repo/commits/$tag"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A release with highlights is a big one: it gets a heading and the support
|
||||||
|
# section, as in Immich. A patch is a sentence or two and the list.
|
||||||
|
if grep -q '^## Highlights$' <<< "$entry"; then
|
||||||
|
cat <<EOF
|
||||||
|
# 🚀 $name $tag
|
||||||
|
|
||||||
|
$entry
|
||||||
|
|
||||||
|
## ☕ Support $name
|
||||||
|
|
||||||
|
If $name is useful to you, you can buy me a coffee. It keeps these tools going. Found a bug or have an idea? Tell me in the [issues](https://github.com/$repo/issues).
|
||||||
|
|
||||||
|
<a href="https://buymeacoffee.com/felitendo"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="48"></a>
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
printf '%s\n\n' "$entry"
|
||||||
|
fi
|
||||||
|
printf "## What's Changed\n%s\n\n%s\n" "$changes" "$full"
|
||||||
+143
@@ -0,0 +1,143 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
What each release brings, newest first. The [GitHub releases](https://github.com/LoonixTools/cachy-auto-update/releases) add every commit that went into it.
|
||||||
|
|
||||||
|
## v1.3.0
|
||||||
|
|
||||||
|
_2026-08-20_
|
||||||
|
|
||||||
|
Welcome to cachy-auto-update `v1.3.0`! This release is all about the progress bar. It now moves through the whole run, and you can finally see what an update is doing while it works.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- A progress bar that never stands still
|
||||||
|
- Live log under Details
|
||||||
|
- Steps with nothing to do are skipped
|
||||||
|
|
||||||
|
## v1.2.2
|
||||||
|
|
||||||
|
_2026-08-14_
|
||||||
|
|
||||||
|
A small patch for the progress bar. It now counts downloads too, and every step says clearly that an update is running, for example **Updates werden heruntergeladen** instead of just "Paketquellen".
|
||||||
|
|
||||||
|
## v1.2.1
|
||||||
|
|
||||||
|
_2026-08-14_
|
||||||
|
|
||||||
|
A quick fix for the new progress bar, which stayed at "0 of 218 items" for the whole run in `v1.2.0`. It now counts every package.
|
||||||
|
|
||||||
|
`cachy-auto-update enable` can also switch off CachyOS's **Reboot recommended!** popup, which shows up in the middle of an update. It only asks. To undo it, delete the link in `/etc/pacman.d/hooks`.
|
||||||
|
|
||||||
|
## v1.2.0
|
||||||
|
|
||||||
|
_2026-08-14_
|
||||||
|
|
||||||
|
Welcome to cachy-auto-update `v1.2.0`! Updates now show up on your desktop with a real progress bar, and the notifications around them finally behave.
|
||||||
|
|
||||||
|
### 🚨 Breaking changes
|
||||||
|
|
||||||
|
- The `NotifyReboot` setting is gone. Its "restart recommended" notice came while the update was still running, which invited a restart halfway through. `cachy-auto-update status` still tells you when a restart is due.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- A progress bar on the desktop (needs `python-gobject`)
|
||||||
|
- Notifications that stay only when they should
|
||||||
|
|
||||||
|
## v1.1.2
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
Better defaults. The minimum battery level is now 30 % instead of 40 %, and the prompt to silence cachy-update's own "N updates available" notification now defaults to yes. German users can answer it with `j` now, too.
|
||||||
|
|
||||||
|
## v1.1.1
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
The settings screen now reacts instantly. Moving the cursor went from 435 ms to 7.5 ms per key press.
|
||||||
|
|
||||||
|
## v1.1.0
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
Welcome to cachy-auto-update `v1.1.0`! Every option can now be changed from the menu, so nothing needs a text editor any more.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- A settings screen
|
||||||
|
|
||||||
|
## v1.0.9
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
cachy-auto-update now says so before an update starts, and asks you to leave the computer on (`NotifyOnStart`, on by default). The result then replaces that message instead of showing up next to it.
|
||||||
|
|
||||||
|
## v1.0.8
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
An important fix for machines nobody watches. A power cut during an update left pacman's lock file behind, and every later run gave up because of it. A lock from before the last boot is now removed and the update runs again. A lock from the current boot is left alone.
|
||||||
|
|
||||||
|
## v1.0.7
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
The package cache is now trimmed by default. It keeps the last three versions of each package (`KeepOldPackages=3`, like Arch), so it no longer grows to 23 GB. Unused Flatpak runtimes moved to `RemoveOrphans`, which stays off, and the log shows how much space a trim freed.
|
||||||
|
|
||||||
|
## v1.0.6
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
A run started by hand now shows what pacman, the AUR helper and Flatpak are doing, while timer runs stay quiet. A run that gets stopped now shows as "interrupted" in the menu.
|
||||||
|
|
||||||
|
## v1.0.5
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
One package that cannot be updated no longer holds back all the others. It is held back for this run, and everything else updates. On one machine, 213 updates were stuck behind a single package. Held-back packages are shown in the menu and in `cachy-auto-update status`.
|
||||||
|
|
||||||
|
## v1.0.4
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
Switching automatic updates or notifications on or off no longer asks you to press a key. The menu just redraws with the new state.
|
||||||
|
|
||||||
|
## v1.0.3
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
The menu now acts on a single key press, no Enter needed. Enter and the arrow keys can no longer close it by accident.
|
||||||
|
|
||||||
|
## v1.0.2
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
`cachy-auto-update --version` now shows the right version. `v1.0.1` still called itself 1.0.0.
|
||||||
|
|
||||||
|
## v1.0.1
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
The first fixes. pacman's errors were misread on systems that are not in English, "Update now" closed the menu instead of going back to it, and the log was unclear when `checkupdates` is missing.
|
||||||
|
|
||||||
|
## v1.0.0
|
||||||
|
|
||||||
|
_2026-08-08_
|
||||||
|
|
||||||
|
Welcome to the very first release of cachy-auto-update! It keeps CachyOS up to date on its own: pacman, AUR, Flatpak and AppImages, installed in the background with no password prompt and nothing for you to do.
|
||||||
|
|
||||||
|
```
|
||||||
|
CachyOS Auto-Update
|
||||||
|
|
||||||
|
Automatic updates ON
|
||||||
|
Notifications ON
|
||||||
|
|
||||||
|
Last check 3 hours ago
|
||||||
|
Last successful update Sat 08 Aug 2026 04:12:03 CEST (23 packages)
|
||||||
|
Next scheduled run Sat 08 Aug 2026 05:00:00 CEST
|
||||||
|
```
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- Updates at the right moment
|
||||||
|
- Speaks up only when it needs you
|
||||||
|
- No stored password
|
||||||
@@ -14,3 +14,54 @@
|
|||||||
- Subject as short as possible. Imperative, lowercase, no trailing period.
|
- Subject as short as possible. Imperative, lowercase, no trailing period.
|
||||||
- Body only when something genuinely cannot be inferred from the diff.
|
- Body only when something genuinely cannot be inferred from the diff.
|
||||||
- Never add `Co-Authored-By`, "Generated with" or any other AI attribution to commits or PR descriptions.
|
- Never add `Co-Authored-By`, "Generated with" or any other AI attribution to commits or PR descriptions.
|
||||||
|
|
||||||
|
## Releases
|
||||||
|
|
||||||
|
Releases look like the ones of big projects such as Immich. `.github/release-notes.sh <tag>` builds
|
||||||
|
the notes: the entry from `CHANGELOG.md` (welcome and highlights), a support section, every commit
|
||||||
|
since the last release sorted by its prefix (`feat`, `fix`, `docs`, ...) with author and link, and
|
||||||
|
the full changelog link. So commit subjects end up in public: keep them clear.
|
||||||
|
|
||||||
|
1. Read `git log <last tag>..HEAD` and pick the version: only fixes → patch, something new → minor,
|
||||||
|
something that breaks or needs the user to act → major.
|
||||||
|
2. Bump the version and add the entry at the top of `CHANGELOG.md`, in one commit (`chore: 1.4.0`).
|
||||||
|
3. Push, tag and create the release:
|
||||||
|
```bash
|
||||||
|
git tag v1.4.0 && git push origin main v1.4.0
|
||||||
|
gh release create v1.4.0 --title v1.4.0 --notes "$(.github/release-notes.sh v1.4.0)"
|
||||||
|
```
|
||||||
|
4. PKGBUILDS picks up the new release for the AUR on its own.
|
||||||
|
|
||||||
|
A minor or major release (has `### Highlights`, gets a heading and the support section):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## v1.4.0
|
||||||
|
|
||||||
|
_2026-09-24_
|
||||||
|
|
||||||
|
Welcome to cachy-auto-update `v1.4.0`! One or two sentences on what this release is about.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="480" alt="What the picture shows" src="https://raw.githubusercontent.com/LoonixTools/cachy-auto-update/v1.4.0/<path>">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
### 🚨 Breaking changes
|
||||||
|
|
||||||
|
- Only if there are any: what changed, and what the user has to do.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- First highlight, a few words
|
||||||
|
- Second highlight
|
||||||
|
```
|
||||||
|
|
||||||
|
A picture or a snippet of the menu under the welcome is optional. The highlights stay a plain list:
|
||||||
|
no heading or text per highlight, the list of commits explains the rest.
|
||||||
|
|
||||||
|
A patch release is just a sentence or two, for example: "A small patch. The menu no longer closes
|
||||||
|
when you press Enter." The list of commits follows on its own.
|
||||||
|
|
||||||
|
- Write for users: what they notice, not how the code does it. Friendly and simple.
|
||||||
|
- Commands and settings they type go in backticks, buttons and labels in bold.
|
||||||
|
- To change an old release: edit its entry, commit, then
|
||||||
|
`gh release edit <tag> --title <tag> --notes "$(.github/release-notes.sh <tag>)"`.
|
||||||
Reference in new issue
Block a user