Skip to content

Commit 2cf23a5

Browse files
committed
first commit
0 parents  commit 2cf23a5

61 files changed

Lines changed: 9080 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copy this file to .env and fill in your values
2+
3+
# Development Team ID (found in Apple Developer account)
4+
DEVELOPMENT_TEAM=YOUR_TEAM_ID
5+
6+
# Bundle identifier for your app
7+
PRODUCT_BUNDLE_IDENTIFIER=com.example.iemsw
8+
9+
# Default bundle identifier for logging (optional)
10+
DEFAULT_BUNDLE_IDENTIFIER=com.example.iemsw

.github/workflows/ci.yml

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
env:
10+
DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
11+
12+
jobs:
13+
lint:
14+
name: SwiftLint
15+
runs-on: macos-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: SwiftLint
20+
uses: norio-nomura/action-swiftlint@3.2.1
21+
with:
22+
args: --strict
23+
24+
test:
25+
name: Test
26+
runs-on: macos-latest
27+
strategy:
28+
matrix:
29+
destination: ["platform=macOS"]
30+
31+
steps:
32+
- uses: actions/checkout@v4
33+
34+
- name: Select Xcode
35+
run: sudo xcode-select -switch /Applications/Xcode_15.4.app/Contents/Developer
36+
37+
- name: Show Xcode version
38+
run: xcodebuild -version
39+
40+
- name: Show available destinations
41+
run: xcodebuild -project iemsw.xcodeproj -scheme iemsw -showdestinations
42+
43+
- name: Build
44+
run: make build
45+
46+
- name: Run tests
47+
run: make test
48+
49+
- name: Generate test coverage
50+
run: make test-coverage
51+
52+
- name: Upload coverage reports to Codecov
53+
uses: codecov/codecov-action@v3
54+
with:
55+
token: ${{ secrets.CODECOV_TOKEN }}
56+
files: ./build/coverage.xml
57+
fail_ci_if_error: false
58+
59+
build:
60+
name: Build
61+
runs-on: macos-latest
62+
needs: [lint, test]
63+
64+
steps:
65+
- uses: actions/checkout@v4
66+
67+
- name: Select Xcode
68+
run: sudo xcode-select -switch /Applications/Xcode_15.4.app/Contents/Developer
69+
70+
- name: Build for Release
71+
run: make build-release
72+
73+
- name: Archive
74+
run: make archive
75+
env:
76+
DEVELOPMENT_TEAM: ${{ secrets.DEVELOPMENT_TEAM }}
77+
78+
- name: Upload build artifacts
79+
uses: actions/upload-artifact@v4
80+
with:
81+
name: iemsw-archive
82+
path: build/iemsw.xcarchive
83+
retention-days: 30
84+
85+
swift-package-manager:
86+
name: Swift Package Manager
87+
runs-on: macos-latest
88+
89+
steps:
90+
- uses: actions/checkout@v4
91+
92+
- name: Build with SPM
93+
run: make spm-build
94+
95+
- name: Test with SPM
96+
run: make spm-test
97+
98+
security-scan:
99+
name: Security Scan
100+
runs-on: macos-latest
101+
102+
steps:
103+
- uses: actions/checkout@v4
104+
105+
- name: Run security scan
106+
run: |
107+
# Check for common security issues
108+
grep -r "TODO.*security" . || true
109+
grep -r "FIXME.*security" . || true
110+
grep -r "password\|secret\|key" --include="*.swift" . || true
111+
112+
- name: Check for sensitive files
113+
run: |
114+
# Check for files that shouldn't be committed
115+
find . -name "*.p12" -o -name "*.mobileprovision" -o -name "*.cer" | head -10
116+
if [ -f "ExportOptions.plist" ]; then
117+
grep -i "YOUR_TEAM_ID" ExportOptions.plist && echo "⚠️ Remember to update YOUR_TEAM_ID in ExportOptions.plist"
118+
fi
119+
120+
validate-project:
121+
name: Validate Project Structure
122+
runs-on: macos-latest
123+
124+
steps:
125+
- uses: actions/checkout@v4
126+
127+
- name: Validate project structure
128+
run: |
129+
echo "Checking required files..."
130+
test -f iemsw.xcodeproj/project.pbxproj || (echo "❌ Xcode project file missing" && exit 1)
131+
test -f Package.swift || (echo "❌ Package.swift missing" && exit 1)
132+
test -f Makefile || (echo "❌ Makefile missing" && exit 1)
133+
test -f .swiftlint.yml || (echo "❌ SwiftLint config missing" && exit 1)
134+
135+
echo "Checking source files..."
136+
test -f iemsw/App.swift || (echo "❌ App.swift missing" && exit 1)
137+
test -f iemsw/MenuBarApp.swift || (echo "❌ MenuBarApp.swift missing" && exit 1)
138+
test -f iemsw/Preferences.swift || (echo "❌ Preferences.swift missing" && exit 1)
139+
test -f iemsw/ImeController.swift || (echo "❌ ImeController.swift missing" && exit 1)
140+
test -f iemsw/CustomIME.swift || (echo "❌ CustomIME.swift missing" && exit 1)
141+
142+
echo "Checking test files..."
143+
test -f iemswTests/ImeControllerTests.swift || (echo "❌ ImeControllerTests.swift missing" && exit 1)
144+
test -f iemswTests/PreferencesTests.swift || (echo "❌ PreferencesTests.swift missing" && exit 1)
145+
146+
echo "✅ All required files found"
147+
148+
- name: Validate Makefile targets
149+
run: |
150+
echo "Validating Makefile targets..."
151+
make help
152+
echo "✅ Makefile is valid"

