Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3b3eaf9

Browse files
committedJan 24, 2025··
chore: switch to an XcodeGen project file
Change-Id: I753a7652cdc730157ae7f8bc036338bae5e6b54b Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent 06b4c16 commit 3b3eaf9

35 files changed

+988
-2041
lines changed
 
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: "Setup Nix devshell"
2+
description: "This action sets up a nix devshell environment"
3+
runs:
4+
using: "composite"
5+
steps:
6+
- name: Setup Nix
7+
uses: DeterminateSystems/nix-installer-action@e50d5f73bfe71c2dd0aa4218de8f4afa59f8f81d # v16
8+
9+
- name: Setup GHA Nix cache
10+
uses: DeterminateSystems/magic-nix-cache-action@6221693898146dc97e38ad0e013488a16477a4c4 # v9
11+
12+
- name: Enter devshell
13+
uses: nicknovitski/nix-develop@9be7cfb4b10451d3390a75dc18ad0465bed4932a # v1.2.1

‎.github/workflows/ci.yml

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ on:
1010
paths-ignore:
1111
- "README.md"
1212

13-
1413
permissions:
1514
contents: read
1615

@@ -19,36 +18,71 @@ jobs:
1918
name: test
2019
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
2120
steps:
21+
- name: Harden Runner
22+
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
23+
with:
24+
egress-policy: audit
25+
2226
- name: Checkout
2327
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
2428
with:
2529
fetch-depth: 1
30+
2631
- name: Switch XCode Version
27-
uses: maxim-lobanov/setup-xcode@v1
32+
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
2833
with:
29-
xcode-version: '16.0.0'
30-
- run: |
31-
make test
34+
# (ThomasK33): depot.dev does not yet support Xcode 16.1 or 16.2 GA, thus we're stuck with 16.0.0 for now.
35+
# I've already reached out, so hopefully this comment will soon be obsolete.
36+
xcode-version: "16.0.0"
37+
38+
- name: Setup Nix
39+
uses: ./.github/actions/nix-devshell
40+
41+
- run: make
42+
43+
- run: make test
44+
3245
format:
3346
name: fmt
3447
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
3548
steps:
49+
- name: Harden Runner
50+
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
51+
with:
52+
egress-policy: audit
53+
3654
- name: Checkout
3755
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3856
with:
3957
fetch-depth: 1
40-
- run: |
41-
make fmt
58+
59+
- name: Switch XCode Version
60+
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
61+
with:
62+
# (ThomasK33): depot.dev does not yet support Xcode 16.1 or 16.2 GA, thus we're stuck with 16.0.0 for now.
63+
# I've already reached out, so hopefully this comment will soon be obsolete.
64+
xcode-version: "16.0.0"
65+
66+
- name: Setup Nix
67+
uses: ./.github/actions/nix-devshell
68+
69+
- run: make fmt
70+
4271
lint:
4372
name: lint
4473
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
4574
steps:
75+
- name: Harden Runner
76+
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
77+
with:
78+
egress-policy: audit
79+
4680
- name: Checkout
4781
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
4882
with:
4983
fetch-depth: 1
50-
- name: Install Swiftlint
51-
run: |
52-
brew install swiftlint
53-
- run: |
54-
make lint
84+
85+
- name: Setup Nix
86+
uses: ./.github/actions/nix-devshell
87+
88+
- run: make lint

‎.gitignore

Lines changed: 290 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,293 @@
1-
# Xcode specifics
1+
# Created by https://www.toptal.com/developers/gitignore/api/xcode,jetbrains,macos,direnv,swift,swiftpm,objective-c
2+
# Edit at https://www.toptal.com/developers/gitignore?templates=xcode,jetbrains,macos,direnv,swift,swiftpm,objective-c
3+
4+
### direnv ###
5+
.direnv
6+
.envrc
7+
8+
### JetBrains ###
9+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
10+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
11+
12+
# User-specific stuff
13+
.idea/**/workspace.xml
14+
.idea/**/tasks.xml
15+
.idea/**/usage.statistics.xml
16+
.idea/**/dictionaries
17+
.idea/**/shelf
18+
19+
# AWS User-specific
20+
.idea/**/aws.xml
21+
22+
# Generated files
23+
.idea/**/contentModel.xml
24+
25+
# Sensitive or high-churn files
26+
.idea/**/dataSources/
27+
.idea/**/dataSources.ids
28+
.idea/**/dataSources.local.xml
29+
.idea/**/sqlDataSources.xml
30+
.idea/**/dynamic.xml
31+
.idea/**/uiDesigner.xml
32+
.idea/**/dbnavigator.xml
33+
34+
# Gradle
35+
.idea/**/gradle.xml
36+
.idea/**/libraries
37+
38+
# Gradle and Maven with auto-import
39+
# When using Gradle or Maven with auto-import, you should exclude module files,
40+
# since they will be recreated, and may cause churn. Uncomment if using
41+
# auto-import.
42+
# .idea/artifacts
43+
# .idea/compiler.xml
44+
# .idea/jarRepositories.xml
45+
# .idea/modules.xml
46+
# .idea/*.iml
47+
# .idea/modules
48+
# *.iml
49+
# *.ipr
50+
51+
# CMake
52+
cmake-build-*/
53+
54+
# Mongo Explorer plugin
55+
.idea/**/mongoSettings.xml
56+
57+
# File-based project format
58+
*.iws
59+
60+
# IntelliJ
61+
out/
62+
63+
# mpeltonen/sbt-idea plugin
64+
.idea_modules/
65+
66+
# JIRA plugin
67+
atlassian-ide-plugin.xml
68+
69+
# Cursive Clojure plugin
70+
.idea/replstate.xml
71+
72+
# SonarLint plugin
73+
.idea/sonarlint/
74+
75+
# Crashlytics plugin (for Android Studio and IntelliJ)
76+
com_crashlytics_export_strings.xml
77+
crashlytics.properties
78+
crashlytics-build.properties
79+
fabric.properties
80+
81+
# Editor-based Rest Client
82+
.idea/httpRequests
83+
84+
# Android studio 3.1+ serialized cache file
85+
.idea/caches/build_file_checksums.ser
86+
87+
### JetBrains Patch ###
88+
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
89+
90+
# *.iml
91+
# modules.xml
92+
# .idea/misc.xml
93+
# *.ipr
94+
95+
# Sonarlint plugin
96+
# https://plugins.jetbrains.com/plugin/7973-sonarlint
97+
.idea/**/sonarlint/
98+
99+
# SonarQube Plugin
100+
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
101+
.idea/**/sonarIssues.xml
102+
103+
# Markdown Navigator plugin
104+
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
105+
.idea/**/markdown-navigator.xml
106+
.idea/**/markdown-navigator-enh.xml
107+
.idea/**/markdown-navigator/
108+
109+
# Cache file creation bug
110+
# See https://youtrack.jetbrains.com/issue/JBR-2257
111+
.idea/$CACHE_FILE$
112+
113+
# CodeStream plugin
114+
# https://plugins.jetbrains.com/plugin/12206-codestream
115+
.idea/codestream.xml
116+
117+
# Azure Toolkit for IntelliJ plugin
118+
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
119+
.idea/**/azureSettings.xml
120+
121+
### macOS ###
122+
# General
2123
.DS_Store
3-
UserInterfaceState.xcuserstate
124+
.AppleDouble
125+
.LSOverride
126+
127+
# Icon must end with two \r
128+
Icon
129+
130+
131+
# Thumbnails
132+
._*
133+
134+
# Files that might appear in the root of a volume
135+
.DocumentRevisions-V100
136+
.fseventsd
137+
.Spotlight-V100
138+
.TemporaryItems
139+
.Trashes
140+
.VolumeIcon.icns
141+
.com.apple.timemachine.donotpresent
142+
143+
# Directories potentially created on remote AFP share
144+
.AppleDB
145+
.AppleDesktop
146+
Network Trash Folder
147+
Temporary Items
148+
.apdisk
149+
150+
### macOS Patch ###
151+
# iCloud generated files
152+
*.icloud
153+
154+
### Objective-C ###
155+
# Xcode
156+
#
157+
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
158+
159+
## User settings
4160
xcuserdata/
5161

