From 779b608c0ada051d2bda247efc8f61dd1297b307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kautler?= Date: Mon, 19 Aug 2024 16:01:37 +0200 Subject: [PATCH] feat(abg): allow usage of version ranges by generating only major or minor version even with more detailed version --- .../domain/ActionCoords.kt | 14 ++-- .../generation/ClassNaming.kt | 2 +- .../generation/Generation.kt | 21 +++-- .../metadata/MetadataReading.kt | 14 +--- .../actionbindinggenerator/utils/TextUtils.kt | 2 +- .../ActionWithNoInputsWithMajorVersion.kt | 55 +++++++++++++ ...ionWithNoInputsWithMajorVersion_Untyped.kt | 80 +++++++++++++++++++ .../ActionWithNoInputsWithMinorVersion.kt | 55 +++++++++++++ ...ionWithNoInputsWithMinorVersion_Untyped.kt | 80 +++++++++++++++++++ .../generation/ClassNamingTest.kt | 5 +- .../generation/GenerationTest.kt | 54 +++++++++++++ .../typing/TypesProvidingTest.kt | 18 ++--- docs/user-guide/using-actions.md | 18 +++++ .../workflows/mavenbinding/JarBuilding.kt | 27 +------ .../mavenbinding/MavenMetadataBuilding.kt | 8 +- .../workflows/mavenbinding/PomBuilding.kt | 2 +- .../mavenbinding/VersionArtifactsBuilding.kt | 2 +- 17 files changed, 393 insertions(+), 64 deletions(-) create mode 100644 action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMajorVersion.kt create mode 100644 action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMajorVersion_Untyped.kt create mode 100644 action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMinorVersion.kt create mode 100644 action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMinorVersion_Untyped.kt diff --git a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords.kt b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords.kt index 30f4ad88c6..8392c8fff5 100644 --- a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords.kt +++ b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords.kt @@ -11,24 +11,28 @@ public data class ActionCoords( * A top-level action is an action with its `action.y(a)ml` file in the repository root, as opposed to actions stored * in subdirectories. */ -public val ActionCoords.isTopLevel: Boolean get() = "/" !in name +public val ActionCoords.isTopLevel: Boolean get() = "__" !in name.substringBefore("___") -public val ActionCoords.prettyPrint: String get() = "$owner/$name@$version${typesUuid?.let { " (types: $it)" } ?: ""}" +public val ActionCoords.prettyPrint: String + get() = "$owner/${ + name.replace("___", " with ").replace("__", "/") + }@$version${typesUuid?.let { " (types: $it)" } ?: ""}" /** * For most actions, it's the same as [ActionCoords.name]. * For actions that aren't executed from the root of the repo, it returns the repo name. */ public val ActionCoords.repoName: String get() = - name.substringBefore("/") + name.substringBefore("__") /** * For most actions, it's empty. * For actions that aren't executed from the root of the repo, it returns the path relative to the repo root where the * action lives. */ -public val ActionCoords.subName: String get() = - if (isTopLevel) "" else "/${name.substringAfter("/")}" +public val ActionCoords.subName: String + get() = + if (isTopLevel) "" else "/${name.substringAfter("__").substringBefore("___").replace("__", "/")}" internal fun String.toActionCoords(): ActionCoords { val (ownerAndName, version) = this.split('@') diff --git a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/ClassNaming.kt b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/ClassNaming.kt index 2d988e4fc6..ba68c602ea 100644 --- a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/ClassNaming.kt +++ b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/ClassNaming.kt @@ -3,4 +3,4 @@ package io.github.typesafegithub.workflows.actionbindinggenerator.generation import io.github.typesafegithub.workflows.actionbindinggenerator.domain.ActionCoords import io.github.typesafegithub.workflows.actionbindinggenerator.utils.toPascalCase -internal fun ActionCoords.buildActionClassName(): String = this.name.toPascalCase() +internal fun ActionCoords.buildActionClassName(): String = this.name.substringBefore("___").toPascalCase() 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 d6575c0849..5520214535 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 @@ -17,6 +17,9 @@ import com.squareup.kotlinpoet.asTypeName import io.github.typesafegithub.workflows.actionbindinggenerator.domain.ActionCoords import io.github.typesafegithub.workflows.actionbindinggenerator.domain.MetadataRevision import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource +import io.github.typesafegithub.workflows.actionbindinggenerator.domain.isTopLevel +import io.github.typesafegithub.workflows.actionbindinggenerator.domain.repoName +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 import io.github.typesafegithub.workflows.actionbindinggenerator.metadata.Input @@ -419,10 +422,20 @@ private fun TypeSpec.Builder.inheritsFromRegularAction( return this .superclass(superclass) .addSuperclassConstructorParameter("%S", coords.owner) - .addSuperclassConstructorParameter("%S", coords.name) - .addSuperclassConstructorParameter("_customVersion ?: %S", coords.version) + .addSuperclassConstructorParameter("%S", coords.name.substringBefore("___").replace("__", "/")) + .addSuperclassConstructorParameter( + "_customVersion ?: %S", + when { + coords.name.endsWith("___major") -> coords.version.majorVersion + coords.name.endsWith("___minor") -> coords.version.minorVersion + else -> coords.version + }, + ) } +private val String.majorVersion get() = substringBefore('.') +private val String.minorVersion get() = split('.', limit = 3).take(2).joinToString(".") + private fun Metadata.primaryConstructor( inputTypings: Map, coords: ActionCoords, @@ -624,9 +637,7 @@ private fun actionKdoc( | |${metadata.description.escapedForComments.removeTrailingWhitespacesForEachLine()} | - |[Action on GitHub](https://github.com/${coords.owner}/${coords.name.substringBefore( - '/', - )}${if ("/" in coords.name) "/tree/${coords.version}/${coords.name.substringAfter('/')}" else ""}) + |[Action on GitHub](https://github.com/${coords.owner}/${coords.repoName}${if (!coords.isTopLevel) "/tree/${coords.version}${coords.subName}" else ""}) """.trimMargin() private fun Map?.getInputTyping(key: String) = this?.get(key) ?: StringTyping diff --git a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/metadata/MetadataReading.kt b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/metadata/MetadataReading.kt index c2fb7ece84..08080ad88c 100644 --- a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/metadata/MetadataReading.kt +++ b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/metadata/MetadataReading.kt @@ -5,6 +5,8 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.domain.ActionCo import io.github.typesafegithub.workflows.actionbindinggenerator.domain.CommitHash import io.github.typesafegithub.workflows.actionbindinggenerator.domain.MetadataRevision import io.github.typesafegithub.workflows.actionbindinggenerator.domain.NewestForVersion +import io.github.typesafegithub.workflows.actionbindinggenerator.domain.repoName +import io.github.typesafegithub.workflows.actionbindinggenerator.domain.subName import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import java.io.IOException @@ -35,17 +37,9 @@ public data class Output( val description: String = "", ) -private fun ActionCoords.actionYmlUrl(gitRef: String) = - "https://raw.githubusercontent.com/$owner/${name.substringBefore( - '/', - )}/$gitRef/${if ("/" in name) "${name.substringAfter('/')}/" else ""}action.yml" +private fun ActionCoords.actionYmlUrl(gitRef: String) = "https://raw.githubusercontent.com/$owner/$repoName/$gitRef$subName/action.yml" -private fun ActionCoords.actionYamlUrl(gitRef: String) = - "https://raw.githubusercontent.com/$owner/${name.substringBefore( - '/', - )}/$gitRef/${if ("/" in name) "${name.substringAfter('/')}/" else ""}action.yaml" - -internal val ActionCoords.gitHubUrl: String get() = "https://github.com/$owner/$name" +private fun ActionCoords.actionYamlUrl(gitRef: String) = "https://raw.githubusercontent.com/$owner/$repoName/$gitRef$subName/action.yaml" public fun ActionCoords.fetchMetadata( metadataRevision: MetadataRevision, diff --git a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/utils/TextUtils.kt b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/utils/TextUtils.kt index 0afd594faf..c3e5b86154 100644 --- a/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/utils/TextUtils.kt +++ b/action-binding-generator/src/main/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/utils/TextUtils.kt @@ -7,7 +7,7 @@ internal fun String.toPascalCase(): String { val normalizedString = if (hasOnlyUppercases) lowercase() else this return normalizedString .replace("+", "-plus-") - .split("-", "_", " ", ".", "/") + .split("-", "_", " ", ".", "/", "__") .joinToString("") { it.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } } diff --git a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMajorVersion.kt b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMajorVersion.kt new file mode 100644 index 0000000000..1359c05b84 --- /dev/null +++ b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMajorVersion.kt @@ -0,0 +1,55 @@ +// This file was generated using action-binding-generator. Don't change it by hand, otherwise your +// changes will be overwritten with the next binding code regeneration. +// See https://github.com/typesafegithub/github-workflows-kt for more info. +@file:Suppress( + "DataClassPrivateConstructor", + "UNUSED_PARAMETER", +) + +package io.github.typesafegithub.workflows.actions.johnsmith + +import io.github.typesafegithub.workflows.domain.actions.Action +import io.github.typesafegithub.workflows.domain.actions.RegularAction +import java.util.LinkedHashMap +import kotlin.ExposedCopyVisibility +import kotlin.String +import kotlin.Suppress +import kotlin.Unit +import kotlin.collections.Map + +/** + * Action: Action With No Inputs + * + * Description + * + * [Action on GitHub](https://github.com/john-smith/action-with-no-inputs-with-major-version) + * + * @param _customInputs Type-unsafe map where you can put any inputs that are not yet supported by + * the binding + * @param _customVersion Allows overriding action's version, for example to use a specific minor + * version, or a newer version that the binding doesn't yet know about + */ +@ExposedCopyVisibility +public data class ActionWithNoInputsWithMajorVersion private constructor( + /** + * Type-unsafe map where you can put any inputs that are not yet supported by the binding + */ + public val _customInputs: Map = mapOf(), + /** + * Allows overriding action's version, for example to use a specific minor version, or a newer + * version that the binding doesn't yet know about + */ + public val _customVersion: String? = null, +) : RegularAction("john-smith", "action-with-no-inputs-with-major-version", + _customVersion ?: "v3") { + public constructor( + vararg pleaseUseNamedArguments: Unit, + _customInputs: Map = mapOf(), + _customVersion: String? = null, + ) : this(_customInputs = _customInputs, _customVersion = _customVersion) + + @Suppress("SpreadOperator") + override fun toYamlArguments(): LinkedHashMap = LinkedHashMap(_customInputs) + + override fun buildOutputObject(stepId: String): Action.Outputs = Outputs(stepId) +} diff --git a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMajorVersion_Untyped.kt b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMajorVersion_Untyped.kt new file mode 100644 index 0000000000..4298712831 --- /dev/null +++ b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMajorVersion_Untyped.kt @@ -0,0 +1,80 @@ +// This file was generated using action-binding-generator. Don't change it by hand, otherwise your +// changes will be overwritten with the next binding code regeneration. +// See https://github.com/typesafegithub/github-workflows-kt for more info. +@file:Suppress( + "DataClassPrivateConstructor", + "UNUSED_PARAMETER", +) + +package io.github.typesafegithub.workflows.actions.johnsmith + +import io.github.typesafegithub.workflows.domain.actions.Action +import io.github.typesafegithub.workflows.domain.actions.RegularAction +import java.util.LinkedHashMap +import kotlin.Deprecated +import kotlin.ExposedCopyVisibility +import kotlin.String +import kotlin.Suppress +import kotlin.Unit +import kotlin.collections.Map + +/** + * ```text + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * !!! WARNING !!! + * !!! !!! + * !!! This action binding has no typings provided. All inputs will !!! + * !!! have a default type of String. !!! + * !!! To be able to use this action in a type-safe way, ask the !!! + * !!! action's owner to provide the typings using !!! + * !!! !!! + * !!! https://github.com/typesafegithub/github-actions-typing !!! + * !!! !!! + * !!! or if it's impossible, contribute typings to a community-driven !!! + * !!! !!! + * !!! https://github.com/typesafegithub/github-actions-typing-catalog !!! + * !!! !!! + * !!! This '_Untyped' binding will be available even once the typings !!! + * !!! are added. !!! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ``` + * + * Action: Action With No Inputs + * + * Description + * + * [Action on GitHub](https://github.com/john-smith/action-with-no-inputs-with-major-version) + * + * @param _customInputs Type-unsafe map where you can put any inputs that are not yet supported by + * the binding + * @param _customVersion Allows overriding action's version, for example to use a specific minor + * version, or a newer version that the binding doesn't yet know about + */ +@Deprecated( + "Use the typed class instead", + ReplaceWith("ActionWithNoInputsWithMajorVersion"), +) +@ExposedCopyVisibility +public data class ActionWithNoInputsWithMajorVersion_Untyped private constructor( + /** + * Type-unsafe map where you can put any inputs that are not yet supported by the binding + */ + public val _customInputs: Map = mapOf(), + /** + * Allows overriding action's version, for example to use a specific minor version, or a newer + * version that the binding doesn't yet know about + */ + public val _customVersion: String? = null, +) : RegularAction("john-smith", "action-with-no-inputs-with-major-version", + _customVersion ?: "v3") { + public constructor( + vararg pleaseUseNamedArguments: Unit, + _customInputs: Map = mapOf(), + _customVersion: String? = null, + ) : this(_customInputs = _customInputs, _customVersion = _customVersion) + + @Suppress("SpreadOperator") + override fun toYamlArguments(): LinkedHashMap = LinkedHashMap(_customInputs) + + override fun buildOutputObject(stepId: String): Action.Outputs = Outputs(stepId) +} diff --git a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMinorVersion.kt b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMinorVersion.kt new file mode 100644 index 0000000000..714c31456e --- /dev/null +++ b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMinorVersion.kt @@ -0,0 +1,55 @@ +// This file was generated using action-binding-generator. Don't change it by hand, otherwise your +// changes will be overwritten with the next binding code regeneration. +// See https://github.com/typesafegithub/github-workflows-kt for more info. +@file:Suppress( + "DataClassPrivateConstructor", + "UNUSED_PARAMETER", +) + +package io.github.typesafegithub.workflows.actions.johnsmith + +import io.github.typesafegithub.workflows.domain.actions.Action +import io.github.typesafegithub.workflows.domain.actions.RegularAction +import java.util.LinkedHashMap +import kotlin.ExposedCopyVisibility +import kotlin.String +import kotlin.Suppress +import kotlin.Unit +import kotlin.collections.Map + +/** + * Action: Action With No Inputs + * + * Description + * + * [Action on GitHub](https://github.com/john-smith/action-with-no-inputs-with-minor-version) + * + * @param _customInputs Type-unsafe map where you can put any inputs that are not yet supported by + * the binding + * @param _customVersion Allows overriding action's version, for example to use a specific minor + * version, or a newer version that the binding doesn't yet know about + */ +@ExposedCopyVisibility +public data class ActionWithNoInputsWithMinorVersion private constructor( + /** + * Type-unsafe map where you can put any inputs that are not yet supported by the binding + */ + public val _customInputs: Map = mapOf(), + /** + * Allows overriding action's version, for example to use a specific minor version, or a newer + * version that the binding doesn't yet know about + */ + public val _customVersion: String? = null, +) : RegularAction("john-smith", "action-with-no-inputs-with-minor-version", + _customVersion ?: "v3.1") { + public constructor( + vararg pleaseUseNamedArguments: Unit, + _customInputs: Map = mapOf(), + _customVersion: String? = null, + ) : this(_customInputs = _customInputs, _customVersion = _customVersion) + + @Suppress("SpreadOperator") + override fun toYamlArguments(): LinkedHashMap = LinkedHashMap(_customInputs) + + override fun buildOutputObject(stepId: String): Action.Outputs = Outputs(stepId) +} diff --git a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMinorVersion_Untyped.kt b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMinorVersion_Untyped.kt new file mode 100644 index 0000000000..a5d3ea68d1 --- /dev/null +++ b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/bindingsfromunittests/ActionWithNoInputsWithMinorVersion_Untyped.kt @@ -0,0 +1,80 @@ +// This file was generated using action-binding-generator. Don't change it by hand, otherwise your +// changes will be overwritten with the next binding code regeneration. +// See https://github.com/typesafegithub/github-workflows-kt for more info. +@file:Suppress( + "DataClassPrivateConstructor", + "UNUSED_PARAMETER", +) + +package io.github.typesafegithub.workflows.actions.johnsmith + +import io.github.typesafegithub.workflows.domain.actions.Action +import io.github.typesafegithub.workflows.domain.actions.RegularAction +import java.util.LinkedHashMap +import kotlin.Deprecated +import kotlin.ExposedCopyVisibility +import kotlin.String +import kotlin.Suppress +import kotlin.Unit +import kotlin.collections.Map + +/** + * ```text + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * !!! WARNING !!! + * !!! !!! + * !!! This action binding has no typings provided. All inputs will !!! + * !!! have a default type of String. !!! + * !!! To be able to use this action in a type-safe way, ask the !!! + * !!! action's owner to provide the typings using !!! + * !!! !!! + * !!! https://github.com/typesafegithub/github-actions-typing !!! + * !!! !!! + * !!! or if it's impossible, contribute typings to a community-driven !!! + * !!! !!! + * !!! https://github.com/typesafegithub/github-actions-typing-catalog !!! + * !!! !!! + * !!! This '_Untyped' binding will be available even once the typings !!! + * !!! are added. !!! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ``` + * + * Action: Action With No Inputs + * + * Description + * + * [Action on GitHub](https://github.com/john-smith/action-with-no-inputs-with-minor-version) + * + * @param _customInputs Type-unsafe map where you can put any inputs that are not yet supported by + * the binding + * @param _customVersion Allows overriding action's version, for example to use a specific minor + * version, or a newer version that the binding doesn't yet know about + */ +@Deprecated( + "Use the typed class instead", + ReplaceWith("ActionWithNoInputsWithMinorVersion"), +) +@ExposedCopyVisibility +public data class ActionWithNoInputsWithMinorVersion_Untyped private constructor( + /** + * Type-unsafe map where you can put any inputs that are not yet supported by the binding + */ + public val _customInputs: Map = mapOf(), + /** + * Allows overriding action's version, for example to use a specific minor version, or a newer + * version that the binding doesn't yet know about + */ + public val _customVersion: String? = null, +) : RegularAction("john-smith", "action-with-no-inputs-with-minor-version", + _customVersion ?: "v3.1") { + public constructor( + vararg pleaseUseNamedArguments: Unit, + _customInputs: Map = mapOf(), + _customVersion: String? = null, + ) : this(_customInputs = _customInputs, _customVersion = _customVersion) + + @Suppress("SpreadOperator") + override fun toYamlArguments(): LinkedHashMap = LinkedHashMap(_customInputs) + + override fun buildOutputObject(stepId: String): Action.Outputs = Outputs(stepId) +} diff --git a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/ClassNamingTest.kt b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/ClassNamingTest.kt index f543792a31..2738f6bd4f 100644 --- a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/ClassNamingTest.kt +++ b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/generation/ClassNamingTest.kt @@ -9,8 +9,9 @@ class ClassNamingTest : context("buildActionClassName") { listOf( ActionCoords("irrelevant", "some-action-name", "v2") to "SomeActionName", - ActionCoords("irrelevant", "some-action-name/subaction", "v2") to "SomeActionNameSubaction", - ActionCoords("irrelevant", "some-action-name/foo/bar/baz", "v2") to "SomeActionNameFooBarBaz", + ActionCoords("irrelevant", "some-action-name__subaction", "v2") to "SomeActionNameSubaction", + ActionCoords("irrelevant", "some-action-name__foo__bar__baz", "v2") to "SomeActionNameFooBarBaz", + ActionCoords("irrelevant", "some-action-name__foo__bar__baz___major", "v2") to "SomeActionNameFooBarBaz", ).forEach { (input, output) -> test("should get '$input' and produce '$output'") { input.buildActionClassName() shouldBe output 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 4e08800962..daec25c4d6 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 @@ -479,6 +479,60 @@ class GenerationTest : binding.shouldContainAndMatchFile("ActionWithPartlyTypings_Untyped.kt") } } + + test("action with no inputs with major version") { + // given + val actionManifestHasNoInputs = emptyMap() + val actionManifest = + Metadata( + inputs = actionManifestHasNoInputs, + name = "Action With No Inputs", + description = "Description", + ) + + val coords = ActionCoords("john-smith", "action-with-no-inputs-with-major-version___major", "v3.1.3") + + // when + val binding = + coords.generateBinding( + metadataRevision = NewestForVersion, + metadata = actionManifest, + inputTypings = Pair(emptyMap(), ACTION), + ) + + // then + assertSoftly { + binding.shouldContainAndMatchFile("ActionWithNoInputsWithMajorVersion.kt") + binding.shouldContainAndMatchFile("ActionWithNoInputsWithMajorVersion_Untyped.kt") + } + } + + test("action with no inputs with minor version") { + // given + val actionManifestHasNoInputs = emptyMap() + val actionManifest = + Metadata( + inputs = actionManifestHasNoInputs, + name = "Action With No Inputs", + description = "Description", + ) + + val coords = ActionCoords("john-smith", "action-with-no-inputs-with-minor-version___minor", "v3.1.3") + + // when + val binding = + coords.generateBinding( + metadataRevision = NewestForVersion, + metadata = actionManifest, + inputTypings = Pair(emptyMap(), ACTION), + ) + + // then + assertSoftly { + binding.shouldContainAndMatchFile("ActionWithNoInputsWithMinorVersion.kt") + binding.shouldContainAndMatchFile("ActionWithNoInputsWithMinorVersion_Untyped.kt") + } + } }) private fun Metadata.allInputsAsStrings(): Map = this.inputs.mapValues { StringTyping } diff --git a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/typing/TypesProvidingTest.kt b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/typing/TypesProvidingTest.kt index ea1a113db5..edd7ebd55a 100644 --- a/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/typing/TypesProvidingTest.kt +++ b/action-binding-generator/src/test/kotlin/io/github/typesafegithub/workflows/actionbindinggenerator/typing/TypesProvidingTest.kt @@ -133,7 +133,7 @@ class TypesProvidingTest : else -> throw IOException() } } - val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3") + val actionCoord = ActionCoords("some-owner", "some-name__some-sub", "v3") // When val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri) @@ -170,7 +170,7 @@ class TypesProvidingTest : else -> throw IOException() } } - val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3") + val actionCoord = ActionCoords("some-owner", "some-name__some-sub", "v3") // When val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri) @@ -212,7 +212,7 @@ class TypesProvidingTest : else -> throw IOException() } } - val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3") + val actionCoord = ActionCoords("some-owner", "some-name__some-sub", "v3") // When val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri) @@ -254,7 +254,7 @@ class TypesProvidingTest : else -> throw IOException() } } - val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3") + val actionCoord = ActionCoords("some-owner", "some-name__some-sub", "v3") // When val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri) @@ -306,7 +306,7 @@ class TypesProvidingTest : else -> throw IOException() } } - val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3") + val actionCoord = ActionCoords("some-owner", "some-name__some-sub", "v3") // When val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri) @@ -330,7 +330,7 @@ class TypesProvidingTest : test("only custom for subaction") { // Given val fetchUri: (URI) -> String = { throw IOException() } - val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3") + val actionCoord = ActionCoords("some-owner", "some-name__some-sub", "v3") // When val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = custom) @@ -382,7 +382,7 @@ class TypesProvidingTest : else -> throw IOException() } } - val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3") + val actionCoord = ActionCoords("some-owner", "some-name__some-sub", "v3") // When val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = custom) @@ -434,7 +434,7 @@ class TypesProvidingTest : else -> throw IOException() } } - val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v3") + val actionCoord = ActionCoords("some-owner", "some-name__some-sub", "v3") // When val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = "") @@ -486,7 +486,7 @@ class TypesProvidingTest : else -> throw IOException() } } - val actionCoord = ActionCoords("some-owner", "some-name/some-sub", "v6") + val actionCoord = ActionCoords("some-owner", "some-name__some-sub", "v6") // When val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri) diff --git a/docs/user-guide/using-actions.md b/docs/user-guide/using-actions.md index b20076d918..7cd8c6b228 100644 --- a/docs/user-guide/using-actions.md +++ b/docs/user-guide/using-actions.md @@ -17,6 +17,24 @@ To add a dependency on an action: corresponding to a released version). If an action's manifest is defined in a subdirectory, like the popular `gradle/actions/setup-gradle@v3`, replace the slashes in the action name with `__`, so in this case it would be `@file:DependsOn("gradle:actions__setup-gradle:v3")`. + + Additionally, the name part can have the suffix `___major` or `___minor`. Without these suffixes if you request + a version `v1.2.3`, the generated YAML will also use exactly `v1.2.3` unless you use a custom version override. + with the `___major` suffix, it would only write `v1` to the generated YAML, with the `___minor` suffix `v1.2`. + + This is especially useful when combined with a version range. The problem with using `v1` or `v1.2` is, that for + GitHub actions these are changing tags or changing branches and not static releases. But in the Maven world + a version that does not end in `-SNAPSHOT` is considered immutable and is not expected to change. This means that + if a new version of the action is released that adds a new input, you cannot use it easily as you still have the old + `v1` artifact in your Maven cache and it will not be updated usually, even though the binding server provides a new + binding including the added input. + + To mitigate this problem you can for example use a dependency like `gradle/actions/setup-gradle___major@[v3,v4)`. + This will resolve to the latest `v3.x.y` version and thus include any newly added inputs, but still only write `v3` + to the YAML. Without the `___major` suffix or a not semantically matching range like `[v3,v5)` or even `[v3,v4]` you + will get problems with the consistency check as then the YAML output changes as soon as a new version is released. + For a minor version you would accordingly use the `___minor` suffix together with a range like `[v4.0,v4.1)` to get + the latest `v4.0` release if the action in question provides such a tag or branch. 3. Use the action by importing a class like `io.github.typesafegithub.workflows.actions.actions.Checkout`. For every action, a binding will be generated. However, some less popular actions don't have typings configured for diff --git a/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/JarBuilding.kt b/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/JarBuilding.kt index 5ad7082666..56613a9e36 100644 --- a/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/JarBuilding.kt +++ b/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/JarBuilding.kt @@ -26,14 +26,9 @@ internal data class Jars( val sourcesJar: ByteArray, ) -internal fun buildJars( - owner: String, - name: String, - version: String, - types: String?, -): Jars? { +internal fun ActionCoords.buildJars(types: String?): Jars? { val binding = - generateBinding(owner = owner, name = name, version = version, types = types).also { + generateBinding(metadataRevision = NewestForVersion, types = types).also { if (it.isEmpty()) return null } val (sourceFilePaths, compilationInputDir) = binding.prepareDirectoryWithSources() @@ -51,24 +46,6 @@ internal fun buildJars( ) } -private fun generateBinding( - owner: String, - name: String, - version: String, - types: String?, -): List { - val actionCoords = - ActionCoords( - owner = owner, - name = name, - version = version, - ) - return actionCoords.generateBinding( - metadataRevision = NewestForVersion, - types = types, - ) -} - private fun compileBinding(sourceFilePaths: List): Path { val compilationOutput = createTempDirectory() diff --git a/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/MavenMetadataBuilding.kt b/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/MavenMetadataBuilding.kt index d7473eea77..46c4eeffb1 100644 --- a/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/MavenMetadataBuilding.kt +++ b/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/MavenMetadataBuilding.kt @@ -12,10 +12,10 @@ internal suspend fun ActionCoords.buildMavenMetadataFile(githubToken: String): S .ofPattern("yyyyMMddHHmmss") .withZone(ZoneId.systemDefault()) .format(Instant.now()) - val availableMajorVersions = + val availableVersions = fetchAvailableVersions(owner = owner, name = name.substringBefore("__"), githubToken = githubToken) - .filter { it.isMajorVersion() } - val newest = availableMajorVersions.max() + .filter { it.isMajorVersion() || name.endsWith("___major") || name.endsWith("___minor") } + val newest = availableVersions.max() return """ @@ -25,7 +25,7 @@ internal suspend fun ActionCoords.buildMavenMetadataFile(githubToken: String): S $newest $newest -${availableMajorVersions.joinToString(separator = "\n") { +${availableVersions.joinToString(separator = "\n") { " $it" }} diff --git a/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/PomBuilding.kt b/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/PomBuilding.kt index 965b62f154..e21ad08b79 100644 --- a/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/PomBuilding.kt +++ b/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/PomBuilding.kt @@ -6,7 +6,7 @@ internal const val LATEST_RELASED_LIBRARY_VERSION = "3.0.0" internal fun ActionCoords.buildPomFile(): String { val nameForRepo = name.substringBefore("__") - val nameForDisplay = name.replace("__", "/") + val nameForDisplay = name.replace("___", " with ").replace("__", "/") return """ diff --git a/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/VersionArtifactsBuilding.kt b/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/VersionArtifactsBuilding.kt index ded2045d3c..1ca3f4e422 100644 --- a/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/VersionArtifactsBuilding.kt +++ b/maven-binding-builder/src/main/kotlin/io/github/typesafegithub/workflows/mavenbinding/VersionArtifactsBuilding.kt @@ -14,7 +14,7 @@ data class JarArtifact( ) : Artifact fun ActionCoords.buildVersionArtifacts(types: String? = null): Map? { - val jars = buildJars(owner = owner, name = name.replace("__", "/"), version = version, types = types) ?: return null + val jars = buildJars(types = types) ?: return null val pom = buildPomFile() val module = buildModuleFile() return mapOf(