diff --git a/.github/workflows/README.adoc b/.github/workflows/README.adoc new file mode 100644 index 0000000000..e3ad8dffc6 --- /dev/null +++ b/.github/workflows/README.adoc @@ -0,0 +1,91 @@ +== The YAML workflow files vs. the `*.main.kts` files + +The YAML workflow files are generated from the `*.main.kts` files. + +These use the https://github.com/typesafegithub/github-workflows-kt[github-workflows-kt] +Kotlin DSL library to conveniently and type-safely write GitHub Action workflow files. + +As there is no official built-in support in GitHub Actions yet until +https://github.com/orgs/community/discussions/15904 is considered, the YAML files +need to be generated manually. + +There is a safeguard check in all the generated files that this is not forgotten. +Running a workflow where the according `*.main.kts` produces a different output will +fail the execution. Additionally, the workflow that runs for pull requests checks +the consistency of all the YAML files as not all are run for pull requests. + + + +== Ways to generate the YAML workflow files + +There are multiple ways to generate the YAML files and all of them are fine: + +* If you are in a `sh` derivate like e.g. `bash` and Kotlin is installed and + available in the `PATH`, you can just call the `*.main.kts` script like any + other shell script: ++ +[source,bash] +---- +$ ./release.main.kts +---- + +* If Kotlin is installed somewhere you can call it with the `*.main.kts` script + as argument: ++ +[source,bash] +---- +$ path/to/kotlin release.main.kts +---- + +* From the IDE you can create a run configuration that executes the `*.main.kts` script. + +* There is a Gradle task `preprocessWorkflows` that generates all YAML files from the + according `*.main.kts` files. Additionally, there is also one task per workflow to + only generate that one: ++ +[source,bash] +---- +$ ./gradlew preprocessReleaseWorkflow +$ ./gradlew preprocessWorkflows +---- + + + +== Caveats + +There are currently three known caveats with the approach we follow. + +* https://youtrack.jetbrains.com/issue/KTIJ-16532 ++ +If you navigate to a file in the dependencies, only a decompiled file is opened, +even though the source JAR would be available. Also the quick documentation is missing. ++ +This can easily by mitigated by attaching the library to the normal project +dependencies while having the need to navigate the source files or while editing them, +which makes them properly viewable and documentation displayable in the editor. + +* https://youtrack.jetbrains.com/issue/KTIJ-14580 ++ +We use `@file:Import` to reduce code duplication by having common code in a common file. +Unfortunately, this triggers a Kotlin IntelliJ plugin bug where the imported file cannot +be loaded properly and so the things supplied by it like dependencies or common functions +are not available. This makes most of the workflow `*.main.kts` files red as hell in the +IDE currently. ++ +To reduce risk for eye-cancer while reading the `*.main.kts` scripts or to be able to +sanely edit them, temporarily add the `@file:DependsOn` from the imported file to the +importing file and wait a second, then remove the line again once you are done. + +* https://youtrack.jetbrains.com/issue/KT-42101 ++ +We use `@file:Import` to reduce code duplication by having common code in a common file. +Unfortunately, this triggers a Kotlin bug where the compilation cache becomes confused +if the imported file is changed without the importing file being changed too. ++ +If only the imported file is changed, it could happen that a old version is used, +or it could also happen that classes added by a `@file:DependsOn` in the imported file +are not available to the importing file. So if there was a change in the imported file, +you either need to also change the importing file, or to properly execute the script, +you need to delete the stale entry from the compilation cache which can be found at for example +`~/.cache/main.kts.compiled.cache/` on Linux and `%LOCALAPPDATA%\main.kts.compiled.cache\` +on Windows. Alternatively, you can also delete the whole cache directory. diff --git a/.github/workflows/branches-and-prs.main.kts b/.github/workflows/branches-and-prs.main.kts index 3e529a5ee4..d33ed5efa8 100755 --- a/.github/workflows/branches-and-prs.main.kts +++ b/.github/workflows/branches-and-prs.main.kts @@ -16,22 +16,17 @@ * limitations under the License. */ -@file:DependsOn("io.github.typesafegithub:github-workflows-kt:0.44.0") -@file:DependsOn("org.codehaus.groovy:groovy:3.0.15") +@file:Import("common.main.kts") -import groovy.lang.Binding -import groovy.lang.GroovyShell import io.github.typesafegithub.workflows.actions.actions.CheckoutV3 import io.github.typesafegithub.workflows.actions.codecov.CodecovActionV3 import io.github.typesafegithub.workflows.actions.gradle.GradleBuildActionV2 import io.github.typesafegithub.workflows.domain.Concurrency import io.github.typesafegithub.workflows.domain.RunnerType import io.github.typesafegithub.workflows.domain.RunnerType.UbuntuLatest -import io.github.typesafegithub.workflows.domain.actions.Action.Outputs -import io.github.typesafegithub.workflows.domain.actions.LocalAction import io.github.typesafegithub.workflows.domain.triggers.PullRequest import io.github.typesafegithub.workflows.domain.triggers.Push -import io.github.typesafegithub.workflows.dsl.expressions.Contexts +import io.github.typesafegithub.workflows.dsl.expressions.Contexts.github import io.github.typesafegithub.workflows.dsl.expressions.expr import io.github.typesafegithub.workflows.dsl.workflow import io.github.typesafegithub.workflows.yaml.writeToFile @@ -53,7 +48,7 @@ workflow( targetFileName = "${__FILE__.name.substringBeforeLast(".main.kts")}.yml", // https://stackoverflow.com/a/72408109/16358266 concurrency = Concurrency( - group = "${expr { github.workflow }}-${expr("${Contexts.github.eventPullRequest.pull_request.number} || ${Contexts.github.ref}")}", + group = "${expr { github.workflow }}-${expr("${github.eventPullRequest.pull_request.number} || ${github.ref}")}", cancelInProgress = true ) ) { @@ -72,38 +67,12 @@ workflow( ) } - val (javaVersions, variants) = getMatrixAxes() job( id = "build-and-verify", name = "Build and Verify", - runsOn = RunnerType.Custom(expr("matrix.os")), - _customArguments = mapOf( - "strategy" to mapOf( - "fail-fast" to false, - "matrix" to mapOf( - "os" to listOf("ubuntu-latest"), - "variant" to variants, - "java" to javaVersions, - "exclude" to javaVersions - .filter { it.toInt() >= 17 } - .map { javaVersion -> - mapOf( - "os" to "ubuntu-latest", - "variant" to "2.5", - "java" to javaVersion - ) - }, - "include" to listOf("windows-latest", "macos-latest") - .flatMap { os -> variants.map { os to it } } - .map { (os, variant) -> - mapOf( - "os" to os, - "variant" to variant, - "java" to javaVersions.first() - ) - } - ) - ) + runsOn = RunnerType.Custom(expr(Matrix.operatingSystem)), + strategy = Strategy( + matrix = Matrix.full ) ) { uses( @@ -116,12 +85,9 @@ workflow( uses( name = "Set up JDKs", action = SetupBuildEnv( - additionalJavaVersion = expr("matrix.java") + additionalJavaVersion = expr(Matrix.java) ) ) - val SPOCK_BUILD_CACHE_USERNAME by Contexts.secrets - val SPOCK_BUILD_CACHE_PASSWORD by Contexts.secrets - val GRADLE_ENTERPRISE_ACCESS_KEY by Contexts.secrets uses( name = "Build Spock", action = GradleBuildActionV2( @@ -129,16 +95,12 @@ workflow( "--no-parallel", "--stacktrace", "ghActionsBuild", - """"-Dvariant=${expr("matrix.variant")}"""", - """"-DjavaVersion=${expr("matrix.java")}"""" + """"-Dvariant=${expr(Matrix.variant)}"""", + """"-DjavaVersion=${expr(Matrix.java)}"""" ).joinToString(" ") ), // secrets are not injected for pull requests - env = linkedMapOf( - "ORG_GRADLE_PROJECT_spockBuildCacheUsername" to expr(SPOCK_BUILD_CACHE_USERNAME), - "ORG_GRADLE_PROJECT_spockBuildCachePassword" to expr(SPOCK_BUILD_CACHE_PASSWORD), - "GRADLE_ENTERPRISE_ACCESS_KEY" to expr(GRADLE_ENTERPRISE_ACCESS_KEY) - ) + env = commonCredentials ) uses( name = "Upload to Codecov.io", @@ -146,28 +108,3 @@ workflow( ) } }.writeToFile() - -data class SetupBuildEnv( - val additionalJavaVersion: String? = null -) : LocalAction("./.github/actions/setup-build-env") { - override fun toYamlArguments() = - additionalJavaVersion?.let { linkedMapOf("additional-java-version" to it) } ?: linkedMapOf() - - override fun buildOutputObject(stepId: String): Outputs = Outputs(stepId) -} - -fun getMatrixAxes(): Pair, List> { - val binding = object : Binding() { - lateinit var javaVersions: List - lateinit var variants: List - - override fun setVariable(name: String?, value: Any?) { - when (name) { - "javaVersions" -> javaVersions = (value as List).map { it.toString() } - "variants" -> variants = value as List - } - } - } - GroovyShell(binding).evaluate(__FILE__.parentFile.resolve("../../matrix.groovy")) - return binding.javaVersions to binding.variants -} diff --git a/.github/workflows/codeql-analysis.main.kts b/.github/workflows/codeql-analysis.main.kts index a614f54c7c..d51de89ded 100755 --- a/.github/workflows/codeql-analysis.main.kts +++ b/.github/workflows/codeql-analysis.main.kts @@ -16,7 +16,7 @@ * limitations under the License. */ -@file:DependsOn("io.github.typesafegithub:github-workflows-kt:0.44.0") +@file:Import("common.main.kts") import io.github.typesafegithub.workflows.actions.actions.CheckoutV3 import io.github.typesafegithub.workflows.actions.github.CodeqlActionAnalyzeV2 @@ -24,8 +24,6 @@ import io.github.typesafegithub.workflows.actions.github.CodeqlActionInitV2 import io.github.typesafegithub.workflows.actions.gradle.GradleBuildActionV2 import io.github.typesafegithub.workflows.domain.Concurrency import io.github.typesafegithub.workflows.domain.RunnerType.UbuntuLatest -import io.github.typesafegithub.workflows.domain.actions.Action -import io.github.typesafegithub.workflows.domain.actions.LocalAction import io.github.typesafegithub.workflows.domain.triggers.Cron import io.github.typesafegithub.workflows.domain.triggers.PullRequest import io.github.typesafegithub.workflows.domain.triggers.Push @@ -65,12 +63,9 @@ workflow( name = "CodeQL-Build", // CodeQL runs on UbuntuLatest, WindowsLatest, and MacOSLatest runsOn = UbuntuLatest, - _customArguments = mapOf( - "strategy" to mapOf( - "fail-fast" to false, - "matrix" to mapOf( - "variant" to listOf("2.5", "3.0", "4.0") - ) + strategy = Strategy( + matrix = Matrix( + variants = Matrix.axes.variants ) ) ) { @@ -122,7 +117,7 @@ workflow( "--stacktrace", "--no-build-cache", "testClasses", - """"-Dvariant=${expr("matrix.variant")}"""" + """"-Dvariant=${expr(Matrix.variant)}"""" ).joinToString(" ") ) ) @@ -132,12 +127,3 @@ workflow( ) } }.writeToFile() - -data class SetupBuildEnv( - val additionalJavaVersion: String? = null -) : LocalAction("./.github/actions/setup-build-env") { - override fun toYamlArguments() = - additionalJavaVersion?.let { linkedMapOf("additional-java-version" to it) } ?: linkedMapOf() - - override fun buildOutputObject(stepId: String): Outputs = Outputs(stepId) -} diff --git a/.github/workflows/common.main.kts b/.github/workflows/common.main.kts new file mode 100755 index 0000000000..eefc0020ea --- /dev/null +++ b/.github/workflows/common.main.kts @@ -0,0 +1,159 @@ +#!/usr/bin/env kotlin + +/* + * Copyright 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:DependsOn("io.github.typesafegithub:github-workflows-kt:0.44.0") + +import io.github.typesafegithub.workflows.domain.Job +import io.github.typesafegithub.workflows.domain.JobOutputs.EMPTY +import io.github.typesafegithub.workflows.domain.RunnerType +import io.github.typesafegithub.workflows.domain.actions.Action.Outputs +import io.github.typesafegithub.workflows.domain.actions.LocalAction +import io.github.typesafegithub.workflows.dsl.JobBuilder +import io.github.typesafegithub.workflows.dsl.WorkflowBuilder +import io.github.typesafegithub.workflows.dsl.expressions.Contexts.secrets +import io.github.typesafegithub.workflows.dsl.expressions.expr +import java.util.Properties + +val SPOCK_BUILD_CACHE_USERNAME by secrets +val SPOCK_BUILD_CACHE_PASSWORD by secrets +val GRADLE_ENTERPRISE_ACCESS_KEY by secrets + +val commonCredentials = linkedMapOf( + "ORG_GRADLE_PROJECT_spockBuildCacheUsername" to expr(SPOCK_BUILD_CACHE_USERNAME), + "ORG_GRADLE_PROJECT_spockBuildCachePassword" to expr(SPOCK_BUILD_CACHE_PASSWORD), + "GRADLE_ENTERPRISE_ACCESS_KEY" to expr(GRADLE_ENTERPRISE_ACCESS_KEY) +) + +data class Strategy( + val failFast: Boolean? = false, + val matrix: Matrix? = null +) { + fun toCustomArguments() = mapOf( + *listOfNotNull( + failFast?.let { "fail-fast" to failFast }, + matrix?.let { "matrix" to matrix.toCustomArguments() } + ).toTypedArray() + ) +} + +data class Matrix( + val operatingSystems: List? = null, + val variants: List? = null, + val javaVersions: List? = null, + val excludes: List>? = null, + val includes: List>? = null +) { + fun toCustomArguments() = mapOf( + *listOfNotNull( + operatingSystems?.let { "os" to operatingSystems }, + variants?.let { "variant" to variants }, + javaVersions?.let { "java" to javaVersions }, + excludes?.let { "exclude" to excludes }, + includes?.let { "include" to includes } + ).toTypedArray() + ) + + data class Axes( + val javaVersions: List, + val variants: List + ) + + companion object { + val operatingSystem = "matrix.os" + val variant = "matrix.variant" + val java = "matrix.java" + } +} + +fun WorkflowBuilder.job( + id: String, + name: String? = null, + runsOn: RunnerType, + needs: List> = emptyList(), + condition: String? = null, + strategy: Strategy? = null, + simpleStrategy: Map>? = null, + block: JobBuilder.() -> Unit +): Job = job( + id = id, + name = name, + runsOn = runsOn, + needs = needs, + condition = condition, + strategyMatrix = simpleStrategy, + _customArguments = mapOf( + *listOfNotNull( + strategy?.let { "strategy" to strategy.toCustomArguments() } + ).toTypedArray() + ), + block = block +) + +val Matrix.Companion.full + get() = Matrix( + operatingSystems = listOf("ubuntu-latest"), + variants = axes.variants, + javaVersions = axes.javaVersions, + excludes = axes.javaVersions + .filter { it.toInt() >= 17 } + .map { javaVersion -> + mapOf( + "os" to "ubuntu-latest", + "variant" to "2.5", + "java" to javaVersion + ) + }, + includes = listOf("windows-latest", "macos-latest") + .flatMap { os -> axes.variants.map { os to it } } + .map { (os, variant) -> + mapOf( + "os" to os, + "variant" to variant, + "java" to axes.javaVersions.first() + ) + } + ) + +val Matrix.Companion.axes by lazy { + Properties().let { properties -> + __FILE__ + .parentFile + .resolve("../../gradle.properties") + .inputStream() + .use { properties.load(it) } + + Matrix.Axes( + properties.getList("javaVersions"), + properties.getList("variants") + ) + } +} + +fun Properties.getList(key: String) = + getProperty(key).trim().split("""\s*+,\s*+""".toRegex()) + +data class SetupBuildEnv( + val additionalJavaVersion: String? = null +) : LocalAction("./.github/actions/setup-build-env") { + override fun toYamlArguments() = + additionalJavaVersion + ?.let { linkedMapOf("additional-java-version" to it) } + ?: linkedMapOf() + + override fun buildOutputObject(stepId: String): Outputs = Outputs(stepId) +} diff --git a/.github/workflows/gradle-wrapper-validation.main.kts b/.github/workflows/gradle-wrapper-validation.main.kts index c1de36a6b3..066f367e3a 100755 --- a/.github/workflows/gradle-wrapper-validation.main.kts +++ b/.github/workflows/gradle-wrapper-validation.main.kts @@ -16,7 +16,7 @@ * limitations under the License. */ -@file:DependsOn("io.github.typesafegithub:github-workflows-kt:0.44.0") +@file:Import("common.main.kts") import io.github.typesafegithub.workflows.actions.actions.CheckoutV3 import io.github.typesafegithub.workflows.actions.gradle.WrapperValidationActionV1 diff --git a/.github/workflows/release.main.kts b/.github/workflows/release.main.kts index f7ee4df86d..00cc2b74bd 100755 --- a/.github/workflows/release.main.kts +++ b/.github/workflows/release.main.kts @@ -16,21 +16,16 @@ * limitations under the License. */ -@file:DependsOn("io.github.typesafegithub:github-workflows-kt:0.44.0") -@file:DependsOn("org.codehaus.groovy:groovy:3.0.15") +@file:Import("common.main.kts") -import groovy.lang.Binding -import groovy.lang.GroovyShell import io.github.typesafegithub.workflows.actions.actions.CheckoutV3 import io.github.typesafegithub.workflows.actions.actions.CheckoutV3.FetchDepth import io.github.typesafegithub.workflows.actions.codecov.CodecovActionV3 import io.github.typesafegithub.workflows.actions.gradle.GradleBuildActionV2 import io.github.typesafegithub.workflows.domain.RunnerType -import io.github.typesafegithub.workflows.domain.actions.Action -import io.github.typesafegithub.workflows.domain.actions.LocalAction import io.github.typesafegithub.workflows.domain.triggers.Push -import io.github.typesafegithub.workflows.dsl.expressions.Contexts import io.github.typesafegithub.workflows.dsl.expressions.Contexts.github +import io.github.typesafegithub.workflows.dsl.expressions.Contexts.secrets import io.github.typesafegithub.workflows.dsl.expressions.expr import io.github.typesafegithub.workflows.dsl.workflow import io.github.typesafegithub.workflows.yaml.writeToFile @@ -46,47 +41,18 @@ workflow( sourceFile = __FILE__.toPath(), targetFileName = "${__FILE__.name.substringBeforeLast(".main.kts")}.yml" ) { - val GITHUB_TOKEN by Contexts.secrets - val SONATYPE_OSS_USER by Contexts.secrets - val SONATYPE_OSS_PASSWORD by Contexts.secrets - val SIGNING_GPG_PASSWORD by Contexts.secrets - val SPOCK_BUILD_CACHE_USERNAME by Contexts.secrets - val SPOCK_BUILD_CACHE_PASSWORD by Contexts.secrets - val GRADLE_ENTERPRISE_ACCESS_KEY by Contexts.secrets + val GITHUB_TOKEN by secrets + val SONATYPE_OSS_USER by secrets + val SONATYPE_OSS_PASSWORD by secrets + val SIGNING_GPG_PASSWORD by secrets - val (javaVersions, variants) = getMatrixAxes() val buildAndVerify = job( id = "build-and-verify", name = "Build and Verify", - runsOn = RunnerType.Custom(expr("matrix.os")), + runsOn = RunnerType.Custom(expr(Matrix.operatingSystem)), condition = "${github.repository} == 'spockframework/spock'", - _customArguments = mapOf( - "strategy" to mapOf( - "fail-fast" to false, - "matrix" to mapOf( - "os" to listOf("ubuntu-latest"), - "variant" to variants, - "java" to javaVersions, - "exclude" to javaVersions - .filter { it.toInt() >= 17 } - .map { javaVersion -> - mapOf( - "os" to "ubuntu-latest", - "variant" to "2.5", - "java" to javaVersion - ) - }, - "include" to listOf("windows-latest", "macos-latest") - .flatMap { os -> variants.map { os to it } } - .map { (os, variant) -> - mapOf( - "os" to os, - "variant" to variant, - "java" to javaVersions.first() - ) - } - ) - ) + strategy = Strategy( + matrix = Matrix.full ) ) { uses( @@ -99,7 +65,7 @@ workflow( uses( name = "Set up JDKs", action = SetupBuildEnv( - additionalJavaVersion = expr("matrix.java") + additionalJavaVersion = expr(Matrix.java) ) ) uses( @@ -109,16 +75,12 @@ workflow( "--no-parallel", "--stacktrace", "ghActionsBuild", - """"-Dvariant=${expr("matrix.variant")}"""", - """"-DjavaVersion=${expr("matrix.java")}"""", + """"-Dvariant=${expr(Matrix.variant)}"""", + """"-DjavaVersion=${expr(Matrix.java)}"""", "-Dscan.tag.main-build" ).joinToString(" ") ), - env = linkedMapOf( - "ORG_GRADLE_PROJECT_spockBuildCacheUsername" to expr(SPOCK_BUILD_CACHE_USERNAME), - "ORG_GRADLE_PROJECT_spockBuildCachePassword" to expr(SPOCK_BUILD_CACHE_PASSWORD), - "GRADLE_ENTERPRISE_ACCESS_KEY" to expr(GRADLE_ENTERPRISE_ACCESS_KEY) - ) + env = commonCredentials ) run( name = "Stop Daemon", @@ -132,14 +94,14 @@ workflow( val releaseSpock = job( id = "release-spock", name = "Release Spock", - runsOn = RunnerType.Custom(expr("matrix.os")), + runsOn = RunnerType.Custom(expr(Matrix.operatingSystem)), needs = listOf(buildAndVerify), strategyMatrix = mapOf( "os" to listOf("ubuntu-latest"), // publish needs to be done for all versions - "variant" to variants, + "variant" to Matrix.axes.variants, // publish needs the min supported java version - "java" to javaVersions.take(1) + "java" to Matrix.axes.javaVersions.take(1) ) ) { uses( @@ -149,7 +111,7 @@ workflow( uses( name = "Set up JDKs", action = SetupBuildEnv( - additionalJavaVersion = expr("matrix.java") + additionalJavaVersion = expr(Matrix.java) ) ) uses( @@ -159,8 +121,8 @@ workflow( "--no-parallel", "--stacktrace", "ghActionsPublish", - """"-Dvariant=${expr("matrix.variant")}"""", - """"-DjavaVersion=${expr("matrix.java")}"""", + """"-Dvariant=${expr(Matrix.variant)}"""", + """"-DjavaVersion=${expr(Matrix.java)}"""", "-Dscan.tag.main-publish" ).joinToString(" ") ), @@ -168,24 +130,21 @@ workflow( "GITHUB_TOKEN" to expr(GITHUB_TOKEN), "SONATYPE_OSS_USER" to expr(SONATYPE_OSS_USER), "SONATYPE_OSS_PASSWORD" to expr(SONATYPE_OSS_PASSWORD), - "SIGNING_PASSWORD" to expr(SIGNING_GPG_PASSWORD), - "ORG_GRADLE_PROJECT_spockBuildCacheUsername" to expr(SPOCK_BUILD_CACHE_USERNAME), - "ORG_GRADLE_PROJECT_spockBuildCachePassword" to expr(SPOCK_BUILD_CACHE_PASSWORD), - "GRADLE_ENTERPRISE_ACCESS_KEY" to expr(GRADLE_ENTERPRISE_ACCESS_KEY) - ) + "SIGNING_PASSWORD" to expr(SIGNING_GPG_PASSWORD) + ).apply { putAll(commonCredentials) } ) } job( id = "publish-release-docs", name = "Publish Release Docs", - runsOn = RunnerType.Custom(expr("matrix.os")), + runsOn = RunnerType.Custom(expr(Matrix.operatingSystem)), needs = listOf(releaseSpock), strategyMatrix = mapOf( "os" to listOf("ubuntu-latest"), // docs need the highest variant - "variant" to variants.takeLast(1), + "variant" to Matrix.axes.variants.takeLast(1), // docs need the highest java version - "java" to javaVersions.takeLast(1) + "java" to Matrix.axes.javaVersions.takeLast(1) ) ) { uses( @@ -195,7 +154,7 @@ workflow( uses( name = "Set up JDKs", action = SetupBuildEnv( - additionalJavaVersion = expr("matrix.java") + additionalJavaVersion = expr(Matrix.java) ) ) run( @@ -209,42 +168,14 @@ workflow( "--no-parallel", "--stacktrace", "ghActionsDocs", - """"-Dvariant=${expr("matrix.variant")}"""", - """"-DjavaVersion=${expr("matrix.java")}"""", + """"-Dvariant=${expr(Matrix.variant)}"""", + """"-DjavaVersion=${expr(Matrix.java)}"""", "-Dscan.tag.main-docs" ).joinToString(" ") ), env = linkedMapOf( - "GITHUB_TOKEN" to expr(GITHUB_TOKEN), - "ORG_GRADLE_PROJECT_spockBuildCacheUsername" to expr(SPOCK_BUILD_CACHE_USERNAME), - "ORG_GRADLE_PROJECT_spockBuildCachePassword" to expr(SPOCK_BUILD_CACHE_PASSWORD), - "GRADLE_ENTERPRISE_ACCESS_KEY" to expr(GRADLE_ENTERPRISE_ACCESS_KEY) - ) + "GITHUB_TOKEN" to expr(GITHUB_TOKEN) + ).apply { putAll(commonCredentials) } ) } }.writeToFile() - -data class SetupBuildEnv( - val additionalJavaVersion: String? = null -) : LocalAction("./.github/actions/setup-build-env") { - override fun toYamlArguments() = - additionalJavaVersion?.let { linkedMapOf("additional-java-version" to it) } ?: linkedMapOf() - - override fun buildOutputObject(stepId: String): Outputs = Outputs(stepId) -} - -fun getMatrixAxes(): Pair, List> { - val binding = object : Binding() { - lateinit var javaVersions: List - lateinit var variants: List - - override fun setVariable(name: String?, value: Any?) { - when (name) { - "javaVersions" -> javaVersions = (value as List).map { it.toString() } - "variants" -> variants = value as List - } - } - } - GroovyShell(binding).evaluate(__FILE__.parentFile.resolve("../../matrix.groovy")) - return binding.javaVersions to binding.variants -} diff --git a/build-logic/preprocess-workflows/preprocess-workflows.gradle b/build-logic/preprocess-workflows/preprocess-workflows.gradle index 52e46d0ce4..23aff703d6 100644 --- a/build-logic/preprocess-workflows/preprocess-workflows.gradle +++ b/build-logic/preprocess-workflows/preprocess-workflows.gradle @@ -3,6 +3,10 @@ plugins { id 'idea' } +dependencies { + implementation('org.jetbrains.kotlin:kotlin-compiler-embeddable:1.8.20') +} + gradlePlugin { plugins { preprocessWorkflowsPlugin { diff --git a/build-logic/preprocess-workflows/src/main/groovy/org/spockframework/gradle/PreprocessWorkflowsPlugin.groovy b/build-logic/preprocess-workflows/src/main/groovy/org/spockframework/gradle/PreprocessWorkflowsPlugin.groovy index a536f92f4a..07a7b270ea 100644 --- a/build-logic/preprocess-workflows/src/main/groovy/org/spockframework/gradle/PreprocessWorkflowsPlugin.groovy +++ b/build-logic/preprocess-workflows/src/main/groovy/org/spockframework/gradle/PreprocessWorkflowsPlugin.groovy @@ -23,6 +23,19 @@ import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.tasks.JavaExec import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaToolchainService +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer +import org.jetbrains.kotlin.com.intellij.openapi.vfs.local.CoreLocalFileSystem +import org.jetbrains.kotlin.com.intellij.openapi.vfs.local.CoreLocalVirtualFile +import org.jetbrains.kotlin.com.intellij.psi.PsiManager +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry +import org.jetbrains.kotlin.psi.KtStringTemplateExpression + +import static org.jetbrains.kotlin.cli.common.CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY +import static org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles.JVM_CONFIG_FILES @CompileStatic class PreprocessWorkflowsPlugin implements Plugin { @@ -47,6 +60,9 @@ class PreprocessWorkflowsPlugin implements Plugin { it.inputs .file(workflowScript) .withPropertyName('workflowScript') + it.inputs + .files(getImportedFiles(project.file(workflowScript))) + .withPropertyName("importedFiles") it.outputs .file(new File(workflowScript.parent, "${workflowName}.yml")) .withPropertyName('workflowFile') @@ -65,4 +81,45 @@ class PreprocessWorkflowsPlugin implements Plugin { } } } + + private List getImportedFiles(File workflowScript) { + if (!workflowScript.file) { + return [] + } + + return PsiManager + .getInstance( + KotlinCoreEnvironment + .createForProduction( + Disposer.newDisposable(), + new CompilerConfiguration().tap { + it.put(MESSAGE_COLLECTOR_KEY, MessageCollector.@Companion.NONE) + }, + JVM_CONFIG_FILES + ) + .project + ) + .findFile( + new CoreLocalVirtualFile( + new CoreLocalFileSystem(), + workflowScript + ) + ) + .with { it as KtFile } + .fileAnnotationList + ?.annotationEntries + ?.findAll { it.shortName?.asString() == "Import" } + *.valueArgumentList + ?.collectMany { it?.arguments ?: [] } + *.argumentExpression + ?.findAll { it instanceof KtStringTemplateExpression } + ?.collect { it as KtStringTemplateExpression } + *.entries + *.first() + ?.findAll { it instanceof KtLiteralStringTemplateEntry } + ?.collect { it as KtLiteralStringTemplateEntry } + ?.collect { new File(workflowScript.parentFile, it.text) } + ?.collectMany { getImportedFiles(it) + it } + ?: [] + } } diff --git a/build.gradle b/build.gradle index 42f954cbc0..c5da76f036 100644 --- a/build.gradle +++ b/build.gradle @@ -13,16 +13,13 @@ plugins { description = "Spock Framework" -ext.javaVersions = null -ext.variants = null -apply from: 'matrix.groovy' -variants = variants.collect { it as BigDecimal } - ext { baseVersion = "2.4" snapshotVersion = true milestone = 0 + javaVersions = javaVersions.trim().split(/\s*+,\s*+/).collect { it as int } javaVersion = (System.getProperty("javaVersion") ?: 8) as int + variants = variants.trim().split(/\s*+,\s*+/).collect { it as BigDecimal } variant = System.getProperty("variant") as BigDecimal ?: variants.first() buildScan.tag "groovy-$variant" if (variant == 2.5) { diff --git a/gradle.properties b/gradle.properties index b08bf73485..2c6d8f3ec5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,3 +19,6 @@ org.gradle.java.installations.fromEnv=JDK8,JDK11,JDK17 org.gradle.parallel=true org.gradle.caching=true + +javaVersions=8, 11, 17 +variants=2.5, 3.0, 4.0 diff --git a/matrix.groovy b/matrix.groovy deleted file mode 100644 index 202bd3dda7..0000000000 --- a/matrix.groovy +++ /dev/null @@ -1,2 +0,0 @@ -javaVersions = [8, 11, 17] // ensure that latest version is actually built on GitHub Actions, otherwise no docs get published -variants = ['2.5', '3.0', '4.0']