Skip to content

Commit 79aa99e

Browse files
committed
feat(server): make it possible to POST custom typings for testing during typing creation
1 parent 8b04bdb commit 79aa99e

File tree

10 files changed

+231
-27
lines changed

10 files changed

+231
-27
lines changed

action-binding-generator/api/action-binding-generator.api

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
public final class io/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords {
2-
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
2+
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
3+
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
34
public final fun component1 ()Ljava/lang/String;
45
public final fun component2 ()Ljava/lang/String;
56
public final fun component3 ()Ljava/lang/String;
6-
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;
7-
public static synthetic fun copy$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;
7+
public final fun component4 ()Ljava/lang/String;
8+
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;
9+
public static synthetic fun copy$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;
810
public fun equals (Ljava/lang/Object;)Z
911
public final fun getName ()Ljava/lang/String;
1012
public final fun getOwner ()Ljava/lang/String;
13+
public final fun getTypesUuid ()Ljava/lang/String;
1114
public final fun getVersion ()Ljava/lang/String;
1215
public fun hashCode ()I
1316
public fun toString ()Ljava/lang/String;
@@ -43,6 +46,7 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/dom
4346

4447
public final class io/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource : java/lang/Enum {
4548
public static final field ACTION Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource;
49+
public static final field CUSTOM Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource;
4650
public static final field TYPING_CATALOG Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource;
4751
public static fun getEntries ()Lkotlin/enums/EnumEntries;
4852
public static fun valueOf (Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource;
@@ -69,8 +73,8 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/gen
6973
}
7074

7175
public final class io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerationKt {
72-
public static final fun generateBinding (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;)Ljava/util/List;
73-
public static synthetic fun generateBinding$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;ILjava/lang/Object;)Ljava/util/List;
76+
public static final fun generateBinding (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;Ljava/lang/String;)Ljava/util/List;
77+
public static synthetic fun generateBinding$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;Ljava/lang/String;ILjava/lang/Object;)Ljava/util/List;
7478
}
7579

