···4040cp -r build/Release/ZipMerge.app /Applications/
4141```
42424343-### Automated Release Pipeline
4343+### Release Process
44444545-**See RELEASING.md for complete setup instructions.**
4545+**Use the local release script for simplicity:**
46464747-The project uses GitHub Actions for automated releases. When you push a version tag, it automatically:
4747+```bash
4848+./release.sh v1.0.0
4949+```
5050+5151+This automated script handles everything:
48521. Builds with Developer ID signing
49532. Notarizes with Apple
50543. Creates GitHub release with signed .zip
5151-4. Outputs SHA256 for Homebrew cask
5555+4. Calculates SHA256 hash
5656+5. Updates Homebrew cask automatically
5757+6. Commits and pushes cask update
52585353-**Quick release process:**
5454-```bash
5555-git tag v1.0.0
5656-git push origin v1.0.0
5757-```
5959+**Prerequisites:**
6060+- `gh` CLI installed and authenticated
6161+- Developer ID Application certificate in Keychain
6262+- Apple ID app-specific password (prompted during script)
58635959-Then update the SHA256 in `/Users/jsp/dev/projects/homebrew-tap/Casks/zipmerge.rb` from the release notes.
6060-6161-**Required GitHub Secrets** (one-time setup - see RELEASING.md):
6262-- `CERTIFICATE_BASE64` - Developer ID certificate
6363-- `CERTIFICATE_PASSWORD` - Certificate password
6464-- `APPLE_ID` - Apple ID email
6565-- `APPLE_ID_PASSWORD` - App-specific password for notarization
6464+The script is fully automated and requires no manual steps. See RELEASING.md for details.
66656766### Distributing via Homebrew
6867
+23-5
RELEASING.md
···11# Release Process
2233-This document describes the automated release pipeline for ZipMerge.
33+This document describes how to release ZipMerge.
4455-## Automated Release Pipeline
55+## Local Release Script (Recommended)
6677-Releases are automated via GitHub Actions. When you push a version tag, the workflow will:
77+The easiest way to create a release is using the local `release.sh` script:
8899+```bash
1010+./release.sh v1.0.0
1111+```
1212+1313+This script will:
9141. Build the app with Developer ID signing
10152. Notarize the app with Apple
11163. Create a GitHub release with the signed .zip
1212-4. Output the SHA256 hash for the Homebrew cask
1717+4. Calculate the SHA256 hash
1818+5. Automatically update the Homebrew cask
1919+6. Commit and push the cask update
13201414-## Required GitHub Secrets
2121+**Prerequisites:**
2222+- `gh` CLI installed (`brew install gh`) and authenticated
2323+- Developer ID Application certificate in Keychain
2424+- Apple ID app-specific password (create at https://appleid.apple.com/account/manage)
2525+2626+The script will prompt for your Apple ID and app-specific password.
2727+2828+## Alternative: GitHub Actions (Optional)
2929+3030+If you prefer CI/CD, there's also a GitHub Actions workflow. However, it requires exporting your signing certificate.
3131+3232+## Required GitHub Secrets (GitHub Actions only)
15331634Before creating your first release, set up these secrets in GitHub repository settings (Settings → Secrets and variables → Actions):
1735
+176
release.sh
···11+#!/bin/bash
22+set -e
33+44+# ZipMerge Local Release Script
55+# This script builds, signs, notarizes, and releases ZipMerge
66+77+# Colors for output
88+RED='\033[0;31m'
99+GREEN='\033[0;32m'
1010+YELLOW='\033[1;33m'
1111+NC='\033[0m' # No Color
1212+1313+# Configuration
1414+HOMEBREW_TAP_PATH="/Users/jsp/dev/projects/homebrew-tap"
1515+APPLE_ID="${APPLE_ID:-}" # Set via environment variable or it will prompt
1616+TEAM_ID="M67B42LX8D"
1717+1818+echo -e "${GREEN}🚀 ZipMerge Release Script${NC}"
1919+echo ""
2020+2121+# Check for version argument
2222+if [ -z "$1" ]; then
2323+ echo -e "${RED}Error: Version number required${NC}"
2424+ echo "Usage: ./release.sh v1.0.0"
2525+ exit 1
2626+fi
2727+2828+VERSION="$1"
2929+echo -e "Release version: ${YELLOW}${VERSION}${NC}"
3030+echo ""
3131+3232+# Check if gh CLI is installed
3333+if ! command -v gh &> /dev/null; then
3434+ echo -e "${RED}Error: gh CLI not found. Install with: brew install gh${NC}"
3535+ exit 1
3636+fi
3737+3838+# Check if logged in to gh
3939+if ! gh auth status &> /dev/null; then
4040+ echo -e "${YELLOW}Please login to GitHub CLI:${NC}"
4141+ gh auth login
4242+fi
4343+4444+# Prompt for Apple ID if not set
4545+if [ -z "$APPLE_ID" ]; then
4646+ echo -e "${YELLOW}Enter your Apple ID email:${NC}"
4747+ read APPLE_ID
4848+fi
4949+5050+# Prompt for app-specific password
5151+echo -e "${YELLOW}Enter your Apple ID app-specific password:${NC}"
5252+echo "(Create one at: https://appleid.apple.com/account/manage)"
5353+read -s APPLE_PASSWORD
5454+echo ""
5555+5656+# Clean previous builds
5757+echo -e "${GREEN}🧹 Cleaning previous builds...${NC}"
5858+rm -rf build/
5959+rm -f ZipMerge.zip
6060+6161+# Build the app
6262+echo -e "${GREEN}🔨 Building ZipMerge...${NC}"
6363+xcodebuild -project ZipMerge.xcodeproj \
6464+ -scheme ZipMerge \
6565+ -configuration Release \
6666+ -derivedDataPath ./build \
6767+ CODE_SIGN_IDENTITY="Developer ID Application" \
6868+ clean build
6969+7070+if [ $? -ne 0 ]; then
7171+ echo -e "${RED}Build failed!${NC}"
7272+ exit 1
7373+fi
7474+7575+APP_PATH="./build/Build/Products/Release/ZipMerge.app"
7676+7777+# Verify code signing
7878+echo -e "${GREEN}✅ Verifying code signature...${NC}"
7979+codesign -dv --verbose=4 "$APP_PATH"
8080+8181+# Create zip for notarization
8282+echo -e "${GREEN}📦 Creating archive...${NC}"
8383+cd build/Build/Products/Release
8484+zip -r ../../../../ZipMerge.zip ZipMerge.app
8585+cd ../../../../
8686+8787+# Notarize the app
8888+echo -e "${GREEN}🔐 Submitting for notarization...${NC}"
8989+echo "This may take 5-10 minutes..."
9090+9191+xcrun notarytool submit ZipMerge.zip \
9292+ --apple-id "$APPLE_ID" \
9393+ --team-id "$TEAM_ID" \
9494+ --password "$APPLE_PASSWORD" \
9595+ --wait
9696+9797+if [ $? -ne 0 ]; then
9898+ echo -e "${RED}Notarization failed!${NC}"
9999+ exit 1
100100+fi
101101+102102+# Staple the notarization ticket
103103+echo -e "${GREEN}📎 Stapling notarization ticket...${NC}"
104104+unzip -q ZipMerge.zip
105105+xcrun stapler staple ZipMerge.app
106106+rm ZipMerge.zip
107107+zip -r -q ZipMerge.zip ZipMerge.app
108108+rm -rf ZipMerge.app
109109+110110+# Calculate SHA256
111111+echo -e "${GREEN}🔢 Calculating SHA256...${NC}"
112112+SHA256=$(shasum -a 256 ZipMerge.zip | awk '{print $1}')
113113+echo -e "SHA256: ${YELLOW}${SHA256}${NC}"
114114+115115+# Create git tag
116116+echo -e "${GREEN}🏷️ Creating git tag...${NC}"
117117+git tag -a "$VERSION" -m "Release $VERSION" || echo "Tag already exists"
118118+git push origin "$VERSION" || echo "Tag already pushed"
119119+120120+# Create GitHub release
121121+echo -e "${GREEN}📤 Creating GitHub release...${NC}"
122122+gh release create "$VERSION" ZipMerge.zip \
123123+ --title "ZipMerge $VERSION" \
124124+ --notes "## Installation
125125+126126+### Via Homebrew
127127+\`\`\`bash
128128+brew tap jaspermayone/tap
129129+brew install --cask zipmerge
130130+\`\`\`
131131+132132+### Manual Installation
133133+1. Download ZipMerge.zip
134134+2. Unzip and move ZipMerge.app to /Applications
135135+136136+## SHA256 Checksum
137137+\`\`\`
138138+$SHA256
139139+\`\`\`"
140140+141141+if [ $? -ne 0 ]; then
142142+ echo -e "${RED}GitHub release failed!${NC}"
143143+ exit 1
144144+fi
145145+146146+# Update Homebrew cask
147147+echo -e "${GREEN}🍺 Updating Homebrew cask...${NC}"
148148+149149+CASK_FILE="$HOMEBREW_TAP_PATH/Casks/zipmerge.rb"
150150+151151+if [ ! -f "$CASK_FILE" ]; then
152152+ echo -e "${RED}Error: Cask file not found at $CASK_FILE${NC}"
153153+ exit 1
154154+fi
155155+156156+# Update version and SHA256 in cask file
157157+sed -i '' "s/version \".*\"/version \"${VERSION#v}\"/" "$CASK_FILE"
158158+sed -i '' "s/sha256 .*/sha256 \"$SHA256\"/" "$CASK_FILE"
159159+160160+echo -e "${GREEN}✅ Cask file updated${NC}"
161161+162162+# Commit and push cask update
163163+echo -e "${GREEN}📝 Committing cask update...${NC}"
164164+cd "$HOMEBREW_TAP_PATH"
165165+git add Casks/zipmerge.rb
166166+git commit -m "Update zipmerge to $VERSION"
167167+git push
168168+169169+echo ""
170170+echo -e "${GREEN}✨ Release complete!${NC}"
171171+echo ""
172172+echo "Users can now install with:"
173173+echo -e "${YELLOW}brew tap jaspermayone/tap${NC}"
174174+echo -e "${YELLOW}brew install --cask zipmerge${NC}"
175175+echo ""
176176+echo "SHA256: $SHA256"