Skip to content

Commit 1e02644

Browse files
committed
2026 Supported macOS Sequoia 15.7.3 (Phase 7-8, Testing, Polish & UI Refinement).
feat: Phase 7 & 8 — Testing, Polish & UI Refinement ## Phase 7 — Testing (71/71 passed) - Add MockXPCService protocol stub for dependency injection - Add XPCServiceProtocol and refactor HostsFileService with injectable init - Add HostEntryTests (20 tests): model properties, hostsFileFormat, sorting, Codable - Add EditorViewModelTests (18 tests): validation flow, createEntry, duplicate detection - Add HostsFileServiceTests (13 tests): CRUD operations via mock XPC - Extend ParserTests with edge cases: tabs, UTF-8, malformed lines - Fix HostsFile.parse() — disabled entries (# IP hostname) were misidentified as header comments; resolved with IP pattern detection ## Phase 8 — Polish & UI Refinement - Add keyboard shortcuts: ⌘N (Add Entry), ⌘R (Refresh), Delete key (remove selected) - Add XPC connection banner with Retry button when helper is not connected - Add isXPCConnected and retryConnection() to HostsViewModel and HostsFileService - Add accessibilityLabel and accessibilityHint to all interactive elements - Add accessibilityElement(children: .combine) to rows, stats bar, and empty state ## Architecture - Flatten Shared sources into HostsManagerExtension for Swift 6 module compatibility - Upgrade Package.swift to swift-tools-version 6.0 - Resolve duplicate _main symbol by excluding HostsManagerExtension.swift from SPM sources Tested on macOS Sequoia 15.7.3
1 parent fd14d6b commit 1e02644

29 files changed

+2890
-646
lines changed

