Skip to content

Commit 8eb74fb

Browse files
authored
Merge pull request #57 from K9i-0/feature/add-sparkle-auto-update
feat: add Sparkle framework for automatic updates
2 parents c723c04 + b6f1f91 commit 8eb74fb

20 files changed

+1512
-309
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: CI
22

33
on:
44
push:
5-
branches: [ main ]
5+
branches: [ main, develop ]
66
pull_request:
7-
branches: [ main ]
7+
branches: [ main, develop ]
88

99
jobs:
1010
build:
@@ -15,7 +15,7 @@ jobs:
1515
- uses: actions/checkout@v4
1616

1717
- name: Select Xcode
18-
run: sudo xcode-select -s /Applications/Xcode_15.2.app
18+
run: sudo xcode-select -s /Applications/Xcode_16.2.app
1919

2020
- name: Build Debug
2121
run: swift build -v
@@ -33,7 +33,7 @@ jobs:
3333
runs-on: macos-latest
3434
strategy:
3535
matrix:
36-
xcode: ['15.0', '15.2']
36+
xcode: ['15.4', '16.2']
3737

3838
steps:
3939
- uses: actions/checkout@v4

.github/workflows/pr-validation.yml

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
name: PR Validation
2+
3+
on:
4+
pull_request:
5+
branches: [develop, main]
6+
types: [opened, synchronize]
7+
8+
jobs:
9+
validate-version:
10+
name: Validate Version Update
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
with:
16+
fetch-depth: 0
17+
18+
- name: Check which branch we're merging to
19+
id: target
20+
run: |
21+
echo "base_branch=${{ github.base_ref }}" >> $GITHUB_OUTPUT
22+
echo "head_branch=${{ github.head_ref }}" >> $GITHUB_OUTPUT
23+
echo "Merging from ${{ github.head_ref }} to ${{ github.base_ref }}"
24+
25+
# Validation for feature -> develop PRs
26+
- name: Validate feature to develop
27+
if: github.base_ref == 'develop' && startsWith(github.head_ref, 'feature/')
28+
run: |
29+
echo "## Validating feature → develop PR"
30+
31+
# Get version from base branch (develop)
32+
git fetch origin develop
33+
BASE_VERSION=$(git show origin/develop:Info.plist | grep -A1 "CFBundleShortVersionString" | tail -1 | sed -E 's/.*<string>(.*)<\/string>.*/\1/')
34+
echo "Develop branch version: $BASE_VERSION"
35+
36+
# Get version from PR branch
37+
PR_VERSION=$(grep -A1 "CFBundleShortVersionString" Info.plist | tail -1 | sed -E 's/.*<string>(.*)<\/string>.*/\1/')
38+
echo "PR branch version: $PR_VERSION"
39+
40+
# Check if version was updated
41+
if [ "$BASE_VERSION" = "$PR_VERSION" ]; then
42+
echo "❌ Error: Version not updated in Info.plist"
43+
echo "Please update the version number when merging features to develop"
44+
echo ""
45+
echo "Current version: $BASE_VERSION"
46+
echo "Expected: A higher version number"
47+
exit 1
48+
fi
49+
50+
# Validate version format (should be x.y.z)
51+
if ! echo "$PR_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
52+
echo "❌ Error: Invalid version format"
53+
echo "Version should be in format: x.y.z (e.g., 1.2.3)"
54+
echo "Found: $PR_VERSION"
55+
exit 1
56+
fi
57+
58+
echo "✅ Version updated: $BASE_VERSION → $PR_VERSION"
59+
60+
# Validation for develop -> main PRs
61+
- name: Validate develop to main
62+
if: github.base_ref == 'main' && github.head_ref == 'develop'
63+
run: |
64+
echo "## Validating develop → main PR"
65+
66+
# Check if CHANGELOG.md was updated
67+
if ! git diff origin/main --name-only | grep -q "CHANGELOG.md"; then
68+
echo "❌ Error: CHANGELOG.md not updated"
69+
echo "Please update CHANGELOG.md with release notes before merging to main"
70+
exit 1
71+
fi
72+
73+
echo "✅ CHANGELOG.md has been updated"
74+
75+
# Get current version
76+
VERSION=$(grep -A1 "CFBundleShortVersionString" Info.plist | tail -1 | sed -E 's/.*<string>(.*)<\/string>.*/\1/')
77+
echo "Release version: $VERSION"
78+
79+
# Check if this version already exists as a tag
80+
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
81+
echo "⚠️ Warning: Version v$VERSION already exists as a tag"
82+
echo "The release workflow will skip creating a new release"
83+
fi
84+
85+
# Validation for hotfix -> main PRs
86+
- name: Validate hotfix to main
87+
if: github.base_ref == 'main' && startsWith(github.head_ref, 'hotfix/')
88+
run: |
89+
echo "## Validating hotfix → main PR"
90+
91+
# Get version from main branch
92+
git fetch origin main
93+
MAIN_VERSION=$(git show origin/main:Info.plist | grep -A1 "CFBundleShortVersionString" | tail -1 | sed -E 's/.*<string>(.*)<\/string>.*/\1/')
94+
echo "Main branch version: $MAIN_VERSION"
95+
96+
# Get version from PR branch
97+
PR_VERSION=$(grep -A1 "CFBundleShortVersionString" Info.plist | tail -1 | sed -E 's/.*<string>(.*)<\/string>.*/\1/')
98+
echo "Hotfix version: $PR_VERSION"
99+
100+
# Check if version was updated
101+
if [ "$MAIN_VERSION" = "$PR_VERSION" ]; then
102+
echo "❌ Error: Version not updated in Info.plist"
103+
echo "Hotfixes must increment the version number"
104+
exit 1
105+
fi
106+
107+
# Check CHANGELOG update
108+
if ! git diff origin/main --name-only | grep -q "CHANGELOG.md"; then
109+
echo "❌ Error: CHANGELOG.md not updated"
110+
echo "Please document the hotfix in CHANGELOG.md"
111+
exit 1
112+
fi
113+
114+
echo "✅ Hotfix validation passed"
115+
116+
check-conventional-commits:
117+
name: Check Commit Messages
118+
runs-on: ubuntu-latest
119+
120+
steps:
121+
- uses: actions/checkout@v4
122+
with:
123+
fetch-depth: 0
124+
125+
- name: Check commit format
126+
run: |
127+
echo "## Checking commit message format"
128+
129+
# Get commits in this PR
130+
COMMITS=$(git log --format="%s" origin/${{ github.base_ref }}..HEAD)
131+
132+
# Check if commits follow conventional format
133+
INVALID_COMMITS=""
134+
while IFS= read -r commit; do
135+
if ! echo "$commit" | grep -qE '^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: .+' && \
136+
! echo "$commit" | grep -qE '^Merge '; then
137+
INVALID_COMMITS="${INVALID_COMMITS}❌ $commit\n"
138+
fi
139+
done <<< "$COMMITS"
140+
141+
if [ -n "$INVALID_COMMITS" ]; then
142+
echo "⚠️ Warning: Some commits don't follow Conventional Commits format:"
143+
echo -e "$INVALID_COMMITS"
144+
echo ""
145+
echo "Expected format: type(scope): description"
146+
echo "Valid types: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert"
147+
echo ""
148+
echo "This is a warning only - not blocking the PR"
149+
else
150+
echo "✅ All commits follow Conventional Commits format"
151+
fi

