Skip to content

Commit 97ab31a

Browse files
authored
Merge pull request #14 from getyourguide/improvements
Experimental UI Tests flag && improvements
2 parents b9e5202 + ac2f29f commit 97ab31a

File tree

4 files changed

+88
-19
lines changed

4 files changed

+88
-19
lines changed

.github/actions/tests/action.yml

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
name: 'spmgraph tests'
22
description: 'Map tests to run based on changed files of a given dependency graph'
33
inputs:
4-
package_directory:
4+
package-directory:
55
description: The directory where the Package.swift file is located
66
required: true
77
verbose:
88
description: Show extra logging for troubleshooting purposes.
99
type: boolean
1010
default: false
11-
excluded_suffixes:
11+
excluded-suffixes:
1212
description: Comma separated suffixes to exclude from the graph e.g. 'Tests','Live','TestSupport'
1313
required: false
1414
default: ''
15-
base_branch:
15+
base-branch:
1616
description: Base branch to compare the changes against
1717
required: false
1818
default: 'main'
19-
changed_files:
19+
changed-files:
2020
description: Optional list of changed files. Otherwise git versioning is used
2121
required: false
2222
default: ''
23-
output_format:
23+
output-format:
2424
description: "The output mode. Options are: textDump, textFile. The first dumps the list of test modules to run in a single line, while the latter Saves the list of test modules into an `output.txt` file in the `current dir`. Both follow the following the xcodebuild/fastlane scan expected format."
2525
required: false
2626
default: 'textDump'
27-
adds_to_summary:
27+
adds-to-summary:
2828
description: List the filtered tests in the action summary.
2929
type: boolean
3030
default: false
@@ -36,6 +36,10 @@ inputs:
3636
3737
- **Warning**: Ensure this is consistent across commands, otherwise your configuration won't be correctly loaded!
3838
required: false
39+
experimental-ui-test-targets:
40+
description: "Warning: This is an experimental flag, use it with caution! Enables support for including UITest targets on selecting testing. It looks for a `uiTestsDependencies.json` in the temporary directory, reads it, and checks if any of the UITest targets dependencies are affected, if so, it includes them in the list of test targets to run."
41+
type: boolean
42+
default: false
3943
outputs:
4044
test_targets:
4145
description: A comma separated list of test targets to run. It can be passed as is to xcodebuild or fastlane scan.
@@ -50,8 +54,8 @@ runs:
5054
- id: spmgraph_test
5155
name: Run spmgraph tests
5256
run: |
53-
# note: changed_files take precedence over baseBranch
54-
spmgraph tests ${{ inputs.package_directory }} ${{ inputs.verbose == 'true' && '-v' || '' }} --baseBranch ${{ github.base_ref || 'main' }} --output ${{ inputs.output_format }} ${{ inputs.excluded_suffixes && '--excludedSuffixes ${{ inputs.excluded_suffixes }}' || '' }} ${{ inputs.changed_files && '--changed_files ${{ inputs.changed_files }}' || '' }} ${{ inputs.config-build-directory && '--config-build-directory ${{ inputs.config-build-directory }}' || '' }}
57+
# note: changed-files takes precedence over baseBranch
58+
spmgraph tests ${{ inputs.package-directory }} ${{ inputs.verbose == 'true' && '-v' || '' }} --baseBranch ${{ github.base_ref || 'main' }} --output ${{ inputs.output-format }} ${{ inputs.excluded-suffixes && '--excludedSuffixes ${{ inputs.excluded-suffixes }}' || '' }} ${{ inputs.changed-files && '--changed-files ${{ inputs.changed-files }}' || '' }} ${{ inputs.config-build-directory && '--config-build-directory ${{ inputs.config-build-directory }}' || '' }} ${{ inputs.experimental-ui-test-targets == 'true' && '--experimentalUITest' || '' }}
5559
if [ ! -s "$GITHUB_WORKSPACE/output.txt" ]; then
5660
echo "tests_needed=false" >> $GITHUB_OUTPUT
5761
else
@@ -61,7 +65,7 @@ runs:
6165
shell: /bin/bash -e {0}
6266

6367
- name: Write to workflow job summary
64-
if: ${{ inputs.adds_to_summary == 'true' }}
68+
if: ${{ inputs.adds-to-summary == 'true' }}
6569
run: |
6670
tests_summary=$'# spmgraph tests\n## Tests to run\n'
6771
echo "$tests_summary" >> $GITHUB_STEP_SUMMARY

Package.resolved

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/SPMGraphExecutable/Subcommands/Tests.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ struct TestsArguments: ParsableArguments {
4141
)
4242
var outputMode: SPMGraphTests.OutputMode = .textDump
4343

44+
@Flag(
45+
name: [.customLong("experimentalUITest"), .long],
46+
help:
47+
"Warning: This is an experimental flag, use it with caution! Enables support for including UITest targets on selecting testing. It looks for a `uiTestsDependencies.json` in the temporary directory, reads it, and checks if any of the UITest targets dependencies are affected, if so, it includes them in the list of test targets to run."
48+
)
49+
var experimentalUITestTargets: Bool = false
50+
4451
@OptionGroup
4552
var config: SPMGraphConfigArguments
4653

@@ -69,6 +76,7 @@ struct Tests: AsyncParsableCommand {
6976
changedFiles: arguments.changedFiles,
7077
baseBranch: arguments.baseBranch,
7178
outputMode: arguments.outputMode,
79+
experimentalUITestTargets: arguments.experimentalUITestTargets,
7280
verbose: arguments.common.verbose
7381
)
7482
)