.github/workflows/ci.yml

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- develop
8+
- 'hotfix**'
9+
10+
pull_request:
11+
branches-ignore:
12+
- main
13+
14+
types:
15+
- opened
16+
- reopened
17+
- synchronize
18+
- ready_for_review
19+
20+
env:
21+
XCODE_VERSION: '16.2'
22+
SCHEME: 'HostsManager'
23+
PROJECT: 'HostsManager.xcodeproj'
24+
DESTINATION: 'platform=macOS'
25+
26+
jobs:
27+
# ─────────────────────────────────────────────
28+
# Job 1: Build via Xcode
29+
# ─────────────────────────────────────────────
30+
build:
31+
name: Build (Xcode)
32+
runs-on: macos-15
33+
if: |
34+
github.event_name == 'push' ||
35+
(github.event_name == 'pull_request' && github.event.pull_request.draft == false)
36+
37+
steps:
38+
- name: Checkout
39+
uses: actions/checkout@v4
40+
41+
- name: Select Xcode ${{ env.XCODE_VERSION }}
42+
run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
43+
44+
- name: Show build environment
45+
run: |
46+
xcodebuild -version
47+
swift --version
48+
49+
- name: Resolve Swift Package dependencies
50+
run: |
51+
xcodebuild -resolvePackageDependencies \
52+
-project ${{ env.PROJECT }} \
53+
-scheme ${{ env.SCHEME }}
54+
55+
- name: Build (Release)
56+
run: |
57+
xcodebuild build \
58+
-project ${{ env.PROJECT }} \
59+
-scheme ${{ env.SCHEME }} \
60+
-destination "${{ env.DESTINATION }}" \
61+
-configuration Release \
62+
CODE_SIGNING_ALLOWED=NO \
63+
| xcpretty && exit ${PIPESTATUS[0]}
64+
65+
# ─────────────────────────────────────────────
66+
# Job 2: Unit Tests via SPM (fast, no signing)
67+
# ─────────────────────────────────────────────
68+
test-spm:
69+
name: Tests (Swift Package Manager)
70+
runs-on: macos-15
71+
needs: build
72+
if: |
73+
github.event_name == 'push' ||
74+
(github.event_name == 'pull_request' && github.event.pull_request.draft == false)
75+
76+
steps:
77+
- name: Checkout
78+
uses: actions/checkout@v4
79+
80+
- name: Select Xcode ${{ env.XCODE_VERSION }}
81+
run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
82+
83+
- name: Run all SPM test targets
84+
run: |
85+
swift test \
86+
--parallel \
87+
--enable-code-coverage \
88+
2>&1 | tee test-output.txt
89+
continue-on-error: false
90+
91+
- name: Upload test results
92+
if: always()
93+
uses: actions/upload-artifact@v4
94+
with:
95+
name: spm-test-results
96+
path: test-output.txt
97+
retention-days: 7
98+
99+
- name: Generate code coverage report
100+
run: |
101+
xcrun llvm-cov export \
102+
.build/debug/HostsManagerPackageTests.xctest/Contents/MacOS/HostsManagerPackageTests \
103+
-instr-profile .build/debug/codecov/default.profdata \
104+
-format lcov > coverage.lcov 2>/dev/null || true
105+
106+
- name: Upload coverage to Codecov
107+
if: success()
108+
uses: codecov/codecov-action@v5
109+
with:
110+
files: coverage.lcov
111+
flags: unittests
112+
fail_ci_if_error: false
113+
114+
# ─────────────────────────────────────────────
115+
# Job 3: Unit Tests via Xcode (full test suite)
116+
# ─────────────────────────────────────────────
117+
test-xcode:
118+
name: Tests (Xcode)
119+
runs-on: macos-15
120+
needs: build
121+
if: |
122+
github.event_name == 'push' ||
123+
(github.event_name == 'pull_request' && github.event.pull_request.draft == false)
124+
125+
steps:
126+
- name: Checkout
127+
uses: actions/checkout@v4
128+
129+
- name: Select Xcode ${{ env.XCODE_VERSION }}
130+
run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
131+
132+
- name: Run tests
133+
run: |
134+
xcodebuild test \
135+
-project ${{ env.PROJECT }} \
136+
-scheme ${{ env.SCHEME }} \
137+
-destination "${{ env.DESTINATION }}" \
138+
-enableCodeCoverage YES \
139+
CODE_SIGNING_ALLOWED=NO \
140+
| xcpretty --report junit --output test-results.xml && exit ${PIPESTATUS[0]}
141+
142+
- name: Upload JUnit test results
143+
if: always()
144+
uses: actions/upload-artifact@v4
145+
with:
146+
name: xcode-test-results
147+
path: test-results.xml
148+
retention-days: 7
149+
150+
# ─────────────────────────────────────────────
151+
# Job 4: Swift lint / format check
152+
# ─────────────────────────────────────────────
153+
lint:
154+
name: Lint (SwiftLint)
155+
runs-on: macos-15
156+
if: |
157+
github.event_name == 'push' ||
158+
(github.event_name == 'pull_request' && github.event.pull_request.draft == false)
159+
160+
steps:
161+
- name: Checkout
162+
uses: actions/checkout@v4
163+
164+
- name: Install SwiftLint
165+
run: brew install swiftlint
166+
167+
- name: Run SwiftLint
168+
run: |
169+
swiftlint lint \
170+
--reporter github-actions-logging \
171+
--strict
172+
173+
# ─────────────────────────────────────────────
174+
# Job 5: Archive & export (only on main branch)
175+
# ─────────────────────────────────────────────
176+
archive:
177+
name: Archive
178+
runs-on: macos-15
179+
needs: [ test-spm, test-xcode ]
180+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
181+
182+
steps:
183+
- name: Checkout
184+
uses: actions/checkout@v4
185+
186+
- name: Select Xcode ${{ env.XCODE_VERSION }}
187+
run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer
188+
189+
- name: Archive
190+
run: |
191+
xcodebuild archive \
192+
-project ${{ env.PROJECT }} \
193+
-scheme ${{ env.SCHEME }} \
194+
-destination "${{ env.DESTINATION }}" \
195+
-archivePath ./build/HostsManager.xcarchive \
196+
CODE_SIGNING_ALLOWED=NO \
197+
| xcpretty && exit ${PIPESTATUS[0]}
198+
199+
- name: Upload archive artifact
200+
uses: actions/upload-artifact@v4
201+
with:
202+
name: HostsManager-archive
203+
path: build/HostsManager.xcarchive
204+
retention-days: 14
205+
206+
# ─────────────────────────────────────────────
207+
# Job 6: Slack Notification
208+
# ─────────────────────────────────────────────
209+
notify:
210+
name: Notify (Slack)
211+
runs-on: ubuntu-l

0 commit comments

Comments
 (0)