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 4a91b6d

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

36 files changed

+1021
-2046
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: 44 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,69 @@ 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 test
42+
3243
format:
3344
name: fmt
3445
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
3546
steps:
47+
- name: Harden Runner
48+
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
49+
with:
50+
egress-policy: audit
51+
3652
- name: Checkout
3753
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3854
with:
3955
fetch-depth: 1
40-
- run: |
41-
make fmt
56+
57+
- name: Switch XCode Version
58+
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
59+
with:
60+
# (ThomasK33): depot.dev does not yet support Xcode 16.1 or 16.2 GA, thus we're stuck with 16.0.0 for now.
61+
# I've already reached out, so hopefully this comment will soon be obsolete.
62+
xcode-version: "16.0.0"
63+
64+
- name: Setup Nix
65+
uses: ./.github/actions/nix-devshell
66+
67+
- run: make fmt
68+
4269
lint:
4370
name: lint
4471
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
4572
steps:
73+
- name: Harden Runner
74+
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
75+
with:
76+
egress-policy: audit
77+
4678
- name: Checkout
4779
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
4880
with:
4981
fetch-depth: 1
50-
- name: Install Swiftlint
51-
run: |
52-
brew install swiftlint
53-
- run: |
54-
make lint
82+
83+
- name: Setup Nix
84+
uses: ./.github/actions/nix-devshell
85+
86+
- 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/VPN/VPN.entitlements

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@
1414
</array>
1515
<key>com.apple.security.network.client</key>
1616
<true/>
17+
<key>com.apple.security.network.server</key>
18+
<true/>
1719
</dict>
1820
</plist>

