Skip to content

Commit 23f435f

Browse files
authored
[APIDiff] Support forwarding breakage allowlists to the api digester (#3547)
* [APIDiff] Support forwarding breakage allowlists to the api digester
1 parent 426e296 commit 23f435f

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

Sources/Commands/APIDigester.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,18 @@ public struct SwiftAPIDigester {
199199
public func compareAPIToBaseline(
200200
at baselinePath: AbsolutePath,
201201
for module: String,
202-
buildPlan: BuildPlan
202+
buildPlan: BuildPlan,
203+
except breakageAllowlistPath: AbsolutePath?
203204
) -> ComparisonResult? {
204205
var args = [
205206
"-diagnose-sdk",
206207
"-baseline-path", baselinePath.pathString,
207208
"-module", module
208209
]
209210
args.append(contentsOf: buildPlan.createAPIToolCommonArgs(includeLibrarySearchPaths: false))
211+
if let breakageAllowlistPath = breakageAllowlistPath {
212+
args.append(contentsOf: ["-breakage-allowlist-path", breakageAllowlistPath.pathString])
213+
}
210214

211215
return try? withTemporaryFile(deleteOnClose: false) { file in
212216
args.append(contentsOf: ["-serialize-diagnostics-path", file.path.pathString])

Sources/Commands/SwiftPackageTool.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,13 @@ extension SwiftPackageTool {
305305
@OptionGroup(_hiddenFromHelp: true)
306306
var swiftOptions: SwiftToolOptions
307307

308+
@Option(help: """
309+
The path to a text file containing breaking changes which should be ignored by the API comparison. \
310+
Each ignored breaking change in the file should appear on its own line and contain the exact message \
311+
to be ignored (e.g. 'API breakage: func foo() has been removed').
312+
""")
313+
var breakageAllowlistPath: AbsolutePath?
314+
308315
@Argument(help: "The baseline treeish to compare to (e.g. a commit hash, branch name, tag, etc.)")
309316
var treeish: String
310317

@@ -360,7 +367,8 @@ extension SwiftPackageTool {
360367
if let comparisonResult = apiDigesterTool.compareAPIToBaseline(
361368
at: moduleBaselinePath,
362369
for: module,
363-
buildPlan: buildOp.buildPlan!
370+
buildPlan: buildOp.buildPlan!,
371+
except: breakageAllowlistPath
364372
) {
365373
results.append(comparisonResult)
366374
}

Tests/CommandsTests/APIDiffTests.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,43 @@ final class APIDiffTests: XCTestCase {
8282
#endif
8383
}
8484

85+
func testBreakageAllowlist() throws {
86+
#if os(macOS)
87+
guard (try? Resources.default.toolchain.getSwiftAPIDigester()) != nil else {
88+
throw XCTSkip("swift-api-digester not available")
89+
}
90+
fixture(name: "Miscellaneous/APIDiff/") { prefix in
91+
let packageRoot = prefix.appending(component: "Bar")
92+
try localFileSystem.writeFileContents(packageRoot.appending(components: "Sources", "Baz", "Baz.swift")) {
93+
$0 <<< "public func baz() -> String { \"hello, world!\" }"
94+
}
95+
try localFileSystem.writeFileContents(packageRoot.appending(components: "Sources", "Qux", "Qux.swift")) {
96+
$0 <<< "public class Qux<T, U> { private let x = 1 }"
97+
}
98+
let customAllowlistPath = packageRoot.appending(components: "foo", "allowlist.txt")
99+
try localFileSystem.writeFileContents(customAllowlistPath) {
100+
$0 <<< "API breakage: class Qux has generic signature change from <T> to <T, U>\n"
101+
}
102+
XCTAssertThrowsError(try execute(["experimental-api-diff", "1.2.3", "-j", "2",
103+
"--breakage-allowlist-path", customAllowlistPath.pathString],
104+
packagePath: packageRoot)) { error in
105+
guard case SwiftPMProductError.executionFailure(error: _, output: let output, stderr: _) = error else {
106+
XCTFail("Unexpected error")
107+
return
108+
}
109+
XCTAssertTrue(output.contains("1 breaking change detected in Qux"))
110+
XCTAssertFalse(output.contains("💔 API breakage: class Qux has generic signature change from <T> to <T, U>"))
111+
XCTAssertTrue(output.contains("💔 API breakage: var Qux.x has been removed"))
112+
XCTAssertTrue(output.contains("1 breaking change detected in Baz"))
113+
XCTAssertTrue(output.contains("💔 API breakage: func bar() has been removed"))
114+
}
115+
116+
}
117+
#else
118+
throw XCTSkip("Test unsupported on current platform")
119+
#endif
120+
}
121+
85122
func testCheckVendedModulesOnly() throws {
86123
#if os(macOS)
87124
guard (try? Resources.default.toolchain.getSwiftAPIDigester()) != nil else {

0 commit comments

Comments
 (0)