Skip to content

Commit ff4fdec

Browse files
committed
[] Apply changes from bitrise-step-select-tests/XcodeSelectiveTesting
1 parent 523bf10 commit ff4fdec

34 files changed

Lines changed: 758 additions & 1469 deletions

Package.resolved

Lines changed: 14 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version: 6.0
1+
// swift-tools-version: 5.6
22

33
import PackageDescription
44

@@ -11,65 +11,41 @@ let products: [PackageDescription.Product] = [
1111
name: "XcodeSelectiveTest",
1212
targets: ["SelectiveTestingPlugin"]
1313
),
14-
.library(
15-
name: "XcodeSelectiveTestCore",
16-
targets: ["SelectiveTestingCore"]
17-
)
1814
]
1915

20-
let flags: [PackageDescription.SwiftSetting] = [.enableExperimentalFeature("StrictConcurrency")]
21-
2216
let targets: [PackageDescription.Target] = [
2317
.executableTarget(
2418
name: "xcode-selective-test",
2519
dependencies: ["SelectiveTestingCore",
26-
.product(name: "ArgumentParser", package: "swift-argument-parser")],
27-
swiftSettings: flags
20+
.product(name: "ArgumentParser", package: "swift-argument-parser")]
2821
),
2922
.target(name: "SelectiveTestingCore",
3023
dependencies: ["DependencyCalculator",
3124
"TestConfigurator",
3225
"Git",
3326
"PathKit",
34-
"Yams",
35-
.product(name: "ArgumentParser", package: "swift-argument-parser")],
36-
swiftSettings: flags
37-
),
27+
"Rainbow",
28+
"Yams"]),
3829
.target(name: "DependencyCalculator",
39-
dependencies: ["Workspace", "PathKit", "Git", .product(name: "Logging", package: "swift-log")],
40-
swiftSettings: flags
41-
),
30+
dependencies: ["Workspace", "PathKit", "SelectiveTestLogger", "Git"]),
4231
.target(name: "TestConfigurator",
43-
dependencies: [
44-
"Workspace",
45-
"PathKit",
46-
.product(name: "Logging", package: "swift-log"),
47-
.product(name: "ArgumentParser", package: "swift-argument-parser")
48-
],
49-
swiftSettings: flags
50-
),
32+
dependencies: ["Workspace", "PathKit", "SelectiveTestLogger"]),
5133
.target(name: "Workspace",
52-
dependencies: ["XcodeProj", .product(name: "Logging", package: "swift-log")],
53-
swiftSettings: flags
54-
),
34+
dependencies: ["XcodeProj", "SelectiveTestLogger"]),
5535
.target(name: "Git",
56-
dependencies: ["SelectiveTestShell", "PathKit", .product(name: "Logging", package: "swift-log")],
57-
swiftSettings: flags
58-
),
59-
.target(name: "SelectiveTestShell",
60-
swiftSettings: flags
61-
),
36+
dependencies: ["SelectiveTestShell", "SelectiveTestLogger", "PathKit"]),
37+
.target(name: "SelectiveTestLogger",
38+
dependencies: ["Rainbow"]),
39+
.target(name: "SelectiveTestShell"),
6240
.testTarget(
6341
name: "SelectiveTestingTests",
64-
dependencies: ["xcode-selective-test", "PathKit", "Workspace"],
65-
resources: [.copy("ExampleProject")],
66-
swiftSettings: flags
42+
dependencies: ["xcode-selective-test", "PathKit"],
43+
resources: [.copy("ExampleProject")]
6744
),
6845
.testTarget(
6946
name: "DependencyCalculatorTests",
7047
dependencies: ["DependencyCalculator", "Workspace", "PathKit", "SelectiveTestingCore"],
71-
resources: [.copy("ExamplePackages")],
72-
swiftSettings: flags
48+
resources: [.copy("ExamplePackages")]
7349
),
7450
.plugin(
7551
name: "SelectiveTestingPlugin",
@@ -83,7 +59,7 @@ let targets: [PackageDescription.Target] = [
8359
]
8460
),
8561
dependencies: ["xcode-selective-test"]
86-
)
62+
),
8763
]
8864

