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
19 changes: 14 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,12 @@ jobs:
code-quality:
runs-on: [self-hosted, macOS, keypath]
timeout-minutes: 5
# No concurrency group: this job never runs `swift test` or touches
# RuleCollectionsManager's config file, so it doesn't share the state
# that caused the race — no need to queue it behind build-and-test.
# This job does not share test state, but it does share the only physical
# runner. Queue it with builds so SwiftFormat gets enough CPU to finish
# before its fixed per-rule safety timeout.
concurrency:
group: keypath-self-hosted-runner
cancel-in-progress: false

steps:
- name: Clean stale git credentials
Expand All @@ -217,6 +220,9 @@ jobs:
- name: Add Homebrew to PATH
run: echo "/opt/homebrew/bin" >> $GITHUB_PATH

- name: Install pinned SwiftFormat
run: mise install swiftformat

- name: Get changed Swift files
id: changed
run: |
Expand Down Expand Up @@ -244,7 +250,7 @@ jobs:
if: steps.changed.outputs.swift_files != ''
run: |
PINNED=$(sed -nE 's/^[[:space:]]*swiftformat[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/p' mise.toml)
ACTUAL=$(swiftformat --version | tr -d '[:space:]')
ACTUAL=$(mise exec swiftformat -- swiftformat --version | tr -d '[:space:]')
echo "SwiftFormat — pinned (mise.toml): '$PINNED', installed: '$ACTUAL'"
if [ -z "$PINNED" ]; then
echo "::error::Could not read the swiftformat pin from mise.toml"
Expand All @@ -260,7 +266,10 @@ jobs:
if: steps.changed.outputs.swift_files != ''
run: |
echo "Checking formatting of changed Swift files (must match the pinned fixed-point)..."
echo "${{ steps.changed.outputs.swift_files }}" | xargs swiftformat --lint || {
# SwiftFormat 0.61.1 can time out while applying rules across a large
# argument set. Each file still uses the same pinned configuration;
# batching one at a time keeps the lint result deterministic.
echo "${{ steps.changed.outputs.swift_files }}" | xargs -n 1 mise exec swiftformat -- swiftformat --lint || {
echo "::error::SwiftFormat found formatting issues. Run 'swiftformat Sources Tests' (at the pinned version) and commit."
exit 1
}
Expand Down
37 changes: 37 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,17 @@ let package = Package(
.swiftLanguageMode(.v6)
]
),
// Foundation-only CLI argument and presentation contracts.
.target(
name: "KeyPathCLICommon",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser")
],
path: "Sources/KeyPathCLICommon",
swiftSettings: [
.swiftLanguageMode(.v6)
]
),
// Installation wizard (extracted from KeyPathAppKit for incremental compilation)
.target(
name: "KeyPathInstallationWizard",
Expand Down Expand Up @@ -289,15 +300,30 @@ let package = Package(
]
),
// CLI library (testable)
.target(
name: "KeyPathCLIHelp",
dependencies: [
"KeyPathCLICommon",
"KeyPathRulesCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
],
path: "Sources/KeyPathCLI/Commands/Help",
swiftSettings: [
.swiftLanguageMode(.v6)
]
),
.target(
name: "KeyPathCLI",
dependencies: [
"KeyPathCLISupport",
"KeyPathCLICommon",
"KeyPathCLIHelp",
"KeyPathAppKit",
"KeyPathRulesCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
],
path: "Sources/KeyPathCLI",
exclude: ["Commands/Help"],
swiftSettings: [
.swiftLanguageMode(.v6)
]
Expand Down Expand Up @@ -389,6 +415,17 @@ let package = Package(
.swiftLanguageMode(.v6)
]
),
.testTarget(
name: "KeyPathCLIHelpTests",
dependencies: [
"KeyPathCLIHelp",
.product(name: "ArgumentParser", package: "swift-argument-parser")
],
path: "Tests/KeyPathCLIHelpTests",
swiftSettings: [
.swiftLanguageMode(.v6)
]
),
// Visual snapshot tests for help documentation screenshots
.testTarget(
name: "KeyPathSnapshotTests",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ actor ConfigurationOperationGate {
struct Permit: Sendable {
fileprivate let owner: UUID
fileprivate let operation: UUID

/// Identifies one admitted root operation without exposing the gate owner.
/// Consumers use this only to avoid repeating preparation work for trusted
/// nested calls that carry the same permit.
var operationID: UUID {
operation
}
}

enum Failure: LocalizedError {
Expand Down
Loading
Loading