‎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: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
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+
- "@loader_path/Frameworks"
27+
GCC_C_LANGUAGE_STANDARD: gnu17
28+
CLANG_CXX_LANGUAGE_STANDARD: "gnu++20"
29+
CLANG_ENABLE_MODULES: YES
30+
CLANG_ENABLE_OBJC_ARC: YES
31+
CLANG_ENABLE_OBJC_WEAK: YES
32+
ENABLE_STRICT_OBJC_MSGSEND: YES
33+
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING: YES
34+
CLANG_WARN_BOOL_CONVERSION: YES
35+
CLANG_WARN_COMMA: YES
36+
CLANG_WARN_CONSTANT_CONVERSION: YES
37+
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS: YES
38+
CLANG_WARN_DIRECT_OBJC_ISA_USAGE: YES_ERROR
39+
CLANG_WARN_DOCUMENTATION_COMMENTS: YES
40+
CLANG_WARN_EMPTY_BODY: YES
41+
CLANG_WARN_ENUM_CONVERSION: YES
42+
CLANG_WARN_INFINITE_RECURSION: YES
43+
CLANG_WARN_INT_CONVERSION: YES
44+
CLANG_WARN_NON_LITERAL_NULL_CONVERSION: YES
45+
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF: YES
46+
CLANG_WARN_OBJC_LITERAL_CONVERSION: YES
47+
CLANG_WARN_OBJC_ROOT_CLASS: YES_ERROR
48+
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER: YES
49+
CLANG_WARN_RANGE_LOOP_ANALYSIS: YES
50+
CLANG_WARN_STRICT_PROTOTYPES: YES
51+
CLANG_WARN_SUSPICIOUS_MOVE: YES
52+
CLANG_WARN_UNGUARDED_AVAILABILITY: YES_AGGRESSIVE
53+
CLANG_WARN_UNREACHABLE_CODE: YES
54+
CLANG_WARN__DUPLICATE_METHOD_MATCH: YES
55+
GCC_WARN_64_TO_32_BIT_CONVERSION: YES
56+
GCC_WARN_ABOUT_RETURN_TYPE: YES_ERROR
57+
GCC_WARN_UNDECLARED_SELECTOR: YES
58+
GCC_WARN_UNINITIALIZED_AUTOS: YES_AGGRESSIVE
59+
GCC_WARN_UNUSED_FUNCTION: YES
60+
GCC_WARN_UNUSED_VARIABLE: YES
61+
GCC_NO_COMMON_BLOCKS: YES
62+
CLANG_ANALYZER_NONNULL: YES
63+
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION: YES_AGGRESSIVE
64+
MTL_FAST_MATH: YES
65+
LOCALIZATION_PREFERS_STRING_CATALOGS: YES
66+
configs:
67+
debug:
68+
GCC_PREPROCESSOR_DEFINITIONS:
69+
- "DEBUG=1"
70+
- "$(inherited)"
71+
ONLY_ACTIVE_ARCH: YES
72+
SWIFT_ACTIVE_COMPILATION_CONDITIONS: "DEBUG $(inherited)"
73+
SWIFT_OPTIMIZATION_LEVEL: "-Onone"
74+
GCC_OPTIMIZATION_LEVEL: 0
75+
DEBUG_INFORMATION_FORMAT: dwarf
76+
ENABLE_TESTABILITY: YES
77+
MTL_ENABLE_DEBUG_INFO: INCLUDE_SOURCE
78+
release:
79+
SWIFT_COMPILATION_MODE: wholemodule
80+
DEBUG_INFORMATION_FORMAT: "dwarf-with-dsym"
81+
ENABLE_NS_ASSERTIONS: NO
82+
MTL_ENABLE_DEBUG_INFO: NO
83+
84+
packages:
85+
ViewInspector:
86+
url: https://github.com/nalexn/ViewInspector
87+
from: 0.10.0
88+
SwiftLintPlugins:
89+
url: https://github.com/SimplyDanny/SwiftLintPlugins
90+
from: 0.57.1
91+
FluidMenuBarExtra:
92+
url: https://github.com/lfroms/fluid-menu-bar-extra
93+
from: 1.1.0
94+
KeychainAccess:
95+
url: https://github.com/kishikawakatsumi/KeychainAccess
96+
branch: e0c7eebc5a4465a3c4680764f26b7a61f567cdaf
97+
SwiftProtobuf:
98+
url: https://github.com/apple/swift-protobuf.git
99+
exactVersion: 1.28.2
100+
Mocker:
101+
url: https://github.com/WeTransfer/Mocker
102+
from: 3.0.2
103+
LaunchAtLogin:
104+
url: https://github.com/sindresorhus/LaunchAtLogin-modern
105+
from: 1.1.0
106+
107+
targets:
108+
Coder Desktop:
109+
type: application
110+
platform: macOS
111+
sources:
112+
- path: 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+
137+
# (ThomasK33): Install the application into the /Applications folder
138+
# so that macOS stops complaining about the app being run from an
139+
# untrusted folder.
140+
DEPLOYMENT_LOCATION: YES
141+
DSTROOT: $(LOCAL_APPS_DIR)/Coder
142+
INSTALL_PATH: /
143+
SKIP_INSTALL: NO
144+
dependencies:
145+
- target: CoderSDK
146+
embed: true
147+
- target: VPN
148+
embed: without-signing # Embed without signing.
149+
- package: FluidMenuBarExtra
150+
- package: KeychainAccess
151+
- package: LaunchAtLogin
152+
scheme:
153+
testPlans:
154+
- path: Coder Desktop.xctestplan
155+
testTargets:
156+
- Coder DesktopTests
157+
- Coder DesktopUITests
158+
buildToolPlugins:
159+
- plugin: SwiftLintBuildToolPlugin
160+
package: SwiftLintPlugins
161+
162+
Coder DesktopTests:
163+
type: bundle.unit-test
164+
platform: macOS
165+
sources:
166+
- path: Coder DesktopTests
167+
settings:
168+
base:
169+
BUNDLE_LOADER: "$(TEST_HOST)"
170+
TEST_HOST: "$(BUILT_PRODUCTS_DIR)/Coder Desktop.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Coder Desktop"
171+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-DesktopTests"
172+
dependencies:
173+
- target: "Coder Desktop"
174+
- target: CoderSDK
175+
embed: false # Do not embed the framework.
176+
- package: ViewInspector
177+
- package: Mocker
178+
179+
Coder DesktopUITests:
180+
type: bundle.ui-testing
181+
platform: macOS
182+
sources:
183+
- path: Coder DesktopUITests
184+
settings:
185+
base:
186+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-DesktopUITests"
187+
dependencies:
188+
- target: Coder Desktop
189+
190+
VPN:
191+
type: system-extension
192+
platform: macOS
193+
sources:
194+
- path: VPN
195+
entitlements:
196+
path: VPN/VPN.entitlements
197+
properties:
198+
com.apple.developer.networking.networkextension:
199+
- packet-tunnel-provider
200+
com.apple.security.app-sandbox: true
201+
com.apple.security.application-groups:
202+
- $(TeamIdentifierPrefix)com.coder.Coder-Desktop
203+
com.apple.security.network.client: true
204+
com.apple.security.network.server: true
205+
settings:
206+
base:
207+
ENABLE_HARDENED_RUNTIME: YES
208+
INFOPLIST_FILE: VPN/Info.plist
209+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-Desktop.VPN"
210+
PRODUCT_MODULE_NAME: "$(PRODUCT_NAME:c99extidentifier)"
211+
PRODUCT_NAME: "$(PRODUCT_BUNDLE_IDENTIFIER)"
212+
SWIFT_EMIT_LOC_STRINGS: YES
213+
SWIFT_OBJC_BRIDGING_HEADER: "VPN/com_coder_Coder_Desktop_VPN-Bridging-Header.h"
214+
dependencies:
215+
- target: VPNLib
216+
embed: true
217+
- target: CoderSDK
218+
embed: true
219+
- sdk: NetworkExtension.framework
220+
221+
VPNLib:
222+
type: framework
223+
platform: macOS
224+
sources:
225+
- path: VPNLib
226+
settings:
227+
base:
228+
PRODUCT_NAME: "$(TARGET_NAME:c99extidentifier)"
229+
SWIFT_EMIT_LOC_STRINGS: YES
230+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-Desktop.VPNLib"
231+
DYLIB_COMPATIBILITY_VERSION: 1
232+
DYLIB_CURRENT_VERSION: 1
233+
DYLIB_INSTALL_NAME_BASE: "@rpath"
234+
CODE_SIGN_IDENTITY: "Apple Development"
235+
CODE_SIGN_STYLE: Automatic
236+
LD_RUNPATH_SEARCH_PATHS:
237+
- "@executable_path/../Frameworks"
238+
- "@loader_path/Frameworks"
239+
scheme:
240+
testTargets:
241+
- VPNLibTests
242+
dependencies:
243+
- package: SwiftProtobuf
244+
- package: SwiftProtobuf
245+
product: SwiftProtobufPluginLibrary
246+
- target: CoderSDK
247+
embed: false
248+
249+
VPNLibTests:
250+
type: bundle.unit-test
251+
platform: macOS
252+
sources:
253+
- path: VPNLibTests
254+
settings:
255+
base:
256+
TEST_HOST: "$(BUILT_PRODUCTS_DIR)/Coder Desktop.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Coder Desktop"
257+
PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-Desktop.VPNLibTests"
258+
dependencies:
259+
- target: Coder Desktop
260+
- target: VPNLib
261+
embed: false
262+
- package: Mocker
263+
264+
CoderSDK:
265+
type: framework
266+
platform: macOS
267+
sources:
268+
- path: CoderSDK
269+
settings:
270+
base:
271+
INFOPLIST_KEY_NSHumanReadableCopyright: ""
272+
PRODUCT_NAME: "$(TARGET_NAME:c99extidentifier)"
273+
SWIFT_EMIT_LOC_STRINGS: YES
274+
GENERATE_INFOPLIST_FILE: YES
275+
DYLIB_COMPATIBILITY_VERSION: 1
276+
DYLIB_CURRENT_VERSION: 1
277+
DYLIB_INSTALL_NAME_BASE: "@rpath"
278+
scheme:
279+
testTargets:
280+
- CoderSDKTests
281+
dependencies: []
282+
283+
CoderSDKTests:
284+
type: bundle.unit-test
285+
platform: macOS
286+
sources:
287+
- path: CoderSDKTests
288+
dependencies:
289+
- target: "Coder Desktop"
290+
- target: CoderSDK
291+
embed: false # Do not embed the framework.
292+
- package: Mocker
293+
settings:
294+
base:
295+
TEST_HOST: "$(BUILT_PRODUCTS_DIR)/Coder Desktop.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Coder Desktop"
296+
PRODUCT_BUNDLE_IDENTIFIER: com.coder.Coder-Desktop.CoderSDKTests