6-
# JetBrains
7-
.idea/
162+
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
163+
*.xcscmblueprint
164+
*.xccheckout
165+
166+
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
167+
build/
168+
DerivedData/
169+
*.moved-aside
170+
*.pbxuser
171+
!default.pbxuser
172+
*.mode1v3
173+
!default.mode1v3
174+
*.mode2v3
175+
!default.mode2v3
176+
*.perspectivev3
177+
!default.perspectivev3
178+
179+
## Obj-C/Swift specific
180+
*.hmap
181+
182+
## App packaging
183+
*.ipa
184+
*.dSYM.zip
185+
*.dSYM
186+
187+
# CocoaPods
188+
# We recommend against adding the Pods directory to your .gitignore. However
189+
# you should judge for yourself, the pros and cons are mentioned at:
190+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
191+
# Pods/
192+
# Add this line if you want to avoid checking in source code from the Xcode workspace
193+
# *.xcworkspace
194+
195+
# Carthage
196+
# Add this line if you want to avoid checking in source code from Carthage dependencies.
197+
# Carthage/Checkouts
198+
199+
Carthage/Build/
200+
201+
# fastlane
202+
# It is recommended to not store the screenshots in the git repo.
203+
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
204+
# For more information about the recommended setup visit:
205+
# https://docs.fastlane.tools/best-practices/source-control/#source-control
206+
207+
fastlane/report.xml
208+
fastlane/Preview.html
209+
fastlane/screenshots/**/*.png
210+
fastlane/test_output
211+
212+
# Code Injection
213+
# After new code Injection tools there's a generated folder /iOSInjectionProject
214+
# https://github.com/johnno1962/injectionforxcode
215+
216+
iOSInjectionProject/
217+
218+
### Objective-C Patch ###
219+
220+
### Swift ###
221+
# Xcode
222+
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
223+
224+
225+
226+
227+
228+
229+
## Playgrounds
230+
timeline.xctimeline
231+
playground.xcworkspace
232+
233+
# Swift Package Manager
234+
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
235+
Packages/
236+
Package.pins
237+
Package.resolved
238+
*.xcodeproj
239+
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
240+
# hence it is not needed unless you have added a package configuration file to your project
241+
# .swiftpm
242+
243+
.build/
244+
245+
# CocoaPods
246+
# We recommend against adding the Pods directory to your .gitignore. However
247+
# you should judge for yourself, the pros and cons are mentioned at:
248+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
249+
# Pods/
250+
# Add this line if you want to avoid checking in source code from the Xcode workspace
251+
*.xcworkspace
252+
253+
# Carthage
254+
# Add this line if you want to avoid checking in source code from Carthage dependencies.
255+
# Carthage/Checkouts
256+
257+
258+
# Accio dependency management
259+
Dependencies/
260+
.accio/
261+
262+
# fastlane
263+
# It is recommended to not store the screenshots in the git repo.
264+
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
265+
# For more information about the recommended setup visit:
266+
# https://docs.fastlane.tools/best-practices/source-control/#source-control
267+
268+
269+
# Code Injection
270+
# After new code Injection tools there's a generated folder /iOSInjectionProject
271+
# https://github.com/johnno1962/injectionforxcode
272+
273+
274+
### SwiftPM ###
275+
Packages
276+
xcuserdata
277+
*.xcodeproj
278+
279+
280+
### Xcode ###
281+
282+
## Xcode 8 and earlier
283+
284+
### Xcode Patch ###
285+
*.xcodeproj/*
286+
!*.xcodeproj/project.pbxproj
287+
!*.xcodeproj/xcshareddata/
288+
!*.xcodeproj/project.xcworkspace/
289+
!*.xcworkspace/contents.xcworkspacedata
290+
/*.gcno
291+
**/xcshareddata/WorkspaceSettings.xcsettings
292+
293+
# End of https://www.toptal.com/developers/gitignore/api/xcode,jetbrains,macos,direnv,swift,swiftpm,objective-c

