Skip to content

Commit 16ddc44

Browse files
committed
feat(ci,darwin): add GitHub Actions CI/CD and macOS GUI scaffolding
Add CI workflow (ubuntu cross-compile for Windows + macOS daemon) and release workflow (Windows installer + macOS daemon tarballs + changelog). Refactor ui/ for cross-platform support: extract Windows-specific code from binding.go, create darwin entry point with launchd integration, system tray, osascript notifications, and macOS build Taskfile.
1 parent 66a48bd commit 16ddc44

12 files changed

Lines changed: 848 additions & 515 deletions

.github/workflows/ci.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: CI
2+
on:
3+
push:
4+
branches: [master]
5+
pull_request:
6+
branches: [master]
7+
8+
jobs:
9+
build-and-vet:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
with:
14+
submodules: recursive
15+
16+
- uses: actions/setup-go@v5
17+
with:
18+
go-version-file: go.mod
19+
20+
- name: Go vet (Windows)
21+
env:
22+
GOOS: windows
23+
GOARCH: amd64
24+
run: go vet ./...
25+
26+
- name: Build Windows
27+
env:
28+
GOOS: windows
29+
GOARCH: amd64
30+
run: go build ./...
31+
32+
# macOS GUI (./ui/) requires CGO for Wails WKWebView bridge,
33+
# so we skip it in cross-compilation and only build daemon + libraries.
34+
- name: Build macOS arm64 (daemon)
35+
env:
36+
CGO_ENABLED: "0"
37+
GOOS: darwin
38+
GOARCH: arm64
39+
run: go build ./cmd/... ./internal/...
40+
41+
- name: Build macOS amd64 (daemon)
42+
env:
43+
CGO_ENABLED: "0"
44+
GOOS: darwin
45+
GOARCH: amd64
46+
run: go build ./cmd/... ./internal/...
47+
48+
- name: Tests
49+
run: go test ./...