Sources/SPMGraphTests/SPMGraphTests.swift

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ public struct SPMGraphTestsInput {
3737
let baseBranch: String
3838
/// The output mode
3939
let outputMode: SPMGraphTests.OutputMode // TODO: Check if it make sense in the SPMGraphConfig fle
40+
/// Enables support for including UITest targets on selecting testing. It looks for a `uiTestsDependencies.json` in the temporary directory,
41+
/// reads it, and checks if any of the UITest targets dependencies are affected, if so, it includes them in the list of test targets to run.
42+
///
43+
/// - warning: This is an experimental flag, use it with caution!
44+
let experimentalUITestTargets: Bool
4045
/// Show extra logging for troubleshooting purposes
4146
let verbose: Bool
4247

@@ -48,6 +53,7 @@ public struct SPMGraphTestsInput {
4853
changedFiles: [String],
4954
baseBranch: String,
5055
outputMode: SPMGraphTests.OutputMode,
56+
experimentalUITestTargets: Bool,
5157
verbose: Bool
5258
) throws {
5359
self.spmPackageDirectory = try AbsolutePath.packagePath(spmPackageDirectory)
@@ -56,6 +62,7 @@ public struct SPMGraphTestsInput {
5662
self.changedFiles = changedFiles
5763
self.baseBranch = baseBranch
5864
self.outputMode = outputMode
65+
self.experimentalUITestTargets = experimentalUITestTargets
5966
self.verbose = verbose
6067
}
6168
}
@@ -184,25 +191,76 @@ public final class SPMGraphTests: SSPMGraphTestsProtocol {
184191

185192
// map tests modules that should run
186193
let testModulesToRun = mapTestmodules(for: affectedModules, package: package)
194+
var inlineTestModulesNames = testModulesToRun.map(\.name).joined(separator: ",")
195+
196+
if input.experimentalUITestTargets {
197+
let uiTestsDependenciesFilePath = try localFileSystem.tempDirectory
198+
.appending(component: "uiTestsDependencies")
199+
.appending(extension: "json")
200+
201+
if input.verbose {
202+
try system.echo("Looking for the UI tests dependencies file at: \(uiTestsDependenciesFilePath)")
203+
}
204+
205+
if localFileSystem.exists(uiTestsDependenciesFilePath) {
206+
if input.verbose {
207+
try system.echo("Found the UI tests dependencies file at: \(uiTestsDependenciesFilePath)")
208+
}
209+
210+
try localFileSystem.readFileContents(uiTestsDependenciesFilePath)
211+
.withData { data in
212+
let uiTestModules = try JSONDecoder().decode(UITestsModulesMap.self, from: data)
213+
214+
let uiTestModulesToRun = uiTestModules.modules
215+
.filter { target in
216+
let allAffectedModules = (affectedModules + testModulesToRun).map(\.name)
217+
return allAffectedModules.contains { moduleName in
218+
target.dependencies.contains(moduleName)
219+
}
220+
}
221+
.map(\.name)
222+
223+
if !uiTestModulesToRun.isEmpty {
224+
inlineTestModulesNames.append(",")
225+
inlineTestModulesNames.append(uiTestModulesToRun.joined(separator: ","))
226+
}
227+
}
228+
}
229+
}
187230

188-
if testModulesToRun.isEmpty {
231+
if inlineTestModulesNames.isEmpty {
189232
try system.echo(
190233
"No test modules to run"
191234
)
192235
} else {
236+
let lineByLineModulesToRun = inlineTestModulesNames.replacingOccurrences(of: ",", with: "\n")
193237
try system.echo(
194-
"The test modules to run are: \(testModulesToRun.map(\.name).joined(separator: "\n"))"
238+
"The test modules to run are: \(lineByLineModulesToRun)"
195239
)
196240
}
197241

198-
try generateOutput(testModulesToRun: testModulesToRun, outputMode: input.outputMode)
242+
try generateOutput(inlineTestModulesToRun: inlineTestModulesNames, outputMode: input.outputMode)
199243

200244
return testModulesToRun
201245
}
202246
}
203247

204248
// MARK: - Private
205249

250+
private struct UITestsModulesMap: Decodable {
251+
struct Module: Decodable {
252+
let name: String
253+
let dependencies: [String]
254+
255+
private enum Keys: String, CodingKey {
256+
case name = "targetName"
257+
case dependencies
258+
}
259+
}
260+
261+
let modules: [Module]
262+
}
263+
206264
private extension SPMGraphTests {
207265
/// Maps and returns the modules that were affected by a set of changed files
208266
///
@@ -288,20 +346,18 @@ private extension SPMGraphTests {
288346

289347
/// A function that generates the output with tests to run
290348
/// - Parameters:
291-
/// - testModulesToRun: All modules which tests need to run
349+
/// - inlineTestModulesToRun: The name of all modules which tests need to run
292350
/// - outputMode: Specifies the output mode
293-
func generateOutput(testModulesToRun: [Module], outputMode: OutputMode) throws {
294-
let inlineModuleNames = testModulesToRun.map(\.name).joined(separator: ",")
295-
351+
func generateOutput(inlineTestModulesToRun: String, outputMode: OutputMode) throws {
296352
switch outputMode {
297353
case .textDump:
298-
try system.echo(inlineModuleNames)
354+
try system.echo(inlineTestModulesToRun)
299355
case .textFile:
300356
let url = AbsolutePath.currentDir.asURL
301357
var fileURL = url.appendingPathComponent("output")
302358
fileURL = fileURL.appendingPathExtension("txt")
303359
do {
304-
try inlineModuleNames.write(to: fileURL, atomically: true, encoding: .utf8)
360+
try inlineTestModulesToRun.write(to: fileURL, atomically: true, encoding: .utf8)
305361
try system.echo(
306362
"✅ Successfully saved the formatted list of test modules to \(fileURL)"
307363
)

0 commit comments

Comments
 (0)