Files
Outpost/scripts/package-dmg.sh
T
Puranjay Savar Mattas 4630f9ef8b 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.
2026-08-14 03:18:30 +01:00

122 lines
4.0 KiB
Bash
Executable File

#!/bin/bash
# Packages an already-exported Outpost.app into a distributable DMG with an
# 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]
#
# Produces: <output-dir>/Outpost-<version>.dmg
# Version/build number are read directly from the app's own Info.plist, so
# this always matches whatever MARKETING_VERSION was set to at archive time.
set -euo pipefail
APP_PATH="${1:?Usage: package-dmg.sh /path/to/Outpost.app [output-dir]}"
OUT_DIR="${2:-$(pwd)/dist}"
if [ ! -d "$APP_PATH" ]; then
echo "error: '$APP_PATH' not found or not a directory" >&2
exit 1
fi
APP_NAME="$(basename "$APP_PATH" .app)"
VERSION="$(defaults read "$APP_PATH/Contents/Info" CFBundleShortVersionString)"
BUILD="$(defaults read "$APP_PATH/Contents/Info" CFBundleVersion)"
mkdir -p "$OUT_DIR"
STAGING_DIR="$(mktemp -d)"
trap 'rm -rf "$STAGING_DIR"' EXIT
echo "Staging '$APP_NAME.app' ($VERSION build $BUILD)..."
cp -R "$APP_PATH" "$STAGING_DIR/"
ln -s /Applications "$STAGING_DIR/Applications"
DMG_NAME="${APP_NAME}-${VERSION}.dmg"
DMG_PATH="$OUT_DIR/$DMG_NAME"
rm -f "$DMG_PATH"
echo "Building $DMG_NAME..."
hdiutil create \
-volname "$APP_NAME $VERSION" \
-srcfolder "$STAGING_DIR" \
-ov \
-format UDZO \
"$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"