.github/workflows/release.yml

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
name: Release
2+
on:
3+
push:
4+
tags:
5+
- "v*"
6+
7+
jobs:
8+
build-windows:
9+
runs-on: windows-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
with:
13+
submodules: recursive
14+
fetch-depth: 0
15+
16+
- uses: actions/setup-go@v5
17+
with:
18+
go-version-file: go.mod
19+
20+
- uses: actions/setup-node@v4
21+
with:
22+
node-version: 20
23+
cache: npm
24+
cache-dependency-path: ui/frontend/package-lock.json
25+
26+
- name: Extract version from tag
27+
shell: bash
28+
run: |
29+
VERSION="${GITHUB_REF_NAME#v}"
30+
COMMIT="$(git rev-parse --short HEAD)"
31+
DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
32+
echo "VERSION=$VERSION" >> $GITHUB_ENV
33+
echo "COMMIT=$COMMIT" >> $GITHUB_ENV
34+
echo "BUILD_DATE=$DATE" >> $GITHUB_ENV
35+
echo "LDFLAGS=-s -w -X main.version=$VERSION -X main.commit=$COMMIT -X main.buildDate=$DATE" >> $GITHUB_ENV
36+
37+
- name: Install tools
38+
shell: bash
39+
run: |
40+
go install github.com/akavel/rsrc@latest
41+
go install github.com/wailsapp/wails/v3/cmd/wails3@latest
42+
choco install nsis -y --no-progress
43+
44+
- name: Build frontend
45+
working-directory: ui/frontend
46+
run: |
47+
npm ci
48+
npm run build
49+
50+
- name: Generate Wails bindings
51+
working-directory: ui
52+
run: wails3 generate bindings
53+
54+
- name: Generate Windows resources (.syso)
55+
shell: bash
56+
run: |
57+
ICO="ui/build/windows/icon.ico"
58+
rsrc -manifest cmd/awg-split-tunnel/app.manifest -ico "$ICO" -o cmd/awg-split-tunnel/rsrc_windows_amd64.syso
59+
rsrc -manifest ui/build/windows/wails.exe.manifest -ico "$ICO" -o ui/rsrc_windows_amd64.syso
60+
rsrc -manifest cmd/awg-split-tunnel-updater/app.manifest -ico "$ICO" -o cmd/awg-split-tunnel-updater/rsrc_windows_amd64.syso
61+
rsrc -manifest cmd/awg-diag/app.manifest -ico "$ICO" -o cmd/awg-diag/rsrc_windows_amd64.syso
62+
63+
- name: Build Go binaries
64+
shell: bash
65+
run: |
66+
mkdir -p build
67+
go build -ldflags "$LDFLAGS" -o build/awg-split-tunnel.exe ./cmd/awg-split-tunnel/
68+
go build -ldflags "$LDFLAGS -H windowsgui" -o build/awg-split-tunnel-ui.exe ./ui/
69+
go build -ldflags "$LDFLAGS" -o build/awg-split-tunnel-updater.exe ./cmd/awg-split-tunnel-updater/
70+
go build -ldflags "$LDFLAGS" -o build/awg-split-tunnel-diag.exe ./cmd/awg-diag/
71+
cp dll/wintun.dll build/
72+
73+
- name: Build NSIS installer
74+
shell: bash
75+
run: |
76+
ABS_SERVICE="$(cygpath -w "$(pwd)/build/awg-split-tunnel.exe")"
77+
ABS_GUI="$(cygpath -w "$(pwd)/build/awg-split-tunnel-ui.exe")"
78+
ABS_UPDATER="$(cygpath -w "$(pwd)/build/awg-split-tunnel-updater.exe")"
79+
ABS_WINTUN="$(cygpath -w "$(pwd)/build/wintun.dll")"
80+
ABS_CONFIG="$(cygpath -w "$(pwd)/config.example.yaml")"
81+
"/c/Program Files (x86)/NSIS/makensis.exe" \
82+
-DARG_WAILS_AMD64_BINARY="$ABS_GUI" \
83+
-DARG_SERVICE_BINARY="$ABS_SERVICE" \
84+
-DARG_UPDATER_BINARY="$ABS_UPDATER" \
85+
-DARG_WINTUN_DLL="$ABS_WINTUN" \
86+
-DARG_CONFIG_EXAMPLE="$ABS_CONFIG" \
87+
-DINFO_PRODUCTVERSION="$VERSION" \
88+
ui/build/windows/nsis/project.nsi
89+
90+
- name: Create release ZIP
91+
shell: pwsh
92+
run: |
93+
Compress-Archive -Path `
94+
build/awg-split-tunnel.exe, `
95+
build/awg-split-tunnel-ui.exe, `
96+
build/awg-split-tunnel-updater.exe, `
97+
build/wintun.dll, `
98+
config.example.yaml `
99+
-DestinationPath "build/awg-split-tunnel-v${{ env.VERSION }}-windows-amd64.zip"
100+
101+
- uses: actions/upload-artifact@v4
102+
with:
103+
name: windows-artifacts
104+
path: |
105+
build/awg-split-tunnel-v*-windows-amd64.zip
106+
build/*installer*.exe
107+
retention-days: 5
108+
109+
build-macos:
110+
runs-on: macos-14
111+
steps:
112+
- uses: actions/checkout@v4
113+
with:
114+
submodules: recursive
115+
fetch-depth: 0
116+
117+
- uses: actions/setup-go@v5
118+
with:
119+
go-version-file: go.mod
120+
121+
- name: Extract version
122+
run: |
123+
VERSION="${GITHUB_REF_NAME#v}"
124+
COMMIT="$(git rev-parse --short HEAD)"
125+
DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
126+
echo "VERSION=$VERSION" >> $GITHUB_ENV
127+
echo "COMMIT=$COMMIT" >> $GITHUB_ENV
128+
echo "BUILD_DATE=$DATE" >> $GITHUB_ENV
129+
echo "LDFLAGS=-s -w -X main.version=$VERSION -X main.commit=$COMMIT -X main.buildDate=$DATE" >> $GITHUB_ENV
130+
131+
- name: Build daemon binaries
132+
run: |
133+
mkdir -p build
134+
135+
# arm64 (native on macos-14 runner)
136+
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 \
137+
go build -ldflags "$LDFLAGS" -o build/awg-split-tunnel-arm64 ./cmd/awg-split-tunnel/
138+
139+
# amd64 (cross-compile)
140+
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 \
141+
go build -ldflags "$LDFLAGS" -o build/awg-split-tunnel-amd64 ./cmd/awg-split-tunnel/
142+
143+
# Universal binary
144+
lipo -create -output build/awg-split-tunnel \
145+
build/awg-split-tunnel-arm64 build/awg-split-tunnel-amd64
146+
147+
- name: Create tarballs
148+
run: |
149+
cd build
150+
for ARCH in arm64 amd64; do
151+
tar czf "awg-split-tunnel-v${VERSION}-darwin-${ARCH}.tar.gz" \
152+
"awg-split-tunnel-${ARCH}"
153+
done
154+
tar czf "awg-split-tunnel-v${VERSION}-darwin-universal.tar.gz" \
155+
"awg-split-tunnel"
156+
157+
- uses: actions/upload-artifact@v4
158+
with:
159+
name: macos-daemon-artifacts
160+
path: build/awg-split-tunnel-v*-darwin-*.tar.gz
161+
retention-days: 5
162+
163+
# build-macos-gui:
164+
# runs-on: macos-14
165+
# steps:
166+
# # Uncomment when macOS GUI is fully implemented and tested.
167+
# # Requires CGO_ENABLED=1 for Wails v3 WKWebView bridge.
168+
# # See ui/main_darwin.go and ui/build/darwin/Taskfile.yml for details.
169+
# - run: echo "macOS GUI build placeholder — enable after GUI implementation"
170+
171+
create-release:
172+
needs: [build-windows, build-macos]
173+
runs-on: ubuntu-latest
174+
permissions:
175+
contents: write
176+
steps:
177+
- uses: actions/checkout@v4
178+
with:
179+
fetch-depth: 0
180+
181+
- uses: actions/download-artifact@v4
182+
with:
183+
path: artifacts
184+
merge-multiple: true
185+
186+
- name: Generate changelog
187+
shell: bash
188+
run: |
189+
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
190+
TAG="${GITHUB_REF_NAME}"
191+
if [ -n "$PREV_TAG" ]; then
192+
RANGE="${PREV_TAG}..HEAD"
193+
else
194+
RANGE="HEAD"
195+
fi
196+
197+
echo "# Changelog - ${TAG}" > CHANGELOG.md
198+
echo "" >> CHANGELOG.md
199+
200+
# Process each conventional commit type
201+
for PAIR in "feat:Features" "fix:Bug Fixes" "perf:Performance" "refactor:Refactoring" "docs:Documentation" "test:Tests" "ci:CI" "build:Build"; do
202+
TYPE="${PAIR%%:*}"
203+
LABEL="${PAIR#*:}"
204+
COMMITS=$(git log $RANGE --oneline --no-merges --grep="^${TYPE}" --format="- %s (%h)" 2>/dev/null || true)
205+
if [ -n "$COMMITS" ]; then
206+
echo "## $LABEL" >> CHANGELOG.md
207+
echo "$COMMITS" >> CHANGELOG.md
208+
echo "" >> CHANGELOG.md
209+
fi
210+
done
211+
212+
# Other commits (not matching any type)
213+
OTHER=$(git log $RANGE --oneline --no-merges \
214+
--invert-grep --grep="^feat" --grep="^fix" --grep="^perf" \
215+
--grep="^refactor" --grep="^docs" --grep="^test" --grep="^ci" \
216+
--grep="^build" --format="- %s (%h)" 2>/dev/null || true)
217+
if [ -n "$OTHER" ]; then
218+
echo "## Other" >> CHANGELOG.md
219+
echo "$OTHER" >> CHANGELOG.md
220+
fi
221+
222+
- name: Create GitHub Release
223+
env:
224+
GH_TOKEN: ${{ github.token }}
225+
run: |
226+
gh release create "${{ github.ref_name }}" \
227+
--title "Release ${{ github.ref_name }}" \
228+
--notes-file CHANGELOG.md \
229+
artifacts/*

0 commit comments

Comments
 (0)