‎Makefile

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,61 @@ LINTFLAGS :=
66
FMTFLAGS :=
77
endif
88

9-
PROJECT := "Coder Desktop/Coder Desktop.xcodeproj"
10-
SCHEME := "Coder Desktop"
9+
PROJECT := Coder\ Desktop
10+
XCPROJECT := Coder\ Desktop/Coder\ Desktop.xcodeproj
11+
SCHEME := Coder\ Desktop
12+
SWIFT_VERSION := 6.0
1113

12-
fmt:
14+
.PHONY: setup
15+
setup: \
16+
$(XCPROJECT) \
17+
$(PROJECT)/VPNLib/vpn.pb.swift
18+
19+
$(XCPROJECT): $(PROJECT)/project.yml
20+
cd $(PROJECT); \
21+
SWIFT_VERSION=$(SWIFT_VERSION) xcodegen
22+
23+
$(PROJECT)/VPNLib/vpn.pb.swift: $(PROJECT)/VPNLib/vpn.proto
24+
protoc --swift_opt=Visibility=public --swift_out=. 'Coder Desktop/VPNLib/vpn.proto'
25+
26+
.PHONY: fmt
27+
fmt: ## Run Swift file formatter
1328
swiftformat \
1429
--exclude '**.pb.swift' \
30+
--swiftversion $(SWIFT_VERSION) \
1531
$(FMTFLAGS) .
1632

