Skip to content

Commit 509d8dd

Browse files
committed
Enable cross-PR testing
1 parent d82d736 commit 509d8dd

File tree

4 files changed

+207
-10
lines changed

4 files changed

+207
-10
lines changed

.github/workflows/pull_request.yml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ jobs:
88
tests:
99
name: Test
1010
uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
11-
soundness:
12-
name: Soundness
13-
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
1411
with:
15-
license_header_check_enabled: false
16-
license_header_check_project_name: "Swift.org"
12+
enable_windows_checks: false
13+
linux_pre_build_command: |
14+
swift cross-pr-checkout.swift
15+
# soundness:
16+
# name: Soundness
17+
# uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
18+
# with:
19+
# license_header_check_enabled: false
20+
# license_header_check_project_name: "Swift.org"

Sources/SwiftFormat/Rules/UseShorthandTypeNames.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
4848
switch node.name.text {
4949
case "Array":
5050
guard let argument = genericArgumentList.firstAndOnly,
51-
case .type(let typeArgument) = argument else {
51+
case .type(let typeArgument) = argument.argument else {
5252
newNode = nil
5353
break
5454
}
@@ -62,7 +62,7 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
6262
case "Dictionary":
6363
guard let arguments = exactlyTwoChildren(of: genericArgumentList),
6464
case .type(let type0Argument) = arguments.0.argument,
65-
caes .type(let type1Argument) = arguments.1.argument else {
65+
case .type(let type1Argument) = arguments.1.argument else {
6666
newNode = nil
6767
break
6868
}
@@ -79,7 +79,7 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
7979
break
8080
}
8181
guard let argument = genericArgumentList.firstAndOnly,
82-
case .type(let typeArgument) = argument else {
82+
case .type(let typeArgument) = argument.argument else {
8383
newNode = nil
8484
break
8585
}
@@ -143,7 +143,7 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
143143
switch expression.baseName.text {
144144
case "Array":
145145
guard let argument = genericArgumentList.firstAndOnly,
146-
case .type(let typeArgument) = argument else {
146+
case .type(let typeArgument) = argument.argument else {
147147
newNode = nil
148148
break
149149
}
@@ -172,7 +172,7 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
172172

173173
case "Optional":
174174
guard let argument = genericArgumentList.firstAndOnly,
175-
case .type(let typeArgument) = argument else {
175+
case .type(let typeArgument) = argument.argument else {
176176
newNode = nil
177177
break
178178
}

cross-pr-checkout.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import subprocess
2+
import pathlib
3+
import requests
4+
5+
class CrossRepoPR:
6+
org: str
7+
repo: str
8+
pr_num: str
9+
10+
def __init__(self, org: str, repo: str, pr_num: str) -> None:
11+
self.org = org
12+
self.repo = repo
13+
self.pr_num = pr_num
14+
15+
def cross_repo_prs() -> list[CrossRepoPR]:
16+
return [
17+
CrossRepoPR("swiftlang", "swift-syntax", "2859")
18+
]
19+
20+
def run(cmd: list[str], cwd: str|None = None):
21+
print(" ".join(cmd))
22+
subprocess.check_call(cmd, cwd=cwd)
23+
24+
def main():
25+
for cross_repo_pr in cross_repo_prs():
26+
run(["git", "clone", f"https://github.com/{cross_repo_pr.org}/{cross_repo_pr.repo}.git", f"{cross_repo_pr.repo}"], cwd="..")
27+
run(["git", "fetch", "origin", f"pull/{cross_repo_pr.pr_num}/merge:pr_merge"], cwd="../swift-syntax")
28+
run(["git", "checkout", "main"], cwd="../swift-syntax")
29+
run(["git", "reset", "--hard", "pr_merge"], cwd="../swift-syntax")
30+
run(["swift", "package", "config", "set-mirror", "--package-url", "https://github.com/swiftlang/swift-syntax.git", "--mirror-url", str(pathlib.Path("../swift-syntax").resolve())])
31+
32+
if __name__ == "__main__":
33+
main()

cross-pr-checkout.swift

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import Foundation
2+
3+
/// Provides convenience APIs for launching and gathering output from a subprocess
4+
public class ProcessRunner {
5+
private static let serialQueue = DispatchQueue(label: "\(ProcessRunner.self)")
6+
7+
let process: Process
8+
var launched = false
9+
10+
public init(
11+
launchPath: String,
12+
arguments: [String],
13+
environment: [String: String] = [:]
14+
) {
15+
process = Process()
16+
process.launchPath = launchPath
17+
process.arguments = arguments
18+
process.environment = environment.merging(ProcessInfo.processInfo.environment) { (current, _) in current }
19+
}
20+
21+
public func run(
22+
input: String? = nil,
23+
captureStdout: Bool = true,
24+
captureStderr: Bool = true
25+
) -> ProcessResult {
26+
let group = DispatchGroup()
27+
28+
let inPipe = Pipe()
29+
if input != nil {
30+
process.standardInput = inPipe
31+
}
32+
33+
var outData = Data()
34+
if captureStdout {
35+
let outPipe = Pipe()
36+
process.standardOutput = outPipe
37+
addHandler(pipe: outPipe, group: group) { outData.append($0) }
38+
}
39+
40+
var errData = Data()
41+
if captureStderr {
42+
let errPipe = Pipe()
43+
process.standardError = errPipe
44+
addHandler(pipe: errPipe, group: group) { errData.append($0) }
45+
}
46+
47+
ProcessRunner.serialQueue.sync {
48+
process.launch()
49+
launched = true
50+
}
51+
52+
if let input = input {
53+
guard let data = input.data(using: .utf8) else {
54+
return ProcessResult(
55+
status: 1,
56+
stdout: Data(),
57+
stderr: "Invalid input".data(using: .utf8)!
58+
)
59+
}
60+
inPipe.fileHandleForWriting.write(data)
61+
inPipe.fileHandleForWriting.closeFile()
62+
}
63+
64+
process.waitUntilExit()
65+
if captureStdout || captureStderr {
66+
// Make sure we've received all stdout/stderr
67+
group.wait()
68+
}
69+
70+
return ProcessResult(
71+
status: process.terminationStatus,
72+
stdout: outData,
73+
stderr: errData
74+
)
75+
}
76+
77+
public func terminate() {
78+
ProcessRunner.serialQueue.sync {
79+
if launched {
80+
process.terminate()
81+
}
82+
}
83+
}
84+
85+
private func addHandler(
86+
pipe: Pipe,
87+
group: DispatchGroup,
88+
addData: @escaping (Data) -> Void
89+
) {
90+
group.enter()
91+
pipe.fileHandleForReading.readabilityHandler = { fileHandle in
92+
// Apparently using availableData can cause various issues
93+
let newData = fileHandle.readData(ofLength: Int.max)
94+
if newData.count == 0 {
95+
pipe.fileHandleForReading.readabilityHandler = nil;
96+
group.leave()
97+
} else {
98+
addData(newData)
99+
}
100+
}
101+
}
102+
}
103+
104+
/// The exit code and output (if redirected) from a subprocess that has
105+
/// terminated
106+
public struct ProcessResult {
107+
public let status: Int32
108+
public let stdout: Data
109+
public let stderr: Data
110+
111+
public var stdoutStr: String? {
112+
return String(data: stdout, encoding: .utf8)
113+
}
114+
public var stderrStr: String? {
115+
return String(data: stderr, encoding: .utf8)
116+
}
117+
}
118+
119+
func run(_ executable: String, _ arguments: String..., workingDirectory: String? = nil) {
120+
let runner = ProcessRunner(
121+
launchPath: executable,
122+
arguments: arguments,
123+
environment: [:],
124+
workingDirectory: workingDirectory
125+
)
126+
runner.run()
127+
}
128+
129+
struct CrossRepoPR {
130+
let org: String
131+
let repo: String
132+
let prNum: String
133+
}
134+
135+
let crossRepoPrs = [
136+
CrossRepoPR(org: "swiftlang", repo: "swift-syntax", prNum: "2859")
137+
]
138+
139+
for crossRepoPr in crossRepoPrs {
140+
run(
141+
"git",
142+
"clone",
143+
"https://github.com/\(crossRepoPr.org)/\(crossRepoPrs.repo).git",
144+
"\(crossRepoPr.repo)",
145+
workingDirectory: ".."
146+
)
147+
run("git", "fetch", "origin", "pull/\(crossRepoPr.prNum)/merge:pr_merge", workingDirectory: "../swift-syntax")
148+
run("git", "checkout", "main", workingDirectory: "../swift-syntax")
149+
run("git", "reset", "--hard", "pr_merge", workingDirectory: "../swift-syntax")
150+
run(
151+
"swift",
152+
"package",
153+
"config",
154+
"set-mirror",
155+
"--package-url",
156+
"https://github.com/swiftlang/swift-syntax.git",
157+
"--mirror-url",
158+
URL(fileURLWithPath: "../swift-syntax").resolveSymlinksInPath().path
159+
)
160+
}

0 commit comments

Comments
 (0)