8965
let package = Package(
@@ -93,11 +69,11 @@ let package = Package(
9369
],
9470
products: products,
9571
dependencies: [
96-
.package(url: "https://github.com/tuist/XcodeProj.git", .upToNextMajor(from: "9.0.2")),
72+
.package(url: "https://github.com/tuist/XcodeProj.git", .upToNextMajor(from: "8.24.1")),
9773
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMajor(from: "1.2.0")),
9874
.package(url: "https://github.com/kylef/PathKit.git", .upToNextMinor(from: "1.0.0")),
75+
.package(url: "https://github.com/onevcat/Rainbow", .upToNextMajor(from: "4.0.0")),
9976
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.5"),
100-
.package(url: "https://github.com/apple/swift-log", from: "1.6.0")
10177
],
10278
targets: targets
10379
)

Plugins/SelectiveTestingPlugin/SelectiveTestingPlugin.swift

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import PackagePlugin
77

88
@main
99
struct SelectiveTestingPlugin: CommandPlugin {
10-
private func run(_ executable: URL, arguments: [String] = []) throws {
10+
private func run(_ executable: String, arguments: [String] = []) throws {
11+
let executableURL = URL(fileURLWithPath: executable)
1112

1213
let process = Process()
13-
process.executableURL = executable
14+
process.executableURL = executableURL
1415
process.arguments = arguments
1516

1617
try process.run()
@@ -23,10 +24,10 @@ struct SelectiveTestingPlugin: CommandPlugin {
2324
}
2425

2526
func performCommand(context: PluginContext, arguments: [String]) async throws {
26-
FileManager.default.changeCurrentDirectoryPath(context.package.directoryURL.path)
27+
FileManager().changeCurrentDirectoryPath(context.package.directory.string)
2728
let tool = try context.tool(named: "xcode-selective-test")
2829

29-
try run(tool.url, arguments: arguments)
30+
try run(tool.path.string, arguments: arguments)
3031
}
3132
}
3233

@@ -35,7 +36,7 @@ struct SelectiveTestingPlugin: CommandPlugin {
3536

3637
extension SelectiveTestingPlugin: XcodeCommandPlugin {
3738
func performCommand(context: XcodePluginContext, arguments: [String]) throws {
38-
FileManager.default.changeCurrentDirectoryPath(context.xcodeProject.directoryURL.path)
39+
FileManager().changeCurrentDirectoryPath(context.xcodeProject.directory.string)
3940

4041
let tool = try context.tool(named: "xcode-selective-test")
4142

@@ -47,29 +48,16 @@ struct SelectiveTestingPlugin: CommandPlugin {
4748
toolArguments.remove(at: indexOfTarget)
4849
}
4950

50-
if !toolArguments.contains(where: { $0 == "--test-plan" }) {
51-
let allFiles = context.xcodeProject.targets.reduce([]) { partialResult, target in
52-
partialResult + target.inputFiles
53-
}
54-
55-
let testPlans = allFiles.filter {
56-
$0.url.pathExtension == "xctestplan"
57-
}
58-
59-
if !testPlans.isEmpty {
60-
if testPlans.count == 1 {
61-
print("Using \(testPlans[0].url.path()) test plan")
62-
} else {
63-
print("Using \(testPlans.count) test plans")
64-
}
65-
66-
for testPlan in testPlans {
67-
toolArguments.append(contentsOf: ["--test-plan", testPlan.url.path()])
68-
}
69-
}
51+
if !toolArguments.contains(where: { $0 == "--test-plan" }),
52+
let testPlan = context.xcodeProject.filePaths.first(where: {
53+
$0.extension == "xctestplan"
54+
})
55+
{
56+
print("Using \(testPlan.string) test plan")
57+
toolArguments.append(contentsOf: ["--test-plan", testPlan.string])
7058
}
7159

72-
try run(tool.url, arguments: toolArguments)
60+
try run(tool.path.string, arguments: toolArguments)
7361
}
7462
}
7563
#endif

README.md

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Run only tests relevant to the changeset.
44

5-
[Watch my talk from Swift Connection 2025](https://www.youtube.com/watch?v=U1fJQRbq-TY)
5+
[Watch Video](https://www.youtube.com/watch?v=0JOX1czraGA)
66

77
[![Swift](https://github.com/mikeger/SelectiveTesting/actions/workflows/test.yml/badge.svg)](https://github.com/mikeger/SelectiveTesting/actions/workflows/test.yml)
88

@@ -48,15 +48,15 @@ Alternatively, you can use a prebuilt binary release of the tool distributed und
4848

4949
### Using Swift Package Manager
5050

51-
Add `.package(url: "git@github.com:mikeger/XcodeSelectiveTesting", .upToNextMajor(from: "0.14.2"))` to your `Package.swift`'s `dependencies` section.
51+
Add `.package(url: "git@github.com:mikeger/XcodeSelectiveTesting", .upToNextMajor(from: "0.11.3"))` to your `Package.swift`'s `dependencies` section.
5252

5353
Use SPM to run the command: `swift run xcode-selective-test`.
5454

5555
Alternatively, you can use a prebuilt binary release of the tool distributed under [releases](https://github.com/mikeger/XcodeSelectiveTesting/releases) section.
5656

5757
### Using [Mint](https://github.com/yonaskolb/Mint)
5858

59-
`mint install mikeger/XcodeSelectiveTesting@0.14.2`
59+
`mint install mikeger/XcodeSelectiveTesting@0.11.3`
6060

6161
### Manually
6262

@@ -83,15 +83,8 @@ NB: This command assumes you have [jq](https://jqlang.github.io/jq/) tool instal
8383

8484
Alternatively, you can use CLI to achieve the same result:
8585

86-
1. Run `mint run mikeger/XcodeSelectiveTesting@0.14.2 YourWorkspace.xcworkspace --test-plan YourTestPlan.xctestplan`
87-
2. Run tests normally, XcodeSelectiveTesting would modify your test plan according to the local changes
88-
89-
To process multiple test plans, specify the `--test-plan` option multiple times:
90-
```bash
91-
mint run mikeger/XcodeSelectiveTesting@0.14.2 YourWorkspace.xcworkspace \
92-
--test-plan TestPlan1.xctestplan \
93-
--test-plan TestPlan2.xctestplan
94-
```
86+
1. Run `mint run mikeger/XcodeSelectiveTesting@0.11.3 YourWorkspace.xcworkspace --test-plan YourTestPlan.xctestplan`
87+
2. Run tests normally, XcodeSelectiveTesting would modify your test plan according to the local changes
9588

9689
### Use case: Xcode-based project, execute tests on the CI, no test plan
9790

@@ -103,17 +96,9 @@ mint run mikeger/XcodeSelectiveTesting@0.14.2 YourWorkspace.xcworkspace \
10396
### Use case: Xcode-based project, execute tests on the CI, with test plan
10497

10598
1. Add code to install the tool
106-
2. Add a CI step before you execute your tests: `mint run mikeger/XcodeSelectiveTesting@0.14.2 YourWorkspace.xcworkspace --test-plan YourTestPlan.xctestplan --base-branch $PR_BASE_BRANCH`
99+
2. Add a CI step before you execute your tests: `mint run mikeger/XcodeSelectiveTesting@0.11.3 YourWorkspace.xcworkspace --test-plan YourTestPlan.xctestplan --base-branch $PR_BASE_BRANCH`
107100
3. Execute your tests
108101

109-
To process multiple test plans on CI:
110-
```bash
111-
mint run mikeger/XcodeSelectiveTesting@0.14.2 YourWorkspace.xcworkspace \
112-
--test-plan TestPlan1.xctestplan \
113-
--test-plan TestPlan2.xctestplan \
114-
--base-branch $PR_BASE_BRANCH
115-
```
116-
117102
### Use case: GitHub Actions, other cases when the git repo is not in the shape to provide the changeset out of the box
118103

119104
1. Add code to install the tool
@@ -129,7 +114,7 @@ Git allows us to find what files were touched in the changeset.
129114
```bash
130115
Root
131116
├── Dependencies
132-
── Login
117+
── Login
133118
│ ├── ❗️LoginAssembly.swift
134119
│ └── ...
135120
├── MyProject.xcodeproj
@@ -160,7 +145,7 @@ This is the hardest part: dealing with obscure Xcode formats. But if we get that
160145

161146
- `--help`: Display all command line options
162147
- `--base-branch`: Branch to compare against to find the relevant changes. If emitted, a local changeset is used (development mode).
163-
- `--test-plan`: Path to the test plan. If not given, tool would try to infer the path. Can be specified multiple times to process multiple test plans.
148+
- `--test-plan`: Path to the test plan. If not given, tool would try to infer the path.
164149
- `--json`: Provide output in JSON format (STDOUT).
165150
- `--dependency-graph`: Opens Safari with a dependency graph visualization. Attention: if you don't trust Javascript ecosystem prefer using `--dot` option. More info [here](https://github.com/mikeger/XcodeSelectiveTesting/wiki/How-to-visualize-your-dependency-structure).
166151
- `--dot`: Output dependency graph in Dot (Graphviz) format. To be used with Graphviz: `brew install graphviz`, then `xcode-selective-test --dot | dot -Tsvg > output.svg && open output.svg`
@@ -175,8 +160,7 @@ It is possible to define the configuration in a separate file. The tool would lo
175160
Options available are (see `selective-testing-config-example.yml` for an example):
176161

177162
- `basePath`: Relative or absolute path to the project. If set, the command line option can be emitted.
178-
- `testPlan`: Relative or absolute path to the test plan to configure. For backwards compatibility.
179-
- `testPlans`: Array of relative or absolute paths to test plans to configure. Use this to process multiple test plans.
163+
- `testPlan`: Relative or absolute path to the test plan to configure.
180164
- `exclude`: List of relative paths to exclude when looking for Swift packages.
181165
- `extra/dependencies`: Options allowing to hint tool about dependencies between targets or packages.
182166
- `extra/targetsFiles`: Options allowing to hint tool about the files affecting targets or packages.
@@ -208,6 +192,5 @@ See LICENSE
208192
- [Bruno Guidolim](https://github.com/bguidolim)
209193
- [Alex Deem](https://github.com/alexdeem)
210194
- [Steffen Matthischke](https://github.com/HeEAaD)
211-
- [Econa77](https://github.com/Econa77)
212195

213196
If you like this product, consider donating to my hometown's charity project [Monsters Corporation](https://monstrov.org) 🤝

Sources/DependencyCalculator/ConcurrentMap.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import Foundation
66

7-
final class ThreadSafe<A: Sendable>: @unchecked Sendable {
7+
final class ThreadSafe<A> {
88
private var _value: A
99
private let queue = DispatchQueue(label: "ThreadSafe")
1010
init(_ value: A) {
@@ -22,8 +22,8 @@ final class ThreadSafe<A: Sendable>: @unchecked Sendable {
2222
}
2323
}
2424

25-
extension Array where Element: Sendable {
26-
func concurrentMap<B: Sendable>(_ transform: @escaping @Sendable (Element) -> B) -> [B] {
25+
extension Array {
26+
func concurrentMap<B>(_ transform: @escaping (Element) -> B) -> [B] {
2727
let result = ThreadSafe([B?](repeating: nil, count: count))
2828
DispatchQueue.concurrentPerform(iterations: count) { idx in
2929
let element = self[idx]

Sources/DependencyCalculator/DependencyCalculator.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import Foundation
66
import PathKit
7-
import Logging
7+
import SelectiveTestLogger
88
import Workspace
99

1010
public extension WorkspaceInfo {
@@ -18,7 +18,7 @@ public extension WorkspaceInfo {
1818
} else if let targetFromFolder = targetForFolder(path) {
1919
result.insert(targetFromFolder)
2020
} else {
21-
logger.info("Changed file at \(path) appears not to belong to any target")
21+
Logger.message("Changed file at \(path) appears not to belong to any target")
2222
}
2323
}
2424
if incldueIndirectlyAffected {
@@ -32,7 +32,7 @@ public extension WorkspaceInfo {
3232

3333
internal func targetForFolder(_ path: Path) -> TargetIdentity? {
3434
return folders.first { folder, _ in
35-
path.string.contains(folder.string + "/")
35+
path.string.hasPrefix(folder.string)
3636
}?.value
3737
}
3838

0 commit comments

Comments
 (0)