‎CONTRIBUTING.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Contributing to Coder Desktop
2+
3+
Thank you for your interest in contributing to Coder Desktop! Below are the
4+
guidelines to help you get started.
5+
6+
## Prerequisites
7+
8+
Before opening the project in Xcode, you need to generate the Xcode project files.
9+
We use [**XcodeGen**](https://github.com/yonaskolb/XcodeGen) to handle this
10+
process, and the project generation is integrated into the `Makefile`.
11+
12+
## Setting Up the Development Environment
13+
14+
To ensure a consistent and reliable development environment, we recommend using
15+
[**Nix**](https://nix.dev/) with Flake support. All the tools required for
16+
development are defined in the `flake.nix` file.
17+
18+
**Note:** Nix is the only supported development environment for this project.
19+
While setups outside of Nix may work, we do not support custom tool installations
20+
or address issues related to missing path setups or other tooling installation
21+
problems. Using Nix ensures consistency across development environments and avoids
22+
these potential issues.
23+
24+
### Installing Nix with Flakes Enabled
25+
26+
If you don’t already have Nix installed, you can:
27+
28+
1. Use the [Determinate Systems installer](https://nixinstaller.com/) for a
29+
simple setup.
30+
2. Alternatively, use the [official installer](https://nixos.org/download.html)
31+
and enable Flake support by adding the following to your Nix configuration:
32+
33+
```nix
34+
experimental-features = nix-command flakes
35+
```
36+
37+
This project does **not** support non-Flake versions of Nix.
38+
39+
### Entering the Development Environment
40+
41+
Run the following command to enter the development environment with all necessary
42+
tools:
43+
44+
```bash
45+
nix develop
46+
```
47+
48+
### Using `direnv` for Environment Automation (Optional)
49+
50+
As an optional recommendation, you can use [`direnv`](https://direnv.net/) to
51+
automatically load and unload the Nix development environment when you navigate
52+
to the project directory. After installing `direnv`, enable it for this project by:
53+
54+
1. Adding the following line to your `.envrc` file in the project directory:
55+
56+
```bash
57+
use flake
58+
```
59+
60+
2. Allowing the `.envrc` file by running:
61+
62+
```bash
63+
direnv allow
64+
```
65+
66+
With `direnv`, the development environment will automatically be set up whenever
67+
you enter the project directory. This step is optional but can significantly
68+
streamline your workflow.
69+
70+
## Generating the Xcode Project Files
71+
72+
Once your development environment is set up, generate the Xcode project files by
73+
running:
74+
75+
```bash
76+
make
77+
```
78+
79+
This will use **XcodeGen** to create the required Xcode project files.
80+
The configuration for the project is defined in `Coder Desktop/project.yml`.
81+
82+
## Common Make Commands
83+
84+
Here are some useful `make` commands for working with the project:
85+
86+
- `make fmt`: Format Swift files using SwiftFormat.
87+
- `make lint`: Lint Swift files using SwiftLint.
88+
- `make test`: Run all tests using `xcodebuild`.
89+
- `make clean`: Clean the Xcode project.
90+
- `make proto`: Generate Swift files from protobufs.
91+
- `make help`: Display all available `make` commands with descriptions.
92+
93+
For continuous development, you can also use:
94+
95+
```bash
96+
make watch-gen
97+
```
98+
99+
This command watches for changes to `Coder Desktop/project.yml` and regenerates
100+
the Xcode project file as needed.
101+
102+
## Testing and Formatting
103+
104+
To maintain code quality, ensure you run the following before submitting any changes:
105+
106+
1. **Format Swift files:**
107+
108+
```bash
109+
make fmt
110+
```
111+
112+
2. **Lint Swift files:**
113+
114+
```bash
115+
make lint
116+
```
117+
118+
3. **Run tests:**
119+
120+
```bash
121+
make test
122+
```
123+
124+
## Contributing Workflow
125+
126+
1. Fork the repository and create your feature branch:
127+
128+
```bash
129+
git checkout -b feature/your-feature-name
130+
```
131+
132+
2. Make your changes and commit them with clear messages.
133+
3. Push your branch to your forked repository:
134+
135+
```bash
136+
git push origin feature/your-feature-name
137+
```
138+
139+
4. Open a pull request to the main repository.
140+
141+
Thank you for contributing! If you have any questions or need further assistance,
142+
feel free to open an issue.

‎Coder Desktop/Coder Desktop.xcodeproj/project.pbxproj

Lines changed: 0 additions & 1659 deletions
This file was deleted.

‎Coder Desktop/Coder Desktop.xcodeproj/project.xcworkspace/contents.xcworkspacedata

Lines changed: 0 additions & 7 deletions
This file was deleted.

‎Coder Desktop/Coder Desktop.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 0 additions & 68 deletions
This file was deleted.

‎Coder Desktop/Coder Desktop.xcodeproj/xcshareddata/xcschemes/Coder Desktop.xcscheme

Lines changed: 0 additions & 140 deletions
This file was deleted.

‎Coder Desktop/Coder Desktop.xcodeproj/xcshareddata/xcschemes/VPN.xcscheme

Lines changed: 0 additions & 67 deletions
This file was deleted.

‎Coder Desktop/Coder Desktop/NetworkExtension.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ enum NetworkExtensionState: Equatable {
1010
var description: String {
1111
switch self {
1212
case .unconfigured:
13-
return "NetworkExtension not configured, try logging in again"
13+
"NetworkExtension not configured, try logging in again"
1414
case .enabled:
15-
return "NetworkExtension tunnel enabled"
15+
"NetworkExtension tunnel enabled"
1616
case .disabled:
17-
return "NetworkExtension tunnel disabled"
17+
"NetworkExtension tunnel disabled"
1818
case let .failed(error):
19-
return "NetworkExtension config failed: \(error)"
19+
"NetworkExtension config failed: \(error)"
2020
}
2121
}
2222
}

‎Coder Desktop/Coder Desktop/Preview Content/PreviewSession.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ class PreviewSession: Session {
2424
}
2525

2626
func tunnelProviderProtocol() -> NETunnelProviderProtocol? {
27-
return nil
27+
nil
2828
}
2929
}

‎Coder Desktop/Coder Desktop/State.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class SecureSession: ObservableObject, Session {
7878
}
7979

8080
private func keychainSet(_ value: String?, for key: String) {
81-
if let value = value {
81+
if let value {
8282
try? keychain.set(value, key: key)
8383
} else {
8484
try? keychain.remove(key)
@@ -132,6 +132,6 @@ struct LiteralHeader: Hashable, Identifiable, Equatable, Codable {
132132

133133
extension LiteralHeader {
134134
func toSDKHeader() -> HTTPHeader {
135-
return .init(header: header, value: value)
135+
.init(header: header, value: value)
136136
}
137137
}

‎Coder Desktop/Coder Desktop/SystemExtension.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ enum SystemExtensionState: Equatable, Sendable {
1111
var description: String {
1212
switch self {
1313
case .uninstalled:
14-
return "VPN SystemExtension is waiting to be activated"
14+
"VPN SystemExtension is waiting to be activated"
1515
case .needsUserApproval:
16-
return "VPN SystemExtension needs user approval to activate"
16+
"VPN SystemExtension needs user approval to activate"
1717
case .installed:
18-
return "VPN SystemExtension is installed"
18+
"VPN SystemExtension is installed"
1919
case let .failed(error):
20-
return "VPN SystemExtension failed with error: \(error)"
20+
"VPN SystemExtension failed with error: \(error)"
2121
}
2222
}
2323
}

‎Coder Desktop/Coder Desktop/VPNService.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ enum VPNServiceError: Error, Equatable {
2929
var description: String {
3030
switch self {
3131
case .longTestError:
32-
return "This is a long error to test the UI with long errors"
32+
"This is a long error to test the UI with long errors"
3333
case let .internalError(description):
34-
return "Internal Error: \(description)"
34+
"Internal Error: \(description)"
3535
case let .systemExtensionError(state):
36-
return state.description
36+
state.description
3737
case let .networkExtensionError(state):
38-
return state.description
38+
state.description
3939
}
4040
}
4141
}

‎Coder Desktop/Coder Desktop/Views/Agent.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ enum AgentStatus: Equatable {
1616

1717
public var color: Color {
1818
switch self {
19-
case .okay: return .green
20-
case .warn: return .yellow
21-
case .error: return .red
22-
case .off: return .gray
19+
case .okay: .green
20+
case .warn: .yellow
21+
case .error: .red
22+
case .off: .gray
2323
}
2424
}
2525
}
@@ -41,7 +41,7 @@ struct AgentRowView: View {
4141

4242
private var wsURL: URL {
4343
// TODO: CoderVPN currently only supports owned workspaces
44-
return baseAccessURL.appending(path: "@me").appending(path: workspace.workspaceName)
44+
baseAccessURL.appending(path: "@me").appending(path: workspace.workspaceName)
4545
}
4646

4747
var body: some View {

‎Coder Desktop/Coder Desktop/Views/Agents.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ struct Agents<VPN: VPNService, S: Session>: View {
2727
}.toggleStyle(.button).buttonStyle(.plain)
2828
}
2929
}
30-
}.onReceive(inspection.notice) { self.inspection.visit(self, $0) } // ViewInspector
30+
}.onReceive(inspection.notice) { inspection.visit(self, $0) } // ViewInspector
3131
}
3232
}

‎Coder Desktop/Coder Desktop/Views/LoginForm.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ struct LoginForm<S: Session>: View {
5555
}.disabled(loading)
5656
.frame(width: 550)
5757
.fixedSize()
58-
.onReceive(inspection.notice) { self.inspection.visit(self, $0) } // ViewInspector
58+
.onReceive(inspection.notice) { inspection.visit(self, $0) } // ViewInspector
5959
}
6060

6161
func submit() async {
@@ -177,9 +177,9 @@ enum LoginError {
177177
var description: String {
178178
switch self {
179179
case .invalidURL:
180-
return "Invalid URL"
180+
"Invalid URL"
181181
case let .failedAuth(err):
182-
return "Could not authenticate with Coder deployment:\n\(err.description)"
182+
"Could not authenticate with Coder deployment:\n\(err.description)"
183183
}
184184
}
185185
}

‎Coder Desktop/Coder Desktop/Views/Settings/LiteralHeaderModal.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ struct LiteralHeaderModal: View {
2626
}.padding(20)
2727
}.onAppear {
2828
if let existingHeader {
29-
self.header = existingHeader.header
30-
self.value = existingHeader.value
29+
header = existingHeader.header
30+
value = existingHeader.value
3131
}
3232
}
3333
}

‎Coder Desktop/Coder Desktop/Views/Settings/LiteralHeadersSection.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,6 @@ struct LiteralHeadersSection<VPN: VPNService>: View {
6666
}.onTapGesture {
6767
selectedHeader = nil
6868
}.disabled(vpn.state != .disabled)
69-
.onReceive(inspection.notice) { self.inspection.visit(self, $0) } // ViewInspector
69+
.onReceive(inspection.notice) { inspection.visit(self, $0) } // ViewInspector
7070
}
7171
}

