Skip to content

Commit 932ed37

Browse files
committed
feat: add DMG release workflow
- Add create-dmg.sh script for building signed/notarized DMG - Add release and release-local make targets - Add GitHub Actions workflow for releases - Add build/ to .gitignore
1 parent c73e27b commit 932ed37

5 files changed

Lines changed: 435 additions & 7 deletions

File tree

.github/workflows/release.yml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*.*.*'
7+
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: 'Version number (e.g., 1.2.3)'
11+
required: true
12+
type: string
13+
14+
permissions:
15+
contents: write
16+
17+
jobs:
18+
build-and-release:
19+
name: Build and Release
20+
runs-on: macos-15
21+
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Determine version
27+
id: version
28+
run: |
29+
if [ "${{ github.event_name }}" = "push" ]; then
30+
VERSION="${GITHUB_REF#refs/tags/v}"
31+
else
32+
VERSION="${{ github.event.inputs.version }}"
33+
fi
34+
echo "version=$VERSION" >> $GITHUB_OUTPUT
35+
echo "Version: $VERSION"
36+
37+
- name: Install dependencies
38+
run: brew install create-dmg
39+
40+
- name: Install Apple certificate
41+
env:
42+
CERTIFICATE_BASE64: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERT_BASE64 }}
43+
CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERT_PASSWORD }}
44+
KEYCHAIN_PASSWORD: ${{ github.run_id }}
45+
run: |
46+
# Create temporary keychain
47+
KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db"
48+
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
49+
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
50+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
51+
52+
# Import certificate
53+
CERT_PATH="$RUNNER_TEMP/certificate.p12"
54+
echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH"
55+
security import "$CERT_PATH" \
56+
-P "$CERTIFICATE_PASSWORD" \
57+
-A \
58+
-t cert \
59+
-f pkcs12 \
60+
-k "$KEYCHAIN_PATH"
61+
62+
# Allow codesign access without prompts
63+
security set-key-partition-list -S apple-tool:,apple: \
64+
-s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
65+
66+
# Add to search list (prepend to ensure it's found first)
67+
security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain
68+
69+
# Verify certificate was imported
70+
echo "Verifying certificate..."
71+
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
72+
73+
- name: Build and create DMG
74+
env:
75+
DEVELOPER_ID_APPLICATION: "Developer ID Application: Liang Yuan (${{ secrets.APPLE_TEAM_ID }})"
76+
APPLE_ID: ${{ secrets.APPLE_ID }}
77+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
78+
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
79+
run: |
80+
chmod +x scripts/create-dmg.sh
81+
./scripts/create-dmg.sh --version "${{ steps.version.outputs.version }}"
82+
83+
- name: Upload DMG artifact
84+
uses: actions/upload-artifact@v4
85+
with:
86+
name: ClaudeCodeUsage-${{ steps.version.outputs.version }}
87+
path: build/ClaudeCodeUsage.dmg
88+
if-no-files-found: error
89+
90+
- name: Create GitHub Release
91+
uses: softprops/action-gh-release@v2
92+
with:
93+
name: ClaudeCodeUsage v${{ steps.version.outputs.version }}
94+
draft: false
95+
prerelease: ${{ contains(steps.version.outputs.version, '-') }}
96+
files: build/ClaudeCodeUsage.dmg
97+
generate_release_notes: true
98+
env:
99+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
100+
101+
- name: Cleanup keychain
102+
if: always()
103+
run: |
104+
security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" || true

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,4 @@ fastlane/screenshots/**/*.png
6666
fastlane/test_output
6767
.DS_Store
6868
/CLAUDE.md
69+
build/

ClaudeCodeUsage.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
ECF4102B2F03E6AD00DFC0C8 /* ClaudeCodeUsage.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ClaudeCodeUsage.app; sourceTree = BUILT_PRODUCTS_DIR; };
3838
ECF410382F03E6AE00DFC0C8 /* ClaudeCodeUsageTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ClaudeCodeUsageTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3939
ECF410422F03E6AE00DFC0C8 /* ClaudeCodeUsageUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ClaudeCodeUsageUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
40-
ECF412B82F03F9B900DFC0C8 /* ClaudeCodeUsage.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = file; path = ClaudeCodeUsage.xctestplan; sourceTree = "<group>"; };
40+
ECF412B82F03F9B900DFC0C8 /* ClaudeCodeUsage.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = ClaudeCodeUsage.xctestplan; sourceTree = "<group>"; };
4141
/* End PBXFileReference section */
4242

4343
/* Begin PBXFileSystemSynchronizedRootGroup section */

Makefile

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
# Makefile for ClaudeCodeUsage
22
# Provides convenient commands for development
33

4-
.PHONY: help test test-core test-data test-ui clean format lint screenshot
4+
.PHONY: help test test-core test-data test-ui clean format lint screenshot release release-local
55

66
# Default target
77
help:
88
@echo "ClaudeCodeUsage Development Commands"
99
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
10-
@echo " make test - Run all tests"
11-
@echo " make screenshot - Capture UI previews to /tmp/ClaudeUsageUI/"
12-
@echo " make clean - Clean build artifacts"
13-
@echo " make format - Format code with swift-format"
14-
@echo " make lint - Lint code with SwiftLint"
10+
@echo " make test - Run all tests"
11+
@echo " make screenshot - Capture UI previews to /tmp/ClaudeUsageUI/"
12+
@echo " make clean - Clean build artifacts"
13+
@echo " make format - Format code with swift-format"
14+
@echo " make lint - Lint code with SwiftLint"
15+
@echo " make release - Build signed/notarized DMG"
16+
@echo " make release-local - Build DMG (skip notarization)"
1517

1618
# Run all tests
1719
test: test-core test-data test-ui
@@ -30,6 +32,7 @@ clean:
3032
rm -rf Packages/ClaudeUsageCore/.build
3133
rm -rf Packages/ClaudeUsageData/.build
3234
rm -rf Packages/ClaudeUsageUI/.build
35+
rm -rf build
3336

3437
# Format code (requires swift-format)
3538
format:
@@ -51,3 +54,11 @@ lint:
5154
screenshot:
5255
swift run --package-path Packages/ClaudeUsageUI PreviewCapture
5356
@echo "Screenshots saved to /tmp/ClaudeUsageUI/"
57+
58+
# Build signed and notarized DMG for distribution
59+
release:
60+
@./scripts/create-dmg.sh
61+
62+
# Build DMG without notarization (for local testing)
63+
release-local:
64+
@./scripts/create-dmg.sh --skip-notarize

0 commit comments

Comments
 (0)