Skip to content

Commit 9f7e86c

Browse files
Add .swift-format configuration and add a script to format
1 parent 6406ec2 commit 9f7e86c

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

Diff for: .github/workflows/test.yml

+15
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,18 @@ jobs:
6767
- run: swift build
6868
env:
6969
DEVELOPER_DIR: /Applications/${{ matrix.xcode }}.app/Contents/Developer/
70+
71+
format:
72+
runs-on: ubuntu-latest
73+
container:
74+
image: swiftwasm/swift:6.0.3
75+
steps:
76+
- uses: actions/checkout@v4
77+
- run: ./Utilities/format.swift
78+
- name: Check for formatting changes
79+
run: |
80+
git config --global --add safe.directory "$GITHUB_WORKSPACE"
81+
git diff --exit-code || {
82+
echo "::error::The formatting changed some files. Please run \`./Utilities/format.swift\` and commit the changes."
83+
exit 1
84+
}

Diff for: .swift-format

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"version": 1,
3+
"lineLength": 120,
4+
"indentation": {
5+
"spaces": 4
6+
},
7+
"lineBreakBeforeEachArgument": true,
8+
"indentConditionalCompilationBlocks": false,
9+
"prioritizeKeepingFunctionOutputTogether": true
10+
}

Diff for: Utilities/format.swift

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env swift
2+
3+
import class Foundation.FileManager
4+
import class Foundation.Process
5+
import class Foundation.ProcessInfo
6+
import struct Foundation.URL
7+
import func Foundation.exit
8+
9+
/// The root directory of the project.
10+
let projectRoot = URL(fileURLWithPath: #filePath).deletingLastPathComponent().deletingLastPathComponent()
11+
12+
/// Returns the path to the executable if it is found in the PATH environment variable.
13+
func which(_ executable: String) -> String? {
14+
let pathSeparator: Character
15+
#if os(Windows)
16+
pathSeparator = ";"
17+
#else
18+
pathSeparator = ":"
19+
#endif
20+
let paths = ProcessInfo.processInfo.environment["PATH"]!.split(separator: pathSeparator)
21+
for path in paths {
22+
let url = URL(fileURLWithPath: String(path)).appendingPathComponent(executable)
23+
if FileManager.default.isExecutableFile(atPath: url.path) {
24+
return url.path
25+
}
26+
}
27+
return nil
28+
}
29+
30+
/// Runs the `swift-format` command with the given arguments in the project root.
31+
func swiftFormat(_ arguments: [String]) throws {
32+
guard let swiftFormat = which("swift-format") else {
33+
print("swift-format not found in PATH")
34+
exit(1)
35+
}
36+
let task = Process()
37+
task.executableURL = URL(fileURLWithPath: swiftFormat)
38+
task.arguments = arguments
39+
task.currentDirectoryURL = projectRoot
40+
try task.run()
41+
task.waitUntilExit()
42+
if task.terminationStatus != 0 {
43+
print("swift-format failed with status \(task.terminationStatus)")
44+
exit(1)
45+
}
46+
}
47+
48+
/// Patterns to exclude from formatting.
49+
let excluded: Set<String> = [
50+
".git",
51+
".build",
52+
".index-build",
53+
"node_modules",
54+
"__Snapshots__",
55+
// Exclude the script itself to avoid changing its file mode.
56+
URL(fileURLWithPath: #filePath).lastPathComponent,
57+
]
58+
59+
/// Returns a list of directories to format.
60+
func filesToFormat() -> [String] {
61+
var files: [String] = []
62+
let fileManager = FileManager.default
63+
let enumerator = fileManager.enumerator(
64+
at: projectRoot, includingPropertiesForKeys: nil
65+
)!
66+
for case let fileURL as URL in enumerator {
67+
if excluded.contains(fileURL.lastPathComponent) {
68+
if fileURL.hasDirectoryPath {
69+
enumerator.skipDescendants()
70+
}
71+
continue
72+
}
73+
guard fileURL.pathExtension == "swift" else { continue }
74+
files.append(fileURL.path)
75+
}
76+
return files
77+
}
78+
79+
// Format the files in the project.
80+
try swiftFormat(["format", "--parallel", "--in-place", "--recursive"] + filesToFormat())

0 commit comments

Comments
 (0)