Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(abg): support different binding versions on different server routes #1639

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/bindings-server.main.kts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ workflow(

cleanMavenLocal()

run(
name = "Execute the script using the bindings from the server with v1 route",
command = """
mv .github/workflows/test-script-consuming-jit-bindings-v1.main.do-not-compile.kts .github/workflows/test-script-consuming-jit-bindings-v1.main.kts
.github/workflows/test-script-consuming-jit-bindings-v1.main.kts
""".trimIndent(),
)

cleanMavenLocal()

run(
name = "Execute the script using bindings but without dependency on library",
command = """
Expand Down
26 changes: 17 additions & 9 deletions .github/workflows/bindings-server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,46 +74,54 @@ jobs:
name: 'Clean Maven Local to fetch required POMs again'
run: 'rm -rf ~/.m2/repository/'
- id: 'step-7'
name: 'Execute the script using the bindings from the server with v1 route'
run: |-
mv .github/workflows/test-script-consuming-jit-bindings-v1.main.do-not-compile.kts .github/workflows/test-script-consuming-jit-bindings-v1.main.kts
.github/workflows/test-script-consuming-jit-bindings-v1.main.kts
- id: 'step-8'
name: 'Clean Maven Local to fetch required POMs again'
run: 'rm -rf ~/.m2/repository/'
- id: 'step-9'
name: 'Execute the script using bindings but without dependency on library'
run: |-
mv .github/workflows/test-served-bindings-depend-on-library.main.do-not-compile.kts .github/workflows/test-served-bindings-depend-on-library.main.kts
.github/workflows/test-served-bindings-depend-on-library.main.kts
- id: 'step-8'
- id: 'step-10'
name: 'Install Kotlin 1.9.0'
uses: 'fwilhe2/setup-kotlin@v1'
with:
version: '1.9.0'
- id: 'step-9'
- id: 'step-11'
name: 'Clean Maven Local to fetch required POMs again'
run: 'rm -rf ~/.m2/repository/'
- id: 'step-10'
- id: 'step-12'
name: 'Execute the script using the bindings from the server, using older Kotlin (1.9.0) as consumer'
run: |2-
cp .github/workflows/test-script-consuming-jit-bindings.main.kts .github/workflows/test-script-consuming-jit-bindings-too-old-kotlin.main.kts
(.github/workflows/test-script-consuming-jit-bindings-too-old-kotlin.main.kts || true) >> output.txt 2>&1
grep "was compiled with an incompatible version of Kotlin" output.txt
- id: 'step-11'
- id: 'step-13'
name: 'Install Kotlin 2.0.0'
uses: 'fwilhe2/setup-kotlin@v1'
with:
version: '2.0.0'
- id: 'step-12'
- id: 'step-14'
name: 'Clean Maven Local to fetch required POMs again'
run: 'rm -rf ~/.m2/repository/'
- id: 'step-13'
- id: 'step-15'
name: 'Execute the script using the bindings from the server, using older Kotlin (2.0.0) as consumer'
run: |-
cp .github/workflows/test-script-consuming-jit-bindings.main.kts .github/workflows/test-script-consuming-jit-bindings-older-kotlin.main.kts
.github/workflows/test-script-consuming-jit-bindings-older-kotlin.main.kts
- id: 'step-14'
- id: 'step-16'
name: 'Compile a Gradle project using the bindings from the server'
run: |-
cd .github/workflows/test-gradle-project-using-bindings-server
./gradlew build
- id: 'step-15'
- id: 'step-17'
name: 'Fetch maven-metadata.xml for top-level action'
run: 'curl --fail http://localhost:8080/actions/checkout/maven-metadata.xml | grep ''<version>v4</version>'''
- id: 'step-16'
- id: 'step-18'
name: 'Fetch maven-metadata.xml for nested action'
run: 'curl --fail http://localhost:8080/actions/cache__save/maven-metadata.xml | grep ''<version>v4</version>'''
deploy:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env kotlin
@file:Repository("https://repo.maven.apache.org/maven2/")
@file:DependsOn("io.github.typesafegithub:github-workflows-kt:1.13.0")

@file:Repository("http://localhost:8080/v1")

// Regular, top-level action.
@file:DependsOn("actions:checkout:v4")

// Nested action.
@file:DependsOn("gradle:actions__setup-gradle:v3")

// Using specific version.
@file:DependsOn("actions:cache:v3.3.3")

// Always untyped action.
@file:DependsOn("typesafegithub:always-untyped-action-for-tests:v1")

import io.github.typesafegithub.workflows.actions.actions.Cache
import io.github.typesafegithub.workflows.actions.actions.Checkout
import io.github.typesafegithub.workflows.actions.actions.Checkout_Untyped
import io.github.typesafegithub.workflows.actions.gradle.ActionsSetupGradle
import io.github.typesafegithub.workflows.actions.typesafegithub.AlwaysUntypedActionForTests_Untyped

println(Checkout_Untyped(fetchTags_Untyped = "false"))
println(Checkout(fetchTags = false))
println(Checkout(fetchTags_Untyped = "false"))
println(AlwaysUntypedActionForTests_Untyped(foobar_Untyped = "baz"))
println(ActionsSetupGradle())
println(Cache(path = listOf("some-path"), key = "some-key"))

// Ensure that 'copy(...)' method is exposed.
Checkout(fetchTags = false).copy(fetchTags = true)
15 changes: 13 additions & 2 deletions action-binding-generator/api/action-binding-generator.api
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,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;)Ljava/util/List;
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;
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;
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;
}

public final class io/github/typesafegithub/workflows/actionbindinggenerator/metadata/Input {
Expand Down Expand Up @@ -182,3 +182,14 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/met
public abstract interface class io/github/typesafegithub/workflows/actionbindinggenerator/typing/Typing {
}

public final class io/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion : java/lang/Enum {
public static final field V1 Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;
public static fun getEntries ()Lkotlin/enums/EnumEntries;
public final fun getLibraryVersion ()Ljava/lang/String;
public final fun isDeprecated ()Z
public final fun isExperimental ()Z
public fun toString ()Ljava/lang/String;
public static fun valueOf (Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;
public static fun values ()[Lio/github/typesafegithub/workflows/actionbindinggenerator/versioning/BindingVersion;
}

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.domain.Metadata
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.fullName
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.isTopLevel
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.prettyPrint
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.subName
import io.github.typesafegithub.workflows.actionbindinggenerator.generation.Properties.CUSTOM_INPUTS
import io.github.typesafegithub.workflows.actionbindinggenerator.generation.Properties.CUSTOM_VERSION
Expand All @@ -36,6 +37,8 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.typing.provideT
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.removeTrailingWhitespacesForEachLine
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.toCamelCase
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.toKotlinPackageName
import io.github.typesafegithub.workflows.actionbindinggenerator.versioning.BindingVersion
import io.github.typesafegithub.workflows.actionbindinggenerator.versioning.BindingVersion.V1

public data class ActionBinding(
val kotlinCode: String,
Expand All @@ -58,6 +61,7 @@ private object Properties {
}

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

val actionBindingSourceCodeUntyped =
generateActionBindingSourceCode(
metadataProcessed,
this,
emptyMap(),
classNameUntyped,
metadata = metadataProcessed,
coords = this,
bindingVersion = bindingVersion,
inputTypings = emptyMap(),
className = classNameUntyped,
untypedClass = true,
replaceWith = inputTypingsResolved.second?.let { CodeBlock.of("ReplaceWith(%S)", className) },
)
Expand All @@ -94,6 +99,7 @@ public fun ActionCoords.generateBinding(
generateActionBindingSourceCode(
metadata = metadataProcessed,
coords = this,
bindingVersion = bindingVersion,
inputTypings = inputTypingsResolved.first,
className = className,
)
Expand Down Expand Up @@ -124,6 +130,7 @@ private fun Metadata.removeDeprecatedInputsIfNameClash(): Metadata {
private fun generateActionBindingSourceCode(
metadata: Metadata,
coords: ActionCoords,
bindingVersion: BindingVersion,
inputTypings: Map<String, Typing>,
className: String,
untypedClass: Boolean = false,
Expand All @@ -140,7 +147,7 @@ private fun generateActionBindingSourceCode(
changes will be overwritten with the next binding code regeneration.
See https://github.com/typesafegithub/github-workflows-kt for more info.
""".trimIndent(),
).addType(generateActionClass(metadata, coords, inputTypings, className, untypedClass, replaceWith))
).addType(generateActionClass(metadata, coords, bindingVersion, inputTypings, className, untypedClass, replaceWith))
.addSuppressAnnotation(metadata)
.indent(" ")
.build()
Expand Down Expand Up @@ -169,6 +176,7 @@ private fun FileSpec.Builder.addSuppressAnnotation(metadata: Metadata) =
private fun generateActionClass(
metadata: Metadata,
coords: ActionCoords,
bindingVersion: BindingVersion,
inputTypings: Map<String, Typing>,
className: String,
untypedClass: Boolean,
Expand All @@ -178,12 +186,13 @@ private fun generateActionClass(
.classBuilder(className)
.addModifiers(KModifier.DATA)
.addKdocIfNotEmpty(actionKdoc(metadata, coords, untypedClass))
.replaceWith(replaceWith)
.deprecateBindingVersion(bindingVersion)
.replaceWith(bindingVersion, replaceWith)
.addClassConstructorAnnotation()
.inheritsFromRegularAction(coords, metadata, className)
.primaryConstructor(metadata.primaryConstructor(inputTypings, coords, className, untypedClass))
.properties(metadata, coords, inputTypings, className, untypedClass)
.addInitializerBlockIfNecessary(metadata, inputTypings, untypedClass)
.addInitializerBlock(metadata, bindingVersion, coords, inputTypings, untypedClass)
.addFunction(metadata.secondaryConstructor(inputTypings, coords, className, untypedClass))
.addFunction(metadata.buildToYamlArgumentsFunction(inputTypings, untypedClass))
.addCustomTypes(inputTypings, coords, className)
Expand Down Expand Up @@ -371,8 +380,23 @@ private fun Metadata.linkedMapOfInputs(
}
}

private fun TypeSpec.Builder.replaceWith(replaceWith: CodeBlock?): TypeSpec.Builder {
if (replaceWith != null) {
private fun TypeSpec.Builder.deprecateBindingVersion(bindingVersion: BindingVersion): TypeSpec.Builder {
if (bindingVersion.isDeprecated) {
addAnnotation(
AnnotationSpec
.builder(Deprecated::class.asClassName())
.addMember("%S", "Use a non-deprecated binding version in the repository URL")
.build(),
)
}
return this
}

private fun TypeSpec.Builder.replaceWith(
bindingVersion: BindingVersion,
replaceWith: CodeBlock?,
): TypeSpec.Builder {
if (!bindingVersion.isDeprecated && replaceWith != null) {
addAnnotation(
AnnotationSpec
.builder(Deprecated::class.asClassName())
Expand Down Expand Up @@ -531,15 +555,63 @@ private fun ParameterSpec.Builder.defaultValueIfNullable(
return this
}

private fun TypeSpec.Builder.addInitializerBlockIfNecessary(
private fun TypeSpec.Builder.addInitializerBlock(
metadata: Metadata,
bindingVersion: BindingVersion,
coords: ActionCoords,
inputTypings: Map<String, Typing>,
untypedClass: Boolean,
): TypeSpec.Builder {
if (untypedClass || metadata.inputs.isEmpty() || metadata.inputs.none { inputTypings.containsKey(it.key) }) {
if (!bindingVersion.isDeprecated &&
!bindingVersion.isExperimental &&
(untypedClass || metadata.inputs.isEmpty() || metadata.inputs.none { inputTypings.containsKey(it.key) })
) {
return this
}
addInitializerBlock(metadata.initializerBlock(inputTypings))

addInitializerBlock(
buildCodeBlock {
if (bindingVersion.isDeprecated) {
val firstStableVersion = BindingVersion.entries.find { !it.isDeprecated && !it.isExperimental }
addStatement(
"println(%S)",
"""
WARNING: The used binding version $bindingVersion for ${coords.prettyPrint} is deprecated! First stable version is $firstStableVersion.
""".trimIndent(),
)
beginControlFlow("""if (System.getenv("GITHUB_ACTIONS").toBoolean())""")
addStatement(
"println(%S)",
"""

::warning title=Deprecated Binding Version Used::The used binding version $bindingVersion for ${coords.prettyPrint} is deprecated! First stable version is $firstStableVersion.
""".trimIndent(),
)
endControlFlow()
add("\n")
}
if (bindingVersion.isExperimental) {
val lastStableVersion = BindingVersion.entries.findLast { !it.isDeprecated && !it.isExperimental }
addStatement(
"println(%S)",
"""
WARNING: The used binding version $bindingVersion for ${coords.prettyPrint} is experimental! Last stable version is $lastStableVersion.
""".trimIndent(),
)
beginControlFlow("""if (System.getenv("GITHUB_ACTIONS").toBoolean())""")
addStatement(
"println(%S)",
"""

::warning title=Experimental Binding Version Used::The used binding version $bindingVersion for ${coords.prettyPrint} is experimental! Last stable version is $lastStableVersion.
""".trimIndent(),
)
endControlFlow()
add("\n")
}
add(metadata.initializerBlock(inputTypings))
},
)
return this
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.typesafegithub.workflows.actionbindinggenerator.versioning

public enum class BindingVersion(
public val isDeprecated: Boolean = false,
public val isExperimental: Boolean = true,
public val libraryVersion: String,
) {
V1(isExperimental = false, libraryVersion = "3.2.0"),
;

override fun toString(): String = super.toString().lowercase()
}
Loading
Loading