.github/workflows/release.yml

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
env:
9+
DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
10+
11+
jobs:
12+
release:
13+
name: Create 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 -switch /Applications/Xcode_15.4.app/Contents/Developer
23+
24+
- name: Install dependencies
25+
run: |
26+
brew install swiftlint swiftformat create-dmg
27+
28+
- name: Setup certificates
29+
env:
30+
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
31+
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
32+
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
33+
run: |
34+
# Create temporary keychain
35+
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
36+
security default-keychain -s build.keychain
37+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
38+
39+
# Import certificate
40+
echo $BUILD_CERTIFICATE_BASE64 | base64 --decode > certificate.p12
41+
security import certificate.p12 -k build.keychain -P "$P12_PASSWORD" -T /usr/bin/codesign
42+
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
43+
44+
- name: Get version from tag
45+
id: get_version
46+
run: |
47+
VERSION=${GITHUB_REF#refs/tags/v}
48+
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
49+
echo "Building version: $VERSION"
50+
51+
- name: Lint code
52+
run: make lint
53+
54+
- name: Run tests
55+
run: make test
56+
57+
- name: Build release
58+
run: make release
59+
env:
60+
VERSION: ${{ steps.get_version.outputs.VERSION }}
61+
DEVELOPMENT_TEAM: ${{ secrets.DEVELOPMENT_TEAM }}
62+
63+
- name: Notarize DMG
64+
run: make notarize
65+
env:
66+
APPLE_ID: ${{ secrets.APPLE_ID }}
67+
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
68+
DEVELOPMENT_TEAM: ${{ secrets.DEVELOPMENT_TEAM }}
69+
70+
- name: Generate checksums
71+
run: |
72+
cd build
73+
shasum -a 256 iemsw.dmg > iemsw.dmg.sha256
74+
cat iemsw.dmg.sha256
75+
76+
- name: Generate release notes
77+
id: release_notes
78+
run: |
79+
VERSION=${{ steps.get_version.outputs.VERSION }}
80+
81+
# Generate changelog since last tag
82+
LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
83+
if [ -n "$LAST_TAG" ]; then
84+
echo "CHANGELOG<<EOF" >> $GITHUB_OUTPUT
85+
echo "## Changes since $LAST_TAG" >> $GITHUB_OUTPUT
86+
git log --pretty=format:"- %s (%h)" $LAST_TAG..HEAD >> $GITHUB_OUTPUT
87+
echo "" >> $GITHUB_OUTPUT
88+
echo "EOF" >> $GITHUB_OUTPUT
89+
else
90+
echo "CHANGELOG=Initial release" >> $GITHUB_OUTPUT
91+
fi
92+
93+
- name: Create Release
94+
id: create_release
95+
uses: actions/create-release@v1
96+
env:
97+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
98+
with:
99+
tag_name: ${{ github.ref }}
100+
release_name: iemsw v${{ steps.get_version.outputs.VERSION }}
101+
body: |
102+
## iemsw v${{ steps.get_version.outputs.VERSION }}
103+
104+
A macOS menu bar helper that switches between English input and native IME by pressing left/right ⌘ keys individually.
105+
106+
### Installation
107+
108+
1. Download `iemsw.dmg` from the assets below
109+
2. Open the DMG file and drag iemsw.app to your Applications folder
110+
3. Launch iemsw and grant accessibility permissions when prompted
111+
4. The app will appear in your menu bar
112+
113+
### Features
114+
115+
- **Left ⌘ key**: Switch to native IME (Japanese, Chinese, Korean, etc.)
116+
- **Right ⌘ key**: Switch to English input
117+
- **Optional idle timeout**: Automatically switch to English after no input
118+
- **Menu bar integration**: Easy access to preferences and controls
119+
- **Launch at login**: Optional automatic startup
120+
121+
### System Requirements
122+
123+
- macOS 11.0 (Big Sur) or later
124+
- Accessibility permissions (granted during first launch)
125+
126+
### Changelog
127+
128+
${{ steps.release_notes.outputs.CHANGELOG }}
129+
130+
### Verification
131+
132+
SHA256 checksum: See `iemsw.dmg.sha256` file in assets.
133+
draft: false
134+
prerelease: false
135+
136+
- name: Upload DMG
137+
uses: actions/upload-release-asset@v1
138+
env:
139+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
140+
with:
141+
upload_url: ${{ steps.create_release.outputs.upload_url }}
142+
asset_path: ./build/iemsw.dmg
143+
asset_name: iemsw.dmg
144+
asset_content_type: application/octet-stream
145+
146+
- name: Upload checksum
147+
uses: actions/upload-release-asset@v1
148+
env:
149+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
150+
with:
151+
upload_url: ${{ steps.create_release.outputs.upload_url }}
152+
asset_path: ./build/iemsw.dmg.sha256
153+
asset_name: iemsw.dmg.sha256
154+
asset_content_type: text/plain
155+
156+
- name: Cleanup keychain
157+
if: always()
158+
run: |
159+
security delete-keychain build.keychain || true
160+
rm certificate.p12 || true
161+
162+
homebrew:
163+
name: Update Homebrew Cask
164+
runs-on: macos-latest
165+
needs: release
166+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
167+
168+
steps:
169+
- uses: actions/checkout@v4
170+
171+
- name: Get version and download URL
172+
id: get_info
173+
run: |
174+
VERSION=${GITHUB_REF#refs/tags/v}
175+
DOWNLOAD_URL="https://github.com/${{ github.repository }}/releases/download/v${VERSION}/iemsw.dmg"
176+
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
177+
echo "DOWNLOAD_URL=$DOWNLOAD_URL" >> $GITHUB_OUTPUT
178+
179+
- name: Download and get SHA256
180+
run: |
181+
curl -L "${{ steps.get_info.outputs.DOWNLOAD_URL }}" -o iemsw.dmg
182+
SHA256=$(shasum -a 256 iemsw.dmg | cut -d' ' -f1)
183+
echo "SHA256=$SHA256" >> $GITHUB_ENV
184+
185+
- name: Create Homebrew Cask PR
186+
uses: peter-evans/create-pull-request@v5
187+
with:
188+
token: ${{ secrets.HOMEBREW_GITHUB_TOKEN }}
189+
push-to-fork: ${{ github.repository_owner }}/homebrew-cask
190+
branch: update-iemsw-${{ steps.get_info.outputs.VERSION }}
191+
title: 'iemsw: update to ${{ steps.get_info.outputs.VERSION }}'
192+
body: |
193+
Update iemsw to version ${{ steps.get_info.outputs.VERSION }}
194+
195+
- Version: ${{ steps.get_info.outputs.VERSION }}
196+
- Download URL: ${{ steps.get_info.outputs.DOWNLOAD_URL }}
197+
- SHA256: ${{ env.SHA256 }}
198+
199+
Generated automatically by GitHub Actions.
200+
commit-message: 'iemsw: update to ${{ steps.get_info.outputs.VERSION }}'

0 commit comments

Comments
 (0)