7680
public final class io/github/typesafegithub/workflows/actionbindinggenerator/metadata/Input {

action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ public data class ActionCoords(
44
val owner: String,
55
val name: String,
66
val version: String,
7+
val typesUuid: String? = null,
78
)
89

910
/**
@@ -12,7 +13,7 @@ public data class ActionCoords(
1213
*/
1314
public val ActionCoords.isTopLevel: Boolean get() = "/" !in name
1415

15-
public val ActionCoords.prettyPrint: String get() = "$owner/$name@$version"
16+
public val ActionCoords.prettyPrint: String get() = "$owner/$name@$version${typesUuid?.let { " (types: $it)" } ?: ""}"
1617

1718
/**
1819
* For most actions, it's the same as [ActionCoords.name].

action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ package io.github.typesafegithub.workflows.actionbindinggenerator.domain
33
public enum class TypingActualSource {
44
ACTION,
55
TYPING_CATALOG,
6+
CUSTOM,
67
}

action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/Generation.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ public fun ActionCoords.generateBinding(
5757
metadataRevision: MetadataRevision,
5858
metadata: Metadata? = null,
5959
inputTypings: Pair<Map<String, Typing>, TypingActualSource?>? = null,
60+
types: String? = null,
6061
): List<ActionBinding> {
6162
val metadataResolved = metadata ?: this.fetchMetadata(metadataRevision) ?: return emptyList()
6263
val metadataProcessed = metadataResolved.removeDeprecatedInputsIfNameClash()
6364

64-
val inputTypingsResolved = inputTypings ?: this.provideTypes(metadataRevision)
65+
val (inputTypingsResolved, typingActualSource) =
66+
inputTypings ?: this.provideTypes(metadataRevision, types = types)
6567

6668
val packageName = owner.toKotlinPackageName()
6769
val className = this.buildActionClassName()
@@ -74,7 +76,7 @@ public fun ActionCoords.generateBinding(
7476
emptyMap(),
7577
classNameUntyped,
7678
untypedClass = true,
77-
replaceWith = inputTypingsResolved.second?.let { CodeBlock.of("ReplaceWith(%S)", className) },
79+
replaceWith = typingActualSource?.let { CodeBlock.of("ReplaceWith(%S)", className) },
7880
)
7981

8082
return listOfNotNull(
@@ -85,12 +87,12 @@ public fun ActionCoords.generateBinding(
8587
packageName = packageName,
8688
typingActualSource = null,
8789
),
88-
inputTypingsResolved.second?.let {
90+
typingActualSource?.let {
8991
val actionBindingSourceCode =
9092
generateActionBindingSourceCode(
9193
metadata = metadataProcessed,
9294
coords = this,
93-
inputTypings = inputTypingsResolved.first,
95+
inputTypings = inputTypingsResolved,
9496
className = className,
9597
)
9698
ActionBinding(

action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/typing/TypesProviding.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.domain.Metadata
77
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.NewestForVersion
88
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource
99
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource.ACTION
10+
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource.CUSTOM
1011
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource.TYPING_CATALOG
1112
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.repoName
1213
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.subName
@@ -20,10 +21,12 @@ import java.net.URI
2021
internal fun ActionCoords.provideTypes(
2122
metadataRevision: MetadataRevision,
2223
fetchUri: (URI) -> String = ::fetchUri,
24+
types: String? = null,
2325
): Pair<Map<String, Typing>, TypingActualSource?> =
2426
(
25-
this.fetchTypingMetadata(metadataRevision, fetchUri)
26-
?: this.toMajorVersion().fetchFromTypingsFromCatalog(fetchUri)
27+
customTypingMetadata(types)
28+
?: this.fetchTypingMetadata(metadataRevision, fetchUri)
29+
?: this.toMajorVersion().fetchTypingsFromCatalog(fetchUri)
2730
)?.let { Pair(it.first.toTypesMap(), it.second) }
2831
?: Pair(emptyMap(), null)
2932

@@ -41,6 +44,9 @@ private fun ActionCoords.catalogMetadata() =
4144
private fun ActionCoords.actionTypesYamlUrl(gitRef: String) =
4245
"https://raw.githubusercontent.com/$owner/$repoName/$gitRef$subName/action-types.yaml"
4346

47+
private fun customTypingMetadata(types: String? = null) =
48+
types?.let { Pair(yaml.decodeFromStringOrDefaultIfEmpty(it, ActionTypes()), CUSTOM) }
49+
4450
private fun ActionCoords.fetchTypingMetadata(
4551
metadataRevision: MetadataRevision,
4652
fetchUri: (URI) -> String = ::fetchUri,
@@ -64,7 +70,7 @@ private fun ActionCoords.fetchTypingMetadata(
6470
return Pair(yaml.decodeFromStringOrDefaultIfEmpty(typesMetadataYaml, ActionTypes()), ACTION)
6571
}
6672

67-
private fun ActionCoords.fetchFromTypingsFromCatalog(fetchUri: (URI) -> String = ::fetchUri): Pair<ActionTypes, TypingActualSource>? =
73+
private fun ActionCoords.fetchTypingsFromCatalog(fetchUri: (URI) -> String = ::fetchUri): Pair<ActionTypes, TypingActualSource>? =
6874
(
6975
fetchTypingsFromUrl(url = actionTypesFromCatalog(), fetchUri = fetchUri)
7076
?: fetchTypingsForOlderVersionFromCatalog(fetchUri = fetchUri)

action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/typing/TypesProvidingTest.kt

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ class TypesProvidingTest :
8585
stored-in-typing-catalog:
8686
type: string
8787
""".trimIndent()
88+
val custom =
89+
"""
90+
inputs:
91+
custom:
92+
type: string
93+
""".trimIndent()
8894
val metadata =
8995
"""
9096
"versionsWithTypings":
@@ -309,6 +315,134 @@ class TypesProvidingTest :
309315
types shouldBe Pair(mapOf("hosted-by-action-yml" to StringTyping), TypingActualSource.ACTION)
310316
}
311317

318+
test("only custom") {
319+
// Given
320+
val fetchUri: (URI) -> String = { throw IOException() }
321+
val actionCoord = ActionCoords("some-owner", "some-name", "v3")
322+
323+
// When
324+
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = custom)
325+
326+
// Then
327+
types shouldBe Pair(mapOf("custom" to StringTyping), TypingActualSource.CUSTOM)
328+
}
329+
330+
test("only custom for subaction") {
331+
// Given
332+
val fetchUri: (URI) -> String = { throw IOException() }
333+
val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3")
334+
335+
// When
336+
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = custom)
337+
338+
// Then
339+
types shouldBe Pair(mapOf("custom" to StringTyping), TypingActualSource.CUSTOM)
340+
}
341+
342+
test("hosted by action, stored in typing catalog, and custom") {
343+
// Given
344+
val fetchUri: (URI) -> String = {
345+
when (it) {
346+
URI(
347+
"https://raw.githubusercontent.com/some-owner/some-name/" +
348+
"some-hash/action-types.yml",
349+
),
350+
-> hostedByActionYml
351+
URI(
352+
"https://raw.githubusercontent.com/typesafegithub/github-actions-typing-catalog/" +
353+
"main/typings/some-owner/some-name/v3/action-types.yml",
354+
),
355+
-> storedInTypingCatalog
356+
else -> throw IOException()
357+
}
358+
}
359+
val actionCoord = ActionCoords("some-owner", "some-name", "v3")
360+
361+
// When
362+
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = custom)
363+
364+
// Then
365+
types shouldBe Pair(mapOf("custom" to StringTyping), TypingActualSource.CUSTOM)
366+
}
367+
368+
test("hosted by subaction, stored in typing catalog, and custom") {
369+
// Given
370+
val fetchUri: (URI) -> String = {
371+
when (it) {
372+
URI(
373+
"https://raw.githubusercontent.com/some-owner/some-name/" +
374+
"some-hash/some-sub/action-types.yml",
375+
),
376+
-> hostedByActionYml
377+
URI(
378+
"https://raw.githubusercontent.com/typesafegithub/github-actions-typing-catalog/" +
379+
"main/typings/some-owner/some-name/v3/some-sub/action-types.yml",
380+
),
381+
-> storedInTypingCatalog
382+
else -> throw IOException()
383+
}
384+
}
385+
val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3")
386+
387+
// When
388+
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = custom)
389+
390+
// Then
391+
types shouldBe Pair(mapOf("custom" to StringTyping), TypingActualSource.CUSTOM)
392+
}
393+
394+
test("hosted by action, stored in typing catalog, and empty custom") {
395+
// Given
396+
val fetchUri: (URI) -> String = {
397+
when (it) {
398+
URI(
399+
"https://raw.githubusercontent.com/some-owner/some-name/" +
400+
"some-hash/action-types.yml",
401+
),
402+
-> hostedByActionYml
403+
URI(
404+
"https://raw.githubusercontent.com/typesafegithub/github-actions-typing-catalog/" +
405+
"main/typings/some-owner/some-name/v3/action-types.yml",
406+
),
407+
-> storedInTypingCatalog
408+
else -> throw IOException()
409+
}
410+
}
411+
val actionCoord = ActionCoords("some-owner", "some-name", "v3")
412+
413+
// When
414+
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = "")
415+
416+
// Then
417+
types shouldBe Pair(emptyMap(), TypingActualSource.CUSTOM)
418+
}
419+
420+
test("hosted by subaction, stored in typing catalog, and empty custom") {
421+
// Given
422+
val fetchUri: (URI) -> String = {
423+
when (it) {
424+
URI(
425+
"https://raw.githubusercontent.com/some-owner/some-name/" +
426+
"some-hash/some-sub/action-types.yml",
427+
),
428+
-> hostedByActionYml
429+
URI(
430+
"https://raw.githubusercontent.com/typesafegithub/github-actions-typing-catalog/" +
431+
"main/typings/some-owner/some-name/v3/some-sub/action-types.yml",
432+
),
433+
-> storedInTypingCatalog
434+
else -> throw IOException()
435+
}
436+
}
437+
val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3")
438+
439+
// When
440+
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = "")
441+
442+
// Then
443+
types shouldBe Pair(emptyMap(), TypingActualSource.CUSTOM)
444+
}
445+
312446
test("only stored in typing catalog for older version") {
313447
// Given
314448
val fetchUri: (URI) -> String = {
@@ -508,5 +642,25 @@ class TypesProvidingTest :
508642
TypingActualSource.TYPING_CATALOG,
509643
)
510644
}
645+
646+
test("only custom") {
647+
// Given
648+
val fetchUri: (URI) -> String = { throw IOException() }
649+
val actionCoord = ActionCoords("some-owner", "some-name", "v3")
650+
651+
// When
652+
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = typingYml)
653+
654+
// Then
655+
types shouldBe
656+
Pair(
657+
mapOf(
658+
"granted-scopes" to ListOfTypings(",", EnumTyping("GrantedScopes", listOf("read", "write"))),
659+
"granted-scopes2" to ListOfTypings(",", EnumTyping("GrantedScopes", listOf("read", "write"))),
660+
"granted-scopes3" to ListOfTypings("""\n""", EnumTyping("GrantedScopes", listOf("read", "write"))),
661+
),
662+
TypingActualSource.CUSTOM,
663+
)
664+
}
511665
}
512666
})

docs/user-guide/using-actions.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ For every action, a binding will be generated. However, some less popular action
2323
their inputs, so by default all inputs are of type `String`, have the suffix `_Untyped`, and additionally the class
2424
name will have an `_Untyped` suffix. The nullability of the inputs will be according to their required status.
2525

26-
There are two ways of configuring typings:
26+
There are two and a half ways of configuring typings:
2727
1. Recommended: a typing manifest (`action-typing.yml`) in the action's repo, see
2828
[github-actions-typing](https://github.com/typesafegithub/github-actions-typing/). Thanks to this, the action's owner
2929
is responsible for providing and maintaining the typings defined in a technology-agnostic way, to be used
@@ -34,6 +34,17 @@ There are two ways of configuring typings:
3434
[github-actions-typing-catalog](https://github.com/typesafegithub/github-actions-typing-catalog),
3535
a community-maintained place to host the typings. You can contribute or fix typings for your favorite action by
3636
sending a PR.
37+
3. Temporary: while developing a typing manifest it might be a good idea to test the result without needing to
38+
release the action in question or merge a PR in the catalog. For this you can `POST` the typing manifest you have
39+
on disk to the binding server using any valid URL for the action in question, for example using
40+
```bash
41+
curl --data-binary @action-types.yml https://bindings.krzeminski.it/pbrisbin/setup-tool-action/v2/setup-tool-action-v2.pom
42+
```
43+
The binding server generates a binding with only the given type manifest and answer with some unique coordinates
44+
that you can use in a test workflow script. The binding will be available the normal cache time on the binding
45+
server and locally as long as you do not delete it from your local Maven repository where it is cached. After
46+
the cache period on the server ended requesting the same coordinates will return a binding as if no typing
47+
information is available at all.
3748

3849
Once there are any typings in place for the action, the `_Untyped` suffixed class is marked `@Deprecated`, and a class
3950
without that suffix is created additionally. In that class for each input that does not have type information available

0 commit comments

Comments
 (0)