17-
test:
33+
.PHONY: test
34+
test: $(XCPROJECT) ## Run all tests
1835
set -o pipefail && xcodebuild test \
19-
-project $(PROJECT) \
36+
-project $(XCPROJECT) \
2037
-scheme $(SCHEME) \
2138
-testPlan $(SCHEME) \
2239
-skipPackagePluginValidation \
2340
CODE_SIGNING_REQUIRED=NO \
2441
CODE_SIGNING_ALLOWED=NO | xcbeautify
2542

26-
lint:
43+
.PHONY: lint
44+
lint: ## Lint swift files
2745
swiftlint \
2846
--strict \
2947
--quiet $(LINTFLAGS)
3048

31-
clean:
49+
.PHONY: clean
50+
clean: ## Clean Xcode project
3251
xcodebuild clean \
33-
-project $(PROJECT)
52+
-project $(XCPROJECT)
53+
rm -rf $(XCPROJECT)
3454

35-
proto:
36-
protoc --swift_opt=Visibility=public --swift_out=. 'Coder Desktop/VPNLib/vpn.proto'
55+
.PHONY: proto
56+
proto: $(PROJECT)/VPNLib/vpn.pb.swift ## Generate Swift files from protobufs
57+
58+
.PHONY: help
59+
help: ## Show this help
60+
@echo "Specify a command. The choices are:"
61+
@grep -hE '^[0-9a-zA-Z_-]+:.*?## .*$$' ${MAKEFILE_LIST} | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[0;36m%-20s\033[m %s\n", $$1, $$2}'
62+
@echo ""
63+
64+
.PHONY: watch-gen
65+
watch-gen: ## Generate Xcode project file and watch for changes
66+
watchexec -w 'Coder Desktop/project.yml' make $(XCPROJECT)

‎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: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
description = "Coder Desktop macOS";
3+
4+
inputs = {
5+
nixpkgs.url = "github:nixos/nixpkgs/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+
27+
formatter = pkgs.nixfmt-rfc-style;
28+
in
29+
{
30+
inherit formatter;
31+
32+
devShells.default = pkgs.mkShellNoCC {
33+
buildInputs = with pkgs; [
34+
apple-sdk_15
35+
clang
36+
formatter
37+
gnumake
38+
protobuf_28
39+
protoc-gen-swift
40+
swiftformat
41+
swiftlint
42+
watchexec
43+
xcodegen
44+
xcbeautify
45+
];
46+
};
47+
}
48+
);
49+
}

0 commit comments

Comments
 (0)
Please sign in to comment.