Skip to content

Commit 8222000

Browse files
committed
feat(abg): support different binding versions on different server routes
1 parent e46b9b4 commit 8222000

File tree

11 files changed

+233
-38
lines changed

11 files changed

+233
-38
lines changed

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

+10
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@ workflow(
9797

9898
cleanMavenLocal()
9999

100+
run(
101+
name = "Execute the script using the bindings from the server with v1 route",
102+
command = """
103+
mv .github/workflows/test-script-consuming-jit-bindings-v1.main.do-not-compile.kts .github/workflows/test-script-consuming-jit-bindings-v1.main.kts
104+
.github/workflows/test-script-consuming-jit-bindings-v1.main.kts
105+
""".trimIndent(),
106+
)
107+
108+
cleanMavenLocal()
109+
100110
run(
101111
name = "Execute the script using bindings but without dependency on library",
102112
command = """

.github/workflows/bindings-server.yaml

+17-9
Original file line numberDiff line numberDiff line change
@@ -74,46 +74,54 @@ jobs:
7474
name: 'Clean Maven Local to fetch required POMs again'
7575
run: 'rm -rf ~/.m2/repository/'
7676
- id: 'step-7'
77+
name: 'Execute the script using the bindings from the server with v1 route'
78+
run: |-
79+
mv .github/workflows/test-script-consuming-jit-bindings-v1.main.do-not-compile.kts .github/workflows/test-script-consuming-jit-bindings-v1.main.kts
80+
.github/workflows/test-script-consuming-jit-bindings-v1.main.kts
81+
- id: 'step-8'
82+
name: 'Clean Maven Local to fetch required POMs again'
83+
run: 'rm -rf ~/.m2/repository/'
84+
- id: 'step-9'
7785
name: 'Execute the script using bindings but without dependency on library'
7886
run: |-
7987
mv .github/workflows/test-served-bindings-depend-on-library.main.do-not-compile.kts .github/workflows/test-served-bindings-depend-on-library.main.kts
8088
.github/workflows/test-served-bindings-depend-on-library.main.kts
81-
- id: 'step-8'
89+
- id: 'step-10'
8290
name: 'Install Kotlin 1.9.0'
8391
uses: 'fwilhe2/setup-kotlin@v1'
8492
with:
8593
version: '1.9.0'
86-
- id: 'step-9'
94+
- id: 'step-11'
8795
name: 'Clean Maven Local to fetch required POMs again'
8896
run: 'rm -rf ~/.m2/repository/'
89-
- id: 'step-10'
97+
- id: 'step-12'
9098
name: 'Execute the script using the bindings from the server, using older Kotlin (1.9.0) as consumer'
9199
run: |2-
92100
cp .github/workflows/test-script-consuming-jit-bindings.main.kts .github/workflows/test-script-consuming-jit-bindings-too-old-kotlin.main.kts
93101
(.github/workflows/test-script-consuming-jit-bindings-too-old-kotlin.main.kts || true) >> output.txt 2>&1
94102
grep "was compiled with an incompatible version of Kotlin" output.txt
95-
- id: 'step-11'
103+
- id: 'step-13'
96104
name: 'Install Kotlin 2.0.0'
97105
uses: 'fwilhe2/setup-kotlin@v1'
98106
with:
99107
version: '2.0.0'
100-
- id: 'step-12'
108+
- id: 'step-14'
101109
name: 'Clean Maven Local to fetch required POMs again'
102110
run: 'rm -rf ~/.m2/repository/'
103-
- id: 'step-13'
111+
- id: 'step-15'
104112
name: 'Execute the script using the bindings from the server, using older Kotlin (2.0.0) as consumer'
105113
run: |-
106114
cp .github/workflows/test-script-consuming-jit-bindings.main.kts .github/workflows/test-script-consuming-jit-bindings-older-kotlin.main.kts
107115
.github/workflows/test-script-consuming-jit-bindings-older-kotlin.main.kts
108-
- id: 'step-14'
116+
- id: 'step-16'
109117
name: 'Compile a Gradle project using the bindings from the server'
110118
run: |-
111119
cd .github/workflows/test-gradle-project-using-bindings-server
112120
./gradlew build
113-
- id: 'step-15'
121+
- id: 'step-17'
114122
name: 'Fetch maven-metadata.xml for top-level action'
115123
run: 'curl --fail http://localhost:8080/actions/checkout/maven-metadata.xml | grep ''<version>v4</version>'''
116-
- id: 'step-16'
124+
- id: 'step-18'
117125
name: 'Fetch maven-metadata.xml for nested action'
118126
run: 'curl --fail http://localhost:8080/actions/cache__save/maven-metadata.xml | grep ''<version>v4</version>'''
119127
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
@@ -84,8 +84,8 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/gen
8484
}
8585

8686
public final class io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerationKt {
87-
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;
88-
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;
87+
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;
88+
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;
8989
}
9090

9191
public final class io/github/typesafegithub/workflows/actionbindinggenerator/metadata/Input {
@@ -194,3 +194,14 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/met
194194
public abstract interface class io/github/typesafegithub/workflows/actionbindinggenerator/typing/Typing {
195195
}
196196

197+
public final class io/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion : java/lang/Enum {
198+
public static final field V1 Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;
199+
public static fun getEntries ()Lkotlin/enums/EnumEntries;
200+
public final fun getLibraryVersion ()Ljava/lang/String;
201+
public final fun isDeprecated ()Z
202+
public final fun isExperimental ()Z
203+
public fun toString ()Ljava/lang/String;
204+
public static fun valueOf (Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;
205+
public static fun values ()[Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;
206+
}
207+

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

+84-12
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.domain.Signific
2323
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource
2424
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.fullName
2525
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.isTopLevel
26+
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.prettyPrint
2627
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.subName
2728
import io.github.typesafegithub.workflows.actionbindinggenerator.generation.Properties.CUSTOM_INPUTS
2829
import io.github.typesafegithub.workflows.actionbindinggenerator.generation.Properties.CUSTOM_VERSION
@@ -39,6 +40,8 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.typing.provideT
3940
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.removeTrailingWhitespacesForEachLine
4041
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.toCamelCase
4142
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.toKotlinPackageName
43+
import io.github.typesafegithub.workflows.actionbindinggenerator.versioning.BindingVersion
44+
import io.github.typesafegithub.workflows.actionbindinggenerator.versioning.BindingVersion.V1
4245

4346
public data class ActionBinding(
4447
val kotlinCode: String,
@@ -61,6 +64,7 @@ private object Properties {
6164
}
6265

6366
public fun ActionCoords.generateBinding(
67+
bindingVersion: BindingVersion = V1,
6468
metadataRevision: MetadataRevision,
6569
metadata: Metadata? = null,
6670
inputTypings: Pair<Map<String, Typing>, TypingActualSource?>? = null,
@@ -76,10 +80,11 @@ public fun ActionCoords.generateBinding(
7680

7781
val actionBindingSourceCodeUntyped =
7882
generateActionBindingSourceCode(
79-
metadataProcessed,
80-
this,
81-
emptyMap(),
82-
classNameUntyped,
83+
metadata = metadataProcessed,
84+
coords = this,
85+
bindingVersion = bindingVersion,
86+
inputTypings = emptyMap(),
87+
className = classNameUntyped,
8388
untypedClass = true,
8489
replaceWith = inputTypingsResolved.second?.let { CodeBlock.of("ReplaceWith(%S)", className) },
8590
)
@@ -97,6 +102,7 @@ public fun ActionCoords.generateBinding(
97102
generateActionBindingSourceCode(
98103
metadata = metadataProcessed,
99104
coords = this,
105+
bindingVersion = bindingVersion,
100106
inputTypings = inputTypingsResolved.first,
101107
className = className,
102108
)
@@ -127,6 +133,7 @@ private fun Metadata.removeDeprecatedInputsIfNameClash(): Metadata {
127133
private fun generateActionBindingSourceCode(
128134
metadata: Metadata,
129135
coords: ActionCoords,
136+
bindingVersion: BindingVersion,
130137
inputTypings: Map<String, Typing>,
131138
className: String,
132139
untypedClass: Boolean = false,
@@ -143,7 +150,7 @@ private fun generateActionBindingSourceCode(
143150
changes will be overwritten with the next binding code regeneration.
144151
See https://github.com/typesafegithub/github-workflows-kt for more info.
145152
""".trimIndent(),
146-
).addType(generateActionClass(metadata, coords, inputTypings, className, untypedClass, replaceWith))
153+
).addType(generateActionClass(metadata, coords, bindingVersion, inputTypings, className, untypedClass, replaceWith))
147154
.addSuppressAnnotation(metadata)
148155
.indent(" ")
149156
.build()
@@ -172,6 +179,7 @@ private fun FileSpec.Builder.addSuppressAnnotation(metadata: Metadata) =
172179
private fun generateActionClass(
173180
metadata: Metadata,
174181
coords: ActionCoords,
182+
bindingVersion: BindingVersion,
175183
inputTypings: Map<String, Typing>,
176184
className: String,
177185
untypedClass: Boolean,
@@ -181,12 +189,13 @@ private fun generateActionClass(
181189
.classBuilder(className)
182190
.addModifiers(KModifier.DATA)
183191
.addKdocIfNotEmpty(actionKdoc(metadata, coords, untypedClass))
184-
.replaceWith(replaceWith)
192+
.deprecateBindingVersion(bindingVersion)
193+
.replaceWith(bindingVersion, replaceWith)
185194
.addClassConstructorAnnotation()
186195
.inheritsFromRegularAction(coords, metadata, className)
187196
.primaryConstructor(metadata.primaryConstructor(inputTypings, coords, className, untypedClass))
188197
.properties(metadata, coords, inputTypings, className, untypedClass)
189-
.addInitializerBlockIfNecessary(metadata, inputTypings, untypedClass)
198+
.addInitializerBlock(metadata, bindingVersion, coords, inputTypings, untypedClass)
190199
.addFunction(metadata.secondaryConstructor(inputTypings, coords, className, untypedClass))
191200
.addFunction(metadata.buildToYamlArgumentsFunction(inputTypings, untypedClass))
192201
.addCustomTypes(inputTypings, coords, className)
@@ -374,8 +383,23 @@ private fun Metadata.linkedMapOfInputs(
374383
}
375384
}
376385

377-
private fun TypeSpec.Builder.replaceWith(replaceWith: CodeBlock?): TypeSpec.Builder {
378-
if (replaceWith != null) {
386+
private fun TypeSpec.Builder.deprecateBindingVersion(bindingVersion: BindingVersion): TypeSpec.Builder {
387+
if (bindingVersion.isDeprecated) {
388+
addAnnotation(
389+
AnnotationSpec
390+
.builder(Deprecated::class.asClassName())
391+
.addMember("%S", "Use a non-deprecated binding version in the repository URL")
392+
.build(),
393+
)
394+
}
395+
return this
396+
}
397+
398+
private fun TypeSpec.Builder.replaceWith(
399+
bindingVersion: BindingVersion,
400+
replaceWith: CodeBlock?,
401+
): TypeSpec.Builder {
402+
if (!bindingVersion.isDeprecated && replaceWith != null) {
379403
addAnnotation(
380404
AnnotationSpec
381405
.builder(Deprecated::class.asClassName())
@@ -544,15 +568,63 @@ private fun ParameterSpec.Builder.defaultValueIfNullable(
544568
return this
545569
}
546570

547-
private fun TypeSpec.Builder.addInitializerBlockIfNecessary(
571+
private fun TypeSpec.Builder.addInitializerBlock(
548572
metadata: Metadata,
573+
bindingVersion: BindingVersion,
574+
coords: ActionCoords,
549575
inputTypings: Map<String, Typing>,
550576
untypedClass: Boolean,
551577
): TypeSpec.Builder {
552-
if (untypedClass || metadata.inputs.isEmpty() || metadata.inputs.none { inputTypings.containsKey(it.key) }) {
578+
if (!bindingVersion.isDeprecated &&
579+
!bindingVersion.isExperimental &&
580+
(untypedClass || metadata.inputs.isEmpty() || metadata.inputs.none { inputTypings.containsKey(it.key) })
581+
) {
553582
return this
554583
}
555-
addInitializerBlock(metadata.initializerBlock(inputTypings))
584+
585+
addInitializerBlock(
586+
buildCodeBlock {
587+
if (bindingVersion.isDeprecated) {
588+
val firstStableVersion = BindingVersion.entries.find { !it.isDeprecated && !it.isExperimental }
589+
addStatement(
590+
"println(%S)",
591+
"""
592+
WARNING: The used binding version $bindingVersion for ${coords.prettyPrint} is deprecated! First stable version is $firstStableVersion.
593+
""".trimIndent(),
594+
)
595+
beginControlFlow("""if (System.getenv("GITHUB_ACTIONS").toBoolean())""")
596+
addStatement(
597+
"println(%S)",
598+
"""
599+
600+
::warning title=Deprecated Binding Version Used::The used binding version $bindingVersion for ${coords.prettyPrint} is deprecated! First stable version is $firstStableVersion.
601+
""".trimIndent(),
602+
)
603+
endControlFlow()
604+
add("\n")
605+
}
606+
if (bindingVersion.isExperimental) {
607+
val lastStableVersion = BindingVersion.entries.findLast { !it.isDeprecated && !it.isExperimental }
608+
addStatement(
609+
"println(%S)",
610+
"""
611+
WARNING: The used binding version $bindingVersion for ${coords.prettyPrint} is experimental! Last stable version is $lastStableVersion.
612+
""".trimIndent(),
613+
)
614+
beginControlFlow("""if (System.getenv("GITHUB_ACTIONS").toBoolean())""")
615+
addStatement(
616+
"println(%S)",
617+
"""
618+
619+
::warning title=Experimental Binding Version Used::The used binding version $bindingVersion for ${coords.prettyPrint} is experimental! Last stable version is $lastStableVersion.
620+
""".trimIndent(),
621+
)
622+
endControlFlow()
623+
add("\n")
624+
}
625+
add(metadata.initializerBlock(inputTypings))
626+
},
627+
)
556628
return this
557629
}
558630

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.2.0"),
9+
;
10+
11+
override fun toString(): String = super.toString().lowercase()
12+
}

0 commit comments

Comments
 (0)