diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 90a655a..afa5dfa 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,6 @@ jobs: distribution: 'temurin' java-version: | 17 - 11 - name: build & publish (sonatype) env: @@ -38,6 +37,6 @@ jobs: ORG_GRADLE_PROJECT_signPwd: ${{ secrets.SIGN_PWD }} PUBLISH_USER: ${{ secrets.PUBLISH_USER }} PUBLISH_KEY: ${{ secrets.PUBLISH_KEY }} - run: ./gradlew build publishToSonatype -s + run: ./gradlew build publishToMavenCentral --stacktrace # -i -d diff --git a/build.gradle.kts b/build.gradle.kts index b57f7d3..118b941 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,43 +1,27 @@ plugins { `kotlin-dsl` - id("signing") - id("openapiprocessor.version") - id("openapiprocessor.publish") + `maven-publish` + signing + alias(libs.plugins.pubplug) alias(libs.plugins.publish) - alias(libs.plugins.nexus) alias(libs.plugins.versions) + id("compile") } -group = projectGroupId() -version = projectVersion() -extra["api"] = libs.versions.api.get() +group = "io.openapiprocessor" +version = libs.versions.project.get() -allprojects { - apply(plugin = "groovy") - - repositories { - mavenCentral() - - maven { - url = uri("https://oss.sonatype.org/content/repositories/snapshots") - content { - includeGroup("io.openapiprocessor") - } - mavenContent { - snapshotsOnly() - } - } - - java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) - } - } - } +versions { + packageName = "io.openapiprocessor.gradle" + entries = mapOf( + "version" to libs.versions.project.get(), + "api" to libs.versions.api.get() + ) +} - dependencies { - compileOnly(rootProject.libs.openapi.processor.api) - implementation(localGroovy()) +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) } } @@ -46,7 +30,6 @@ java { withSourcesJar() } -@Suppress("UnstableApiUsage") testing { suites { val test by getting(JvmTestSuite::class) { @@ -75,9 +58,14 @@ testing { } } -//tasks.updateDaemonJvm { -// jvmVersion = JavaVersion.VERSION_17 -//} +// compile groovy before kotlin +tasks.compileGroovy { + classpath = sourceSets.main.get().compileClasspath +} + +tasks.compileKotlin { + libraries.from(sourceSets.main.get().groovy.classesDirectory) +} tasks.named("testInt") { shouldRunAfter(tasks.named("test")) @@ -107,18 +95,14 @@ gradlePlugin { create("processorPlugin") { id = "io.openapiprocessor.openapi-processor" displayName = "Gradle openapi-processor plugin" - description = "plugin to run openapi-processor-*, e.g. openapi-processor-spring (requires gradle 7.0+, with gradle 5.5+ use 2021.3)" + description = "plugin to run openapi-processor-*, e.g. openapi-processor-spring (requires gradle 7.2+)" tags.set(listOf("openapi", "openapi-processor")) implementationClass = "io.openapiprocessor.gradle.OpenApiProcessorPlugin" } } } -nexusPublishing { - repositories { - sonatype { - username = getPublishUser() - password = getPublishKey() - } - } +publishingCentral { + deploymentName = "gradle" + waitFor = "VALIDATED" } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8c09a5d..2d217d7 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -2,24 +2,7 @@ plugins { `kotlin-dsl` } -repositories { - mavenCentral() - maven { - url = uri("https://plugins.gradle.org/m2/") - } -} - dependencies { // catalog hack: https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 // compileOnly(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) } - -gradlePlugin { - plugins { - create("VersionPlugin") { - id = "openapiprocessor.version" - implementationClass = "VersionPlugin" - } - } -} - diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index b5a0fab..6a010f9 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -1,7 +1,29 @@ +rootProject.name = "buildSrc" + +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() +// maven { +// url = uri("https://central.sonatype.com/repository/maven-snapshots") +// } + } +} + dependencyResolutionManagement { versionCatalogs { create("libs") { from(files("../gradle/libs.versions.toml")) } } + + repositories { + mavenCentral() +// maven { +// url = uri("https://central.sonatype.com/repository/maven-snapshots") +// } +// maven { +// url = uri("https://plugins.gradle.org/m2/") +// } + } } diff --git a/buildSrc/src/main/kotlin/Project.kt b/buildSrc/src/main/kotlin/Project.kt deleted file mode 100644 index 554aea1..0000000 --- a/buildSrc/src/main/kotlin/Project.kt +++ /dev/null @@ -1,42 +0,0 @@ -//import org.gradle.accessors.dm.LibrariesForLibs -import org.gradle.api.Project -import org.gradle.api.provider.Provider -//import org.gradle.kotlin.dsl.the - -// see buildSrc/build.gradle.kts -//val Project.libs: LibrariesForLibs -// get() = the() - -fun Project.isReleaseVersion(): Boolean { - return ! version.toString().endsWith("SNAPSHOT") -} - - -fun Project.getBuildProperty(property: String): String { - val propertyValue = findProperty(property) - return if (propertyValue != null) { - propertyValue as String - } else { - System.getenv(property) ?: "n/a" - } -} - -fun Project.projectGroupId(): String { - return getGradleProperty("projectGroupId").get() -} - -fun Project.projectVersion(): String { - return getGradleProperty("projectVersion").get() -} - -fun Project.getPublishUser(): String { - return getBuildProperty("PUBLISH_USER") -} - -fun Project.getPublishKey(): String { - return getBuildProperty("PUBLISH_KEY") -} - -fun Project.getGradleProperty(property: String): Provider { - return providers.gradleProperty(property) -} diff --git a/buildSrc/src/main/kotlin/VersionPlugin.kt b/buildSrc/src/main/kotlin/VersionPlugin.kt deleted file mode 100644 index dd86e27..0000000 --- a/buildSrc/src/main/kotlin/VersionPlugin.kt +++ /dev/null @@ -1,42 +0,0 @@ -import gradle.kotlin.dsl.accessors._9c04ceaef20eeb51aed3ad37a03c872b.ext -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.tasks.SourceSetContainer -import org.gradle.kotlin.dsl.getByType -import org.gradle.kotlin.dsl.register - -/** - * provides a "generateVersion" task to create a simple Version.java class: - * - *
{@code
- * package io.openapiprocessor.gradle;
- *
- * public class Version {
- *     public static final String version = "${project.version}";
- *     public static final String api = "${project.ext.api}";
- * }
- * }
- * - * The io/openapiprocessor/gradle/Version.java file is generated to: - * - * $(project.buildDir}/version - * - * Add it added as a source directory to include it in compilation. - */ -class VersionPlugin: Plugin { - - override fun apply(project: Project) { - val generateVersion = project.tasks.register("generateVersion") { - buildFile = project.buildFile - targetDir = project.layout.buildDirectory.dir("version") - pluginVersion = project.version.toString() - apiVersion = project.ext.get("api").toString() - } - - val ssc = project.extensions.getByType() - val main = ssc.named("main") - main.configure { - java.srcDir(generateVersion) - } - } -} diff --git a/buildSrc/src/main/kotlin/VersionTask.kt b/buildSrc/src/main/kotlin/VersionTask.kt deleted file mode 100644 index 45e7c71..0000000 --- a/buildSrc/src/main/kotlin/VersionTask.kt +++ /dev/null @@ -1,59 +0,0 @@ -import org.gradle.api.DefaultTask -import org.gradle.api.file.Directory -import org.gradle.api.provider.Provider -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.OutputDirectory -import org.gradle.api.tasks.TaskAction -import java.io.File -import java.nio.file.Files -import java.time.Instant - -/** - * simple task to create a Version class. - */ - -abstract class VersionTask: DefaultTask() { - /** - * the "build.gradle" file with the current versions. - */ - @get:InputFiles - abstract var buildFile: File - - /** - * Target directory for the generated version class. - */ - @get:OutputDirectory - abstract var targetDir: Provider - - @get:Internal - abstract var pluginVersion: String - - @get:Internal - abstract var apiVersion: String - - /** - * generate the version class. - */ - @TaskAction - fun generateVersion () { - val targetPkg = targetDir.get().dir("io").dir("openapiprocessor").dir("gradle") - Files.createDirectories(targetPkg.asFile.toPath()) - - val target = targetPkg.file("Version.java") - target.asFile.writeText(""" - /* - * DO NOT MODIFY - this file was auto generated by VersionPlugin.groovy - * - * ${Instant.now()} - */ - - package io.openapiprocessor.gradle; - - public class Version { - public static final String version = "$pluginVersion"; - public static final String api = "$apiVersion"; - } - """.trimIndent()) - } -} diff --git a/buildSrc/src/main/kotlin/compile.gradle.kts b/buildSrc/src/main/kotlin/compile.gradle.kts new file mode 100644 index 0000000..910ec29 --- /dev/null +++ b/buildSrc/src/main/kotlin/compile.gradle.kts @@ -0,0 +1,10 @@ +// basic compile settings for project and subprojects + +plugins { + groovy +} + +dependencies { + compileOnly("io.openapiprocessor:openapi-processor-api:2024.2") + implementation(localGroovy()) +} diff --git a/buildSrc/src/main/kotlin/openapiprocessor.publish.gradle.kts b/buildSrc/src/main/kotlin/openapiprocessor.publish.gradle.kts deleted file mode 100644 index 4051649..0000000 --- a/buildSrc/src/main/kotlin/openapiprocessor.publish.gradle.kts +++ /dev/null @@ -1,63 +0,0 @@ -plugins { - id("maven-publish") - id("signing") -} - -publishing { - publications { - create("openapiprocessor") { - pom { - name = getGradleProperty("projectTitle") - description = getGradleProperty("projectDesc") - url = getGradleProperty("projectUrl") - - scm { - url = "https://github.com/${getGradleProperty("projectGithubRepo")}".toString () - } - - licenses { - license { - name = "The Apache Software License, Version 2.0" - url = "https://www.apache.org/licenses/LICENSE-2.0.txt" - distribution = "repo" - } - } - - developers { - developer { - id = "hauner" - name = "Martin Hauner" - } - } - } - } - } - - repositories { - maven { - val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2" - val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots" - url = uri(if (isReleaseVersion()) releasesRepoUrl else snapshotsRepoUrl) - - credentials { - username = getPublishUser() - password = getPublishKey() - } - } - } -} - -// signing requires the sign key and pwd as environment variables: -// -// ORG_GRADLE_PROJECT_signKey=... -// ORG_GRADLE_PROJECT_signPwd=... - -signing { - setRequired({ gradle.taskGraph.hasTask("${project.path}:publishToSonatype") }) - - val signKey: String? by project - val signPwd: String? by project - useInMemoryPgpKeys(signKey, signPwd) - - sign(publishing.publications["openapiprocessor"]) -} diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 0f89e04..db8383a 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -20,16 +20,23 @@ link:{oapj-license}[image:{badge-license}[]] a gradle plugin based on the link:{oap-api}[openapi-processor-api] to handle any openapi-processor without an explicit dependency on the processor. -[cols="2*",options="header"] +[cols="3*",options="header"] |=== | plugin version -| required gradle version +| minimum gradle version +| minimum java version -| 2022.1 or newer +| 2025.x +| 7.2 +| 17 + +| 2022.x, 2023.x | 7.0+ +| | 2021.3 | 5.5+ with groovy dsl, 6.5 with kotlin dsl +| |=== NOTE: unfortunately it may be necessary to configure a few xref:oap::jdk.adoc[additional jvm parameter] to run the processor with JDK 16+. This is only necessary to format the generated source code with google code format. diff --git a/gradle.properties b/gradle.properties index a8f2261..675c018 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,10 @@ -projectVersion=2025.1-SNAPSHOT projectGroupId=io.openapiprocessor projectUrl=https://openapiprocessor.io projectTitle=openapi-processor projectDesc=OpenAPI Processor Gradle Plugin +projectRepo=openapi-processor/openapi-processor-gradle -projectGithubRepo=openapi-processor/openapi-processor-gradle - -#org.gradle.configuration-cache=true -#org.gradle.configuration-cache.parallel=true +org.gradle.configuration-cache=true +org.gradle.configuration-cache.parallel=true org.gradle.warning.mode=all diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ef08a04..3b2c51e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,9 +7,9 @@ spock = "2.4-M4-groovy-3.0" bytebuddy = "1.17.6" # plugins -versions = "0.51.0" -publish = "1.3.1" -nexus = "2.0.0" +updates = "0.51.0" +build-plugins = "2025.10-SNAPSHOT" +pubplug = "1.3.1" [libraries] openapi-processor-api = { module = "io.openapiprocessor:openapi-processor-api", version.ref = "api" } @@ -19,6 +19,8 @@ spock-core = { module = "org.spockframework:spock-core" } bytebuddy = { module = "net.bytebuddy:byte-buddy", version.ref = "bytebuddy" } [plugins] -publish = { id = "com.gradle.plugin-publish", version.ref = "publish" } -nexus = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexus" } -versions = { id = "com.github.ben-manes.versions", version.ref = "versions" } +pubplug = { id = "com.gradle.plugin-publish", version.ref = "pubplug" } +updates = { id = "com.github.ben-manes.versions", version.ref = "updates" } +publish = { id = "io.openapiprocessor.build.plugin.publish", version.ref = "build-plugins" } +versions = { id = "io.openapiprocessor.build.plugin.create-versions", version.ref = "build-plugins" } +tasktree = {id = "com.dorongold.task-tree", version = "4.0.1" } diff --git a/justfile b/justfile index e31ad0f..dbbf024 100644 --- a/justfile +++ b/justfile @@ -7,3 +7,7 @@ wrapper version="8.14.2": cache: ./gradlew --configuration-cache help + +# publish snapshot (if version has '-SNAPSHOT' suffix) or release +publish: + ./gradlew publishToMavenCentral diff --git a/processor-one/build.gradle b/processor-one/build.gradle deleted file mode 100644 index 677b2ef..0000000 --- a/processor-one/build.gradle +++ /dev/null @@ -1 +0,0 @@ -// configured by root project diff --git a/processor-one/build.gradle.kts b/processor-one/build.gradle.kts new file mode 100644 index 0000000..1434c96 --- /dev/null +++ b/processor-one/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("compile") +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } +} diff --git a/processor-two/build.gradle b/processor-two/build.gradle deleted file mode 100644 index 677b2ef..0000000 --- a/processor-two/build.gradle +++ /dev/null @@ -1 +0,0 @@ -// configured by root project diff --git a/processor-two/build.gradle.kts b/processor-two/build.gradle.kts new file mode 100644 index 0000000..1434c96 --- /dev/null +++ b/processor-two/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("compile") +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } +} diff --git a/processor-v1/build.gradle b/processor-v1/build.gradle deleted file mode 100644 index 677b2ef..0000000 --- a/processor-v1/build.gradle +++ /dev/null @@ -1 +0,0 @@ -// configured by root project diff --git a/processor-v1/build.gradle.kts b/processor-v1/build.gradle.kts new file mode 100644 index 0000000..7aa26f9 --- /dev/null +++ b/processor-v1/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("compile") +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} diff --git a/processor-v2/build.gradle.kts b/processor-v2/build.gradle.kts new file mode 100644 index 0000000..7aa26f9 --- /dev/null +++ b/processor-v2/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("compile") +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} diff --git a/processor-v2/src/main/groovy/io/openapiprocessor/processor/ProcessorV2.groovy b/processor-v2/src/main/groovy/io/openapiprocessor/processor/ProcessorV2.groovy new file mode 100644 index 0000000..fd603c4 --- /dev/null +++ b/processor-v2/src/main/groovy/io/openapiprocessor/processor/ProcessorV2.groovy @@ -0,0 +1,17 @@ +package io.openapiprocessor.processor + +import io.openapiprocessor.api.v2.OpenApiProcessor + +class ProcessorV2 implements OpenApiProcessor { + + @Override + String getName () { + 'v2' + } + + @Override + void run (Map options) { + println "processor ${name} did run ! (${options.targetDir})" + } + +} diff --git a/processor-v2/src/main/resources/META-INF/services/io.openapiprocessor.api.v2.OpenApiProcessor b/processor-v2/src/main/resources/META-INF/services/io.openapiprocessor.api.v2.OpenApiProcessor new file mode 100644 index 0000000..4757758 --- /dev/null +++ b/processor-v2/src/main/resources/META-INF/services/io.openapiprocessor.api.v2.OpenApiProcessor @@ -0,0 +1 @@ +io.openapiprocessor.processor.ProcessorV2 diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 0cd5676..0000000 --- a/settings.gradle +++ /dev/null @@ -1,7 +0,0 @@ -rootProject.name = 'openapi-processor-gradle' - -include 'processor-one' -include 'processor-two' -include 'processor-v1' - -//includeBuild '../openapi-processor-api' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..88093f5 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,42 @@ +rootProject.name = "openapi-processor-gradle" + +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() +// mavenLocal() + maven { + url = uri("https://central.sonatype.com/repository/maven-snapshots") +// content { +// includeGroup("io.openapiprocessor") +// } + mavenContent { + snapshotsOnly() + } + } + } +} + +dependencyResolutionManagement { + repositories { + mavenCentral() + + maven { + name = "maven central snapshots" + url = uri("https://central.sonatype.com/repository/maven-snapshots") + content { + includeGroup("io.openapiprocessor") + } + mavenContent { + snapshotsOnly() + } + } + } +} + +include("processor-one") +include("processor-two") +include("processor-v1") +include("processor-v2") + +//includeBuild '../openapi-processor-api' diff --git a/src/main/groovy/com/github/hauner/openapi/gradle/Processor.groovy b/src/main/groovy/com/github/hauner/openapi/gradle/Processor.groovy deleted file mode 100644 index 4c9227f..0000000 --- a/src/main/groovy/com/github/hauner/openapi/gradle/Processor.groovy +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2020 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package com.github.hauner.openapi.gradle - -/** - * backward compatibility, replaced by {@link io.openapiprocessor.gradle.Processor} - */ -@Deprecated -class Processor extends io.openapiprocessor.gradle.Processor { - - Processor (String name) { - super(name) - } - -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/ClosureAction.groovy b/src/main/groovy/io/openapiprocessor/gradle/ClosureAction.groovy new file mode 100644 index 0000000..cb22e83 --- /dev/null +++ b/src/main/groovy/io/openapiprocessor/gradle/ClosureAction.groovy @@ -0,0 +1,23 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +import groovy.transform.CompileStatic +import org.gradle.api.Action + +@CompileStatic +class ClosureAction implements Action { + private final Closure closure + + ClosureAction(Closure closure) { + this.closure = closure + } + + @Override + void execute(T t) { + closure.call(t) + } +} diff --git a/src/main/groovy/io/openapiprocessor/gradle/MapBuilder.groovy b/src/main/groovy/io/openapiprocessor/gradle/MapBuilder.groovy index 6ad6ccf..733724d 100644 --- a/src/main/groovy/io/openapiprocessor/gradle/MapBuilder.groovy +++ b/src/main/groovy/io/openapiprocessor/gradle/MapBuilder.groovy @@ -5,6 +5,7 @@ package io.openapiprocessor.gradle +import groovy.transform.CompileStatic import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -25,6 +26,7 @@ import org.slf4j.LoggerFactory * def map = builder.get() * */ +@CompileStatic class MapBuilder { Logger log = LoggerFactory.getLogger (MapBuilder) @@ -51,7 +53,7 @@ class MapBuilder { */ @Override Object invokeMethod(String methodName, Object args) { - def value = args[0] + def value = (args as Collection)[0] if (value instanceof Closure) { def builder = new MapBuilder() builder.with value @@ -59,6 +61,8 @@ class MapBuilder { } else { setProperty (methodName, value) } + + return null } /** @@ -80,5 +84,4 @@ class MapBuilder { props.put (propertyName, value) } - } diff --git a/src/main/groovy/io/openapiprocessor/gradle/MissingProcessorException.groovy b/src/main/groovy/io/openapiprocessor/gradle/MissingProcessorException.groovy deleted file mode 100644 index 61cae8f..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/MissingProcessorException.groovy +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2020 the original 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 - * - * http://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. - */ - -package io.openapiprocessor.gradle - -class MissingProcessorException extends RuntimeException { - - MissingProcessorException(String processorName) { - super("can't find processor: ${processorName}!") - } - -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtension.groovy b/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtension.groovy deleted file mode 100644 index 46348d3..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtension.groovy +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2020 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle - -import org.gradle.api.Action -import org.gradle.api.Project -import org.gradle.api.file.RegularFile -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.MapProperty -import org.gradle.api.provider.Property - -/** - * Extension object of the plugin. Used to configure the processors, e.g. - *
- * openapiProcessor {
- *     ...
- *     apiPath "...."
- *
- *     spring {
- *       processor "..:...:..."
- *       targetDir "..."
- *
- *       .. other
- *     }
- *
- *     json {
- *       processor "..:...:..."
- *       targetDir "..."
- *
- *       .. other
- *     }
- *     ...
- *
- *     checkUpdates "never"|"daily"|"always"
- * }
- * 
- */ -abstract class OpenApiProcessorExtension extends OpenApiProcessorExtensionBase { - - /** - * the path to the openapi yaml file. Used for all processors if not set in a nested processor - * configuration. - */ - RegularFileProperty api - - /** - * check automatically for updates. Can be "never"|"daily"|"always". Default is "never". - */ - Property checkUpdates - - /** - * properties of the nested processor configurations by processor name, e.g. - *
-     *  openapiProcessor {
-     *
-     *      aProcessor {
-     *          processor "..:...:..."
-     *          targetDir "..."
-     *
-     *       .. other
-     *          prop "abc"
-     *          prop "xyz"
-     *      }
-     *
-     *  }
-     * 
- */ - MapProperty processors - - private Project project - - OpenApiProcessorExtension (Project project) { - api = project.objects.fileProperty() - - checkUpdates = project.objects.property(String) - checkUpdates.set("never") - - processors = project.objects.mapProperty (String, Processor) - this.project = project - } - - /** - * groovy/kotlin dsl. create a new processor configuration. - * - *
-     *  openapiProcessor {
-     *    process("newProcessor") { ... }
-     * }
-     * 
- * - * @param name unique name of the processor - * @param args {@link Processor} action - * @return the new processor - */ - Processor process(String name, Action action) { - def processor = new Processor (name) - action.execute (processor) - processors.put (name, processor) - processor - } - - Processor process(GString name, Action action) { - process (name.toString (), action) - } - - /** - * groovy dsl only. create a new processor configuration. - * - *
-     *  openapiProcessor {
-     *    newProcessor { ... }
-     * }
-     * 
- * - * gradle will never call this from a kotlin build script unless explicitly calling it, i.e. - * - *
-     *  openapiProcessor {
-     *    methodMissing "newProcessor" { ... }
-     * }
-     * 
- * - * @param name unique name of the processor - * @param args arg array. arg[0] must be a {@link Processor} configuration block - * @return the new processor - */ - def methodMissing (String name, def args) { - def arg = args[0] - - // should be a nested processor configuration - if (arg instanceof Closure) { - // apply it to a new Processor () entry - def processor = new Processor (name) - - processor.metaClass.file = { Object path -> - return project.file(path) - } - -// processor.metaClass.files = { Object... paths -> -// return project.files(paths) -// } - - processor.with(arg) - processors.put (name, processor) - return processor - } - - throw new MissingMethodException(name, OpenApiProcessorExtension, args) - } - - /** - * set apiPath. - */ - void apiPath(String apiPath) { - this.api.fileValue(new File(apiPath)) - } - - /** - * set apiPath. - */ - void apiPath(GString apiPath) { - this.api.fileValue(new File(apiPath)) - } - - void setApiPath(File apiPath) { - api.set(apiPath) - } - - void setApiPath(RegularFile apiPath) { - api.set(apiPath) - } - - void checkUpdates(String check) { - checkUpdates.set(check) - } - - Property getCheckUpdates() { - return checkUpdates - } -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionBase.groovy b/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionBase.groovy new file mode 100644 index 0000000..f504094 --- /dev/null +++ b/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionBase.groovy @@ -0,0 +1,54 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +import groovy.transform.CompileDynamic +import groovy.transform.CompileStatic + +@CompileStatic +class OpenApiProcessorExtensionBase { + + /** + * groovy dsl. create a new processor configuration. + * + *
+     *  openapiProcessor {
+     *    newProcessor { ... }
+     * }
+     * 
+ * + * gradle will never call this from a kotlin build script unless explicitly calling it, i.e. + * + *
+     *  openapiProcessor {
+     *    methodMissing "newProcessor" { ... }
+     * }
+     * 
+ * + * @param name unique name of the processor + * @param args arg array. arg[0] must be a {@link ProcessorBase} configuration block + * @return the new processor + */ + @CompileDynamic + def methodMissing(String name, def args) { + def arg = args[0] + + // expecting a nested processor configuration + if (arg instanceof Closure) { + def processor = createProcessor(name) + processor.with(arg) + processors.put(name, processor) + return processor + } + + throw new MissingMethodException(name, OpenApiProcessorExtension, args) + } + + GroovyObject createProcessor(String name) { + return Class.forName("io.openapiprocessor.gradle.Processor") + .getDeclaredConstructor(String).newInstance(name) as GroovyObject + } +} diff --git a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionUtils.groovy b/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionUtils.groovy deleted file mode 100644 index 2a7279a..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionUtils.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle - -import org.gradle.api.Project - -class OpenApiProcessorExtensionUtils { - static final String EXTENSION_NAME_DEFAULT = 'openapiProcessor' - static final String EXTENSION_NAME_ALTERNATIVE = 'openapi' - - static void createExtension (Project project) { - def extension = project.extensions.create ( - EXTENSION_NAME_DEFAULT, - OpenApiProcessorExtension, - project) - - // make same extension object available under alternative name - project.extensions.add(EXTENSION_NAME_ALTERNATIVE, extension) - } - - static OpenApiProcessorExtension getExtension(Project project) { - return project.extensions.findByName (EXTENSION_NAME_DEFAULT) as OpenApiProcessorExtension - } -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorPlugin.groovy b/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorPlugin.groovy deleted file mode 100644 index 03e50a8..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorPlugin.groovy +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2019 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle - -import io.openapiprocessor.gradle.version.GitHubVersionCheck -import io.openapiprocessor.gradle.version.GitHubVersionProvider -import io.openapiprocessor.gradle.version.VersionCheck -import org.gradle.api.Action -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.Dependency - -import static io.openapiprocessor.gradle.OpenApiProcessorExtensionUtils.* - -/** - * openapi-processor-gradle plugin. - */ -class OpenApiProcessorPlugin implements Plugin { - - @Override - void apply (Project project) { - if (!isSupportedGradleVersion (project)) { - return - } - - addOpenApiProcessorRepository (project) - - createExtension (project) - - project.afterEvaluate (createCheckUpdatesAction ()) - project.afterEvaluate (createTasksBuilderAction ()) - } - - private static boolean isSupportedGradleVersion (Project project) { - String version = project.gradle.gradleVersion - - if (version < "7.0") { - project.logger.error ("the current gradle version is ${version}") - project.logger.error ("openapi-processor-gradle requires gradle 7.0+") - return false - } - - return true - } - - private void addOpenApiProcessorRepository (Project project) { - def snapshots = project.findProperty ("openapi-processor-gradle.snapshots") - if (snapshots == null || snapshots != "true") { - project.logger.debug("openapi-processor: snapshot repository disabled") - return - } - - project.repositories { - maven { - url "https://oss.sonatype.org/content/repositories/snapshots" - mavenContent { - snapshotsOnly () - } - } - } - project.logger.debug("openapi-processor: snapshot repository enabled") - } - - /** - * Provides an Action that checks for plugin updates. - */ - private Action createCheckUpdatesAction () { - return new Action() { - @Override - void execute (Project project) { - def extension = getExtension (project) - def interval = extension.checkUpdates.get() - - def version = new VersionCheck(project.rootDir.absolutePath, interval) - if (!version.canCheck("gradle")) - return - - checkLatestRelease () - } - } - } - - /** - * Provides an Action that create a 'process{ProcessorName}' task for each configured processor. - */ - private Action createTasksBuilderAction () { - return new Action() { - @Override - void execute (Project project) { - def extension = getExtension (project) - extension.processors.get ().each { entry -> - def name = "process${entry.key.capitalize ()}" - def action = createTaskBuilderAction (entry.key, entry.value) - project.tasks.register (name, OpenApiProcessorTask, action) - } - } - } - } - - /** - * Creates an Action that configures a 'process{ProcessorName}' task from its configuration. - */ - private Action createTaskBuilderAction(String name, Processor processor) { - new Action() { - @Override - void execute (OpenApiProcessorTask task) { - def project = task.getProject () - - task.processorName.set (processor.name) - task.processorProps.set (processor.other) - - task.setGroup ('openapi processor') - task.setDescription ("process openapi with openapi-processor-${processor.name}") - - copyApiPath (task) - task.apiDir.set (inputDirectory) - task.targetDir.set (outputDirectory) - - def handler = project.getDependencies () - List dependencies = [] - - if (processor.dependencies.empty) { - task.logger.warn ("'${EXTENSION_NAME_DEFAULT}.${name}.processor' not set!") - } - - dependencies.add (handler.create("io.openapiprocessor:openapi-processor-api:${Version.api}")) - - processor.dependencies.each { - dependencies.add (handler.create (it)) - } - - Dependency[] deps = dependencies.toArray (new Dependency[0]) - - Configuration cfg = project.getConfigurations () - .detachedConfiguration (deps) - - cfg.setVisible (false) - cfg.setTransitive (true) - cfg.setDescription ("the dependencies of the process${name.capitalize ()} task.") - task.dependencies.from (cfg) - } - - private String getInputDirectory () { - String path = processor.apiPath - def file = new File (path) - file.parent - } - - private String getOutputDirectory () { - processor.targetDir - } - - // copy common api path to openapi-processor props if not set - private copyApiPath (OpenApiProcessorTask task) { - if(processor.hasApiPath ()) - return - - def extension = getExtension (task.project) - if (!extension.api.present) { - task.logger.warn ("'${extName}.apiPath'!") - return - } - - processor.apiPath = extension.api.get () - } - } - } - - private void checkLatestRelease () { - new GitHubVersionCheck(new GitHubVersionProvider(), Version.version).check() - } -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorTask.java b/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorTask.java deleted file mode 100644 index 1d6c90e..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorTask.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2019 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle; - -import org.gradle.api.DefaultTask; -import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.provider.MapProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.tasks.Classpath; -import org.gradle.api.tasks.InputDirectory; -import org.gradle.api.tasks.Internal; -import org.gradle.api.tasks.OutputDirectory; -import org.gradle.api.tasks.TaskAction; -import org.gradle.workers.WorkQueue; -import org.gradle.workers.WorkerExecutor; - -import javax.inject.Inject; - -import static io.openapiprocessor.gradle.OpenApiProcessorExtensionUtils.getExtension; - -/** - * processor task. Uses a worker executor to run the processor with an isolated "openapiProcessor" - * configuration classpath. - */ -abstract public class OpenApiProcessorTask extends DefaultTask { - - /** - * Source directory (i.e. parent) of the openapi.yaml input file. Used by gradle for the up-to-date check. - * - * @return parent directory of the openapi.yaml - */ - @InputDirectory - abstract public Property getApiDir(); - - /** - * Target directory for the sources generated by the processor. Used by gradle for the up-to-date check. - * - * @return target directory - */ - @OutputDirectory - abstract public Property getTargetDir(); - - /** - * The dependencies of the processor. - * - * @return the processor dependencies - */ - @Classpath - abstract public ConfigurableFileCollection getDependencies(); - - /** - * name of the processor. - * - * @return the processor name. - */ - @Internal - abstract public Property getProcessorName(); - - /** - * properties configured by the processor closure in the OpenApiProcessorExtension. - * - * @return the processor properties - */ - @Internal - abstract public MapProperty getProcessorProps(); - - @Inject - abstract public WorkerExecutor getWorkerExecutor(); - - /** - * runs the configured processor with its own classloader. - */ - @TaskAction - public void runProcessor () { - WorkQueue workQueue = getWorkerExecutor ().classLoaderIsolation ( - workerSpec -> workerSpec.getClasspath ().from (getDependencies ())); - - var extension = getExtension(getProject()); - - workQueue.submit(OpenApiProcessorWorker.class, parameters -> { - parameters.getProcessorName ().set (getProcessorName ()); - parameters.getProcessorProps ().set (getProcessorProps ()); - parameters.getRootDir().set(getProject().getRootDir().getAbsolutePath()); - parameters.getCheckUpdates().set(extension.getCheckUpdates()); - }); - } - -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorWorkParameters.java b/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorWorkParameters.java deleted file mode 100644 index 24695c6..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorWorkParameters.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2021 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle; - -import org.gradle.api.provider.MapProperty; -import org.gradle.api.provider.Property; -import org.gradle.workers.WorkParameters; - -interface OpenApiProcessorWorkParameters extends WorkParameters { - - Property getProcessorName (); - - MapProperty getProcessorProps (); - - Property getRootDir (); - - Property getCheckUpdates (); -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorWorker.java b/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorWorker.java deleted file mode 100644 index ed8090c..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/OpenApiProcessorWorker.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2019 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle; - -import io.openapiprocessor.api.v2.OpenApiProcessorVersion; -import io.openapiprocessor.api.v2.Version; -import io.openapiprocessor.gradle.version.VersionCheck; -import org.gradle.api.logging.Logger; -import org.gradle.workers.WorkAction; -import org.slf4j.LoggerFactory; - -import java.util.Map; - -/** - * Runs the processor with the class loader that includes the dependencies from the openapiProcessor - * configuration. - */ -@SuppressWarnings ("deprecation") -abstract public class OpenApiProcessorWorker implements WorkAction { - private final Logger log = (Logger) LoggerFactory.getLogger(OpenApiProcessorWorker.class); - - @Override - public void execute () { - Object processor = getProcessor (getProcessorName ()); - Map properties = getProcessorProperties (); - - try { - check (processor); - run (processor, properties); - - } catch (Throwable t) { - waitForLogging (); - throw t; - } - } - - private void check (Object processor) { - try { - if (!shouldCheck(processor)) - return; - - runCheck(processor); - - } catch (Throwable ignore) { - // ignore, do not complain - } - } - - private void run (Object processor, Map properties) { - if (processor instanceof io.openapiprocessor.api.v2.OpenApiProcessor) { - run ((io.openapiprocessor.api.v2.OpenApiProcessor) processor, properties); - - } else if (processor instanceof io.openapiprocessor.api.v1.OpenApiProcessor) { - run ((io.openapiprocessor.api.v1.OpenApiProcessor) processor, properties); - - } else if (processor instanceof io.openapiprocessor.api.OpenApiProcessor) { - run ((io.openapiprocessor.api.OpenApiProcessor) processor, properties); - - } else if (processor instanceof com.github.hauner.openapi.api.OpenApiProcessor) { - run ((com.github.hauner.openapi.api.OpenApiProcessor) processor, properties); - } - } - - private static void waitForLogging () { - // without waiting gradle does not reliably log a processor error/exception. - try { - Thread.sleep (1000); - } catch (InterruptedException e) { - throw new RuntimeException (e); - } - } - - private boolean shouldCheck (Object processor) { - if(! (processor instanceof io.openapiprocessor.api.v2.OpenApiProcessor)) { - return false; - } - - var theProcessor = (io.openapiprocessor.api.v2.OpenApiProcessor)processor; - - VersionCheck version = new VersionCheck(getRootDir(), getCheckUpdates()); - return version.canCheck(theProcessor.getName()); - } - - private void runCheck (Object processor) { - if (! (processor instanceof OpenApiProcessorVersion)) { - return; - } - - var processorVersion = (OpenApiProcessorVersion) processor; - - if (processorVersion.hasNewerVersion ()) { - String currentVersion = processorVersion.getVersion (); - Version latestVersion = processorVersion.getLatestVersion (); - - log.quiet("{} version {} is available! I'm version {}.", - getProcessorName (), latestVersion.getName (), currentVersion); - } - } - - private void run (io.openapiprocessor.api.v2.OpenApiProcessor processor, Map properties) { - processor.run (properties); - } - - private void run (io.openapiprocessor.api.v1.OpenApiProcessor processor, Map properties) { - processor.run (properties); - } - - private void run (io.openapiprocessor.api.OpenApiProcessor processor, Map properties) { - processor.run (properties); - } - - private void run (com.github.hauner.openapi.api.OpenApiProcessor processor, Map properties) { - processor.run (properties); - } - - private Object getProcessor (String processorName) { - Object processor = ProcessorLoader.load (processorName, getClass ().getClassLoader ()); - if (processor == null) { - throw new MissingProcessorException(processorName); - } - return processor; - } - - private String getProcessorName() { - return getParameters ().getProcessorName ().get (); - } - - private Map getProcessorProperties() { - return getParameters ().getProcessorProps ().get (); - } - - private String getRootDir() { - return getParameters ().getRootDir ().get (); - } - - private String getCheckUpdates() { - return getParameters ().getCheckUpdates ().get (); - } -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/Processor.groovy b/src/main/groovy/io/openapiprocessor/gradle/Processor.groovy deleted file mode 100644 index 2fb4b1f..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/Processor.groovy +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2020 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle - -import org.gradle.api.file.Directory -import org.gradle.api.file.FileCollection -import org.gradle.api.file.RegularFile -import org.gradle.api.provider.Provider - -/** - * represents an openapi-processor configured in {@link OpenApiProcessorExtension} - */ -class Processor { - public static final String API_PATH = 'apiPath' - public static final String TARGET_DIR = 'targetDir' - - String name - String config - def dependencies = [] // String | FileCollection... - - Map other = [:] - - Processor (String configName) { - this.config = configName - this.name = configName - } - - void processorName (String processorName) { - this.name = processorName - } - - void processorName (GString processorName) { - this.name = processorName.toString () - } - - void processor (FileCollection fc) { - dependencies.add (fc) - } - - void processor (File f) { - dependencies.add (f) - } - - void processor (String dep) { - dependencies.add (dep) - } - - String getTargetDir () { - other.get (TARGET_DIR) - } - - void targetDir (String targetDir) { - other.put (TARGET_DIR, targetDir) - } - - void targetDir (GString targetDir) { - other.put (TARGET_DIR, targetDir.toString ()) - } - - void targetDir(Directory targetDir) { - other.put (TARGET_DIR, targetDir.toString()) - } - - void targetDir(Provider targetDir) { - other.put (TARGET_DIR, targetDir.get().toString()) - } - - void setTargetDir (String targetDir) { - other.put (TARGET_DIR, targetDir) - } - - void setTargetDir (GString targetDir) { - other.put (TARGET_DIR, targetDir.toString ()) - } - - void setTargetDir(Directory targetDir) { - other.put (TARGET_DIR, targetDir.toString()) - } - - /** - * allow to assign targetDir like - * - * {@code targetDir = layout.buildDirectory.dir("openapi")} - * - * @param targetDir targetDir provider - */ - void setTargetDir(Provider targetDir) { - other.put (TARGET_DIR, targetDir.get().toString()) - } - - void apiPath (String apiPath) { - other.put (API_PATH, apiPath) - } - - void apiPath (GString apiPath) { - other.put (API_PATH, apiPath.toString ()) - } - - boolean hasApiPath () { - other.containsKey (API_PATH) - } - - String getApiPath () { - other.get (API_PATH) - } - - void setApiPath (String path) { - other.put (API_PATH, path) - } - - void setApiPath (RegularFile apiPath) { - other.put (API_PATH, apiPath.toString()) - } - - void prop (Map props) { - other.putAll (props) - } - - void prop (String key, Object value) { - if (value instanceof RegularFile) { - other.put(key, value.toString()) - } else { - other.put (key, value) - } - } - - void prop (GString key, Object value) { - if (value instanceof RegularFile) { - other.put(key.toString(), value.toString()) - } else { - other.put (key.toString(), value) - } - } - - def methodMissing (String name, def args) { - if (args[0] instanceof Closure) { - def builder = new MapBuilder() - builder.with (args[0] as Closure) - other.put (name, builder.get ()) - } else { - other.put (name, args[0]) - } - } -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/ProcessorBase.groovy b/src/main/groovy/io/openapiprocessor/gradle/ProcessorBase.groovy new file mode 100644 index 0000000..4da9c5f --- /dev/null +++ b/src/main/groovy/io/openapiprocessor/gradle/ProcessorBase.groovy @@ -0,0 +1,27 @@ +/* + * Copyright 2020 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +import groovy.transform.CompileDynamic +import groovy.transform.CompileStatic + +/** + * groovy dsl. represents an openapi-processor configured in {@link OpenApiProcessorExtension} + */ +@CompileStatic +class ProcessorBase { + + @CompileDynamic + def methodMissing(String name, def args) { + if (args[0] instanceof Closure) { + def builder = new MapBuilder() + builder.with(args[0] as Closure) + other.put(name, builder.get()) + } else { + other.put(name, args[0]) + } + } +} diff --git a/src/main/groovy/io/openapiprocessor/gradle/ProcessorLoader.groovy b/src/main/groovy/io/openapiprocessor/gradle/ProcessorLoader.groovy deleted file mode 100644 index 588fd6e..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/ProcessorLoader.groovy +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2019 the original 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 - * - * http://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. - */ - -package io.openapiprocessor.gradle - -/** - * Find a processor using the ServiceLoader. - * - * @author Martin Hauner - */ -class ProcessorLoader { - - static def load(String processorName, ClassLoader classLoader) { - def processor = findProcessor (processorName, io.openapiprocessor.api.v1.OpenApiProcessor, classLoader) - if (processor) { - return processor - } - - processor = findProcessor (processorName, io.openapiprocessor.api.OpenApiProcessor, classLoader) - if (processor) { - return processor - } - - processor = findProcessor (processorName, com.github.hauner.openapi.api.OpenApiProcessor, classLoader) - if (processor) { - return processor - } - - null - } - - private static findProcessor(String processorName, Class clazz, ClassLoader classLoader) { - def processors = [] - processors.addAll(ServiceLoader.load (clazz, classLoader)) - - def processor = processors.find { - it.getName () == processorName - } - - processor - } -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/Time.groovy b/src/main/groovy/io/openapiprocessor/gradle/Time.groovy deleted file mode 100644 index 142e50c..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/Time.groovy +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle - -import java.time.Instant - -interface Time { - Instant now() -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersion.groovy b/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersion.groovy deleted file mode 100644 index c3beac9..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersion.groovy +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle.version - -import java.time.Instant - -class GitHubVersion { - String name - Instant publishedAt - String text -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersionException.groovy b/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersionException.groovy deleted file mode 100644 index d9c9fbf..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersionException.groovy +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle.version - -class GitHubVersionException extends RuntimeException { - - GitHubVersionException(URI uri, Throwable cause) { - super("can't find version: ${uri}!", cause) - } - -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersionProvider.groovy b/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersionProvider.groovy deleted file mode 100644 index 430c956..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersionProvider.groovy +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle.version - -import groovy.json.JsonSlurper - -import java.time.Instant - -class GitHubVersionProvider { - public static final URI LATEST = new URI("https://api.github.com/repos/openapi-processor/openapi-processor-gradle/releases/latest") - - private URI versionUri - - GitHubVersionProvider() { - versionUri = LATEST - } - - GitHubVersionProvider(URI versionUri) { - this.versionUri = versionUri - } - - GitHubVersion getVersion () { - try { - def json = new JsonSlurper().parse(versionUri.toURL()) as Map - return new GitHubVersion( - name: json.name, - publishedAt: Instant.parse(json.published_at as CharSequence), - text: json.body - ) - } catch (Throwable t) { - throw new GitHubVersionException(versionUri, t) - } - } -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/version/VersionCheck.groovy b/src/main/groovy/io/openapiprocessor/gradle/version/VersionCheck.groovy deleted file mode 100644 index 3b78631..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/version/VersionCheck.groovy +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle.version - -import org.gradle.api.logging.Logger -import org.slf4j.LoggerFactory - -class VersionCheck { - private final Logger log = (Logger) LoggerFactory.getLogger(VersionCheck.class); - - private String rootDir - private String interval - - VersionCheck(String rootDir, String interval) { - this.rootDir = rootDir - this.interval = interval - } - - boolean canCheck(String module) { - if (interval == "never") { - return false - } else if (interval == "always") { - return true - } else if (interval == "daily") { - def settingsFile = new File(rootDir, "build/openapiprocessor/${module}.yaml") - def settings = new VersionCheckSettings(settingsFile.toString()) - new VersionCheckLatest(settings, 1).shouldCheck(module) - } else { - log.warn("unknown checkUpdate interval '{}'", interval) - } - } -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/version/VersionCheckLatest.groovy b/src/main/groovy/io/openapiprocessor/gradle/version/VersionCheckLatest.groovy deleted file mode 100644 index 929b40e..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/version/VersionCheckLatest.groovy +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle.version - -import io.openapiprocessor.gradle.Time - -import java.time.Instant -import java.time.temporal.ChronoUnit - -class VersionCheckLatest { - private VersionCheckSettings settings - private int interval; - private Time time - - static class DefaultTime implements Time { - @Override - Instant now() { - return Instant.now() - } - } - - VersionCheckLatest(VersionCheckSettings settings, int intervalDays, Time time = new DefaultTime()) { - this.settings = settings - this.interval = intervalDays - this.time = time - } - - boolean shouldCheck(String module) { - def now = time.now() - def last = settings.get(module) - if (last == null) { - settings.set(module, now) - return true - } - - def shouldCheck = last.isBefore(now.minus(interval, ChronoUnit.DAYS)) - if (shouldCheck) { - settings.set(module, now) - return true - } - - return false - } -} diff --git a/src/main/groovy/io/openapiprocessor/gradle/version/VersionCheckSettings.groovy b/src/main/groovy/io/openapiprocessor/gradle/version/VersionCheckSettings.groovy deleted file mode 100644 index c2e15ab..0000000 --- a/src/main/groovy/io/openapiprocessor/gradle/version/VersionCheckSettings.groovy +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle - * PDX-License-Identifier: Apache-2.0 - */ - -package io.openapiprocessor.gradle.version - -import org.yaml.snakeyaml.Yaml - -import java.nio.file.Files -import java.time.Instant - -class VersionCheckSettings { - private Yaml yaml - private String settingsName - - private Map settings - - VersionCheckSettings(String settingsName) { - this.settingsName = settingsName - this.settings = new HashMap<>() - yaml = new Yaml() - } - - Instant get(String name) { - def at = settings.get(name) - if (at == null) { - return null - } - - return Instant.parse(at) - } - - void set(String name) { - settings.put(name, Instant.now().toString()) - } - - void set(String name, Instant at) { - settings.put(name, at.toString()) - } - - void read() { - def file = new File(settingsName) - if (file.exists()) { - settings = yaml.loadAs(new FileReader(file), LinkedHashMap) - } else { - settings = new LinkedHashMap<>() - } - } - - void write() { - def file = new File(settingsName) - Files.createDirectories(file.parentFile.toPath()) - yaml.dump(settings, new FileWriter(file)) - } -} diff --git a/src/main/kotlin/com/github/hauner/openapi/gradle/Processor.kt b/src/main/kotlin/com/github/hauner/openapi/gradle/Processor.kt new file mode 100644 index 0000000..e1bd357 --- /dev/null +++ b/src/main/kotlin/com/github/hauner/openapi/gradle/Processor.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package com.github.hauner.openapi.gradle + +/** + * backward compatibility, replaced by [io.openapiprocessor.gradle.ProcessorBase] + */ +@Deprecated("backward compatibility.") +class Processor(name: String): io.openapiprocessor.gradle.Processor(name) diff --git a/src/main/kotlin/io/openapiprocessor/gradle/MissingProcessorException.kt b/src/main/kotlin/io/openapiprocessor/gradle/MissingProcessorException.kt new file mode 100644 index 0000000..c89c20a --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/MissingProcessorException.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +class MissingProcessorException(processorName: String) + : RuntimeException("can't find processor: ${processorName}!") diff --git a/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorExtension.kt b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorExtension.kt new file mode 100644 index 0000000..0b4ecd6 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorExtension.kt @@ -0,0 +1,135 @@ +/* + * Copyright 2020 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +import groovy.lang.GString +import org.gradle.api.Action +import org.gradle.api.Project +import org.gradle.api.file.RegularFile +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import java.io.File + +/** + * Extension object of the plugin. Used to configure the processors, e.g. + *
+ * openapiProcessor {
+ *     ...
+ *     apiPath "...."
+ *
+ *     spring {
+ *       processor "...:...:..."
+ *       targetDir "..."
+ *
+ *       ... other
+ *     }
+ *
+ *     json {
+ *       processor "...:...:..."
+ *       targetDir "..."
+ *
+ *       ... other
+ *     }
+ *     ...
+ *
+ *     checkUpdates "never"|"daily"|"always"
+ * }
+ * 
+ */ +abstract class OpenApiProcessorExtension(private val project: Project): OpenApiProcessorExtensionBase() { + + /** + * the path to the openapi yaml file. Used for all processors if not set in a nested processor + * configuration. + */ + val api: RegularFileProperty = project.objects.fileProperty() + + /** + * check automatically for updates. Can be "never"|"daily"|"always". Default is "never". + */ + val checkUpdates: Property = project.objects.property(String::class.java) + + /** + * properties of the nested processor configurations by processor name, e.g. + *
+     *  openapiProcessor {
+     *
+     *      aProcessor {
+     *          processor "...:...:..."
+     *          targetDir "..."
+     *
+     *          // ... other
+     *          prop "abc"
+     *          prop "xyz"
+     *      }
+     *
+     *  }
+     * 
+ */ + val processors: MapProperty = project.objects.mapProperty( + String::class.java, + Processor::class.java) + + init { + checkUpdates.set("never") + } + + /** + * groovy/kotlin dsl. create a new processor configuration. + * + *
+     *  openapiProcessor {
+     *    process("newProcessor") { ... }
+     * }
+     * 
+ * + * @param name unique name of the processor + * @param action [ProcessorBase] action + * @return the new processor + */ + fun process(name: String, action: Action): Processor { + val processor = Processor(name) + action.execute (processor) + processors.put (name, processor) + return processor + } + + fun process(name: GString, action: Action): Processor { + return process (name.toString (), action) + } + + /** + * set apiPath. + */ + fun apiPath(apiPath: String) { + this.api.fileValue(File(apiPath)) + } + + /** + * set apiPath. + */ + fun apiPath(apiPath: GString) { + apiPath(apiPath.toString()) + } + + fun setApiPath(apiPath: File) { + api.set(apiPath) + } + + fun setApiPath(apiPath: RegularFile) { + api.set(apiPath) + } + + fun checkUpdates(check: String) { + checkUpdates.set(check) + } + + // declaration clash +// fun getCheckUpdates(): Property { +// return checkUpdates +// } +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorExtensionUtils.kt b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorExtensionUtils.kt new file mode 100644 index 0000000..693ddcf --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorExtensionUtils.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +import org.gradle.api.Project + +class OpenApiProcessorExtensionUtils { + companion object { + const val EXTENSION_NAME_DEFAULT = "openapiProcessor" + const val EXTENSION_NAME_ALTERNATIVE = "openapi" + + fun createExtension (project: Project) { + val extension = project.extensions.create ( + EXTENSION_NAME_DEFAULT, + OpenApiProcessorExtension::class.java, + project) + + // make same extension object available under alternative name + project.extensions.add(EXTENSION_NAME_ALTERNATIVE, extension) + } + + fun getExtension(project: Project): OpenApiProcessorExtension { + return project.extensions.getByName (EXTENSION_NAME_DEFAULT) as OpenApiProcessorExtension + } + } +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorPlugin.kt b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorPlugin.kt new file mode 100644 index 0000000..c3d40de --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorPlugin.kt @@ -0,0 +1,169 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +import io.openapiprocessor.gradle.OpenApiProcessorExtensionUtils.Companion.EXTENSION_NAME_DEFAULT +import io.openapiprocessor.gradle.OpenApiProcessorExtensionUtils.Companion.createExtension +import io.openapiprocessor.gradle.OpenApiProcessorExtensionUtils.Companion.getExtension +import io.openapiprocessor.gradle.version.GitHubVersionCheck +import io.openapiprocessor.gradle.version.GitHubVersionProvider +import io.openapiprocessor.gradle.version.VersionCheck +import org.gradle.api.Action +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.artifacts.Dependency +import java.io.File + +/** + * openapi-processor-gradle plugin. + */ +class OpenApiProcessorPlugin: Plugin { + + override fun apply(project: Project) { + if (!isSupportedGradleVersion(project)) { + return + } + + addOpenApiProcessorRepository(project) + + createExtension(project) + + project.afterEvaluate(createCheckUpdatesAction()) + project.afterEvaluate(createTasksBuilderAction()) + } + + private fun addOpenApiProcessorRepository (project: Project) { + val snapshots = project.findProperty ("openapi-processor-gradle.snapshots") + if (snapshots == null || snapshots != "true") { + project.logger.debug("openapi-processor: snapshot repository disabled") + return + } + + project.repositories.maven { + url = project.uri("https://oss.sonatype.org/content/repositories/snapshots/") + mavenContent { snapshotsOnly() } + } + + project.logger.debug("openapi-processor: snapshot repository enabled") + } + + /** + * Provides an Action that checks for plugin updates. + */ + private fun createCheckUpdatesAction(): Action { + return object : Action { + override fun execute(project: Project) { + val extension = getExtension(project) + val interval = extension.checkUpdates.get() + + val version = VersionCheck(project.rootDir.absolutePath, interval) + if (!version.canCheck("gradle")) + return + + checkLatestRelease() + } + } + } + + /** + * Provides an Action that create a 'process{ProcessorName}' task for each configured processor. + */ + private fun createTasksBuilderAction(): Action { + return object : Action { + override fun execute(project: Project) { + val extension = getExtension(project) + extension.processors.get().forEach { entry -> + val name = "process${entry.key.replaceFirstChar { it.uppercase() }}" + val action = createTaskBuilderAction(entry.key, entry.value) + project.tasks.register(name, OpenApiProcessorTask::class.java, action) + } + } + } + } + + /** + * Creates an Action that configures a 'process{ProcessorName}' task from its configuration. + */ + private fun createTaskBuilderAction(name: String, processor: Processor): Action { + return object: Action { + // copy common api path to openapi-processor props if not set + fun copyApiPath (task: OpenApiProcessorTask) { + if(processor.hasApiPath ()) + return + + val extension = getExtension(task.project) + if (!extension.api.isPresent) { + task.logger.warn ("'${EXTENSION_NAME_DEFAULT}.apiPath'!") + return + } + + processor.setApiPath(extension.api.get()) + } + + fun getInputDirectory(): String { + val path = processor.getApiPath() + val file = File(path) + return file.parent + } + + fun getOutputDirectory(): String { + return processor.getTargetDir() + } + + override fun execute(task: OpenApiProcessorTask) { + val project = task.project + + task.getProcessorName().set (processor.name) + task.getProcessorProps().set(processor.other) + task.group = "openapi processor" + task.description = "process openapi with openapi-processor-${processor.name}" + + copyApiPath (task) + task.getApiDir().set(project.layout.projectDirectory.dir(getInputDirectory())) + task.getTargetDir().set(project.layout.projectDirectory.dir(getOutputDirectory())) + + val handler = project.dependencies + val dependencies = ArrayList() + + if (processor.dependencies.isEmpty()) { + task.logger.warn ("'${EXTENSION_NAME_DEFAULT}.${name}.processor' not set!") + } + + dependencies.add (handler.create("io.openapiprocessor:openapi-processor-api:${Versions.api}")) + + processor.dependencies.forEach { + dependencies.add (handler.create (it)) + } + + val deps = dependencies.toTypedArray() + val cfg = project.configurations.detachedConfiguration(*deps) + + cfg.isVisible = false + cfg.isTransitive = true + cfg.description = "the dependencies of the process${name.replaceFirstChar { it.uppercase() }} task." + task.getDependencies().from (cfg) + } + } + } + + private fun checkLatestRelease(): Boolean { + return GitHubVersionCheck(GitHubVersionProvider(), Versions.version).check() + } + + companion object { + private fun isSupportedGradleVersion(project: Project): Boolean { + val version: String = project.gradle.gradleVersion + + if (version < "7.0") { + project.logger.error ("the current gradle version is $version") + project.logger.error ("openapi-processor-gradle requires gradle 7.0+") + return false + } + + return true + } + } +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorTask.kt b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorTask.kt new file mode 100644 index 0000000..e5015f9 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorTask.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Classpath +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.gradle.workers.WorkerExecutor + +import javax.inject.Inject + +/** + * processor task. Uses a worker executor to run the processor with an isolated "openapiProcessor" + * configuration classpath. + */ +abstract class OpenApiProcessorTask: DefaultTask() { + + /** + * Source directory (i.e. parent) of the openapi.yaml input file. Used by gradle for the up-to-date check. + * + * @return parent directory of the openapi.yaml + */ + @InputDirectory + abstract fun getApiDir(): DirectoryProperty + + /** + * Target directory for the sources generated by the processor. Used by gradle for the up-to-date check. + * + * @return target directory + */ + @OutputDirectory + abstract fun getTargetDir(): DirectoryProperty + + /** + * The dependencies of the processor. + * + * @return the processor dependencies + */ + @Classpath + abstract fun getDependencies(): ConfigurableFileCollection + + /** + * name of the processor. + * + * @return the processor name. + */ + @Internal + abstract fun getProcessorName(): Property + + /** + * properties configured by the processor closure in the OpenApiProcessorExtension. + * + * @return the processor properties + */ + @Internal + abstract fun getProcessorProps(): MapProperty + + @Inject + abstract fun getWorkerExecutor(): WorkerExecutor + + /** + * runs the configured processor with its own classloader. + */ + @TaskAction + fun runProcessor() { + val theProcessorName = getProcessorName() + val theProcessorProps = getProcessorProps() + val extension = OpenApiProcessorExtensionUtils.getExtension(project) + + getWorkerExecutor().classLoaderIsolation { + classpath.from(getDependencies()) + + }.submit(OpenApiProcessorWorker::class.java) { + getProcessorName().set(theProcessorName) + getProcessorProps().set(theProcessorProps) + getRootDir().set(project.rootDir.absolutePath) + getCheckUpdates().set(extension.checkUpdates) + } + } +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorWorkParameters.kt b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorWorkParameters.kt new file mode 100644 index 0000000..6d50812 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorWorkParameters.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.workers.WorkParameters + +interface OpenApiProcessorWorkParameters : WorkParameters { + fun getProcessorName(): Property + fun getProcessorProps(): MapProperty + fun getRootDir(): Property + fun getCheckUpdates(): Property +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorWorker.kt b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorWorker.kt new file mode 100644 index 0000000..9433398 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/OpenApiProcessorWorker.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +@file:Suppress("DEPRECATION") + +package io.openapiprocessor.gradle + +import com.github.hauner.openapi.api.OpenApiProcessor +import io.openapiprocessor.api.OpenApiProcessor as OpenApiProcessorV0 +import io.openapiprocessor.api.v1.OpenApiProcessor as OpenApiProcessorV1 +import io.openapiprocessor.api.v2.OpenApiProcessor as OpenApiProcessorV2 +import io.openapiprocessor.api.v2.OpenApiProcessorVersion +import io.openapiprocessor.gradle.version.VersionCheck +import org.gradle.api.logging.Logger +import org.gradle.workers.WorkAction +import org.slf4j.LoggerFactory + +/** + * Runs the processor with the class loader that includes the dependencies from the openapiProcessor + * configuration. + */ +@SuppressWarnings ("deprecation") +abstract class OpenApiProcessorWorker: WorkAction { + private var log: Logger = LoggerFactory.getLogger(this.javaClass.name) as Logger + + @Override + override fun execute() { + val processor = getProcessor(getProcessorName()) + val properties = getProcessorProperties() + + try { + check(processor) + run(processor, properties); + + } catch (t: Throwable) { + waitForLogging() + throw t + } + } + + private fun check (processor: Any) { + try { + if (!shouldCheck(processor)) + return + + runCheck(processor) + + } catch (ignore: Throwable) { + // ignore, do not complain + } + } + + @Suppress("UNCHECKED_CAST") + private fun run(processor: Any, properties: Map) { + when (processor) { + is OpenApiProcessorV2 -> { + processor.run(properties as MutableMap) + } + is OpenApiProcessorV1 -> { + processor.run(properties as MutableMap) + } + is OpenApiProcessorV0 -> { + processor.run(properties as MutableMap) + } + is OpenApiProcessor -> { + processor.run(properties as MutableMap) + } + } + } + + private fun shouldCheck (processor: Any): Boolean { + if(processor !is OpenApiProcessorV2) { + return false + } + + val version = VersionCheck(getRootDir(), getCheckUpdates()) + return version.canCheck(processor.name) + } + + private fun runCheck(processor: Any) { + if (processor !is OpenApiProcessorVersion) { + return + } + + if (processor.hasNewerVersion()) { + val currentVersion = processor.version + val latestVersion = processor.latestVersion + + log.quiet("{} version {} is available! I'm version {}.", + getProcessorName(), latestVersion.name, currentVersion) + } + } + + private fun getProcessor (processorName: String): Any { + val processor = ProcessorLoader.load (processorName, javaClass.getClassLoader ()) + if (processor == null) { + throw MissingProcessorException(processorName) + } + return processor + } + + private fun getProcessorName(): String { + return parameters.getProcessorName().get() + } + + @Suppress("UNCHECKED_CAST") + private fun getProcessorProperties(): Map { + return this.parameters.getProcessorProps().get() + } + + private fun getRootDir(): String { + return parameters.getRootDir().get() + } + + private fun getCheckUpdates(): String { + return parameters.getCheckUpdates().get() + } + + companion object { + private fun waitForLogging () { + // without waiting gradle does not reliably log a processor error/exception. + try { + Thread.sleep (1000) + } catch (e: InterruptedException) { + throw RuntimeException(e) + } + } + } +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/Processor.kt b/src/main/kotlin/io/openapiprocessor/gradle/Processor.kt new file mode 100644 index 0000000..d661112 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/Processor.kt @@ -0,0 +1,128 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle + +import groovy.lang.GString +import org.gradle.api.file.Directory +import org.gradle.api.file.RegularFile +import org.gradle.api.provider.Provider + +/** + * represents an openapi-processor configured in [OpenApiProcessorExtension] + */ + +open class Processor(configName: String): ProcessorBase() { + + companion object { + const val API_PATH = "apiPath" + const val TARGET_DIR = "targetDir" + } + + var name: String + val config: String + val other: MutableMap = mutableMapOf() + val dependencies: MutableCollection = mutableListOf() + + init { + name = configName + config = configName + } + + fun processorName(processorName: String) { + this.name = processorName + } + + fun processorName(processorName: GString) { + this.name = processorName.toString() + } + + fun processor(dependency: Any) { + dependencies.add(dependency) + } + + fun getTargetDir(): String { + return other[TARGET_DIR] as String + } + + fun targetDir(targetDir: String) { + other[TARGET_DIR] = targetDir + } + + fun targetDir(targetDir: GString) { + other[TARGET_DIR] = targetDir.toString() + } + + fun targetDir(targetDir: Directory) { + other[TARGET_DIR] = targetDir.toString() + } + + fun targetDir(targetDir: Provider) { + other[TARGET_DIR] = targetDir.get().toString() + } + + fun setTargetDir(targetDir: String) { + other[TARGET_DIR] = targetDir + } + + fun setTargetDir(targetDir: GString) { + other[TARGET_DIR] = targetDir.toString () + } + + fun setTargetDir(targetDir: Directory) { + other[TARGET_DIR] = targetDir.toString() + } + + /** + * allow to assign targetDir like + * + * {@code targetDir = layout.buildDirectory.dir("openapi")} + * + * @param targetDir targetDir provider + */ + fun setTargetDir(targetDir: Provider) { + other[TARGET_DIR] = targetDir.get().toString() + } + + fun apiPath(apiPath: String) { + other[API_PATH] = apiPath + } + + fun apiPath(apiPath: GString) { + other[API_PATH] = apiPath.toString () + } + + fun hasApiPath(): Boolean { + return other.containsKey(API_PATH) + } + + fun getApiPath(): String { + return other.get (API_PATH) as String + } + + fun setApiPath(path: String) { + other[API_PATH] = path + } + + fun setApiPath(apiPath: RegularFile) { + other[API_PATH] = apiPath.toString() + } + + fun prop(props: Map) { + other.putAll(props) + } + + fun prop(key: String, value: Any) { + if (value is RegularFile) { + other[key] = value.toString() + } else { + other[key] = value + } + } + + fun prop(key: GString, value: Any) { + prop(key.toString(), value) + } +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/ProcessorLoader.kt b/src/main/kotlin/io/openapiprocessor/gradle/ProcessorLoader.kt new file mode 100644 index 0000000..b81de27 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/ProcessorLoader.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +@file:Suppress("DEPRECATION") + +package io.openapiprocessor.gradle + +import com.github.hauner.openapi.api.OpenApiProcessor +import io.openapiprocessor.api.OpenApiProcessor as OpenApiProcessorV0 +import io.openapiprocessor.api.v1.OpenApiProcessor as OpenApiProcessorV1 +import io.openapiprocessor.api.v2.OpenApiProcessor as OpenApiProcessorV2 +import java.util.ServiceLoader + +/** + * Find a processor using the ServiceLoader. + */ +class ProcessorLoader { + companion object { + fun load(processorName: String, classLoader: ClassLoader): Any? { + val processors2 = ServiceLoader.load (OpenApiProcessorV2::class.java, classLoader) + val processor2 = processors2.find { it.name == processorName } + if (processor2 != null) { + return processor2 + } + + val processors1 = ServiceLoader.load (OpenApiProcessorV1::class.java, classLoader) + val processor1 = processors1.find { it.name == processorName } + if (processor1 != null) { + return processor1 + } + + val processors0 = ServiceLoader.load (OpenApiProcessorV0::class.java, classLoader) + val processor0 = processors0.find { it.name == processorName } + if (processor0 != null) { + return processor0 + } + + val processors = ServiceLoader.load (OpenApiProcessor::class.java, classLoader) + val processor = processors.find { it.name == processorName } + if (processor != null) { + return processor + } + + return null + } + } +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersion.kt b/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersion.kt new file mode 100644 index 0000000..4cc74c4 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersion.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle.version + +import java.time.Instant + +class GitHubVersion( + val name: String, + val publishedAt: Instant, + val text: String +) diff --git a/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersionCheck.groovy b/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersionCheck.kt similarity index 51% rename from src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersionCheck.groovy rename to src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersionCheck.kt index edf8b54..87775bb 100644 --- a/src/main/groovy/io/openapiprocessor/gradle/version/GitHubVersionCheck.groovy +++ b/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersionCheck.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle * PDX-License-Identifier: Apache-2.0 */ @@ -9,20 +9,12 @@ package io.openapiprocessor.gradle.version import org.gradle.api.logging.Logger import org.slf4j.LoggerFactory -class GitHubVersionCheck { - private Logger log = LoggerFactory.getLogger(GitHubVersionCheck) as Logger +class GitHubVersionCheck(private val provider: GitHubVersionProvider, private val currentVersion: String) { + private var log: Logger = LoggerFactory.getLogger(this.javaClass.name) as Logger - private GitHubVersionProvider provider - private String currentVersion - - GitHubVersionCheck(GitHubVersionProvider provider, String currentVersion) { - this.provider = provider - this.currentVersion = currentVersion - } - - boolean check () { + fun check(): Boolean { try { - def version = provider.getVersion() + val version = provider.getVersion() if (version.name > currentVersion && !version.name.contains("SNAPSHOT")) { log.quiet("openapi-processor-gradle version ${version.name} is available! I'm version ${currentVersion}.") @@ -30,7 +22,7 @@ class GitHubVersionCheck { } return false - } catch (GitHubVersionException ignore) { + } catch (ignore: GitHubVersionException) { // just ignore, do not complain return false } diff --git a/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersionException.kt b/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersionException.kt new file mode 100644 index 0000000..0891a45 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersionException.kt @@ -0,0 +1,11 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle.version + +import java.net.URI + +class GitHubVersionException(uri: URI, cause: Throwable) + : RuntimeException("can't find version: ${uri}!", cause) diff --git a/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersionProvider.kt b/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersionProvider.kt new file mode 100644 index 0000000..266d1a1 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/version/GitHubVersionProvider.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle.version + +import groovy.json.JsonSlurper +import java.net.URI + +import java.time.Instant + +open class GitHubVersionProvider(private val versionUri: URI = LATEST) { + + @Suppress("UNCHECKED_CAST") + open fun getVersion(): GitHubVersion { + try { + val json = JsonSlurper().parse(versionUri.toURL()) as Map + val name = json["name"]!! + val text = json["body"]!! + val publishedAt = Instant.parse(json["published_at"]!!) + return GitHubVersion(name, publishedAt, text) + } catch (t: Throwable) { + throw GitHubVersionException(versionUri, t) + } + } + + companion object { + val LATEST: URI = URI("https://api.github.com/repos/openapi-processor/openapi-processor-gradle/releases/latest") + } +} diff --git a/src/main/java/io/openapiprocessor/gradle/OpenApiProcessorExtensionBase.java b/src/main/kotlin/io/openapiprocessor/gradle/version/Time.kt similarity index 54% rename from src/main/java/io/openapiprocessor/gradle/OpenApiProcessorExtensionBase.java rename to src/main/kotlin/io/openapiprocessor/gradle/version/Time.kt index 14baa0f..926a138 100644 --- a/src/main/java/io/openapiprocessor/gradle/OpenApiProcessorExtensionBase.java +++ b/src/main/kotlin/io/openapiprocessor/gradle/version/Time.kt @@ -3,7 +3,10 @@ * PDX-License-Identifier: Apache-2.0 */ -package io.openapiprocessor.gradle; +package io.openapiprocessor.gradle.version -abstract class OpenApiProcessorExtensionBase { +import java.time.Instant + +interface Time { + fun now(): Instant } diff --git a/src/main/kotlin/io/openapiprocessor/gradle/version/VersionCheck.kt b/src/main/kotlin/io/openapiprocessor/gradle/version/VersionCheck.kt new file mode 100644 index 0000000..e2502a2 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/version/VersionCheck.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2023 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle.version + +import org.gradle.api.logging.Logger +import org.slf4j.LoggerFactory +import java.io.File + +class VersionCheck(private val rootDir: String, private val interval: String) { + private var log: Logger = LoggerFactory.getLogger(this.javaClass.name) as Logger + + fun canCheck(module: String): Boolean { + when (interval) { + "never" -> { + return false + } + "always" -> { + return true + } + "daily" -> { + val settingsFile = File(rootDir, "build/openapiprocessor/${module}.yaml") + val settings = VersionCheckSettings(settingsFile.toString()) + return VersionCheckLatest(settings, 1).shouldCheck(module) + } + else -> { + log.warn("unknown checkUpdate interval '{}'", interval) + return false + } + } + } +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/version/VersionCheckLatest.kt b/src/main/kotlin/io/openapiprocessor/gradle/version/VersionCheckLatest.kt new file mode 100644 index 0000000..fa8142b --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/version/VersionCheckLatest.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle.version + +import java.time.Instant +import java.time.temporal.ChronoUnit + +class VersionCheckLatest( + private val settings: VersionCheckSettings, + private val intervalDays: Long, + private val time: Time = DefaultTime(), +) { + class DefaultTime: Time { + override fun now(): Instant { + return Instant.now() + } + } + + fun shouldCheck(module: String): Boolean { + val now = time.now() + val last = settings.get(module) + if (last == null) { + settings.set(module, now) + return true + } + + val shouldCheck = last.isBefore(now.minus(intervalDays, ChronoUnit.DAYS)) + if (shouldCheck) { + settings.set(module, now) + return true + } + + return false + } +} diff --git a/src/main/kotlin/io/openapiprocessor/gradle/version/VersionCheckSettings.kt b/src/main/kotlin/io/openapiprocessor/gradle/version/VersionCheckSettings.kt new file mode 100644 index 0000000..f0cd580 --- /dev/null +++ b/src/main/kotlin/io/openapiprocessor/gradle/version/VersionCheckSettings.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2025 https://github.com/openapi-processor/openapi-processor-gradle + * PDX-License-Identifier: Apache-2.0 + */ + +package io.openapiprocessor.gradle.version + +import org.yaml.snakeyaml.Yaml +import java.io.File +import java.io.FileReader +import java.io.FileWriter + +import java.nio.file.Files +import java.time.Instant + +class VersionCheckSettings(private val settingsName: String) { + private val yaml = Yaml() + private var settings: MutableMap = LinkedHashMap() + + fun get(name: String): Instant? { + val at = settings[name] ?: return null + return Instant.parse(at) + } + + fun set(name: String) { + settings[name] = Instant.now().toString() + } + + fun set(name: String, at: Instant) { + settings[name] = at.toString() + } + + fun read() { + val file = File(settingsName) + when { + file.exists() -> { + settings = yaml.load(FileReader(file)) + } + else -> { + settings = LinkedHashMap() + } + } + } + + fun write() { + val file = File(settingsName) + Files.createDirectories(file.parentFile.toPath()) + yaml.dump(settings, FileWriter(file)) + } +} diff --git a/src/test/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionSpec.groovy b/src/test/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionSpec.groovy index 6985208..3c46d5d 100644 --- a/src/test/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionSpec.groovy +++ b/src/test/groovy/io/openapiprocessor/gradle/OpenApiProcessorExtensionSpec.groovy @@ -48,22 +48,22 @@ class OpenApiProcessorExtensionSpec extends Specification { void "creates processor from string" () { when: - ex.test { - processor("a processor") - } + ex.process("test", { + processor("/a processor") + }) then: - ex.processors.get ().test.dependencies.first() == "a processor" + ex.processors.get().test.dependencies.first() == "/a processor" } void "creates processor from file" () { when: - ex.test { + ex.process("test") { processor(project.file("processor")) } then: - ex.processors.get ().test.dependencies.first().name == "processor" + ex.processors.get().test.dependencies.first().name == "processor" } void "converts processor properties to map via process()/prop() methods" () { diff --git a/src/test/groovy/io/openapiprocessor/gradle/ProcessorSpec.groovy b/src/test/groovy/io/openapiprocessor/gradle/ProcessorSpec.groovy index c0e0bbd..2748924 100644 --- a/src/test/groovy/io/openapiprocessor/gradle/ProcessorSpec.groovy +++ b/src/test/groovy/io/openapiprocessor/gradle/ProcessorSpec.groovy @@ -5,7 +5,6 @@ package io.openapiprocessor.gradle -import org.gradle.api.provider.ProviderFactory import org.gradle.testfixtures.ProjectBuilder import spock.lang.Specification diff --git a/src/test/groovy/io/openapiprocessor/gradle/version/GitHubVersionCheckSpec.groovy b/src/test/groovy/io/openapiprocessor/gradle/version/GitHubVersionCheckSpec.groovy index 7948fc0..4970904 100644 --- a/src/test/groovy/io/openapiprocessor/gradle/version/GitHubVersionCheckSpec.groovy +++ b/src/test/groovy/io/openapiprocessor/gradle/version/GitHubVersionCheckSpec.groovy @@ -6,12 +6,13 @@ package io.openapiprocessor.gradle.version import spock.lang.Specification +import java.time.Instant class GitHubVersionCheckSpec extends Specification { void "finds newer version" () { def provider = Stub GitHubVersionProvider - provider.version >> new GitHubVersion(name: "2023.2") + provider.getVersion() >> new GitHubVersion("2023.2", Instant.now(), "newer") when: def check = new GitHubVersionCheck(provider, "2023.1") @@ -23,7 +24,10 @@ class GitHubVersionCheckSpec extends Specification { void "ignores older or equal version" () { def provider = Stub GitHubVersionProvider - provider.version >>> [new GitHubVersion(name: "2022.3"), new GitHubVersion(name: "2022.2")] + provider.getVersion() >>> [ + new GitHubVersion("2022.3", Instant.now(), "newer"), + new GitHubVersion("2022.2", Instant.now(), "newer") + ] when: def check = new GitHubVersionCheck(provider, "2023.1") @@ -37,7 +41,7 @@ class GitHubVersionCheckSpec extends Specification { void "ignores newer snapshot version" () { def provider = Stub GitHubVersionProvider - provider.version >> new GitHubVersion(name: "2023.2-SNAPSHOT") + provider.getVersion() >> new GitHubVersion("2023.2-SNAPSHOT", Instant.now(), "snapshot") when: def check = new GitHubVersionCheck(provider, "2023.1") @@ -49,7 +53,7 @@ class GitHubVersionCheckSpec extends Specification { void "ignores error"() { def provider = Stub GitHubVersionProvider - provider.version >> { throw new GitHubVersionException(null, null) } + provider.getVersion() >> { throw new GitHubVersionException(new URI("/bad"), new Exception()) } when: def check = new GitHubVersionCheck(provider, "any") diff --git a/src/test/groovy/io/openapiprocessor/gradle/version/VersionCheckLatestSpec.groovy b/src/test/groovy/io/openapiprocessor/gradle/version/VersionCheckLatestSpec.groovy index 307981e..6162a0b 100644 --- a/src/test/groovy/io/openapiprocessor/gradle/version/VersionCheckLatestSpec.groovy +++ b/src/test/groovy/io/openapiprocessor/gradle/version/VersionCheckLatestSpec.groovy @@ -5,7 +5,7 @@ package io.openapiprocessor.gradle.version -import io.openapiprocessor.gradle.Time + import spock.lang.Specification import spock.lang.TempDir @@ -21,7 +21,7 @@ class VersionCheckLatestSpec extends Specification { void "should check if there was no latest check"() { def file = testPath.resolve(".openapiprocessor.yaml") def settings = new VersionCheckSettings(file.toString()) - def latest = new VersionCheckLatest(settings, 1) + def latest = new VersionCheckLatest(settings, 1, new VersionCheckLatest.DefaultTime()) when: def check = latest.shouldCheck("gradle") diff --git a/src/testInt/groovy/io/openapiprocessor/gradle/GroovyDslSpec.groovy b/src/testInt/groovy/io/openapiprocessor/gradle/GroovyDslSpec.groovy index b603687..464c8ac 100644 --- a/src/testInt/groovy/io/openapiprocessor/gradle/GroovyDslSpec.groovy +++ b/src/testInt/groovy/io/openapiprocessor/gradle/GroovyDslSpec.groovy @@ -72,4 +72,17 @@ class GroovyDslSpec extends PluginSpec { where: gradleVersion << Gradle.VERSIONS_8.reverse () } + + @Unroll + void "test groovy (method) dsl with with gradle 9 (#gradleVersion)" () { + when: + def result = build(gradleVersion) + + then: + result.task(':processV1').outcome == SUCCESS + result.output.contains("processor v1 did run !") + + where: + gradleVersion << Gradle.VERSIONS_9.reverse () + } } diff --git a/src/testInt/groovy/io/openapiprocessor/gradle/KotlinDslSpec.groovy b/src/testInt/groovy/io/openapiprocessor/gradle/KotlinDslSpec.groovy index d9d7b54..b3ee7c9 100644 --- a/src/testInt/groovy/io/openapiprocessor/gradle/KotlinDslSpec.groovy +++ b/src/testInt/groovy/io/openapiprocessor/gradle/KotlinDslSpec.groovy @@ -72,4 +72,17 @@ class KotlinDslSpec extends PluginSpec { where: gradleVersion << Gradle.VERSIONS_8.reverse () } + + @Unroll + void "test kotlin dsl with with gradle 9 (#gradleVersion)" () { + when: + def result = build(gradleVersion) + + then: + result.task(':processV1').outcome == SUCCESS + result.output.contains("processor v1 did run !") + + where: + gradleVersion << Gradle.VERSIONS_9.reverse () + } } diff --git a/src/testInt/groovy/io/openapiprocessor/gradle/MultipleConfigurationsDifferentProcessorsSpec.groovy b/src/testInt/groovy/io/openapiprocessor/gradle/MultipleConfigurationsDifferentProcessorsSpec.groovy index 06f72b4..140f7a9 100644 --- a/src/testInt/groovy/io/openapiprocessor/gradle/MultipleConfigurationsDifferentProcessorsSpec.groovy +++ b/src/testInt/groovy/io/openapiprocessor/gradle/MultipleConfigurationsDifferentProcessorsSpec.groovy @@ -86,6 +86,18 @@ class MultipleConfigurationsDifferentProcessorsSpec extends PluginSpec { gradleVersion << Gradle.VERSIONS_8.reverse () } + @Unroll + void "process task runs processor from gradle 9 (#gradleVersion)" () { + when: + def result = build(gradleVersion) + + then: + assertResult (result) + + where: + gradleVersion << Gradle.VERSIONS_9.reverse () + } + private void assertResult(BuildResult result) { assert result.task(':processV1').outcome == SUCCESS assert result.output.contains("processor v1 did run !") diff --git a/src/testInt/groovy/io/openapiprocessor/gradle/MultipleConfigurationsSameProcessorSpec.groovy b/src/testInt/groovy/io/openapiprocessor/gradle/MultipleConfigurationsSameProcessorSpec.groovy index 9cc15ac..bc8e457 100644 --- a/src/testInt/groovy/io/openapiprocessor/gradle/MultipleConfigurationsSameProcessorSpec.groovy +++ b/src/testInt/groovy/io/openapiprocessor/gradle/MultipleConfigurationsSameProcessorSpec.groovy @@ -81,6 +81,18 @@ class MultipleConfigurationsSameProcessorSpec extends PluginSpec { gradleVersion << Gradle.VERSIONS_8.reverse () } + @Unroll + void "process task runs processor from gradle 9 (#gradleVersion)" () { + when: + def result = build(gradleVersion) + + then: + assertResult (result) + + where: + gradleVersion << Gradle.VERSIONS_9.reverse () + } + private void assertResult(BuildResult result) { assert result.task(':processFirstApi').outcome == SUCCESS assert result.output.contains("processor one did run !") diff --git a/src/testInt/groovy/io/openapiprocessor/gradle/SnapshotsRepositorySpec.groovy b/src/testInt/groovy/io/openapiprocessor/gradle/SnapshotsRepositorySpec.groovy index 0307ff6..b309cf8 100644 --- a/src/testInt/groovy/io/openapiprocessor/gradle/SnapshotsRepositorySpec.groovy +++ b/src/testInt/groovy/io/openapiprocessor/gradle/SnapshotsRepositorySpec.groovy @@ -29,7 +29,7 @@ class SnapshotsRepositorySpec extends PluginSpec { ['--stacktrace', '--debug'] } - void "does not add snapshot repository if ot enabled or disabled" () { + void "does not add snapshot repository if enabled or disabled" () { when: def result = build("8.5", """\ """.stripIndent()) diff --git a/src/testInt/groovy/io/openapiprocessor/gradle/support/Gradle.groovy b/src/testInt/groovy/io/openapiprocessor/gradle/support/Gradle.groovy index d60d2f5..f0afcbf 100644 --- a/src/testInt/groovy/io/openapiprocessor/gradle/support/Gradle.groovy +++ b/src/testInt/groovy/io/openapiprocessor/gradle/support/Gradle.groovy @@ -7,6 +7,10 @@ package io.openapiprocessor.gradle.support class Gradle { + static List VERSIONS_9 = [ + '9.0.0' + ] + static List VERSIONS_8 = [ /* '8.0', '8.0.1', */ '8.0.2', /* '8.1', */ '8.1.1', @@ -22,16 +26,20 @@ class Gradle { /* '8.11', */ '8.11.1', /* '8.12', */ '8.12.1', '8.13', - /* '8.14', '8.14.1',*/ '8.14.2' + /* '8.14', '8.14.1', '8.14.2' */ '8.14.3' ] static List VERSIONS_7 = [ - /* '7.0', '7.0.1', */ '7.0.2', - /* '7.1', */ '7.1.1', '7.2', /* '7.3', '7.3.1', '7.3.2', */ '7.3.3', /* '7.4', '7.4.1', */ '7.4.2', /* '7.5', */ '7.5.1', - /* '7.6', '7.6.1', '7.6.2', '7.6.3', '7.6.4', */ '7.6.5' + /* '7.6', '7.6.1', '7.6.2', '7.6.3', '7.6.4', '7.6.5' */ '7.6.6' + ] + + // these only work with java 11 + static List VERSIONS_7_JDK11 = [ + /* '7.0', '7.0.1', */ '7.0.2', + /* '7.1', */ '7.1.1' ] } diff --git a/src/testInt/groovy/io/openapiprocessor/gradle/support/PluginSpec.groovy b/src/testInt/groovy/io/openapiprocessor/gradle/support/PluginSpec.groovy index f10f20b..ede56cb 100644 --- a/src/testInt/groovy/io/openapiprocessor/gradle/support/PluginSpec.groovy +++ b/src/testInt/groovy/io/openapiprocessor/gradle/support/PluginSpec.groovy @@ -49,6 +49,7 @@ abstract class PluginSpec extends Specification { .withArguments(getGradleArguments ()) .withPluginClasspath ([ new File("${projectDir}/build/classes/groovy/main/"), + new File("${projectDir}/build/classes/kotlin/main/"), new File("${projectDir}/build/classes/java/main/"), new File("${projectDir}/build/resources/main/") ])