‎Coder Desktop/Coder Desktop/Views/VPNMenu.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
1414
VStack(alignment: .leading, spacing: Theme.Size.trayPadding) {
1515
HStack {
1616
Toggle(isOn: Binding(
17-
get: { self.vpn.state == .connected || self.vpn.state == .connecting },
17+
get: { vpn.state == .connected || vpn.state == .connecting },
1818
set: { isOn in Task {
19-
if isOn { await self.vpn.start() } else { await self.vpn.stop() }
19+
if isOn { await vpn.start() } else { await vpn.stop() }
2020
}
2121
}
2222
)) {
@@ -78,11 +78,11 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
7878
}.padding(.bottom, Theme.Size.trayMargin)
7979
.environmentObject(vpn)
8080
.environmentObject(session)
81-
.onReceive(inspection.notice) { self.inspection.visit(self, $0) } // ViewInspector
81+
.onReceive(inspection.notice) { inspection.visit(self, $0) } // ViewInspector
8282
}
8383

8484
private var vpnDisabled: Bool {
85-
return !session.hasSession ||
85+
!session.hasSession ||
8686
vpn.state == .connecting ||
8787
vpn.state == .disconnecting
8888
}

‎Coder Desktop/Coder DesktopTests/AgentsTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct AgentsTests {
1919
}
2020

2121
private func createMockAgents(count: Int) -> [Agent] {
22-
return (1 ... count).map {
22+
(1 ... count).map {
2323
Agent(
2424
id: UUID(),
2525
name: "a\($0)",

‎Coder Desktop/Coder DesktopTests/Util.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class MockSession: Session {
4646
}
4747

4848
func tunnelProviderProtocol() -> NETunnelProviderProtocol? {
49-
return nil
49+
nil
5050
}
5151
}
5252

‎Coder Desktop/CoderSDK/Client.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public struct Client {
2828
method: HTTPMethod,
2929
body: Data? = nil
3030
) async throws(ClientError) -> HTTPResponse {
31-
let url = self.url.appendingPathComponent(path)
31+
let url = url.appendingPathComponent(path)
3232
var req = URLRequest(url: url)
3333
if let token { req.addValue(token, forHTTPHeaderField: Headers.sessionToken) }
3434
req.httpMethod = method.rawValue
@@ -49,10 +49,10 @@ public struct Client {
4949
return HTTPResponse(resp: httpResponse, data: data, req: req)
5050
}
5151

52-
func request<T: Encodable & Sendable>(
52+
func request(
5353
_ path: String,
5454
method: HTTPMethod,
55-
body: T
55+
body: some Encodable & Sendable
5656
) async throws(ClientError) -> HTTPResponse {
5757
let encodedBody: Data?
5858
do {
@@ -67,7 +67,7 @@ public struct Client {
6767
_ path: String,
6868
method: HTTPMethod
6969
) async throws(ClientError) -> HTTPResponse {
70-
return try await doRequest(path: path, method: method)
70+
try await doRequest(path: path, method: method)
7171
}
7272

7373
func responseAsError(_ resp: HTTPResponse) -> ClientError {
@@ -86,7 +86,7 @@ public struct Client {
8686
}
8787
}
8888

89-
public struct APIError: Decodable {
89+
public struct APIError: Decodable, Sendable {
9090
let response: Response
9191
let statusCode: Int
9292
let method: String
@@ -105,13 +105,13 @@ public struct APIError: Decodable {
105105
}
106106
}
107107

108-
public struct Response: Decodable {
108+
public struct Response: Decodable, Sendable {
109109
let message: String
110110
let detail: String?
111111
let validations: [FieldValidation]?
112112
}
113113

114-
public struct FieldValidation: Decodable {
114+
public struct FieldValidation: Decodable, Sendable {
115115
let field: String
116116
let detail: String
117117
}
@@ -125,13 +125,13 @@ public enum ClientError: Error {
125125
public var description: String {
126126
switch self {
127127
case let .api(error):
128-
return error.description
128+
error.description
129129
case let .network(error):
130-
return error.localizedDescription
130+
error.localizedDescription
131131
case let .unexpectedResponse(data):
132-
return "Unexpected or non HTTP response: \(data)"
132+
"Unexpected or non HTTP response: \(data)"
133133
case let .encodeFailure(error):
134-
return "Failed to encode body: \(error)"
134+
"Failed to encode body: \(error)"
135135
}
136136
}
137137
}

‎Coder Desktop/CoderSDK/Deployment.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import Foundation
2+
13
public extension Client {
24
func buildInfo() async throws(ClientError) -> BuildInfoResponse {
35
let res = try await request("/api/v2/buildinfo", method: .get)
@@ -25,7 +27,7 @@ public struct BuildInfoResponse: Encodable, Decodable, Equatable, Sendable {
2527

2628
// `version` in the form `[0-9]+.[0-9]+.[0-9]+`
2729
public var semver: String? {
28-
return try? NSRegularExpression(pattern: #"v(\d+\.\d+\.\d+)"#)
30+
try? NSRegularExpression(pattern: #"v(\d+\.\d+\.\d+)"#)
2931
.firstMatch(in: version, range: NSRange(version.startIndex ..< version.endIndex, in: version))
3032
.flatMap { Range($0.range(at: 1), in: version).map { String(version[$0]) } }
3133
}

‎Coder Desktop/CoderSDK/HTTP.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import Foundation
2+
13
public struct HTTPResponse {
24
let resp: HTTPURLResponse
35
let data: Data

‎Coder Desktop/CoderSDKTests/CoderSDKTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@testable import CoderSDK
2+
import Foundation
23
import Mocker
34
import Testing
45

‎Coder Desktop/VPN/Manager.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -208,23 +208,23 @@ enum ManagerError: Error {
208208
var description: String {
209209
switch self {
210210
case let .download(err):
211-
return "Download error: \(err)"
211+
"Download error: \(err)"
212212
case let .tunnelSetup(err):
213-
return "Tunnel setup error: \(err)"
213+
"Tunnel setup error: \(err)"
214214
case let .handshake(err):
215-
return "Handshake error: \(err)"
215+
"Handshake error: \(err)"
216216
case let .validation(err):
217-
return "Validation error: \(err)"
217+
"Validation error: \(err)"
218218
case .incorrectResponse:
219-
return "Received unexpected response over tunnel"
219+
"Received unexpected response over tunnel"
220220
case let .failedRPC(err):
221-
return "Failed rpc: \(err)"
221+
"Failed rpc: \(err)"
222222
case let .serverInfo(msg):
223-
return msg
223+
msg
224224
case let .errorResponse(msg):
225-
return msg
225+
msg
226226
case .noTunnelFileDescriptor:
227-
return "Could not find a tunnel file descriptor"
227+
"Could not find a tunnel file descriptor"
228228
}
229229
}
230230
}

‎Coder Desktop/VPN/TunnelHandle.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@ enum TunnelHandleError: Error {
7575

7676
var description: String {
7777
switch self {
78-
case let .pipe(err): return "pipe error: \(err)"
79-
case let .dylib(d): return d
80-
case let .symbol(symbol, message): return "\(symbol): \(message)"
81-
case let .openTunnel(error): return "OpenTunnel: \(error.message)"
82-
case let .close(errs): return "close tunnel: \(errs.map(\.localizedDescription).joined(separator: ", "))"
78+
case let .pipe(err): "pipe error: \(err)"
79+
case let .dylib(d): d
80+
case let .symbol(symbol, message): "\(symbol): \(message)"
81+
case let .openTunnel(error): "OpenTunnel: \(error.message)"
82+
case let .close(errs): "close tunnel: \(errs.map(\.localizedDescription).joined(separator: ", "))"
8383
}
8484
}
8585
}
@@ -93,11 +93,11 @@ enum OpenTunnelError: Int32 {
9393

9494
var message: String {
9595
switch self {
96-
case .errDupReadFD: return "Failed to duplicate read file descriptor"
97-
case .errDupWriteFD: return "Failed to duplicate write file descriptor"
98-
case .errOpenPipe: return "Failed to open the pipe"
99-
case .errNewTunnel: return "Failed to create a new tunnel"
100-
case .unknown: return "Unknown error code"
96+
case .errDupReadFD: "Failed to duplicate read file descriptor"
97+
case .errDupWriteFD: "Failed to duplicate write file descriptor"
98+
case .errOpenPipe: "Failed to open the pipe"
99+
case .errNewTunnel: "Failed to create a new tunnel"
100+
case .unknown: "Unknown error code"
101101
}
102102
}
103103
}

‎Coder Desktop/VPNLib/Download.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ public enum ValidationError: Error {
1414
public var errorDescription: String? {
1515
switch self {
1616
case .fileNotFound:
17-
return "The file does not exist."
17+
"The file does not exist."
1818
case .unableToCreateStaticCode:
19-
return "Unable to create a static code object."
19+
"Unable to create a static code object."
2020
case .invalidSignature:
21-
return "The file's signature is invalid."
21+
"The file's signature is invalid."
2222
case .unableToRetrieveInfo:
23-
return "Unable to retrieve signing information."
23+
"Unable to retrieve signing information."
2424
case let .invalidIdentifier(identifier):
25-
return "Invalid identifier: \(identifier ?? "unknown")."
25+
"Invalid identifier: \(identifier ?? "unknown")."
2626
case let .invalidVersion(version):
27-
return "Invalid runtime version: \(version ?? "unknown")."
27+
"Invalid runtime version: \(version ?? "unknown")."
2828
case let .invalidTeamIdentifier(identifier):
29-
return "Invalid team identifier: \(identifier ?? "unknown")."
29+
"Invalid team identifier: \(identifier ?? "unknown")."
3030
case .missingInfoPList:
31-
return "Info.plist is not embedded within the dylib."
31+
"Info.plist is not embedded within the dylib."
3232
}
3333
}
3434
}
@@ -159,13 +159,13 @@ public enum DownloadError: Error {
159159
var localizedDescription: String {
160160
switch self {
161161
case let .unexpectedStatusCode(code):
162-
return "Unexpected HTTP status code: \(code)"
162+
"Unexpected HTTP status code: \(code)"
163163
case let .networkError(error):
164-
return "Network error: \(error.localizedDescription)"
164+
"Network error: \(error.localizedDescription)"
165165
case let .fileOpError(error):
166-
return "File operation error: \(error.localizedDescription)"
166+
"File operation error: \(error.localizedDescription)"
167167
case .invalidResponse:
168-
return "Received non-HTTP response"
168+
"Received non-HTTP response"
169169
}
170170
}
171171
}

‎Coder Desktop/VPNLib/Speaker.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public actor Speaker<SendMsg: RPCMessage & Message, RecvMsg: RPCMessage & Messag
9595

9696
/// Send a unary RPC message and handle the response
9797
public func unaryRPC(_ req: SendMsg) async throws -> RecvMsg {
98-
return try await withCheckedThrowingContinuation { continuation in
98+
try await withCheckedThrowingContinuation { continuation in
9999
Task { [sender, secretary, logger] in
100100
let msgID = await secretary.record(continuation: continuation)
101101
var req = req
@@ -199,7 +199,7 @@ actor Handshaker {
199199
}
200200
}
201201

202-
let vStr = versions.map { $0.description }.joined(separator: ",")
202+
let vStr = versions.map(\.description).joined(separator: ",")
203203
let ours = String(format: "\(headerPreamble) \(role) \(vStr)\n")
204204
do {
205205
try writeFD.write(contentsOf: ours.data(using: .utf8)!)

‎Coder Desktop/VPNLibTests/ProtoTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ struct HandshakerTests {
104104
let result: ProtoVersion
105105

106106
var description: String {
107-
return "\(tun) vs \(mgr) -> \(result)"
107+
"\(tun) vs \(mgr) -> \(result)"
108108
}
109109
}
110110

‎Coder Desktop/project.yml

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
name: "Coder Desktop"
2+
options:
3+
bundleIdPrefix: com.coder
4+
deploymentTarget:
5+
macOS: "14.6"
6+
xcodeVersion: "1600"
7+
minimumXcodeGenVersion: "2.42.0"
8+
9+
settings:
10+
base:
11+
MARKETING_VERSION: "1.0" # Sets the version number.
12+
CURRENT_PROJECT_VERSION: "1" # Sets the build number.
13+
14+
ALWAYS_SEARCH_USER_PATHS: NO
15+
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS: YES
16+
COPY_PHASE_STRIP: NO
17+
DEAD_CODE_STRIPPING: YES
18+
DEVELOPMENT_TEAM: "4399GN35BJ"
19+
GENERATE_INFOPLIST_FILE: YES
20+
PRODUCT_NAME: "$(TARGET_NAME)"
21+
SWIFT_VERSION: ${SWIFT_VERSION}
22+
ENABLE_USER_SCRIPT_SANDBOXING: YES
23+
LD_RUNPATH_SEARCH_PATHS:
24+
- "$(inherited)"
25+
- "@executable_path/../Frameworks"
26+
- "@executable_path/../../../../Frameworks"
27+
- "@loader_path/Frameworks"
28+
GCC_C_LANGUAGE_STANDARD: gnu17
29+
CLANG_CXX_LANGUAGE_STANDARD: "gnu++20"
30+
CLANG_ENABLE_MODULES: YES
31+
CLANG_ENABLE_OBJC_ARC: YES
32+
CLANG_ENABLE_OBJC_WEAK: YES
33+
ENABLE_STRICT_OBJC_MSGSEND: YES
34+
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING: YES
35+
CLANG_WARN_BOOL_CONVERSION: YES
36+
CLANG_WARN_COMMA: YES
37+
CLANG_WARN_CONSTANT_CONVERSION: YES
38+
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS: YES
39+
CLANG_WARN_DIRECT_OBJC_ISA_USAGE: YES_ERROR
40+
CLANG_WARN_DOCUMENTATION_COMMENTS: YES
41+
CLANG_WARN_EMPTY_BODY: YES
42+
CLANG_WARN_ENUM_CONVERSION: YES
43+
CLANG_WARN_INFINITE_RECURSION: YES
44+
CLANG_WARN_INT_CONVERSION: YES
45+
CLANG_WARN_NON_LITERAL_NULL_CONVERSION: YES
46+
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF: YES
47+
CLANG_WARN_OBJC_LITERAL_CONVERSION: YES
48+
CLANG_WARN_OBJC_ROOT_CLASS: YES_ERROR
49+
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER: YES
50+
CLANG_WARN_RANGE_LOOP_ANALYSIS: YES
51+
CLANG_WARN_STRICT_PROTOTYPES: YES
52+
CLANG_WARN_SUSPICIOUS_MOVE: YES
53+
CLANG_WARN_UNGUARDED_AVAILABILITY: YES_AGGRESSIVE
54+
CLANG_WARN_UNREACHABLE_CODE: YES
55+
CLANG_WARN__DUPLICATE_METHOD_MATCH: YES
56+
GCC_WARN_64_TO_32_BIT_CONVERSION: YES
57+
GCC_WARN_ABOUT_RETURN_TYPE: YES_ERROR
58+
GCC_WARN_UNDECLARED_SELECTOR: YES
59+
GCC_WARN_UNINITIALIZED_AUTOS: YES_AGGRESSIVE
60+
GCC_WARN_UNUSED_FUNCTION: YES
61+
GCC_WARN_UNUSED_VARIABLE: YES
62+
GCC_NO_COMMON_BLOCKS: YES
63+
CLANG_ANALYZER_NONNULL: YES
64+
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION: YES_AGGRESSIVE
65+
MTL_FAST_MATH: YES
66+
LOCALIZATION_PREFERS_STRING_CATALOGS: YES
67+
configs:
68+
debug:
69+
GCC_PREPROCESSOR_DEFINITIONS:
70+
- "DEBUG=1"
71+
- "$(inherited)"
72+
ONLY_ACTIVE_ARCH: YES
73+
SWIFT_ACTIVE_COMPILATION_CONDITIONS: "DEBUG $(inherited)"
74+
SWIFT_OPTIMIZATION_LEVEL: "-Onone"
75+
GCC_OPTIMIZATION_LEVEL: 0
76+
DEBUG_INFORMATION_FORMAT: dwarf
77+
ENABLE_TESTABILITY: YES
78+
MTL_ENABLE_DEBUG_INFO: INCLUDE_SOURCE
79+
release:
80+
SWIFT_COMPILATION_MODE: wholemodule
81+
DEBUG_INFORMATION_FORMAT: "dwarf-with-dsym"
82+
ENABLE_NS_ASSERTIONS: NO
83+
MTL_ENABLE_DEBUG_INFO: NO
84+
85+
packages:
86+
ViewInspector:
87+
url: https://github.com/nalexn/ViewInspector
88+
from: 0.10.0
89+
SwiftLintPlugins:
90+
url: https://github.com/SimplyDanny/SwiftLintPlugins
91+
from: 0.57.1
92+
FluidMenuBarExtra:
93+
url: https://github.com/lfroms/fluid-menu-bar-extra
94+
from: 1.1.0
95+
KeychainAccess:
96+
url: https://github.com/kishikawakatsumi/KeychainAccess
97+
branch: e0c7eebc5a4465a3c4680764f26b7a61f567cdaf
98+
SwiftProtobuf:
99+
url: https://github.com/apple/swift-protobuf.git
100+
exactVersion: 1.28.2
101+
Mocker:
102+
url: https://github.com/WeTransfer/Mocker
103+
from: 3.0.2
104+
LaunchAtLogin:
105+
url: https://github.com/sindresorhus/LaunchAtLogin-modern
106+
from: 1.1.0
107+
108+
targets:
109+
Coder Desktop:
110+
type: application
111+
platform: macOS
112+
sources: [Coder Desktop]
113+
entitlements:
114+
path: Coder Desktop/Coder_Desktop.entitlements
115+
properties:
116+
com.apple.developer.networking.networkextension:
117+
- packet-tunnel-provider
118+
com.apple.developer.system-extension.install: true
119+
com.apple.security.app-sandbox: true
120+
com.apple.security.files.user-selected.read-only: true
121+
com.apple.security.network.client: true
122+
settings:
123+
base:
124+
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon # Sets the app icon to "AppIcon".
125+
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor
126+
CODE_SIGN_IDENTITY: "Apple Development"
127+
CODE_SIGN_STYLE: Automatic
128+
COMBINE_HIDPI_IMAGES: YES
129+
DEVELOPMENT_ASSET_PATHS: '"Coder Desktop/Preview Content"' # Adds development assets.
130+
ENABLE_HARDENED_RUNTIME: YES
131+
ENABLE_PREVIEWS: YES
132+
INFOPLIST_KEY_LSUIElement: YES
133+
INFOPLIST_KEY_NSHumanReadableCopyright: ""
134+
SWIFT_EMIT_LOC_STRINGS: YES
135+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-Desktop"
136+
dependencies:
137+
- target: CoderSDK
138+
embed: true
139+
- target: VPN
140+
embed: without-signing # Embed without signing.
141+
- package: FluidMenuBarExtra
142+
- package: KeychainAccess
143+
- package: LaunchAtLogin
144+
scheme:
145+
testPlans:
146+
- path: Coder Desktop.xctestplan
147+
testTargets:
148+
- Coder DesktopTests
149+
- Coder DesktopUITests
150+
buildToolPlugins:
151+
- plugin: SwiftLintBuildToolPlugin
152+
package: SwiftLintPlugins
153+
154+
Coder DesktopTests:
155+
type: bundle.unit-test
156+
platform: macOS
157+
sources: [Coder DesktopTests]
158+
settings:
159+
base:
160+
BUNDLE_LOADER: "$(TEST_HOST)"
161+
TEST_HOST: "$(BUILT_PRODUCTS_DIR)/Coder Desktop.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Coder Desktop"
162+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-DesktopTests"
163+
dependencies:
164+
- target: "Coder Desktop"
165+
- target: CoderSDK
166+
embed: false # Do not embed the framework.
167+
- package: ViewInspector
168+
- package: Mocker
169+
170+
Coder DesktopUITests:
171+
type: bundle.ui-testing
172+
platform: macOS
173+
sources: [Coder DesktopUITests]
174+
settings:
175+
base:
176+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-DesktopUITests"
177+
dependencies:
178+
- target: Coder Desktop
179+
180+
VPN:
181+
type: system-extension
182+
platform: macOS
183+
sources: [VPN]
184+
entitlements:
185+
path: VPN/VPN.entitlements
186+
properties:
187+
com.apple.developer.networking.networkextension:
188+
- packet-tunnel-provider
189+
com.apple.security.app-sandbox: true
190+
com.apple.security.application-groups:
191+
- $(TeamIdentifierPrefix)com.coder.Coder-Desktop
192+
com.apple.security.network.client: true
193+
settings:
194+
base:
195+
INFOPLIST_FILE: VPN/Info.plist
196+
PRODUCT_MODULE_NAME: "$(PRODUCT_NAME:c99extidentifier)"
197+
PRODUCT_NAME: "$(inherited)"
198+
SWIFT_EMIT_LOC_STRINGS: YES
199+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-Desktop.VPN"
200+
ENABLE_HARDENED_RUNTIME: YES
201+
SWIFT_OBJC_BRIDGING_HEADER: "VPN/com_coder_Coder_Desktop_VPN-Bridging-Header.h"
202+
dependencies:
203+
- target: VPNLib
204+
embed: true
205+
- target: CoderSDK
206+
embed: true
207+
- sdk: NetworkExtension.framework
208+
209+
VPNLib:
210+
type: framework
211+
platform: macOS
212+
sources: [VPNLib]
213+
settings:
214+
base:
215+
PRODUCT_NAME: "$(TARGET_NAME:c99extidentifier)"
216+
SWIFT_EMIT_LOC_STRINGS: YES
217+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-Desktop.VPNLib"
218+
scheme:
219+
testTargets:
220+
- VPNLibTests
221+
dependencies:
222+
- package: SwiftProtobuf
223+
- package: SwiftProtobuf
224+
product: SwiftProtobufPluginLibrary
225+
- target: CoderSDK
226+
embed: false
227+
228+
VPNLibTests:
229+
type: bundle.unit-test
230+
platform: macOS
231+
sources: [VPNLibTests]
232+
settings:
233+
base:
234+
TEST_HOST: "$(BUILT_PRODUCTS_DIR)/Coder Desktop.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Coder Desktop"
235+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-Desktop.VPNLibTests"
236+
dependencies:
237+
- target: Coder Desktop
238+
- target: VPNLib
239+
embed: false
240+
- package: Mocker
241+
242+
CoderSDK:
243+
type: framework
244+
platform: macOS
245+
sources: [CoderSDK]
246+
settings:
247+
base:
248+
INFOPLIST_KEY_NSHumanReadableCopyright: ""
249+
PRODUCT_NAME: "$(TARGET_NAME:c99extidentifier)"
250+
SWIFT_EMIT_LOC_STRINGS: YES
251+
GENERATE_INFOPLIST_FILE: YES
252+
scheme:
253+
testTargets:
254+
- CoderSDKTests
255+
dependencies: []
256+
257+
CoderSDKTests:
258+
type: bundle.unit-test
259+
platform: macOS
260+
sources: [CoderSDKTests]
261+
dependencies:
262+
- target: "Coder Desktop"
263+
- target: CoderSDK
264+
embed: false # Do not embed the framework.
265+
- package: Mocker
266+
settings:
267+
base:
268+
TEST_HOST: "$(BUILT_PRODUCTS_DIR)/Coder Desktop.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Coder Desktop"
269+
PRODUCT_BUNDLE_IDENTIFIER: com.coder.Coder-Desktop.CoderSDKTests

‎Makefile

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,21 @@ endif
88

99
PROJECT := "Coder Desktop/Coder Desktop.xcodeproj"
1010
SCHEME := "Coder Desktop"
11+
SWIFT_VERSION := 6.0
1112

12-
fmt:
13+
$(PROJECT): Coder\ Desktop/project.yml
14+
cd Coder\ Desktop; \
15+
SWIFT_VERSION=$(SWIFT_VERSION) xcodegen
16+
17+
.PHONY: fmt
18+
fmt: ## Run Swift file formatter
1319
swiftformat \
1420
--exclude '**.pb.swift' \
21+
--swiftversion $(SWIFT_VERSION) \
1522
$(FMTFLAGS) .
1623

17-
test:
24+
.PHONY: test
25+
test: ## Run all tests
1826
set -o pipefail && xcodebuild test \
1927
-project $(PROJECT) \
2028
-scheme $(SCHEME) \
@@ -23,14 +31,27 @@ test:
2331
CODE_SIGNING_REQUIRED=NO \
2432
CODE_SIGNING_ALLOWED=NO | xcbeautify
2533

26-
lint:
34+
.PHONY: lint
35+
lint: ## Lint swift files
2736
swiftlint \
2837
--strict \
2938
--quiet $(LINTFLAGS)
3039

31-
clean:
40+
.PHONY: clean
41+
clean: ## Clean Xcode project
3242
xcodebuild clean \
3343
-project $(PROJECT)
3444

35-
proto:
45+
.PHONY: proto
46+
proto: ## Generate Swift files from protobufs
3647
protoc --swift_opt=Visibility=public --swift_out=. 'Coder Desktop/VPNLib/vpn.proto'
48+
49+
.PHONY: help
50+
help: ## Show this help
51+
@echo "Specify a command. The choices are:"
52+
@grep -hE '^[0-9a-zA-Z_-]+:.*?## .*$$' ${MAKEFILE_LIST} | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[0;36m%-20s\033[m %s\n", $$1, $$2}'
53+
@echo ""
54+
55+
.PHONY: watch-gen
56+
watch-gen: ## Generate Xcode project file and watch for changes
57+
watchexec -w 'Coder Desktop/project.yml' make $(PROJECT)

‎flake.lock

Lines changed: 61 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎flake.nix

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
description = "Coder Desktop macOS";
3+
4+
inputs = {
5+
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
6+
flake-utils.url = "github:numtide/flake-utils";
7+
};
8+
9+
outputs =
10+
{
11+
self,
12+
nixpkgs,
13+
flake-utils,
14+
}:
15+
flake-utils.lib.eachSystem
16+
(with flake-utils.lib.system; [
17+
aarch64-darwin
18+
x86_64-darwin
19+
])
20+
(
21+
system:
22+
let
23+
pkgs = import nixpkgs {
24+
inherit system;
25+
26+
config.allowUnfreePredicate =
27+
pkg:
28+
builtins.elem (pkgs.lib.getName pkg) [
29+
"Xcode.app"
30+
];
31+
};
32+
33+
formatter = pkgs.nixfmt-rfc-style;
34+
in
35+
{
36+
inherit formatter;
37+
38+
devShells.default = pkgs.mkShellNoCC {
39+
buildInputs = with pkgs; [
40+
apple-sdk_15
41+
clang
42+
formatter
43+
gnumake
44+
protobuf_28
45+
protoc-gen-swift
46+
swiftformat
47+
swiftlint
48+
watchexec
49+
xcodegen
50+
xcbeautify
51+
];
52+
53+
LD = "${pkgs.clang}/bin/clang";
54+
};
55+
}
56+
);
57+
}

0 commit comments

Comments
 (0)
Please sign in to comment.