Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4

- name: Select Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
# This project requires Xcode 26+ (see README Requirements). Pin an exact
# version here if `latest-stable` ever resolves below that floor.
xcode-version: latest-stable

- name: Cache SwiftPM dependency sources
uses: actions/cache@v4
with:
# Package.resolved isn't committed (swift-build/swift-tools-protocols float
# on `branch: main`), so it always hashes to the same empty match — key off
# Package.swift instead. Cache only fetched sources, not .build's compiled
# objects, so a stale cache can't silently serve outdated build products
# across dependency or toolchain changes; sources just get an incremental
# `git fetch` instead of a full clone.
path: |
~/Library/Caches/org.swift.swiftpm
.build/checkouts
.build/repositories
key: ${{ runner.os }}-spm-${{ hashFiles('Package.swift') }}
restore-keys: |
${{ runner.os }}-spm-

- name: Build
run: swift build

- name: Run tests
run: swift test

lint:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4

- name: Install SwiftLint
env:
SWIFTLINT_VERSION: "0.63.3" # keep in sync with the version contributors install locally
run: |
curl -sL "https://github.com/realm/SwiftLint/releases/download/${SWIFTLINT_VERSION}/portable_swiftlint.zip" -o swiftlint.zip
unzip -q swiftlint.zip -d "$RUNNER_TEMP/swiftlint-bin"
chmod +x "$RUNNER_TEMP/swiftlint-bin/swiftlint"
echo "$RUNNER_TEMP/swiftlint-bin" >> "$GITHUB_PATH"

- name: Lint
run: swiftlint lint
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repos:
- repo: local
hooks:
- id: swiftlint
name: SwiftLint
description: Lint staged Swift files with SwiftLint.
entry: swiftlint lint
language: system
files: \.swift$
exclude: ^\.build/
47 changes: 47 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
included:
- Sources
- Tests

excluded:
- .build
- .swiftpm

opt_in_rules:
- empty_count
- closure_spacing
- contains_over_first_not_nil
- fatal_error_message
- first_where
- force_unwrapping
- implicitly_unwrapped_optional
- last_where
- redundant_nil_coalescing
- sorted_first_last
- unneeded_parentheses_in_closure_argument

disabled_rules:
- todo

line_length:
warning: 120
error: 200

trailing_comma:
mandatory_comma: true

identifier_name:
excluded:
- id
- s
- t
- fm
- op
- v26_2
- v16_0
- v16_2_1

force_unwrapping:
severity: warning

implicitly_unwrapped_optional:
severity: warning
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,24 @@ swift test

# Build release binary
swift build -c release

# Lint
swiftlint lint
```

### Pre-commit hooks

This repo uses [pre-commit](https://pre-commit.com) to lint staged Swift files with
[SwiftLint](https://github.com/realm/SwiftLint) before each commit.

```bash
brew install pre-commit swiftlint
pre-commit install
```

After that, `git commit` runs SwiftLint automatically against whatever `.swift` files are
staged. Run it manually against everything with `pre-commit run --all-files`.

### Project layout

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,3 @@ public extension BuildServerBootstrap {
)
}
}

2 changes: 1 addition & 1 deletion Sources/SourceKitXcodeBSP/Xcode/XcodePaths.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public struct XcodeVersion: Sendable, CustomStringConvertible {

public init(versionString: String) {
let parts = versionString.split(separator: ".").compactMap { Int($0) }
major = parts.count > 0 ? parts[0] : 0
major = !parts.isEmpty ? parts[0] : 0
minor = parts.count > 1 ? parts[1] : 0
patch = parts.count > 2 ? parts[2] : 0
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/sourcekit-xcode-bsp/SourcekitXcodeBspCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ struct Serve: AsyncParsableCommand {
serviceProvider: serviceProvider
)
}
}
}
2 changes: 1 addition & 1 deletion Sources/test-ipc/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import SwiftBuild

private final class NopDelegate: SWBPlanningOperationDelegate, @unchecked Sendable {
func provisioningTaskInputs(targetGUID: String, provisioningSourceData: SWBProvisioningTaskInputsSourceData) async -> SWBProvisioningTaskInputs { .init() }
func executeExternalTool(commandLine: [String], workingDirectory: String?, environment: [String : String]) async throws -> SWBExternalToolResult {
func executeExternalTool(commandLine: [String], workingDirectory: String?, environment: [String: String]) async throws -> SWBExternalToolResult {
print(" executeExternalTool: \(commandLine.first ?? "?") (returning .deferred)")
return .deferred
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ struct WorkspaceChangeFilterTests {
func rejectsOtherProjects() {
let filter = WorkspaceChangeFilter(
allowedPaths: [
"/Projects/App/App.xcodeproj/project.pbxproj",
"/Projects/App/App.xcodeproj/project.pbxproj"
]
)

Expand Down Expand Up @@ -110,7 +110,7 @@ struct WorkspaceChangeFilterTests {
// Even if a checkout path were mistakenly allowlisted, ignore components win.
let filter = WorkspaceChangeFilter(
allowedPaths: [
"/Projects/App/SourcePackages/checkouts/Dep/Package.swift",
"/Projects/App/SourcePackages/checkouts/Dep/Package.swift"
]
)
#expect(
Expand All @@ -126,7 +126,7 @@ struct WorkspaceChangeFilterTests {
// be an ignore component or reloads never fire.
let filter = WorkspaceChangeFilter(
allowedPaths: [
"/Users/me/checkouts/MyApp/MyApp.xcodeproj/project.pbxproj",
"/Users/me/checkouts/MyApp/MyApp.xcodeproj/project.pbxproj"
]
)
#expect(
Expand Down
2 changes: 1 addition & 1 deletion Tests/SourceKitXcodeBSPTests/Xcode/XcodePathsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ struct XcodePathsTests {
.infoPlistInvalid,
.versionNotFound,
.unsupportedVersion(XcodeVersion(major: 15, minor: 0)),
.swbBuildServiceNotFound
.swbBuildServiceNotFound,
]

for error in errors {
Expand Down
Loading