diff --git a/Sources/DependencyCalculator/DependencyCalculator.swift b/Sources/DependencyCalculator/DependencyCalculator.swift index 182752e..b1220cd 100644 --- a/Sources/DependencyCalculator/DependencyCalculator.swift +++ b/Sources/DependencyCalculator/DependencyCalculator.swift @@ -8,7 +8,8 @@ import SelectiveTestLogger import Workspace public extension WorkspaceInfo { - func affectedTargets(changedFiles: Set) -> Set { + func affectedTargets(changedFiles: Set, + incldueIndirectlyAffected: Bool = true) -> Set { var result = Set() for path in changedFiles { @@ -20,9 +21,13 @@ public extension WorkspaceInfo { Logger.message("Changed file at \(path) appears not to belong to any target") } } - - let indirectlyAffected = indirectlyAffectedTargets(targets: result) - return result.union(indirectlyAffected) + if incldueIndirectlyAffected { + let indirectlyAffected = indirectlyAffectedTargets(targets: result) + return result.union(indirectlyAffected) + } + else { + return result + } } internal func targetForFolder(_ path: Path) -> TargetIdentity? { diff --git a/Sources/SelectiveTestingCore/SelectiveTestingTool.swift b/Sources/SelectiveTestingCore/SelectiveTestingTool.swift index 45f2269..fe2eed3 100644 --- a/Sources/SelectiveTestingCore/SelectiveTestingTool.swift +++ b/Sources/SelectiveTestingCore/SelectiveTestingTool.swift @@ -16,6 +16,7 @@ public final class SelectiveTestingTool { private let basePath: Path private let printJSON: Bool private let renderDependencyGraph: Bool + private let turbo: Bool private let dot: Bool private let verbose: Bool private let testPlan: String? @@ -27,6 +28,7 @@ public final class SelectiveTestingTool { printJSON: Bool = false, renderDependencyGraph: Bool = false, dot: Bool = false, + turbo: Bool = false, verbose: Bool = false) throws { if let configData = try? (Path.current + Config.defaultConfigName).read(), @@ -46,6 +48,7 @@ public final class SelectiveTestingTool { self.basePath = Path(finalBasePath) self.printJSON = printJSON self.renderDependencyGraph = renderDependencyGraph + self.turbo = turbo self.dot = dot self.verbose = verbose self.testPlan = testPlan ?? config?.testPlan @@ -70,7 +73,8 @@ public final class SelectiveTestingTool { exclude: config?.exclude ?? []) // 3. Find affected targets - let affectedTargets = workspaceInfo.affectedTargets(changedFiles: changeset) + let affectedTargets = workspaceInfo.affectedTargets(changedFiles: changeset, + incldueIndirectlyAffected: !turbo) if renderDependencyGraph { try Shell.exec("open -a Safari \"\(workspaceInfo.dependencyStructure.mermaidInURL(highlightTargets: affectedTargets))\"") diff --git a/Sources/xcode-selective-test/SelectiveTesting.swift b/Sources/xcode-selective-test/SelectiveTesting.swift index 510e3fa..ee0fea0 100644 --- a/Sources/xcode-selective-test/SelectiveTesting.swift +++ b/Sources/xcode-selective-test/SelectiveTesting.swift @@ -28,6 +28,9 @@ struct SelectiveTesting: AsyncParsableCommand { @Flag(help: "Output dependency graph in Dot (Graphviz) format") var dot: Bool = false + @Flag(help: "Turbo mode: run directly affected tests only") + var turbo: Bool = false + @Flag(help: "Produce verbose output") var verbose: Bool = false @@ -38,6 +41,7 @@ struct SelectiveTesting: AsyncParsableCommand { printJSON: JSON, renderDependencyGraph: dependencyGraph, dot: dot, + turbo: turbo, verbose: verbose) let _ = try await tool.run() } diff --git a/Tests/SelectiveTestingTests/IntegrationTestTool.swift b/Tests/SelectiveTestingTests/IntegrationTestTool.swift index 0339a03..fac09aa 100644 --- a/Tests/SelectiveTestingTests/IntegrationTestTool.swift +++ b/Tests/SelectiveTestingTests/IntegrationTestTool.swift @@ -60,11 +60,11 @@ final class IntegrationTestTool { func createSUT(config: Config? = nil, basePath: Path? = nil, - testPlan: String? = nil) throws -> SelectiveTestingTool + testPlan: String? = nil, + turbo: Bool = false) throws -> SelectiveTestingTool { if let config { let configText = try config.save() - print("config: \(configText)") let path = Path.current + Config.defaultConfigName try configText.write(toFile: path.string, atomically: true, encoding: .utf8) } @@ -73,6 +73,7 @@ final class IntegrationTestTool { basePath: basePath?.string, testPlan: testPlan, renderDependencyGraph: false, + turbo: turbo, verbose: true) } diff --git a/Tests/SelectiveTestingTests/SelectiveTestingProjectTests.swift b/Tests/SelectiveTestingTests/SelectiveTestingProjectTests.swift index b7374e3..66905f7 100644 --- a/Tests/SelectiveTestingTests/SelectiveTestingProjectTests.swift +++ b/Tests/SelectiveTestingTests/SelectiveTestingProjectTests.swift @@ -41,6 +41,21 @@ final class SelectiveTestingProjectTests: XCTestCase { ])) } + func testProjectAlone_turbo() async throws { + // given + let tool = try testTool.createSUT(config: nil, + basePath: "ExampleProject.xcodeproj", + turbo: true) + // when + try testTool.changeFile(at: testTool.projectPath + "ExampleProject/Deep/Path/ContentView.swift") + + // then + let result = try await tool.run() + XCTAssertEqual(result, Set([ + testTool.mainProjectMainTarget + ])) + } + func testProjectDeepPathChange() async throws { // given let tool = try testTool.createSUT(config: nil,