Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 28 additions & 54 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
env:
RELEASE_TAG: ${{ github.ref_name }}

steps:
- name: Checkout
Expand Down Expand Up @@ -52,54 +54,32 @@ jobs:
SPARKLE_PUBLIC_KEY = $SPARKLE_PUBLIC_KEY
EOF

- name: Validate and derive release metadata
- name: Validate release version
run: |
TAG="$GITHUB_REF_NAME"

if [[ ! "$TAG" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)(-([0-9A-Za-z]+([.-][0-9A-Za-z]+)*))?$ ]]; then
echo "Tag must be in vX.Y.Z or vX.Y.Z-suffix format, received: $TAG"
exit 1
fi

MARKETING_VERSION="${BASH_REMATCH[1]}"
RELEASE_VERSION="${TAG#v}"
IS_PRERELEASE=false
if [[ "$TAG" != "v$MARKETING_VERSION" ]]; then
IS_PRERELEASE=true
fi

PROJECT_VERSIONS="$(
BUILD_SETTINGS="$(
xcodebuild \
-project BitDream.xcodeproj \
-scheme BitDream \
-configuration Release \
-destination "generic/platform=macOS" \
-showBuildSettings |
awk '$1 == "MARKETING_VERSION" && $2 == "=" { print $3 }' |
sort -u
-showBuildSettings
)"
VERSION_COUNT="$(printf '%s\n' "$PROJECT_VERSIONS" | awk 'NF { count++ } END { print count + 0 }')"
MARKETING_VERSIONS="$(printf '%s\n' "$BUILD_SETTINGS" | awk '$1 == "MARKETING_VERSION" && $2 == "=" { print $3 }' | sort -u)"
VERSION_COUNT="$(printf '%s\n' "$MARKETING_VERSIONS" | awk 'NF { count++ } END { print count + 0 }')"

if [[ "$VERSION_COUNT" -ne 1 ]]; then
echo "Expected exactly one project MARKETING_VERSION, but found $VERSION_COUNT."
printf '%s\n' "$PROJECT_VERSIONS"
echo "Expected exactly one MARKETING_VERSION, but found $VERSION_COUNT."
printf '%s\n' "$MARKETING_VERSIONS"
exit 1
fi

if [[ "$MARKETING_VERSION" != "$PROJECT_VERSIONS" ]]; then
echo "Release tag $TAG does not match project MARKETING_VERSION $PROJECT_VERSIONS."
echo "Expected v$PROJECT_VERSIONS or v$PROJECT_VERSIONS-suffix."
EXPECTED_TAG="v$MARKETING_VERSIONS"
if [[ "$RELEASE_TAG" != "$EXPECTED_TAG" ]]; then
Comment thread
austin-smith marked this conversation as resolved.
echo "Release tag $RELEASE_TAG does not match MARKETING_VERSION $MARKETING_VERSIONS."
echo "Expected tag: $EXPECTED_TAG"
exit 1
fi

BUILD_NUMBER="$GITHUB_RUN_NUMBER"

echo "RELEASE_TAG=$TAG" >> "$GITHUB_ENV"
echo "RELEASE_VERSION=$RELEASE_VERSION" >> "$GITHUB_ENV"
echo "MARKETING_VERSION=$MARKETING_VERSION" >> "$GITHUB_ENV"
echo "BUILD_NUMBER=$BUILD_NUMBER" >> "$GITHUB_ENV"
echo "IS_PRERELEASE=$IS_PRERELEASE" >> "$GITHUB_ENV"

- name: Import Apple signing certificate
env:
P12_BASE64: ${{ secrets.APPLE_CERT_P12_BASE64 }}
Expand Down Expand Up @@ -182,6 +162,9 @@ jobs:

- name: Build macOS app archive
run: |
# Sparkle compares CFBundleVersion, so released builds stamp the
# validated release version there. The project keeps a local build
# number for development builds.
xcodebuild archive \
-project BitDream.xcodeproj \
-scheme BitDream \
Expand All @@ -192,8 +175,7 @@ jobs:
CODE_SIGN_IDENTITY="Developer ID Application" \
DEVELOPMENT_TEAM="${{ secrets.APPLE_TEAM_ID }}" \
OTHER_CODE_SIGN_FLAGS="--keychain $KEYCHAIN_PATH" \
MARKETING_VERSION="$MARKETING_VERSION" \
CURRENT_PROJECT_VERSION="$BUILD_NUMBER" \
CURRENT_PROJECT_VERSION="${RELEASE_TAG#v}" \
Comment thread
austin-smith marked this conversation as resolved.
SPARKLE_APPCAST_URL="$SPARKLE_APPCAST_URL" \
SPARKLE_PUBLIC_KEY="$SPARKLE_PUBLIC_KEY" \
ARCHS=arm64
Expand Down Expand Up @@ -308,7 +290,7 @@ jobs:
rm -f "$DMG_PATH"

create-dmg \
--volname "BitDream ${MARKETING_VERSION}" \
--volname "BitDream ${RELEASE_TAG#v}" \
--volicon "$VOLUME_ICON_PATH" \
--window-size 660 420 \
--background "$DMG_BACKGROUND_PATH" \
Expand Down Expand Up @@ -397,6 +379,12 @@ jobs:
codesign --verify --verbose=2 "$DMG_PATH"
xcrun stapler validate "$DMG_PATH"

