Repository: typesafegithub/github-workflows-kt
Pull request #1321 (2024-03-25 14:36:30)

feat(abg): create enum for binding generation modes
Part of #1318.

Thanks to this, we'll be able to define yet another mode, optimized for hosting the JARs with bindings by a dedicated service.


Patch:
diff --git a/action-binding-generator/api/action-binding-generator.api b/action-binding-generator/api/action-binding-generator.api
index ad7599db0..5b4d6adb9 100644
--- a/action-binding-generator/api/action-binding-generator.api
+++ b/action-binding-generator/api/action-binding-generator.api
@@ -81,6 +81,14 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/gen
 	public fun toString ()Ljava/lang/String;
 }
 
+public final class io/github/typesafegithub/workflows/actionbindinggenerator/generation/ClientType : java/lang/Enum {
+	public static final field BUNDLED_WITH_LIB Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ClientType;
+	public static final field CLIENT_SIDE_GENERATION Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ClientType;
+	public static fun getEntries ()Lkotlin/enums/EnumEntries;
+	public static fun valueOf (Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ClientType;
+	public static fun values ()[Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ClientType;
+}
+
 public final class io/github/typesafegithub/workflows/actionbindinggenerator/generation/ExtractUsedActionsFromWorkflowKt {
 	public static final fun extractUsedActionsFromWorkflow (Ljava/lang/String;)Ljava/util/List;
 }
@@ -90,8 +98,8 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/gen
 }
 
 public final class io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerationKt {
-	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;Z)Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ActionBinding;
-	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;ZILjava/lang/Object;)Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ActionBinding;
+	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;Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ClientType;)Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ActionBinding;
+	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;Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ClientType;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/actionbindinggenerator/generation/ActionBinding;
 }
 
 public final class io/github/typesafegithub/workflows/actionbindinggenerator/metadata/Input {
diff --git a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerateActionBindingsCliHelper.kt b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerateActionBindingsCliHelper.kt
index c45257beb..d0f4ada38 100644
--- a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerateActionBindingsCliHelper.kt
+++ b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerateActionBindingsCliHelper.kt
@@ -49,7 +49,7 @@ public fun generateActionBindings(
             val binding =
                 action.generateBinding(
                     metadataRevision = NewestForVersion,
-                    generateForScript = true,
+                    clientType = ClientType.CLIENT_SIDE_GENERATION,
                 )
             it.toFile().writeText(binding.kotlinCode)
         }
diff --git a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/Generation.kt b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/Generation.kt
index d2346c0b3..9a22d0c85 100644
--- a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/Generation.kt
+++ b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/Generation.kt
@@ -44,6 +44,19 @@ public data class ActionBinding(
     val typingActualSource: TypingActualSource?,
 )
 
+public enum class ClientType {
+    /**
+     * The binding is going to be bundled with the library.
+     */
+    BUNDLED_WITH_LIB,
+
+    /**
+     * The binding is going to be generated on the client side, and consumed
+     * via `@file:Import(...)`.
+     */
+    CLIENT_SIDE_GENERATION,
+}
+
 private object Types {
     val mapStringString = Map::class.asTypeName().parameterizedBy(String::class.asTypeName(), String::class.asTypeName())
     val nullableString = String::class.asTypeName().copy(nullable = true)
@@ -60,7 +73,7 @@ public fun ActionCoords.generateBinding(
     metadataRevision: MetadataRevision,
     metadata: Metadata = this.fetchMetadata(metadataRevision),
     inputTypings: Pair<Map<String, Typing>, TypingActualSource?> = provideTypes(metadataRevision),
-    generateForScript: Boolean = false,
+    clientType: ClientType = ClientType.BUNDLED_WITH_LIB,
 ): ActionBinding {
     require(this.version.removePrefix("v").toIntOrNull() != null) {
         "Only major versions are supported, and '${this.version}' was given!"
@@ -71,9 +84,9 @@ public fun ActionCoords.generateBinding(
         println("$prettyPrint I suggest the following typings:\n$formatSuggestions")
     }
 
-    val className = this.buildActionClassName(includeVersion = !generateForScript)
+    val className = this.buildActionClassName(includeVersion = clientType == ClientType.BUNDLED_WITH_LIB)
     val actionBindingSourceCode =
-        generateActionBindingSourceCode(metadataProcessed, this, inputTypings.first, className, generateForScript = generateForScript)
+        generateActionBindingSourceCode(metadataProcessed, this, inputTypings.first, className, clientType)
     val packageName = owner.toKotlinPackageName()
     return ActionBinding(
         kotlinCode = actionBindingSourceCode,
@@ -101,11 +114,15 @@ private fun generateActionBindingSourceCode(
     coords: ActionCoords,
     inputTypings: Map<String, Typing>,
     className: String,
-    generateForScript: Boolean,
+    clientType: ClientType,
 ): String {
     val fileSpec =
         FileSpec.builder(
-            if (generateForScript) "" else "io.github.typesafegithub.workflows.actions.${coords.owner.toKotlinPackageName()}",
+            if (clientType == ClientType.BUNDLED_WITH_LIB) {
+                "io.github.typesafegithub.workflows.actions.${coords.owner.toKotlinPackageName()}"
+            } else {
+                ""
+            },
             className,
         )
             .addFileComment(
@@ -115,14 +132,14 @@ private fun generateActionBindingSourceCode(
                 See https://github.com/typesafegithub/github-workflows-kt for more info.
                 """.trimIndent(),
             )
-            .addType(generateActionClass(metadata, coords, inputTypings, className, generateForScript = generateForScript))
+            .addType(generateActionClass(metadata, coords, inputTypings, className, clientType))
             .addSuppressAnnotation(metadata, coords)
             .indent("    ")
             .build()
     return buildString {
         fileSpec.writeTo(this)
     }.let {
-        if (generateForScript) {
+        if (clientType == ClientType.CLIENT_SIDE_GENERATION) {
             it.lines()
                 .filter { !it.startsWith("import io.github.typesafegithub.workflows.actions.") }
                 .joinToString(separator = "\n")
@@ -157,18 +174,18 @@ private fun generateActionClass(
     coords: ActionCoords,
     inputTypings: Map<String, Typing>,
     className: String,
-    generateForScript: Boolean,
+    clientType: ClientType,
 ): TypeSpec {
     return TypeSpec.classBuilder(className)
         .addModifiers(KModifier.DATA)
         .apply {
-            if (generateForScript) {
+            if (clientType == ClientType.CLIENT_SIDE_GENERATION) {
                 addExperimentalAnnotation()
             }
         }
         .addKdoc(actionKdoc(metadata, coords))
         .addMaybeDeprecated(coords)
-        .inheritsFromRegularAction(coords, metadata, className, generateForScript = generateForScript)
+        .inheritsFromRegularAction(coords, metadata, className, clientType)
         .primaryConstructor(metadata.primaryConstructor(inputTypings, coords, className))
         .properties(metadata, coords, inputTypings, className)
         .addFunction(metadata.secondaryConstructor(inputTypings, coords, className))
@@ -332,7 +349,7 @@ private fun TypeSpec.Builder.inheritsFromRegularAction(
     coords: ActionCoords,
     metadata: Metadata,
     className: String,
-    generateForScript: Boolean,
+    clientType: ClientType,
 ): TypeSpec.Builder {
     val superclass =
         ClassName("io.github.typesafegithub.workflows.domain.actions", "RegularAction")
@@ -341,7 +358,11 @@ private fun TypeSpec.Builder.inheritsFromRegularAction(
                     OutputsBase
                 } else {
                     ClassName(
-                        if (generateForScript) "" else "io.github.typesafegithub.workflows.actions.${coords.owner.toKotlinPackageName()}",
+                        if (clientType == ClientType.BUNDLED_WITH_LIB) {
+                            "io.github.typesafegithub.workflows.actions.${coords.owner.toKotlinPackageName()}"
+                        } else {
+                            ""
+                        },
                         className,
                         "Outputs",
                     )


Test patch:
diff --git a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerationTest.kt b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerationTest.kt
index 280b42c72..fece8e474 100644
--- a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerationTest.kt
+++ b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerationTest.kt
@@ -388,7 +388,7 @@ class GenerationTest : FunSpec({
         binding.shouldMatchFile("ActionWithInputsSharingTypeV3.kt")
     }
 
-    test("action binding generated to be used from a script") {
+    test("action binding generated on the client side") {
         // given
         val actionManifest =
             Metadata(
@@ -426,7 +426,7 @@ class GenerationTest : FunSpec({
             coords.generateBinding(
                 metadataRevision = FromLockfile,
                 metadata = actionManifest,
-                generateForScript = true,
+                clientType = ClientType.CLIENT_SIDE_GENERATION,
                 inputTypings =
                     Pair(
                         mapOf(