feat(scripts): generate a Markdown changelog alongside the DMG

Groups commits since the last tag by conventional-commit type
(feat/fix/perf/refactor/docs/test/chore/other) and prints it to the
terminal for pasting into the Gitea release notes - nothing gets
written to the repo, it's regenerated from git log every run.
Handles both the "already tagged, HEAD == tag" and "about to tag,
HEAD ahead of the last tag" cases.
This commit is contained in:
2026-08-14 03:18:30 +01:00
parent 472b9658d8
commit 4630f9ef8b
6 changed files with 80 additions and 1 deletions
@@ -58,21 +58,25 @@
"size" : "128x128"
},
{
"filename" : "outpost.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "outpost 1.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "outpost 2.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "outpost 3.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

+76 -1
View File
@@ -1,6 +1,9 @@
#!/bin/bash
# Packages an already-exported Outpost.app into a distributable DMG with an
# Applications-folder symlink for drag-to-install.
# Applications-folder symlink for drag-to-install, then prints a Markdown
# changelog to the terminal for pasting into the Gitea release notes —
# nothing is written to the repo, this is generated fresh from git log
# every time.
#
# Usage: scripts/package-dmg.sh /path/to/Outpost.app [output-dir]
#
@@ -44,3 +47,75 @@ hdiutil create \
"$DMG_PATH"
echo "Done: $DMG_PATH"
# --- Changelog -------------------------------------------------------------
# Groups commits by conventional-commit type (feat/fix/.../other) between the
# previous tag and whatever's being released. Two workflows are supported:
# - already tagged (HEAD == latest tag): diff against the tag before it.
# - not tagged yet (HEAD ahead of latest tag): diff since that tag.
# Falls back to the full log if there are no tags at all yet.
print_section() {
title="$1"
content="$2"
if [ -n "$content" ]; then
printf '### %s\n\n%s\n' "$title" "$content"
fi
}
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
if [ -z "$REPO_ROOT" ]; then
echo "" >&2
echo "warning: not inside a git repository, skipping changelog" >&2
exit 0
fi
LATEST_TAG="$(git -C "$REPO_ROOT" describe --tags --abbrev=0 2>/dev/null || true)"
if [ -z "$LATEST_TAG" ]; then
RANGE="HEAD"
HEADING="Changelog"
else
HEAD_COMMIT="$(git -C "$REPO_ROOT" rev-parse HEAD)"
TAG_COMMIT="$(git -C "$REPO_ROOT" rev-parse "$LATEST_TAG")"
if [ "$HEAD_COMMIT" = "$TAG_COMMIT" ]; then
PREV_TAG="$(git -C "$REPO_ROOT" describe --tags --abbrev=0 "${LATEST_TAG}^" 2>/dev/null || true)"
RANGE="${PREV_TAG:+$PREV_TAG..}$LATEST_TAG"
HEADING="Changelog ($LATEST_TAG)"
else
RANGE="$LATEST_TAG..HEAD"
HEADING="Changelog (since $LATEST_TAG)"
fi
fi
FEAT="" ; FIX="" ; PERF="" ; REFACTOR="" ; DOCS="" ; TESTS="" ; CHORE="" ; OTHER=""
while IFS='|' read -r hash subject; do
[ -z "${hash:-}" ] && continue
case "$subject" in
feat*) FEAT="${FEAT}- ${subject#*: } (${hash})"$'\n' ;;
fix*) FIX="${FIX}- ${subject#*: } (${hash})"$'\n' ;;
perf*) PERF="${PERF}- ${subject#*: } (${hash})"$'\n' ;;
refactor*) REFACTOR="${REFACTOR}- ${subject#*: } (${hash})"$'\n' ;;
docs*) DOCS="${DOCS}- ${subject#*: } (${hash})"$'\n' ;;
test*) TESTS="${TESTS}- ${subject#*: } (${hash})"$'\n' ;;
chore*) CHORE="${CHORE}- ${subject#*: } (${hash})"$'\n' ;;
*) OTHER="${OTHER}- ${subject} (${hash})"$'\n' ;;
esac
done <<EOF
$(git -C "$REPO_ROOT" log "$RANGE" --no-merges --pretty=format:'%h|%s' 2>/dev/null)
EOF
echo ""
echo "---"
echo ""
echo "## $HEADING"
echo ""
print_section "Features" "$FEAT"
print_section "Fixes" "$FIX"
print_section "Performance" "$PERF"
print_section "Refactors" "$REFACTOR"
print_section "Documentation" "$DOCS"
print_section "Tests" "$TESTS"
print_section "Chores" "$CHORE"
print_section "Other" "$OTHER"