BUNDLE_VERSION="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' "$APP_PATH/Contents/Info.plist")"
if [[ "v$BUNDLE_VERSION" != "$RELEASE_TAG" ]]; then
echo "CFBundleVersion ($BUNDLE_VERSION) does not match the release tag ($RELEASE_TAG)."
exit 1
fi

- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
Expand All @@ -405,18 +393,10 @@ jobs:
if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
gh release upload "$RELEASE_TAG" "$DMG_PATH" --clobber
else
if [[ "${IS_PRERELEASE}" == "true" ]]; then
gh release create "$RELEASE_TAG" \
--title "$RELEASE_TAG" \
--generate-notes \
--prerelease \
"$DMG_PATH"
else
gh release create "$RELEASE_TAG" \
--title "$RELEASE_TAG" \
--generate-notes \
"$DMG_PATH"
fi
gh release create "$RELEASE_TAG" \
--title "$RELEASE_TAG" \
--generate-notes \
"$DMG_PATH"
fi

- name: Prepare Sparkle private key
Expand Down Expand Up @@ -460,12 +440,6 @@ jobs:
rm -rf "$APPCAST_WORK_DIR" "$PAGES_DIR"
mkdir -p "$APPCAST_WORK_DIR" "$PAGES_DIR"

if curl -fsSL "$SPARKLE_APPCAST_URL" -o "$APPCAST_WORK_DIR/appcast.xml"; then
echo "Using existing appcast.xml from GitHub Pages"
else
echo "No existing appcast.xml found; generating a new feed"
fi

cp "$DMG_PATH" "$APPCAST_WORK_DIR/"

"$GENERATE_APPCAST" \
Expand Down
8 changes: 4 additions & 4 deletions BitDream.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 26.0;
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.0.1;
PRODUCT_BUNDLE_IDENTIFIER = crapshack.BitDream;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand Down Expand Up @@ -552,7 +552,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 26.0;
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.0.1;
PRODUCT_BUNDLE_IDENTIFIER = crapshack.BitDream;
PRODUCT_NAME = "$(TARGET_NAME)";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "BitDream App Developer ID";
Expand Down Expand Up @@ -590,7 +590,7 @@
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 26.0;
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.0.1;
PRODUCT_BUNDLE_IDENTIFIER = crapshack.BitDream.BitDreamWidgets;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand Down Expand Up @@ -636,7 +636,7 @@
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 26.0;
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.0.1;
PRODUCT_BUNDLE_IDENTIFIER = crapshack.BitDream.BitDreamWidgets;
PRODUCT_NAME = "$(TARGET_NAME)";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "BitDream Widget Developer ID";
Expand Down
7 changes: 0 additions & 7 deletions docs/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@ Run the preflight checks, then create a stable release tag:
./scripts/tag-version.sh
```

For a prerelease, provide a suffix without the leading hyphen:

```bash
./scripts/tag-version.sh --dry-run --prerelease beta.1
./scripts/tag-version.sh --prerelease beta.1
```

Pushing the tag starts `.github/workflows/release.yml`, which builds, signs, notarizes, and publishes the macOS release. The workflow rejects tags that do not match the Xcode marketing version.

See `docs/build-settings.md` and `docs/sparkle-updates.md` for configuration details.
28 changes: 3 additions & 25 deletions scripts/tag-version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,24 @@ set -euo pipefail

usage() {
cat <<'EOF'
Usage: ./scripts/tag-version.sh [--dry-run] [--prerelease SUFFIX]
Usage: ./scripts/tag-version.sh [--dry-run]

Create and push a release tag based on the app's MARKETING_VERSION.

Options:
--dry-run Run every preflight check without creating or pushing a tag.
--prerelease SUFFIX Append a prerelease suffix, for example beta.1.
-h, --help Show this help text.
--dry-run Run every preflight check without creating or pushing a tag.
-h, --help Show this help text.
EOF
}

dry_run=false
prerelease_suffix=""

while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run)
dry_run=true
shift
;;
--prerelease)
if [[ $# -lt 2 || -z "$2" ]]; then
echo "--prerelease requires a suffix." >&2
usage >&2
exit 2
fi
prerelease_suffix="$2"
shift 2
;;
-h|--help)
usage
exit 0
Expand All @@ -45,11 +34,6 @@ while [[ $# -gt 0 ]]; do
esac
done

if [[ -n "$prerelease_suffix" && ! "$prerelease_suffix" =~ ^[0-9A-Za-z]+([.-][0-9A-Za-z]+)*$ ]]; then
echo "Prerelease suffix must contain alphanumeric identifiers separated by dots or hyphens: $prerelease_suffix" >&2
exit 2
fi

for command in git xcodebuild; do
if ! command -v "$command" >/dev/null 2>&1; then
echo "Required command not found: $command" >&2
Expand Down Expand Up @@ -124,9 +108,6 @@ if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
fi

tag="v$version"
if [[ -n "$prerelease_suffix" ]]; then
tag="$tag-$prerelease_suffix"
fi

if git show-ref --verify --quiet "refs/tags/$tag"; then
echo "Tag already exists: $tag" >&2
Expand All @@ -146,9 +127,6 @@ fi
short_commit="$(git rev-parse --short HEAD)"
echo
echo "Release version: $version"
if [[ -n "$prerelease_suffix" ]]; then
echo "Prerelease: $prerelease_suffix"
fi
echo "Tag: $tag"
echo "Commit: $short_commit"

Expand Down
Loading