Skip to content

Commit ed74dc3

Browse files
authored
Extend reporting part to handle more than one action per repo (#229)
Part of #204. After this change, not all actions are validated yet. It's just the part that handles the validation results is prepared to handle more than one action.y(a)ml file.
1 parent 8241912 commit ed74dc3

File tree

9 files changed

+133
-101
lines changed

9 files changed

+133
-101
lines changed

src/main/kotlin/it/krzeminski/githubactionstyping/Logic.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import kotlin.io.path.exists
1515
*/
1616
fun validateTypings(repoRoot: Path = Path.of(".")): Pair<Boolean, String> {
1717
require(repoRoot.exists()) { "The given repo root leads to non-existent dir: $repoRoot" }
18-
val manifest = repoRoot.readYamlFile("action") ?:
18+
val (manifest, manifestPath) = repoRoot.readYamlFile("action") ?:
1919
return Pair(false, "No action manifest (action.yml or action.yaml) found!")
2020

21-
val typesManifest = repoRoot.readYamlFile("action-types") ?:
21+
val (typesManifest, _) = repoRoot.readYamlFile("action-types") ?:
2222
return Pair(false, "No types manifest (action-types.yml or action-types.yaml) found!")
2323

24-
return manifestsToReport(manifest, typesManifest)
24+
return manifestsToReport(repoRoot.relativize(manifestPath), manifest, typesManifest)
2525
}

src/main/kotlin/it/krzeminski/githubactionstyping/ManifestsToReport.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import it.krzeminski.githubactionstyping.reporting.toPlaintextReport
77
import it.krzeminski.githubactionstyping.validation.ItemValidationResult
88
import it.krzeminski.githubactionstyping.validation.buildInputOutputMismatchValidationResult
99
import it.krzeminski.githubactionstyping.validation.validate
10+
import java.nio.file.Path
1011

11-
fun manifestsToReport(manifest: String, typesManifest: String): Pair<Boolean, String> {
12+
fun manifestsToReport(manifestPath: Path, manifest: String, typesManifest: String): Pair<Boolean, String> {
1213
val parsedTypesManifest = if (typesManifest.isNotBlank()) {
1314
parseTypesManifest(typesManifest)
1415
} else {
@@ -24,6 +25,7 @@ fun manifestsToReport(manifest: String, typesManifest: String): Pair<Boolean, St
2425

2526
if (inputsInManifest != inputsInTypesManifest || outputsInManifest != outputsInTypesManifest) {
2627
val inputOutputMismatchValidationResult = buildInputOutputMismatchValidationResult(
28+
manifestPath = manifestPath,
2729
inputsInManifest = inputsInManifest,
2830
inputsInTypesManifest = inputsInTypesManifest,
2931
outputsInManifest = outputsInManifest,
@@ -48,7 +50,7 @@ fun manifestsToReport(manifest: String, typesManifest: String): Pair<Boolean, St
4850
printlnDebug("==============================================")
4951
printlnDebug()
5052

51-
val validationResult = parsedTypesManifest.validate()
53+
val validationResult = parsedTypesManifest.validate(manifestPath)
5254
val isValid = validationResult.overallResult is ItemValidationResult.Valid
5355
val report = validationResult.toPlaintextReport()
5456

src/main/kotlin/it/krzeminski/githubactionstyping/parsing/TypesManifestReading.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import java.nio.file.Path
44
import kotlin.io.path.exists
55
import kotlin.io.path.readText
66

7-
fun Path.readYamlFile(nameWithoutExtension: String): String? =
7+
fun Path.readYamlFile(nameWithoutExtension: String): Pair<String, Path>? =
88
listOf("yaml", "yml")
99
.map { "$nameWithoutExtension.$it" }
1010
.firstOrNull { this.resolve(it).exists() }
11-
?.let { this.resolve(it).readText() }
11+
?.let { this.resolve(it).let { Pair(it.readText(), it) } }

src/main/kotlin/it/krzeminski/githubactionstyping/reporting/PlaintextReport.kt

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
11
package it.krzeminski.githubactionstyping.reporting
22

3-
import it.krzeminski.githubactionstyping.validation.ActionValidationResult
43
import it.krzeminski.githubactionstyping.validation.ItemValidationResult
4+
import it.krzeminski.githubactionstyping.validation.RepoValidationResult
55

6-
fun ActionValidationResult.toPlaintextReport(): String = buildString {
7-
appendLine("Overall result: ")
8-
this@toPlaintextReport.overallResult.appendStatus(this)
9-
appendLine()
6+
fun RepoValidationResult.toPlaintextReport(): String = buildString {
7+
this@toPlaintextReport.pathToActionValidationResult.forEach { (path, resultForAction) ->
8+
appendLine("For action with manifest at '$path':")
9+
appendLine("Result:")
10+
resultForAction.overallResult.appendStatus(this)
11+
appendLine()
1012

11-
appendLine("Inputs:")
12-
this@toPlaintextReport.inputs.forEach { (key, value) ->
13-
appendLine("$key:")
14-
append(" ")
15-
value.appendStatus(this)
16-
}
17-
if (this@toPlaintextReport.inputs.isEmpty()) {
18-
appendLine("None.")
19-
}
20-
appendLine()
13+
appendLine("Inputs:")
14+
resultForAction.inputs.forEach { (key, value) ->
15+
appendLine("$key:")
16+
append(" ")
17+
value.appendStatus(this)
18+
}
19+
if (resultForAction.inputs.isEmpty()) {
20+
appendLine("None.")
21+
}
22+
appendLine()
2123

22-
appendLine("Outputs:")
23-
this@toPlaintextReport.outputs.forEach { (key, value) ->
24-
appendLine("$key:")
25-
append(" ")
26-
value.appendStatus(this)
27-
}
28-
if (this@toPlaintextReport.outputs.isEmpty()) {
29-
appendLine("None.")
24+
appendLine("Outputs:")
25+
resultForAction.outputs.forEach { (key, value) ->
26+
appendLine("$key:")
27+
append(" ")
28+
value.appendStatus(this)
29+
}
30+
if (resultForAction.outputs.isEmpty()) {
31+
appendLine("None.")
32+
}
33+
appendLine()
3034
}
31-
appendLine()
3235
}
3336

3437
private fun ItemValidationResult.appendStatus(

src/main/kotlin/it/krzeminski/githubactionstyping/validation/ManifestValidation.kt

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,54 +8,64 @@ import it.krzeminski.githubactionstyping.validation.types.validateFloat
88
import it.krzeminski.githubactionstyping.validation.types.validateInteger
99
import it.krzeminski.githubactionstyping.validation.types.validateList
1010
import it.krzeminski.githubactionstyping.validation.types.validateString
11+
import java.nio.file.Path
1112

12-
fun TypesManifest.validate(): ActionValidationResult {
13+
fun TypesManifest.validate(manifestPath: Path): RepoValidationResult {
1314
val inputValidationResults = this.inputs.mapValues { (_, value) -> value.validate() }
1415
val outputValidationResults = this.outputs.mapValues { (_, value) -> value.validate() }
1516
val isSomethingInvalid = (inputValidationResults.values + outputValidationResults.values)
1617
.any { it != ItemValidationResult.Valid }
1718

18-
return ActionValidationResult(
19+
return RepoValidationResult(
1920
overallResult = if (isSomethingInvalid) ItemValidationResult.Invalid("Some typing is invalid.") else ItemValidationResult.Valid,
20-
inputs = inputValidationResults,
21-
outputs = outputValidationResults,
21+
pathToActionValidationResult = mapOf(manifestPath to ActionValidationResult(
22+
overallResult = if (isSomethingInvalid) ItemValidationResult.Invalid("Some typing is invalid.") else ItemValidationResult.Valid,
23+
inputs = inputValidationResults,
24+
outputs = outputValidationResults,
25+
)
26+
)
2227
)
2328
}
2429

2530
fun buildInputOutputMismatchValidationResult(
31+
manifestPath: Path,
2632
inputsInManifest: Set<String>,
2733
inputsInTypesManifest: Set<String>,
2834
outputsInManifest: Set<String>,
2935
outputsInTypesManifest: Set<String>,
30-
): ActionValidationResult {
31-
return ActionValidationResult(
32-
overallResult = ItemValidationResult.Invalid(
33-
"Input/output mismatch detected. Please fix it first, then rerun to see other possible violations.",
34-
),
35-
inputs = (inputsInManifest + inputsInTypesManifest)
36-
.associateWith {
37-
if (it in inputsInManifest && it in inputsInTypesManifest) {
38-
ItemValidationResult.Valid
39-
} else {
40-
if (it !in inputsInManifest) {
41-
ItemValidationResult.Invalid("This input doesn't exist in the action manifest.")
36+
): RepoValidationResult {
37+
return RepoValidationResult(
38+
overallResult = ItemValidationResult.Invalid("There was input/output mismatch for one of the actions."),
39+
pathToActionValidationResult = mapOf(manifestPath to ActionValidationResult(
40+
overallResult = ItemValidationResult.Invalid(
41+
"Input/output mismatch detected. Please fix it first, then rerun to see other possible violations.",
42+
),
43+
inputs = (inputsInManifest + inputsInTypesManifest)
44+
.associateWith {
45+
if (it in inputsInManifest && it in inputsInTypesManifest) {
46+
ItemValidationResult.Valid
4247
} else {
43-
ItemValidationResult.Invalid("This input doesn't exist in the types manifest.")
48+
if (it !in inputsInManifest) {
49+
ItemValidationResult.Invalid("This input doesn't exist in the action manifest.")
50+
} else {
51+
ItemValidationResult.Invalid("This input doesn't exist in the types manifest.")
52+
}
4453
}
45-
}
46-
},
47-
outputs = (outputsInManifest + outputsInTypesManifest)
48-
.associateWith {
49-
if (it in outputsInManifest && it in outputsInTypesManifest) {
50-
ItemValidationResult.Valid
51-
} else {
52-
if (it !in outputsInManifest) {
53-
ItemValidationResult.Invalid("This output doesn't exist in the action manifest.")
54+
},
55+
outputs = (outputsInManifest + outputsInTypesManifest)
56+
.associateWith {
57+
if (it in outputsInManifest && it in outputsInTypesManifest) {
58+
ItemValidationResult.Valid
5459
} else {
55-
ItemValidationResult.Invalid("This output doesn't exist in the types manifest.")
60+
if (it !in outputsInManifest) {
61+
ItemValidationResult.Invalid("This output doesn't exist in the action manifest.")
62+
} else {
63+
ItemValidationResult.Invalid("This output doesn't exist in the types manifest.")
64+
}
5665
}
57-
}
58-
},
66+
},
67+
)
68+
)
5969
)
6070
}
6171

@@ -74,14 +84,3 @@ private fun ApiItem.validate(): ItemValidationResult {
7484
else -> ItemValidationResult.Invalid("Unknown type: '${this.type}'.")
7585
}
7686
}
77-
78-
data class ActionValidationResult(
79-
val overallResult: ItemValidationResult,
80-
val inputs: Map<String, ItemValidationResult> = emptyMap(),
81-
val outputs: Map<String, ItemValidationResult> = emptyMap(),
82-
)
83-
84-
sealed interface ItemValidationResult {
85-
object Valid : ItemValidationResult
86-
data class Invalid(val message: String) : ItemValidationResult
87-
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package it.krzeminski.githubactionstyping.validation
2+
3+
import java.nio.file.Path
4+
5+
data class RepoValidationResult(
6+
val overallResult: ItemValidationResult,
7+
val pathToActionValidationResult: Map<Path, ActionValidationResult>,
8+
)
9+
10+
data class ActionValidationResult(
11+
val overallResult: ItemValidationResult,
12+
val inputs: Map<String, ItemValidationResult> = emptyMap(),
13+
val outputs: Map<String, ItemValidationResult> = emptyMap(),
14+
)
15+
16+
sealed interface ItemValidationResult {
17+
data object Valid : ItemValidationResult
18+
data class Invalid(val message: String) : ItemValidationResult
19+
}

src/test/kotlin/it/krzeminski/githubactionstyping/LogicTest.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ class LogicTest : FunSpec({
2121
assertSoftly {
2222
isValid shouldBe true
2323
report shouldBe """
24-
Overall result:
24+
For action with manifest at 'action.yml':
25+
Result:
2526
${'\u001b'}[32m✔ VALID${'\u001b'}[0m
2627
2728
Inputs:
@@ -48,7 +49,8 @@ class LogicTest : FunSpec({
4849
assertSoftly {
4950
isValid shouldBe false
5051
report shouldBe """
51-
Overall result:
52+
For action with manifest at 'action.yml':
53+
Result:
5254
${'\u001b'}[31m❌ INVALID: Some typing is invalid.${'\u001b'}[0m
5355
5456
Inputs:

0 commit comments

Comments
 (0)