.github/workflows/release-dev.yml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
name: Development Release
2+
3+
on:
4+
push:
5+
branches:
6+
- develop
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
dev:
13+
name: Build Development Release
14+
runs-on: macos-latest
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Select Xcode
22+
run: sudo xcode-select -s /Applications/Xcode_15.2.app
23+
24+
- name: Get latest version
25+
id: version
26+
run: |
27+
# Get current version from Info.plist
28+
CURRENT_VERSION=$(defaults read "$PWD/Info.plist" CFBundleShortVersionString)
29+
30+
# Append -dev suffix
31+
NEW_VERSION="${CURRENT_VERSION}-dev"
32+
33+
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
34+
echo "tag=v$NEW_VERSION" >> $GITHUB_OUTPUT
35+
echo "✅ Development version: $NEW_VERSION"
36+
37+
# Build the app
38+
- name: Create app bundle
39+
run: |
40+
./scripts/create-app-bundle.sh "${{ steps.version.outputs.version }}"
41+
42+
# Ad-hoc sign (for development releases)
43+
- name: Sign app bundle
44+
run: |
45+
echo "⚠️ Ad-hoc signing development build"
46+
codesign --force --deep --sign - "ClaudeCodeMonitor.app"
47+
48+
# Create DMG
49+
- name: Create DMG
50+
run: |
51+
if ! command -v create-dmg &> /dev/null; then
52+
brew install create-dmg
53+
fi
54+
55+
DMG_NAME="ClaudeCodeMonitor-${{ steps.version.outputs.version }}.dmg"
56+
57+
create-dmg \
58+
--volname "Claude Code Monitor Dev" \
59+
--window-pos 200 120 \
60+
--window-size 600 400 \
61+
--icon-size 100 \
62+
--icon "ClaudeCodeMonitor.app" 150 185 \
63+
--hide-extension "ClaudeCodeMonitor.app" \
64+
--app-drop-link 450 185 \
65+
--no-internet-enable \
66+
--hdiutil-quiet \
67+
"$DMG_NAME" \
68+
"ClaudeCodeMonitor.app"
69+
70+
echo "DMG_PATH=$DMG_NAME" >> $GITHUB_ENV
71+
72+
# Generate simple changelog
73+
- name: Generate changelog
74+
id: changelog
75+
run: |
76+
echo "## 🚧 Development Release ${{ steps.version.outputs.version }}" > changelog.md
77+
echo "" >> changelog.md
78+
echo "This is an automated development release from the develop branch." >> changelog.md
79+
echo "For testing purposes only. Not recommended for production use." >> changelog.md
80+
echo "" >> changelog.md
81+
echo "### Recent Changes" >> changelog.md
82+
echo "" >> changelog.md
83+
84+
# Get commits since last tag
85+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
86+
if [ -n "$LAST_TAG" ]; then
87+
git log --pretty=format:"* %s (%h)" $LAST_TAG..HEAD | head -20 >> changelog.md
88+
else
89+
git log --pretty=format:"* %s (%h)" -20 >> changelog.md
90+
fi
91+
92+
{
93+
echo "changelog<<EOF"
94+
cat changelog.md
95+
echo "EOF"
96+
} >> $GITHUB_OUTPUT
97+
98+
# Create release (without tag)
99+
- name: Create Development Release
100+
uses: softprops/action-gh-release@v2
101+
with:
102+
tag_name: ${{ steps.version.outputs.tag }}
103+
name: Development Build ${{ steps.version.outputs.version }}
104+
body: ${{ steps.changelog.outputs.changelog }}
105+
draft: false
106+
prerelease: true
107+
files: |
108+
${{ env.DMG_PATH }}

0 commit comments

Comments
 (0)