Skip to content

Commit 449f7e8

Browse files
committed
feat(abg): support different binding versions on different server routes
1 parent 7bd5616 commit 449f7e8

File tree

10 files changed

+226
-35
lines changed

10 files changed

+226
-35
lines changed

.github/workflows/bindings-server.main.kts

+10
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ workflow(
9191

9292
cleanMavenLocal()
9393

94+
run(
95+
name = "Execute the script using the bindings from the server with v1 route",
96+
command = """
97+
mv .github/workflows/test-script-consuming-jit-bindings-v1.main.do-not-compile.kts .github/workflows/test-script-consuming-jit-bindings-v1.main.kts
98+
.github/workflows/test-script-consuming-jit-bindings-v1.main.kts
99+
""".trimIndent(),
100+
)
101+
102+
cleanMavenLocal()
103+
94104
run(
95105
name = "Execute the script using bindings but without dependency on library",
96106
command = """

.github/workflows/bindings-server.yaml

+12-4
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,30 @@ jobs:
5757
name: 'Clean Maven Local to fetch required POMs again'
5858
run: 'rm -rf ~/.m2/repository/'
5959
- id: 'step-7'
60+
name: 'Execute the script using the bindings from the server with v1 route'
61+
run: |-
62+
mv .github/workflows/test-script-consuming-jit-bindings-v1.main.do-not-compile.kts .github/workflows/test-script-consuming-jit-bindings-v1.main.kts
63+
.github/workflows/test-script-consuming-jit-bindings-v1.main.kts
64+
- id: 'step-8'
65+
name: 'Clean Maven Local to fetch required POMs again'
66+
run: 'rm -rf ~/.m2/repository/'
67+
- id: 'step-9'
6068
name: 'Execute the script using bindings but without dependency on library'
6169
run: |-
6270
mv .github/workflows/test-served-bindings-depend-on-library.main.do-not-compile.kts .github/workflows/test-served-bindings-depend-on-library.main.kts
6371
.github/workflows/test-served-bindings-depend-on-library.main.kts
64-
- id: 'step-8'
72+
- id: 'step-10'
6573
name: 'Clean Maven Local to fetch required POMs again'
6674
run: 'rm -rf ~/.m2/repository/'
67-
- id: 'step-9'
75+
- id: 'step-11'
6876
name: 'Compile a Gradle project using the bindings from the server'
6977
run: |-
7078
cd .github/workflows/test-gradle-project-using-bindings-server
7179
./gradlew build
72-
- id: 'step-10'
80+
- id: 'step-12'
7381
name: 'Fetch maven-metadata.xml for top-level action'
7482
run: 'curl --fail http://localhost:8080/actions/checkout/maven-metadata.xml | grep ''<version>v4</version>'''
75-
- id: 'step-11'
83+
- id: 'step-13'
7684
name: 'Fetch maven-metadata.xml for nested action'
7785
run: 'curl --fail http://localhost:8080/actions/cache__save/maven-metadata.xml | grep ''<version>v4</version>'''
7886
deploy:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env kotlin
2+
@file:Repository("https://repo.maven.apache.org/maven2/")
3+
@file:DependsOn("io.github.typesafegithub:github-workflows-kt:1.13.0")
4+
5+
@file:Repository("http://localhost:8080/v1")
6+
7+
// Regular, top-level action.
8+
@file:DependsOn("actions:checkout:v4")
9+
10+
// Nested action.
11+
@file:DependsOn("gradle:actions__setup-gradle:v3")
12+
13+
// Using specific version.
14+
@file:DependsOn("actions:cache:v3.3.3")
15+
16+
// Always untyped action.
17+
@file:DependsOn("typesafegithub:always-untyped-action-for-tests:v1")
18+
19+
import io.github.typesafegithub.workflows.actions.actions.Cache
20+
import io.github.typesafegithub.workflows.actions.actions.Checkout
21+
import io.github.typesafegithub.workflows.actions.actions.Checkout_Untyped
22+
import io.github.typesafegithub.workflows.actions.gradle.ActionsSetupGradle
23+
import io.github.typesafegithub.workflows.actions.typesafegithub.AlwaysUntypedActionForTests_Untyped
24+
25+
println(Checkout_Untyped(fetchTags_Untyped = "false"))
26+
println(Checkout(fetchTags = false))
27+
println(Checkout(fetchTags_Untyped = "false"))
28+
println(AlwaysUntypedActionForTests_Untyped(foobar_Untyped = "baz"))
29+
println(ActionsSetupGradle())
30+
println(Cache(path = listOf("some-path"), key = "some-key"))
31+
32+
// Ensure that 'copy(...)' method is exposed.
33+
Checkout(fetchTags = false).copy(fetchTags = true)

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

+13-2
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/gen
7272
}
7373

7474
public final class io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerationKt {
75-
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;
76-
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;
75+
public static final fun generateBinding (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;)Ljava/util/List;
76+
public static synthetic fun generateBinding$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;ILjava/lang/Object;)Ljava/util/List;
7777
}
7878

7979
public final class io/github/typesafegithub/workflows/actionbindinggenerator/metadata/Input {
@@ -182,3 +182,14 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/met
182182
public abstract interface class io/github/typesafegithub/workflows/actionbindinggenerator/typing/Typing {
183183
}
184184

185+
public final class io/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion : java/lang/Enum {
186+
public static final field V1 Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;
187+
public static fun getEntries ()Lkotlin/enums/EnumEntries;
188+
public final fun getLibraryVersion ()Ljava/lang/String;
189+
public final fun isDeprecated ()Z
190+
public final fun isExperimental ()Z
191+
public fun toString ()Ljava/lang/String;
192+
public static fun valueOf (Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;
193+
public static fun values ()[Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;
194+
}
195+

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

+84-12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.domain.Metadata
2020
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource
2121
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.fullName
2222
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.isTopLevel
23+
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.prettyPrint
2324
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.subName
2425
import io.github.typesafegithub.workflows.actionbindinggenerator.generation.Properties.CUSTOM_INPUTS
2526
import io.github.typesafegithub.workflows.actionbindinggenerator.generation.Properties.CUSTOM_VERSION
@@ -36,6 +37,8 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.typing.provideT
3637
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.removeTrailingWhitespacesForEachLine
3738
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.toCamelCase
3839
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.toKotlinPackageName
40+
import io.github.typesafegithub.workflows.actionbindinggenerator.versioning.BindingVersion
41+
import io.github.typesafegithub.workflows.actionbindinggenerator.versioning.BindingVersion.V1
3942

4043
public data class ActionBinding(
4144
val kotlinCode: String,
@@ -58,6 +61,7 @@ private object Properties {
5861
}
5962

6063
public fun ActionCoords.generateBinding(
64+
bindingVersion: BindingVersion = V1,
6165
metadataRevision: MetadataRevision,
6266
metadata: Metadata? = null,
6367
inputTypings: Pair<Map<String, Typing>, TypingActualSource?>? = null,
@@ -73,10 +77,11 @@ public fun ActionCoords.generateBinding(
7377

7478
val actionBindingSourceCodeUntyped =
7579
generateActionBindingSourceCode(
76-
metadataProcessed,
77-
this,
78-
emptyMap(),
79-
classNameUntyped,
80+
metadata = metadataProcessed,
81+
coords = this,
82+
bindingVersion = bindingVersion,
83+
inputTypings = emptyMap(),
84+
className = classNameUntyped,
8085
untypedClass = true,
8186
replaceWith = inputTypingsResolved.second?.let { CodeBlock.of("ReplaceWith(%S)", className) },
8287
)
@@ -94,6 +99,7 @@ public fun ActionCoords.generateBinding(
9499
generateActionBindingSourceCode(
95100
metadata = metadataProcessed,
96101
coords = this,
102+
bindingVersion = bindingVersion,
97103
inputTypings = inputTypingsResolved.first,
98104
className = className,
99105
)
@@ -124,6 +130,7 @@ private fun Metadata.removeDeprecatedInputsIfNameClash(): Metadata {
124130
private fun generateActionBindingSourceCode(
125131
metadata: Metadata,
126132
coords: ActionCoords,
133+
bindingVersion: BindingVersion,
127134
inputTypings: Map<String, Typing>,
128135
className: String,
129136
untypedClass: Boolean = false,
@@ -140,7 +147,7 @@ private fun generateActionBindingSourceCode(
140147
changes will be overwritten with the next binding code regeneration.
141148
See https://github.com/typesafegithub/github-workflows-kt for more info.
142149
""".trimIndent(),
143-
).addType(generateActionClass(metadata, coords, inputTypings, className, untypedClass, replaceWith))
150+
).addType(generateActionClass(metadata, coords, bindingVersion, inputTypings, className, untypedClass, replaceWith))
144151
.addSuppressAnnotation(metadata)
145152
.indent(" ")
146153
.build()
@@ -169,6 +176,7 @@ private fun FileSpec.Builder.addSuppressAnnotation(metadata: Metadata) =
169176
private fun generateActionClass(
170177
metadata: Metadata,
171178
coords: ActionCoords,
179+
bindingVersion: BindingVersion,
172180
inputTypings: Map<String, Typing>,
173181
className: String,
174182
untypedClass: Boolean,
@@ -178,12 +186,13 @@ private fun generateActionClass(
178186
.classBuilder(className)
179187
.addModifiers(KModifier.DATA)
180188
.addKdocIfNotEmpty(actionKdoc(metadata, coords, untypedClass))
181-
.replaceWith(replaceWith)
189+
.deprecateBindingVersion(bindingVersion)
190+
.replaceWith(bindingVersion, replaceWith)
182191
.addClassConstructorAnnotation()
183192
.inheritsFromRegularAction(coords, metadata, className)
184193
.primaryConstructor(metadata.primaryConstructor(inputTypings, coords, className, untypedClass))
185194
.properties(metadata, coords, inputTypings, className, untypedClass)
186-
.addInitializerBlockIfNecessary(metadata, inputTypings, untypedClass)
195+
.addInitializerBlock(metadata, bindingVersion, coords, inputTypings, untypedClass)
187196
.addFunction(metadata.secondaryConstructor(inputTypings, coords, className, untypedClass))
188197
.addFunction(metadata.buildToYamlArgumentsFunction(inputTypings, untypedClass))
189198
.addCustomTypes(inputTypings, coords, className)
@@ -371,8 +380,23 @@ private fun Metadata.linkedMapOfInputs(
371380
}
372381
}
373382

374-
private fun TypeSpec.Builder.replaceWith(replaceWith: CodeBlock?): TypeSpec.Builder {
375-
if (replaceWith != null) {
383+
private fun TypeSpec.Builder.deprecateBindingVersion(bindingVersion: BindingVersion): TypeSpec.Builder {
384+
if (bindingVersion.isDeprecated) {
385+
addAnnotation(
386+
AnnotationSpec
387+
.builder(Deprecated::class.asClassName())
388+
.addMember("%S", "Use a non-deprecated binding version in the repository URL")
389+
.build(),
390+
)
391+
}
392+
return this
393+
}
394+
395+
private fun TypeSpec.Builder.replaceWith(
396+
bindingVersion: BindingVersion,
397+
replaceWith: CodeBlock?,
398+
): TypeSpec.Builder {
399+
if (!bindingVersion.isDeprecated && replaceWith != null) {
376400
addAnnotation(
377401
AnnotationSpec
378402
.builder(Deprecated::class.asClassName())
@@ -531,15 +555,63 @@ private fun ParameterSpec.Builder.defaultValueIfNullable(
531555
return this
532556
}
533557

534-
private fun TypeSpec.Builder.addInitializerBlockIfNecessary(
558+
private fun TypeSpec.Builder.addInitializerBlock(
535559
metadata: Metadata,
560+
bindingVersion: BindingVersion,
561+
coords: ActionCoords,
536562
inputTypings: Map<String, Typing>,
537563
untypedClass: Boolean,
538564
): TypeSpec.Builder {
539-
if (untypedClass || metadata.inputs.isEmpty() || metadata.inputs.none { inputTypings.containsKey(it.key) }) {
565+
if (!bindingVersion.isDeprecated &&
566+
!bindingVersion.isExperimental &&
567+
(untypedClass || metadata.inputs.isEmpty() || metadata.inputs.none { inputTypings.containsKey(it.key) })
568+
) {
540569
return this
541570
}
542-
addInitializerBlock(metadata.initializerBlock(inputTypings))
571+
572+
addInitializerBlock(
573+
buildCodeBlock {
574+
if (bindingVersion.isDeprecated) {
575+
val firstStableVersion = BindingVersion.entries.find { !it.isDeprecated && !it.isExperimental }
576+
addStatement(
577+
"println(%S)",
578+
"""
579+
WARNING: The used binding version $bindingVersion for ${coords.prettyPrint} is deprecated! First stable version is $firstStableVersion.
580+
""".trimIndent(),
581+
)
582+
beginControlFlow("""if (System.getenv("GITHUB_ACTIONS").toBoolean())""")
583+
addStatement(
584+
"println(%S)",
585+
"""
586+
587+
::warning title=Deprecated Binding Version Used::The used binding version $bindingVersion for ${coords.prettyPrint} is deprecated! First stable version is $firstStableVersion.
588+
""".trimIndent(),
589+
)
590+
endControlFlow()
591+
add("\n")
592+
}
593+
if (bindingVersion.isExperimental) {
594+
val lastStableVersion = BindingVersion.entries.findLast { !it.isDeprecated && !it.isExperimental }
595+
addStatement(
596+
"println(%S)",
597+
"""
598+
WARNING: The used binding version $bindingVersion for ${coords.prettyPrint} is experimental! Last stable version is $lastStableVersion.
599+
""".trimIndent(),
600+
)
601+
beginControlFlow("""if (System.getenv("GITHUB_ACTIONS").toBoolean())""")
602+
addStatement(
603+
"println(%S)",
604+
"""
605+
606+
::warning title=Experimental Binding Version Used::The used binding version $bindingVersion for ${coords.prettyPrint} is experimental! Last stable version is $lastStableVersion.
607+
""".trimIndent(),
608+
)
609+
endControlFlow()
610+
add("\n")
611+
}
612+
add(metadata.initializerBlock(inputTypings))
613+
},
614+
)
543615
return this
544616
}
545617

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.github.typesafegithub.workflows.actionbindinggenerator.versioning
2+
3+
public enum class BindingVersion(
4+
public val isDeprecated: Boolean = false,
5+
public val isExperimental: Boolean = true,
6+
public val libraryVersion: String,
7+
) {
8+
V1(isExperimental = false, libraryVersion = "3.0.1"),
9+
;
10+
11+
override fun toString(): String = super.toString().lowercase()
12+
}

0 commit comments

Comments
 (0)