diff --git a/build.gradle.kts b/build.gradle.kts index d8ead21..65ac81a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,11 @@ +@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed plugins { groovy id("java-library") id("maven-publish") id("signing") - id("com.github.ben-manes.versions") version ("0.41.0") - id("io.github.gradle-nexus.publish-plugin") version ("1.1.0") + alias(libs.plugins.nexus) + alias(libs.plugins.versions) } val projectGroupId: String by project @@ -14,47 +15,12 @@ group = projectGroupId version = projectVersion java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 -} - -fun getBuildProperty(property: String): String { - val prop: String? = project.findProperty(property) as String? - if(prop != null) { - return prop - } - - val env: String? = System.getenv(property) - if (env != null) { - return env - } - - return "n/a" -} - -fun getBuildSignKey(property: String): String { - val prop: String? = project.findProperty(property) as String? - if(prop != null) { - return prop - } - - val env: String? = System.getenv(property) - if (env != null) { - return env.replace("\\n", "\n") + toolchain { + languageVersion.set(JavaLanguageVersion.of(libs.versions.build.jdk.get())) } - return "n/a" -} - -fun isReleaseVersion(): Boolean { - return !(project.version.toString().endsWith("SNAPSHOT")) -} - -ext { - set("publishUser", getBuildProperty("PUBLISH_USER")) - set("publishKey", getBuildProperty("PUBLISH_KEY")) - set("signKey", getBuildSignKey("SIGN_KEY")) - set("signPwd", getBuildProperty("SIGN_PWD")) + withJavadocJar () + withSourcesJar () } repositories { @@ -68,118 +34,21 @@ repositories { } dependencies { - compileOnly("io.openapiprocessor:openapi-processor-api:2021.1") - - implementation(platform("com.fasterxml.jackson:jackson-bom:2.13.1")) - implementation(platform("org.codehaus.groovy:groovy-bom:3.0.9")) + compileOnly(libs.openapi.processor.api) - implementation("org.codehaus.groovy:groovy") - implementation("org.codehaus.groovy:groovy-nio") + implementation(platform(libs.jackson.bom)) implementation("com.fasterxml.jackson.core:jackson-databind") implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml") - implementation("io.github.java-diff-utils:java-diff-utils:4.11") - implementation("com.google.jimfs:jimfs:1.2") { - exclude("com.google.guava") - } -} -val sourcesJar by tasks.registering(Jar::class) { - archiveClassifier.set("sources") - from(sourceSets.main.get().allSource) -} - -val javadocJar by tasks.registering(Jar::class) { - dependsOn("javadoc") - archiveClassifier.set("javadoc") - from(tasks.javadoc.get().destinationDir) -} - -artifacts { - archives(sourcesJar) - archives(javadocJar) -} + implementation(platform(libs.groovy.bom)) + implementation("org.apache.groovy:groovy") + implementation("org.apache.groovy:groovy-nio") -//apply(from = "${rootProject.rootDir}/gradle/publishing.gradle.kts") - -val projectTitle: String by project -val projectDesc: String by project -val projectUrl: String by project -val projectGithubRepo: String by project - -// does not work on oss.sonatype.org -tasks.withType().configureEach { - enabled = false -} - -publishing { - publications { - create("OpenApiProcessor") { - from(components["java"]) - artifact(sourcesJar.get()) - artifact(javadocJar.get()) - - groupId = project.group.toString() - artifactId = project.name - version = project.version.toString() - - pom { - name.set(projectTitle) - description.set(projectDesc) - url.set(projectUrl) - - licenses { - license { - name.set("The Apache License, Version 2.0") - url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") - distribution.set("repo") - } - } - - developers { - developer { - id.set("hauner") - name.set("Martin Hauner") - } - } - - scm { - url.set("https://github.com/${projectGithubRepo}") - } - } - } - } - - 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 = project.extra["publishUser"].toString() - password = project.extra["publishKey"].toString() - } - } + implementation(libs.diff.utils) + implementation(libs.jimfs) { + exclude("com.google.guava") } + implementation(libs.slf4j) } -//tasks.withType().configureEach { -// onlyIf { isReleaseVersion() } -//} - -signing { - useInMemoryPgpKeys( - project.extra["signKey"].toString(), - project.extra["signPwd"].toString()) - - sign(publishing.publications["OpenApiProcessor"]) -} - -nexusPublishing { - repositories { - sonatype { - username.set(project.extra["publishUser"].toString()) - password.set(project.extra["publishKey"].toString()) - } - } -} +apply(from = "${rootProject.rootDir}/gradle/publishing.gradle") diff --git a/gradle.properties b/gradle.properties index 3f91cce..a55378d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -projectVersion=2022.2p-SNAPSHOT +projectVersion=2022.5-SNAPSHOT projectGroupId=io.openapiprocessor projectUrl=https://openapiprocessor.io diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..3e1d29c --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,21 @@ +[versions] +build-jdk = "11" +target-jdk = "8" + +[libraries] +openapi-processor-api = "io.openapiprocessor:openapi-processor-api:2021.1" + +jackson-bom = "com.fasterxml.jackson:jackson-bom:2.13.4" +jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind" } +jackson-yaml = { module = "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" } + +groovy-bom = "org.apache.groovy:groovy-bom:4.0.5" + +diff-utils = "io.github.java-diff-utils:java-diff-utils:4.12" +jimfs = "com.google.jimfs:jimfs:1.2" +slf4j = "org.slf4j:slf4j-api:2.0.3" + +[plugins] +versions = { id = "com.github.ben-manes.versions", version = "0.42.0" } +nexus = { id = "io.github.gradle-nexus.publish-plugin", version = "1.1.0" } +jacoco = { id = "org.barfuin.gradle.jacocolog", version = "2.0.0" } diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle new file mode 100644 index 0000000..6e23e5a --- /dev/null +++ b/gradle/publishing.gradle @@ -0,0 +1,94 @@ +configure(project.rootProject) { + ext { + publishUser = getBuildProperty ('PUBLISH_USER') + publishKey = getBuildProperty ('PUBLISH_KEY') + + signKey = getBuildSignKey ('SIGN_KEY') + signPwd = getBuildProperty ('SIGN_PWD') + + isReleaseVersion = !version.endsWith("SNAPSHOT") + } +} + +publishing { + publications { + processorTest (MavenPublication) { + groupId project.group + artifactId project.name + version project.version + + from components.java + + pom { + name = project.projectTitle + description = project.projectDesc + url = project.projectUrl + + 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' + } + } + + scm { + url = "https://github.com/${project.projectGithubRepo}".toString () + } + } + + } + } + + repositories { + maven { + def releaseRepository = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2") + def snapshotRepository = uri("https://oss.sonatype.org/content/repositories/snapshots") + url = project.isReleaseVersion ? releaseRepository : snapshotRepository + + credentials { + username = publishUser + password = publishKey + } + } + } +} + +//tasks.withType(Sign) { +// onlyIf { project.isReleaseVersion } +//} + +signing { + useInMemoryPgpKeys(signKey, signPwd) + + signing { + sign publishing.publications.processorTest + } +} + +nexusPublishing { + repositories { + sonatype() { + username = publishUser + password = publishKey + } + } +} + +// helper + +String getBuildProperty(String property) { + project.findProperty (property) ?: System.getenv (property) ?: 'n/a' +} + +String getBuildSignKey(String property) { + project.findProperty (property) ?: System.getenv (property) ? + System.getenv (property).replace("\\n", "\n"): 'n/a' +} diff --git a/gradle/publishing.gradle.kts b/gradle/publishing.gradle.kts new file mode 100644 index 0000000..8bcc156 --- /dev/null +++ b/gradle/publishing.gradle.kts @@ -0,0 +1,84 @@ +/* +val projectTitle: String by project +val projectDesc: String by project +val projectUrl: String by project +val projectGithubRepo: String by project + +// does not work on oss.sonatype.org +tasks.withType().configureEach { + enabled = false +} + +publishing { + publications { + create("OpenApiProcessor") { + from(components["java"]) + artifact(sourcesJar.get()) + artifact(javadocJar.get()) + + groupId = project.group.toString() + artifactId = project.name + version = project.version.toString() + + pom { + name.set(projectTitle) + description.set(projectDesc) + url.set(projectUrl) + + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + distribution.set("repo") + } + } + + developers { + developer { + id.set("hauner") + name.set("Martin Hauner") + } + } + + scm { + url.set("https://github.com/${projectGithubRepo}") + } + } + } + } + + 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 = project.extra["publishUser"].toString() + password = project.extra["publishKey"].toString() + } + } + } +} + +//tasks.withType().configureEach { +// onlyIf { isReleaseVersion() } +//} + +signing { + useInMemoryPgpKeys( + project.extra["signKey"].toString(), + project.extra["signPwd"].toString()) + + sign(publishing.publications["OpenApiProcessor"]) +} + +nexusPublishing { + repositories { + sonatype { + username.set(project.extra["publishUser"].toString()) + password.set(project.extra["publishKey"].toString()) + } + } +} +*/ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a0f7639..8fad3f5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/groovy/io/openapiprocessor/test/FileSupport.groovy b/src/main/groovy/io/openapiprocessor/test/FileSupport.groovy index 414193d..c9e9847 100644 --- a/src/main/groovy/io/openapiprocessor/test/FileSupport.groovy +++ b/src/main/groovy/io/openapiprocessor/test/FileSupport.groovy @@ -10,12 +10,16 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.dataformat.yaml.YAMLFactory import com.github.difflib.DiffUtils import com.github.difflib.UnifiedDiffUtils +import org.slf4j.Logger +import org.slf4j.LoggerFactory import java.nio.file.Files import java.nio.file.Path import java.util.stream.Stream class FileSupport { + private static final Logger log = LoggerFactory.getLogger (FileSupport) + private Class resourceBase private String inputs private String generated @@ -37,13 +41,17 @@ class FileSupport { .filter ({f -> !Files.isDirectory (f)}) paths.forEach { p -> - Path relativePath = source.relativize (p) - Path targetPath = target.resolve (relativePath.toString ()) - Files.createDirectories (targetPath.getParent ()) - - InputStream src = Files.newInputStream (p) - OutputStream dst = Files.newOutputStream (targetPath) - src.transferTo (dst) + try { + Path relativePath = source.relativize (p) + Path targetPath = target.resolve (relativePath.toString ()) + Files.createDirectories (targetPath.getParent ()) + + InputStream src = Files.newInputStream (p) + OutputStream dst = Files.newOutputStream (targetPath) + src.transferTo (dst) + } catch (Exception ex) { + log.error ("failed to copy {}", p.toString (), ex) + } } paths.close () @@ -58,14 +66,18 @@ class FileSupport { */ void copy (String source, List sources, Path target) { for (String p : sources) { - String relativePath = p.substring (source.size () + 1) - - Path targetPath = target.resolve (relativePath.toString ()) - Files.createDirectories (targetPath.getParent ()) - - InputStream src = getResource (p) - OutputStream dst = Files.newOutputStream (targetPath) - src.transferTo (dst) + try { + String relativePath = p.substring (source.size () + 1) + + Path targetPath = target.resolve (relativePath.toString ()) + Files.createDirectories (targetPath.getParent ()) + + InputStream src = getResource (p) + OutputStream dst = Files.newOutputStream (targetPath) + src.transferTo (dst) + } catch (Exception ex) { + log.error ("failed to copy {}", p, ex) + } } } @@ -110,13 +122,18 @@ class FileSupport { * collect output paths, relative to packageName */ List collectRelativeOutputPaths (String path, String packageName) { - collectRelativeResourcePaths (path, generated).collect { - it.substring (packageName.size () + 1) + def testItems = readTestItems (path, generated) + + def items = [] + testItems.items.forEach { + items.add (it.substring (packageName.size () + 1)) } + + items } /** - * collect absolute paths from output.yaml in resources + * collect absolute paths from items listed in the test items yaml file */ List collectAbsoluteResourcePaths (String path, String itemsYaml) { collectRelativeResourcePaths (path, itemsYaml).collect { @@ -125,21 +142,90 @@ class FileSupport { } /** - * collect paths from output.yaml in resources + * collect paths from test items yaml file (input.yaml/generated.yaml) */ List collectRelativeResourcePaths (String path, String itemsYaml) { + def testItems = readTestItems (path, itemsYaml) + testItems.items + } + + /** + * get the generated files. + * + * @param path path of the generated files + * @return the generated files + */ + static SortedSet getGeneratedFiles (Path path) { + def result = new TreeSet () + result.addAll (collectPaths (path)) + result + } + + /** + *get the expected files (from generated.yaml) and strip package name. + * + * @param path the resource path of the test + * @param packageName stripped package name + * @return the expected files + */ + SortedSet getExpectedFiles (String path, String packageName) { + def items = readTestItems (path, generated) + + def wanted = items.items.collect { + it.substring (packageName.size () + 1) + } + + def result = new TreeSet () + result.addAll (wanted) + result + } + + /** + * read expected files and strip package name. + * + * @param path the resource path of the test + * @param packageName stripped package name + * @return the expected files + TestItems getExpectedFiles (String path, String packageName) { + def items = readTestItems (path, generated) + + def wanted = items.items.collect { + it.substring (packageName.size () + 1) + } + + def ignore = items.ignore.collect { + it.substring (packageName.size () + 1) + } + + def expected = new TestItems () + expected.items = wanted.sort () + expected.ignore = ignore.sort () + expected + } + */ + + /** + * read test items yaml + * + * @param resource path + * @param name of test items yaml file + * @return content of yaml + */ + TestItems readTestItems (String path, String itemsYaml) { def source = getResource ("${path}/${itemsYaml}") if (!source) { println "ERROR: missing '${path}/${itemsYaml}' configuration file!" } def mapper = createYamlParser () - def sourceItems = mapper.readValue (source.text, TestItems) - sourceItems.items + mapper.readValue (source.text, TestItems) } /** - * unified diff resources <=> file system + * unified diff resources <=> file system. + * + * @param expected resource path + * @param generated file system path * * @return true if there is a difference */ @@ -166,9 +252,14 @@ class FileSupport { } /** - * unified diff file system <=> file system + * unified diff file system <=> file system. + * + * @param expected file system path + * @param generated file system path + * + * @return true if there is a difference */ - static void printUnifiedDiff (Path expected, Path generated) { + boolean printUnifiedDiff (Path expected, Path generated) { def patch = DiffUtils.diff ( expected.readLines (), generated.readLines ()) @@ -184,6 +275,8 @@ class FileSupport { diff.each { println it } + + return !patch.deltas.isEmpty () } InputStream getResource (String path) { diff --git a/src/main/groovy/io/openapiprocessor/test/TestItems.groovy b/src/main/groovy/io/openapiprocessor/test/TestItems.groovy index 2bff262..976d82a 100644 --- a/src/main/groovy/io/openapiprocessor/test/TestItems.groovy +++ b/src/main/groovy/io/openapiprocessor/test/TestItems.groovy @@ -1,17 +1,6 @@ /* - * 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. + * Copyright 2020 https://github.com/openapi-processor/openapi-processor-test + * PDX-License-Identifier: Apache-2.0 */ package io.openapiprocessor.test @@ -20,7 +9,5 @@ package io.openapiprocessor.test * input.yaml / generated.yaml mapping. */ class TestItems { - List items - } diff --git a/src/main/groovy/io/openapiprocessor/test/TestSetRunner.groovy b/src/main/groovy/io/openapiprocessor/test/TestSetRunner.groovy index a02d374..6e0844a 100644 --- a/src/main/groovy/io/openapiprocessor/test/TestSetRunner.groovy +++ b/src/main/groovy/io/openapiprocessor/test/TestSetRunner.groovy @@ -54,11 +54,14 @@ class TestSetRunner { def expectedPath = "${sourcePath}/${packageName}" def generatedPath = Path.of (folder.absolutePath).resolve (packageName) - def expectedFiles = files.collectRelativeOutputPaths (sourcePath, packageName).sort () - def generatedFiles = files.collectPaths (generatedPath).sort () + def expectedFiles = files.getExpectedFiles (sourcePath, packageName) + def generatedFiles = files.getGeneratedFiles (generatedPath) - assert expectedFiles == generatedFiles + // even if not expected, check that the annotation was generated + def expectedFilesPlus = expectedFiles + ["support/Generated.java"] + assert expectedFilesPlus == generatedFiles + // compare expected files with the generated files def success = true expectedFiles.each { def expected = "${expectedPath}/$it" @@ -110,9 +113,12 @@ class TestSetRunner { processor.run (options) then: - def expectedFiles = files.collectPaths (expectedPath) - def generatedFiles = files.collectPaths (generatedPath) - assert expectedFiles == generatedFiles + def expectedFiles = files.getExpectedFiles (path, packageName) + def generatedFiles = files.getGeneratedFiles (generatedPath) + + // even if not expected, check that the annotation was generated + def expectedFilesPlus = expectedFiles + ["support/Generated.java"] + assert expectedFilesPlus == generatedFiles def success = true expectedFiles.each {