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.
122 lines
4.0 KiB
Bash
Executable File
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"
|