From 17a5c40e46b0ed2dc189981baa0952a98567c3f5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 08:28:11 -0400 Subject: [PATCH 001/479] initial import --- .gitignore | 70 ++++++++ build.gradle | 26 +++ gradle.properties | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 50518 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++++++++++++++++++ gradlew.bat | 90 ++++++++++ settings.gradle | 1 + .../gradle/plugin/avro/AvroPlugin.java | 59 +++++++ .../gradle/plugin/avro/Constants.java | 9 + .../plugin/avro/GenerateAvroJavaTask.java | 49 ++++++ .../plugin/avro/GenerateAvroProtocolTask.java | 43 +++++ .../gradle/plugin/avro/OutputDirTask.java | 18 ++ .../META-INF/gradle-plugins/avro.properties | 1 + .../gradle/plugin/avro/AvroPluginSpec.groovy | 59 +++++++ 15 files changed, 596 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/Constants.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java create mode 100644 src/main/resources/META-INF/gradle-plugins/avro.properties create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..7adeb75184b --- /dev/null +++ b/.gitignore @@ -0,0 +1,70 @@ +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log + +# OS generated files # +###################### +.DS_Store* +ehthumbs.db +Icon? +Thumbs.db + +# Editor Files # +################ +*~ +*.swp + +# Gradle Files # +################ +.gradle +local.properties + +# Build output directies +/target +**/test-output +**/target +**/bin +build +*/build +.m2 + +# IntelliJ specific files/directories +out +.idea +*.ipr +*.iws +*.iml +atlassian-ide-plugin.xml + +# Eclipse specific files/directories +.classpath +.project +.settings +.metadata +.factorypath +.generated + +# NetBeans specific files/directories +.nbattrs diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000000..f433ea6d07f --- /dev/null +++ b/build.gradle @@ -0,0 +1,26 @@ +apply plugin: "groovy" +apply plugin: "idea" +apply plugin: "maven-publish" + +repositories { + jcenter() +} + +dependencies { + compile gradleApi() + compile localGroovy() + compile "org.apache.avro:avro-compiler:1.7.5" + testCompile "org.spockframework:spock-core:0.6-groovy-1.8" +} + +sourceCompatibility = 1.7 + +group = "com.commercehub.gradle.plugin" + +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + } + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000000..8d0c7be9623 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +version=1.0.0-SNAPSHOT diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..b979729db0ad460288cfe16f07072da7b1305e93 GIT binary patch literal 50518 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..93eec6c72a7 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Oct 21 09:54:33 EDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-1.7-bin.zip diff --git a/gradlew b/gradlew new file mode 100755 index 00000000000..91a7e269e19 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000000..8a0b282aa68 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000000..cf064976db5 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "gradle-avro-plugin" diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java new file mode 100644 index 00000000000..f805b1146cb --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -0,0 +1,59 @@ +package com.commercehub.gradle.plugin.avro; + +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceTask; + +import java.io.File; + +public class AvroPlugin implements Plugin { + @Override + public void apply(final Project project) { + project.getPlugins().apply(JavaPlugin.class); + project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().all(new Action() { + public void execute(SourceSet sourceSet) { + // TODO: use an extension? + GenerateAvroProtocolTask protoTask = configureProtocolGenerationTask(project, sourceSet); + configureJavaGenerationTask(project, sourceSet, protoTask); + } + }); + } + + private static GenerateAvroProtocolTask configureProtocolGenerationTask(Project project, SourceSet sourceSet) { + File outputDir = getGeneratedOutputDir(project, sourceSet, Constants.PROTOCOL_EXTENSION); + String taskName = sourceSet.getTaskName("generate", "avroProtocol"); + GenerateAvroProtocolTask task = project.getTasks().create(taskName, GenerateAvroProtocolTask.class); + task.setDescription(String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); + // TODO: group name? + task.source(project.file(String.format("src/%s/avro", sourceSet.getName()))); + task.include("*." + Constants.IDL_EXTENSION); + task.setOutputDir(outputDir); + return task; + } + + private static GenerateAvroJavaTask configureJavaGenerationTask(Project project, SourceSet sourceSet, GenerateAvroProtocolTask protoTask) { + File outputDir = getGeneratedOutputDir(project, sourceSet, "java"); + String taskName = sourceSet.getTaskName("generate", "avroJava"); + GenerateAvroJavaTask task = project.getTasks().create(taskName, GenerateAvroJavaTask.class); + task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.", sourceSet.getName())); + // TODO: group name? + task.source(project.file(String.format("src/%s/avro", sourceSet.getName()))); + task.source(protoTask.getOutputs()); + task.include("*." + Constants.SCHEMA_EXTENSION, "*." + Constants.PROTOCOL_EXTENSION); + task.setOutputDir(outputDir); + getCompileJavaTask(project, sourceSet).source(task.getOutputs()); + return task; + } + + private static File getGeneratedOutputDir(Project project, SourceSet sourceSet, String extension) { + return new File(project.getBuildDir(), String.format("generated-%s-avro-%s", sourceSet.getName(), extension)); + } + + private static SourceTask getCompileJavaTask(Project project, SourceSet sourceSet) { + return (SourceTask) project.getTasks().getByName(sourceSet.getCompileJavaTaskName()); + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java new file mode 100644 index 00000000000..243457df8ec --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -0,0 +1,9 @@ +package com.commercehub.gradle.plugin.avro; + +class Constants { + static final String UTF8_ENCONDING = "UTF-8"; + + static final String SCHEMA_EXTENSION = "avsc"; + static final String PROTOCOL_EXTENSION = "avpr"; + static final String IDL_EXTENSION = "avdl"; +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java new file mode 100644 index 00000000000..6cf7b45274d --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -0,0 +1,49 @@ +package com.commercehub.gradle.plugin.avro; + +import org.apache.avro.compiler.specific.SpecificCompiler; +import org.apache.commons.io.FilenameUtils; +import org.gradle.api.GradleException; +import org.gradle.api.file.FileCollection; +import org.gradle.api.tasks.TaskAction; + +import java.io.File; +import java.io.IOException; + +public class GenerateAvroJavaTask extends OutputDirTask { + @TaskAction + protected void process() { + boolean didWork = false; + FileCollection sourceFiles = getInputs().getSourceFiles(); + getLogger().info("Found {} files", sourceFiles.getFiles().size()); + for (File sourceFile : sourceFiles) { + getLogger().info("Processing {}", sourceFile); + String extension = FilenameUtils.getExtension(sourceFile.getName()); + if (Constants.PROTOCOL_EXTENSION.equals(extension)) { + processProtoFile(sourceFile); + didWork = true; + } else if (Constants.SCHEMA_EXTENSION.equals(extension)) { + processSchemaFile(sourceFile); + didWork = true; + } else { + throw new GradleException(String.format("Supported file extension: %s", sourceFile)); + } + } + setDidWork(didWork); + } + + private void processProtoFile(File sourceFile) { + try { + SpecificCompiler.compileProtocol(sourceFile, getOutputDir()); + } catch (IOException ex) { + throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); + } + } + + private void processSchemaFile(File sourceFile) { + try { + SpecificCompiler.compileSchema(sourceFile, getOutputDir()); + } catch (IOException ex) { + throw new GradleException(String.format("Failed to compile schema definition file %s", sourceFile), ex); + } + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java new file mode 100644 index 00000000000..15e42bdb5f8 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -0,0 +1,43 @@ +package com.commercehub.gradle.plugin.avro; + +import org.apache.avro.compiler.idl.Idl; +import org.apache.avro.compiler.idl.ParseException; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.gradle.api.GradleException; +import org.gradle.api.file.FileCollection; +import org.gradle.api.tasks.TaskAction; + +import java.io.File; +import java.io.IOException; + +public class GenerateAvroProtocolTask extends OutputDirTask { + @TaskAction + protected void process() { + boolean didWork = false; + FileCollection sourceFiles = getInputs().getSourceFiles(); + getLogger().info("Found {} files", sourceFiles.getFiles().size()); + for (File sourceFile : sourceFiles) { + getLogger().info("Processing {}", sourceFile); + String extension = FilenameUtils.getExtension(sourceFile.getName()); + if (Constants.IDL_EXTENSION.equals(extension)) { + processIDLFile(sourceFile); + didWork = true; + } else { + throw new GradleException(String.format("Unsupported file extension: %s for %s", extension, sourceFile)); + } + } + setDidWork(didWork); + } + + private void processIDLFile(File idlFile) { + File protoFile = new File(getOutputDir(), + FilenameUtils.getBaseName(idlFile.getName()) + Constants.PROTOCOL_EXTENSION); + try (Idl idl = new Idl(idlFile)) { + String protoJson = idl.CompilationUnit().toString(); + FileUtils.writeStringToFile(protoFile, protoJson, Constants.UTF8_ENCONDING); + } catch (IOException | ParseException ex) { + throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); + } + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java new file mode 100644 index 00000000000..05c6fe4b652 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java @@ -0,0 +1,18 @@ +package com.commercehub.gradle.plugin.avro; + +import org.gradle.api.tasks.SourceTask; + +import java.io.File; + +class OutputDirTask extends SourceTask { + private File outputDir; + + public void setOutputDir(File outputDir) { + this.outputDir = outputDir; + getOutputs().dir(outputDir); + } + + protected File getOutputDir() { + return outputDir; + } +} diff --git a/src/main/resources/META-INF/gradle-plugins/avro.properties b/src/main/resources/META-INF/gradle-plugins/avro.properties new file mode 100644 index 00000000000..514cc66f7a7 --- /dev/null +++ b/src/main/resources/META-INF/gradle-plugins/avro.properties @@ -0,0 +1 @@ +implementation-class=com.commercehub.gradle.plugin.avro.AvroPlugin diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy new file mode 100644 index 00000000000..9daff99a171 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy @@ -0,0 +1,59 @@ +package com.commercehub.gradle.plugin.avro + +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import spock.lang.Specification + +class AvroPluginSpec extends Specification { + Project project = ProjectBuilder.builder().build() + + def "avro protocol generation tasks are registered"() { + when: "the plugin is applied to a project" + project.apply(plugin: AvroPlugin) + + then: "avro protocol generation tasks are registered with the project with appropriate configuration" + project.tasks.withType(GenerateAvroProtocolTask).collect {it.name}.sort() == ["generateAvroProtocol", "generateTestAvroProtocol"] + mainGenerateAvroProtoTask.description == "Generates main Avro protocol definition files from IDL files." + testGenerateAvroProtoTask.description == "Generates test Avro protocol definition files from IDL files." + mainGenerateAvroProtoTask.group == null + testGenerateAvroProtoTask.group == null + // Can't easily test the sources + mainGenerateAvroProtoTask.outputDir == project.file("build/generated-main-avro-avpr") + testGenerateAvroProtoTask.outputDir == project.file("build/generated-test-avro-avpr") + } + + def "avro java generation tasks are registered"() { + when: "the plugin is applied to a project" + project.apply(plugin: AvroPlugin) + + then: "avro java generation tasks are registered with the project with appropriate configuration" + project.tasks.withType(GenerateAvroJavaTask).collect {it.name}.sort() == ["generateAvroJava", "generateTestAvroJava"] + mainGenerateAvroJavaTask.description == "Generates main Avro Java source files from schema/protocol definition files." + testGenerateAvroJavaTask.description == "Generates test Avro Java source files from schema/protocol definition files." + mainGenerateAvroJavaTask.group == null + testGenerateAvroJavaTask.group == null + // Can't easily test the sources + mainGenerateAvroJavaTask.outputDir == project.file("build/generated-main-avro-java") + testGenerateAvroJavaTask.outputDir == project.file("build/generated-test-avro-java") + } + + OutputDirTask getTask(String name) { + return project.tasks.getByName(name) as OutputDirTask + } + + OutputDirTask getMainGenerateAvroProtoTask() { + return getTask("generateAvroProtocol") + } + + OutputDirTask getTestGenerateAvroProtoTask() { + return getTask("generateTestAvroProtocol") + } + + OutputDirTask getMainGenerateAvroJavaTask() { + return getTask("generateAvroJava") + } + + OutputDirTask getTestGenerateAvroJavaTask() { + return getTask("generateTestAvroJava") + } +} From e5ef38166d185233df1c12c2124421c6d864caa0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 08:35:18 -0400 Subject: [PATCH 002/479] fix exception message when unsupported file extension is used --- .../commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 6cf7b45274d..1376b02be3a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -25,7 +25,7 @@ protected void process() { processSchemaFile(sourceFile); didWork = true; } else { - throw new GradleException(String.format("Supported file extension: %s", sourceFile)); + throw new GradleException(String.format("Unsupported file extension: %s for %s", extension, sourceFile)); } } setDidWork(didWork); From df8fe193e736877754cabb029b66447ddcdeab26 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 08:59:04 -0400 Subject: [PATCH 003/479] generateAvroJava: use logic from avro-tools SpecificCompilerTool This enables compiling schema definition files that have dependencies on each other, as long as they're processed in the right order. --- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 1376b02be3a..a65c2472b7a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -1,5 +1,7 @@ package com.commercehub.gradle.plugin.avro; +import org.apache.avro.Protocol; +import org.apache.avro.Schema; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.commons.io.FilenameUtils; import org.gradle.api.GradleException; @@ -10,6 +12,8 @@ import java.io.IOException; public class GenerateAvroJavaTask extends OutputDirTask { + private Schema.Parser parser = new Schema.Parser(); + @TaskAction protected void process() { boolean didWork = false; @@ -33,7 +37,9 @@ protected void process() { private void processProtoFile(File sourceFile) { try { - SpecificCompiler.compileProtocol(sourceFile, getOutputDir()); + Protocol protocol = Protocol.parse(sourceFile); + SpecificCompiler compiler = new SpecificCompiler(protocol); + compiler.compileToDestination(sourceFile, getOutputDir()); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); } @@ -41,7 +47,9 @@ private void processProtoFile(File sourceFile) { private void processSchemaFile(File sourceFile) { try { - SpecificCompiler.compileSchema(sourceFile, getOutputDir()); + Schema schema = parser.parse(sourceFile); + SpecificCompiler compiler = new SpecificCompiler(schema); + compiler.compileToDestination(sourceFile, getOutputDir()); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile schema definition file %s", sourceFile), ex); } From c4d3d066c464fb2d79f705484e5494dc0e7ba06e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 09:29:57 -0400 Subject: [PATCH 004/479] generateAvroJava: separate handling of different file types --- .../plugin/avro/GenerateAvroJavaTask.java | 57 +++++++++++++++---- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index a65c2472b7a..009384f082f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -5,37 +5,69 @@ import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.commons.io.FilenameUtils; import org.gradle.api.GradleException; -import org.gradle.api.file.FileCollection; import org.gradle.api.tasks.TaskAction; import java.io.File; import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; public class GenerateAvroJavaTask extends OutputDirTask { + private static Set SUPPORTED_EXTENSIONS = Collections.unmodifiableSet(new HashSet<>( + Arrays.asList(Constants.PROTOCOL_EXTENSION, Constants.SCHEMA_EXTENSION))); + private Schema.Parser parser = new Schema.Parser(); @TaskAction protected void process() { - boolean didWork = false; - FileCollection sourceFiles = getInputs().getSourceFiles(); - getLogger().info("Found {} files", sourceFiles.getFiles().size()); - for (File sourceFile : sourceFiles) { - getLogger().info("Processing {}", sourceFile); + getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); + failOnUnsupportedFiles(); + } + + private void failOnUnsupportedFiles() { + for (File sourceFile : getInputs().getSourceFiles()) { + String extension = FilenameUtils.getExtension(sourceFile.getName()); + if (!SUPPORTED_EXTENSIONS.contains(extension)) { + throw new GradleException(String.format("Unsupported file extension: %s for %s", extension, sourceFile)); + } + } + } + + private void processFiles() { + int processedFileCount = 0; + processedFileCount += processProtoFiles(); + processedFileCount += processSchemaFiles(); + setDidWork(processedFileCount > 0); + } + + private int processProtoFiles() { + int processedFileCount = 0; + for (File sourceFile : getInputs().getSourceFiles()) { String extension = FilenameUtils.getExtension(sourceFile.getName()); if (Constants.PROTOCOL_EXTENSION.equals(extension)) { processProtoFile(sourceFile); - didWork = true; - } else if (Constants.SCHEMA_EXTENSION.equals(extension)) { + processedFileCount++; + } + } + return processedFileCount; + } + + private int processSchemaFiles() { + int processedFileCount = 0; + for (File sourceFile : getInputs().getSourceFiles()) { + String extension = FilenameUtils.getExtension(sourceFile.getName()); + if (Constants.SCHEMA_EXTENSION.equals(extension)) { processSchemaFile(sourceFile); - didWork = true; - } else { - throw new GradleException(String.format("Unsupported file extension: %s for %s", extension, sourceFile)); + processedFileCount++; } } - setDidWork(didWork); + return processedFileCount; } private void processProtoFile(File sourceFile) { + getLogger().info("Processing {}", sourceFile); try { Protocol protocol = Protocol.parse(sourceFile); SpecificCompiler compiler = new SpecificCompiler(protocol); @@ -46,6 +78,7 @@ private void processProtoFile(File sourceFile) { } private void processSchemaFile(File sourceFile) { + getLogger().info("Processing {}", sourceFile); try { Schema schema = parser.parse(sourceFile); SpecificCompiler compiler = new SpecificCompiler(schema); From 4729e4700fab4fde353a84d3236d83673d0ac16c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 12:24:50 -0400 Subject: [PATCH 005/479] generateAvroJava: support compiling schemas with dependencies This is accomplished by trying to compile the schema, and then retrying later as needed. --- .../gradle/plugin/avro/FileExtensionSpec.java | 27 +++++ .../plugin/avro/GenerateAvroJavaTask.java | 107 +++++++++++------- 2 files changed, 95 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java new file mode 100644 index 00000000000..02a1281c76a --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java @@ -0,0 +1,27 @@ +package com.commercehub.gradle.plugin.avro; + +import org.apache.commons.io.FilenameUtils; +import org.gradle.api.specs.Spec; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +class FileExtensionSpec implements Spec { + private final Set extensions; + + FileExtensionSpec(String... extensions) { + this.extensions = new HashSet<>(Arrays.asList(extensions)); + } + + FileExtensionSpec(Collection extensions) { + this.extensions = new HashSet<>(extensions); + } + + @Override + public boolean isSatisfiedBy(File file) { + return extensions.contains(FilenameUtils.getExtension(file.getName())); + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 009384f082f..602b0db1161 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -1,37 +1,41 @@ package com.commercehub.gradle.plugin.avro; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.apache.avro.Protocol; import org.apache.avro.Schema; +import org.apache.avro.SchemaParseException; import org.apache.avro.compiler.specific.SpecificCompiler; -import org.apache.commons.io.FilenameUtils; import org.gradle.api.GradleException; +import org.gradle.api.file.FileCollection; +import org.gradle.api.specs.NotSpec; +import org.gradle.api.specs.Spec; import org.gradle.api.tasks.TaskAction; import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; +import java.util.Map; +import java.util.Queue; import java.util.Set; -public class GenerateAvroJavaTask extends OutputDirTask { - private static Set SUPPORTED_EXTENSIONS = Collections.unmodifiableSet(new HashSet<>( - Arrays.asList(Constants.PROTOCOL_EXTENSION, Constants.SCHEMA_EXTENSION))); +import static com.commercehub.gradle.plugin.avro.Constants.*; - private Schema.Parser parser = new Schema.Parser(); +public class GenerateAvroJavaTask extends OutputDirTask { + private static Set SUPPORTED_EXTENSIONS = Sets.newHashSet(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); @TaskAction protected void process() { getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); + processFiles(); } private void failOnUnsupportedFiles() { - for (File sourceFile : getInputs().getSourceFiles()) { - String extension = FilenameUtils.getExtension(sourceFile.getName()); - if (!SUPPORTED_EXTENSIONS.contains(extension)) { - throw new GradleException(String.format("Unsupported file extension: %s for %s", extension, sourceFile)); - } + FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(SUPPORTED_EXTENSIONS))); + if (!unsupportedFiles.isEmpty()) { + throw new GradleException( + String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); } } @@ -44,24 +48,9 @@ private void processFiles() { private int processProtoFiles() { int processedFileCount = 0; - for (File sourceFile : getInputs().getSourceFiles()) { - String extension = FilenameUtils.getExtension(sourceFile.getName()); - if (Constants.PROTOCOL_EXTENSION.equals(extension)) { - processProtoFile(sourceFile); - processedFileCount++; - } - } - return processedFileCount; - } - - private int processSchemaFiles() { - int processedFileCount = 0; - for (File sourceFile : getInputs().getSourceFiles()) { - String extension = FilenameUtils.getExtension(sourceFile.getName()); - if (Constants.SCHEMA_EXTENSION.equals(extension)) { - processSchemaFile(sourceFile); - processedFileCount++; - } + for (File sourceFile : filterSources(new FileExtensionSpec(PROTOCOL_EXTENSION))) { + processProtoFile(sourceFile); + processedFileCount++; } return processedFileCount; } @@ -77,14 +66,54 @@ private void processProtoFile(File sourceFile) { } } - private void processSchemaFile(File sourceFile) { - getLogger().info("Processing {}", sourceFile); - try { - Schema schema = parser.parse(sourceFile); - SpecificCompiler compiler = new SpecificCompiler(schema); - compiler.compileToDestination(sourceFile, getOutputDir()); - } catch (IOException ex) { - throw new GradleException(String.format("Failed to compile schema definition file %s", sourceFile), ex); + private int processSchemaFiles() { + int processedTotal = 0; + int processedThisPass = -1; + Map types = Maps.newHashMap(); + Queue nextPass = Lists.newLinkedList(filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles()); + Queue thisPass = Lists.newLinkedList(); + while (processedThisPass != 0) { + if (processedThisPass > 0) { + processedTotal += processedThisPass; + } + processedThisPass = 0; + thisPass.addAll(nextPass); + nextPass.clear(); + File sourceFile = thisPass.poll(); + while (sourceFile != null) { + getLogger().debug("Processing {}", sourceFile); + try { + Schema.Parser parser = new Schema.Parser(); + parser.addTypes(types); + Schema schema = parser.parse(sourceFile); + SpecificCompiler compiler = new SpecificCompiler(schema); + compiler.compileToDestination(sourceFile, getOutputDir()); + types = parser.getTypes(); + getLogger().info("Processed {}", sourceFile); + processedThisPass++; + } catch (SchemaParseException ex) { + if (ex.getMessage().matches("(?i).*(undefined name|not a defined name).*")) { + getLogger().debug("Found undefined name in {}; will try again later", sourceFile); + nextPass.add(sourceFile); + } else { + throw new GradleException(String.format("Failed to compile schema definition file %s", sourceFile), ex); + } + } catch (NullPointerException ex) { + getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency); will try again later", sourceFile); + nextPass.add(sourceFile); + } catch (IOException ex) { + throw new GradleException(String.format("Failed to compile schema definition file %s", sourceFile), ex); + } + sourceFile = thisPass.poll(); + } + } + if (!nextPass.isEmpty()) { + throw new GradleException(String.format("Failed to compile schema definition files due to undefined names: %s", nextPass)); } + return processedTotal; + } + + private FileCollection filterSources(Spec spec) { + return getInputs().getSourceFiles().filter(spec); } } From 907f46a4d15e31a94a935b06bc793c9ad879abab Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 12:30:27 -0400 Subject: [PATCH 006/479] share code between tasks --- .../plugin/avro/GenerateAvroJavaTask.java | 5 --- .../plugin/avro/GenerateAvroProtocolTask.java | 38 ++++++++++++------- .../gradle/plugin/avro/OutputDirTask.java | 6 +++ 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 602b0db1161..9d56df8831c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -10,7 +10,6 @@ import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; -import org.gradle.api.specs.Spec; import org.gradle.api.tasks.TaskAction; import java.io.File; @@ -112,8 +111,4 @@ private int processSchemaFiles() { } return processedTotal; } - - private FileCollection filterSources(Spec spec) { - return getInputs().getSourceFiles().filter(spec); - } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 15e42bdb5f8..01df4e5e649 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -6,33 +6,43 @@ import org.apache.commons.io.FilenameUtils; import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; +import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.TaskAction; import java.io.File; import java.io.IOException; +import static com.commercehub.gradle.plugin.avro.Constants.*; + public class GenerateAvroProtocolTask extends OutputDirTask { @TaskAction protected void process() { - boolean didWork = false; - FileCollection sourceFiles = getInputs().getSourceFiles(); - getLogger().info("Found {} files", sourceFiles.getFiles().size()); - for (File sourceFile : sourceFiles) { - getLogger().info("Processing {}", sourceFile); - String extension = FilenameUtils.getExtension(sourceFile.getName()); - if (Constants.IDL_EXTENSION.equals(extension)) { - processIDLFile(sourceFile); - didWork = true; - } else { - throw new GradleException(String.format("Unsupported file extension: %s for %s", extension, sourceFile)); - } + getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); + failOnUnsupportedFiles(); + processFiles(); + } + + private void failOnUnsupportedFiles() { + FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(IDL_EXTENSION))); + if (!unsupportedFiles.isEmpty()) { + throw new GradleException( + String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); + } + } + + private void processFiles() { + int processedFileCount = 0; + for (File sourceFile : filterSources(new FileExtensionSpec(IDL_EXTENSION))) { + processIDLFile(sourceFile); + processedFileCount++; } - setDidWork(didWork); + setDidWork(processedFileCount > 0); } private void processIDLFile(File idlFile) { + getLogger().info("Processing {}", idlFile); File protoFile = new File(getOutputDir(), - FilenameUtils.getBaseName(idlFile.getName()) + Constants.PROTOCOL_EXTENSION); + FilenameUtils.getBaseName(idlFile.getName()) + PROTOCOL_EXTENSION); try (Idl idl = new Idl(idlFile)) { String protoJson = idl.CompilationUnit().toString(); FileUtils.writeStringToFile(protoFile, protoJson, Constants.UTF8_ENCONDING); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java index 05c6fe4b652..1fca25c69ce 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java @@ -1,5 +1,7 @@ package com.commercehub.gradle.plugin.avro; +import org.gradle.api.file.FileCollection; +import org.gradle.api.specs.Spec; import org.gradle.api.tasks.SourceTask; import java.io.File; @@ -15,4 +17,8 @@ public void setOutputDir(File outputDir) { protected File getOutputDir() { return outputDir; } + + protected FileCollection filterSources(Spec spec) { + return getInputs().getSourceFiles().filter(spec); + } } From 939af1dee6c7fa4f98291918a3628afd073243e0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 12:34:06 -0400 Subject: [PATCH 007/479] put the tasks in a source generation group --- .../com/commercehub/gradle/plugin/avro/AvroPlugin.java | 4 ++-- .../com/commercehub/gradle/plugin/avro/Constants.java | 2 ++ .../commercehub/gradle/plugin/avro/AvroPluginSpec.groovy | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index f805b1146cb..999d11cbd61 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -28,7 +28,7 @@ private static GenerateAvroProtocolTask configureProtocolGenerationTask(Project String taskName = sourceSet.getTaskName("generate", "avroProtocol"); GenerateAvroProtocolTask task = project.getTasks().create(taskName, GenerateAvroProtocolTask.class); task.setDescription(String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); - // TODO: group name? + task.setGroup(Constants.GROUP_SOURCE_GENERATION); task.source(project.file(String.format("src/%s/avro", sourceSet.getName()))); task.include("*." + Constants.IDL_EXTENSION); task.setOutputDir(outputDir); @@ -40,7 +40,7 @@ private static GenerateAvroJavaTask configureJavaGenerationTask(Project project, String taskName = sourceSet.getTaskName("generate", "avroJava"); GenerateAvroJavaTask task = project.getTasks().create(taskName, GenerateAvroJavaTask.class); task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.", sourceSet.getName())); - // TODO: group name? + task.setGroup(Constants.GROUP_SOURCE_GENERATION); task.source(project.file(String.format("src/%s/avro", sourceSet.getName()))); task.source(protoTask.getOutputs()); task.include("*." + Constants.SCHEMA_EXTENSION, "*." + Constants.PROTOCOL_EXTENSION); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 243457df8ec..683653305ae 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -6,4 +6,6 @@ class Constants { static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; static final String IDL_EXTENSION = "avdl"; + + static final String GROUP_SOURCE_GENERATION = "Source Generation"; } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy index 9daff99a171..6754562571f 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy @@ -15,8 +15,8 @@ class AvroPluginSpec extends Specification { project.tasks.withType(GenerateAvroProtocolTask).collect {it.name}.sort() == ["generateAvroProtocol", "generateTestAvroProtocol"] mainGenerateAvroProtoTask.description == "Generates main Avro protocol definition files from IDL files." testGenerateAvroProtoTask.description == "Generates test Avro protocol definition files from IDL files." - mainGenerateAvroProtoTask.group == null - testGenerateAvroProtoTask.group == null + mainGenerateAvroProtoTask.group == Constants.GROUP_SOURCE_GENERATION + testGenerateAvroProtoTask.group == Constants.GROUP_SOURCE_GENERATION // Can't easily test the sources mainGenerateAvroProtoTask.outputDir == project.file("build/generated-main-avro-avpr") testGenerateAvroProtoTask.outputDir == project.file("build/generated-test-avro-avpr") @@ -30,8 +30,8 @@ class AvroPluginSpec extends Specification { project.tasks.withType(GenerateAvroJavaTask).collect {it.name}.sort() == ["generateAvroJava", "generateTestAvroJava"] mainGenerateAvroJavaTask.description == "Generates main Avro Java source files from schema/protocol definition files." testGenerateAvroJavaTask.description == "Generates test Avro Java source files from schema/protocol definition files." - mainGenerateAvroJavaTask.group == null - testGenerateAvroJavaTask.group == null + mainGenerateAvroJavaTask.group == Constants.GROUP_SOURCE_GENERATION + testGenerateAvroJavaTask.group == Constants.GROUP_SOURCE_GENERATION // Can't easily test the sources mainGenerateAvroJavaTask.outputDir == project.file("build/generated-main-avro-java") testGenerateAvroJavaTask.outputDir == project.file("build/generated-test-avro-java") From 35839bb4ef261511b8cbe88ab26275bccd1a4131 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 13:28:36 -0400 Subject: [PATCH 008/479] tweak intellij project file generation --- .../gradle/plugin/avro/AvroPlugin.java | 86 ++++++++++++++++--- .../gradle/plugin/avro/Constants.java | 1 + 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 999d11cbd61..1baac06a6f2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -1,20 +1,34 @@ package com.commercehub.gradle.plugin.avro; +import com.google.common.collect.ImmutableSet; import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.SourceTask; +import org.gradle.plugins.ide.idea.IdeaPlugin; +import org.gradle.plugins.ide.idea.model.IdeaModule; import java.io.File; +import java.io.FileFilter; +import java.util.HashSet; +import java.util.Set; + +import static com.commercehub.gradle.plugin.avro.Constants.*; public class AvroPlugin implements Plugin { @Override public void apply(final Project project) { project.getPlugins().apply(JavaPlugin.class); - project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().all(new Action() { + configureTasks(project); + configureIntelliJ(project); + } + + private static void configureTasks(final Project project) { + getSourceSets(project).all(new Action() { public void execute(SourceSet sourceSet) { // TODO: use an extension? GenerateAvroProtocolTask protoTask = configureProtocolGenerationTask(project, sourceSet); @@ -23,32 +37,69 @@ public void execute(SourceSet sourceSet) { }); } + private static void configureIntelliJ(final Project project) { + project.getPlugins().withType(IdeaPlugin.class).all(new Action() { + @Override + public void execute(IdeaPlugin ideaPlugin) { + SourceSetContainer sourceSets = getSourceSets(project); + SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); + SourceSet testSourceSet = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME); + IdeaModule module = ideaPlugin.getModel().getModule(); + module.setSourceDirs(new ImmutableSet.Builder() + .addAll(module.getSourceDirs()) + .add(getAvroSourceDir(project, mainSourceSet)) + .add(getGeneratedOutputDir(project, mainSourceSet, JAVA_EXTENSION)) + .build()); + module.setTestSourceDirs(new ImmutableSet.Builder() + .addAll(module.getTestSourceDirs()) + .add(getAvroSourceDir(project, testSourceSet)) + .add(getGeneratedOutputDir(project, testSourceSet, JAVA_EXTENSION)) + .build()); + // IntelliJ doesn't allow source directories beneath an excluded directory. + // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. + Set excludeDirs = new HashSet<>(module.getExcludeDirs()); + excludeDirs.remove(project.getBuildDir()); + for (File dir : project.getBuildDir().listFiles(new NonGeneratedDirectoryFileFilter())) { + excludeDirs.add(dir); + } + module.setExcludeDirs(excludeDirs); + } + }); + } + private static GenerateAvroProtocolTask configureProtocolGenerationTask(Project project, SourceSet sourceSet) { - File outputDir = getGeneratedOutputDir(project, sourceSet, Constants.PROTOCOL_EXTENSION); + File outputDir = getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION); String taskName = sourceSet.getTaskName("generate", "avroProtocol"); GenerateAvroProtocolTask task = project.getTasks().create(taskName, GenerateAvroProtocolTask.class); - task.setDescription(String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); - task.setGroup(Constants.GROUP_SOURCE_GENERATION); - task.source(project.file(String.format("src/%s/avro", sourceSet.getName()))); - task.include("*." + Constants.IDL_EXTENSION); + task.setDescription( + String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); + task.setGroup(GROUP_SOURCE_GENERATION); + task.source(getAvroSourceDir(project, sourceSet)); + task.include("*." + IDL_EXTENSION); task.setOutputDir(outputDir); return task; } - private static GenerateAvroJavaTask configureJavaGenerationTask(Project project, SourceSet sourceSet, GenerateAvroProtocolTask protoTask) { - File outputDir = getGeneratedOutputDir(project, sourceSet, "java"); + private static GenerateAvroJavaTask configureJavaGenerationTask(Project project, SourceSet sourceSet, + GenerateAvroProtocolTask protoTask) { + File outputDir = getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION); String taskName = sourceSet.getTaskName("generate", "avroJava"); GenerateAvroJavaTask task = project.getTasks().create(taskName, GenerateAvroJavaTask.class); - task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.", sourceSet.getName())); - task.setGroup(Constants.GROUP_SOURCE_GENERATION); - task.source(project.file(String.format("src/%s/avro", sourceSet.getName()))); + task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.", + sourceSet.getName())); + task.setGroup(GROUP_SOURCE_GENERATION); + task.source(getAvroSourceDir(project, sourceSet)); task.source(protoTask.getOutputs()); - task.include("*." + Constants.SCHEMA_EXTENSION, "*." + Constants.PROTOCOL_EXTENSION); + task.include("*." + SCHEMA_EXTENSION, "*." + PROTOCOL_EXTENSION); task.setOutputDir(outputDir); getCompileJavaTask(project, sourceSet).source(task.getOutputs()); return task; } + private static File getAvroSourceDir(Project project, SourceSet sourceSet) { + return project.file(String.format("src/%s/avro", sourceSet.getName())); + } + private static File getGeneratedOutputDir(Project project, SourceSet sourceSet, String extension) { return new File(project.getBuildDir(), String.format("generated-%s-avro-%s", sourceSet.getName(), extension)); } @@ -56,4 +107,15 @@ private static File getGeneratedOutputDir(Project project, SourceSet sourceSet, private static SourceTask getCompileJavaTask(Project project, SourceSet sourceSet) { return (SourceTask) project.getTasks().getByName(sourceSet.getCompileJavaTaskName()); } + + private static SourceSetContainer getSourceSets(Project project) { + return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets(); + } + + private static class NonGeneratedDirectoryFileFilter implements FileFilter { + @Override + public boolean accept(File file) { + return file.isDirectory() && !file.getName().startsWith("generated-"); + } + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 683653305ae..68f21daf7c6 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -6,6 +6,7 @@ class Constants { static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; static final String IDL_EXTENSION = "avdl"; + static final String JAVA_EXTENSION = "java"; static final String GROUP_SOURCE_GENERATION = "Source Generation"; } From 7f2718712f7649724f0a4dcf7ed3417120ba4681 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 13:41:14 -0400 Subject: [PATCH 009/479] generateAvroProtocol: incude dot before file extension --- .../gradle/plugin/avro/GenerateAvroProtocolTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 01df4e5e649..24f9bd1bbf2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -42,7 +42,7 @@ private void processFiles() { private void processIDLFile(File idlFile) { getLogger().info("Processing {}", idlFile); File protoFile = new File(getOutputDir(), - FilenameUtils.getBaseName(idlFile.getName()) + PROTOCOL_EXTENSION); + FilenameUtils.getBaseName(idlFile.getName()) + "." + PROTOCOL_EXTENSION); try (Idl idl = new Idl(idlFile)) { String protoJson = idl.CompilationUnit().toString(); FileUtils.writeStringToFile(protoFile, protoJson, Constants.UTF8_ENCONDING); From 59fd4f59dd5b7537a7b9c89c3ea6db0e26c3a2e4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 14:44:16 -0400 Subject: [PATCH 010/479] support configuring different string types --- .../gradle/plugin/avro/AvroExtension.java | 5 +++ .../gradle/plugin/avro/AvroPlugin.java | 38 ++++++++++++++++++- .../gradle/plugin/avro/Constants.java | 2 + .../plugin/avro/DefaultAvroExtension.java | 14 +++++++ .../plugin/avro/GenerateAvroJavaTask.java | 28 ++++++++++++++ 5 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java new file mode 100644 index 00000000000..1c5c25e367b --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -0,0 +1,5 @@ +package com.commercehub.gradle.plugin.avro; + +public interface AvroExtension { + String getStringType(); +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 1baac06a6f2..c415f9cac37 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -1,9 +1,12 @@ package com.commercehub.gradle.plugin.avro; import com.google.common.collect.ImmutableSet; +import org.apache.avro.generic.GenericData; import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.internal.ConventionMapping; +import org.gradle.api.internal.IConventionAware; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.SourceSet; @@ -16,6 +19,7 @@ import java.io.FileFilter; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Callable; import static com.commercehub.gradle.plugin.avro.Constants.*; @@ -23,14 +27,35 @@ public class AvroPlugin implements Plugin { @Override public void apply(final Project project) { project.getPlugins().apply(JavaPlugin.class); + configureExtension(project); configureTasks(project); configureIntelliJ(project); } + private static void configureExtension(final Project project) { + final AvroExtension avroExtension = project.getExtensions().create(AVRO_EXTENSION_NAME, DefaultAvroExtension.class); + conventionMapping(avroExtension).map("stringType", new Callable() { + @Override + public String call() throws Exception { + return GenericData.StringType.String.name(); + } + }); + project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { + @Override + public void execute(GenerateAvroJavaTask task) { + conventionMapping(task).map("stringType", new Callable() { + @Override + public String call() throws Exception { + return avroExtension.getStringType(); + } + }); + } + }); + } + private static void configureTasks(final Project project) { getSourceSets(project).all(new Action() { public void execute(SourceSet sourceSet) { - // TODO: use an extension? GenerateAvroProtocolTask protoTask = configureProtocolGenerationTask(project, sourceSet); configureJavaGenerationTask(project, sourceSet, protoTask); } @@ -118,4 +143,15 @@ public boolean accept(File file) { return file.isDirectory() && !file.getName().startsWith("generated-"); } } + + private static ConventionMapping conventionMapping(Object conventionAware) { + // TODO: try other alternatives to convention mapping + // Convention mapping is an internal API. + // Other options here: http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api + return ((IConventionAware) conventionAware).getConventionMapping(); + } + + private AvroExtension avro(Project project) { + return project.getExtensions().getByType(AvroExtension.class); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 68f21daf7c6..2cadfd28fa4 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -9,4 +9,6 @@ class Constants { static final String JAVA_EXTENSION = "java"; static final String GROUP_SOURCE_GENERATION = "Source Generation"; + + static final String AVRO_EXTENSION_NAME = "avro"; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java new file mode 100644 index 00000000000..e848f55045a --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -0,0 +1,14 @@ +package com.commercehub.gradle.plugin.avro; + +public class DefaultAvroExtension implements AvroExtension { + private String stringType; + + @Override + public String getStringType() { + return stringType; + } + + public void setStringType(String stringType) { + this.stringType = stringType; + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 9d56df8831c..f1c0fbab731 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -7,13 +7,16 @@ import org.apache.avro.Schema; import org.apache.avro.SchemaParseException; import org.apache.avro.compiler.specific.SpecificCompiler; +import org.apache.avro.generic.GenericData; import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; +import org.gradle.api.tasks.Input; import org.gradle.api.tasks.TaskAction; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.Map; import java.util.Queue; import java.util.Set; @@ -23,6 +26,29 @@ public class GenerateAvroJavaTask extends OutputDirTask { private static Set SUPPORTED_EXTENSIONS = Sets.newHashSet(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); + private String stringType; + + @Input + public String getStringType() { + return stringType; + } + + public void setStringType(String stringType) { + this.stringType = stringType; + } + + private GenericData.StringType parseStringType() { + String stringType = getStringType(); + for (GenericData.StringType type : GenericData.StringType.values()) { + if (type.name().equalsIgnoreCase(stringType)) { + return type; + } + } + throw new IllegalArgumentException(String.format("Invalid stringType '%s'. Valid values are: %s", stringType, + Arrays.asList(GenericData.StringType.values()))); + + } + @TaskAction protected void process() { getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); @@ -59,6 +85,7 @@ private void processProtoFile(File sourceFile) { try { Protocol protocol = Protocol.parse(sourceFile); SpecificCompiler compiler = new SpecificCompiler(protocol); + compiler.setStringType(parseStringType()); compiler.compileToDestination(sourceFile, getOutputDir()); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); @@ -86,6 +113,7 @@ private int processSchemaFiles() { parser.addTypes(types); Schema schema = parser.parse(sourceFile); SpecificCompiler compiler = new SpecificCompiler(schema); + compiler.setStringType(parseStringType()); compiler.compileToDestination(sourceFile, getOutputDir()); types = parser.getTypes(); getLogger().info("Processed {}", sourceFile); From 88772c1418e7ae05ce7cef0fa07dee8790614051 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 14:46:48 -0400 Subject: [PATCH 011/479] add license --- LICENSE.txt | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000000..37ec93a14fd --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. From 127a6b2a81b30b308e9d6466ff48d90cc1191e47 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 15:53:47 -0400 Subject: [PATCH 012/479] docs: add readme, changes --- CHANGES.md | 9 +++++++++ README.md | 30 ++++++++++++++++++++++++++++++ gradle.properties | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 CHANGES.md create mode 100644 README.md diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 00000000000..cdaf306d5e0 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,9 @@ +# Change Log + +* 0.1.0 (unreleased) + * Add support for converting IDL files to JSON protocol declaration files + * Add support for generating Java classes from JSON protocol declaration files + * Add support for generating Java classes from JSON schema declaration files + * Add support for inter-dependent JSON schema declaration files + * Add support for tweaking source/exclude directories in IntelliJ + * Add support for specifying the string type to use in generated classes diff --git a/README.md b/README.md new file mode 100644 index 00000000000..3964ef9cc7d --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# Overview + +This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Java code generation for [Apache Avro](http://avro.apache.org/). It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files. + +# Usage + +Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](). + +```groovy +buildscript { + repositories { + jcenter() + } + dependencies { + classpath "com.commercehub.gradle.plugin:gradle-avro-plugin:VERSION" + } +} + +apply plugin: "avro" +``` + +Optionally, configure the string type to `charSequence` (the default), `string`, or `utf8`. + +```groovy +avro { + stringType = "string" +} +``` + +If you now run `gradle build`, Java classes will be compiled from Avro files in `src/main/avro`. Actually, it will attempt to process an "avro" directory in every `SourceSet` (main, test, etc.) diff --git a/gradle.properties b/gradle.properties index 8d0c7be9623..17048556aa1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=1.0.0-SNAPSHOT +version=0.1.0-SNAPSHOT From 0d4c4d7b3acff8c256e648a800bd8778c97eb2d0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 15:55:49 -0400 Subject: [PATCH 013/479] docs: fix link in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3964ef9cc7d..d40b9f6001a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Usage -Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](). +Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](https://github.com/commercehub-oss/gradle-avro-plugin/blob/master/CHANGES.md). ```groovy buildscript { From 74bbf0965839ea4247beef4a909353af0f9d1568 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 16:07:08 -0400 Subject: [PATCH 014/479] build: add support for publishing --- build.gradle | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f433ea6d07f..9a14e74dd62 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,15 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.3" + classpath "com.github.townsfolk:gradle-release:1.2" + } +} + apply plugin: "groovy" apply plugin: "idea" -apply plugin: "maven-publish" repositories { jcenter() @@ -17,10 +26,42 @@ sourceCompatibility = 1.7 group = "com.commercehub.gradle.plugin" +task sourcesJar(type: Jar, dependsOn: classes) { + from sourceSets.main.allSource + classifier "sources" + extension "jar" +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + from javadoc.destinationDir + classifier "javadoc" + extension "jar" +} + +apply plugin: "maven-publish" publishing { publications { mavenJava(MavenPublication) { from components.java + artifact sourcesJar + artifact javadocJar } } } + +apply plugin: "release" +apply plugin: "bintray" +def project = this +bintray { + user = project.hasProperty("bintrayUserName") ? bintrayUserName : null + key = project.hasProperty("bintrayApiKey") ? bintrayApiKey : null + publications = ["mavenJava"] + pkg { + repo = "main" + userOrg = "commercehub-oss" + name = project.name + licenses = ["Apache-2.0"] + } +} +bintrayUpload.dependsOn build, sourcesJar, javadocJar +createReleaseTag.dependsOn bintrayUpload From bc40ff0d01b00fdb2f156d16a74e4f2251eac4e5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 16:07:26 -0400 Subject: [PATCH 015/479] plugin: remove unused method --- .../java/com/commercehub/gradle/plugin/avro/AvroPlugin.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index c415f9cac37..8e406b8b102 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -150,8 +150,4 @@ private static ConventionMapping conventionMapping(Object conventionAware) { // Other options here: http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api return ((IConventionAware) conventionAware).getConventionMapping(); } - - private AvroExtension avro(Project project) { - return project.getExtensions().getByType(AvroExtension.class); - } } From a0f0c417f46685c872ea3e7179809a49ad51a5c6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 16:10:38 -0400 Subject: [PATCH 016/479] version: update to 0.1.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 17048556aa1..de55ab654e5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.1.0-SNAPSHOT +version=0.1.0 From bacac0ffbf30a23280e5ebef4f6499d42b90f8d2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 16:11:39 -0400 Subject: [PATCH 017/479] [Gradle Release Plugin] - new version commit: '0.2.0'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index de55ab654e5..caeaf12047c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.1.0 +version=0.2.0 From 748686c0360c5ee36924ac71fce313a085bf5c82 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 16:12:12 -0400 Subject: [PATCH 018/479] updated changelog --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index cdaf306d5e0..859b680ece4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,6 @@ # Change Log -* 0.1.0 (unreleased) +* 0.1.0 (2013-10-23) * Add support for converting IDL files to JSON protocol declaration files * Add support for generating Java classes from JSON protocol declaration files * Add support for generating Java classes from JSON schema declaration files From e50c49ac9d8df5b74876c44d841140fac5fe87cc Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Oct 2013 17:55:07 -0400 Subject: [PATCH 019/479] fix null pointer exception when build directory doesn't exist --- CHANGES.md | 3 +++ .../com/commercehub/gradle/plugin/avro/AvroPlugin.java | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 859b680ece4..14ac279a377 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,8 @@ # Change Log +* 0.1.1 (unreleased) + * Fixed NullPointerException when performing clean builds + * 0.1.0 (2013-10-23) * Add support for converting IDL files to JSON protocol declaration files * Add support for generating Java classes from JSON protocol declaration files diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 8e406b8b102..23788cae49b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -17,6 +17,7 @@ import java.io.File; import java.io.FileFilter; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.Callable; @@ -84,8 +85,10 @@ public void execute(IdeaPlugin ideaPlugin) { // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. Set excludeDirs = new HashSet<>(module.getExcludeDirs()); excludeDirs.remove(project.getBuildDir()); - for (File dir : project.getBuildDir().listFiles(new NonGeneratedDirectoryFileFilter())) { - excludeDirs.add(dir); + File buildDir = project.getBuildDir(); + if (buildDir.isDirectory()) { + Collections.addAll(excludeDirs, + project.getBuildDir().listFiles(new NonGeneratedDirectoryFileFilter())); } module.setExcludeDirs(excludeDirs); } From 4bba0f7944979715bfed549582997ab483580ee4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 23 Oct 2013 08:12:16 -0400 Subject: [PATCH 020/479] plugin: extract getMainSourceSet and getTestSourceSet methods --- .../commercehub/gradle/plugin/avro/AvroPlugin.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 23788cae49b..69f93603cb1 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -67,9 +67,8 @@ private static void configureIntelliJ(final Project project) { project.getPlugins().withType(IdeaPlugin.class).all(new Action() { @Override public void execute(IdeaPlugin ideaPlugin) { - SourceSetContainer sourceSets = getSourceSets(project); - SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); - SourceSet testSourceSet = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME); + SourceSet mainSourceSet = getMainSourceSet(project); + SourceSet testSourceSet = getTestSourceSet(project); IdeaModule module = ideaPlugin.getModel().getModule(); module.setSourceDirs(new ImmutableSet.Builder() .addAll(module.getSourceDirs()) @@ -140,6 +139,14 @@ private static SourceSetContainer getSourceSets(Project project) { return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets(); } + private static SourceSet getMainSourceSet(Project project) { + return getSourceSets(project).getByName(SourceSet.MAIN_SOURCE_SET_NAME); + } + + private static SourceSet getTestSourceSet(Project project) { + return getSourceSets(project).getByName(SourceSet.TEST_SOURCE_SET_NAME); + } + private static class NonGeneratedDirectoryFileFilter implements FileFilter { @Override public boolean accept(File file) { From f9c27296fbe9da33264835ee58ac8978c46ff1a9 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 23 Oct 2013 08:13:24 -0400 Subject: [PATCH 021/479] update changelog and version --- CHANGES.md | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 14ac279a377..f6860592d12 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,6 @@ # Change Log -* 0.1.1 (unreleased) +* 0.1.1 (2013-10-24) * Fixed NullPointerException when performing clean builds * 0.1.0 (2013-10-23) diff --git a/gradle.properties b/gradle.properties index caeaf12047c..a482420ba1f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.2.0 +version=0.1.1 From 99049483f0fdcbb95a3f24f5fc4e5d8784eb2562 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 23 Oct 2013 08:14:08 -0400 Subject: [PATCH 022/479] [Gradle Release Plugin] - new version commit: '0.1.2'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index a482420ba1f..33aa3f7c4d3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.1.1 +version=0.1.2 From 27af1f48d01c099c138cc8e63e0b023499492383 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 23 Oct 2013 10:52:16 -0400 Subject: [PATCH 023/479] fix dependencies --- CHANGES.md | 3 ++ build.gradle | 1 + .../gradle/plugin/avro/AvroPlugin.java | 17 +++---- .../plugin/avro/GenerateAvroJavaTask.java | 13 +++--- .../gradle/plugin/avro/SetBuilder.java | 44 +++++++++++++++++++ 5 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java diff --git a/CHANGES.md b/CHANGES.md index f6860592d12..766a52aeee6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,8 @@ # Change Log +* 0.1.2 (2013-10-24) + * Eliminate dependency on guava, make dependency on commons-io explicit + * 0.1.1 (2013-10-24) * Fixed NullPointerException when performing clean builds diff --git a/build.gradle b/build.gradle index 9a14e74dd62..53a916b8512 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,7 @@ dependencies { compile gradleApi() compile localGroovy() compile "org.apache.avro:avro-compiler:1.7.5" + compile "org.apache.commons:commons-io:1.3.2" testCompile "org.spockframework:spock-core:0.6-groovy-1.8" } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 69f93603cb1..96f299f1729 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -1,6 +1,5 @@ package com.commercehub.gradle.plugin.avro; -import com.google.common.collect.ImmutableSet; import org.apache.avro.generic.GenericData; import org.gradle.api.Action; import org.gradle.api.Plugin; @@ -17,9 +16,6 @@ import java.io.File; import java.io.FileFilter; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; import java.util.concurrent.Callable; import static com.commercehub.gradle.plugin.avro.Constants.*; @@ -70,26 +66,25 @@ public void execute(IdeaPlugin ideaPlugin) { SourceSet mainSourceSet = getMainSourceSet(project); SourceSet testSourceSet = getTestSourceSet(project); IdeaModule module = ideaPlugin.getModel().getModule(); - module.setSourceDirs(new ImmutableSet.Builder() + module.setSourceDirs(new SetBuilder() .addAll(module.getSourceDirs()) .add(getAvroSourceDir(project, mainSourceSet)) .add(getGeneratedOutputDir(project, mainSourceSet, JAVA_EXTENSION)) .build()); - module.setTestSourceDirs(new ImmutableSet.Builder() + module.setTestSourceDirs(new SetBuilder() .addAll(module.getTestSourceDirs()) .add(getAvroSourceDir(project, testSourceSet)) .add(getGeneratedOutputDir(project, testSourceSet, JAVA_EXTENSION)) .build()); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. - Set excludeDirs = new HashSet<>(module.getExcludeDirs()); - excludeDirs.remove(project.getBuildDir()); + SetBuilder excludeDirs = new SetBuilder<>(); + excludeDirs.addAll(module.getExcludeDirs()).remove(project.getBuildDir()); File buildDir = project.getBuildDir(); if (buildDir.isDirectory()) { - Collections.addAll(excludeDirs, - project.getBuildDir().listFiles(new NonGeneratedDirectoryFileFilter())); + excludeDirs.addAll(project.getBuildDir().listFiles(new NonGeneratedDirectoryFileFilter())); } - module.setExcludeDirs(excludeDirs); + module.setExcludeDirs(excludeDirs.build()); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index f1c0fbab731..0ea842c4ff8 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -1,8 +1,5 @@ package com.commercehub.gradle.plugin.avro; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.apache.avro.SchemaParseException; @@ -17,6 +14,8 @@ import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.Set; @@ -24,7 +23,7 @@ import static com.commercehub.gradle.plugin.avro.Constants.*; public class GenerateAvroJavaTask extends OutputDirTask { - private static Set SUPPORTED_EXTENSIONS = Sets.newHashSet(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); + private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); private String stringType; @@ -95,9 +94,9 @@ private void processProtoFile(File sourceFile) { private int processSchemaFiles() { int processedTotal = 0; int processedThisPass = -1; - Map types = Maps.newHashMap(); - Queue nextPass = Lists.newLinkedList(filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles()); - Queue thisPass = Lists.newLinkedList(); + Map types = new HashMap<>(); + Queue nextPass = new LinkedList<>(filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles()); + Queue thisPass = new LinkedList<>(); while (processedThisPass != 0) { if (processedThisPass > 0) { processedTotal += processedThisPass; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java new file mode 100644 index 00000000000..820e91d3e97 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java @@ -0,0 +1,44 @@ +package com.commercehub.gradle.plugin.avro; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +class SetBuilder { + private Set set = newHashSet(); + + SetBuilder add(T e) { + set.add(e); + return this; + } + + @SafeVarargs + final SetBuilder addAll(T... c) { + Collections.addAll(set, c); + return this; + } + + SetBuilder addAll(Collection c) { + set.addAll(c); + return this; + } + + SetBuilder remove(T e) { + set.remove(e); + return this; + } + + Set build() { + return set; + } + + static HashSet newHashSet() { + return new HashSet<>(); + } + + @SafeVarargs + static Set build(T... c) { + return new SetBuilder().addAll(c).build(); + } +} From b881e7e1f9363f150eeb62ce2b5c6c5c63abff19 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 23 Oct 2013 10:53:02 -0400 Subject: [PATCH 024/479] [Gradle Release Plugin] - new version commit: '0.1.3'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 33aa3f7c4d3..9c714180447 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.1.2 +version=0.1.3 From de228e79a790db7a3d17482e95cd0b783c8cd6e3 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 26 Nov 2013 13:49:30 -0500 Subject: [PATCH 025/479] clean generated java files before re-generating them --- CHANGES.md | 9 ++++++--- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 13 +++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 766a52aeee6..34c782ce11a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,12 +1,15 @@ # Change Log -* 0.1.2 (2013-10-24) +* 0.1.3 + * Always regenerate all Java classes when any schema file changes to avoid some classes having outdated schema information. + +* 0.1.2 * Eliminate dependency on guava, make dependency on commons-io explicit -* 0.1.1 (2013-10-24) +* 0.1.1 * Fixed NullPointerException when performing clean builds -* 0.1.0 (2013-10-23) +* 0.1.0 * Add support for converting IDL files to JSON protocol declaration files * Add support for generating Java classes from JSON protocol declaration files * Add support for generating Java classes from JSON schema declaration files diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 0ea842c4ff8..0eda79a8ce6 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -52,6 +52,7 @@ private GenericData.StringType parseStringType() { protected void process() { getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); + preClean(); processFiles(); } @@ -63,6 +64,18 @@ private void failOnUnsupportedFiles() { } } + /** + * We need to remove all previously generated Java classes. Otherwise, when we call + * {@link SpecificCompiler#compileToDestination(java.io.File, java.io.File)}, it will skip generating classes for + * any schema files where the generated class is newer than the schema file. That seems like a useful performance + * optimization, but it can cause problems in the case where the schema file for this class hasn't changed, but + * the schema definition for one of the types it depends on has, resulting in some usages of a type now having + * outdated schema. + */ + private void preClean() { + getProject().delete(getOutputDir()); + } + private void processFiles() { int processedFileCount = 0; processedFileCount += processProtoFiles(); From f60c756075bae566b8a9a10e8a9b4badf31e7bf9 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 26 Nov 2013 13:50:19 -0500 Subject: [PATCH 026/479] [Gradle Release Plugin] - new version commit: '0.1.4'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 9c714180447..49bc55caaab 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.1.3 +version=0.1.4 From 8ee66fe47d3cda0d36d41a1b28b7bedf4b4a775e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 6 Jun 2014 23:57:10 -0400 Subject: [PATCH 027/479] Improve documentation --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d40b9f6001a..f5f405aa5ea 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ buildscript { apply plugin: "avro" ``` -Optionally, configure the string type to `charSequence` (the default), `string`, or `utf8`. +Optionally, configure the string type to `charSequence`, `string` (the default), or `utf8`. ```groovy avro { @@ -27,4 +27,15 @@ avro { } ``` +Additionally, ensure that you have a compile dependency on avro, such as: + +```groovy +repositories { + jcenter() +} +dependencies { + compile "org.apache.avro:avro:1.7.6" +} +``` + If you now run `gradle build`, Java classes will be compiled from Avro files in `src/main/avro`. Actually, it will attempt to process an "avro" directory in every `SourceSet` (main, test, etc.) From 59ef28ae6db878d0a5e99576fb29da3aaf7739d7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 7 Jun 2014 00:00:01 -0400 Subject: [PATCH 028/479] build: upgrade gradle to 1.12 --- gradle/wrapper/gradle-wrapper.jar | Bin 50518 -> 51348 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew.bat | 180 +++++++++++------------ 3 files changed, 92 insertions(+), 92 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index b979729db0ad460288cfe16f07072da7b1305e93..0087cd3b18659b5577cf6ad3ef61f8eb9416ebba 100644 GIT binary patch delta 36750 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 M<1B_tlX?X45AcdIrvLx| delta 36012 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 93eec6c72a7..a9aea9e6c26 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Oct 21 09:54:33 EDT 2013 +#Fri Jun 06 23:58:32 EDT 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip diff --git a/gradlew.bat b/gradlew.bat index 8a0b282aa68..aec99730b4e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,90 +1,90 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From b335c7f1ec16bfaf5d4ebcee40ef14ad9bc71164 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 7 Jun 2014 00:07:05 -0400 Subject: [PATCH 029/479] build: update dependencies (avro 1.7.6, spock 0.7) --- CHANGES.md | 4 ++++ build.gradle | 4 ++-- gradle.properties | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 34c782ce11a..4ba325513cb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,9 @@ # Change Log +* 0.2.0 + * Build against Gradle 1.12 + * Compile using Avro 1.7.6 + * 0.1.3 * Always regenerate all Java classes when any schema file changes to avoid some classes having outdated schema information. diff --git a/build.gradle b/build.gradle index 53a916b8512..1e1a9b2114a 100644 --- a/build.gradle +++ b/build.gradle @@ -18,9 +18,9 @@ repositories { dependencies { compile gradleApi() compile localGroovy() - compile "org.apache.avro:avro-compiler:1.7.5" + compile "org.apache.avro:avro-compiler:1.7.6" compile "org.apache.commons:commons-io:1.3.2" - testCompile "org.spockframework:spock-core:0.6-groovy-1.8" + testCompile "org.spockframework:spock-core:0.7-groovy-1.8" } sourceCompatibility = 1.7 diff --git a/gradle.properties b/gradle.properties index 49bc55caaab..632458877eb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.1.4 +version=0.2.0-SNAPSHOT From 69f1af9853cf6e46414b797b80a273cd653c6e42 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 7 Jun 2014 00:22:13 -0400 Subject: [PATCH 030/479] Add support for qualified plugin ID --- CHANGES.md | 2 ++ README.md | 2 +- .../gradle/plugin/avro/UnqualifiedAvroPlugin.java | 15 +++++++++++++++ .../META-INF/gradle-plugins/avro.properties | 2 +- .../com.commercehub.gradle.plugin.avro.properties | 1 + 5 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/UnqualifiedAvroPlugin.java create mode 100644 src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties diff --git a/CHANGES.md b/CHANGES.md index 4ba325513cb..dd3b6521e6c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,8 @@ * 0.2.0 * Build against Gradle 1.12 * Compile using Avro 1.7.6 + * Support for qualified plugin ID + * Deprecate unqualified plugin ID * 0.1.3 * Always regenerate all Java classes when any schema file changes to avoid some classes having outdated schema information. diff --git a/README.md b/README.md index f5f405aa5ea..1ab1c7f72fa 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ buildscript { } } -apply plugin: "avro" +apply plugin: "com.commercehub.gradle.plugin.avro" ``` Optionally, configure the string type to `charSequence`, `string` (the default), or `utf8`. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/UnqualifiedAvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/UnqualifiedAvroPlugin.java new file mode 100644 index 00000000000..7c098a14e0f --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/UnqualifiedAvroPlugin.java @@ -0,0 +1,15 @@ +package com.commercehub.gradle.plugin.avro; + +import org.gradle.api.Project; + +@Deprecated +public class UnqualifiedAvroPlugin extends AvroPlugin { + // TODO: remove this class (and related avro.properties) in 0.4.0. + + @Override + public void apply(Project project) { + project.getLogger().warn("The 'avro' plugin ID is deprecated; " + + "please update your build to use 'com.commercehub.gradle.plugin.avro' instead."); + super.apply(project); + } +} diff --git a/src/main/resources/META-INF/gradle-plugins/avro.properties b/src/main/resources/META-INF/gradle-plugins/avro.properties index 514cc66f7a7..2acb12647df 100644 --- a/src/main/resources/META-INF/gradle-plugins/avro.properties +++ b/src/main/resources/META-INF/gradle-plugins/avro.properties @@ -1 +1 @@ -implementation-class=com.commercehub.gradle.plugin.avro.AvroPlugin +implementation-class=com.commercehub.gradle.plugin.avro.UnqualifiedAvroPlugin diff --git a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties new file mode 100644 index 00000000000..514cc66f7a7 --- /dev/null +++ b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties @@ -0,0 +1 @@ +implementation-class=com.commercehub.gradle.plugin.avro.AvroPlugin From 5a72334a782d588dc09a152c0c9e8d4993b23fc6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 7 Jun 2014 00:24:19 -0400 Subject: [PATCH 031/479] new version: 0.2.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 632458877eb..caeaf12047c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.2.0-SNAPSHOT +version=0.2.0 From 6c72ae60ad353e728cebc5968758b1650be7aec1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 7 Jun 2014 00:25:06 -0400 Subject: [PATCH 032/479] [Gradle Release Plugin] - new version commit: '0.2.1'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index caeaf12047c..930d2a315aa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.2.0 +version=0.2.1 From 4352dd4deefd92d85a460dd71dd717c92a82aef6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 7 Jun 2014 02:18:15 -0400 Subject: [PATCH 033/479] docs: add usage instructions for gradle 2.1+ --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ab1c7f72fa..ab2ff10d726 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,12 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](https://github.com/commercehub-oss/gradle-avro-plugin/blob/master/CHANGES.md). ```groovy +// Gradle 2.1 and later +plugins { + id "com.commercehub.gradle.plugin.avro" version "VERSION" +} + +// Earlier versions of Gradle buildscript { repositories { jcenter() @@ -15,7 +21,6 @@ buildscript { classpath "com.commercehub.gradle.plugin:gradle-avro-plugin:VERSION" } } - apply plugin: "com.commercehub.gradle.plugin.avro" ``` From 680a1a5f9285c730c7090e69c9c1c3dbc43e06d6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 17 Jun 2014 22:03:12 -0400 Subject: [PATCH 034/479] IntelliJ: register generated source directories even if they don't already exist. (#1) --- CHANGES.md | 3 +++ gradle.properties | 2 +- .../gradle/plugin/avro/AvroPlugin.java | 20 +++++++++++++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index dd3b6521e6c..9510d2a1da1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,8 @@ # Change Log +* 0.3.0 + * IntelliJ: register generated source directories even if they don't already exist. + * 0.2.0 * Build against Gradle 1.12 * Compile using Avro 1.7.6 diff --git a/gradle.properties b/gradle.properties index 930d2a315aa..76601fa1368 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.2.1 +version=0.3.0-SNAPSHOT diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 96f299f1729..92a30fcc7a0 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -4,6 +4,7 @@ import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.Task; import org.gradle.api.internal.ConventionMapping; import org.gradle.api.internal.IConventionAware; import org.gradle.api.plugins.JavaPlugin; @@ -11,6 +12,7 @@ import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.SourceTask; +import org.gradle.plugins.ide.idea.GenerateIdeaModule; import org.gradle.plugins.ide.idea.IdeaPlugin; import org.gradle.plugins.ide.idea.model.IdeaModule; @@ -65,16 +67,30 @@ private static void configureIntelliJ(final Project project) { public void execute(IdeaPlugin ideaPlugin) { SourceSet mainSourceSet = getMainSourceSet(project); SourceSet testSourceSet = getTestSourceSet(project); + final File mainGeneratedOutputDir = getGeneratedOutputDir(project, mainSourceSet, JAVA_EXTENSION); + final File testGeneratedOutputDir = getGeneratedOutputDir(project, testSourceSet, JAVA_EXTENSION); + project.getTasks().withType(GenerateIdeaModule.class).all(new Action() { + @Override + public void execute(GenerateIdeaModule generateIdeaModule) { + generateIdeaModule.doFirst(new Action() { + @Override + public void execute(Task task) { + project.mkdir(mainGeneratedOutputDir); + project.mkdir(testGeneratedOutputDir); + } + }); + } + }); IdeaModule module = ideaPlugin.getModel().getModule(); module.setSourceDirs(new SetBuilder() .addAll(module.getSourceDirs()) .add(getAvroSourceDir(project, mainSourceSet)) - .add(getGeneratedOutputDir(project, mainSourceSet, JAVA_EXTENSION)) + .add(mainGeneratedOutputDir) .build()); module.setTestSourceDirs(new SetBuilder() .addAll(module.getTestSourceDirs()) .add(getAvroSourceDir(project, testSourceSet)) - .add(getGeneratedOutputDir(project, testSourceSet, JAVA_EXTENSION)) + .add(testGeneratedOutputDir) .build()); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. From 9777421fc581f729779059725f223d3e84c59f75 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 17 Jun 2014 22:17:09 -0400 Subject: [PATCH 035/479] Add avro-base plugin, which exposes tasks and the extension without creating tasks, defaults, etc. --- CHANGES.md | 1 + README.md | 8 ++++ .../gradle/plugin/avro/AvroBasePlugin.java | 47 +++++++++++++++++++ .../gradle/plugin/avro/AvroPlugin.java | 34 +------------- ...ercehub.gradle.plugin.avro-base.properties | 1 + 5 files changed, 58 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java create mode 100644 src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties diff --git a/CHANGES.md b/CHANGES.md index 9510d2a1da1..23ea5c52534 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ * 0.3.0 * IntelliJ: register generated source directories even if they don't already exist. + * Add avro-base plugin, which exposes tasks and the extension without creating tasks, defaults, etc. * 0.2.0 * Build against Gradle 1.12 diff --git a/README.md b/README.md index ab2ff10d726..c86aba04b2b 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,11 @@ dependencies { ``` If you now run `gradle build`, Java classes will be compiled from Avro files in `src/main/avro`. Actually, it will attempt to process an "avro" directory in every `SourceSet` (main, test, etc.) + +# IntelliJ Integration + +The plugin attempts to make IntelliJ play more smoothly with generated sources when using Gradle-generated project files. However, there are still some rough edges. It will work best if you first run `gradle build`, and _after_ that run `gradle idea`. If you do it in the other order, IntelliJ may not properly exclude some directories within your `build` directory. + +# Alternate Usage + +If the defaults used by the plugin don't work for you, you can still use the tasks by themselves. In this case, use the "com.commercehub.gradle.plugin.avro" plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java new file mode 100644 index 00000000000..c05d6cd4388 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -0,0 +1,47 @@ +package com.commercehub.gradle.plugin.avro; + +import org.apache.avro.generic.GenericData; +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.internal.ConventionMapping; +import org.gradle.api.internal.IConventionAware; + +import java.util.concurrent.Callable; + +import static com.commercehub.gradle.plugin.avro.Constants.AVRO_EXTENSION_NAME; + +public class AvroBasePlugin implements Plugin { + @Override + public void apply(final Project project) { + configureExtension(project); + } + + private static void configureExtension(final Project project) { + final AvroExtension avroExtension = project.getExtensions().create(AVRO_EXTENSION_NAME, DefaultAvroExtension.class); + conventionMapping(avroExtension).map("stringType", new Callable() { + @Override + public String call() throws Exception { + return GenericData.StringType.String.name(); + } + }); + project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { + @Override + public void execute(GenerateAvroJavaTask task) { + conventionMapping(task).map("stringType", new Callable() { + @Override + public String call() throws Exception { + return avroExtension.getStringType(); + } + }); + } + }); + } + + private static ConventionMapping conventionMapping(Object conventionAware) { + // TODO: try other alternatives to convention mapping + // Convention mapping is an internal API. + // Other options here: http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api + return ((IConventionAware) conventionAware).getConventionMapping(); + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 92a30fcc7a0..2810009dd6d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -1,12 +1,9 @@ package com.commercehub.gradle.plugin.avro; -import org.apache.avro.generic.GenericData; import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; -import org.gradle.api.internal.ConventionMapping; -import org.gradle.api.internal.IConventionAware; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.SourceSet; @@ -18,7 +15,6 @@ import java.io.File; import java.io.FileFilter; -import java.util.concurrent.Callable; import static com.commercehub.gradle.plugin.avro.Constants.*; @@ -26,32 +22,11 @@ public class AvroPlugin implements Plugin { @Override public void apply(final Project project) { project.getPlugins().apply(JavaPlugin.class); - configureExtension(project); + project.getPlugins().apply(AvroBasePlugin.class); configureTasks(project); configureIntelliJ(project); } - private static void configureExtension(final Project project) { - final AvroExtension avroExtension = project.getExtensions().create(AVRO_EXTENSION_NAME, DefaultAvroExtension.class); - conventionMapping(avroExtension).map("stringType", new Callable() { - @Override - public String call() throws Exception { - return GenericData.StringType.String.name(); - } - }); - project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { - @Override - public void execute(GenerateAvroJavaTask task) { - conventionMapping(task).map("stringType", new Callable() { - @Override - public String call() throws Exception { - return avroExtension.getStringType(); - } - }); - } - }); - } - private static void configureTasks(final Project project) { getSourceSets(project).all(new Action() { public void execute(SourceSet sourceSet) { @@ -164,11 +139,4 @@ public boolean accept(File file) { return file.isDirectory() && !file.getName().startsWith("generated-"); } } - - private static ConventionMapping conventionMapping(Object conventionAware) { - // TODO: try other alternatives to convention mapping - // Convention mapping is an internal API. - // Other options here: http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api - return ((IConventionAware) conventionAware).getConventionMapping(); - } } diff --git a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties new file mode 100644 index 00000000000..b9dc06f0a4f --- /dev/null +++ b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties @@ -0,0 +1 @@ +implementation-class=com.commercehub.gradle.plugin.avro.AvroBasePlugin From 45e6fbcb4824f37c9da19e62276777f2498037d0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 17 Jun 2014 22:37:40 -0400 Subject: [PATCH 036/479] Document how to use avro-base --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index c86aba04b2b..274700c873a 100644 --- a/README.md +++ b/README.md @@ -52,3 +52,21 @@ The plugin attempts to make IntelliJ play more smoothly with generated sources w # Alternate Usage If the defaults used by the plugin don't work for you, you can still use the tasks by themselves. In this case, use the "com.commercehub.gradle.plugin.avro" plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. + +Here's a short example of what this might look like: + +```groovy +apply plugin: "java" +apply plugin: "com.commercehub.gradle.plugin.avro-base" + +dependencies { + compile "org.apache.avro:avro:1.7.6" +} + +task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { + source("src/avro") + outputDir = file("dest/avro") +} + +compileJava.source(generateAvro.outputs) +``` From 8842c32d0f20b60598f20c0c6fba8621ea6c04fd Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 17 Jun 2014 22:42:41 -0400 Subject: [PATCH 037/479] add travis support --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000..409121df002 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: java +env: + global: + - TERM=dumb +install: true +script: ./gradlew build From 7cacde208bd1c3cfd21f3d91fb456c1c76cbdd17 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 17 Jun 2014 22:46:05 -0400 Subject: [PATCH 038/479] add travis badge to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 274700c873a..f9078ad2344 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Java code generation for [Apache Avro](http://avro.apache.org/). It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files. +[![Build Status](https://travis-ci.org/commercehub-oss/gradle-avro-plugin.svg?branch=master)](https://travis-ci.org/commercehub-oss/gradle-avro-plugin) + # Usage Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](https://github.com/commercehub-oss/gradle-avro-plugin/blob/master/CHANGES.md). From 20429a2334b183d473158b8c74b977d20ac17bd6 Mon Sep 17 00:00:00 2001 From: Keegan Witt Date: Fri, 25 Jul 2014 11:15:55 -0400 Subject: [PATCH 039/479] added output encoding option (requires Avro 1.7.7) --- README.md | 8 ++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/README.md b/README.md index f9078ad2344..08824f8516b 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,14 @@ avro { } ``` +Optionally, you can also configure the output character encoding. + +```groovy +avro { + encoding = "UTF-8" +} +``` + Additionally, ensure that you have a compile dependency on avro, such as: ```groovy diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 0eda79a8ce6..a2eb8703310 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -25,8 +25,19 @@ public class GenerateAvroJavaTask extends OutputDirTask { private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); + private String encoding; + private String stringType; + @Input + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + @Input public String getStringType() { return stringType; @@ -98,6 +109,9 @@ private void processProtoFile(File sourceFile) { Protocol protocol = Protocol.parse(sourceFile); SpecificCompiler compiler = new SpecificCompiler(protocol); compiler.setStringType(parseStringType()); + if (encoding != null) { + compiler.setOutputCharacterEncoding(encoding); + } compiler.compileToDestination(sourceFile, getOutputDir()); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); @@ -126,6 +140,9 @@ private int processSchemaFiles() { Schema schema = parser.parse(sourceFile); SpecificCompiler compiler = new SpecificCompiler(schema); compiler.setStringType(parseStringType()); + if (encoding != null) { + compiler.setOutputCharacterEncoding(encoding); + } compiler.compileToDestination(sourceFile, getOutputDir()); types = parser.getTypes(); getLogger().info("Processed {}", sourceFile); From 91f7662677a81f86bd584665c9ec94f5b8644d35 Mon Sep 17 00:00:00 2001 From: Keegan Witt Date: Fri, 25 Jul 2014 11:17:23 -0400 Subject: [PATCH 040/479] updated to Avro 1.7.7 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1e1a9b2114a..5e47ec8acb3 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ repositories { dependencies { compile gradleApi() compile localGroovy() - compile "org.apache.avro:avro-compiler:1.7.6" + compile "org.apache.avro:avro-compiler:1.7.7" compile "org.apache.commons:commons-io:1.3.2" testCompile "org.spockframework:spock-core:0.7-groovy-1.8" } From c06f06b2447a4f16a9d6229d03752fa804bb4fdb Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 8 Oct 2014 19:37:16 -0400 Subject: [PATCH 041/479] [Gradle Release Plugin] - pre tag commit: '0.3.0'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 76601fa1368..62044170efc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.3.0-SNAPSHOT +version=0.3.0 From 1226f7001b0e0a978fb9903f7399c20784858f92 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 8 Oct 2014 19:37:56 -0400 Subject: [PATCH 042/479] [Gradle Release Plugin] - new version commit: '0.3.1'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 62044170efc..43feb2057b0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.3.0 +version=0.3.1 From 4c373d4aa4c5c1c5a0ace982cda2dc086f0dfc81 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 17 Oct 2014 20:35:22 -0400 Subject: [PATCH 043/479] Fix encoding support (#5) --- CHANGES.md | 4 ++++ .../gradle/plugin/avro/AvroBasePlugin.java | 18 ++++++++++++++++-- .../gradle/plugin/avro/AvroExtension.java | 1 + .../plugin/avro/DefaultAvroExtension.java | 10 ++++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 11 ++++------- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 23ea5c52534..85ccdbbd909 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,9 @@ # Change Log +# 0.3.1 + * Fix extension support for configuring encoding + * Make default encoding UTF-8 + * 0.3.0 * IntelliJ: register generated source directories even if they don't already exist. * Add avro-base plugin, which exposes tasks and the extension without creating tasks, defaults, etc. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index c05d6cd4388..b116e9f3414 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -19,7 +19,14 @@ public void apply(final Project project) { private static void configureExtension(final Project project) { final AvroExtension avroExtension = project.getExtensions().create(AVRO_EXTENSION_NAME, DefaultAvroExtension.class); - conventionMapping(avroExtension).map("stringType", new Callable() { + ConventionMapping extensionMapping = conventionMapping(avroExtension); + extensionMapping.map("encoding", new Callable() { + @Override + public String call() throws Exception { + return Constants.UTF8_ENCONDING; + } + }); + extensionMapping.map("stringType", new Callable() { @Override public String call() throws Exception { return GenericData.StringType.String.name(); @@ -28,7 +35,14 @@ public String call() throws Exception { project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override public void execute(GenerateAvroJavaTask task) { - conventionMapping(task).map("stringType", new Callable() { + ConventionMapping taskMapping = conventionMapping(task); + taskMapping.map("encoding", new Callable() { + @Override + public String call() throws Exception { + return avroExtension.getEncoding(); + } + }); + taskMapping.map("stringType", new Callable() { @Override public String call() throws Exception { return avroExtension.getStringType(); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 1c5c25e367b..c6bc904f6be 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -1,5 +1,6 @@ package com.commercehub.gradle.plugin.avro; public interface AvroExtension { + String getEncoding(); String getStringType(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index e848f55045a..8787de2adfc 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -1,8 +1,18 @@ package com.commercehub.gradle.plugin.avro; public class DefaultAvroExtension implements AvroExtension { + private String encoding; private String stringType; + @Override + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + @Override public String getStringType() { return stringType; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index a2eb8703310..db0bdde9709 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -25,7 +25,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); - private String encoding; + private String encoding = Constants.UTF8_ENCONDING; private String stringType; @@ -61,6 +61,7 @@ private GenericData.StringType parseStringType() { @TaskAction protected void process() { + getLogger().debug("Using encoding {}", getEncoding()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -109,9 +110,7 @@ private void processProtoFile(File sourceFile) { Protocol protocol = Protocol.parse(sourceFile); SpecificCompiler compiler = new SpecificCompiler(protocol); compiler.setStringType(parseStringType()); - if (encoding != null) { - compiler.setOutputCharacterEncoding(encoding); - } + compiler.setOutputCharacterEncoding(getEncoding()); compiler.compileToDestination(sourceFile, getOutputDir()); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); @@ -140,9 +139,7 @@ private int processSchemaFiles() { Schema schema = parser.parse(sourceFile); SpecificCompiler compiler = new SpecificCompiler(schema); compiler.setStringType(parseStringType()); - if (encoding != null) { - compiler.setOutputCharacterEncoding(encoding); - } + compiler.setOutputCharacterEncoding(getEncoding()); compiler.compileToDestination(sourceFile, getOutputDir()); types = parser.getTypes(); getLogger().info("Processed {}", sourceFile); From 112ab54f8fff6f31ff7c0c828859f5d5e7ede489 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 17 Oct 2014 20:36:01 -0400 Subject: [PATCH 044/479] [Gradle Release Plugin] - new version commit: '0.3.2'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 43feb2057b0..94f9589e0f9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.3.1 +version=0.3.2 From 2a1e807aabdbf63df5d344bde27cf6c05f8a9310 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 17 Oct 2014 20:38:27 -0400 Subject: [PATCH 045/479] Fix changelog formatting --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 85ccdbbd909..3afed2204d6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,6 @@ # Change Log -# 0.3.1 +* 0.3.1 * Fix extension support for configuring encoding * Make default encoding UTF-8 From f23827ba3f2ccc9714b07e09a0aaf16a64b06525 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 18 Oct 2014 12:29:31 -0400 Subject: [PATCH 046/479] Defer determination of task output dirs (#6) --- .../gradle/plugin/avro/AvroPlugin.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 2810009dd6d..ec8e53c4709 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -15,6 +15,7 @@ import java.io.File; import java.io.FileFilter; +import java.util.concurrent.Callable; import static com.commercehub.gradle.plugin.avro.Constants.*; @@ -80,8 +81,7 @@ public void execute(Task task) { }); } - private static GenerateAvroProtocolTask configureProtocolGenerationTask(Project project, SourceSet sourceSet) { - File outputDir = getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION); + private static GenerateAvroProtocolTask configureProtocolGenerationTask(final Project project, final SourceSet sourceSet) { String taskName = sourceSet.getTaskName("generate", "avroProtocol"); GenerateAvroProtocolTask task = project.getTasks().create(taskName, GenerateAvroProtocolTask.class); task.setDescription( @@ -89,13 +89,17 @@ private static GenerateAvroProtocolTask configureProtocolGenerationTask(Project task.setGroup(GROUP_SOURCE_GENERATION); task.source(getAvroSourceDir(project, sourceSet)); task.include("*." + IDL_EXTENSION); - task.setOutputDir(outputDir); + task.getConventionMapping().map("outputDir", new Callable() { + @Override + public File call() throws Exception { + return getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION); + } + }); return task; } - private static GenerateAvroJavaTask configureJavaGenerationTask(Project project, SourceSet sourceSet, + private static GenerateAvroJavaTask configureJavaGenerationTask(final Project project, final SourceSet sourceSet, GenerateAvroProtocolTask protoTask) { - File outputDir = getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION); String taskName = sourceSet.getTaskName("generate", "avroJava"); GenerateAvroJavaTask task = project.getTasks().create(taskName, GenerateAvroJavaTask.class); task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.", @@ -104,7 +108,12 @@ private static GenerateAvroJavaTask configureJavaGenerationTask(Project project, task.source(getAvroSourceDir(project, sourceSet)); task.source(protoTask.getOutputs()); task.include("*." + SCHEMA_EXTENSION, "*." + PROTOCOL_EXTENSION); - task.setOutputDir(outputDir); + task.getConventionMapping().map("outputDir", new Callable() { + @Override + public File call() throws Exception { + return getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION); + } + }); getCompileJavaTask(project, sourceSet).source(task.getOutputs()); return task; } From 76b970114a0eabc73d1dcc34f7a8ad309a01de68 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 18 Oct 2014 12:31:22 -0400 Subject: [PATCH 047/479] Update change log --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 3afed2204d6..f3f07dda09b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,8 @@ # Change Log +* Unreleased + * Improve handling when custom buildDir is used + * 0.3.1 * Fix extension support for configuring encoding * Make default encoding UTF-8 From 9a421de99ad7120134295d78f67ef24da6ba186c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 18 Oct 2014 12:35:24 -0400 Subject: [PATCH 048/479] update change log for 0.3.2 --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index f3f07dda09b..a01f18b47e7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log * Unreleased + +* 0.3.2 * Improve handling when custom buildDir is used * 0.3.1 From c0c53ef72c7873aa2cc3f65ff7f0062d84745a76 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 18 Oct 2014 12:35:54 -0400 Subject: [PATCH 049/479] [Gradle Release Plugin] - new version commit: '0.3.3'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 94f9589e0f9..8cabea5288e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.3.2 +version=0.3.3 From b7fe9f1bb19deb5b0ee6cbb41356b4b491329ccf Mon Sep 17 00:00:00 2001 From: Victor Iacoban Date: Wed, 12 Nov 2014 15:47:52 -0800 Subject: [PATCH 050/479] no java is generated from avdl files --- src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index ec8e53c4709..9efad569de5 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -106,6 +106,7 @@ private static GenerateAvroJavaTask configureJavaGenerationTask(final Project pr sourceSet.getName())); task.setGroup(GROUP_SOURCE_GENERATION); task.source(getAvroSourceDir(project, sourceSet)); + task.source(protoTask.getOutputDir()); task.source(protoTask.getOutputs()); task.include("*." + SCHEMA_EXTENSION, "*." + PROTOCOL_EXTENSION); task.getConventionMapping().map("outputDir", new Callable() { From 6c4b266840300ea861e97be1f3e3ca4d5549a744 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 13 Nov 2014 14:58:04 -0500 Subject: [PATCH 051/479] update changelog --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index a01f18b47e7..3445a67f58b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,9 @@ * Unreleased +* 0.3.3 + * Fix generation of Java files from .avdl files; contribution from [viacoban](https://github.com/viacoban) + * 0.3.2 * Improve handling when custom buildDir is used From 0356b3aefcc84a109031ab74b91be9eda50aa46d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 13 Nov 2014 14:58:46 -0500 Subject: [PATCH 052/479] [Gradle Release Plugin] - new version commit: '0.3.4'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8cabea5288e..6e06493c564 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.3.3 +version=0.3.4 From 217125795bd9d39021a1611f9a1277ffd4b905ad Mon Sep 17 00:00:00 2001 From: Victor Iacoban Date: Sat, 15 Nov 2014 11:56:01 -0800 Subject: [PATCH 053/479] avdl import not working for external dependencies --- .../plugin/avro/GenerateAvroProtocolTask.java | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 24f9bd1bbf2..1bcc357e2e8 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -5,14 +5,23 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.gradle.api.GradleException; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; import org.gradle.api.file.FileCollection; +import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.TaskAction; import java.io.File; import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.LinkedList; +import java.util.List; -import static com.commercehub.gradle.plugin.avro.Constants.*; +import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; +import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; public class GenerateAvroProtocolTask extends OutputDirTask { @TaskAction @@ -32,22 +41,37 @@ private void failOnUnsupportedFiles() { private void processFiles() { int processedFileCount = 0; + ClassLoader loader = getRuntimeClassLoader(getProject()); for (File sourceFile : filterSources(new FileExtensionSpec(IDL_EXTENSION))) { - processIDLFile(sourceFile); + processIDLFile(sourceFile, loader); processedFileCount++; } setDidWork(processedFileCount > 0); } - private void processIDLFile(File idlFile) { + private void processIDLFile(File idlFile, ClassLoader loader) { getLogger().info("Processing {}", idlFile); File protoFile = new File(getOutputDir(), FilenameUtils.getBaseName(idlFile.getName()) + "." + PROTOCOL_EXTENSION); - try (Idl idl = new Idl(idlFile)) { - String protoJson = idl.CompilationUnit().toString(); + try (Idl idl = new Idl(idlFile, loader)) { + String protoJson = idl.CompilationUnit().toString(true); FileUtils.writeStringToFile(protoFile, protoJson, Constants.UTF8_ENCONDING); } catch (IOException | ParseException ex) { throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); } } + + private ClassLoader getRuntimeClassLoader(Project project) { + List urls = new LinkedList<>(); + Configuration configuration = project.getConfigurations().getByName(JavaPlugin.RUNTIME_CONFIGURATION_NAME); + for (File file : configuration) { + try { + urls.add(file.toURI().toURL()); + } catch (MalformedURLException e) { + getLogger().debug(e.getMessage()); + } + } + return urls.isEmpty() ? ClassLoader.getSystemClassLoader() : + new URLClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader()); + } } From 84bd228ed27df83d2c4d02221ea1f1e8c442fa05 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 16 Nov 2014 19:27:20 -0500 Subject: [PATCH 054/479] Fix registration of generated source for compilation (#8) --- CHANGES.md | 1 + .../java/com/commercehub/gradle/plugin/avro/AvroPlugin.java | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 3445a67f58b..1f786d05b7b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log * Unreleased + * Fix registration of generated sources for compilation (#8) * 0.3.3 * Fix generation of Java files from .avdl files; contribution from [viacoban](https://github.com/viacoban) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 9efad569de5..f1cec14fa3d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -115,7 +115,9 @@ public File call() throws Exception { return getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION); } }); - getCompileJavaTask(project, sourceSet).source(task.getOutputs()); + SourceTask compileJavaTask = getCompileJavaTask(project, sourceSet); + compileJavaTask.source(task.getOutputDir()); + compileJavaTask.source(task.getOutputs()); return task; } From 0c033f42c15e30f0abd39efe622cd119cbec7c27 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 16 Nov 2014 19:30:00 -0500 Subject: [PATCH 055/479] update change log for 0.3.4 --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 1f786d05b7b..b4b81555a01 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,10 @@ # Change Log * Unreleased + +* 0.3.4 * Fix registration of generated sources for compilation (#8) + * Change classloader handling to better support import of external dependencies (#9) * 0.3.3 * Fix generation of Java files from .avdl files; contribution from [viacoban](https://github.com/viacoban) From 439be31400c0565bff4feedcb570e9496452be9c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 16 Nov 2014 19:31:15 -0500 Subject: [PATCH 056/479] [Gradle Release Plugin] - new version commit: '0.3.5'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6e06493c564..a52099ab73f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.3.4 +version=0.3.5 From c0718c18117b406dec55ab369e61c8198f22477a Mon Sep 17 00:00:00 2001 From: Eric Wood Date: Wed, 15 Jul 2015 13:37:05 -0500 Subject: [PATCH 057/479] Adding fieldVisibility support. --- README.md | 8 +++++ .../gradle/plugin/avro/AvroBasePlugin.java | 12 +++++++ .../gradle/plugin/avro/AvroExtension.java | 1 + .../plugin/avro/DefaultAvroExtension.java | 8 +++++ .../plugin/avro/GenerateAvroJavaTask.java | 33 +++++++++++++++++++ 5 files changed, 62 insertions(+) diff --git a/README.md b/README.md index 08824f8516b..35e7b4a7f19 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,14 @@ avro { } ``` +Optionally, you can also configure the visibility of generated fields. + +```groovy +avro { + fieldVisibility = "PRIVATE" +} +``` + Additionally, ensure that you have a compile dependency on avro, such as: ```groovy diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index b116e9f3414..1d4b177efb0 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -32,6 +32,12 @@ public String call() throws Exception { return GenericData.StringType.String.name(); } }); + extensionMapping.map("fieldVisibility", new Callable() { + @Override + public String call() throws Exception { + return "PUBLIC_DEPRECATED"; + } + }); project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override public void execute(GenerateAvroJavaTask task) { @@ -48,6 +54,12 @@ public String call() throws Exception { return avroExtension.getStringType(); } }); + taskMapping.map("fieldVisibility", new Callable() { + @Override + public String call() throws Exception { + return avroExtension.getFieldVisibility(); + } + }); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index c6bc904f6be..903cabfee28 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -3,4 +3,5 @@ public interface AvroExtension { String getEncoding(); String getStringType(); + String getFieldVisibility(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 8787de2adfc..e5551044d2d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -3,6 +3,7 @@ public class DefaultAvroExtension implements AvroExtension { private String encoding; private String stringType; + private String fieldVisibility; @Override public String getEncoding() { @@ -21,4 +22,11 @@ public String getStringType() { public void setStringType(String stringType) { this.stringType = stringType; } + + @Override + public String getFieldVisibility() { return fieldVisibility; } + + public void setFieldVisibility(String fieldVisibility) { + this.fieldVisibility = fieldVisibility; + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index db0bdde9709..acbaca69949 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -29,6 +29,8 @@ public class GenerateAvroJavaTask extends OutputDirTask { private String stringType; + private String fieldVisibility; + @Input public String getEncoding() { return encoding; @@ -47,6 +49,13 @@ public void setStringType(String stringType) { this.stringType = stringType; } + @Input + public String getFieldVisibility() { return fieldVisibility; } + + public void setFieldVisibility(String fieldVisibility) { + this.fieldVisibility = fieldVisibility; + } + private GenericData.StringType parseStringType() { String stringType = getStringType(); for (GenericData.StringType type : GenericData.StringType.values()) { @@ -59,9 +68,27 @@ private GenericData.StringType parseStringType() { } + private SpecificCompiler.FieldVisibility parseFieldVisibility() { + getLogger().debug("Parsing fieldVisibility {}", getFieldVisibility()); + SpecificCompiler.FieldVisibility viz = null; + + if(getFieldVisibility() == null) { + return SpecificCompiler.FieldVisibility.PUBLIC_DEPRECATED; + } + + try { + viz = SpecificCompiler.FieldVisibility.valueOf(getFieldVisibility()); + } catch(Exception ex) { + throw new IllegalArgumentException(String.format("Invalid fieldVisibility '%s'.", getFieldVisibility())); + } + + return viz; + } + @TaskAction protected void process() { getLogger().debug("Using encoding {}", getEncoding()); + getLogger().debug("Using fieldVisibility {}", getFieldVisibility()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -111,6 +138,9 @@ private void processProtoFile(File sourceFile) { SpecificCompiler compiler = new SpecificCompiler(protocol); compiler.setStringType(parseStringType()); compiler.setOutputCharacterEncoding(getEncoding()); + getLogger().debug("Setting fieldVisibility to {}", parseFieldVisibility().toString()); + SpecificCompiler.FieldVisibility visibility = parseFieldVisibility(); + compiler.setFieldVisibility(visibility); compiler.compileToDestination(sourceFile, getOutputDir()); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); @@ -140,6 +170,9 @@ private int processSchemaFiles() { SpecificCompiler compiler = new SpecificCompiler(schema); compiler.setStringType(parseStringType()); compiler.setOutputCharacterEncoding(getEncoding()); + getLogger().debug("Setting fieldVisibility to {}", parseFieldVisibility().toString()); + SpecificCompiler.FieldVisibility visibility = parseFieldVisibility(); + compiler.setFieldVisibility(visibility); compiler.compileToDestination(sourceFile, getOutputDir()); types = parser.getTypes(); getLogger().info("Processed {}", sourceFile); From 9a74dccb8c755c5c241ef10382c986c1b26beca0 Mon Sep 17 00:00:00 2001 From: Eric Wood Date: Wed, 15 Jul 2015 18:00:38 -0500 Subject: [PATCH 058/479] Updating CHANGES.md to indicate addition of fieldVisibility. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index b4b81555a01..32b50511d15 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log * Unreleased + * Add ability to specify fieldVisibility for generated Java source; contribution from [wooder79](https://github.com/wooder79) * 0.3.4 * Fix registration of generated sources for compilation (#8) From b3808810b0512e56a3ce685ebcdca22296ed9786 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 12 Aug 2015 15:18:57 -0400 Subject: [PATCH 059/479] update, prep for release of 0.4.0 --- CHANGES.md | 6 + README.md | 10 +- RELEASING.md | 6 + build.gradle | 84 +++++++------- gradle.properties | 1 - gradle/wrapper/gradle-wrapper.jar | Bin 51348 -> 53636 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- .../plugin/avro/UnqualifiedAvroPlugin.java | 15 --- .../META-INF/gradle-plugins/avro.properties | 1 - .../avro/AvroPluginFunctionalSpec.groovy | 105 ++++++++++++++++++ .../gradle/plugin/avro/interop.avdl | 50 +++++++++ .../commercehub/gradle/plugin/avro/mail.avpr | 26 +++++ .../commercehub/gradle/plugin/avro/user.avsc | 9 ++ 13 files changed, 251 insertions(+), 66 deletions(-) create mode 100644 RELEASING.md delete mode 100644 gradle.properties delete mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/UnqualifiedAvroPlugin.java delete mode 100644 src/main/resources/META-INF/gradle-plugins/avro.properties create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/mail.avpr create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc diff --git a/CHANGES.md b/CHANGES.md index 32b50511d15..f87520d0106 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,13 @@ # Change Log * Unreleased + +* 0.4.0 * Add ability to specify fieldVisibility for generated Java source; contribution from [wooder79](https://github.com/wooder79) + * Removed support for unqualified plugin ID (just "avro") + * Published via new mechanism to [Gradle plugin portal](https://plugins.gradle.org) + * Stopped publishing to previous location on Bintray + * Built against Gradle 2.6; uses [test kit](https://docs.gradle.org/current/userguide/test_kit.html) for functional testing * 0.3.4 * Fix registration of generated sources for compilation (#8) diff --git a/README.md b/README.md index 35e7b4a7f19..bcb3821cf8a 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,12 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav [![Build Status](https://travis-ci.org/commercehub-oss/gradle-avro-plugin.svg?branch=master)](https://travis-ci.org/commercehub-oss/gradle-avro-plugin) +# Compatibility + +* Currently tested against Gradle 2.6; other versions may be compatible +* Currently tested against Avro 1.7.7; other versions may be compatible +* Java 7 or higher required + # Usage Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](https://github.com/commercehub-oss/gradle-avro-plugin/blob/master/CHANGES.md). @@ -57,7 +63,7 @@ repositories { jcenter() } dependencies { - compile "org.apache.avro:avro:1.7.6" + compile "org.apache.avro:avro:1.7.7" } ``` @@ -78,7 +84,7 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - compile "org.apache.avro:avro:1.7.6" + compile "org.apache.avro:avro:1.7.7" } task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 00000000000..b093b421b21 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,6 @@ +# Release Process + +1. Check that you've followed the setup steps listed [here](https://plugins.gradle.org/docs/submit) +1. Update `CHANGES.md` +1. Update the plugin version in `build.gradle` under "pluginBundle/version" +1. Run `./gradlew clean build publishPlugins` diff --git a/build.gradle b/build.gradle index 5e47ec8acb3..95229be2965 100644 --- a/build.gradle +++ b/build.gradle @@ -1,16 +1,9 @@ -buildscript { - repositories { - jcenter() - } - dependencies { - classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.3" - classpath "com.github.townsfolk:gradle-release:1.2" - } +plugins { + id "groovy" + id "idea" + id "com.gradle.plugin-publish" version "0.9.1" } -apply plugin: "groovy" -apply plugin: "idea" - repositories { jcenter() } @@ -20,49 +13,50 @@ dependencies { compile localGroovy() compile "org.apache.avro:avro-compiler:1.7.7" compile "org.apache.commons:commons-io:1.3.2" - testCompile "org.spockframework:spock-core:0.7-groovy-1.8" + testCompile "org.spockframework:spock-core:1.0-groovy-2.3" + testCompile gradleTestKit() } sourceCompatibility = 1.7 -group = "com.commercehub.gradle.plugin" - -task sourcesJar(type: Jar, dependsOn: classes) { - from sourceSets.main.allSource - classifier "sources" - extension "jar" +pluginBundle { + website = "https://github.com/commercehub-oss/gradle-avro-plugin" + vcsUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" + description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." + tags = ["serialization", "avro"] + version = "0.4.0" + plugins { + avro { + id = "com.commercehub.gradle.plugin.avro" + displayName = "Avro Plugin" + } + avroBase { + id = "com.commercehub.gradle.plugin.avro-base" + displayName = "Avro Base Plugin" + } + } } -task javadocJar(type: Jar, dependsOn: javadoc) { - from javadoc.destinationDir - classifier "javadoc" - extension "jar" +idea.project.ipr { + withXml { provider -> + provider.node.component.find { it.@name == "VcsDirectoryMappings" }.mapping.@vcs = "Git" + } } -apply plugin: "maven-publish" -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar - } +// Write the plugin's classpath to a file to share with the tests +task createClasspathManifest { + def outputDir = file("$buildDir/$name") + + inputs.files sourceSets.main.runtimeClasspath + outputs.dir outputDir + + doLast { + outputDir.mkdirs() + file("$outputDir/plugin-classpath.txt").text = sourceSets.main.runtimeClasspath.join("\n") } } -apply plugin: "release" -apply plugin: "bintray" -def project = this -bintray { - user = project.hasProperty("bintrayUserName") ? bintrayUserName : null - key = project.hasProperty("bintrayApiKey") ? bintrayApiKey : null - publications = ["mavenJava"] - pkg { - repo = "main" - userOrg = "commercehub-oss" - name = project.name - licenses = ["Apache-2.0"] - } +// Add the classpath file to the test runtime classpath +dependencies { + testRuntime files(createClasspathManifest) } -bintrayUpload.dependsOn build, sourcesJar, javadocJar -createReleaseTag.dependsOn bintrayUpload diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index a52099ab73f..00000000000 --- a/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -version=0.3.5 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0087cd3b18659b5577cf6ad3ef61f8eb9416ebba..fd7e590e5154e82211909581e71018372134fb27 100644 GIT binary patch delta 31518 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%0AidC0W48oaW0j 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 S$gH5jjfw^arr-6?fBzpr3ieL` delta 29341 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a9aea9e6c26..bcce60f3eda 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jun 06 23:58:32 EDT 2014 +#Wed Aug 12 13:50:22 EDT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-bin.zip diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/UnqualifiedAvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/UnqualifiedAvroPlugin.java deleted file mode 100644 index 7c098a14e0f..00000000000 --- a/src/main/java/com/commercehub/gradle/plugin/avro/UnqualifiedAvroPlugin.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.commercehub.gradle.plugin.avro; - -import org.gradle.api.Project; - -@Deprecated -public class UnqualifiedAvroPlugin extends AvroPlugin { - // TODO: remove this class (and related avro.properties) in 0.4.0. - - @Override - public void apply(Project project) { - project.getLogger().warn("The 'avro' plugin ID is deprecated; " + - "please update your build to use 'com.commercehub.gradle.plugin.avro' instead."); - super.apply(project); - } -} diff --git a/src/main/resources/META-INF/gradle-plugins/avro.properties b/src/main/resources/META-INF/gradle-plugins/avro.properties deleted file mode 100644 index 2acb12647df..00000000000 --- a/src/main/resources/META-INF/gradle-plugins/avro.properties +++ /dev/null @@ -1 +0,0 @@ -implementation-class=com.commercehub.gradle.plugin.avro.UnqualifiedAvroPlugin diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy new file mode 100644 index 00000000000..79501f78353 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -0,0 +1,105 @@ +package com.commercehub.gradle.plugin.avro + +import org.gradle.testkit.runner.GradleRunner +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +import java.nio.file.Files +import java.nio.file.Path + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class AvroPluginFunctionalSpec extends Specification { + private static final String AVRO_VERSION = "1.7.7" // TODO: externalize + + @Rule + TemporaryFolder testProjectDir + + File buildFile + File avroDir + + def setup() { + buildFile = testProjectDir.newFile('build.gradle') + avroDir = testProjectDir.newFolder("src", "main", "avro") + + def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") + if (pluginClasspathResource == null) { + throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") + } + + def pluginClasspath = pluginClasspathResource.readLines() + .collect { it.replace('\\', '\\\\') } // escape backslashes in Windows paths + .collect { "'$it'" } + .join(", ") + + // Add the logic under test to the test build + buildFile << """ + buildscript { + dependencies { + classpath files($pluginClasspath) + } + } + apply plugin: "com.commercehub.gradle.plugin.avro" + repositories { jcenter() } + dependencies { compile "org.apache.avro:avro:${AVRO_VERSION}" } + """ + } + + def "can generate and compile java files from json schema"() { + given: + copyResource("user.avsc", avroDir) + + when: + def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/example/avro/User.class")) + } + + def "can generate and compile java files from json protocol"() { + given: + buildFile << """ + dependencies { compile "org.apache.avro:avro-ipc:${AVRO_VERSION}" } + """ + copyResource("mail.avpr", avroDir) + + when: + def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/org/apache/avro/test/Mail.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/test/Message.class")) + } + + def "can generate and compile java files from IDL"() { + given: + copyResource("interop.avdl", avroDir) + + when: + def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + + then: + result.task(":generateAvroProtocol").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/org/apache/avro/Foo.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/Interop.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/Kind.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/MD5.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/Node.class")) + } + + private void copyResource(String name, File targetFolder) { + def file = new File(targetFolder, name) + file << getClass().getResourceAsStream(name) + } + + private Path projectPath(String path) { + return testProjectDir.root.toPath().resolve(path) + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl b/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl new file mode 100644 index 00000000000..7e056665165 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +// Currently genavro only does Protocols. +@namespace("org.apache.avro") +protocol InteropProtocol { + record Foo { + string label; + } + + enum Kind { A, B, C } + fixed MD5(16); + + record Node { + string label; + array children = []; + } + + record Interop { + int intField = 1; + long longField = -1; + string stringField; + boolean boolField = false; + float floatField = 0.0; + double doubleField = -1.0e12; + null nullField; + array arrayField = []; + map mapField; + union { boolean, double, array } unionFIeld; + Kind enumField; + MD5 fixedField; + Node recordField; + } + +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/mail.avpr b/src/test/resources/com/commercehub/gradle/plugin/avro/mail.avpr new file mode 100644 index 00000000000..74105922b4b --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/mail.avpr @@ -0,0 +1,26 @@ +{"namespace": "org.apache.avro.test", + "protocol": "Mail", + + "types": [ + {"name": "Message", "type": "record", + "fields": [ + {"name": "to", "type": "string"}, + {"name": "from", "type": "string"}, + {"name": "body", "type": "string"} + ] + } + ], + + "messages": { + "send": { + "request": [{"name": "message", "type": "Message"}], + "response": "string" + }, + "fireandforget": { + "request": [{"name": "message", "type": "Message"}], + "response": "null", + "one-way": true + } + + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc new file mode 100644 index 00000000000..117ea70ee06 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc @@ -0,0 +1,9 @@ +{"namespace": "example.avro", + "type": "record", + "name": "User", + "fields": [ + {"name": "name", "type": "string"}, + {"name": "favorite_number", "type": ["int", "null"]}, + {"name": "favorite_color", "type": ["string", "null"]} + ] +} From eceeaccb130822eae86544610726d98137a5c7c6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 12 Aug 2015 15:21:17 -0400 Subject: [PATCH 060/479] Try migrating to travis' container-based infrastructure See http://docs.travis-ci.com/user/migrating-from-legacy/ --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 409121df002..73cdf6982bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +sudo: false language: java env: global: From addb28add2772913b1e4d62dab28791f8664ce9c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 12 Aug 2015 15:26:55 -0400 Subject: [PATCH 061/479] Specify legacy maven coords for plugin --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index 95229be2965..73cdfc785ef 100644 --- a/build.gradle +++ b/build.gradle @@ -35,6 +35,10 @@ pluginBundle { displayName = "Avro Base Plugin" } } + mavenCoordinates { + groupId = "com.commercehub.gradle.plugin" + artifactId = "gradle-avro-plugin" + } } idea.project.ipr { From 1fd99280e05b28aaca1c5c30c1c0df60a63d7763 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 13 Aug 2015 09:42:50 -0400 Subject: [PATCH 062/479] update documentation --- README.md | 4 +++- RELEASING.md | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bcb3821cf8a..1648e38323d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,9 @@ plugins { // Earlier versions of Gradle buildscript { repositories { - jcenter() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { classpath "com.commercehub.gradle.plugin:gradle-avro-plugin:VERSION" diff --git a/RELEASING.md b/RELEASING.md index b093b421b21..7dfabe0dfd8 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -3,4 +3,6 @@ 1. Check that you've followed the setup steps listed [here](https://plugins.gradle.org/docs/submit) 1. Update `CHANGES.md` 1. Update the plugin version in `build.gradle` under "pluginBundle/version" +1. Commit and tag with the version number 1. Run `./gradlew clean build publishPlugins` +1. Push From be8893e10b283978ced43d9371a389292913919e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 13 Aug 2015 09:58:32 -0400 Subject: [PATCH 063/479] build: improve vcs specification --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 73cdfc785ef..af3ca49b3f9 100644 --- a/build.gradle +++ b/build.gradle @@ -41,9 +41,9 @@ pluginBundle { } } -idea.project.ipr { - withXml { provider -> - provider.node.component.find { it.@name == "VcsDirectoryMappings" }.mapping.@vcs = "Git" +idea { + project { + vcs = "Git" } } From 0baf1d294039fc31a21d9180e523dce80fda00bd Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 18 Aug 2015 13:50:06 -0400 Subject: [PATCH 064/479] Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) --- CHANGES.md | 1 + .../gradle/plugin/avro/AvroPlugin.java | 4 +- .../avro/AvroPluginFunctionalSpec.groovy | 50 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f87520d0106..65168c24e57 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log * Unreleased + * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) * 0.4.0 * Add ability to specify fieldVisibility for generated Java source; contribution from [wooder79](https://github.com/wooder79) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index f1cec14fa3d..961c0712003 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -88,7 +88,7 @@ private static GenerateAvroProtocolTask configureProtocolGenerationTask(final Pr String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); task.setGroup(GROUP_SOURCE_GENERATION); task.source(getAvroSourceDir(project, sourceSet)); - task.include("*." + IDL_EXTENSION); + task.include("**/*." + IDL_EXTENSION); task.getConventionMapping().map("outputDir", new Callable() { @Override public File call() throws Exception { @@ -108,7 +108,7 @@ private static GenerateAvroJavaTask configureJavaGenerationTask(final Project pr task.source(getAvroSourceDir(project, sourceSet)); task.source(protoTask.getOutputDir()); task.source(protoTask.getOutputs()); - task.include("*." + SCHEMA_EXTENSION, "*." + PROTOCOL_EXTENSION); + task.include("**/*." + SCHEMA_EXTENSION, "**/*." + PROTOCOL_EXTENSION); task.getConventionMapping().map("outputDir", new Callable() { @Override public File call() throws Exception { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 79501f78353..2518555cbd8 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -18,10 +18,12 @@ class AvroPluginFunctionalSpec extends Specification { File buildFile File avroDir + File avroSubDir def setup() { buildFile = testProjectDir.newFile('build.gradle') avroDir = testProjectDir.newFolder("src", "main", "avro") + avroSubDir = testProjectDir.newFolder("src", "main", "avro", "foo") def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") if (pluginClasspathResource == null) { @@ -94,6 +96,54 @@ class AvroPluginFunctionalSpec extends Specification { Files.exists(projectPath("build/classes/main/org/apache/avro/Node.class")) } + def "supports json schema files in subdirectories"() { + given: + copyResource("user.avsc", avroSubDir) + + when: + def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/example/avro/User.class")) + } + + def "supports json protocol files in subdirectories"() { + given: + buildFile << """ + dependencies { compile "org.apache.avro:avro-ipc:${AVRO_VERSION}" } + """ + copyResource("mail.avpr", avroSubDir) + + when: + def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/org/apache/avro/test/Mail.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/test/Message.class")) + } + + def "supports IDL files in subdirectories"() { + given: + copyResource("interop.avdl", avroSubDir) + + when: + def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + + then: + result.task(":generateAvroProtocol").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/org/apache/avro/Foo.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/Interop.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/Kind.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/MD5.class")) + Files.exists(projectPath("build/classes/main/org/apache/avro/Node.class")) + } + private void copyResource(String name, File targetFolder) { def file = new File(targetFolder, name) file << getClass().getResourceAsStream(name) From bb08ea588a39eada965e69ba539497d9c1d1061a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 11 Sep 2015 09:47:41 -0400 Subject: [PATCH 065/479] Add functional test coverage for enum handling --- .../avro/EnumHandlingFunctionalSpec.groovy | 101 ++++++++++++++++++ .../gradle/plugin/avro/innerEnum.avsc | 18 ++++ .../gradle/plugin/avro/simpleEnum.avsc | 11 ++ .../gradle/plugin/avro/useEnum.avsc | 8 ++ 4 files changed, 138 insertions(+) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/innerEnum.avsc create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/simpleEnum.avsc create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/useEnum.avsc diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy new file mode 100644 index 00000000000..ad983f60e00 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -0,0 +1,101 @@ +package com.commercehub.gradle.plugin.avro + +import org.gradle.testkit.runner.GradleRunner +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +import java.nio.file.Files +import java.nio.file.Path + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class EnumHandlingFunctionalSpec extends Specification { + private static final String AVRO_VERSION = "1.7.7" // TODO: externalize + + @Rule + TemporaryFolder testProjectDir + + File buildFile + File avroDir + File avroSubDir + + def setup() { + buildFile = testProjectDir.newFile('build.gradle') + avroDir = testProjectDir.newFolder("src", "main", "avro") + avroSubDir = testProjectDir.newFolder("src", "main", "avro", "foo") + + def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") + if (pluginClasspathResource == null) { + throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") + } + + def pluginClasspath = pluginClasspathResource.readLines() + .collect { it.replace('\\', '\\\\') } // escape backslashes in Windows paths + .collect { "'$it'" } + .join(", ") + + // Add the logic under test to the test build + buildFile << """ + buildscript { + dependencies { + classpath files($pluginClasspath) + } + } + apply plugin: "com.commercehub.gradle.plugin.avro" + repositories { jcenter() } + dependencies { compile "org.apache.avro:avro:${AVRO_VERSION}" } + """ + } + + def "supports simple enums"() { + given: + copyResource("simpleEnum.avsc", avroDir) + + when: + def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/example/avro/MyEnum.class")) + } + + def "supports enums nested within a schema"() { + given: + copyResource("innerEnum.avsc", avroDir) + + when: + def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/example/avro/Test.class")) + Files.exists(projectPath("build/classes/main/example/avro/Kind.class")) + } + + def "supports using enums defined in a separate schema file"() { + given: + copyResource("useEnum.avsc", avroDir) + copyResource("simpleEnum.avsc", avroDir) + + when: + def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/example/avro/User.class")) + Files.exists(projectPath("build/classes/main/example/avro/MyEnum.class")) + } + + private void copyResource(String name, File targetFolder) { + def file = new File(targetFolder, name) + file << getClass().getResourceAsStream(name) + } + + private Path projectPath(String path) { + return testProjectDir.root.toPath().resolve(path) + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/innerEnum.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/innerEnum.avsc new file mode 100644 index 00000000000..ff4c6894ecc --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/innerEnum.avsc @@ -0,0 +1,18 @@ +{ + "namespace": "example.avro", + "type": "record", + "name": "Test", + "fields": [ + { + "name": "kind", + "type": [ + "null", + { + "name": "Kind", + "type": "enum", + "symbols": ["X", "Y", "Z"] + } + ] + } + ] +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/simpleEnum.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/simpleEnum.avsc new file mode 100644 index 00000000000..db570b2e48b --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/simpleEnum.avsc @@ -0,0 +1,11 @@ +{ + "namespace": "example.avro", + "type": "enum", + "symbols": [ + "zero", + "int", + "two", + "three" + ], + "name": "MyEnum" +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/useEnum.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/useEnum.avsc new file mode 100644 index 00000000000..d34a605e012 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/useEnum.avsc @@ -0,0 +1,8 @@ +{"namespace": "example.avro", + "type": "record", + "name": "User", + "fields": [ + {"name": "name", "type": "string"}, + {"name": "kind", "type": "MyEnum"} + ] +} From 05d75fa69fce761ec7bc8a16aceb6c0d55bfbcee Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 11 Sep 2015 15:02:54 -0400 Subject: [PATCH 066/479] Expose original error messages from avro-compiler when compilation fails --- CHANGES.md | 1 + .../plugin/avro/GenerateAvroJavaTask.java | 37 +++++---- .../avro/AvroPluginFunctionalSpec.groovy | 60 +++----------- .../avro/EnumHandlingFunctionalSpec.groovy | 80 +++++-------------- .../gradle/plugin/avro/FunctionalSpec.groovy | 65 +++++++++++++++ .../gradle/plugin/avro/enumField.avsc | 15 ++++ .../gradle/plugin/avro/enumMalformed.avsc | 12 +++ .../avro/{simpleEnum.avsc => enumSimple.avsc} | 0 .../avro/{innerEnum.avsc => enumUnion.avsc} | 0 .../avro/{useEnum.avsc => enumUseSimple.avsc} | 2 +- 10 files changed, 149 insertions(+), 123 deletions(-) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/enumField.avsc create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/enumMalformed.avsc rename src/test/resources/com/commercehub/gradle/plugin/avro/{simpleEnum.avsc => enumSimple.avsc} (100%) rename src/test/resources/com/commercehub/gradle/plugin/avro/{innerEnum.avsc => enumUnion.avsc} (100%) rename src/test/resources/com/commercehub/gradle/plugin/avro/{useEnum.avsc => enumUseSimple.avsc} (75%) diff --git a/CHANGES.md b/CHANGES.md index 65168c24e57..10dac89f0b0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ * Unreleased * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) + * Expose original error messages from `avro-compiler` when compilation fails * 0.4.0 * Add ability to specify fieldVisibility for generated Java source; contribution from [wooder79](https://github.com/wooder79) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index acbaca69949..1fdd64db9e4 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -13,14 +13,11 @@ import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; -import java.util.Set; +import java.util.*; -import static com.commercehub.gradle.plugin.avro.Constants.*; +import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; +import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; +import static java.lang.System.lineSeparator; public class GenerateAvroJavaTask extends OutputDirTask { private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); @@ -151,6 +148,7 @@ private int processSchemaFiles() { int processedTotal = 0; int processedThisPass = -1; Map types = new HashMap<>(); + Map errors = new HashMap<>(); // file path to error message Queue nextPass = new LinkedList<>(filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles()); Queue thisPass = new LinkedList<>(); while (processedThisPass != 0) { @@ -162,7 +160,8 @@ private int processSchemaFiles() { nextPass.clear(); File sourceFile = thisPass.poll(); while (sourceFile != null) { - getLogger().debug("Processing {}", sourceFile); + String path = getProject().relativePath(sourceFile); + getLogger().debug("Processing {}", path); try { Schema.Parser parser = new Schema.Parser(); parser.addTypes(types); @@ -175,26 +174,34 @@ private int processSchemaFiles() { compiler.setFieldVisibility(visibility); compiler.compileToDestination(sourceFile, getOutputDir()); types = parser.getTypes(); - getLogger().info("Processed {}", sourceFile); + getLogger().info("Processed {}", path); processedThisPass++; + errors.remove(path); } catch (SchemaParseException ex) { - if (ex.getMessage().matches("(?i).*(undefined name|not a defined name).*")) { - getLogger().debug("Found undefined name in {}; will try again later", sourceFile); + String errorMessage = ex.getMessage(); + if (errorMessage.matches("(?i).*(undefined name|not a defined name).*")) { + getLogger().debug("Found undefined name in {} ({}); will try again later", path, errorMessage); nextPass.add(sourceFile); + errors.put(path, ex.getMessage()); } else { - throw new GradleException(String.format("Failed to compile schema definition file %s", sourceFile), ex); + throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } } catch (NullPointerException ex) { - getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency); will try again later", sourceFile); + getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency); will try again later", path); nextPass.add(sourceFile); + errors.put(path, ex.getMessage()); } catch (IOException ex) { - throw new GradleException(String.format("Failed to compile schema definition file %s", sourceFile), ex); + throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } sourceFile = thisPass.poll(); } } if (!nextPass.isEmpty()) { - throw new GradleException(String.format("Failed to compile schema definition files due to undefined names: %s", nextPass)); + StringBuilder errorMessage = new StringBuilder("Could not compile schema definition files:"); + for (Map.Entry error : errors.entrySet()) { + errorMessage.append(lineSeparator()).append("* ").append(error.getKey()).append(": ").append(error.getValue()); + } + throw new GradleException(errorMessage.toString()); } return processedTotal; } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 2518555cbd8..8ef76b7458e 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -1,53 +1,13 @@ package com.commercehub.gradle.plugin.avro import org.gradle.testkit.runner.GradleRunner -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification import java.nio.file.Files -import java.nio.file.Path +import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS -class AvroPluginFunctionalSpec extends Specification { - private static final String AVRO_VERSION = "1.7.7" // TODO: externalize - - @Rule - TemporaryFolder testProjectDir - - File buildFile - File avroDir - File avroSubDir - - def setup() { - buildFile = testProjectDir.newFile('build.gradle') - avroDir = testProjectDir.newFolder("src", "main", "avro") - avroSubDir = testProjectDir.newFolder("src", "main", "avro", "foo") - - def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") - if (pluginClasspathResource == null) { - throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") - } - - def pluginClasspath = pluginClasspathResource.readLines() - .collect { it.replace('\\', '\\\\') } // escape backslashes in Windows paths - .collect { "'$it'" } - .join(", ") - - // Add the logic under test to the test build - buildFile << """ - buildscript { - dependencies { - classpath files($pluginClasspath) - } - } - apply plugin: "com.commercehub.gradle.plugin.avro" - repositories { jcenter() } - dependencies { compile "org.apache.avro:avro:${AVRO_VERSION}" } - """ - } - +class AvroPluginFunctionalSpec extends FunctionalSpec { def "can generate and compile java files from json schema"() { given: copyResource("user.avsc", avroDir) @@ -144,12 +104,16 @@ class AvroPluginFunctionalSpec extends Specification { Files.exists(projectPath("build/classes/main/org/apache/avro/Node.class")) } - private void copyResource(String name, File targetFolder) { - def file = new File(targetFolder, name) - file << getClass().getResourceAsStream(name) - } + def "gives a meaningful error message when presented a malformed schema file"() { + given: + copyResource("enumMalformed.avsc", avroDir) - private Path projectPath(String path) { - return testProjectDir.root.toPath().resolve(path) + when: + def result = buildAndFail() + + then: + result.task(":generateAvroJava").outcome == FAILED + result.standardError.contains("> Could not compile schema definition files:") + result.standardError.contains("* src/main/avro/enumMalformed.avsc: \"enum\" is not a defined name. The type of the \"gender\" field must be a defined name or a {\"type\": ...} expression.") } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index ad983f60e00..737ffe29257 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -1,72 +1,43 @@ package com.commercehub.gradle.plugin.avro -import org.gradle.testkit.runner.GradleRunner -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import spock.lang.Specification - import java.nio.file.Files -import java.nio.file.Path import static org.gradle.testkit.runner.TaskOutcome.SUCCESS -class EnumHandlingFunctionalSpec extends Specification { - private static final String AVRO_VERSION = "1.7.7" // TODO: externalize - - @Rule - TemporaryFolder testProjectDir - - File buildFile - File avroDir - File avroSubDir - - def setup() { - buildFile = testProjectDir.newFile('build.gradle') - avroDir = testProjectDir.newFolder("src", "main", "avro") - avroSubDir = testProjectDir.newFolder("src", "main", "avro", "foo") - - def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") - if (pluginClasspathResource == null) { - throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") - } +class EnumHandlingFunctionalSpec extends FunctionalSpec { + def "supports simple enums"() { + given: + copyResource("enumSimple.avsc", avroDir) - def pluginClasspath = pluginClasspathResource.readLines() - .collect { it.replace('\\', '\\\\') } // escape backslashes in Windows paths - .collect { "'$it'" } - .join(", ") + when: + def result = runBuild() - // Add the logic under test to the test build - buildFile << """ - buildscript { - dependencies { - classpath files($pluginClasspath) - } - } - apply plugin: "com.commercehub.gradle.plugin.avro" - repositories { jcenter() } - dependencies { compile "org.apache.avro:avro:${AVRO_VERSION}" } - """ + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/example/avro/MyEnum.class")) } - def "supports simple enums"() { + def "supports enums defined within a record field"() { given: - copyResource("simpleEnum.avsc", avroDir) + copyResource("enumField.avsc", avroDir) when: - def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + def result = runBuild() then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/example/avro/MyEnum.class")) + Files.exists(projectPath("build/classes/main/example/avro/Test.class")) + Files.exists(projectPath("build/classes/main/example/avro/Gender.class")) } - def "supports enums nested within a schema"() { + def "supports enums defined within a union"() { given: - copyResource("innerEnum.avsc", avroDir) + copyResource("enumUnion.avsc", avroDir) when: - def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + def result = runBuild() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -77,11 +48,11 @@ class EnumHandlingFunctionalSpec extends Specification { def "supports using enums defined in a separate schema file"() { given: - copyResource("useEnum.avsc", avroDir) - copyResource("simpleEnum.avsc", avroDir) + copyResource("enumSimple.avsc", avroDir) + copyResource("enumUseSimple.avsc", avroDir) when: - def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + def result = runBuild() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -89,13 +60,4 @@ class EnumHandlingFunctionalSpec extends Specification { Files.exists(projectPath("build/classes/main/example/avro/User.class")) Files.exists(projectPath("build/classes/main/example/avro/MyEnum.class")) } - - private void copyResource(String name, File targetFolder) { - def file = new File(targetFolder, name) - file << getClass().getResourceAsStream(name) - } - - private Path projectPath(String path) { - return testProjectDir.root.toPath().resolve(path) - } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy new file mode 100644 index 00000000000..8b9625a8506 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -0,0 +1,65 @@ +package com.commercehub.gradle.plugin.avro + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +import java.nio.file.Path + +abstract class FunctionalSpec extends Specification { + protected static final String AVRO_VERSION = "1.7.7" // TODO: externalize + + @Rule + TemporaryFolder testProjectDir + + File buildFile + File avroDir + File avroSubDir + + def setup() { + buildFile = testProjectDir.newFile('build.gradle') + avroDir = testProjectDir.newFolder("src", "main", "avro") + avroSubDir = testProjectDir.newFolder("src", "main", "avro", "foo") + + def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") + if (pluginClasspathResource == null) { + throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") + } + + def pluginClasspath = pluginClasspathResource.readLines() + .collect { it.replace('\\', '\\\\') } // escape backslashes in Windows paths + .collect { "'$it'" } + .join(", ") + + // Add the logic under test to the test build + buildFile << """ + buildscript { + dependencies { + classpath files($pluginClasspath) + } + } + apply plugin: "com.commercehub.gradle.plugin.avro" + repositories { jcenter() } + dependencies { compile "org.apache.avro:avro:${AVRO_VERSION}" } + """ + } + + protected void copyResource(String name, File targetFolder) { + def file = new File(targetFolder, name) + file << getClass().getResourceAsStream(name) + } + + protected Path projectPath(String path) { + return testProjectDir.root.toPath().resolve(path) + } + + protected BuildResult runBuild() { + return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("--info", "build").build() + } + + protected BuildResult buildAndFail() { + return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("--info", "build").buildAndFail() + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/enumField.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/enumField.avsc new file mode 100644 index 00000000000..05ec79e5a40 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/enumField.avsc @@ -0,0 +1,15 @@ +{ + "namespace": "example.avro", + "type": "record", + "name": "Test", + "fields": [ + { + "name": "gender", + "type": { + "name": "Gender", + "type": "enum", + "symbols": ["MALE", "FEMALE"] + } + } + ] +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/enumMalformed.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/enumMalformed.avsc new file mode 100644 index 00000000000..7b86671b805 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/enumMalformed.avsc @@ -0,0 +1,12 @@ +{ + "namespace": "example.avro", + "type": "record", + "name": "Test", + "fields": [ + { + "name": "gender", + "type": "enum", + "symbols": ["MALE", "FEMALE"] + } + ] +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/simpleEnum.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/enumSimple.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/simpleEnum.avsc rename to src/test/resources/com/commercehub/gradle/plugin/avro/enumSimple.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/innerEnum.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/enumUnion.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/innerEnum.avsc rename to src/test/resources/com/commercehub/gradle/plugin/avro/enumUnion.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/useEnum.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/enumUseSimple.avsc similarity index 75% rename from src/test/resources/com/commercehub/gradle/plugin/avro/useEnum.avsc rename to src/test/resources/com/commercehub/gradle/plugin/avro/enumUseSimple.avsc index d34a605e012..15741804f16 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/useEnum.avsc +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/enumUseSimple.avsc @@ -3,6 +3,6 @@ "name": "User", "fields": [ {"name": "name", "type": "string"}, - {"name": "kind", "type": "MyEnum"} + {"name": "kind", "type": "MyEnum"} ] } From 90a6ee681f1b08fc2d9e7655ce34ebbe3d668694 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 11 Sep 2015 15:08:55 -0400 Subject: [PATCH 067/479] update version: 0.5.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 10dac89f0b0..dd6a8b58310 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log * Unreleased + +* 0.5.0 * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) * Expose original error messages from `avro-compiler` when compilation fails diff --git a/build.gradle b/build.gradle index af3ca49b3f9..2b8d4068576 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ pluginBundle { vcsUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." tags = ["serialization", "avro"] - version = "0.4.0" + version = "0.5.0" plugins { avro { id = "com.commercehub.gradle.plugin.avro" From f1b6c9f6378b516547b68e873d7e37d192ca97b3 Mon Sep 17 00:00:00 2001 From: Ryon Day Date: Wed, 16 Sep 2015 16:14:16 -0500 Subject: [PATCH 068/479] Add support for alternate Velocity template directory. This can be used to "fake" inheritance and interface implementation with the generated Avro classes. --- CHANGES.md | 1 + README.md | 9 ++++++++ .../gradle/plugin/avro/AvroBasePlugin.java | 18 ++++++++++++++- .../gradle/plugin/avro/AvroExtension.java | 1 + .../gradle/plugin/avro/Constants.java | 4 +++- .../plugin/avro/DefaultAvroExtension.java | 10 ++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 23 +++++++++++++++++-- .../plugin/avro/GenerateAvroProtocolTask.java | 2 +- 8 files changed, 63 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index dd6a8b58310..690894e6a78 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log * Unreleased + * Add ability to set source directory for the Avro compiler's Velocity templates. * 0.5.0 * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) diff --git a/README.md b/README.md index 1648e38323d..26da1830f1d 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,15 @@ avro { } ``` +Optionally, you can also configure the source directory for the Velocity templates that the Avro compiler uses to +generate Java files. + +```groovy +avro { + templateDirectory = "/path/to/velocity/templates" +} +``` + Additionally, ensure that you have a compile dependency on avro, such as: ```groovy diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 1d4b177efb0..b58b3495339 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -10,8 +10,10 @@ import java.util.concurrent.Callable; import static com.commercehub.gradle.plugin.avro.Constants.AVRO_EXTENSION_NAME; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_TEMPLATE_DIR; public class AvroBasePlugin implements Plugin { + @Override public void apply(final Project project) { configureExtension(project); @@ -23,7 +25,7 @@ private static void configureExtension(final Project project) { extensionMapping.map("encoding", new Callable() { @Override public String call() throws Exception { - return Constants.UTF8_ENCONDING; + return Constants.UTF8_ENCODING; } }); extensionMapping.map("stringType", new Callable() { @@ -38,6 +40,13 @@ public String call() throws Exception { return "PUBLIC_DEPRECATED"; } }); + extensionMapping.map("templateDirectory", new Callable() { + @Override + public String call() throws Exception { + return DEFAULT_TEMPLATE_DIR; + + } + }); project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override public void execute(GenerateAvroJavaTask task) { @@ -60,6 +69,13 @@ public String call() throws Exception { return avroExtension.getFieldVisibility(); } }); + taskMapping.map("templateDirectory", new Callable() { + @Override + public String call() throws Exception { + + return avroExtension.getTemplateDirectory(); + } + }); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 903cabfee28..fea34f3d1b8 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -4,4 +4,5 @@ public interface AvroExtension { String getEncoding(); String getStringType(); String getFieldVisibility(); + String getTemplateDirectory(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 2cadfd28fa4..11f81d91710 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -1,7 +1,9 @@ package com.commercehub.gradle.plugin.avro; class Constants { - static final String UTF8_ENCONDING = "UTF-8"; + static final String UTF8_ENCODING = "UTF-8"; + + public static final String DEFAULT_TEMPLATE_DIR = "/org/apache/avro/compiler/specific/templates/java/classic/"; static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index e5551044d2d..57caf673dec 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -4,6 +4,7 @@ public class DefaultAvroExtension implements AvroExtension { private String encoding; private String stringType; private String fieldVisibility; + private String templateDirectory; @Override public String getEncoding() { @@ -29,4 +30,13 @@ public void setStringType(String stringType) { public void setFieldVisibility(String fieldVisibility) { this.fieldVisibility = fieldVisibility; } + + @Override + public String getTemplateDirectory() { return templateDirectory; } + + public void setTemplateDirectory(String templateDirectory) { + this.templateDirectory = templateDirectory; + } + + } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 1fdd64db9e4..2de16db2c10 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -13,7 +13,12 @@ import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Set; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; @@ -22,12 +27,14 @@ public class GenerateAvroJavaTask extends OutputDirTask { private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); - private String encoding = Constants.UTF8_ENCONDING; + private String encoding = Constants.UTF8_ENCODING; private String stringType; private String fieldVisibility; + private String templateDirectory; + @Input public String getEncoding() { return encoding; @@ -39,6 +46,7 @@ public void setEncoding(String encoding) { @Input public String getStringType() { + System.out.println("StringType was get: " + stringType); return stringType; } @@ -53,6 +61,13 @@ public void setFieldVisibility(String fieldVisibility) { this.fieldVisibility = fieldVisibility; } + @Input + public String getTemplateDirectory() { return templateDirectory; } + + public void setTemplateDirectory(String templateDirectory) { + this.templateDirectory = templateDirectory; + } + private GenericData.StringType parseStringType() { String stringType = getStringType(); for (GenericData.StringType type : GenericData.StringType.values()) { @@ -86,6 +101,7 @@ private SpecificCompiler.FieldVisibility parseFieldVisibility() { protected void process() { getLogger().debug("Using encoding {}", getEncoding()); getLogger().debug("Using fieldVisibility {}", getFieldVisibility()); + getLogger().debug("Using template directory '{}'", getTemplateDirectory()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -138,6 +154,7 @@ private void processProtoFile(File sourceFile) { getLogger().debug("Setting fieldVisibility to {}", parseFieldVisibility().toString()); SpecificCompiler.FieldVisibility visibility = parseFieldVisibility(); compiler.setFieldVisibility(visibility); + compiler.setTemplateDir(getTemplateDirectory()); compiler.compileToDestination(sourceFile, getOutputDir()); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); @@ -172,6 +189,8 @@ private int processSchemaFiles() { getLogger().debug("Setting fieldVisibility to {}", parseFieldVisibility().toString()); SpecificCompiler.FieldVisibility visibility = parseFieldVisibility(); compiler.setFieldVisibility(visibility); + getLogger().info("Setting templateDirectory to '{}'", getTemplateDirectory()); + compiler.setTemplateDir(getTemplateDirectory()); compiler.compileToDestination(sourceFile, getOutputDir()); types = parser.getTypes(); getLogger().info("Processed {}", path); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 1bcc357e2e8..b345317709f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -55,7 +55,7 @@ private void processIDLFile(File idlFile, ClassLoader loader) { FilenameUtils.getBaseName(idlFile.getName()) + "." + PROTOCOL_EXTENSION); try (Idl idl = new Idl(idlFile, loader)) { String protoJson = idl.CompilationUnit().toString(true); - FileUtils.writeStringToFile(protoFile, protoJson, Constants.UTF8_ENCONDING); + FileUtils.writeStringToFile(protoFile, protoJson, Constants.UTF8_ENCODING); } catch (IOException | ParseException ex) { throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); } From 150f4319b5ab3ac0c08ec5e2c949c900a8a8f2ef Mon Sep 17 00:00:00 2001 From: Ryon Day Date: Wed, 16 Sep 2015 16:14:16 -0500 Subject: [PATCH 069/479] Add support for alternate Velocity template directory. This can be used to "fake" inheritance and interface implementation with the generated Avro classes. --- CHANGES.md | 1 + README.md | 9 ++++++++ .../gradle/plugin/avro/AvroBasePlugin.java | 18 ++++++++++++++- .../gradle/plugin/avro/AvroExtension.java | 1 + .../gradle/plugin/avro/Constants.java | 4 +++- .../plugin/avro/DefaultAvroExtension.java | 10 +++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 22 +++++++++++++++++-- .../plugin/avro/GenerateAvroProtocolTask.java | 2 +- 8 files changed, 62 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index dd6a8b58310..690894e6a78 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log * Unreleased + * Add ability to set source directory for the Avro compiler's Velocity templates. * 0.5.0 * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) diff --git a/README.md b/README.md index 1648e38323d..26da1830f1d 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,15 @@ avro { } ``` +Optionally, you can also configure the source directory for the Velocity templates that the Avro compiler uses to +generate Java files. + +```groovy +avro { + templateDirectory = "/path/to/velocity/templates" +} +``` + Additionally, ensure that you have a compile dependency on avro, such as: ```groovy diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 1d4b177efb0..b58b3495339 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -10,8 +10,10 @@ import java.util.concurrent.Callable; import static com.commercehub.gradle.plugin.avro.Constants.AVRO_EXTENSION_NAME; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_TEMPLATE_DIR; public class AvroBasePlugin implements Plugin { + @Override public void apply(final Project project) { configureExtension(project); @@ -23,7 +25,7 @@ private static void configureExtension(final Project project) { extensionMapping.map("encoding", new Callable() { @Override public String call() throws Exception { - return Constants.UTF8_ENCONDING; + return Constants.UTF8_ENCODING; } }); extensionMapping.map("stringType", new Callable() { @@ -38,6 +40,13 @@ public String call() throws Exception { return "PUBLIC_DEPRECATED"; } }); + extensionMapping.map("templateDirectory", new Callable() { + @Override + public String call() throws Exception { + return DEFAULT_TEMPLATE_DIR; + + } + }); project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override public void execute(GenerateAvroJavaTask task) { @@ -60,6 +69,13 @@ public String call() throws Exception { return avroExtension.getFieldVisibility(); } }); + taskMapping.map("templateDirectory", new Callable() { + @Override + public String call() throws Exception { + + return avroExtension.getTemplateDirectory(); + } + }); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 903cabfee28..fea34f3d1b8 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -4,4 +4,5 @@ public interface AvroExtension { String getEncoding(); String getStringType(); String getFieldVisibility(); + String getTemplateDirectory(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 2cadfd28fa4..11f81d91710 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -1,7 +1,9 @@ package com.commercehub.gradle.plugin.avro; class Constants { - static final String UTF8_ENCONDING = "UTF-8"; + static final String UTF8_ENCODING = "UTF-8"; + + public static final String DEFAULT_TEMPLATE_DIR = "/org/apache/avro/compiler/specific/templates/java/classic/"; static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index e5551044d2d..57caf673dec 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -4,6 +4,7 @@ public class DefaultAvroExtension implements AvroExtension { private String encoding; private String stringType; private String fieldVisibility; + private String templateDirectory; @Override public String getEncoding() { @@ -29,4 +30,13 @@ public void setStringType(String stringType) { public void setFieldVisibility(String fieldVisibility) { this.fieldVisibility = fieldVisibility; } + + @Override + public String getTemplateDirectory() { return templateDirectory; } + + public void setTemplateDirectory(String templateDirectory) { + this.templateDirectory = templateDirectory; + } + + } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 1fdd64db9e4..9dd88ad9036 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -13,7 +13,12 @@ import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Set; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; @@ -22,12 +27,14 @@ public class GenerateAvroJavaTask extends OutputDirTask { private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); - private String encoding = Constants.UTF8_ENCONDING; + private String encoding = Constants.UTF8_ENCODING; private String stringType; private String fieldVisibility; + private String templateDirectory; + @Input public String getEncoding() { return encoding; @@ -53,6 +60,13 @@ public void setFieldVisibility(String fieldVisibility) { this.fieldVisibility = fieldVisibility; } + @Input + public String getTemplateDirectory() { return templateDirectory; } + + public void setTemplateDirectory(String templateDirectory) { + this.templateDirectory = templateDirectory; + } + private GenericData.StringType parseStringType() { String stringType = getStringType(); for (GenericData.StringType type : GenericData.StringType.values()) { @@ -86,6 +100,7 @@ private SpecificCompiler.FieldVisibility parseFieldVisibility() { protected void process() { getLogger().debug("Using encoding {}", getEncoding()); getLogger().debug("Using fieldVisibility {}", getFieldVisibility()); + getLogger().debug("Using template directory '{}'", getTemplateDirectory()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -138,6 +153,7 @@ private void processProtoFile(File sourceFile) { getLogger().debug("Setting fieldVisibility to {}", parseFieldVisibility().toString()); SpecificCompiler.FieldVisibility visibility = parseFieldVisibility(); compiler.setFieldVisibility(visibility); + compiler.setTemplateDir(getTemplateDirectory()); compiler.compileToDestination(sourceFile, getOutputDir()); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); @@ -172,6 +188,8 @@ private int processSchemaFiles() { getLogger().debug("Setting fieldVisibility to {}", parseFieldVisibility().toString()); SpecificCompiler.FieldVisibility visibility = parseFieldVisibility(); compiler.setFieldVisibility(visibility); + getLogger().info("Setting templateDirectory to '{}'", getTemplateDirectory()); + compiler.setTemplateDir(getTemplateDirectory()); compiler.compileToDestination(sourceFile, getOutputDir()); types = parser.getTypes(); getLogger().info("Processed {}", path); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 1bcc357e2e8..b345317709f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -55,7 +55,7 @@ private void processIDLFile(File idlFile, ClassLoader loader) { FilenameUtils.getBaseName(idlFile.getName()) + "." + PROTOCOL_EXTENSION); try (Idl idl = new Idl(idlFile, loader)) { String protoJson = idl.CompilationUnit().toString(true); - FileUtils.writeStringToFile(protoFile, protoJson, Constants.UTF8_ENCONDING); + FileUtils.writeStringToFile(protoFile, protoJson, Constants.UTF8_ENCODING); } catch (IOException | ParseException ex) { throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); } From dcf340e808d8606f0ca194184f5eff5376699f8e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 17 Sep 2015 12:04:12 -0400 Subject: [PATCH 070/479] Various cleanup of codebase * Consolidated default values into Constants * Standardized parsing of enum values in Enums (case-insensitive matching) * Removed duplication of compiler configuration logic in GenerateAvroJavaTask --- CHANGES.md | 2 + .../gradle/plugin/avro/AvroBasePlugin.java | 12 +- .../gradle/plugin/avro/Constants.java | 15 ++- .../plugin/avro/DefaultAvroExtension.java | 1 - .../commercehub/gradle/plugin/avro/Enums.java | 15 +++ .../plugin/avro/GenerateAvroJavaTask.java | 107 +++++++----------- .../plugin/avro/GenerateAvroProtocolTask.java | 3 + 7 files changed, 77 insertions(+), 78 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/Enums.java diff --git a/CHANGES.md b/CHANGES.md index 690894e6a78..9879ca54bb0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,8 @@ * Unreleased * Add ability to set source directory for the Avro compiler's Velocity templates. + * Matching of fieldVisibility settings is now case-insensitive. + * Removed some excessive debug logging * 0.5.0 * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index b58b3495339..a9bb1b36ad7 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -1,6 +1,5 @@ package com.commercehub.gradle.plugin.avro; -import org.apache.avro.generic.GenericData; import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; @@ -9,11 +8,9 @@ import java.util.concurrent.Callable; -import static com.commercehub.gradle.plugin.avro.Constants.AVRO_EXTENSION_NAME; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_TEMPLATE_DIR; +import static com.commercehub.gradle.plugin.avro.Constants.*; public class AvroBasePlugin implements Plugin { - @Override public void apply(final Project project) { configureExtension(project); @@ -25,19 +22,19 @@ private static void configureExtension(final Project project) { extensionMapping.map("encoding", new Callable() { @Override public String call() throws Exception { - return Constants.UTF8_ENCODING; + return DEFAULT_ENCODING; } }); extensionMapping.map("stringType", new Callable() { @Override public String call() throws Exception { - return GenericData.StringType.String.name(); + return DEFAULT_STRING_TYPE; } }); extensionMapping.map("fieldVisibility", new Callable() { @Override public String call() throws Exception { - return "PUBLIC_DEPRECATED"; + return DEFAULT_FIELD_VISIBILITY; } }); extensionMapping.map("templateDirectory", new Callable() { @@ -72,7 +69,6 @@ public String call() throws Exception { taskMapping.map("templateDirectory", new Callable() { @Override public String call() throws Exception { - return avroExtension.getTemplateDirectory(); } }); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 11f81d91710..3315cbf891f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -1,9 +1,22 @@ package com.commercehub.gradle.plugin.avro; +import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; +import org.apache.avro.generic.GenericData.StringType; + +/** + * Various constants needed by the plugin. + * + *

The default values from {@code avro-compiler} aren't exposed in a way that's easily accessible, so even default + * values that we want to match are still reproduced here.

+ */ class Constants { static final String UTF8_ENCODING = "UTF-8"; - public static final String DEFAULT_TEMPLATE_DIR = "/org/apache/avro/compiler/specific/templates/java/classic/"; + static final String DEFAULT_ENCODING = UTF8_ENCODING; + static final String DEFAULT_STRING_TYPE = StringType.String.name(); + static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); + static final String DEFAULT_TEMPLATE_DIR = System.getProperty("org.apache.avro.specific.templates", + "/org/apache/avro/compiler/specific/templates/java/classic/"); static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 57caf673dec..60f9697d3ec 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -38,5 +38,4 @@ public void setTemplateDirectory(String templateDirectory) { this.templateDirectory = templateDirectory; } - } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java b/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java new file mode 100644 index 00000000000..d43499e6a85 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java @@ -0,0 +1,15 @@ +package com.commercehub.gradle.plugin.avro; + +import java.util.Arrays; + +class Enums { + static T parseCaseInsensitive(String label, T[] values, String input) { + for (T value : values) { + if (value.name().equalsIgnoreCase(input)) { + return value; + } + } + throw new IllegalArgumentException(String.format("Invalid %s '%s'. Value values are: %s", + label, input, Arrays.asList(values))); + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 2de16db2c10..1f408df3e04 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -4,7 +4,8 @@ import org.apache.avro.Schema; import org.apache.avro.SchemaParseException; import org.apache.avro.compiler.specific.SpecificCompiler; -import org.apache.avro.generic.GenericData; +import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; +import org.apache.avro.generic.GenericData.StringType; import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; @@ -13,27 +14,24 @@ import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; -import java.util.Set; - -import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; +import java.util.*; + +import static com.commercehub.gradle.plugin.avro.Constants.*; import static java.lang.System.lineSeparator; +/** + * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and + * {@link SpecificCompiler}. + */ public class GenerateAvroJavaTask extends OutputDirTask { private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); - private String encoding = Constants.UTF8_ENCODING; - - private String stringType; - - private String fieldVisibility; - - private String templateDirectory; + private String encoding = Constants.DEFAULT_ENCODING; + private String stringType = Constants.DEFAULT_STRING_TYPE; + private String fieldVisibility = Constants.DEFAULT_FIELD_VISIBILITY; + private String templateDirectory = DEFAULT_TEMPLATE_DIR; + private transient StringType parsedStringType; + private transient FieldVisibility parsedFieldVisibility; @Input public String getEncoding() { @@ -46,7 +44,6 @@ public void setEncoding(String encoding) { @Input public String getStringType() { - System.out.println("StringType was get: " + stringType); return stringType; } @@ -68,40 +65,15 @@ public void setTemplateDirectory(String templateDirectory) { this.templateDirectory = templateDirectory; } - private GenericData.StringType parseStringType() { - String stringType = getStringType(); - for (GenericData.StringType type : GenericData.StringType.values()) { - if (type.name().equalsIgnoreCase(stringType)) { - return type; - } - } - throw new IllegalArgumentException(String.format("Invalid stringType '%s'. Valid values are: %s", stringType, - Arrays.asList(GenericData.StringType.values()))); - - } - - private SpecificCompiler.FieldVisibility parseFieldVisibility() { - getLogger().debug("Parsing fieldVisibility {}", getFieldVisibility()); - SpecificCompiler.FieldVisibility viz = null; - - if(getFieldVisibility() == null) { - return SpecificCompiler.FieldVisibility.PUBLIC_DEPRECATED; - } - - try { - viz = SpecificCompiler.FieldVisibility.valueOf(getFieldVisibility()); - } catch(Exception ex) { - throw new IllegalArgumentException(String.format("Invalid fieldVisibility '%s'.", getFieldVisibility())); - } - - return viz; - } - @TaskAction protected void process() { + parsedStringType = Enums.parseCaseInsensitive("stringType", StringType.values(), getStringType()); + parsedFieldVisibility = + Enums.parseCaseInsensitive("fieldVisibility", FieldVisibility.values(), getFieldVisibility()); getLogger().debug("Using encoding {}", getEncoding()); - getLogger().debug("Using fieldVisibility {}", getFieldVisibility()); - getLogger().debug("Using template directory '{}'", getTemplateDirectory()); + getLogger().debug("Using stringType {}", parsedStringType.name()); + getLogger().debug("Using fieldVisibility {}", parsedFieldVisibility.name()); + getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -147,15 +119,7 @@ private int processProtoFiles() { private void processProtoFile(File sourceFile) { getLogger().info("Processing {}", sourceFile); try { - Protocol protocol = Protocol.parse(sourceFile); - SpecificCompiler compiler = new SpecificCompiler(protocol); - compiler.setStringType(parseStringType()); - compiler.setOutputCharacterEncoding(getEncoding()); - getLogger().debug("Setting fieldVisibility to {}", parseFieldVisibility().toString()); - SpecificCompiler.FieldVisibility visibility = parseFieldVisibility(); - compiler.setFieldVisibility(visibility); - compiler.setTemplateDir(getTemplateDirectory()); - compiler.compileToDestination(sourceFile, getOutputDir()); + compile(Protocol.parse(sourceFile), sourceFile); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); } @@ -182,16 +146,7 @@ private int processSchemaFiles() { try { Schema.Parser parser = new Schema.Parser(); parser.addTypes(types); - Schema schema = parser.parse(sourceFile); - SpecificCompiler compiler = new SpecificCompiler(schema); - compiler.setStringType(parseStringType()); - compiler.setOutputCharacterEncoding(getEncoding()); - getLogger().debug("Setting fieldVisibility to {}", parseFieldVisibility().toString()); - SpecificCompiler.FieldVisibility visibility = parseFieldVisibility(); - compiler.setFieldVisibility(visibility); - getLogger().info("Setting templateDirectory to '{}'", getTemplateDirectory()); - compiler.setTemplateDir(getTemplateDirectory()); - compiler.compileToDestination(sourceFile, getOutputDir()); + compile(parser.parse(sourceFile), sourceFile); types = parser.getTypes(); getLogger().info("Processed {}", path); processedThisPass++; @@ -224,4 +179,20 @@ private int processSchemaFiles() { } return processedTotal; } + + private void compile(Protocol protocol, File sourceFile) throws IOException { + compile(new SpecificCompiler(protocol), sourceFile); + } + + private void compile(Schema schema, File sourceFile) throws IOException { + compile(new SpecificCompiler(schema), sourceFile); + } + + private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { + compiler.setOutputCharacterEncoding(getEncoding()); + compiler.setStringType(parsedStringType); + compiler.setFieldVisibility(parsedFieldVisibility); + compiler.setTemplateDir(getTemplateDirectory()); + compiler.compileToDestination(sourceFile, getOutputDir()); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index b345317709f..1792670467c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -23,6 +23,9 @@ import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; +/** + * Task to convert Avro IDL files into Avro protocol files using {@link Idl}. + */ public class GenerateAvroProtocolTask extends OutputDirTask { @TaskAction protected void process() { From d67f249dcda52da7e959068b7eea9e9c5e2d7381 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 17 Sep 2015 15:57:40 -0400 Subject: [PATCH 071/479] Additional test coverage for plugin configuration options --- README.md | 7 +- .../avro/AvroPluginFunctionalSpec.groovy | 12 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 8 +- .../plugin/avro/OptionsFunctionalSpec.groovy | 136 ++++++++++ .../commercehub/gradle/plugin/avro/record.vm | 249 ++++++++++++++++++ 5 files changed, 399 insertions(+), 13 deletions(-) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/record.vm diff --git a/README.md b/README.md index 26da1830f1d..373be2a4438 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Add the following to your `build.gradle` file. Substitute the desired version b ```groovy // Gradle 2.1 and later plugins { - id "com.commercehub.gradle.plugin.avro" version "VERSION" + id "com.commercehub.gradle.plugin.avro" version "VERSION" } // Earlier versions of Gradle @@ -42,7 +42,7 @@ avro { } ``` -Optionally, you can also configure the output character encoding. +Optionally, you can also configure the output character encoding (default `UTF-8`). ```groovy avro { @@ -50,7 +50,8 @@ avro { } ``` -Optionally, you can also configure the visibility of generated fields. +Optionally, you can also configure the visibility of generated fields to `PRIVATE`, `PUBLIC_DEPRECATED` (the default) +or `PUBLIC`. ```groovy avro { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 8ef76b7458e..61e87bd7b76 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -13,7 +13,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("user.avsc", avroDir) when: - def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + def result = runBuild() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -29,7 +29,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("mail.avpr", avroDir) when: - def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + def result = runBuild() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -43,7 +43,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("interop.avdl", avroDir) when: - def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + def result = runBuild() then: result.task(":generateAvroProtocol").outcome == SUCCESS @@ -61,7 +61,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("user.avsc", avroSubDir) when: - def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + def result = runBuild() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -77,7 +77,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("mail.avpr", avroSubDir) when: - def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + def result = runBuild() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -91,7 +91,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("interop.avdl", avroSubDir) when: - def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("build").build() + def result = runBuild() then: result.task(":generateAvroProtocol").outcome == SUCCESS diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 8b9625a8506..e25399fd4d7 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -55,11 +55,11 @@ abstract class FunctionalSpec extends Specification { return testProjectDir.root.toPath().resolve(path) } - protected BuildResult runBuild() { - return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("--info", "build").build() + protected BuildResult runBuild(String... args = ["build"]) { + return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments(args).build() } - protected BuildResult buildAndFail() { - return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments("--info", "build").buildAndFail() + protected BuildResult buildAndFail(String... args = ["build"]) { + return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments(args).buildAndFail() } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy new file mode 100644 index 00000000000..a25502f8f30 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -0,0 +1,136 @@ +package com.commercehub.gradle.plugin.avro + +import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility +import org.apache.avro.generic.GenericData.StringType +import spock.lang.Unroll + +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENCODING +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class OptionsFunctionalSpec extends FunctionalSpec { + def "works with default options"() { + given: + copyResource("user.avsc", avroDir) + + when: + def result = runBuild("generateAvroJava") + + then: "the task succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + + and: "the encoding is the default" + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + + and: "the stringType is string" + content.contains("public java.lang.String getName()") + + and: "the fieldVisibility is PUBLIC_DEPRECATED" + content.contains("@Deprecated public java.lang.String name;") + + and: "the default template is used" + !content.contains("Custom template") + } + + def "supports configuring encoding"() { + given: + def encoding = "UTF-16" + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | encoding = "${encoding}" + |} + |""".stripMargin() + + when: + def result = runBuild("generateAvroJava") + + then: "the task succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + + and: "the specified encoding is used" + projectPath("build/generated-main-avro-java/example/avro/User.java").getText(encoding) + } + + @Unroll + def "supports configuring stringType to #stringType"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | stringType = "${stringType.name()}" + |} + |""".stripMargin() + + when: + def result = runBuild("generateAvroJava") + + then: "the task succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + + and: "the specified stringType is used" + content.contains(expectedContent) + + where: + stringType | expectedContent + StringType.String | "public java.lang.String getName()" + StringType.CharSequence | "public java.lang.CharSequence getName()" + StringType.Utf8 | "public org.apache.avro.util.Utf8 getName()" + } + + @Unroll + def "supports configuring fieldVisibility to #fieldVisibility"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | fieldVisibility = "${fieldVisibility.name()}" + |} + |""".stripMargin() + + when: + def result = runBuild("generateAvroJava") + + then: "the task succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + + and: "the specified fieldVisibility is used" + content.contains(expectedContent) + + where: + fieldVisibility | expectedContent + FieldVisibility.PRIVATE | "private java.lang.String name;" + FieldVisibility.PUBLIC | "public java.lang.String name;" + FieldVisibility.PUBLIC_DEPRECATED | "@Deprecated public java.lang.String name;" + } + + def "supports configuring templateDirectory"() { + given: + def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") + copyResource("user.avsc", avroDir) + copyResource("record.vm", templatesDir) + buildFile << """ + |buildscript { + | dependencies { + | classpath files(["${templatesDir.parentFile.absolutePath}"]) + | } + |} + |avro { + | templateDirectory = "/alternateTemplates/" + |} + |""".stripMargin() + + when: + def result = runBuild("generateAvroJava") + + then: "the task succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + + and: "the specified templates are used" + content.contains("Custom template") + } + + // TODO: invalid value handling +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm b/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm new file mode 100644 index 00000000000..ff93a4adca7 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm @@ -0,0 +1,249 @@ +## +## Licensed to the Apache Software Foundation (ASF) under one +## or more contributor license agreements. See the NOTICE file +## distributed with this work for additional information +## regarding copyright ownership. The ASF licenses this file +## to you 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. +## +#if ($schema.getNamespace()) +package $schema.getNamespace(); +#end +@SuppressWarnings("all") +#if ($schema.getDoc()) +/** $schema.getDoc() */ +#end +#foreach ($annotation in $this.javaAnnotations($schema)) +@$annotation +#end +@org.apache.avro.specific.AvroGenerated +public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends org.apache.avro.specific.SpecificExceptionBase#else extends org.apache.avro.specific.SpecificRecordBase#end implements org.apache.avro.specific.SpecificRecord { + // Custom template + public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse(${this.javaSplit($schema.toString())}); + public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; } +#foreach ($field in $schema.getFields()) +#if ($field.doc()) + /** $field.doc() */ +#end +#foreach ($annotation in $this.javaAnnotations($field)) + @$annotation +#end + #if (${this.deprecatedFields()})@Deprecated#end #if (${this.publicFields()})public#elseif (${this.privateFields()})private#end ${this.javaUnbox($field.schema())} ${this.mangle($field.name(), $schema.isError())}; +#end +#if ($schema.isError()) + + public ${this.mangle($schema.getName())}() { + super(); + } + + public ${this.mangle($schema.getName())}(Object value) { + super(value); + } + + public ${this.mangle($schema.getName())}(Throwable cause) { + super(cause); + } + + public ${this.mangle($schema.getName())}(Object value, Throwable cause) { + super(value, cause); + } + +#else +#if ($schema.getFields().size() > 0) + + /** + * Default constructor. Note that this does not initialize fields + * to their default values from the schema. If that is desired then + * one should use newBuilder(). + */ + public ${this.mangle($schema.getName())}() {} + + /** + * All-args constructor. + */ + public ${this.mangle($schema.getName())}(#foreach($field in $schema.getFields())${this.javaType($field.schema())} ${this.mangle($field.name())}#if($velocityCount < $schema.getFields().size()), #end#end) { +#foreach ($field in $schema.getFields()) + this.${this.mangle($field.name())} = ${this.mangle($field.name())}; +#end + } +#end + +#end + public org.apache.avro.Schema getSchema() { return SCHEMA$; } + // Used by DatumWriter. Applications should not call. + public java.lang.Object get(int field$) { + switch (field$) { +#set ($i = 0) +#foreach ($field in $schema.getFields()) + case $i: return ${this.mangle($field.name(), $schema.isError())}; +#set ($i = $i + 1) +#end + default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + } + } + // Used by DatumReader. Applications should not call. + @SuppressWarnings(value="unchecked") + public void put(int field$, java.lang.Object value$) { + switch (field$) { +#set ($i = 0) +#foreach ($field in $schema.getFields()) + case $i: ${this.mangle($field.name(), $schema.isError())} = (${this.javaType($field.schema())})value$; break; +#set ($i = $i + 1) +#end + default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + } + } + +#foreach ($field in $schema.getFields()) + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * $field.doc()#end + */ + public ${this.javaType($field.schema())} ${this.generateGetMethod($schema, $field)}() { + return ${this.mangle($field.name(), $schema.isError())}; + } + +#if ($this.createSetters) + /** + * Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * $field.doc()#end + * @param value the value to set. + */ + public void ${this.generateSetMethod($schema, $field)}(${this.javaType($field.schema())} value) { + this.${this.mangle($field.name(), $schema.isError())} = value; + } +#end + +#end + /** Creates a new ${this.mangle($schema.getName())} RecordBuilder */ + public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder() { + return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(); + } + + /** Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing Builder */ + public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder other) { + return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other); + } + + /** Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing $this.mangle($schema.getName()) instance */ + public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())} other) { + return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other); + } + + /** + * RecordBuilder for ${this.mangle($schema.getName())} instances. + */ + public static class Builder extends#if ($schema.isError()) org.apache.avro.specific.SpecificErrorBuilderBase<${this.mangle($schema.getName())}>#else org.apache.avro.specific.SpecificRecordBuilderBase<${this.mangle($schema.getName())}>#end + + implements#if ($schema.isError()) org.apache.avro.data.ErrorBuilder<${this.mangle($schema.getName())}>#else org.apache.avro.data.RecordBuilder<${this.mangle($schema.getName())}>#end { + +#foreach ($field in $schema.getFields()) + private ${this.javaUnbox($field.schema())} ${this.mangle($field.name(), $schema.isError())}; +#end + + /** Creates a new Builder */ + private Builder() { + super(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.SCHEMA$); + } + + /** Creates a Builder by copying an existing Builder */ + private Builder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder other) { + super(other); +#foreach ($field in $schema.getFields()) + if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) { + this.${this.mangle($field.name(), $schema.isError())} = data().deepCopy(fields()[$field.pos()].schema(), other.${this.mangle($field.name(), $schema.isError())}); + fieldSetFlags()[$field.pos()] = true; + } +#end + } + + /** Creates a Builder by copying an existing $this.mangle($schema.getName()) instance */ + private Builder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())} other) { + #if ($schema.isError())super(other)#else + super(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.SCHEMA$)#end; +#foreach ($field in $schema.getFields()) + if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) { + this.${this.mangle($field.name(), $schema.isError())} = data().deepCopy(fields()[$field.pos()].schema(), other.${this.mangle($field.name(), $schema.isError())}); + fieldSetFlags()[$field.pos()] = true; + } +#end + } +#if ($schema.isError()) + + @Override + public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder setValue(Object value) { + super.setValue(value); + return this; + } + + @Override + public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder clearValue() { + super.clearValue(); + return this; + } + + @Override + public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder setCause(Throwable cause) { + super.setCause(cause); + return this; + } + + @Override + public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder clearCause() { + super.clearCause(); + return this; + } +#end + +#foreach ($field in $schema.getFields()) + /** Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field */ + public ${this.javaType($field.schema())} ${this.generateGetMethod($schema, $field)}() { + return ${this.mangle($field.name(), $schema.isError())}; + } + + /** Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field */ + public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema())} value) { + validate(fields()[$field.pos()], value); + this.${this.mangle($field.name(), $schema.isError())} = value; + fieldSetFlags()[$field.pos()] = true; + return this; + } + + /** Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has been set */ + public boolean ${this.generateHasMethod($schema, $field)}() { + return fieldSetFlags()[$field.pos()]; + } + + /** Clears the value of the '${this.mangle($field.name(), $schema.isError())}' field */ + public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateClearMethod($schema, $field)}() { +#if (${this.isUnboxedJavaTypeNullable($field.schema())}) + ${this.mangle($field.name(), $schema.isError())} = null; +#end + fieldSetFlags()[$field.pos()] = false; + return this; + } + +#end + @Override + public ${this.mangle($schema.getName())} build() { + try { + ${this.mangle($schema.getName())} record = new ${this.mangle($schema.getName())}(#if ($schema.isError())getValue(), getCause()#end); +#foreach ($field in $schema.getFields()) + record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : (${this.javaType($field.schema())}) defaultValue(fields()[$field.pos()]); +#end + return record; + } catch (Exception e) { + throw new org.apache.avro.AvroRuntimeException(e); + } + } + } +} From 5bfe091137f5b9b282e2ecd4a2e7d95b6ce92655 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 17 Sep 2015 16:21:42 -0400 Subject: [PATCH 072/479] Add tests for invalid option value scenarios --- .../avro/AvroPluginFunctionalSpec.groovy | 14 ++-- .../avro/EnumHandlingFunctionalSpec.groovy | 8 +-- .../gradle/plugin/avro/FunctionalSpec.groovy | 4 +- .../plugin/avro/OptionsFunctionalSpec.groovy | 68 ++++++++++++++----- 4 files changed, 65 insertions(+), 29 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 61e87bd7b76..2ee5f56e44d 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -13,7 +13,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("user.avsc", avroDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -29,7 +29,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("mail.avpr", avroDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -43,7 +43,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("interop.avdl", avroDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroProtocol").outcome == SUCCESS @@ -61,7 +61,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("user.avsc", avroSubDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -77,7 +77,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("mail.avpr", avroSubDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -91,7 +91,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("interop.avdl", avroSubDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroProtocol").outcome == SUCCESS @@ -109,7 +109,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { copyResource("enumMalformed.avsc", avroDir) when: - def result = buildAndFail() + def result = runAndFail() then: result.task(":generateAvroJava").outcome == FAILED diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index 737ffe29257..0867ec46cd4 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -10,7 +10,7 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { copyResource("enumSimple.avsc", avroDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -23,7 +23,7 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { copyResource("enumField.avsc", avroDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -37,7 +37,7 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { copyResource("enumUnion.avsc", avroDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroJava").outcome == SUCCESS @@ -52,7 +52,7 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { copyResource("enumUseSimple.avsc", avroDir) when: - def result = runBuild() + def result = run() then: result.task(":generateAvroJava").outcome == SUCCESS diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index e25399fd4d7..c9d993812db 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -55,11 +55,11 @@ abstract class FunctionalSpec extends Specification { return testProjectDir.root.toPath().resolve(path) } - protected BuildResult runBuild(String... args = ["build"]) { + protected BuildResult run(String... args = ["build"]) { return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments(args).build() } - protected BuildResult buildAndFail(String... args = ["build"]) { + protected BuildResult runAndFail(String... args = ["build"]) { return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments(args).buildAndFail() } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index a25502f8f30..979f4f49963 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -5,6 +5,7 @@ import org.apache.avro.generic.GenericData.StringType import spock.lang.Unroll import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENCODING +import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class OptionsFunctionalSpec extends FunctionalSpec { @@ -13,7 +14,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { copyResource("user.avsc", avroDir) when: - def result = runBuild("generateAvroJava") + def result = run("generateAvroJava") then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS @@ -42,7 +43,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { |""".stripMargin() when: - def result = runBuild("generateAvroJava") + def result = run("generateAvroJava") then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS @@ -57,12 +58,12 @@ class OptionsFunctionalSpec extends FunctionalSpec { copyResource("user.avsc", avroDir) buildFile << """ |avro { - | stringType = "${stringType.name()}" + | stringType = "${stringType}" |} |""".stripMargin() when: - def result = runBuild("generateAvroJava") + def result = run("generateAvroJava") then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS @@ -72,10 +73,12 @@ class OptionsFunctionalSpec extends FunctionalSpec { content.contains(expectedContent) where: - stringType | expectedContent - StringType.String | "public java.lang.String getName()" - StringType.CharSequence | "public java.lang.CharSequence getName()" - StringType.Utf8 | "public org.apache.avro.util.Utf8 getName()" + stringType | expectedContent + StringType.String.name() | "public java.lang.String getName()" + StringType.CharSequence.name() | "public java.lang.CharSequence getName()" + StringType.Utf8.name() | "public org.apache.avro.util.Utf8 getName()" + StringType.Utf8.name().toUpperCase() | "public org.apache.avro.util.Utf8 getName()" + StringType.Utf8.name().toLowerCase() | "public org.apache.avro.util.Utf8 getName()" } @Unroll @@ -84,12 +87,12 @@ class OptionsFunctionalSpec extends FunctionalSpec { copyResource("user.avsc", avroDir) buildFile << """ |avro { - | fieldVisibility = "${fieldVisibility.name()}" + | fieldVisibility = "${fieldVisibility}" |} |""".stripMargin() when: - def result = runBuild("generateAvroJava") + def result = run("generateAvroJava") then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS @@ -99,10 +102,11 @@ class OptionsFunctionalSpec extends FunctionalSpec { content.contains(expectedContent) where: - fieldVisibility | expectedContent - FieldVisibility.PRIVATE | "private java.lang.String name;" - FieldVisibility.PUBLIC | "public java.lang.String name;" - FieldVisibility.PUBLIC_DEPRECATED | "@Deprecated public java.lang.String name;" + fieldVisibility | expectedContent + FieldVisibility.PRIVATE.name().toLowerCase() | "private java.lang.String name;" + FieldVisibility.PRIVATE.name() | "private java.lang.String name;" + FieldVisibility.PUBLIC.name() | "public java.lang.String name;" + FieldVisibility.PUBLIC_DEPRECATED.name() | "@Deprecated public java.lang.String name;" } def "supports configuring templateDirectory"() { @@ -122,7 +126,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { |""".stripMargin() when: - def result = runBuild("generateAvroJava") + def result = run("generateAvroJava") then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS @@ -132,5 +136,37 @@ class OptionsFunctionalSpec extends FunctionalSpec { content.contains("Custom template") } - // TODO: invalid value handling + def "rejects unsupported stringType values"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | stringType = "badValue" + |} + |""".stripMargin() + + when: + def result = runAndFail("generateAvroJava") + + then: + result.task(":generateAvroJava").outcome == FAILED + result.standardError.contains("Invalid stringType 'badValue'. Value values are: [CharSequence, String, Utf8]") + } + + def "rejects unsupported fieldVisibility values"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | fieldVisibility = "badValue" + |} + |""".stripMargin() + + when: + def result = runAndFail("generateAvroJava") + + then: + result.task(":generateAvroJava").outcome == FAILED + result.standardError.contains("Invalid fieldVisibility 'badValue'. Value values are: [PUBLIC, PUBLIC_DEPRECATED, PRIVATE]") + } } From cf73979a8ac396d14b9e5770fce35a45052d91c4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 18 Sep 2015 10:36:02 -0400 Subject: [PATCH 073/479] Upgrade gradle wrapper, add checkstyle/codenarc, fix some style issues --- .editorconfig | 10 + CHANGES.md | 2 + README.md | 2 +- build.gradle | 35 ++ config/checkstyle/checkstyle.xml | 107 ++++++ config/codenarc/codenarc.groovy | 327 ++++++++++++++++++ gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 53638 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 6 +- .../gradle/plugin/avro/AvroBasePlugin.java | 3 +- .../plugin/avro/DefaultAvroExtension.java | 8 +- .../plugin/avro/GenerateAvroJavaTask.java | 14 +- .../plugin/avro/GenerateAvroProtocolTask.java | 4 +- .../gradle/plugin/avro/SetBuilder.java | 7 +- .../avro/AvroPluginFunctionalSpec.groovy | 5 +- .../gradle/plugin/avro/AvroPluginSpec.groovy | 4 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 6 +- 17 files changed, 515 insertions(+), 29 deletions(-) create mode 100644 .editorconfig create mode 100644 config/checkstyle/checkstyle.xml create mode 100644 config/codenarc/codenarc.groovy diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..339679857ad --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +# EditorConfig is awesome: http://EditorConfig.org + +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 4 diff --git a/CHANGES.md b/CHANGES.md index 9879ca54bb0..240a2cfa410 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,8 @@ * Add ability to set source directory for the Avro compiler's Velocity templates. * Matching of fieldVisibility settings is now case-insensitive. * Removed some excessive debug logging + * Built against Gradle 2.7 + * Added Checkstyle and Codenarc to build * 0.5.0 * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) diff --git a/README.md b/README.md index 373be2a4438..8ab351a0cf6 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Gradle 2.6; other versions may be compatible +* Currently tested against Gradle 2.7; other versions may be compatible * Currently tested against Avro 1.7.7; other versions may be compatible * Java 7 or higher required diff --git a/build.gradle b/build.gradle index 2b8d4068576..3fa938a6b52 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,7 @@ plugins { id "groovy" + id "checkstyle" + id "codenarc" id "idea" id "com.gradle.plugin-publish" version "0.9.1" } @@ -44,6 +46,22 @@ pluginBundle { idea { project { vcs = "Git" + ipr { + withXml { provider -> + def node = provider.asNode() + node.append(new XmlParser().parseText(""" + + + + """.stripIndent())) + } + } } } @@ -64,3 +82,20 @@ task createClasspathManifest { dependencies { testRuntime files(createClasspathManifest) } + +checkstyle { + toolVersion = "6.10.1" +} +// Nasty workaround for https://issues.gradle.org/browse/GRADLE-2888 +def checkstyleWarningsFile = "build/reports/checkstyle/main.xml" +checkstyleMain << { + File warningsFile = file(checkstyleWarningsFile) + if (warningsFile.exists() && warningsFile.text.contains(" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/codenarc/codenarc.groovy b/config/codenarc/codenarc.groovy new file mode 100644 index 00000000000..69e141ffb8a --- /dev/null +++ b/config/codenarc/codenarc.groovy @@ -0,0 +1,327 @@ +ruleset { + + // rulesets/basic.xml + AssertWithinFinallyBlock + AssignmentInConditional + BigDecimalInstantiation + BitwiseOperatorInConditional + BooleanGetBoolean + BrokenNullCheck + BrokenOddnessCheck + ClassForName + ComparisonOfTwoConstants + ComparisonWithSelf + ConstantAssertExpression + ConstantIfExpression + ConstantTernaryExpression + DeadCode + DoubleNegative + DuplicateCaseStatement + DuplicateMapKey + DuplicateSetValue + EmptyCatchBlock + EmptyClass + EmptyElseBlock + EmptyFinallyBlock + EmptyForStatement + EmptyIfStatement + EmptyInstanceInitializer + EmptyMethod + EmptyStaticInitializer + EmptySwitchStatement + EmptySynchronizedStatement + EmptyTryBlock + EmptyWhileStatement + EqualsAndHashCode + EqualsOverloaded + ExplicitGarbageCollection + ForLoopShouldBeWhileLoop + HardCodedWindowsFileSeparator + HardCodedWindowsRootDirectory + IntegerGetInteger + RandomDoubleCoercedToZero + RemoveAllOnSelf + ReturnFromFinallyBlock + ThrowExceptionFromFinallyBlock + + // rulesets/braces.xml + ElseBlockBraces + ForStatementBraces + IfStatementBraces + WhileStatementBraces + + // rulesets/concurrency.xml + BusyWait + DoubleCheckedLocking + InconsistentPropertyLocking + InconsistentPropertySynchronization + NestedSynchronization + StaticCalendarField + StaticConnection + StaticDateFormatField + StaticMatcherField + StaticSimpleDateFormatField + SynchronizedMethod + SynchronizedOnBoxedPrimitive + SynchronizedOnGetClass + SynchronizedOnReentrantLock + SynchronizedOnString + SynchronizedOnThis + SynchronizedReadObjectMethod + SystemRunFinalizersOnExit + ThisReferenceEscapesConstructor + ThreadGroup + ThreadLocalNotStaticFinal + ThreadYield + UseOfNotifyMethod + VolatileArrayField + VolatileLongOrDoubleField + WaitOutsideOfWhileLoop + + // rulesets/convention.xml + ConfusingTernary + CouldBeElvis + HashtableIsObsolete + IfStatementCouldBeTernary + InvertedIfElse + LongLiteralWithLowerCaseL + ParameterReassignment + TernaryCouldBeElvis + VectorIsObsolete + + // rulesets/design.xml + AbstractClassWithPublicConstructor + BooleanMethodReturnsNull + BuilderMethodWithSideEffects + CloneableWithoutClone + CloseWithoutCloseable + CompareToWithoutComparable + ConstantsOnlyInterface + EmptyMethodInAbstractClass + FinalClassWithProtectedMember + ImplementationAsType + LocaleSetDefault + PrivateFieldCouldBeFinal + PublicInstanceField + ReturnsNullInsteadOfEmptyArray + ReturnsNullInsteadOfEmptyCollection + SimpleDateFormatMissingLocale + StatelessSingleton + + // rulesets/exceptions.xml + CatchArrayIndexOutOfBoundsException + CatchError + CatchException + CatchIllegalMonitorStateException + CatchIndexOutOfBoundsException + CatchNullPointerException + CatchRuntimeException + CatchThrowable + ConfusingClassNamedException + ExceptionExtendsError + ExceptionNotThrown + MissingNewInThrowStatement + ReturnNullFromCatchBlock + SwallowThreadDeath + ThrowError + ThrowException + ThrowNullPointerException + ThrowRuntimeException + ThrowThrowable + + // rulesets/formatting.xml + BracesForClass + BracesForForLoop + BracesForIfElse + BracesForMethod + BracesForTryCatchFinally + ClosureStatementOnOpeningLineOfMultipleLineClosure + LineLength (length: 140) + SpaceAfterCatch + SpaceAfterClosingBrace + SpaceAfterComma + SpaceAfterFor + SpaceAfterIf + SpaceAfterOpeningBrace + SpaceAfterSemicolon + SpaceAfterSwitch + SpaceAfterWhile + SpaceAroundClosureArrow + SpaceAroundMapEntryColon (characterAfterColonRegex: /\s/) + SpaceAroundOperator + SpaceBeforeClosingBrace + SpaceBeforeOpeningBrace + + // rulesets/generic.xml + IllegalClassMember + IllegalClassReference + IllegalPackageReference + IllegalRegex + IllegalString + RequiredRegex + RequiredString + StatelessClass + + // rulesets/groovyism.xml + AssignCollectionSort + AssignCollectionUnique + ClosureAsLastMethodParameter + CollectAllIsDeprecated + ConfusingMultipleReturns + ExplicitArrayListInstantiation + ExplicitCallToAndMethod + ExplicitCallToCompareToMethod + ExplicitCallToDivMethod + ExplicitCallToEqualsMethod + ExplicitCallToGetAtMethod + ExplicitCallToLeftShiftMethod + ExplicitCallToMinusMethod + ExplicitCallToModMethod + ExplicitCallToMultiplyMethod + ExplicitCallToOrMethod + ExplicitCallToPlusMethod + ExplicitCallToPowerMethod + ExplicitCallToRightShiftMethod + ExplicitCallToXorMethod + ExplicitHashMapInstantiation + ExplicitHashSetInstantiation + ExplicitLinkedHashMapInstantiation + ExplicitLinkedListInstantiation + ExplicitStackInstantiation + ExplicitTreeSetInstantiation + GStringAsMapKey + GStringExpressionWithinString + GetterMethodCouldBeProperty + GroovyLangImmutable + UseCollectMany + UseCollectNested + + // rulesets/imports.xml + DuplicateImport + ImportFromSamePackage + ImportFromSunPackages + MisorderedStaticImports (comesBefore: false) + UnnecessaryGroovyImport + UnusedImport + + // rulesets/junit.xml + ChainedTest + CoupledTestCase + JUnitAssertAlwaysFails + JUnitAssertAlwaysSucceeds + JUnitFailWithoutMessage + JUnitLostTest + JUnitPublicField + JUnitPublicNonTestMethod + JUnitSetUpCallsSuper + JUnitStyleAssertions + JUnitTearDownCallsSuper + JUnitTestMethodWithoutAssert + JUnitUnnecessarySetUp + JUnitUnnecessaryTearDown + JUnitUnnecessaryThrowsException + SpockIgnoreRestUsed + UnnecessaryFail + UseAssertEqualsInsteadOfAssertTrue + UseAssertFalseInsteadOfNegation + UseAssertNullInsteadOfAssertEquals + UseAssertSameInsteadOfAssertTrue + UseAssertTrueInsteadOfAssertEquals + UseAssertTrueInsteadOfNegation + + // rulesets/logging.xml + LoggerForDifferentClass + LoggerWithWrongModifiers + LoggingSwallowsStacktrace + MultipleLoggers + PrintStackTrace + Println + SystemErrPrint + SystemOutPrint + + // rulesets/naming.xml + AbstractClassName + ClassName + ClassNameSameAsFilename + ConfusingMethodName + FieldName + InterfaceName + ObjectOverrideMisspelledMethodName + PackageName + ParameterName + PropertyName + VariableName + + // rulesets/security.xml + FileCreateTempFile + InsecureRandom + NonFinalPublicField + NonFinalSubclassOfSensitiveInterface + ObjectFinalize + PublicFinalizeMethod + SystemExit + UnsafeArrayDeclaration + + // rulesets/serialization.xml + EnumCustomSerializationIgnored + SerialPersistentFields + SerialVersionUID + SerializableClassMustDefineSerialVersionUID + + // rulesets/size.xml + ClassSize + MethodCount + MethodSize + NestedBlockDepth + + // rulesets/unnecessary.xml + AddEmptyString + ConsecutiveLiteralAppends + ConsecutiveStringConcatenation + UnnecessaryBigDecimalInstantiation + UnnecessaryBigIntegerInstantiation + UnnecessaryBooleanExpression + UnnecessaryBooleanInstantiation + UnnecessaryCallForLastElement + UnnecessaryCallToSubstring + UnnecessaryCatchBlock + UnnecessaryCollectCall + UnnecessaryCollectionCall + UnnecessaryConstructor + UnnecessaryDefInFieldDeclaration + UnnecessaryDefInMethodDeclaration + UnnecessaryDefInVariableDeclaration + UnnecessaryDotClass + UnnecessaryDoubleInstantiation + UnnecessaryElseStatement + UnnecessaryFinalOnPrivateMethod + UnnecessaryFloatInstantiation + UnnecessaryGetter + UnnecessaryIfStatement + UnnecessaryInstanceOfCheck + UnnecessaryInstantiationToGetClass + UnnecessaryIntegerInstantiation + UnnecessaryLongInstantiation + UnnecessaryModOne + UnnecessaryNullCheck + UnnecessaryNullCheckBeforeInstanceOf + UnnecessaryObjectReferences + UnnecessaryOverridingMethod + UnnecessaryPackageReference + UnnecessaryParenthesesForMethodCallWithClosure + UnnecessaryPublicModifier + UnnecessarySelfAssignment + UnnecessarySemicolon + UnnecessaryStringInstantiation + UnnecessaryTernaryExpression + UnnecessaryTransientModifier + + // rulesets/unused.xml + UnusedArray + UnusedMethodParameter + UnusedObject + UnusedPrivateField + UnusedPrivateMethod + UnusedPrivateMethodParameter + UnusedVariable +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index fd7e590e5154e82211909581e71018372134fb27..e8c6bf7bb47dff6b81c2cf7a349eb7e912c9fbe2 100644 GIT binary patch delta 8143 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 a!dx4O5sX6+>;HLW1*YDjn0Eh}=l=nlz$2Le delta 8095 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/dev/null` diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index a9bb1b36ad7..5c11abba32b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -79,7 +79,8 @@ public String call() throws Exception { private static ConventionMapping conventionMapping(Object conventionAware) { // TODO: try other alternatives to convention mapping // Convention mapping is an internal API. - // Other options here: http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api + // Other options here: + // http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api return ((IConventionAware) conventionAware).getConventionMapping(); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 60f9697d3ec..5da5ffa1acd 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -25,14 +25,18 @@ public void setStringType(String stringType) { } @Override - public String getFieldVisibility() { return fieldVisibility; } + public String getFieldVisibility() { + return fieldVisibility; + } public void setFieldVisibility(String fieldVisibility) { this.fieldVisibility = fieldVisibility; } @Override - public String getTemplateDirectory() { return templateDirectory; } + public String getTemplateDirectory() { + return templateDirectory; + } public void setTemplateDirectory(String templateDirectory) { this.templateDirectory = templateDirectory; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 1f408df3e04..d45a47b1b1a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -1,5 +1,6 @@ package com.commercehub.gradle.plugin.avro; +import com.google.common.collect.ImmutableSet; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.apache.avro.SchemaParseException; @@ -24,7 +25,7 @@ * {@link SpecificCompiler}. */ public class GenerateAvroJavaTask extends OutputDirTask { - private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); + private static Set SUPPORTED_EXTENSIONS = ImmutableSet.of(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); private String encoding = Constants.DEFAULT_ENCODING; private String stringType = Constants.DEFAULT_STRING_TYPE; @@ -52,14 +53,18 @@ public void setStringType(String stringType) { } @Input - public String getFieldVisibility() { return fieldVisibility; } + public String getFieldVisibility() { + return fieldVisibility; + } public void setFieldVisibility(String fieldVisibility) { this.fieldVisibility = fieldVisibility; } @Input - public String getTemplateDirectory() { return templateDirectory; } + public String getTemplateDirectory() { + return templateDirectory; + } public void setTemplateDirectory(String templateDirectory) { this.templateDirectory = templateDirectory; @@ -161,7 +166,8 @@ private int processSchemaFiles() { throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } } catch (NullPointerException ex) { - getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency); will try again later", path); + getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency);" + + " will try again later", path); nextPass.add(sourceFile); errors.put(path, ex.getMessage()); } catch (IOException ex) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 1792670467c..766201334c7 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -74,7 +74,7 @@ private ClassLoader getRuntimeClassLoader(Project project) { getLogger().debug(e.getMessage()); } } - return urls.isEmpty() ? ClassLoader.getSystemClassLoader() : - new URLClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader()); + return urls.isEmpty() ? ClassLoader.getSystemClassLoader() + : new URLClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader()); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java index 820e91d3e97..5439ab9621a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java @@ -1,8 +1,9 @@ package com.commercehub.gradle.plugin.avro; +import com.google.common.collect.Sets; + import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.Set; class SetBuilder { @@ -33,8 +34,8 @@ Set build() { return set; } - static HashSet newHashSet() { - return new HashSet<>(); + static Set newHashSet() { + return Sets.newHashSet(); } @SafeVarargs diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 2ee5f56e44d..a8c2f061594 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -1,7 +1,5 @@ package com.commercehub.gradle.plugin.avro -import org.gradle.testkit.runner.GradleRunner - import java.nio.file.Files import static org.gradle.testkit.runner.TaskOutcome.FAILED @@ -114,6 +112,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == FAILED result.standardError.contains("> Could not compile schema definition files:") - result.standardError.contains("* src/main/avro/enumMalformed.avsc: \"enum\" is not a defined name. The type of the \"gender\" field must be a defined name or a {\"type\": ...} expression.") + result.standardError.contains("* src/main/avro/enumMalformed.avsc: \"enum\" is not a defined name. The type of the \"gender\" " + + "field must be a defined name or a {\"type\": ...} expression.") } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy index 6754562571f..d065e1f79c7 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy @@ -12,7 +12,7 @@ class AvroPluginSpec extends Specification { project.apply(plugin: AvroPlugin) then: "avro protocol generation tasks are registered with the project with appropriate configuration" - project.tasks.withType(GenerateAvroProtocolTask).collect {it.name}.sort() == ["generateAvroProtocol", "generateTestAvroProtocol"] + project.tasks.withType(GenerateAvroProtocolTask)*.name.sort() == ["generateAvroProtocol", "generateTestAvroProtocol"] mainGenerateAvroProtoTask.description == "Generates main Avro protocol definition files from IDL files." testGenerateAvroProtoTask.description == "Generates test Avro protocol definition files from IDL files." mainGenerateAvroProtoTask.group == Constants.GROUP_SOURCE_GENERATION @@ -27,7 +27,7 @@ class AvroPluginSpec extends Specification { project.apply(plugin: AvroPlugin) then: "avro java generation tasks are registered with the project with appropriate configuration" - project.tasks.withType(GenerateAvroJavaTask).collect {it.name}.sort() == ["generateAvroJava", "generateTestAvroJava"] + project.tasks.withType(GenerateAvroJavaTask)*.name.sort() == ["generateAvroJava", "generateTestAvroJava"] mainGenerateAvroJavaTask.description == "Generates main Avro Java source files from schema/protocol definition files." testGenerateAvroJavaTask.description == "Generates test Avro Java source files from schema/protocol definition files." mainGenerateAvroJavaTask.group == Constants.GROUP_SOURCE_GENERATION diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index c9d993812db..35fd1bca0d2 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -28,10 +28,8 @@ abstract class FunctionalSpec extends Specification { throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") } - def pluginClasspath = pluginClasspathResource.readLines() - .collect { it.replace('\\', '\\\\') } // escape backslashes in Windows paths - .collect { "'$it'" } - .join(", ") + // escape backslashes in Windows paths and assemble + def pluginClasspath = pluginClasspathResource.readLines()*.replace('\\', '\\\\').collect { "'$it'" }.join(", ") // Add the logic under test to the test build buildFile << """ From d48880cb0312ab6489dab008ce0f2d338911e497 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 18 Sep 2015 11:04:44 -0400 Subject: [PATCH 074/479] Better document dependency support --- README.md | 49 +++++++++++++++++++ src/test/resources/examples/inline/Cat.avsc | 17 +++++++ .../resources/examples/separate/Breed.avsc | 6 +++ src/test/resources/examples/separate/Cat.avsc | 8 +++ 4 files changed, 80 insertions(+) create mode 100644 src/test/resources/examples/inline/Cat.avsc create mode 100644 src/test/resources/examples/separate/Breed.avsc create mode 100644 src/test/resources/examples/separate/Cat.avsc diff --git a/README.md b/README.md index 8ab351a0cf6..8db43031528 100644 --- a/README.md +++ b/README.md @@ -106,3 +106,52 @@ task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) compileJava.source(generateAvro.outputs) ``` + +# Handling dependencies + +If you have record/enum/fixed types that are referenced in other record types, just define the shared type in a separate file rather than inline in the definition of each record type that uses it. The plugin will automatically recognize the dependency and compile the files in the correct order. For example, instead of `Cat.avsc`: + +```json +{ + "name": "Cat", + "namespace": "example", + "type": "record", + "fields" : [ + { + "name": "breed", + "type": { + "name": "Breed", + "type": "enum", + "symbols" : [ + "ABYSSINIAN", "AMERICAN_SHORTHAIR", "BIRMAN", "MAINE_COON", "ORIENTAL", "PERSIAN", "RAGDOLL", "SIAMESE", "SPHYNX" + ] + } + } + ] +} +``` + +use `Breed.avsc`: + +```json +{ + "name": "Breed", + "namespace": "example", + "type": "enum", + "symbols" : ["ABYSSINIAN", "AMERICAN_SHORTHAIR", "BIRMAN", "MAINE_COON", "ORIENTAL", "PERSIAN", "RAGDOLL", "SIAMESE", "SPHYNX"] +} +``` + + +and `Cat.avsc`: + +```json +{ + "name": "Cat", + "namespace": "example", + "type": "record", + "fields" : [ + {"name": "breed", "type": "Breed"} + ] +} +``` diff --git a/src/test/resources/examples/inline/Cat.avsc b/src/test/resources/examples/inline/Cat.avsc new file mode 100644 index 00000000000..0752abad722 --- /dev/null +++ b/src/test/resources/examples/inline/Cat.avsc @@ -0,0 +1,17 @@ +{ + "name": "Cat", + "namespace": "example", + "type": "record", + "fields" : [ + { + "name": "breed", + "type": { + "name": "Breed", + "type": "enum", + "symbols" : [ + "ABYSSINIAN", "AMERICAN_SHORTHAIR", "BIRMAN", "MAINE_COON", "ORIENTAL", "PERSIAN", "RAGDOLL", "SIAMESE", "SPHYNX" + ] + } + } + ] +} diff --git a/src/test/resources/examples/separate/Breed.avsc b/src/test/resources/examples/separate/Breed.avsc new file mode 100644 index 00000000000..ce752ac4ea1 --- /dev/null +++ b/src/test/resources/examples/separate/Breed.avsc @@ -0,0 +1,6 @@ +{ + "name": "Breed", + "namespace": "example", + "type": "enum", + "symbols" : ["ABYSSINIAN", "AMERICAN_SHORTHAIR", "BIRMAN", "MAINE_COON", "ORIENTAL", "PERSIAN", "RAGDOLL", "SIAMESE", "SPHYNX"] +} diff --git a/src/test/resources/examples/separate/Cat.avsc b/src/test/resources/examples/separate/Cat.avsc new file mode 100644 index 00000000000..cb5aa8be4f3 --- /dev/null +++ b/src/test/resources/examples/separate/Cat.avsc @@ -0,0 +1,8 @@ +{ + "name": "Cat", + "namespace": "example", + "type": "record", + "fields" : [ + {"name": "breed", "type": "Breed"} + ] +} From b6fe8ba460315431e33e7f50440f5d6ba04ebc77 Mon Sep 17 00:00:00 2001 From: Ryon Day Date: Mon, 21 Sep 2015 11:27:26 -0500 Subject: [PATCH 075/479] Add support for the last remaining Avro compiler option (creation of Setters) --- CHANGES.md | 1 + README.md | 9 +++ .../gradle/plugin/avro/AvroBasePlugin.java | 28 +++++--- .../gradle/plugin/avro/AvroExtension.java | 1 + .../gradle/plugin/avro/Constants.java | 10 +++ .../plugin/avro/DefaultAvroExtension.java | 13 ++++ .../plugin/avro/GenerateAvroJavaTask.java | 71 +++++++++++++++---- .../gradle/plugin/avro/SetBuilder.java | 2 +- .../plugin/avro/OptionsFunctionalSpec.groovy | 28 ++++++++ 9 files changed, 139 insertions(+), 24 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 240a2cfa410..82d42b58a11 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ * Removed some excessive debug logging * Built against Gradle 2.7 * Added Checkstyle and Codenarc to build + * Add ability to suppress the Avro compiler's creation of setters in created domain objects. * 0.5.0 * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) diff --git a/README.md b/README.md index 8db43031528..5d52a955fce 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,15 @@ avro { } ``` +Optionally, you can suppress the creation of setter methods in created domain objects. + +```groovy +avro { + createSetters = FALSE +} +``` + + Additionally, ensure that you have a compile dependency on avro, such as: ```groovy diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 5c11abba32b..4852ac61711 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -19,59 +19,71 @@ public void apply(final Project project) { private static void configureExtension(final Project project) { final AvroExtension avroExtension = project.getExtensions().create(AVRO_EXTENSION_NAME, DefaultAvroExtension.class); ConventionMapping extensionMapping = conventionMapping(avroExtension); - extensionMapping.map("encoding", new Callable() { + extensionMapping.map(OPTION_ENCODING, new Callable() { @Override public String call() throws Exception { return DEFAULT_ENCODING; } }); - extensionMapping.map("stringType", new Callable() { + extensionMapping.map(OPTION_STRING_TYPE, new Callable() { @Override public String call() throws Exception { return DEFAULT_STRING_TYPE; } }); - extensionMapping.map("fieldVisibility", new Callable() { + extensionMapping.map(OPTION_FIELD_VISIBILITY, new Callable() { @Override public String call() throws Exception { return DEFAULT_FIELD_VISIBILITY; } }); - extensionMapping.map("templateDirectory", new Callable() { + extensionMapping.map(OPTION_TEMPLATE_DIR, new Callable() { @Override public String call() throws Exception { return DEFAULT_TEMPLATE_DIR; } }); + extensionMapping.map(OPTION_CREATE_SETTERS, new Callable() { + @Override + public Boolean call() throws Exception { + return DEFAULT_CREATE_SETTERS; + } + }); project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override public void execute(GenerateAvroJavaTask task) { ConventionMapping taskMapping = conventionMapping(task); - taskMapping.map("encoding", new Callable() { + taskMapping.map(OPTION_ENCODING, new Callable() { @Override public String call() throws Exception { return avroExtension.getEncoding(); } }); - taskMapping.map("stringType", new Callable() { + taskMapping.map(OPTION_STRING_TYPE, new Callable() { @Override public String call() throws Exception { return avroExtension.getStringType(); } }); - taskMapping.map("fieldVisibility", new Callable() { + taskMapping.map(OPTION_FIELD_VISIBILITY, new Callable() { @Override public String call() throws Exception { return avroExtension.getFieldVisibility(); } }); - taskMapping.map("templateDirectory", new Callable() { + taskMapping.map(OPTION_TEMPLATE_DIR, new Callable() { @Override public String call() throws Exception { return avroExtension.getTemplateDirectory(); } }); + taskMapping.map(Constants.OPTION_CREATE_SETTERS, new Callable() { + @Override + public Boolean call() throws Exception { + return avroExtension.isCreateSetters(); + } + }); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index fea34f3d1b8..7a5297bb8d1 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -5,4 +5,5 @@ public interface AvroExtension { String getStringType(); String getFieldVisibility(); String getTemplateDirectory(); + Boolean isCreateSetters(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 3315cbf891f..8398c5153f5 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -3,6 +3,8 @@ import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; import org.apache.avro.generic.GenericData.StringType; +import static java.lang.Boolean.TRUE; + /** * Various constants needed by the plugin. * @@ -17,6 +19,7 @@ class Constants { static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); static final String DEFAULT_TEMPLATE_DIR = System.getProperty("org.apache.avro.specific.templates", "/org/apache/avro/compiler/specific/templates/java/classic/"); + static final Boolean DEFAULT_CREATE_SETTERS = TRUE; static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; @@ -26,4 +29,11 @@ class Constants { static final String GROUP_SOURCE_GENERATION = "Source Generation"; static final String AVRO_EXTENSION_NAME = "avro"; + + static final String OPTION_CREATE_SETTERS = "createSetters"; + static final String OPTION_TEMPLATE_DIR = "templateDirectory"; + static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; + static final String OPTION_STRING_TYPE = "stringType"; + static final String OPTION_ENCODING = "encoding"; + } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 5da5ffa1acd..6ffb883302f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -5,6 +5,7 @@ public class DefaultAvroExtension implements AvroExtension { private String stringType; private String fieldVisibility; private String templateDirectory; + private boolean createSetters; @Override public String getEncoding() { @@ -42,4 +43,16 @@ public void setTemplateDirectory(String templateDirectory) { this.templateDirectory = templateDirectory; } + @Override + public Boolean isCreateSetters() { + return createSetters; + } + + public void setCreateSetters(boolean createSetters) { + this.createSetters = createSetters; + } + + public void setCreateSetters(String createSetters) { + this.createSetters = Boolean.parseBoolean(createSetters); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index d45a47b1b1a..5238b20878d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -15,70 +15,99 @@ import java.io.File; import java.io.IOException; -import java.util.*; - -import static com.commercehub.gradle.plugin.avro.Constants.*; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_TEMPLATE_DIR; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_FIELD_VISIBILITY; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; +import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; import static java.lang.System.lineSeparator; /** * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and * {@link SpecificCompiler}. */ -public class GenerateAvroJavaTask extends OutputDirTask { +public class GenerateAvroJavaTask + extends OutputDirTask { + private static Set SUPPORTED_EXTENSIONS = ImmutableSet.of(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); private String encoding = Constants.DEFAULT_ENCODING; private String stringType = Constants.DEFAULT_STRING_TYPE; private String fieldVisibility = Constants.DEFAULT_FIELD_VISIBILITY; private String templateDirectory = DEFAULT_TEMPLATE_DIR; + private Boolean createSetters = DEFAULT_CREATE_SETTERS; + private transient StringType parsedStringType; private transient FieldVisibility parsedFieldVisibility; @Input public String getEncoding() { + return encoding; } public void setEncoding(String encoding) { + this.encoding = encoding; } @Input public String getStringType() { + return stringType; } public void setStringType(String stringType) { + this.stringType = stringType; } @Input public String getFieldVisibility() { + return fieldVisibility; } public void setFieldVisibility(String fieldVisibility) { + this.fieldVisibility = fieldVisibility; } @Input public String getTemplateDirectory() { + return templateDirectory; } + @Input + public Boolean isCreateSetters() { + + return createSetters; + } + public void setTemplateDirectory(String templateDirectory) { + this.templateDirectory = templateDirectory; } @TaskAction protected void process() { - parsedStringType = Enums.parseCaseInsensitive("stringType", StringType.values(), getStringType()); + + parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); parsedFieldVisibility = - Enums.parseCaseInsensitive("fieldVisibility", FieldVisibility.values(), getFieldVisibility()); + Enums.parseCaseInsensitive(OPTION_FIELD_VISIBILITY, FieldVisibility.values(), getFieldVisibility()); getLogger().debug("Using encoding {}", getEncoding()); getLogger().debug("Using stringType {}", parsedStringType.name()); getLogger().debug("Using fieldVisibility {}", parsedFieldVisibility.name()); getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); + getLogger().debug("{}creating setters in domain classes.", isCreateSetters() ? "" : "not "); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -86,26 +115,30 @@ protected void process() { } private void failOnUnsupportedFiles() { + FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(SUPPORTED_EXTENSIONS))); if (!unsupportedFiles.isEmpty()) { throw new GradleException( - String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); + String.format("Unsupported file extension for the following files: %s", + unsupportedFiles)); } } /** - * We need to remove all previously generated Java classes. Otherwise, when we call - * {@link SpecificCompiler#compileToDestination(java.io.File, java.io.File)}, it will skip generating classes for - * any schema files where the generated class is newer than the schema file. That seems like a useful performance - * optimization, but it can cause problems in the case where the schema file for this class hasn't changed, but - * the schema definition for one of the types it depends on has, resulting in some usages of a type now having - * outdated schema. + * We need to remove all previously generated Java classes. Otherwise, when we call {@link + * SpecificCompiler#compileToDestination(java.io.File, java.io.File)}, it will skip generating classes for any + * schema files where the generated class is newer than the schema file. That seems like a useful performance + * optimization, but it can cause problems in the case where the schema file for this class hasn't changed, but the + * schema definition for one of the types it depends on has, resulting in some usages of a type now having outdated + * schema. */ private void preClean() { + getProject().delete(getOutputDir()); } private void processFiles() { + int processedFileCount = 0; processedFileCount += processProtoFiles(); processedFileCount += processSchemaFiles(); @@ -113,6 +146,7 @@ private void processFiles() { } private int processProtoFiles() { + int processedFileCount = 0; for (File sourceFile : filterSources(new FileExtensionSpec(PROTOCOL_EXTENSION))) { processProtoFile(sourceFile); @@ -122,6 +156,7 @@ private int processProtoFiles() { } private void processProtoFile(File sourceFile) { + getLogger().info("Processing {}", sourceFile); try { compile(Protocol.parse(sourceFile), sourceFile); @@ -131,6 +166,7 @@ private void processProtoFile(File sourceFile) { } private int processSchemaFiles() { + int processedTotal = 0; int processedThisPass = -1; Map types = new HashMap<>(); @@ -163,11 +199,12 @@ private int processSchemaFiles() { nextPass.add(sourceFile); errors.put(path, ex.getMessage()); } else { - throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); + throw new GradleException(String.format("Failed to compile schema definition file %s", path), + ex); } } catch (NullPointerException ex) { getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency);" - + " will try again later", path); + + " will try again later", path); nextPass.add(sourceFile); errors.put(path, ex.getMessage()); } catch (IOException ex) { @@ -187,18 +224,22 @@ private int processSchemaFiles() { } private void compile(Protocol protocol, File sourceFile) throws IOException { + compile(new SpecificCompiler(protocol), sourceFile); } private void compile(Schema schema, File sourceFile) throws IOException { + compile(new SpecificCompiler(schema), sourceFile); } private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { + compiler.setOutputCharacterEncoding(getEncoding()); compiler.setStringType(parsedStringType); compiler.setFieldVisibility(parsedFieldVisibility); compiler.setTemplateDir(getTemplateDirectory()); + compiler.setCreateSetters(isCreateSetters()); compiler.compileToDestination(sourceFile, getOutputDir()); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java index 5439ab9621a..20753ea846f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java @@ -40,6 +40,6 @@ static Set newHashSet() { @SafeVarargs static Set build(T... c) { - return new SetBuilder().addAll(c).build(); + return Sets.newHashSet(c); } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 979f4f49963..9026eccfe4f 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -109,6 +109,34 @@ class OptionsFunctionalSpec extends FunctionalSpec { FieldVisibility.PUBLIC_DEPRECATED.name() | "@Deprecated public java.lang.String name;" } + @Unroll + def "supports configuring createSetters to #createSetters"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | createSetters = ${createSetters} + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "the task succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + + and: "the specified createSetters is used" + content.contains(expectedContent) == createSetters + + where: + createSetters | expectedContent + Boolean.TRUE | "public void setName(java.lang.String value)" + Boolean.FALSE | "public void setName(java.lang.String value)" + true | "public void setName(java.lang.String value)" + false | "public void setName(java.lang.String value)" + } + def "supports configuring templateDirectory"() { given: def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") From 5986617b1d4f15deb0187aba690b82501afaae57 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 22 Sep 2015 12:55:38 -0400 Subject: [PATCH 076/479] Minor fixes to ryonday's createSetters feature. --- CHANGES.md | 4 +- README.md | 3 +- config/checkstyle/checkstyle.xml | 5 +- .../gradle/plugin/avro/AvroBasePlugin.java | 6 +- .../gradle/plugin/avro/AvroExtension.java | 2 +- .../gradle/plugin/avro/Constants.java | 9 +-- .../plugin/avro/DefaultAvroExtension.java | 2 +- .../plugin/avro/GenerateAvroJavaTask.java | 71 ++++++------------- .../gradle/plugin/avro/SetBuilder.java | 11 +-- .../plugin/avro/OptionsFunctionalSpec.groovy | 15 ++-- 10 files changed, 45 insertions(+), 83 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 82d42b58a11..9b452720127 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,12 +1,12 @@ # Change Log * Unreleased - * Add ability to set source directory for the Avro compiler's Velocity templates. + * Add new configuration option "templateDirectory" to set source directory for the Avro compiler's Velocity templates. + * Add new configuration option "createSetters" to allow suppressing the Avro compiler's creation of setters in created domain objects. * Matching of fieldVisibility settings is now case-insensitive. * Removed some excessive debug logging * Built against Gradle 2.7 * Added Checkstyle and Codenarc to build - * Add ability to suppress the Avro compiler's creation of setters in created domain objects. * 0.5.0 * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) diff --git a/README.md b/README.md index 5d52a955fce..b4642b2f7d1 100644 --- a/README.md +++ b/README.md @@ -72,11 +72,10 @@ Optionally, you can suppress the creation of setter methods in created domain ob ```groovy avro { - createSetters = FALSE + createSetters = false } ``` - Additionally, ensure that you have a compile dependency on avro, such as: ```groovy diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index c2eaa45e5c2..68bb850a2a9 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -4,10 +4,7 @@ - - - - + diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 4852ac61711..9dd21f722dc 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -37,7 +37,7 @@ public String call() throws Exception { return DEFAULT_FIELD_VISIBILITY; } }); - extensionMapping.map(OPTION_TEMPLATE_DIR, new Callable() { + extensionMapping.map(OPTION_TEMPLATE_DIRECTORY, new Callable() { @Override public String call() throws Exception { return DEFAULT_TEMPLATE_DIR; @@ -72,13 +72,13 @@ public String call() throws Exception { return avroExtension.getFieldVisibility(); } }); - taskMapping.map(OPTION_TEMPLATE_DIR, new Callable() { + taskMapping.map(OPTION_TEMPLATE_DIRECTORY, new Callable() { @Override public String call() throws Exception { return avroExtension.getTemplateDirectory(); } }); - taskMapping.map(Constants.OPTION_CREATE_SETTERS, new Callable() { + taskMapping.map(OPTION_CREATE_SETTERS, new Callable() { @Override public Boolean call() throws Exception { return avroExtension.isCreateSetters(); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 7a5297bb8d1..d7e38e57801 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -5,5 +5,5 @@ public interface AvroExtension { String getStringType(); String getFieldVisibility(); String getTemplateDirectory(); - Boolean isCreateSetters(); + boolean isCreateSetters(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 8398c5153f5..f2d2c57fa60 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -3,8 +3,6 @@ import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; import org.apache.avro.generic.GenericData.StringType; -import static java.lang.Boolean.TRUE; - /** * Various constants needed by the plugin. * @@ -18,8 +16,8 @@ class Constants { static final String DEFAULT_STRING_TYPE = StringType.String.name(); static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); static final String DEFAULT_TEMPLATE_DIR = System.getProperty("org.apache.avro.specific.templates", - "/org/apache/avro/compiler/specific/templates/java/classic/"); - static final Boolean DEFAULT_CREATE_SETTERS = TRUE; + "/org/apache/avro/compiler/specific/templates/java/classic/"); + static final boolean DEFAULT_CREATE_SETTERS = true; static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; @@ -31,9 +29,8 @@ class Constants { static final String AVRO_EXTENSION_NAME = "avro"; static final String OPTION_CREATE_SETTERS = "createSetters"; - static final String OPTION_TEMPLATE_DIR = "templateDirectory"; + static final String OPTION_TEMPLATE_DIRECTORY = "templateDirectory"; static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; static final String OPTION_ENCODING = "encoding"; - } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 6ffb883302f..1532f5b8b6c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -44,7 +44,7 @@ public void setTemplateDirectory(String templateDirectory) { } @Override - public Boolean isCreateSetters() { + public boolean isCreateSetters() { return createSetters; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 5238b20878d..18f267d148b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -15,91 +15,78 @@ import java.io.File; import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; -import java.util.Set; - -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_TEMPLATE_DIR; -import static com.commercehub.gradle.plugin.avro.Constants.OPTION_FIELD_VISIBILITY; -import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; -import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; +import java.util.*; + +import static com.commercehub.gradle.plugin.avro.Constants.*; import static java.lang.System.lineSeparator; /** * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and * {@link SpecificCompiler}. */ -public class GenerateAvroJavaTask - extends OutputDirTask { - +public class GenerateAvroJavaTask extends OutputDirTask { private static Set SUPPORTED_EXTENSIONS = ImmutableSet.of(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); private String encoding = Constants.DEFAULT_ENCODING; private String stringType = Constants.DEFAULT_STRING_TYPE; private String fieldVisibility = Constants.DEFAULT_FIELD_VISIBILITY; private String templateDirectory = DEFAULT_TEMPLATE_DIR; - private Boolean createSetters = DEFAULT_CREATE_SETTERS; + private boolean createSetters = DEFAULT_CREATE_SETTERS; private transient StringType parsedStringType; private transient FieldVisibility parsedFieldVisibility; @Input public String getEncoding() { - return encoding; } public void setEncoding(String encoding) { - this.encoding = encoding; } @Input public String getStringType() { - return stringType; } public void setStringType(String stringType) { - this.stringType = stringType; } @Input public String getFieldVisibility() { - return fieldVisibility; } public void setFieldVisibility(String fieldVisibility) { - this.fieldVisibility = fieldVisibility; } @Input public String getTemplateDirectory() { - return templateDirectory; } + public void setTemplateDirectory(String templateDirectory) { + this.templateDirectory = templateDirectory; + } + @Input public Boolean isCreateSetters() { - return createSetters; } - public void setTemplateDirectory(String templateDirectory) { + public void setCreateSetters(boolean createSetters) { + this.createSetters = createSetters; + } - this.templateDirectory = templateDirectory; + public void setCreateSetters(String createSetters) { + this.createSetters = Boolean.parseBoolean(createSetters); } @TaskAction protected void process() { - parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); parsedFieldVisibility = Enums.parseCaseInsensitive(OPTION_FIELD_VISIBILITY, FieldVisibility.values(), getFieldVisibility()); @@ -107,7 +94,7 @@ protected void process() { getLogger().debug("Using stringType {}", parsedStringType.name()); getLogger().debug("Using fieldVisibility {}", parsedFieldVisibility.name()); getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); - getLogger().debug("{}creating setters in domain classes.", isCreateSetters() ? "" : "not "); + getLogger().debug("Using createSetters {}", isCreateSetters()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -115,30 +102,25 @@ protected void process() { } private void failOnUnsupportedFiles() { - FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(SUPPORTED_EXTENSIONS))); if (!unsupportedFiles.isEmpty()) { throw new GradleException( - String.format("Unsupported file extension for the following files: %s", - unsupportedFiles)); + String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); } } /** - * We need to remove all previously generated Java classes. Otherwise, when we call {@link - * SpecificCompiler#compileToDestination(java.io.File, java.io.File)}, it will skip generating classes for any - * schema files where the generated class is newer than the schema file. That seems like a useful performance - * optimization, but it can cause problems in the case where the schema file for this class hasn't changed, but the - * schema definition for one of the types it depends on has, resulting in some usages of a type now having outdated - * schema. + * We need to remove all previously generated Java classes. Otherwise, when we call + * {@link SpecificCompiler#compileToDestination(java.io.File, java.io.File)}, it will skip generating classes for any schema files where + * the generated class is newer than the schema file. That seems like a useful performance optimization, but it can cause problems in + * the case where the schema file for this class hasn't changed, but the schema definition for one of the types it depends on has, + * resulting in some usages of a type now having outdated schema. */ private void preClean() { - getProject().delete(getOutputDir()); } private void processFiles() { - int processedFileCount = 0; processedFileCount += processProtoFiles(); processedFileCount += processSchemaFiles(); @@ -146,7 +128,6 @@ private void processFiles() { } private int processProtoFiles() { - int processedFileCount = 0; for (File sourceFile : filterSources(new FileExtensionSpec(PROTOCOL_EXTENSION))) { processProtoFile(sourceFile); @@ -156,7 +137,6 @@ private int processProtoFiles() { } private void processProtoFile(File sourceFile) { - getLogger().info("Processing {}", sourceFile); try { compile(Protocol.parse(sourceFile), sourceFile); @@ -166,7 +146,6 @@ private void processProtoFile(File sourceFile) { } private int processSchemaFiles() { - int processedTotal = 0; int processedThisPass = -1; Map types = new HashMap<>(); @@ -199,12 +178,11 @@ private int processSchemaFiles() { nextPass.add(sourceFile); errors.put(path, ex.getMessage()); } else { - throw new GradleException(String.format("Failed to compile schema definition file %s", path), - ex); + throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } } catch (NullPointerException ex) { getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency);" - + " will try again later", path); + + " will try again later", path); nextPass.add(sourceFile); errors.put(path, ex.getMessage()); } catch (IOException ex) { @@ -224,17 +202,14 @@ private int processSchemaFiles() { } private void compile(Protocol protocol, File sourceFile) throws IOException { - compile(new SpecificCompiler(protocol), sourceFile); } private void compile(Schema schema, File sourceFile) throws IOException { - compile(new SpecificCompiler(schema), sourceFile); } private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { - compiler.setOutputCharacterEncoding(getEncoding()); compiler.setStringType(parsedStringType); compiler.setFieldVisibility(parsedFieldVisibility); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java index 20753ea846f..0fc3cdb2ee9 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java @@ -7,7 +7,7 @@ import java.util.Set; class SetBuilder { - private Set set = newHashSet(); + private Set set = Sets.newHashSet(); SetBuilder add(T e) { set.add(e); @@ -33,13 +33,4 @@ SetBuilder remove(T e) { Set build() { return set; } - - static Set newHashSet() { - return Sets.newHashSet(); - } - - @SafeVarargs - static Set build(T... c) { - return Sets.newHashSet(c); - } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 9026eccfe4f..00ce55d992b 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -30,6 +30,9 @@ class OptionsFunctionalSpec extends FunctionalSpec { and: "the default template is used" !content.contains("Custom template") + + and: "createSetters is enabled" + content.contains("public void setName(java.lang.String value)") } def "supports configuring encoding"() { @@ -127,14 +130,14 @@ class OptionsFunctionalSpec extends FunctionalSpec { def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) and: "the specified createSetters is used" - content.contains(expectedContent) == createSetters + content.contains("public void setName(java.lang.String value)") == expectedPresent where: - createSetters | expectedContent - Boolean.TRUE | "public void setName(java.lang.String value)" - Boolean.FALSE | "public void setName(java.lang.String value)" - true | "public void setName(java.lang.String value)" - false | "public void setName(java.lang.String value)" + createSetters | expectedPresent + "Boolean.TRUE" | true + "Boolean.FALSE" | false + "true" | true + "false" | false } def "supports configuring templateDirectory"() { From bf4edb927db8c7b9ae72b15193e44e0185fe8804 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 30 Sep 2015 10:33:35 -0400 Subject: [PATCH 077/479] version: 0.6.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 9b452720127..0bf8159b5ce 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log * Unreleased + +* 0.6.0 * Add new configuration option "templateDirectory" to set source directory for the Avro compiler's Velocity templates. * Add new configuration option "createSetters" to allow suppressing the Avro compiler's creation of setters in created domain objects. * Matching of fieldVisibility settings is now case-insensitive. diff --git a/build.gradle b/build.gradle index 3fa938a6b52..67e5adbe19c 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ pluginBundle { vcsUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." tags = ["serialization", "avro"] - version = "0.5.0" + version = "0.6.0" plugins { avro { id = "com.commercehub.gradle.plugin.avro" From e50950d65cc4db747d2c7cf6866932f145965174 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 9 Oct 2015 12:22:46 -0400 Subject: [PATCH 078/479] Re-format changelog for easier copy-paste --- CHANGES.md | 123 +++++++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0bf8159b5ce..c619a2439ce 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,63 +1,64 @@ # Change Log -* Unreleased - -* 0.6.0 - * Add new configuration option "templateDirectory" to set source directory for the Avro compiler's Velocity templates. - * Add new configuration option "createSetters" to allow suppressing the Avro compiler's creation of setters in created domain objects. - * Matching of fieldVisibility settings is now case-insensitive. - * Removed some excessive debug logging - * Built against Gradle 2.7 - * Added Checkstyle and Codenarc to build - -* 0.5.0 - * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) - * Expose original error messages from `avro-compiler` when compilation fails - -* 0.4.0 - * Add ability to specify fieldVisibility for generated Java source; contribution from [wooder79](https://github.com/wooder79) - * Removed support for unqualified plugin ID (just "avro") - * Published via new mechanism to [Gradle plugin portal](https://plugins.gradle.org) - * Stopped publishing to previous location on Bintray - * Built against Gradle 2.6; uses [test kit](https://docs.gradle.org/current/userguide/test_kit.html) for functional testing - -* 0.3.4 - * Fix registration of generated sources for compilation (#8) - * Change classloader handling to better support import of external dependencies (#9) - -* 0.3.3 - * Fix generation of Java files from .avdl files; contribution from [viacoban](https://github.com/viacoban) - -* 0.3.2 - * Improve handling when custom buildDir is used - -* 0.3.1 - * Fix extension support for configuring encoding - * Make default encoding UTF-8 - -* 0.3.0 - * IntelliJ: register generated source directories even if they don't already exist. - * Add avro-base plugin, which exposes tasks and the extension without creating tasks, defaults, etc. - -* 0.2.0 - * Build against Gradle 1.12 - * Compile using Avro 1.7.6 - * Support for qualified plugin ID - * Deprecate unqualified plugin ID - -* 0.1.3 - * Always regenerate all Java classes when any schema file changes to avoid some classes having outdated schema information. - -* 0.1.2 - * Eliminate dependency on guava, make dependency on commons-io explicit - -* 0.1.1 - * Fixed NullPointerException when performing clean builds - -* 0.1.0 - * Add support for converting IDL files to JSON protocol declaration files - * Add support for generating Java classes from JSON protocol declaration files - * Add support for generating Java classes from JSON schema declaration files - * Add support for inter-dependent JSON schema declaration files - * Add support for tweaking source/exclude directories in IntelliJ - * Add support for specifying the string type to use in generated classes +## Unreleased + +## 0.6.0 +* Add new configuration option "templateDirectory" to set source directory for the Avro compiler's Velocity templates. +* Add new configuration option "createSetters" to allow suppressing the Avro compiler's creation of setters in created domain objects. +* Matching of fieldVisibility settings is now case-insensitive. +* Removed some excessive debug logging +* Built against Gradle 2.7 +* Added Checkstyle and Codenarc to build + +## 0.5.0 +* Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) +* Expose original error messages from `avro-compiler` when compilation fails + +## 0.4.0 +* Add ability to specify fieldVisibility for generated Java source; contribution from [wooder79](https://github.com/wooder79) +* Removed support for unqualified plugin ID (just "avro") +* Published via new mechanism to [Gradle plugin portal](https://plugins.gradle.org) +* Stopped publishing to previous location on Bintray +* Built against Gradle 2.6; uses [test kit](https://docs.gradle.org/current/userguide/test_kit.html) for functional testing + +## 0.3.4 +* Fix registration of generated sources for compilation (#8) +* Change classloader handling to better support import of external dependencies (#9) + +## 0.3.3 +* Fix generation of Java files from .avdl files; contribution from [viacoban](https://github.com/viacoban) + +## 0.3.2 +* Improve handling when custom buildDir is used + +## 0.3.1 +* Fix extension support for configuring encoding +* Make default encoding UTF-8 + +## 0.3.0 +* IntelliJ: register generated source directories even if they don't already exist. +* Add avro-base plugin, which exposes tasks and the extension without creating tasks, defaults, etc. +* Add support for configuring encoding + +## 0.2.0 +* Build against Gradle 1.12 +* Compile using Avro 1.7.6 +* Support for qualified plugin ID +* Deprecate unqualified plugin ID + +## 0.1.3 +* Always regenerate all Java classes when any schema file changes to avoid some classes having outdated schema information. + +## 0.1.2 +* Eliminate dependency on guava, make dependency on commons-io explicit + +## 0.1.1 +* Fixed NullPointerException when performing clean builds + +## 0.1.0 +* Add support for converting IDL files to JSON protocol declaration files +* Add support for generating Java classes from JSON protocol declaration files +* Add support for generating Java classes from JSON schema declaration files +* Add support for inter-dependent JSON schema declaration files +* Add support for tweaking source/exclude directories in IntelliJ +* Add support for specifying the string type to use in generated classes From a7faa4aa315ce511187139c324ea330041ea3ba8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 9 Oct 2015 12:23:13 -0400 Subject: [PATCH 079/479] Update release instructions --- RELEASING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASING.md b/RELEASING.md index 7dfabe0dfd8..a452f8710c3 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -2,7 +2,11 @@ 1. Check that you've followed the setup steps listed [here](https://plugins.gradle.org/docs/submit) 1. Update `CHANGES.md` +1. Ensure that there is a milestone for the version, and that appropriate issues are associated with the milestone. 1. Update the plugin version in `build.gradle` under "pluginBundle/version" 1. Commit and tag with the version number 1. Run `./gradlew clean build publishPlugins` 1. Push +1. If there was a issue requesting the release, close it. +1. Close the milestone. +1. Go to the [GitHub Releases page](https://github.com/commercehub-oss/gradle-avro-plugin/releases), click "Draft a new release", select the tag version, use the version number as the title, copy the relevant segment from `CHANGES.md` into the description, and click "Publish release". From a9bbe0c28c046af99c25fecd7da8ca05addc3067 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 9 Oct 2015 12:28:01 -0400 Subject: [PATCH 080/479] Remove usage of Guava (#18) --- CHANGES.md | 3 +++ config/checkstyle/checkstyle.xml | 3 +++ import-control.xml | 24 +++++++++++++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 3 +-- .../gradle/plugin/avro/SetBuilder.java | 10 +++++--- 5 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 import-control.xml diff --git a/CHANGES.md b/CHANGES.md index c619a2439ce..5e097b5835e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased +* Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. +* Remove usage of Guava. ## 0.6.0 * Add new configuration option "templateDirectory" to set source directory for the Avro compiler's Velocity templates. @@ -9,6 +11,7 @@ * Removed some excessive debug logging * Built against Gradle 2.7 * Added Checkstyle and Codenarc to build +* Known Bug: doesn't work properly unless you manually add a dependency on guava; please upgrade to 0.6.1 ## 0.5.0 * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 68bb850a2a9..a9dbb2e79d8 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -54,6 +54,9 @@ + + + diff --git a/import-control.xml b/import-control.xml new file mode 100644 index 00000000000..68068a27f5f --- /dev/null +++ b/import-control.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 18f267d148b..4b528a1a774 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -1,6 +1,5 @@ package com.commercehub.gradle.plugin.avro; -import com.google.common.collect.ImmutableSet; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.apache.avro.SchemaParseException; @@ -25,7 +24,7 @@ * {@link SpecificCompiler}. */ public class GenerateAvroJavaTask extends OutputDirTask { - private static Set SUPPORTED_EXTENSIONS = ImmutableSet.of(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); + private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); private String encoding = Constants.DEFAULT_ENCODING; private String stringType = Constants.DEFAULT_STRING_TYPE; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java index 0fc3cdb2ee9..d7b3825a574 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java @@ -1,13 +1,12 @@ package com.commercehub.gradle.plugin.avro; -import com.google.common.collect.Sets; - import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Set; class SetBuilder { - private Set set = Sets.newHashSet(); + private Set set = new HashSet<>(); SetBuilder add(T e) { set.add(e); @@ -33,4 +32,9 @@ SetBuilder remove(T e) { Set build() { return set; } + + @SafeVarargs + static Set build(T... c) { + return new SetBuilder().addAll(c).build(); + } } From b869a6b33ea3027172f278c325147a43840acb8d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 9 Oct 2015 12:31:20 -0400 Subject: [PATCH 081/479] Minor readme tweak --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b4642b2f7d1..f5a841f7976 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ avro { } ``` -Additionally, ensure that you have a compile dependency on avro, such as: +Additionally, ensure that you have a compile dependency on Avro, such as: ```groovy repositories { From b9c78c7161308c0936526a0c1c2637f24e1cec4e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 9 Oct 2015 12:33:19 -0400 Subject: [PATCH 082/479] version: 0.6.1 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 5e097b5835e..1c4e71f50b6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.6.1 * Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. * Remove usage of Guava. diff --git a/build.gradle b/build.gradle index 67e5adbe19c..7bb901bc031 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ pluginBundle { vcsUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." tags = ["serialization", "avro"] - version = "0.6.0" + version = "0.6.1" plugins { avro { id = "com.commercehub.gradle.plugin.avro" From 61b36b6bba667ce99f2050be95ed2894c5933eb3 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 9 Oct 2015 12:45:40 -0400 Subject: [PATCH 083/479] Remove usage of Apache Commons IO (#19) --- CHANGES.md | 3 +- build.gradle | 1 - import-control.xml | 2 - .../gradle/plugin/avro/FileExtensionSpec.java | 1 - .../gradle/plugin/avro/FileUtils.java | 134 ++++++++++ .../gradle/plugin/avro/FilenameUtils.java | 253 ++++++++++++++++++ .../plugin/avro/GenerateAvroProtocolTask.java | 2 - 7 files changed, 389 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java diff --git a/CHANGES.md b/CHANGES.md index 1c4e71f50b6..33915872b12 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,10 +1,11 @@ # Change Log ## Unreleased +* Remove usage of Apache Commons IO (#19) ## 0.6.1 * Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. -* Remove usage of Guava. +* Remove usage of Guava (#18) ## 0.6.0 * Add new configuration option "templateDirectory" to set source directory for the Avro compiler's Velocity templates. diff --git a/build.gradle b/build.gradle index 7bb901bc031..a80fbf0197b 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,6 @@ dependencies { compile gradleApi() compile localGroovy() compile "org.apache.avro:avro-compiler:1.7.7" - compile "org.apache.commons:commons-io:1.3.2" testCompile "org.spockframework:spock-core:1.0-groovy-2.3" testCompile gradleTestKit() } diff --git a/import-control.xml b/import-control.xml index 68068a27f5f..3a6efb0794e 100644 --- a/import-control.xml +++ b/import-control.xml @@ -15,8 +15,6 @@ - - diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java index 02a1281c76a..5fb10b296ce 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java @@ -1,6 +1,5 @@ package com.commercehub.gradle.plugin.avro; -import org.apache.commons.io.FilenameUtils; import org.gradle.api.specs.Spec; import java.io.File; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java new file mode 100644 index 00000000000..71e64462dca --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 com.commercehub.gradle.plugin.avro; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * General file manipulation utilities. + * + *

This copy from Apache Commons IO has been pruned down to just what is needed for gradle-avro-plugin.

+ * + *

+ * Facilities are provided in the following areas: + *

    + *
  • writing to a file + *
  • reading from a file + *
  • make a directory including parent directories + *
  • copying files and directories + *
  • deleting files and directories + *
  • converting to and from a URL + *
  • listing files and directories by filter and extension + *
  • comparing file content + *
  • file last changed date + *
  • calculating a checksum + *
+ *

+ * Origin of code: Excalibur, Alexandria, Commons-Utils + * + * @author Kevin A. Burton + * @author Scott Sanders + * @author Daniel Rall + * @author Christoph.Reck + * @author Peter Donald + * @author Jeff Turner + * @author Matthew Hawthorne + * @author Jeremias Maerki + * @author Stephen Colebourne + * @author Ian Springer + * @author Chris Eldredge + * @author Jim Harrington + * @author Niall Pemberton + * @author Sandy McArthur + * @version $Id: FileUtils.java 507684 2007-02-14 20:38:25Z bayard $ + */ +class FileUtils { + /** + * Opens a {@link FileOutputStream} for the specified file, checking and + * creating the parent directory if it does not exist. + *

+ * At the end of the method either the stream will be successfully opened, + * or an exception will have been thrown. + *

+ * The parent directory will be created if it does not exist. + * The file will be created if it does not exist. + * An exception is thrown if the file object exists but is a directory. + * An exception is thrown if the file exists but cannot be written to. + * An exception is thrown if the parent directory cannot be created. + * + * @param file the file to open for output, must not be null + * @return a new {@link FileOutputStream} for the specified file + * @throws IOException if the file object is a directory + * @throws IOException if the file cannot be written to + * @throws IOException if a parent directory needs creating but that fails + * @since Commons IO 1.3 + */ + public static FileOutputStream openOutputStream(File file) throws IOException { + if (file.exists()) { + if (file.isDirectory()) { + throw new IOException("File '" + file + "' exists but is a directory"); + } + if (!file.canWrite()) { + throw new IOException("File '" + file + "' cannot be written to"); + } + } else { + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + if (!parent.mkdirs()) { + throw new IOException("File '" + file + "' could not be created"); + } + } + } + return new FileOutputStream(file); + } + + /** + * Writes a String to a file creating the file if it does not exist. + * + * NOTE: As from v1.3, the parent directories of the file will be created + * if they do not exist. + * + * @param file the file to write + * @param data the content to write to the file + * @param encoding the encoding to use, null means platform default + * @throws IOException in case of an I/O error + * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM + */ + public static void writeStringToFile(File file, String data, String encoding) throws IOException { + if (encoding == null) { + throw new IllegalArgumentException("Must specify encoding"); + } + OutputStream out = null; + try { + out = openOutputStream(file); + if (data != null) { + out.write(data.getBytes(encoding)); + } + } finally { + try { + if (out != null) { + out.close(); + } + } catch (IOException ioe) { + // ignore + } + } + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java new file mode 100644 index 00000000000..1ada6dbd164 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 com.commercehub.gradle.plugin.avro; + +/** + * General filename and filepath manipulation utilities. + * + *

This copy from Apache Commons IO has been pruned down to just what is needed for gradle-avro-plugin.

+ * + *

+ * When dealing with filenames you can hit problems when moving from a Windows + * based development machine to a Unix based production machine. + * This class aims to help avoid those problems. + *

+ * NOTE: You may be able to avoid using this class entirely simply by + * using JDK {@link java.io.File File} objects and the two argument constructor + * {@link java.io.File#File(java.io.File, java.lang.String) File(File,String)}. + *

+ * Most methods on this class are designed to work the same on both Unix and Windows. + * Those that don't include 'System', 'Unix' or 'Windows' in their name. + *

+ * Most methods recognise both separators (forward and back), and both + * sets of prefixes. See the javadoc of each method for details. + *

+ * This class defines six components within a filename + * (example C:\dev\project\file.txt): + *

    + *
  • the prefix - C:\
  • + *
  • the path - dev\project\
  • + *
  • the full path - C:\dev\project\
  • + *
  • the name - file.txt
  • + *
  • the base name - file
  • + *
  • the extension - txt
  • + *
+ * Note that this class works best if directory filenames end with a separator. + * If you omit the last separator, it is impossible to determine if the filename + * corresponds to a file or a directory. As a result, we have chosen to say + * it corresponds to a file. + *

+ * This class only supports Unix and Windows style names. + * Prefixes are matched as follows: + *

+ * Windows:
+ * a\b\c.txt           --> ""          --> relative
+ * \a\b\c.txt          --> "\"         --> current drive absolute
+ * C:a\b\c.txt         --> "C:"        --> drive relative
+ * C:\a\b\c.txt        --> "C:\"       --> absolute
+ * \\server\a\b\c.txt  --> "\\server\" --> UNC
+ *
+ * Unix:
+ * a/b/c.txt           --> ""          --> relative
+ * /a/b/c.txt          --> "/"         --> absolute
+ * ~/a/b/c.txt         --> "~/"        --> current user
+ * ~                   --> "~/"        --> current user (slash added)
+ * ~user/a/b/c.txt     --> "~user/"    --> named user
+ * ~user               --> "~user/"    --> named user (slash added)
+ * 
+ * Both prefix styles are matched always, irrespective of the machine that you are + * currently running on. + *

+ * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils. + * + * @author Kevin A. Burton + * @author Scott Sanders + * @author Daniel Rall + * @author Christoph.Reck + * @author Peter Donald + * @author Jeff Turner + * @author Matthew Hawthorne + * @author Martin Cooper + * @author Jeremias Maerki + * @author Stephen Colebourne + * @version $Id: FilenameUtils.java 490424 2006-12-27 01:20:43Z bayard $ + * @since Commons IO 1.1 + */ +class FilenameUtils { + /** + * The extension separator character. + */ + private static final char EXTENSION_SEPARATOR = '.'; + + /** + * The Unix separator character. + */ + private static final char UNIX_SEPARATOR = '/'; + + /** + * The Windows separator character. + */ + private static final char WINDOWS_SEPARATOR = '\\'; + + /** + * Returns the index of the last directory separator character. + *

+ * This method will handle a file in either Unix or Windows format. + * The position of the last forward or backslash is returned. + *

+ * The output will be the same irrespective of the machine that the code is running on. + * + * @param filename the filename to find the last path separator in, null returns -1 + * @return the index of the last separator character, or -1 if there + * is no such character + */ + public static int indexOfLastSeparator(String filename) { + if (filename == null) { + return -1; + } + int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR); + int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR); + return Math.max(lastUnixPos, lastWindowsPos); + } + + /** + * Returns the index of the last extension separator character, which is a dot. + *

+ * This method also checks that there is no directory separator after the last dot. + * To do this it uses {@link #indexOfLastSeparator(String)} which will + * handle a file in either Unix or Windows format. + *

+ * The output will be the same irrespective of the machine that the code is running on. + * + * @param filename the filename to find the last path separator in, null returns -1 + * @return the index of the last separator character, or -1 if there + * is no such character + */ + public static int indexOfExtension(String filename) { + if (filename == null) { + return -1; + } + int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR); + int lastSeparator = indexOfLastSeparator(filename); + return lastSeparator > extensionPos ? -1 : extensionPos; + } + + /** + * Gets the name minus the path from a full filename. + *

+ * This method will handle a file in either Unix or Windows format. + * The text after the last forward or backslash is returned. + *

+     * a/b/c.txt --> c.txt
+     * a.txt     --> a.txt
+     * a/b/c     --> c
+     * a/b/c/    --> ""
+     * 
+ *

+ * The output will be the same irrespective of the machine that the code is running on. + * + * @param filename the filename to query, null returns null + * @return the name of the file without the path, or an empty string if none exists + */ + public static String getName(String filename) { + if (filename == null) { + return null; + } + int index = indexOfLastSeparator(filename); + return filename.substring(index + 1); + } + + /** + * Gets the base name, minus the full path and extension, from a full filename. + *

+ * This method will handle a file in either Unix or Windows format. + * The text after the last forward or backslash and before the last dot is returned. + *

+     * a/b/c.txt --> c
+     * a.txt     --> a
+     * a/b/c     --> c
+     * a/b/c/    --> ""
+     * 
+ *

+ * The output will be the same irrespective of the machine that the code is running on. + * + * @param filename the filename to query, null returns null + * @return the name of the file without the path, or an empty string if none exists + */ + public static String getBaseName(String filename) { + return removeExtension(getName(filename)); + } + + /** + * Gets the extension of a filename. + *

+ * This method returns the textual part of the filename after the last dot. + * There must be no directory separator after the dot. + *

+     * foo.txt      --> "txt"
+     * a/b/c.jpg    --> "jpg"
+     * a/b.txt/c    --> ""
+     * a/b/c        --> ""
+     * 
+ *

+ * The output will be the same irrespective of the machine that the code is running on. + * + * @param filename the filename to retrieve the extension of. + * @return the extension of the file or an empty string if none exists. + */ + public static String getExtension(String filename) { + if (filename == null) { + return null; + } + int index = indexOfExtension(filename); + if (index == -1) { + return ""; + } else { + return filename.substring(index + 1); + } + } + + //----------------------------------------------------------------------- + /** + * Removes the extension from a filename. + *

+ * This method returns the textual part of the filename before the last dot. + * There must be no directory separator after the dot. + *

+     * foo.txt    --> foo
+     * a\b\c.jpg  --> a\b\c
+     * a\b\c      --> a\b\c
+     * a.b\c      --> a.b\c
+     * 
+ *

+ * The output will be the same irrespective of the machine that the code is running on. + * + * @param filename the filename to query, null returns null + * @return the filename minus the extension + */ + public static String removeExtension(String filename) { + if (filename == null) { + return null; + } + int index = indexOfExtension(filename); + if (index == -1) { + return filename; + } else { + return filename.substring(0, index); + } + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 766201334c7..1be971d920c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -2,8 +2,6 @@ import org.apache.avro.compiler.idl.Idl; import org.apache.avro.compiler.idl.ParseException; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; From 739aeb9fd16f349ce00e85b96d37449e9caf5cbf Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 09:27:37 -0400 Subject: [PATCH 084/479] Add ability to retry duplicate type definitions, with new configuration option "retryDuplicateTypes" (#13) --- CHANGES.md | 1 + .../gradle/plugin/avro/AvroBasePlugin.java | 12 ++ .../gradle/plugin/avro/AvroExtension.java | 1 + .../gradle/plugin/avro/Constants.java | 2 + .../plugin/avro/DefaultAvroExtension.java | 14 ++ .../gradle/plugin/avro/FileState.java | 71 ++++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 125 ++++++++++------- .../gradle/plugin/avro/MapUtils.java | 18 +++ .../gradle/plugin/avro/ProcessingState.java | 99 +++++++++++++ .../gradle/plugin/avro/TypeState.java | 34 +++++ .../DuplicateHandlingFunctionalSpec.groovy | 131 ++++++++++++++++++ .../avro/EnumHandlingFunctionalSpec.groovy | 3 + .../gradle/plugin/avro/FunctionalSpec.groovy | 1 + .../plugin/avro/OptionsFunctionalSpec.groovy | 22 +++ .../gradle/plugin/avro/duplicate/Cat.avsc | 16 +++ .../gradle/plugin/avro/duplicate/Dog.avsc | 16 +++ .../gradle/plugin/avro/duplicate/Fish.avsc | 26 ++++ .../gradle/plugin/avro/duplicate/Person.avsc | 16 +++ .../gradle/plugin/avro/duplicate/Spider.avsc | 18 +++ 19 files changed, 579 insertions(+), 47 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/FileState.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Cat.avsc create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Dog.avsc create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Fish.avsc create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Person.avsc create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Spider.avsc diff --git a/CHANGES.md b/CHANGES.md index 33915872b12..5e34563d836 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## Unreleased * Remove usage of Apache Commons IO (#19) +* Add ability to retry duplicate type definitions, with new configuration option "retryDuplicateTypes" (#13) ## 0.6.1 * Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 9dd21f722dc..bcd306a0bdf 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -50,6 +50,12 @@ public Boolean call() throws Exception { return DEFAULT_CREATE_SETTERS; } }); + extensionMapping.map(OPTION_RETRY_DUPLICATE_TYPES, new Callable() { + @Override + public Boolean call() throws Exception { + return DEFAULT_RETRY_DUPLICATE_TYPES; + } + }); project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override public void execute(GenerateAvroJavaTask task) { @@ -84,6 +90,12 @@ public Boolean call() throws Exception { return avroExtension.isCreateSetters(); } }); + taskMapping.map(OPTION_RETRY_DUPLICATE_TYPES, new Callable() { + @Override + public Boolean call() throws Exception { + return avroExtension.isRetryDuplicateTypes(); + } + }); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index d7e38e57801..8355a434197 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -6,4 +6,5 @@ public interface AvroExtension { String getFieldVisibility(); String getTemplateDirectory(); boolean isCreateSetters(); + boolean isRetryDuplicateTypes(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index f2d2c57fa60..086ba41c130 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -18,6 +18,7 @@ class Constants { static final String DEFAULT_TEMPLATE_DIR = System.getProperty("org.apache.avro.specific.templates", "/org/apache/avro/compiler/specific/templates/java/classic/"); static final boolean DEFAULT_CREATE_SETTERS = true; + static final boolean DEFAULT_RETRY_DUPLICATE_TYPES = true; static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; @@ -33,4 +34,5 @@ class Constants { static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; static final String OPTION_ENCODING = "encoding"; + static final String OPTION_RETRY_DUPLICATE_TYPES = "retryDuplicateTypes"; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 1532f5b8b6c..88c44488fa3 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -6,6 +6,7 @@ public class DefaultAvroExtension implements AvroExtension { private String fieldVisibility; private String templateDirectory; private boolean createSetters; + private boolean retryDuplicateTypes; @Override public String getEncoding() { @@ -55,4 +56,17 @@ public void setCreateSetters(boolean createSetters) { public void setCreateSetters(String createSetters) { this.createSetters = Boolean.parseBoolean(createSetters); } + + @Override + public boolean isRetryDuplicateTypes() { + return retryDuplicateTypes; + } + + public void setRetryDuplicateTypes(boolean retryDuplicateTypes) { + this.retryDuplicateTypes = retryDuplicateTypes; + } + + public void setRetryDuplicateTypes(String retryDuplicateTypes) { + this.retryDuplicateTypes = Boolean.parseBoolean(retryDuplicateTypes); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java new file mode 100644 index 00000000000..6412a78b1fe --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java @@ -0,0 +1,71 @@ +package com.commercehub.gradle.plugin.avro; + +import java.io.File; +import java.util.Set; +import java.util.TreeSet; + +class FileState implements Comparable { + private final File file; + private final String path; + private String errorMessage; + private Set duplicateTypeNames = new TreeSet<>(); + + FileState(File file, String path) { + this.file = file; + this.path = path; + } + + File getFile() { + return file; + } + + Set getDuplicateTypeNames() { + return duplicateTypeNames; + } + + void clearError() { + errorMessage = null; + } + + void setError(Throwable ex) { + this.errorMessage = ex.getMessage(); + } + + void addDuplicateTypeName(String typeName) { + duplicateTypeNames.add(typeName); + } + + boolean isFailed() { + return errorMessage != null; + } + + public String getPath() { + return path; + } + + public String getErrorMessage() { + return errorMessage; + } + + @Override + public int compareTo(FileState o) { + return path.compareTo(o.getPath()); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FileState fileState = (FileState) o; + return path.equals(fileState.path); + } + + @Override + public int hashCode() { + return path.hashCode(); + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 4b528a1a774..e3642197ff7 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -14,9 +14,13 @@ import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static com.commercehub.gradle.plugin.avro.Constants.*; +import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; import static java.lang.System.lineSeparator; /** @@ -24,13 +28,16 @@ * {@link SpecificCompiler}. */ public class GenerateAvroJavaTask extends OutputDirTask { + private static Pattern ERROR_UNKNOWN_TYPE = Pattern.compile("(?i).*(undefined name|not a defined name).*"); + private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); - private String encoding = Constants.DEFAULT_ENCODING; - private String stringType = Constants.DEFAULT_STRING_TYPE; - private String fieldVisibility = Constants.DEFAULT_FIELD_VISIBILITY; + private String encoding = DEFAULT_ENCODING; + private String stringType = DEFAULT_STRING_TYPE; + private String fieldVisibility = DEFAULT_FIELD_VISIBILITY; private String templateDirectory = DEFAULT_TEMPLATE_DIR; private boolean createSetters = DEFAULT_CREATE_SETTERS; + private boolean retryDuplicateTypes = DEFAULT_RETRY_DUPLICATE_TYPES; private transient StringType parsedStringType; private transient FieldVisibility parsedFieldVisibility; @@ -72,7 +79,7 @@ public void setTemplateDirectory(String templateDirectory) { } @Input - public Boolean isCreateSetters() { + public boolean isCreateSetters() { return createSetters; } @@ -84,6 +91,19 @@ public void setCreateSetters(String createSetters) { this.createSetters = Boolean.parseBoolean(createSetters); } + @Input + public boolean isRetryDuplicateTypes() { + return retryDuplicateTypes; + } + + public void setRetryDuplicateTypes(boolean retryDuplicateTypes) { + this.retryDuplicateTypes = retryDuplicateTypes; + } + + public void setRetryDuplicateTypes(String retryDuplicateTypes) { + this.retryDuplicateTypes = Boolean.parseBoolean(retryDuplicateTypes); + } + @TaskAction protected void process() { parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); @@ -94,6 +114,7 @@ protected void process() { getLogger().debug("Using fieldVisibility {}", parsedFieldVisibility.name()); getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); getLogger().debug("Using createSetters {}", isCreateSetters()); + getLogger().debug("Using retryDuplicateTypes {}", isRetryDuplicateTypes()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -145,59 +166,69 @@ private void processProtoFile(File sourceFile) { } private int processSchemaFiles() { - int processedTotal = 0; - int processedThisPass = -1; - Map types = new HashMap<>(); - Map errors = new HashMap<>(); // file path to error message - Queue nextPass = new LinkedList<>(filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles()); - Queue thisPass = new LinkedList<>(); - while (processedThisPass != 0) { - if (processedThisPass > 0) { - processedTotal += processedThisPass; - } - processedThisPass = 0; - thisPass.addAll(nextPass); - nextPass.clear(); - File sourceFile = thisPass.poll(); - while (sourceFile != null) { - String path = getProject().relativePath(sourceFile); - getLogger().debug("Processing {}", path); - try { - Schema.Parser parser = new Schema.Parser(); - parser.addTypes(types); - compile(parser.parse(sourceFile), sourceFile); - types = parser.getTypes(); + Set files = filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles(); + ProcessingState processingState = new ProcessingState(files, getProject()); + while (processingState.isWorkRemaining()) { + FileState fileState = processingState.nextFileState(); + String path = fileState.getPath(); + getLogger().debug("Processing {}, excluding types {}", path, fileState.getDuplicateTypeNames()); + File sourceFile = fileState.getFile(); + Map parserTypes = processingState.determineParserTypes(fileState); + try { + Schema.Parser parser = new Schema.Parser(); + parser.addTypes(parserTypes); + compile(parser.parse(sourceFile), sourceFile); + Map typesDefinedInFile = asymmetricDifference(parser.getTypes(), parserTypes); + processingState.processTypeDefinitions(fileState, typesDefinedInFile); + if (getLogger().isDebugEnabled()) { + getLogger().debug("Processed {}; contained types {}", path, typesDefinedInFile.keySet()); + } else { getLogger().info("Processed {}", path); - processedThisPass++; - errors.remove(path); - } catch (SchemaParseException ex) { - String errorMessage = ex.getMessage(); - if (errorMessage.matches("(?i).*(undefined name|not a defined name).*")) { - getLogger().debug("Found undefined name in {} ({}); will try again later", path, errorMessage); - nextPass.add(sourceFile); - errors.put(path, ex.getMessage()); + } + } catch (SchemaParseException ex) { + String errorMessage = ex.getMessage(); + Matcher unknownTypeMatcher = ERROR_UNKNOWN_TYPE.matcher(errorMessage); + Matcher duplicateTypeMatcher = ERROR_DUPLICATE_TYPE.matcher(errorMessage); + if (unknownTypeMatcher.matches()) { + fileState.setError(ex); + processingState.queueForDelayedRetry(fileState); + getLogger().debug("Found undefined name in {} ({}); will try again", path, errorMessage); + } else if (duplicateTypeMatcher.matches()) { + String typeName = duplicateTypeMatcher.group(1); + if (isRetryDuplicateTypes()) { + fileState.setError(ex); + fileState.addDuplicateTypeName(typeName); + processingState.queueForImmediateRetry(fileState); + getLogger().debug("Identified duplicate type {} in {}; will re-process excluding it", typeName, path); } else { - throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); + throw new GradleException(String.format( + "Failed to compile schema definition file %s due to duplicate definition of type %s;" + + " This can be resolved by either declaring %s in its own schema file, or enabling the %s option", + path, typeName, typeName, OPTION_RETRY_DUPLICATE_TYPES), ex); } - } catch (NullPointerException ex) { - getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency);" - + " will try again later", path); - nextPass.add(sourceFile); - errors.put(path, ex.getMessage()); - } catch (IOException ex) { + } else { throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } - sourceFile = thisPass.poll(); + } catch (NullPointerException ex) { + fileState.setError(ex); + processingState.queueForDelayedRetry(fileState); + getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency);" + + " will try again", path); + } catch (IOException ex) { + throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } } - if (!nextPass.isEmpty()) { + Set failedFiles = processingState.getFailedFiles(); + if (!failedFiles.isEmpty()) { StringBuilder errorMessage = new StringBuilder("Could not compile schema definition files:"); - for (Map.Entry error : errors.entrySet()) { - errorMessage.append(lineSeparator()).append("* ").append(error.getKey()).append(": ").append(error.getValue()); + for (FileState fileState : failedFiles) { + String path = fileState.getPath(); + String fileErrorMessage = fileState.getErrorMessage(); + errorMessage.append(lineSeparator()).append("* ").append(path).append(": ").append(fileErrorMessage); } throw new GradleException(errorMessage.toString()); } - return processedTotal; + return processingState.getProcessedTotal(); } private void compile(Protocol protocol, File sourceFile) throws IOException { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java new file mode 100644 index 00000000000..af3133c36b9 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java @@ -0,0 +1,18 @@ +package com.commercehub.gradle.plugin.avro; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class MapUtils { + /** + * Returns the map of all entries present in the first map but not present in the second map (by key). + */ + static Map asymmetricDifference(Map a, Map b) { + if (b == null || b.isEmpty()) { + return a; + } + Map result = new LinkedHashMap<>(a); + result.keySet().removeAll(b.keySet()); + return result; + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java new file mode 100644 index 00000000000..a8205d74aa0 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -0,0 +1,99 @@ +package com.commercehub.gradle.plugin.avro; + +import org.apache.avro.Schema; +import org.gradle.api.Project; + +import java.io.File; +import java.util.*; + +class ProcessingState { + private final Set fileStates = new TreeSet<>(); + private final Map typeStates = new HashMap<>(); + private final Queue nextPass = new LinkedList<>(); + private final Queue thisPass = new LinkedList<>(); + private int processedTotal = 0; + private int processedThisPass = 0; + + ProcessingState(Set files, Project project) { + for (File file : files) { + fileStates.add(new FileState(file, project.relativePath(file))); + } + thisPass.addAll(fileStates); + } + + Map determineParserTypes(FileState fileState) { + Set duplicateTypeNames = fileState.getDuplicateTypeNames(); + Map types = new HashMap<>(); + for (TypeState typeState : typeStates.values()) { + String typeName = typeState.getName(); + if (!duplicateTypeNames.contains(typeName)) { + types.put(typeState.getName(), typeState.getSchema()); + } + } + return types; + } + + void processTypeDefinitions(FileState fileState, Map newTypes) { + String path = fileState.getPath(); + for (Map.Entry entry : newTypes.entrySet()) { + String typeName = entry.getKey(); + Schema schema = entry.getValue(); + getTypeState(typeName).processTypeDefinition(path, schema); + } + fileState.clearError(); + processedThisPass++; + processedTotal++; + } + + Set getFailedFiles() { + Set failedFiles = new LinkedHashSet<>(); + for (FileState fileState : fileStates) { + if (fileState.isFailed()) { + failedFiles.add(fileState); + } + } + return failedFiles; + } + + TypeState getTypeState(String typeName) { + TypeState typeState = typeStates.get(typeName); + if (typeState == null) { + typeState = new TypeState(typeName); + typeStates.put(typeName, typeState); + } + return typeState; + } + + void queueForImmediateRetry(FileState fileState) { + thisPass.add(fileState); + } + + void queueForDelayedRetry(FileState fileState) { + nextPass.add(fileState); + } + + FileState nextFileState() { + FileState fileState = thisPass.poll(); + if (fileState != null) { + return fileState; + } + nextPass(); + return thisPass.poll(); + } + + boolean isWorkRemaining() { + return !thisPass.isEmpty() || (processedThisPass > 0 && !nextPass.isEmpty()); + } + + int getProcessedTotal() { + return processedTotal; + } + + private void nextPass() { + if (processedThisPass > 0) { + thisPass.addAll(nextPass); + nextPass.clear(); + processedThisPass = 0; + } + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java new file mode 100644 index 00000000000..4d58c6ce706 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java @@ -0,0 +1,34 @@ +package com.commercehub.gradle.plugin.avro; + +import org.apache.avro.Schema; +import org.gradle.api.GradleException; + +import java.util.Set; +import java.util.TreeSet; + +class TypeState { + private final String name; + private final Set locations = new TreeSet<>(); + private Schema schema; + + TypeState(String name) { + this.name = name; + } + + void processTypeDefinition(String path, Schema schema) { + locations.add(path); + if (this.schema == null) { + this.schema = schema; + } else if (!this.schema.equals(schema)) { + throw new GradleException(String.format("Found conflicting definition of type %s in %s", name, locations)); + } // Otherwise duplicate declaration of identical schema; nothing to do + } + + String getName() { + return name; + } + + Schema getSchema() { + return schema; + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy new file mode 100644 index 00000000000..cf33088fa39 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -0,0 +1,131 @@ +package com.commercehub.gradle.plugin.avro + +import java.nio.file.Files + +import static org.gradle.testkit.runner.TaskOutcome.FAILED +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +/** + * Functional tests related to handling of duplicate type definitions. + * + *

This situation is generally encountered when schema files define records with inline record/enum definitions, and those inline types + * are used in more than one file.

+ */ +class DuplicateHandlingFunctionalSpec extends FunctionalSpec { + def "Duplicate enum definition fails if handling disabled"() { + given: + disableRetryDuplicateTypes() + copyIdenticalEnum() + + when: + def result = runAndFail() + + then: + result.task(":generateAvroJava").outcome == FAILED + result.standardError.contains("Failed to compile schema definition file src/main/avro/duplicate/Person.avsc" + + " due to duplicate definition of type example.Gender") + result.standardError.contains("This can be resolved by either declaring example.Gender in its own schema file," + + " or enabling the retryDuplicateTypes option") + } + + def "Duplicate record definition fails if handling disabled"() { + given: + disableRetryDuplicateTypes() + copyIdenticalRecord() + + when: + def result = runAndFail() + + then: + result.task(":generateAvroJava").outcome == FAILED + result.standardError.contains("Failed to compile schema definition file src/main/avro/duplicate/Person.avsc" + + " due to duplicate definition of type example.Person") + result.standardError.contains("This can be resolved by either declaring example.Person in its own schema file," + + " or enabling the retryDuplicateTypes option") + } + + + def "Duplicate enum definition succeeds if definition identical"() { + given: + copyIdenticalEnum() + + when: + def result = run() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/example/Person.class")) + Files.exists(projectPath("build/classes/main/example/Cat.class")) + Files.exists(projectPath("build/classes/main/example/Gender.class")) + } + + def "Duplicate record definition succeeds if definition identical"() { + given: + copyIdenticalRecord() + + when: + def result = run() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + Files.exists(projectPath("build/classes/main/example/Person.class")) + Files.exists(projectPath("build/classes/main/example/Fish.class")) + Files.exists(projectPath("build/classes/main/example/Gender.class")) + } + + def "Duplicate enum definition fails if definition differs"() { + given: + copyDifferentEnum() + + when: + def result = runAndFail() + + then: + result.task(":generateAvroJava").outcome == FAILED + result.standardError.contains("Found conflicting definition of type example.Gender in " + + "[src/main/avro/duplicate/Dog.avsc, src/main/avro/duplicate/Person.avsc]") + } + + def "Duplicate record definition fails if definition differs"() { + given: + copyDifferentRecord() + + when: + def result = runAndFail() + + then: + result.task(":generateAvroJava").outcome == FAILED + result.standardError.contains("Found conflicting definition of type example.Person in " + + "[src/main/avro/duplicate/Person.avsc, src/main/avro/duplicate/Spider.avsc]") + } + + private void disableRetryDuplicateTypes() { + buildFile << """ + avro { + retryDuplicateTypes = false + } + """ + } + + private void copyIdenticalEnum() { + copyResource("duplicate/Person.avsc", avroDir) + copyResource("duplicate/Cat.avsc", avroDir) + } + + private void copyDifferentEnum() { + copyResource("duplicate/Person.avsc", avroDir) + copyResource("duplicate/Dog.avsc", avroDir) + } + + private void copyIdenticalRecord() { + copyResource("duplicate/Person.avsc", avroDir) + copyResource("duplicate/Fish.avsc", avroDir) + } + + private void copyDifferentRecord() { + copyResource("duplicate/Person.avsc", avroDir) + copyResource("duplicate/Spider.avsc", avroDir) + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index 0867ec46cd4..a1240b43e74 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -4,6 +4,9 @@ import java.nio.file.Files import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +/** + * Functional tests relating to handling of enums. + */ class EnumHandlingFunctionalSpec extends FunctionalSpec { def "supports simple enums"() { given: diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 35fd1bca0d2..1557802d732 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -46,6 +46,7 @@ abstract class FunctionalSpec extends Specification { protected void copyResource(String name, File targetFolder) { def file = new File(targetFolder, name) + file.parentFile.mkdirs() file << getClass().getResourceAsStream(name) } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 00ce55d992b..5c8231050f0 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -140,6 +140,28 @@ class OptionsFunctionalSpec extends FunctionalSpec { "false" | false } + @Unroll + def "supports configuring retryDuplicateTypes to #retryDuplicateTypes"() { + given: + copyResource("duplicate/Person.avsc", avroDir) + copyResource("duplicate/Cat.avsc", avroDir) + buildFile << """ + |avro { + | retryDuplicateTypes = ${retryDuplicateTypes} + |} + |""".stripMargin() + + expect: + expectedSuccess ? run("generateAvroJava") : runAndFail("generateAvroJava") + + where: + retryDuplicateTypes | expectedSuccess + "Boolean.TRUE" | true + "Boolean.FALSE" | false + "true" | true + "false" | false + } + def "supports configuring templateDirectory"() { given: def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Cat.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Cat.avsc new file mode 100644 index 00000000000..cdf2c71b42a --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Cat.avsc @@ -0,0 +1,16 @@ +{ + "name": "Cat", + "namespace": "example", + "type": "record", + "fields": [ + { "name": "name", "type": "string" }, + { + "name": "gender", + "type": { + "name": "Gender", + "type": "enum", + "symbols": [ "MALE", "FEMALE", "OTHER" ] + } + } + ] +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Dog.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Dog.avsc new file mode 100644 index 00000000000..a206a724acb --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Dog.avsc @@ -0,0 +1,16 @@ +{ + "name": "Dog", + "namespace": "example", + "type": "record", + "fields": [ + { "name": "name", "type": "string" }, + { + "name": "gender", + "type": { + "name": "Gender", + "type": "enum", + "symbols": [ "MALE", "FEMALE" ] + } + } + ] +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Fish.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Fish.avsc new file mode 100644 index 00000000000..5f759351c23 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Fish.avsc @@ -0,0 +1,26 @@ +{ + "name": "Fish", + "namespace": "example", + "type": "record", + "fields": [ + { "name": "name", "type": "string" }, + { + "name": "owner", + "type": { + "name": "Person", + "type": "record", + "fields": [ + { "name": "name", "type": "string" }, + { + "name": "gender", + "type": { + "name": "Gender", + "type": "enum", + "symbols": [ "MALE", "FEMALE", "OTHER" ] + } + } + ] + } + } + ] +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Person.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Person.avsc new file mode 100644 index 00000000000..c9e5dc27229 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Person.avsc @@ -0,0 +1,16 @@ +{ + "name": "Person", + "namespace": "example", + "type": "record", + "fields": [ + { "name": "name", "type": "string" }, + { + "name": "gender", + "type": { + "name": "Gender", + "type": "enum", + "symbols": [ "MALE", "FEMALE", "OTHER" ] + } + } + ] +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Spider.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Spider.avsc new file mode 100644 index 00000000000..5ecc5334d75 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Spider.avsc @@ -0,0 +1,18 @@ +{ + "name": "Spider", + "namespace": "example", + "type": "record", + "fields": [ + { "name": "name", "type": "string" }, + { + "name": "owner", + "type": { + "name": "Person", + "type": "record", + "fields": [ + { "name": "name", "type": "string" } + ] + } + } + ] +} From e95b04b1f8db7cff91d99532c945bc43f1595696 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 09:29:22 -0400 Subject: [PATCH 085/479] Don't ignore gradle wrapper jar --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 7adeb75184b..caf72a94d98 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,6 @@ atlassian-ide-plugin.xml # NetBeans specific files/directories .nbattrs + +# Specifically include the gradle wrapper jar +!/gradle/wrapper/gradle-wrapper.jar From a53b3e6741840062604ec1faa6e41aabc437f43c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 09:50:34 -0400 Subject: [PATCH 086/479] Simplify processing queues --- .../plugin/avro/GenerateAvroJavaTask.java | 6 +-- .../gradle/plugin/avro/ProcessingState.java | 49 ++++++------------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index e3642197ff7..fecca35e5e0 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -191,14 +191,14 @@ private int processSchemaFiles() { Matcher duplicateTypeMatcher = ERROR_DUPLICATE_TYPE.matcher(errorMessage); if (unknownTypeMatcher.matches()) { fileState.setError(ex); - processingState.queueForDelayedRetry(fileState); + processingState.queueForDelayedProcessing(fileState); getLogger().debug("Found undefined name in {} ({}); will try again", path, errorMessage); } else if (duplicateTypeMatcher.matches()) { String typeName = duplicateTypeMatcher.group(1); if (isRetryDuplicateTypes()) { fileState.setError(ex); fileState.addDuplicateTypeName(typeName); - processingState.queueForImmediateRetry(fileState); + processingState.queueForProcessing(fileState); getLogger().debug("Identified duplicate type {} in {}; will re-process excluding it", typeName, path); } else { throw new GradleException(String.format( @@ -211,7 +211,7 @@ private int processSchemaFiles() { } } catch (NullPointerException ex) { fileState.setError(ex); - processingState.queueForDelayedRetry(fileState); + processingState.queueForDelayedProcessing(fileState); getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency);" + " will try again", path); } catch (IOException ex) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java index a8205d74aa0..c510481635e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -7,18 +7,15 @@ import java.util.*; class ProcessingState { - private final Set fileStates = new TreeSet<>(); private final Map typeStates = new HashMap<>(); - private final Queue nextPass = new LinkedList<>(); - private final Queue thisPass = new LinkedList<>(); + private final Set delayedFiles = new LinkedHashSet<>(); + private final Queue filesToProcess = new LinkedList<>(); private int processedTotal = 0; - private int processedThisPass = 0; ProcessingState(Set files, Project project) { for (File file : files) { - fileStates.add(new FileState(file, project.relativePath(file))); + filesToProcess.add(new FileState(file, project.relativePath(file))); } - thisPass.addAll(fileStates); } Map determineParserTypes(FileState fileState) { @@ -41,18 +38,12 @@ void processTypeDefinitions(FileState fileState, Map newTypes) { getTypeState(typeName).processTypeDefinition(path, schema); } fileState.clearError(); - processedThisPass++; processedTotal++; + queueDelayedFilesForProcessing(); } Set getFailedFiles() { - Set failedFiles = new LinkedHashSet<>(); - for (FileState fileState : fileStates) { - if (fileState.isFailed()) { - failedFiles.add(fileState); - } - } - return failedFiles; + return delayedFiles; } TypeState getTypeState(String typeName) { @@ -64,36 +55,28 @@ TypeState getTypeState(String typeName) { return typeState; } - void queueForImmediateRetry(FileState fileState) { - thisPass.add(fileState); + void queueForProcessing(FileState fileState) { + filesToProcess.add(fileState); + } + + void queueForDelayedProcessing(FileState fileState) { + delayedFiles.add(fileState); } - void queueForDelayedRetry(FileState fileState) { - nextPass.add(fileState); + private void queueDelayedFilesForProcessing() { + filesToProcess.addAll(delayedFiles); + delayedFiles.clear(); } FileState nextFileState() { - FileState fileState = thisPass.poll(); - if (fileState != null) { - return fileState; - } - nextPass(); - return thisPass.poll(); + return filesToProcess.poll(); } boolean isWorkRemaining() { - return !thisPass.isEmpty() || (processedThisPass > 0 && !nextPass.isEmpty()); + return !filesToProcess.isEmpty(); } int getProcessedTotal() { return processedTotal; } - - private void nextPass() { - if (processedThisPass > 0) { - thisPass.addAll(nextPass); - nextPass.clear(); - processedThisPass = 0; - } - } } From 3fa53ff88ec4692490247d4554a5b1dc61dd5309 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 11:05:48 -0400 Subject: [PATCH 087/479] Make duplicate retry behavior always-on; no configuration option to disable (#13) --- CHANGES.md | 2 +- .../gradle/plugin/avro/AvroBasePlugin.java | 12 -- .../gradle/plugin/avro/AvroExtension.java | 1 - .../gradle/plugin/avro/Constants.java | 2 - .../plugin/avro/DefaultAvroExtension.java | 14 --- .../plugin/avro/GenerateAvroJavaTask.java | 106 +++++++----------- .../DuplicateHandlingFunctionalSpec.groovy | 41 ------- 7 files changed, 44 insertions(+), 134 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5e34563d836..e45be7d0d64 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ ## Unreleased * Remove usage of Apache Commons IO (#19) -* Add ability to retry duplicate type definitions, with new configuration option "retryDuplicateTypes" (#13) +* Add ability to retry processing of duplicate type definitions (#13) ## 0.6.1 * Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index bcd306a0bdf..9dd21f722dc 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -50,12 +50,6 @@ public Boolean call() throws Exception { return DEFAULT_CREATE_SETTERS; } }); - extensionMapping.map(OPTION_RETRY_DUPLICATE_TYPES, new Callable() { - @Override - public Boolean call() throws Exception { - return DEFAULT_RETRY_DUPLICATE_TYPES; - } - }); project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override public void execute(GenerateAvroJavaTask task) { @@ -90,12 +84,6 @@ public Boolean call() throws Exception { return avroExtension.isCreateSetters(); } }); - taskMapping.map(OPTION_RETRY_DUPLICATE_TYPES, new Callable() { - @Override - public Boolean call() throws Exception { - return avroExtension.isRetryDuplicateTypes(); - } - }); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 8355a434197..d7e38e57801 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -6,5 +6,4 @@ public interface AvroExtension { String getFieldVisibility(); String getTemplateDirectory(); boolean isCreateSetters(); - boolean isRetryDuplicateTypes(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 086ba41c130..f2d2c57fa60 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -18,7 +18,6 @@ class Constants { static final String DEFAULT_TEMPLATE_DIR = System.getProperty("org.apache.avro.specific.templates", "/org/apache/avro/compiler/specific/templates/java/classic/"); static final boolean DEFAULT_CREATE_SETTERS = true; - static final boolean DEFAULT_RETRY_DUPLICATE_TYPES = true; static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; @@ -34,5 +33,4 @@ class Constants { static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; static final String OPTION_ENCODING = "encoding"; - static final String OPTION_RETRY_DUPLICATE_TYPES = "retryDuplicateTypes"; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 88c44488fa3..1532f5b8b6c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -6,7 +6,6 @@ public class DefaultAvroExtension implements AvroExtension { private String fieldVisibility; private String templateDirectory; private boolean createSetters; - private boolean retryDuplicateTypes; @Override public String getEncoding() { @@ -56,17 +55,4 @@ public void setCreateSetters(boolean createSetters) { public void setCreateSetters(String createSetters) { this.createSetters = Boolean.parseBoolean(createSetters); } - - @Override - public boolean isRetryDuplicateTypes() { - return retryDuplicateTypes; - } - - public void setRetryDuplicateTypes(boolean retryDuplicateTypes) { - this.retryDuplicateTypes = retryDuplicateTypes; - } - - public void setRetryDuplicateTypes(String retryDuplicateTypes) { - this.retryDuplicateTypes = Boolean.parseBoolean(retryDuplicateTypes); - } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index fecca35e5e0..2e67b0504d2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -37,7 +37,6 @@ public class GenerateAvroJavaTask extends OutputDirTask { private String fieldVisibility = DEFAULT_FIELD_VISIBILITY; private String templateDirectory = DEFAULT_TEMPLATE_DIR; private boolean createSetters = DEFAULT_CREATE_SETTERS; - private boolean retryDuplicateTypes = DEFAULT_RETRY_DUPLICATE_TYPES; private transient StringType parsedStringType; private transient FieldVisibility parsedFieldVisibility; @@ -91,19 +90,6 @@ public void setCreateSetters(String createSetters) { this.createSetters = Boolean.parseBoolean(createSetters); } - @Input - public boolean isRetryDuplicateTypes() { - return retryDuplicateTypes; - } - - public void setRetryDuplicateTypes(boolean retryDuplicateTypes) { - this.retryDuplicateTypes = retryDuplicateTypes; - } - - public void setRetryDuplicateTypes(String retryDuplicateTypes) { - this.retryDuplicateTypes = Boolean.parseBoolean(retryDuplicateTypes); - } - @TaskAction protected void process() { parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); @@ -114,7 +100,6 @@ protected void process() { getLogger().debug("Using fieldVisibility {}", parsedFieldVisibility.name()); getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); getLogger().debug("Using createSetters {}", isCreateSetters()); - getLogger().debug("Using retryDuplicateTypes {}", isRetryDuplicateTypes()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -169,54 +154,7 @@ private int processSchemaFiles() { Set files = filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles(); ProcessingState processingState = new ProcessingState(files, getProject()); while (processingState.isWorkRemaining()) { - FileState fileState = processingState.nextFileState(); - String path = fileState.getPath(); - getLogger().debug("Processing {}, excluding types {}", path, fileState.getDuplicateTypeNames()); - File sourceFile = fileState.getFile(); - Map parserTypes = processingState.determineParserTypes(fileState); - try { - Schema.Parser parser = new Schema.Parser(); - parser.addTypes(parserTypes); - compile(parser.parse(sourceFile), sourceFile); - Map typesDefinedInFile = asymmetricDifference(parser.getTypes(), parserTypes); - processingState.processTypeDefinitions(fileState, typesDefinedInFile); - if (getLogger().isDebugEnabled()) { - getLogger().debug("Processed {}; contained types {}", path, typesDefinedInFile.keySet()); - } else { - getLogger().info("Processed {}", path); - } - } catch (SchemaParseException ex) { - String errorMessage = ex.getMessage(); - Matcher unknownTypeMatcher = ERROR_UNKNOWN_TYPE.matcher(errorMessage); - Matcher duplicateTypeMatcher = ERROR_DUPLICATE_TYPE.matcher(errorMessage); - if (unknownTypeMatcher.matches()) { - fileState.setError(ex); - processingState.queueForDelayedProcessing(fileState); - getLogger().debug("Found undefined name in {} ({}); will try again", path, errorMessage); - } else if (duplicateTypeMatcher.matches()) { - String typeName = duplicateTypeMatcher.group(1); - if (isRetryDuplicateTypes()) { - fileState.setError(ex); - fileState.addDuplicateTypeName(typeName); - processingState.queueForProcessing(fileState); - getLogger().debug("Identified duplicate type {} in {}; will re-process excluding it", typeName, path); - } else { - throw new GradleException(String.format( - "Failed to compile schema definition file %s due to duplicate definition of type %s;" - + " This can be resolved by either declaring %s in its own schema file, or enabling the %s option", - path, typeName, typeName, OPTION_RETRY_DUPLICATE_TYPES), ex); - } - } else { - throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); - } - } catch (NullPointerException ex) { - fileState.setError(ex); - processingState.queueForDelayedProcessing(fileState); - getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency);" - + " will try again", path); - } catch (IOException ex) { - throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); - } + processSchemaFile(processingState, processingState.nextFileState()); } Set failedFiles = processingState.getFailedFiles(); if (!failedFiles.isEmpty()) { @@ -231,6 +169,48 @@ private int processSchemaFiles() { return processingState.getProcessedTotal(); } + private void processSchemaFile(ProcessingState processingState, FileState fileState) { + String path = fileState.getPath(); + getLogger().debug("Processing {}, excluding types {}", path, fileState.getDuplicateTypeNames()); + File sourceFile = fileState.getFile(); + Map parserTypes = processingState.determineParserTypes(fileState); + try { + Schema.Parser parser = new Schema.Parser(); + parser.addTypes(parserTypes); + compile(parser.parse(sourceFile), sourceFile); + Map typesDefinedInFile = asymmetricDifference(parser.getTypes(), parserTypes); + processingState.processTypeDefinitions(fileState, typesDefinedInFile); + if (getLogger().isDebugEnabled()) { + getLogger().debug("Processed {}; contained types {}", path, typesDefinedInFile.keySet()); + } else { + getLogger().info("Processed {}", path); + } + } catch (SchemaParseException ex) { + String errorMessage = ex.getMessage(); + Matcher unknownTypeMatcher = ERROR_UNKNOWN_TYPE.matcher(errorMessage); + Matcher duplicateTypeMatcher = ERROR_DUPLICATE_TYPE.matcher(errorMessage); + if (unknownTypeMatcher.matches()) { + fileState.setError(ex); + processingState.queueForDelayedProcessing(fileState); + getLogger().debug("Found undefined name in {} ({}); will try again", path, errorMessage); + } else if (duplicateTypeMatcher.matches()) { + String typeName = duplicateTypeMatcher.group(1); + fileState.setError(ex); + fileState.addDuplicateTypeName(typeName); + processingState.queueForProcessing(fileState); + getLogger().debug("Identified duplicate type {} in {}; will re-process excluding it", typeName, path); + } else { + throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); + } + } catch (NullPointerException ex) { + fileState.setError(ex); + processingState.queueForDelayedProcessing(fileState); + getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency); will try again", path); + } catch (IOException ex) { + throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); + } + } + private void compile(Protocol protocol, File sourceFile) throws IOException { compile(new SpecificCompiler(protocol), sourceFile); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index cf33088fa39..0349990ff6c 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -12,39 +12,6 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS * are used in more than one file.

*/ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { - def "Duplicate enum definition fails if handling disabled"() { - given: - disableRetryDuplicateTypes() - copyIdenticalEnum() - - when: - def result = runAndFail() - - then: - result.task(":generateAvroJava").outcome == FAILED - result.standardError.contains("Failed to compile schema definition file src/main/avro/duplicate/Person.avsc" - + " due to duplicate definition of type example.Gender") - result.standardError.contains("This can be resolved by either declaring example.Gender in its own schema file," - + " or enabling the retryDuplicateTypes option") - } - - def "Duplicate record definition fails if handling disabled"() { - given: - disableRetryDuplicateTypes() - copyIdenticalRecord() - - when: - def result = runAndFail() - - then: - result.task(":generateAvroJava").outcome == FAILED - result.standardError.contains("Failed to compile schema definition file src/main/avro/duplicate/Person.avsc" - + " due to duplicate definition of type example.Person") - result.standardError.contains("This can be resolved by either declaring example.Person in its own schema file," - + " or enabling the retryDuplicateTypes option") - } - - def "Duplicate enum definition succeeds if definition identical"() { given: copyIdenticalEnum() @@ -101,14 +68,6 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { + "[src/main/avro/duplicate/Person.avsc, src/main/avro/duplicate/Spider.avsc]") } - private void disableRetryDuplicateTypes() { - buildFile << """ - avro { - retryDuplicateTypes = false - } - """ - } - private void copyIdenticalEnum() { copyResource("duplicate/Person.avsc", avroDir) copyResource("duplicate/Cat.avsc", avroDir) From 42c4c3660802cf558644f6bded10554a2c713908 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 13:38:07 -0400 Subject: [PATCH 088/479] Update readme --- README.md | 99 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index f5a841f7976..ecc53e931f3 100644 --- a/README.md +++ b/README.md @@ -34,68 +34,110 @@ buildscript { apply plugin: "com.commercehub.gradle.plugin.avro" ``` -Optionally, configure the string type to `charSequence`, `string` (the default), or `utf8`. +Additionally, ensure that you have a compile dependency on Avro, such as: ```groovy -avro { - stringType = "string" +repositories { + jcenter() +} +dependencies { + compile "org.apache.avro:avro:1.7.7" } ``` -Optionally, you can also configure the output character encoding (default `UTF-8`). +If you now run `gradle build`, Java classes will be compiled from Avro files in `src/main/avro`. +Actually, it will attempt to process an "avro" directory in every `SourceSet` (main, test, etc.) + +# Configuration + +There are a number of configuration options supported in the `avro` block. + +| option | default | description | +| ----------------- | --------------------- | ------------------------------------------------- | +| createSetters | `true` | `createSetters` passed to Avro compiler | +| encoding | `"UTF-8"` | `outputCharacterEncoding` passed to Avro compiler | +| fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | +| stringType | `"String"` | `stringType` passed to Avro compiler | +| templateDirectory | see below | `templateDir` passed to Avro compiler | + +## createSetters + +Valid values: `true` (default), `false` + +Set to `false` to not create setter methods in the generated classes. + +Example: ```groovy avro { - encoding = "UTF-8" + createSetters = false } ``` -Optionally, you can also configure the visibility of generated fields to `PRIVATE`, `PUBLIC_DEPRECATED` (the default) -or `PUBLIC`. +## encoding + +Valid values: any charset name supported by [Charset](http://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html), default `"UTF-8"` + +By default, the plugin will output generated Java files in UTF-8. +If desired, you can specify an alternate encoding. + +Example: ```groovy avro { - fieldVisibility = "PRIVATE" + encoding = "UTF-8" } ``` -Optionally, you can also configure the source directory for the Velocity templates that the Avro compiler uses to -generate Java files. +## fieldVisibility + +Valid values (matched case-insensitively): `"PUBLIC"`, `"PUBLIC_DEPRECATED"` (default), `"PRIVATE"` + +By default, the fields in generated Java files will have public visibility and be annotated with `@Deprecated`. +Set to `"PRIVATE"` to restrict visibility of the fields, or `"PUBLIC"` to remove the `@Deprecated` annotations. + +Example: ```groovy avro { - templateDirectory = "/path/to/velocity/templates" + fieldVisibility = "PRIVATE" } ``` -Optionally, you can suppress the creation of setter methods in created domain objects. +## stringType + +Valid values (matched case-insensitively): `"CharSequence"`, `"String"` (default), `"Utf8"` + +By default, the generated Java files will use [`java.lang.String`](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html) to represent string types. +Alternatively, you can set it to `"Utf8"` to use [`org.apache.avro.util.Utf8`](https://avro.apache.org/docs/1.7.7/api/java/org/apache/avro/util/Utf8.html) or `"charSequence"` to use [`java.lang.CharSequence`](http://docs.oracle.com/javase/7/docs/api/java/lang/CharSequence.html). ```groovy avro { - createSetters = false + stringType = "CharSequence" } ``` -Additionally, ensure that you have a compile dependency on Avro, such as: +## templateDirectory + +By default, files will be generated using Avro's default templates. +If desired, you can override the template set used by either setting this property or the `"org.apache.avro.specific.templates"` System property. ```groovy -repositories { - jcenter() -} -dependencies { - compile "org.apache.avro:avro:1.7.7" +avro { + templateDirectory = "/path/to/velocity/templates" } ``` -If you now run `gradle build`, Java classes will be compiled from Avro files in `src/main/avro`. Actually, it will attempt to process an "avro" directory in every `SourceSet` (main, test, etc.) - # IntelliJ Integration -The plugin attempts to make IntelliJ play more smoothly with generated sources when using Gradle-generated project files. However, there are still some rough edges. It will work best if you first run `gradle build`, and _after_ that run `gradle idea`. If you do it in the other order, IntelliJ may not properly exclude some directories within your `build` directory. +The plugin attempts to make IntelliJ play more smoothly with generated sources when using Gradle-generated project files. +However, there are still some rough edges. It will work best if you first run `gradle build`, and _after_ that run `gradle idea`. +If you do it in the other order, IntelliJ may not properly exclude some directories within your `build` directory. # Alternate Usage -If the defaults used by the plugin don't work for you, you can still use the tasks by themselves. In this case, use the "com.commercehub.gradle.plugin.avro" plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. +If the defaults used by the plugin don't work for you, you can still use the tasks by themselves. +In this case, use the "com.commercehub.gradle.plugin.avro" plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. Here's a short example of what this might look like: @@ -115,9 +157,12 @@ task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) compileJava.source(generateAvro.outputs) ``` -# Handling dependencies +# File Processing -If you have record/enum/fixed types that are referenced in other record types, just define the shared type in a separate file rather than inline in the definition of each record type that uses it. The plugin will automatically recognize the dependency and compile the files in the correct order. For example, instead of `Cat.avsc`: +When using this plugin, it is recommended to define each record/enum/fixed type in its own file rather than using inline type definitions. +This approach allows defining any type of schema structure, and eliminates the potential for conflicting definitions of a type between multiple files. +The plugin will automatically recognize the dependency and compile the files in the correct order. +For example, instead of `Cat.avsc`: ```json { @@ -163,3 +208,7 @@ and `Cat.avsc`: ] } ``` + +There may be cases where the schema files contain inline type definitions and it is undesirable to modify them. +In this case, the plugin will automatically recognize any duplicate type definitions and check if they match. +If any conflicts are identified, it will cause a build failure. From 89e51791006f0f0c998237b255a5eecb71b56ee4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 13:42:38 -0400 Subject: [PATCH 089/479] Remove test for removed retryDuplicateTypes configuration option --- .../plugin/avro/OptionsFunctionalSpec.groovy | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 5c8231050f0..00ce55d992b 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -140,28 +140,6 @@ class OptionsFunctionalSpec extends FunctionalSpec { "false" | false } - @Unroll - def "supports configuring retryDuplicateTypes to #retryDuplicateTypes"() { - given: - copyResource("duplicate/Person.avsc", avroDir) - copyResource("duplicate/Cat.avsc", avroDir) - buildFile << """ - |avro { - | retryDuplicateTypes = ${retryDuplicateTypes} - |} - |""".stripMargin() - - expect: - expectedSuccess ? run("generateAvroJava") : runAndFail("generateAvroJava") - - where: - retryDuplicateTypes | expectedSuccess - "Boolean.TRUE" | true - "Boolean.FALSE" | false - "true" | true - "false" | false - } - def "supports configuring templateDirectory"() { given: def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") From 5aead6f350f9398dc99833eb641ad67a909ef020 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 14:11:47 -0400 Subject: [PATCH 090/479] Support snapshots for development testing --- RELEASING.md | 3 ++- build.gradle | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index a452f8710c3..e108e11fd02 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -3,9 +3,10 @@ 1. Check that you've followed the setup steps listed [here](https://plugins.gradle.org/docs/submit) 1. Update `CHANGES.md` 1. Ensure that there is a milestone for the version, and that appropriate issues are associated with the milestone. -1. Update the plugin version in `build.gradle` under "pluginBundle/version" +1. Update the plugin version in `build.gradle` under "version" 1. Commit and tag with the version number 1. Run `./gradlew clean build publishPlugins` +1. Update the version the next SNAPSHOT and commit. 1. Push 1. If there was a issue requesting the release, close it. 1. Close the milestone. diff --git a/build.gradle b/build.gradle index a80fbf0197b..ff03a5ff652 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ plugins { id "checkstyle" id "codenarc" id "idea" + id "maven" id "com.gradle.plugin-publish" version "0.9.1" } @@ -20,12 +21,14 @@ dependencies { sourceCompatibility = 1.7 +version = "0.7.0-SNAPSHOT" +group = "com.commercehub.gradle.plugin" + pluginBundle { website = "https://github.com/commercehub-oss/gradle-avro-plugin" vcsUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." tags = ["serialization", "avro"] - version = "0.6.1" plugins { avro { id = "com.commercehub.gradle.plugin.avro" From 1b6791a8344100761635726ee82e35f743bd4d4d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 15:40:11 -0400 Subject: [PATCH 091/479] Rename "encoding" option to "outputCharacterEncoding", allow using java objects for most settings, fix string createSetters arguments --- CHANGES.md | 5 +++ README.md | 38 ++++++++-------- import-control.xml | 1 + .../gradle/plugin/avro/AvroBasePlugin.java | 8 ++-- .../gradle/plugin/avro/AvroExtension.java | 2 +- .../gradle/plugin/avro/Constants.java | 4 +- .../plugin/avro/DefaultAvroExtension.java | 31 +++++++++---- .../plugin/avro/GenerateAvroJavaTask.java | 32 +++++++++----- .../plugin/avro/OptionsFunctionalSpec.groovy | 44 ++++++++++++------- 9 files changed, 102 insertions(+), 63 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e45be7d0d64..f467521a507 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,11 @@ ## Unreleased * Remove usage of Apache Commons IO (#19) * Add ability to retry processing of duplicate type definitions (#13) +* Renamed "encoding" option to "outputCharacterEncoding" to match Avro compiler +* Allowed setting "outputCharacterEncoding" to a `java.nio.charset.Charset` (in addition to a `String` charset name) +* Allowed setting "stringType" to a `org.apache.avro.generic.GenericData.StringType` (in addition to a String) +* Allowed setting "fieldVisibility" to a `org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility` (in addition to a String) +* Fixed handling of non-"true" String settings for "createSetters" option ## 0.6.1 * Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. diff --git a/README.md b/README.md index ecc53e931f3..7e5d69e4e6f 100644 --- a/README.md +++ b/README.md @@ -52,17 +52,17 @@ Actually, it will attempt to process an "avro" directory in every `SourceSet` (m There are a number of configuration options supported in the `avro` block. -| option | default | description | -| ----------------- | --------------------- | ------------------------------------------------- | -| createSetters | `true` | `createSetters` passed to Avro compiler | -| encoding | `"UTF-8"` | `outputCharacterEncoding` passed to Avro compiler | -| fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | -| stringType | `"String"` | `stringType` passed to Avro compiler | -| templateDirectory | see below | `templateDir` passed to Avro compiler | +| option | default | description | +| ----------------------- | --------------------- | ------------------------------------------------- | +| createSetters | `true` | `createSetters` passed to Avro compiler | +| fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | +| outputCharacterEncoding | `"UTF-8"` | `outputCharacterEncoding` passed to Avro compiler | +| stringType | `"String"` | `stringType` passed to Avro compiler | +| templateDirectory | see below | `templateDir` passed to Avro compiler | ## createSetters -Valid values: `true` (default), `false` +Valid values: `true` (default), `false`; supports equivalent `String` values Set to `false` to not create setter methods in the generated classes. @@ -74,39 +74,39 @@ avro { } ``` -## encoding +## fieldVisibility -Valid values: any charset name supported by [Charset](http://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html), default `"UTF-8"` +Valid values: any [FieldVisibility](http://avro.apache.org/docs/1.7.7/api/java/org/apache/avro/compiler/specific/SpecificCompiler.FieldVisibility.html) or equivalent `String` name (matched case-insensitively); default `"PUBLIC_DEPRECATED"` (default) -By default, the plugin will output generated Java files in UTF-8. -If desired, you can specify an alternate encoding. +By default, the fields in generated Java files will have public visibility and be annotated with `@Deprecated`. +Set to `"PRIVATE"` to restrict visibility of the fields, or `"PUBLIC"` to remove the `@Deprecated` annotations. Example: ```groovy avro { - encoding = "UTF-8" + fieldVisibility = "PRIVATE" } ``` -## fieldVisibility +## outputCharacterEncoding -Valid values (matched case-insensitively): `"PUBLIC"`, `"PUBLIC_DEPRECATED"` (default), `"PRIVATE"` +Valid values: any [Charset](http://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html) or equivalent `String` name, default `"UTF-8"` -By default, the fields in generated Java files will have public visibility and be annotated with `@Deprecated`. -Set to `"PRIVATE"` to restrict visibility of the fields, or `"PUBLIC"` to remove the `@Deprecated` annotations. +By default, the plugin will output generated Java files in UTF-8. +If desired, you can specify an alternate encoding. Example: ```groovy avro { - fieldVisibility = "PRIVATE" + outputCharacterEncoding = "UTF-8" } ``` ## stringType -Valid values (matched case-insensitively): `"CharSequence"`, `"String"` (default), `"Utf8"` +Valid values: any [StringType](http://avro.apache.org/docs/1.7.7/api/java/org/apache/avro/generic/GenericData.StringType.html) or equivalent `String` name (matched case-insensitively); default `"String"` (default) By default, the generated Java files will use [`java.lang.String`](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html) to represent string types. Alternatively, you can set it to `"Utf8"` to use [`org.apache.avro.util.Utf8`](https://avro.apache.org/docs/1.7.7/api/java/org/apache/avro/util/Utf8.html) or `"charSequence"` to use [`java.lang.CharSequence`](http://docs.oracle.com/javase/7/docs/api/java/lang/CharSequence.html). diff --git a/import-control.xml b/import-control.xml index 3a6efb0794e..6cb25369756 100644 --- a/import-control.xml +++ b/import-control.xml @@ -7,6 +7,7 @@ + diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 9dd21f722dc..f1f615ee0ff 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -19,10 +19,10 @@ public void apply(final Project project) { private static void configureExtension(final Project project) { final AvroExtension avroExtension = project.getExtensions().create(AVRO_EXTENSION_NAME, DefaultAvroExtension.class); ConventionMapping extensionMapping = conventionMapping(avroExtension); - extensionMapping.map(OPTION_ENCODING, new Callable() { + extensionMapping.map(OPTION_OUTPUT_CHARACTER_ENCODING, new Callable() { @Override public String call() throws Exception { - return DEFAULT_ENCODING; + return DEFAULT_OUTPUT_CHARACTER_ENCODING; } }); extensionMapping.map(OPTION_STRING_TYPE, new Callable() { @@ -54,10 +54,10 @@ public Boolean call() throws Exception { @Override public void execute(GenerateAvroJavaTask task) { ConventionMapping taskMapping = conventionMapping(task); - taskMapping.map(OPTION_ENCODING, new Callable() { + taskMapping.map(OPTION_OUTPUT_CHARACTER_ENCODING, new Callable() { @Override public String call() throws Exception { - return avroExtension.getEncoding(); + return avroExtension.getOutputCharacterEncoding(); } }); taskMapping.map(OPTION_STRING_TYPE, new Callable() { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index d7e38e57801..17ec54be45e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -1,7 +1,7 @@ package com.commercehub.gradle.plugin.avro; public interface AvroExtension { - String getEncoding(); + String getOutputCharacterEncoding(); String getStringType(); String getFieldVisibility(); String getTemplateDirectory(); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index f2d2c57fa60..b6ce1391c32 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -12,7 +12,7 @@ class Constants { static final String UTF8_ENCODING = "UTF-8"; - static final String DEFAULT_ENCODING = UTF8_ENCODING; + static final String DEFAULT_OUTPUT_CHARACTER_ENCODING = UTF8_ENCODING; static final String DEFAULT_STRING_TYPE = StringType.String.name(); static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); static final String DEFAULT_TEMPLATE_DIR = System.getProperty("org.apache.avro.specific.templates", @@ -32,5 +32,5 @@ class Constants { static final String OPTION_TEMPLATE_DIRECTORY = "templateDirectory"; static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; - static final String OPTION_ENCODING = "encoding"; + static final String OPTION_OUTPUT_CHARACTER_ENCODING = "outputCharacterEncoding"; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 1532f5b8b6c..310c52c9464 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -1,19 +1,28 @@ package com.commercehub.gradle.plugin.avro; +import org.apache.avro.compiler.specific.SpecificCompiler; +import org.apache.avro.generic.GenericData; + +import java.nio.charset.Charset; + public class DefaultAvroExtension implements AvroExtension { - private String encoding; + private String outputCharacterEncoding; private String stringType; private String fieldVisibility; private String templateDirectory; private boolean createSetters; @Override - public String getEncoding() { - return encoding; + public String getOutputCharacterEncoding() { + return outputCharacterEncoding; } - public void setEncoding(String encoding) { - this.encoding = encoding; + public void setOutputCharacterEncoding(String outputCharacterEncoding) { + this.outputCharacterEncoding = outputCharacterEncoding; + } + + public void setOutputCharacterEncoding(Charset outputCharacterEncoding) { + setOutputCharacterEncoding(outputCharacterEncoding.name()); } @Override @@ -25,6 +34,10 @@ public void setStringType(String stringType) { this.stringType = stringType; } + public void setStringType(GenericData.StringType stringType) { + setStringType(stringType.name()); + } + @Override public String getFieldVisibility() { return fieldVisibility; @@ -34,6 +47,10 @@ public void setFieldVisibility(String fieldVisibility) { this.fieldVisibility = fieldVisibility; } + public void setFieldVisibility(SpecificCompiler.FieldVisibility fieldVisibility) { + setFieldVisibility(fieldVisibility.name()); + } + @Override public String getTemplateDirectory() { return templateDirectory; @@ -48,10 +65,6 @@ public boolean isCreateSetters() { return createSetters; } - public void setCreateSetters(boolean createSetters) { - this.createSetters = createSetters; - } - public void setCreateSetters(String createSetters) { this.createSetters = Boolean.parseBoolean(createSetters); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 2e67b0504d2..90d3bf87094 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -5,6 +5,7 @@ import org.apache.avro.SchemaParseException; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; +import org.apache.avro.generic.GenericData; import org.apache.avro.generic.GenericData.StringType; import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; @@ -14,6 +15,7 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.Charset; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; @@ -32,7 +34,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); - private String encoding = DEFAULT_ENCODING; + private String outputCharacterEncoding = DEFAULT_OUTPUT_CHARACTER_ENCODING; private String stringType = DEFAULT_STRING_TYPE; private String fieldVisibility = DEFAULT_FIELD_VISIBILITY; private String templateDirectory = DEFAULT_TEMPLATE_DIR; @@ -42,12 +44,16 @@ public class GenerateAvroJavaTask extends OutputDirTask { private transient FieldVisibility parsedFieldVisibility; @Input - public String getEncoding() { - return encoding; + public String getOutputCharacterEncoding() { + return outputCharacterEncoding; } - public void setEncoding(String encoding) { - this.encoding = encoding; + public void setOutputCharacterEncoding(String outputCharacterEncoding) { + this.outputCharacterEncoding = outputCharacterEncoding; + } + + public void setOutputCharacterEncoding(Charset outputCharacterEncoding) { + setOutputCharacterEncoding(outputCharacterEncoding.name()); } @Input @@ -55,6 +61,10 @@ public String getStringType() { return stringType; } + public void setStringType(GenericData.StringType stringType) { + setStringType(stringType.name()); + } + public void setStringType(String stringType) { this.stringType = stringType; } @@ -68,6 +78,10 @@ public void setFieldVisibility(String fieldVisibility) { this.fieldVisibility = fieldVisibility; } + public void setFieldVisibility(SpecificCompiler.FieldVisibility fieldVisibility) { + setFieldVisibility(fieldVisibility.name()); + } + @Input public String getTemplateDirectory() { return templateDirectory; @@ -82,10 +96,6 @@ public boolean isCreateSetters() { return createSetters; } - public void setCreateSetters(boolean createSetters) { - this.createSetters = createSetters; - } - public void setCreateSetters(String createSetters) { this.createSetters = Boolean.parseBoolean(createSetters); } @@ -95,7 +105,7 @@ protected void process() { parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); parsedFieldVisibility = Enums.parseCaseInsensitive(OPTION_FIELD_VISIBILITY, FieldVisibility.values(), getFieldVisibility()); - getLogger().debug("Using encoding {}", getEncoding()); + getLogger().debug("Using outputCharacterEncoding {}", getOutputCharacterEncoding()); getLogger().debug("Using stringType {}", parsedStringType.name()); getLogger().debug("Using fieldVisibility {}", parsedFieldVisibility.name()); getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); @@ -220,7 +230,7 @@ private void compile(Schema schema, File sourceFile) throws IOException { } private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { - compiler.setOutputCharacterEncoding(getEncoding()); + compiler.setOutputCharacterEncoding(getOutputCharacterEncoding()); compiler.setStringType(parsedStringType); compiler.setFieldVisibility(parsedFieldVisibility); compiler.setTemplateDir(getTemplateDirectory()); diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 00ce55d992b..86342d1133a 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -4,7 +4,9 @@ import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility import org.apache.avro.generic.GenericData.StringType import spock.lang.Unroll -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENCODING +import java.nio.charset.StandardCharsets + +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_OUTPUT_CHARACTER_ENCODING import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -20,7 +22,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { result.task(":generateAvroJava").outcome == SUCCESS and: "the encoding is the default" - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) and: "the stringType is string" content.contains("public java.lang.String getName()") @@ -35,13 +37,12 @@ class OptionsFunctionalSpec extends FunctionalSpec { content.contains("public void setName(java.lang.String value)") } - def "supports configuring encoding"() { + def "supports configuring outputCharacterEncoding to #outputCharacterEncoding"() { given: - def encoding = "UTF-16" copyResource("user.avsc", avroDir) buildFile << """ |avro { - | encoding = "${encoding}" + | outputCharacterEncoding = ${outputCharacterEncoding} |} |""".stripMargin() @@ -52,7 +53,13 @@ class OptionsFunctionalSpec extends FunctionalSpec { result.task(":generateAvroJava").outcome == SUCCESS and: "the specified encoding is used" - projectPath("build/generated-main-avro-java/example/avro/User.java").getText(encoding) + projectPath("build/generated-main-avro-java/example/avro/User.java").getText(expectedEncoding) + + where: + outputCharacterEncoding | expectedEncoding + "'UTF-16'" | "UTF-16" + "'utf-32'" | "UTF-32" + "${StandardCharsets.name}.UTF_16" | "UTF-16" } @Unroll @@ -61,7 +68,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { copyResource("user.avsc", avroDir) buildFile << """ |avro { - | stringType = "${stringType}" + | stringType = ${stringType} |} |""".stripMargin() @@ -70,18 +77,19 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) and: "the specified stringType is used" content.contains(expectedContent) where: - stringType | expectedContent - StringType.String.name() | "public java.lang.String getName()" - StringType.CharSequence.name() | "public java.lang.CharSequence getName()" - StringType.Utf8.name() | "public org.apache.avro.util.Utf8 getName()" - StringType.Utf8.name().toUpperCase() | "public org.apache.avro.util.Utf8 getName()" - StringType.Utf8.name().toLowerCase() | "public org.apache.avro.util.Utf8 getName()" + stringType | expectedContent + "'${StringType.String.name()}'" | "public java.lang.String getName()" + "'${StringType.CharSequence.name()}'" | "public java.lang.CharSequence getName()" + "'${StringType.Utf8.name()}'" | "public org.apache.avro.util.Utf8 getName()" + "'${StringType.Utf8.name().toUpperCase()}'" | "public org.apache.avro.util.Utf8 getName()" + "'${StringType.Utf8.name().toLowerCase()}'" | "public org.apache.avro.util.Utf8 getName()" + "${StringType.name}.${StringType.Utf8.name()}" | "public org.apache.avro.util.Utf8 getName()" } @Unroll @@ -99,7 +107,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) and: "the specified fieldVisibility is used" content.contains(expectedContent) @@ -127,7 +135,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) and: "the specified createSetters is used" content.contains("public void setName(java.lang.String value)") == expectedPresent @@ -138,6 +146,8 @@ class OptionsFunctionalSpec extends FunctionalSpec { "Boolean.FALSE" | false "true" | true "false" | false + "'true'" | true + "'false'" | false } def "supports configuring templateDirectory"() { @@ -161,7 +171,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) and: "the specified templates are used" content.contains("Custom template") From 41516e971431db5dd9b60720500ea9620dd2e8af Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 15:40:20 -0400 Subject: [PATCH 092/479] Remove unused method --- .../java/com/commercehub/gradle/plugin/avro/FileState.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java index 6412a78b1fe..974f28b2281 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java @@ -35,10 +35,6 @@ void addDuplicateTypeName(String typeName) { duplicateTypeNames.add(typeName); } - boolean isFailed() { - return errorMessage != null; - } - public String getPath() { return path; } From eb678f8a6fc73a36b559d6f793368af7b6bd2212 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Oct 2015 16:17:41 -0400 Subject: [PATCH 093/479] Automatically use encoding from `JavaCompile` task as "outputCharacterEncoding", if set --- CHANGES.md | 1 + README.md | 16 ++++-- .../gradle/plugin/avro/AvroPlugin.java | 50 +++++++++++++------ .../plugin/avro/OptionsFunctionalSpec.groovy | 22 +++++++- 4 files changed, 69 insertions(+), 20 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f467521a507..86565d19cb0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ * Allowed setting "stringType" to a `org.apache.avro.generic.GenericData.StringType` (in addition to a String) * Allowed setting "fieldVisibility" to a `org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility` (in addition to a String) * Fixed handling of non-"true" String settings for "createSetters" option +* Automatically use encoding from `JavaCompile` task as "outputCharacterEncoding", if set ## 0.6.1 * Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. diff --git a/README.md b/README.md index 7e5d69e4e6f..c634c7fdf96 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ There are a number of configuration options supported in the `avro` block. | ----------------------- | --------------------- | ------------------------------------------------- | | createSetters | `true` | `createSetters` passed to Avro compiler | | fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | -| outputCharacterEncoding | `"UTF-8"` | `outputCharacterEncoding` passed to Avro compiler | +| outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | | stringType | `"String"` | `stringType` passed to Avro compiler | | templateDirectory | see below | `templateDir` passed to Avro compiler | @@ -91,14 +91,20 @@ avro { ## outputCharacterEncoding -Valid values: any [Charset](http://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html) or equivalent `String` name, default `"UTF-8"` +Valid values: any [Charset](http://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html) or equivalent `String` name -By default, the plugin will output generated Java files in UTF-8. -If desired, you can specify an alternate encoding. +Controls the character encoding of generated Java files. +If the associated `JavaCompile` task has a configured encoding, it will be used automatically. +Otherwise, it will use the value configured in the `avro` block, defaulting to `"UTF-8"`. -Example: +Examples: ```groovy +// Option 1: configure compilation task (avro plugin will automatically match) +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} +// Option 2: just configure avro plugin avro { outputCharacterEncoding = "UTF-8" } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 961c0712003..8b4e51c3098 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -4,11 +4,13 @@ import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; +import org.gradle.api.internal.ConventionMapping; +import org.gradle.api.internal.IConventionAware; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; -import org.gradle.api.tasks.SourceTask; +import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.plugins.ide.idea.GenerateIdeaModule; import org.gradle.plugins.ide.idea.IdeaPlugin; import org.gradle.plugins.ide.idea.model.IdeaModule; @@ -59,15 +61,15 @@ public void execute(Task task) { }); IdeaModule module = ideaPlugin.getModel().getModule(); module.setSourceDirs(new SetBuilder() - .addAll(module.getSourceDirs()) - .add(getAvroSourceDir(project, mainSourceSet)) - .add(mainGeneratedOutputDir) - .build()); + .addAll(module.getSourceDirs()) + .add(getAvroSourceDir(project, mainSourceSet)) + .add(mainGeneratedOutputDir) + .build()); module.setTestSourceDirs(new SetBuilder() - .addAll(module.getTestSourceDirs()) - .add(getAvroSourceDir(project, testSourceSet)) - .add(testGeneratedOutputDir) - .build()); + .addAll(module.getTestSourceDirs()) + .add(getAvroSourceDir(project, testSourceSet)) + .add(testGeneratedOutputDir) + .build()); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. SetBuilder excludeDirs = new SetBuilder<>(); @@ -85,7 +87,7 @@ private static GenerateAvroProtocolTask configureProtocolGenerationTask(final Pr String taskName = sourceSet.getTaskName("generate", "avroProtocol"); GenerateAvroProtocolTask task = project.getTasks().create(taskName, GenerateAvroProtocolTask.class); task.setDescription( - String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); + String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); task.setGroup(GROUP_SOURCE_GENERATION); task.source(getAvroSourceDir(project, sourceSet)); task.include("**/*." + IDL_EXTENSION); @@ -103,7 +105,7 @@ private static GenerateAvroJavaTask configureJavaGenerationTask(final Project pr String taskName = sourceSet.getTaskName("generate", "avroJava"); GenerateAvroJavaTask task = project.getTasks().create(taskName, GenerateAvroJavaTask.class); task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.", - sourceSet.getName())); + sourceSet.getName())); task.setGroup(GROUP_SOURCE_GENERATION); task.source(getAvroSourceDir(project, sourceSet)); task.source(protoTask.getOutputDir()); @@ -115,9 +117,21 @@ public File call() throws Exception { return getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION); } }); - SourceTask compileJavaTask = getCompileJavaTask(project, sourceSet); + + final JavaCompile compileJavaTask = getCompileJavaTask(project, sourceSet); compileJavaTask.source(task.getOutputDir()); compileJavaTask.source(task.getOutputs()); + + final AvroExtension avroExtension = project.getExtensions().findByType(AvroExtension.class); + ConventionMapping taskMapping = conventionMapping(task); + taskMapping.map(OPTION_OUTPUT_CHARACTER_ENCODING, new Callable() { + @Override + public String call() throws Exception { + String compilationEncoding = compileJavaTask.getOptions().getEncoding(); + String extensionEncoding = avroExtension.getOutputCharacterEncoding(); + return compilationEncoding != null ? compilationEncoding : extensionEncoding; + } + }); return task; } @@ -129,8 +143,8 @@ private static File getGeneratedOutputDir(Project project, SourceSet sourceSet, return new File(project.getBuildDir(), String.format("generated-%s-avro-%s", sourceSet.getName(), extension)); } - private static SourceTask getCompileJavaTask(Project project, SourceSet sourceSet) { - return (SourceTask) project.getTasks().getByName(sourceSet.getCompileJavaTaskName()); + private static JavaCompile getCompileJavaTask(Project project, SourceSet sourceSet) { + return (JavaCompile) project.getTasks().getByName(sourceSet.getCompileJavaTaskName()); } private static SourceSetContainer getSourceSets(Project project) { @@ -145,6 +159,14 @@ private static SourceSet getTestSourceSet(Project project) { return getSourceSets(project).getByName(SourceSet.TEST_SOURCE_SET_NAME); } + private static ConventionMapping conventionMapping(Object conventionAware) { + // TODO: try other alternatives to convention mapping + // Convention mapping is an internal API. + // Other options here: + // http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api + return ((IConventionAware) conventionAware).getConventionMapping(); + } + private static class NonGeneratedDirectoryFileFilter implements FileFilter { @Override public boolean accept(File file) { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 86342d1133a..21997583f1d 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -53,7 +53,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { result.task(":generateAvroJava").outcome == SUCCESS and: "the specified encoding is used" - projectPath("build/generated-main-avro-java/example/avro/User.java").getText(expectedEncoding) + projectPath("build/generated-main-avro-java/example/avro/User.java").getText(expectedEncoding).contains("public class User") where: outputCharacterEncoding | expectedEncoding @@ -62,6 +62,26 @@ class OptionsFunctionalSpec extends FunctionalSpec { "${StandardCharsets.name}.UTF_16" | "UTF-16" } + def "uses encoding from java compilation task by default"() { + given: + def encoding = "UTF-16" + copyResource("user.avsc", avroDir) + buildFile << """ + |compileJava { + | options.encoding = '${encoding}' + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "the task succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + + and: "the specified encoding is used" + projectPath("build/generated-main-avro-java/example/avro/User.java").getText(encoding).contains("public class User") + } + @Unroll def "supports configuring stringType to #stringType"() { given: From 61f6524ea4a0d89ef3b0df1f46b2058256038038 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Nov 2015 11:55:00 -0500 Subject: [PATCH 094/479] Change default outputCharacterEncoding to system default (#20) --- CHANGES.md | 1 + build.gradle | 3 + .../gradle/plugin/avro/AvroBasePlugin.java | 13 --- .../gradle/plugin/avro/Constants.java | 3 - .../plugin/avro/GenerateAvroJavaTask.java | 12 ++- .../plugin/avro/GenerateAvroProtocolTask.java | 12 ++- .../plugin/avro/EncodingFunctionalSpec.groovy | 83 +++++++++++++++++++ .../plugin/avro/OptionsFunctionalSpec.groovy | 63 ++------------ .../gradle/plugin/avro/idioma.avsc | 13 +++ 9 files changed, 128 insertions(+), 75 deletions(-) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/idioma.avsc diff --git a/CHANGES.md b/CHANGES.md index 86565d19cb0..da476245876 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ * Allowed setting "fieldVisibility" to a `org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility` (in addition to a String) * Fixed handling of non-"true" String settings for "createSetters" option * Automatically use encoding from `JavaCompile` task as "outputCharacterEncoding", if set +* Change default "outputCharacterEncoding" to system default to match `JavaCompile` task behavior ## 0.6.1 * Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. diff --git a/build.gradle b/build.gradle index ff03a5ff652..a5d8b631251 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,9 @@ dependencies { testCompile gradleTestKit() } +tasks.withType(AbstractCompile) { + options.encoding = "UTF-8" +} sourceCompatibility = 1.7 version = "0.7.0-SNAPSHOT" diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index f1f615ee0ff..04c2552d418 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -19,12 +19,6 @@ public void apply(final Project project) { private static void configureExtension(final Project project) { final AvroExtension avroExtension = project.getExtensions().create(AVRO_EXTENSION_NAME, DefaultAvroExtension.class); ConventionMapping extensionMapping = conventionMapping(avroExtension); - extensionMapping.map(OPTION_OUTPUT_CHARACTER_ENCODING, new Callable() { - @Override - public String call() throws Exception { - return DEFAULT_OUTPUT_CHARACTER_ENCODING; - } - }); extensionMapping.map(OPTION_STRING_TYPE, new Callable() { @Override public String call() throws Exception { @@ -37,13 +31,6 @@ public String call() throws Exception { return DEFAULT_FIELD_VISIBILITY; } }); - extensionMapping.map(OPTION_TEMPLATE_DIRECTORY, new Callable() { - @Override - public String call() throws Exception { - return DEFAULT_TEMPLATE_DIR; - - } - }); extensionMapping.map(OPTION_CREATE_SETTERS, new Callable() { @Override public Boolean call() throws Exception { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index b6ce1391c32..764fb8d21d3 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -12,11 +12,8 @@ class Constants { static final String UTF8_ENCODING = "UTF-8"; - static final String DEFAULT_OUTPUT_CHARACTER_ENCODING = UTF8_ENCODING; static final String DEFAULT_STRING_TYPE = StringType.String.name(); static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); - static final String DEFAULT_TEMPLATE_DIR = System.getProperty("org.apache.avro.specific.templates", - "/org/apache/avro/compiler/specific/templates/java/classic/"); static final boolean DEFAULT_CREATE_SETTERS = true; static final String SCHEMA_EXTENSION = "avsc"; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 90d3bf87094..c62ff2fd4d5 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -11,6 +11,7 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.TaskAction; import java.io.File; @@ -34,15 +35,16 @@ public class GenerateAvroJavaTask extends OutputDirTask { private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); - private String outputCharacterEncoding = DEFAULT_OUTPUT_CHARACTER_ENCODING; + private String outputCharacterEncoding; private String stringType = DEFAULT_STRING_TYPE; private String fieldVisibility = DEFAULT_FIELD_VISIBILITY; - private String templateDirectory = DEFAULT_TEMPLATE_DIR; + private String templateDirectory; private boolean createSetters = DEFAULT_CREATE_SETTERS; private transient StringType parsedStringType; private transient FieldVisibility parsedFieldVisibility; + @Optional @Input public String getOutputCharacterEncoding() { return outputCharacterEncoding; @@ -82,6 +84,7 @@ public void setFieldVisibility(SpecificCompiler.FieldVisibility fieldVisibility) setFieldVisibility(fieldVisibility.name()); } + @Optional @Input public String getTemplateDirectory() { return templateDirectory; @@ -230,10 +233,13 @@ private void compile(Schema schema, File sourceFile) throws IOException { } private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { + String templateDirectory = getTemplateDirectory(); compiler.setOutputCharacterEncoding(getOutputCharacterEncoding()); compiler.setStringType(parsedStringType); compiler.setFieldVisibility(parsedFieldVisibility); - compiler.setTemplateDir(getTemplateDirectory()); + if (templateDirectory != null) { + compiler.setTemplateDir(templateDirectory); + } compiler.setCreateSetters(isCreateSetters()); compiler.compileToDestination(sourceFile, getOutputDir()); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 1be971d920c..356ab924f07 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -56,7 +56,7 @@ private void processIDLFile(File idlFile, ClassLoader loader) { FilenameUtils.getBaseName(idlFile.getName()) + "." + PROTOCOL_EXTENSION); try (Idl idl = new Idl(idlFile, loader)) { String protoJson = idl.CompilationUnit().toString(true); - FileUtils.writeStringToFile(protoFile, protoJson, Constants.UTF8_ENCODING); + writeJsonFile(protoFile, protoJson); } catch (IOException | ParseException ex) { throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); } @@ -75,4 +75,14 @@ private ClassLoader getRuntimeClassLoader(Project project) { return urls.isEmpty() ? ClassLoader.getSystemClassLoader() : new URLClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader()); } + + /** + * Writes a file in a manner appropriate for a JSON file. UTF-8 will be used, as it is the default encoding for JSON, and should be + * maximally interoperable. + * + * @see JSON Character Encoding + */ + private void writeJsonFile(File file, String data) throws IOException { + FileUtils.writeStringToFile(file, data, Constants.UTF8_ENCODING); + } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy new file mode 100644 index 00000000000..96ccc470c1c --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -0,0 +1,83 @@ +package com.commercehub.gradle.plugin.avro + +import spock.lang.Unroll + +import java.nio.charset.Charset +import java.nio.charset.StandardCharsets + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class EncodingFunctionalSpec extends FunctionalSpec { + private static final List LANGUAGES = ["alemán", "chino", "español", "francés", "inglés", "japonés"] + /* Not all encodings have the characters needed for the test file, and not all encoding may be supported by any given JRE */ + private static final List AVAILABLE_ENCODINGS = + ["UTF-8", "UTF-16", "UTF-32", "windows-1252", "X-MacRoman"].findAll { Charset.isSupported(it) } + + def "default encoding matches default compilation behavior"() { + given: + copyResource("idioma.avsc", avroDir) + + when: + def result = run() + + then: "compilation succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + + and: "the system default encoding is used" + def content = projectPath("build/generated-main-avro-java/example/avro/Idioma.java").text + LANGUAGES.collect { content.contains(it) }.every { it } + } + + @Unroll + def "supports configuring outputCharacterEncoding to #outputCharacterEncoding"() { + given: + copyResource("idioma.avsc", avroDir) + buildFile << """ + |avro { + | outputCharacterEncoding = ${outputCharacterEncoding} + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "compilation succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + + and: "the specified encoding is used" + def content = projectPath("build/generated-main-avro-java/example/avro/Idioma.java").getText(expectedEncoding) + LANGUAGES.collect { content.contains(it) }.every { it } + + where: + outputCharacterEncoding | expectedEncoding + "'UTF-16'" | "UTF-16" + "'utf-8'" | "UTF-8" + "${StandardCharsets.name}.UTF_16" | "UTF-16" + } + + @Unroll + def "uses configured encoding #encoding from java compilation task"() { + given: + copyResource("idioma.avsc", avroDir) + buildFile << """ + |compileJava { + | options.encoding = '${encoding}' + |} + |""".stripMargin() + + when: + def result = run() + + then: "compilation succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + + and: "the specified encoding is used" + def content = projectPath("build/generated-main-avro-java/example/avro/Idioma.java").getText(encoding) + LANGUAGES.collect { content.contains(it) }.every { it } + + where: + encoding << AVAILABLE_ENCODINGS + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 21997583f1d..16373e59ea3 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -4,12 +4,12 @@ import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility import org.apache.avro.generic.GenericData.StringType import spock.lang.Unroll -import java.nio.charset.StandardCharsets - -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_OUTPUT_CHARACTER_ENCODING import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +/** + * Functional tests for most functions. Encoding tests have been pulled out into {@link EncodingFunctionalSpec}. + */ class OptionsFunctionalSpec extends FunctionalSpec { def "works with default options"() { given: @@ -20,9 +20,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - - and: "the encoding is the default" - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text and: "the stringType is string" content.contains("public java.lang.String getName()") @@ -37,51 +35,6 @@ class OptionsFunctionalSpec extends FunctionalSpec { content.contains("public void setName(java.lang.String value)") } - def "supports configuring outputCharacterEncoding to #outputCharacterEncoding"() { - given: - copyResource("user.avsc", avroDir) - buildFile << """ - |avro { - | outputCharacterEncoding = ${outputCharacterEncoding} - |} - |""".stripMargin() - - when: - def result = run("generateAvroJava") - - then: "the task succeeds" - result.task(":generateAvroJava").outcome == SUCCESS - - and: "the specified encoding is used" - projectPath("build/generated-main-avro-java/example/avro/User.java").getText(expectedEncoding).contains("public class User") - - where: - outputCharacterEncoding | expectedEncoding - "'UTF-16'" | "UTF-16" - "'utf-32'" | "UTF-32" - "${StandardCharsets.name}.UTF_16" | "UTF-16" - } - - def "uses encoding from java compilation task by default"() { - given: - def encoding = "UTF-16" - copyResource("user.avsc", avroDir) - buildFile << """ - |compileJava { - | options.encoding = '${encoding}' - |} - |""".stripMargin() - - when: - def result = run("generateAvroJava") - - then: "the task succeeds" - result.task(":generateAvroJava").outcome == SUCCESS - - and: "the specified encoding is used" - projectPath("build/generated-main-avro-java/example/avro/User.java").getText(encoding).contains("public class User") - } - @Unroll def "supports configuring stringType to #stringType"() { given: @@ -97,7 +50,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text and: "the specified stringType is used" content.contains(expectedContent) @@ -127,7 +80,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text and: "the specified fieldVisibility is used" content.contains(expectedContent) @@ -155,7 +108,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text and: "the specified createSetters is used" content.contains("public void setName(java.lang.String value)") == expectedPresent @@ -191,7 +144,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").getText(DEFAULT_OUTPUT_CHARACTER_ENCODING) + def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text and: "the specified templates are used" content.contains("Custom template") diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/idioma.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/idioma.avsc new file mode 100644 index 00000000000..a246218ba58 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/idioma.avsc @@ -0,0 +1,13 @@ +{ + "namespace": "example.avro", + "type": "enum", + "symbols": [ + "alemán", + "chino", + "español", + "francés", + "inglés", + "japonés" + ], + "name": "Idioma" +} From 8ac7addd096781ee437e053e0922ee7a70e64981 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Nov 2015 12:02:12 -0500 Subject: [PATCH 095/479] Use travis build matrix to test java 7/8 build compatibility --- .editorconfig | 3 +++ .travis.yml | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/.editorconfig b/.editorconfig index 339679857ad..c285d17b2ae 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,3 +8,6 @@ insert_final_newline = true charset = utf-8 indent_style = space indent_size = 4 + +[*.yml] +indent_size = 2 diff --git a/.travis.yml b/.travis.yml index 73cdf6982bc..a17e1082d12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,8 @@ env: - TERM=dumb install: true script: ./gradlew build +jdk: + - oraclejdk8 + - oraclejdk7 + - openjdk7 + # - openjdk6 From 352e87b3b1157792649233b08bb11b3a0f8a3adb Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Nov 2015 12:10:51 -0500 Subject: [PATCH 096/479] version: 0.7.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index da476245876..732afa17d4d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.7.0 * Remove usage of Apache Commons IO (#19) * Add ability to retry processing of duplicate type definitions (#13) * Renamed "encoding" option to "outputCharacterEncoding" to match Avro compiler diff --git a/build.gradle b/build.gradle index a5d8b631251..7c17ff93b5d 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ tasks.withType(AbstractCompile) { } sourceCompatibility = 1.7 -version = "0.7.0-SNAPSHOT" +version = "0.7.0" group = "com.commercehub.gradle.plugin" pluginBundle { From 32903806f13551a13fa97e8123f840e99b484788 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Nov 2015 12:13:15 -0500 Subject: [PATCH 097/479] version: 0.8.0-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7c17ff93b5d..c6cf960c337 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ tasks.withType(AbstractCompile) { } sourceCompatibility = 1.7 -version = "0.7.0" +version = "0.8.0-SNAPSHOT" group = "com.commercehub.gradle.plugin" pluginBundle { From fbbab307106eab454bd461936b92de18f4619c26 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Nov 2015 12:16:09 -0500 Subject: [PATCH 098/479] Update changelog with missing issue link --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 732afa17d4d..778f3866d59 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ * Allowed setting "fieldVisibility" to a `org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility` (in addition to a String) * Fixed handling of non-"true" String settings for "createSetters" option * Automatically use encoding from `JavaCompile` task as "outputCharacterEncoding", if set -* Change default "outputCharacterEncoding" to system default to match `JavaCompile` task behavior +* Change default "outputCharacterEncoding" to system default to match `JavaCompile` task behavior (#20) ## 0.6.1 * Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. From 66c4ca93e7ecd2370618b151b2eae5b9dca0cbe2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 25 Nov 2015 09:15:01 -0500 Subject: [PATCH 099/479] Add support for Java 6 (#21) --- .travis.yml | 2 +- CHANGES.md | 1 + README.md | 2 +- build.gradle | 4 +-- config/checkstyle/checkstyle.xml | 5 ++- .../gradle/plugin/avro/AvroPlugin.java | 2 +- .../gradle/plugin/avro/Constants.java | 9 +++++ .../gradle/plugin/avro/FileExtensionSpec.java | 4 +-- .../gradle/plugin/avro/FileState.java | 2 +- .../plugin/avro/GenerateAvroJavaTask.java | 3 +- .../plugin/avro/GenerateAvroProtocolTask.java | 20 ++++++++--- .../gradle/plugin/avro/MapUtils.java | 2 +- .../gradle/plugin/avro/ProcessingState.java | 8 ++--- .../gradle/plugin/avro/SetBuilder.java | 4 +-- .../gradle/plugin/avro/TypeState.java | 2 +- .../avro/AvroPluginFunctionalSpec.groovy | 34 +++++++++---------- .../DuplicateHandlingFunctionalSpec.groovy | 14 ++++---- .../plugin/avro/EncodingFunctionalSpec.groovy | 15 ++++---- .../avro/EnumHandlingFunctionalSpec.groovy | 16 ++++----- .../gradle/plugin/avro/FunctionalSpec.groovy | 6 ++-- .../plugin/avro/OptionsFunctionalSpec.groovy | 10 +++--- 21 files changed, 89 insertions(+), 76 deletions(-) diff --git a/.travis.yml b/.travis.yml index a17e1082d12..daaad480b35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,4 +9,4 @@ jdk: - oraclejdk8 - oraclejdk7 - openjdk7 - # - openjdk6 + - openjdk6 diff --git a/CHANGES.md b/CHANGES.md index 778f3866d59..5377e3cc599 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Add support for Java 6 (#21) ## 0.7.0 * Remove usage of Apache Commons IO (#19) diff --git a/README.md b/README.md index c634c7fdf96..e2323dc6028 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Gradle 2.7; other versions may be compatible * Currently tested against Avro 1.7.7; other versions may be compatible -* Java 7 or higher required +* Java 6 or higher required # Usage diff --git a/build.gradle b/build.gradle index c6cf960c337..22a3192c61f 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ dependencies { tasks.withType(AbstractCompile) { options.encoding = "UTF-8" } -sourceCompatibility = 1.7 +sourceCompatibility = 1.6 version = "0.8.0-SNAPSHOT" group = "com.commercehub.gradle.plugin" @@ -89,7 +89,7 @@ dependencies { } checkstyle { - toolVersion = "6.10.1" + toolVersion = "6.1.1" // Last version of checkstyle to support Java 6 } // Nasty workaround for https://issues.gradle.org/browse/GRADLE-2888 def checkstyleWarningsFile = "build/reports/checkstyle/main.xml" diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index a9dbb2e79d8..58216aa0194 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -12,7 +12,10 @@ - + + + + diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 8b4e51c3098..d79fbd5806b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -72,7 +72,7 @@ public void execute(Task task) { .build()); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. - SetBuilder excludeDirs = new SetBuilder<>(); + SetBuilder excludeDirs = new SetBuilder(); excludeDirs.addAll(module.getExcludeDirs()).remove(project.getBuildDir()); File buildDir = project.getBuildDir(); if (buildDir.isDirectory()) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 764fb8d21d3..c79015f31be 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -30,4 +30,13 @@ class Constants { static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; static final String OPTION_OUTPUT_CHARACTER_ENCODING = "outputCharacterEncoding"; + + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + /** + * The system-dependent line separator string. In Java 7+, use System.lineSeparator() instead. + */ + static String lineSeparator() { + return LINE_SEPARATOR; + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java index 5fb10b296ce..03224700dc9 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java @@ -12,11 +12,11 @@ class FileExtensionSpec implements Spec { private final Set extensions; FileExtensionSpec(String... extensions) { - this.extensions = new HashSet<>(Arrays.asList(extensions)); + this.extensions = new HashSet(Arrays.asList(extensions)); } FileExtensionSpec(Collection extensions) { - this.extensions = new HashSet<>(extensions); + this.extensions = new HashSet(extensions); } @Override diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java index 974f28b2281..234cfa06fb0 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java @@ -8,7 +8,7 @@ class FileState implements Comparable { private final File file; private final String path; private String errorMessage; - private Set duplicateTypeNames = new TreeSet<>(); + private Set duplicateTypeNames = new TreeSet(); FileState(File file, String path) { this.file = file; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index c62ff2fd4d5..0c649392514 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -24,7 +24,6 @@ import static com.commercehub.gradle.plugin.avro.Constants.*; import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; -import static java.lang.System.lineSeparator; /** * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and @@ -120,7 +119,7 @@ protected void process() { } private void failOnUnsupportedFiles() { - FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(SUPPORTED_EXTENSIONS))); + FileCollection unsupportedFiles = filterSources(new NotSpec(new FileExtensionSpec(SUPPORTED_EXTENSIONS))); if (!unsupportedFiles.isEmpty()) { throw new GradleException( String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 356ab924f07..b2079da40e6 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -33,7 +33,7 @@ protected void process() { } private void failOnUnsupportedFiles() { - FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(IDL_EXTENSION))); + FileCollection unsupportedFiles = filterSources(new NotSpec(new FileExtensionSpec(IDL_EXTENSION))); if (!unsupportedFiles.isEmpty()) { throw new GradleException( String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); @@ -54,16 +54,28 @@ private void processIDLFile(File idlFile, ClassLoader loader) { getLogger().info("Processing {}", idlFile); File protoFile = new File(getOutputDir(), FilenameUtils.getBaseName(idlFile.getName()) + "." + PROTOCOL_EXTENSION); - try (Idl idl = new Idl(idlFile, loader)) { + Idl idl = null; + try { + idl = new Idl(idlFile, loader); String protoJson = idl.CompilationUnit().toString(true); writeJsonFile(protoFile, protoJson); - } catch (IOException | ParseException ex) { + } catch (IOException ex) { throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); + } catch (ParseException ex) { + throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); + } finally { + if (idl != null) { + try { + idl.close(); + } catch (IOException ioe) { + // ignore + } + } } } private ClassLoader getRuntimeClassLoader(Project project) { - List urls = new LinkedList<>(); + List urls = new LinkedList(); Configuration configuration = project.getConfigurations().getByName(JavaPlugin.RUNTIME_CONFIGURATION_NAME); for (File file : configuration) { try { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java index af3133c36b9..6cccfcfcc59 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java @@ -11,7 +11,7 @@ static Map asymmetricDifference(Map a, Map b) { if (b == null || b.isEmpty()) { return a; } - Map result = new LinkedHashMap<>(a); + Map result = new LinkedHashMap(a); result.keySet().removeAll(b.keySet()); return result; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java index c510481635e..378759322cf 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -7,9 +7,9 @@ import java.util.*; class ProcessingState { - private final Map typeStates = new HashMap<>(); - private final Set delayedFiles = new LinkedHashSet<>(); - private final Queue filesToProcess = new LinkedList<>(); + private final Map typeStates = new HashMap(); + private final Set delayedFiles = new LinkedHashSet(); + private final Queue filesToProcess = new LinkedList(); private int processedTotal = 0; ProcessingState(Set files, Project project) { @@ -20,7 +20,7 @@ class ProcessingState { Map determineParserTypes(FileState fileState) { Set duplicateTypeNames = fileState.getDuplicateTypeNames(); - Map types = new HashMap<>(); + Map types = new HashMap(); for (TypeState typeState : typeStates.values()) { String typeName = typeState.getName(); if (!duplicateTypeNames.contains(typeName)) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java index d7b3825a574..b9054170050 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java @@ -6,14 +6,13 @@ import java.util.Set; class SetBuilder { - private Set set = new HashSet<>(); + private Set set = new HashSet(); SetBuilder add(T e) { set.add(e); return this; } - @SafeVarargs final SetBuilder addAll(T... c) { Collections.addAll(set, c); return this; @@ -33,7 +32,6 @@ Set build() { return set; } - @SafeVarargs static Set build(T... c) { return new SetBuilder().addAll(c).build(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java index 4d58c6ce706..be63e77744a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java @@ -8,7 +8,7 @@ class TypeState { private final String name; - private final Set locations = new TreeSet<>(); + private final Set locations = new TreeSet(); private Schema schema; TypeState(String name) { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index a8c2f061594..70e95f1a4d1 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -1,7 +1,5 @@ package com.commercehub.gradle.plugin.avro -import java.nio.file.Files - import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -16,7 +14,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/example/avro/User.class")) + projectFile("build/classes/main/example/avro/User.class").file } def "can generate and compile java files from json protocol"() { @@ -32,8 +30,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/org/apache/avro/test/Mail.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/test/Message.class")) + projectFile("build/classes/main/org/apache/avro/test/Mail.class").file + projectFile("build/classes/main/org/apache/avro/test/Message.class").file } def "can generate and compile java files from IDL"() { @@ -47,11 +45,11 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { result.task(":generateAvroProtocol").outcome == SUCCESS result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/org/apache/avro/Foo.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/Interop.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/Kind.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/MD5.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/Node.class")) + projectFile("build/classes/main/org/apache/avro/Foo.class").file + projectFile("build/classes/main/org/apache/avro/Interop.class").file + projectFile("build/classes/main/org/apache/avro/Kind.class").file + projectFile("build/classes/main/org/apache/avro/MD5.class").file + projectFile("build/classes/main/org/apache/avro/Node.class").file } def "supports json schema files in subdirectories"() { @@ -64,7 +62,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/example/avro/User.class")) + projectFile("build/classes/main/example/avro/User.class").file } def "supports json protocol files in subdirectories"() { @@ -80,8 +78,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/org/apache/avro/test/Mail.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/test/Message.class")) + projectFile("build/classes/main/org/apache/avro/test/Mail.class").file + projectFile("build/classes/main/org/apache/avro/test/Message.class").file } def "supports IDL files in subdirectories"() { @@ -95,11 +93,11 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { result.task(":generateAvroProtocol").outcome == SUCCESS result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/org/apache/avro/Foo.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/Interop.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/Kind.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/MD5.class")) - Files.exists(projectPath("build/classes/main/org/apache/avro/Node.class")) + projectFile("build/classes/main/org/apache/avro/Foo.class").file + projectFile("build/classes/main/org/apache/avro/Interop.class").file + projectFile("build/classes/main/org/apache/avro/Kind.class").file + projectFile("build/classes/main/org/apache/avro/MD5.class").file + projectFile("build/classes/main/org/apache/avro/Node.class").file } def "gives a meaningful error message when presented a malformed schema file"() { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index 0349990ff6c..51fafa349b5 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -1,7 +1,5 @@ package com.commercehub.gradle.plugin.avro -import java.nio.file.Files - import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -22,9 +20,9 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/example/Person.class")) - Files.exists(projectPath("build/classes/main/example/Cat.class")) - Files.exists(projectPath("build/classes/main/example/Gender.class")) + projectFile("build/classes/main/example/Person.class").file + projectFile("build/classes/main/example/Cat.class").file + projectFile("build/classes/main/example/Gender.class").file } def "Duplicate record definition succeeds if definition identical"() { @@ -37,9 +35,9 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/example/Person.class")) - Files.exists(projectPath("build/classes/main/example/Fish.class")) - Files.exists(projectPath("build/classes/main/example/Gender.class")) + projectFile("build/classes/main/example/Person.class").file + projectFile("build/classes/main/example/Fish.class").file + projectFile("build/classes/main/example/Gender.class").file } def "Duplicate enum definition fails if definition differs"() { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy index 96ccc470c1c..182c9786562 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -3,7 +3,6 @@ package com.commercehub.gradle.plugin.avro import spock.lang.Unroll import java.nio.charset.Charset -import java.nio.charset.StandardCharsets import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -25,7 +24,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { result.task(":compileJava").outcome == SUCCESS and: "the system default encoding is used" - def content = projectPath("build/generated-main-avro-java/example/avro/Idioma.java").text + def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").text LANGUAGES.collect { content.contains(it) }.every { it } } @@ -46,14 +45,14 @@ class EncodingFunctionalSpec extends FunctionalSpec { result.task(":generateAvroJava").outcome == SUCCESS and: "the specified encoding is used" - def content = projectPath("build/generated-main-avro-java/example/avro/Idioma.java").getText(expectedEncoding) + def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(expectedEncoding) LANGUAGES.collect { content.contains(it) }.every { it } where: - outputCharacterEncoding | expectedEncoding - "'UTF-16'" | "UTF-16" - "'utf-8'" | "UTF-8" - "${StandardCharsets.name}.UTF_16" | "UTF-16" + outputCharacterEncoding | expectedEncoding + "'UTF-16'" | "UTF-16" + "'utf-8'" | "UTF-8" + "java.nio.charset.Charset.forName('UTF-16')" | "UTF-16" } @Unroll @@ -74,7 +73,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { result.task(":compileJava").outcome == SUCCESS and: "the specified encoding is used" - def content = projectPath("build/generated-main-avro-java/example/avro/Idioma.java").getText(encoding) + def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(encoding) LANGUAGES.collect { content.contains(it) }.every { it } where: diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index a1240b43e74..c098f370a3b 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -1,7 +1,5 @@ package com.commercehub.gradle.plugin.avro -import java.nio.file.Files - import static org.gradle.testkit.runner.TaskOutcome.SUCCESS /** @@ -18,7 +16,7 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/example/avro/MyEnum.class")) + projectFile("build/classes/main/example/avro/MyEnum.class").file } def "supports enums defined within a record field"() { @@ -31,8 +29,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/example/avro/Test.class")) - Files.exists(projectPath("build/classes/main/example/avro/Gender.class")) + projectFile("build/classes/main/example/avro/Test.class").file + projectFile("build/classes/main/example/avro/Gender.class").file } def "supports enums defined within a union"() { @@ -45,8 +43,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/example/avro/Test.class")) - Files.exists(projectPath("build/classes/main/example/avro/Kind.class")) + projectFile("build/classes/main/example/avro/Test.class").file + projectFile("build/classes/main/example/avro/Kind.class").file } def "supports using enums defined in a separate schema file"() { @@ -60,7 +58,7 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - Files.exists(projectPath("build/classes/main/example/avro/User.class")) - Files.exists(projectPath("build/classes/main/example/avro/MyEnum.class")) + projectFile("build/classes/main/example/avro/User.class").file + projectFile("build/classes/main/example/avro/MyEnum.class").file } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 1557802d732..95d5d2a48a1 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -6,8 +6,6 @@ import org.junit.Rule import org.junit.rules.TemporaryFolder import spock.lang.Specification -import java.nio.file.Path - abstract class FunctionalSpec extends Specification { protected static final String AVRO_VERSION = "1.7.7" // TODO: externalize @@ -50,8 +48,8 @@ abstract class FunctionalSpec extends Specification { file << getClass().getResourceAsStream(name) } - protected Path projectPath(String path) { - return testProjectDir.root.toPath().resolve(path) + protected File projectFile(String path) { + return new File(testProjectDir.root, path) } protected BuildResult run(String... args = ["build"]) { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 16373e59ea3..46df380b55b 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -20,7 +20,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the stringType is string" content.contains("public java.lang.String getName()") @@ -50,7 +50,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified stringType is used" content.contains(expectedContent) @@ -80,7 +80,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified fieldVisibility is used" content.contains(expectedContent) @@ -108,7 +108,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified createSetters is used" content.contains("public void setName(java.lang.String value)") == expectedPresent @@ -144,7 +144,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS - def content = projectPath("build/generated-main-avro-java/example/avro/User.java").text + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified templates are used" content.contains("Custom template") From 42ed6efa43de46158c1cac25eef746f378110dd9 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 2 Dec 2015 09:30:09 -0500 Subject: [PATCH 100/479] version: 0.8.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 5377e3cc599..eb3b3c9daa2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.8.0 * Add support for Java 6 (#21) ## 0.7.0 diff --git a/build.gradle b/build.gradle index 22a3192c61f..9a385640e3a 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ tasks.withType(AbstractCompile) { } sourceCompatibility = 1.6 -version = "0.8.0-SNAPSHOT" +version = "0.8.0" group = "com.commercehub.gradle.plugin" pluginBundle { From 70c37c6bbdd5353302d9129c44cbc86e48b4c9a7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 2 Dec 2015 09:32:43 -0500 Subject: [PATCH 101/479] version: 0.9.0-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9a385640e3a..6b160a45c65 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ tasks.withType(AbstractCompile) { } sourceCompatibility = 1.6 -version = "0.8.0" +version = "0.9.0-SNAPSHOT" group = "com.commercehub.gradle.plugin" pluginBundle { From 8d5e3b1b61c713c2e11c9dc8bb9524131c4c04ca Mon Sep 17 00:00:00 2001 From: Ben McCann Date: Tue, 31 May 2016 12:05:10 -0700 Subject: [PATCH 102/479] Upgrade to Avro 1.8.1 --- README.md | 12 ++++++------ build.gradle | 2 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e2323dc6028..bceb7615e6a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility * Currently tested against Gradle 2.7; other versions may be compatible -* Currently tested against Avro 1.7.7; other versions may be compatible +* Currently tested against Avro 1.8.1; other versions may be compatible * Java 6 or higher required # Usage @@ -41,7 +41,7 @@ repositories { jcenter() } dependencies { - compile "org.apache.avro:avro:1.7.7" + compile "org.apache.avro:avro:1.8.1" } ``` @@ -76,7 +76,7 @@ avro { ## fieldVisibility -Valid values: any [FieldVisibility](http://avro.apache.org/docs/1.7.7/api/java/org/apache/avro/compiler/specific/SpecificCompiler.FieldVisibility.html) or equivalent `String` name (matched case-insensitively); default `"PUBLIC_DEPRECATED"` (default) +Valid values: any [FieldVisibility](http://avro.apache.org/docs/1.8.1/api/java/org/apache/avro/compiler/specific/SpecificCompiler.FieldVisibility.html) or equivalent `String` name (matched case-insensitively); default `"PUBLIC_DEPRECATED"` (default) By default, the fields in generated Java files will have public visibility and be annotated with `@Deprecated`. Set to `"PRIVATE"` to restrict visibility of the fields, or `"PUBLIC"` to remove the `@Deprecated` annotations. @@ -112,10 +112,10 @@ avro { ## stringType -Valid values: any [StringType](http://avro.apache.org/docs/1.7.7/api/java/org/apache/avro/generic/GenericData.StringType.html) or equivalent `String` name (matched case-insensitively); default `"String"` (default) +Valid values: any [StringType](http://avro.apache.org/docs/1.8.1/api/java/org/apache/avro/generic/GenericData.StringType.html) or equivalent `String` name (matched case-insensitively); default `"String"` (default) By default, the generated Java files will use [`java.lang.String`](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html) to represent string types. -Alternatively, you can set it to `"Utf8"` to use [`org.apache.avro.util.Utf8`](https://avro.apache.org/docs/1.7.7/api/java/org/apache/avro/util/Utf8.html) or `"charSequence"` to use [`java.lang.CharSequence`](http://docs.oracle.com/javase/7/docs/api/java/lang/CharSequence.html). +Alternatively, you can set it to `"Utf8"` to use [`org.apache.avro.util.Utf8`](https://avro.apache.org/docs/1.8.1/api/java/org/apache/avro/util/Utf8.html) or `"charSequence"` to use [`java.lang.CharSequence`](http://docs.oracle.com/javase/7/docs/api/java/lang/CharSequence.html). ```groovy avro { @@ -152,7 +152,7 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - compile "org.apache.avro:avro:1.7.7" + compile "org.apache.avro:avro:1.8.1" } task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { diff --git a/build.gradle b/build.gradle index 6b160a45c65..9a51a0c71a2 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ repositories { dependencies { compile gradleApi() compile localGroovy() - compile "org.apache.avro:avro-compiler:1.7.7" + compile "org.apache.avro:avro-compiler:1.8.1" testCompile "org.spockframework:spock-core:1.0-groovy-2.3" testCompile gradleTestKit() } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 95d5d2a48a1..e38818b2fd5 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro + package com.commercehub.gradle.plugin.avro import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner @@ -7,7 +7,7 @@ import org.junit.rules.TemporaryFolder import spock.lang.Specification abstract class FunctionalSpec extends Specification { - protected static final String AVRO_VERSION = "1.7.7" // TODO: externalize + protected static final String AVRO_VERSION = "1.8.1" // TODO: externalize @Rule TemporaryFolder testProjectDir From 3dc2b4e01338111dde975042f35559c18e6fc35e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 31 May 2016 17:01:56 -0400 Subject: [PATCH 103/479] Minor cleanup after pull request #24. --- CHANGES.md | 1 + .../com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index eb3b3c9daa2..7835426adc5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Update Avro to 0.8.1 (#23) ## 0.8.0 * Add support for Java 6 (#21) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index e38818b2fd5..328ddbc6068 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -1,4 +1,4 @@ - package com.commercehub.gradle.plugin.avro +package com.commercehub.gradle.plugin.avro import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner From 8688b8c32c34dad9ff518123dec56fcee1043480 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 1 Jun 2016 13:27:12 -0400 Subject: [PATCH 104/479] Upgrade Gradle to 2.13, add version compatibility testing --- .travis.yml | 4 +- CHANGES.md | 4 +- README.md | 8 ++- build.gradle | 32 +++++++++++- gradle/wrapper/gradle-wrapper.jar | Bin 53638 -> 53556 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 46 ++++++++++-------- gradlew.bat | 8 +-- .../avro/AvroPluginFunctionalSpec.groovy | 38 +++++++-------- .../DuplicateHandlingFunctionalSpec.groovy | 16 +++--- .../plugin/avro/EncodingFunctionalSpec.groovy | 10 ++-- .../avro/EnumHandlingFunctionalSpec.groovy | 16 +++--- .../gradle/plugin/avro/FunctionalSpec.groovy | 23 +++++++-- .../plugin/avro/OptionsFunctionalSpec.groovy | 18 +++---- 14 files changed, 140 insertions(+), 87 deletions(-) diff --git a/.travis.yml b/.travis.yml index daaad480b35..46a6eae49b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,9 @@ sudo: false language: java env: global: - - TERM=dumb + - TERM=dumb install: true -script: ./gradlew build +script: ./gradlew build testVersionCompatibility jdk: - oraclejdk8 - oraclejdk7 diff --git a/CHANGES.md b/CHANGES.md index 7835426adc5..63845fc3a98 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,9 @@ # Change Log ## Unreleased -* Update Avro to 0.8.1 (#23) +* Built using Avro 0.8.1 (#23) +* Built using Gradle 2.13 +* Added version cross-compatibility testing ## 0.8.0 * Add support for Java 6 (#21) diff --git a/README.md b/README.md index bceb7615e6a..a45ee528d9b 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,13 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Gradle 2.7; other versions may be compatible -* Currently tested against Avro 1.8.1; other versions may be compatible * Java 6 or higher required +* Currently built against Gradle 2.13 + * Currently tested against Gradle 2.0-2.13; other versions may be compatible, but 1.x versions are unlikely to work +* Currently built against Avro 1.8.1 + * Currently tested against Avro 1.8.0-1.8.1; other versions may be compatible + * If you need support for Avro 1.7.x, try plugin version 0.8.0; versions of Avro before that are unlikely to work +* Currently tested against Avro 1.8.1; other versions may be compatible # Usage diff --git a/build.gradle b/build.gradle index 9a51a0c71a2..353ec5c7a9b 100644 --- a/build.gradle +++ b/build.gradle @@ -11,11 +11,15 @@ repositories { jcenter() } +def compileAvroVersion = "1.8.1" + dependencies { compile gradleApi() compile localGroovy() - compile "org.apache.avro:avro-compiler:1.8.1" - testCompile "org.spockframework:spock-core:1.0-groovy-2.3" + compile "org.apache.avro:avro-compiler:${compileAvroVersion}" + testCompile("org.spockframework:spock-core:1.0-groovy-2.4") { + exclude module: "groovy-all" + } testCompile gradleTestKit() } @@ -104,3 +108,27 @@ codenarc { toolVersion = "0.24.1" config = project.resources.text.fromFile("config/codenarc/codenarc.groovy") } + +tasks.create("testVersionCompatibility") { + description = "Tests cross-compatibility of the plugin with different versions of Avro and Gradle" +} + +test { + systemProperties = [ + avroVersion: compileAvroVersion, + gradleVersion: gradle.gradleVersion, + ] +} + +["1.8.0", "1.8.1"].each { def avroVersion -> + ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13"].each { def gradleVersion -> + def newTask = tasks.create(name: "testAvro${avroVersion}Gradle${gradleVersion}", type: Test) { + description = "Test cross-compatibility of the plugin with Avro ${avroVersion} and Gradle ${gradleVersion}" + systemProperties = [ + avroVersion: avroVersion, + gradleVersion: gradleVersion, + ] + } + testVersionCompatibility.dependsOn newTask + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e8c6bf7bb47dff6b81c2cf7a349eb7e912c9fbe2..ca78035ef0501d802d4fc55381ef2d5c3ce0ec6e 100644 GIT binary patch delta 3725 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 M+arpIM*|o9FP9^Dn*aa+ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7de51610898..6cd014077d6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Sep 17 16:38:56 EDT 2015 +#Wed Jun 01 09:51:50 EDT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip diff --git a/gradlew b/gradlew index 97fac783e1c..27309d92314 100755 --- a/gradlew +++ b/gradlew @@ -6,12 +6,30 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then diff --git a/gradlew.bat b/gradlew.bat index aec99730b4e..f6d5974e72f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,7 +46,7 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 70e95f1a4d1..8984b272316 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -12,15 +12,15 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/example/avro/User.class").file } def "can generate and compile java files from json protocol"() { given: buildFile << """ - dependencies { compile "org.apache.avro:avro-ipc:${AVRO_VERSION}" } + dependencies { compile "org.apache.avro:avro-ipc:${avroVersion}" } """ copyResource("mail.avpr", avroDir) @@ -28,8 +28,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/org/apache/avro/test/Mail.class").file projectFile("build/classes/main/org/apache/avro/test/Message.class").file } @@ -42,9 +42,9 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroProtocol").outcome == SUCCESS - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroProtocol").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/org/apache/avro/Foo.class").file projectFile("build/classes/main/org/apache/avro/Interop.class").file projectFile("build/classes/main/org/apache/avro/Kind.class").file @@ -60,15 +60,15 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/example/avro/User.class").file } def "supports json protocol files in subdirectories"() { given: buildFile << """ - dependencies { compile "org.apache.avro:avro-ipc:${AVRO_VERSION}" } + dependencies { compile "org.apache.avro:avro-ipc:${avroVersion}" } """ copyResource("mail.avpr", avroSubDir) @@ -76,8 +76,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/org/apache/avro/test/Mail.class").file projectFile("build/classes/main/org/apache/avro/test/Message.class").file } @@ -90,9 +90,9 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroProtocol").outcome == SUCCESS - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroProtocol").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/org/apache/avro/Foo.class").file projectFile("build/classes/main/org/apache/avro/Interop.class").file projectFile("build/classes/main/org/apache/avro/Kind.class").file @@ -108,9 +108,9 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = runAndFail() then: - result.task(":generateAvroJava").outcome == FAILED - result.standardError.contains("> Could not compile schema definition files:") - result.standardError.contains("* src/main/avro/enumMalformed.avsc: \"enum\" is not a defined name. The type of the \"gender\" " + + taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.output.contains("> Could not compile schema definition files:") + result.output.contains("* src/main/avro/enumMalformed.avsc: \"enum\" is not a defined name. The type of the \"gender\" " + "field must be a defined name or a {\"type\": ...} expression.") } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index 51fafa349b5..0a0e81156ef 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -18,8 +18,8 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/example/Person.class").file projectFile("build/classes/main/example/Cat.class").file projectFile("build/classes/main/example/Gender.class").file @@ -33,8 +33,8 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/example/Person.class").file projectFile("build/classes/main/example/Fish.class").file projectFile("build/classes/main/example/Gender.class").file @@ -48,8 +48,8 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def result = runAndFail() then: - result.task(":generateAvroJava").outcome == FAILED - result.standardError.contains("Found conflicting definition of type example.Gender in " + taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.output.contains("Found conflicting definition of type example.Gender in " + "[src/main/avro/duplicate/Dog.avsc, src/main/avro/duplicate/Person.avsc]") } @@ -61,8 +61,8 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def result = runAndFail() then: - result.task(":generateAvroJava").outcome == FAILED - result.standardError.contains("Found conflicting definition of type example.Person in " + taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.output.contains("Found conflicting definition of type example.Person in " + "[src/main/avro/duplicate/Person.avsc, src/main/avro/duplicate/Spider.avsc]") } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy index 182c9786562..205596350ab 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -20,8 +20,8 @@ class EncodingFunctionalSpec extends FunctionalSpec { def result = run() then: "compilation succeeds" - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS and: "the system default encoding is used" def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").text @@ -42,7 +42,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "compilation succeeds" - result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS and: "the specified encoding is used" def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(expectedEncoding) @@ -69,8 +69,8 @@ class EncodingFunctionalSpec extends FunctionalSpec { def result = run() then: "compilation succeeds" - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS and: "the specified encoding is used" def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(encoding) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index c098f370a3b..e115fa0e7ab 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -14,8 +14,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/example/avro/MyEnum.class").file } @@ -27,8 +27,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/example/avro/Test.class").file projectFile("build/classes/main/example/avro/Gender.class").file } @@ -41,8 +41,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/example/avro/Test.class").file projectFile("build/classes/main/example/avro/Kind.class").file } @@ -56,8 +56,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - result.task(":generateAvroJava").outcome == SUCCESS - result.task(":compileJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS projectFile("build/classes/main/example/avro/User.class").file projectFile("build/classes/main/example/avro/MyEnum.class").file } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 328ddbc6068..1b9aa889890 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -1,13 +1,17 @@ package com.commercehub.gradle.plugin.avro +import org.gradle.testkit.jarjar.org.gradle.util.GradleVersion import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.internal.feature.TestKitFeature import org.junit.Rule import org.junit.rules.TemporaryFolder import spock.lang.Specification +@SuppressWarnings(["Println"]) abstract class FunctionalSpec extends Specification { - protected static final String AVRO_VERSION = "1.8.1" // TODO: externalize + protected final String avroVersion = System.getProperty("avroVersion") + protected final GradleVersion gradleVersion = GradleVersion.version(System.getProperty("gradleVersion")) @Rule TemporaryFolder testProjectDir @@ -17,6 +21,9 @@ abstract class FunctionalSpec extends Specification { File avroSubDir def setup() { + println "Testing using Avro version ${avroVersion}." + println "Testing using Gradle version ${gradleVersion}." + buildFile = testProjectDir.newFile('build.gradle') avroDir = testProjectDir.newFolder("src", "main", "avro") avroSubDir = testProjectDir.newFolder("src", "main", "avro", "foo") @@ -38,7 +45,7 @@ abstract class FunctionalSpec extends Specification { } apply plugin: "com.commercehub.gradle.plugin.avro" repositories { jcenter() } - dependencies { compile "org.apache.avro:avro:${AVRO_VERSION}" } + dependencies { compile "org.apache.avro:avro:${avroVersion}" } """ } @@ -52,11 +59,19 @@ abstract class FunctionalSpec extends Specification { return new File(testProjectDir.root, path) } + protected GradleRunner createGradleRunner() { + return GradleRunner.create().withProjectDir(testProjectDir.root).withGradleVersion(gradleVersion.version) + } + protected BuildResult run(String... args = ["build"]) { - return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments(args).build() + return createGradleRunner().withArguments(args).build() } protected BuildResult runAndFail(String... args = ["build"]) { - return GradleRunner.create().withProjectDir(testProjectDir.root).withArguments(args).buildAndFail() + return createGradleRunner().withArguments(args).buildAndFail() + } + + protected boolean isTaskInfoAbsent() { + return gradleVersion < TestKitFeature.CAPTURE_BUILD_RESULT_TASKS.since } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 46df380b55b..0abaa6d3eb7 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -19,7 +19,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the stringType is string" @@ -49,7 +49,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified stringType is used" @@ -79,7 +79,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified fieldVisibility is used" @@ -107,7 +107,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified createSetters is used" @@ -143,7 +143,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified templates are used" @@ -163,8 +163,8 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = runAndFail("generateAvroJava") then: - result.task(":generateAvroJava").outcome == FAILED - result.standardError.contains("Invalid stringType 'badValue'. Value values are: [CharSequence, String, Utf8]") + taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.output.contains("Invalid stringType 'badValue'. Value values are: [CharSequence, String, Utf8]") } def "rejects unsupported fieldVisibility values"() { @@ -180,7 +180,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = runAndFail("generateAvroJava") then: - result.task(":generateAvroJava").outcome == FAILED - result.standardError.contains("Invalid fieldVisibility 'badValue'. Value values are: [PUBLIC, PUBLIC_DEPRECATED, PRIVATE]") + taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.output.contains("Invalid fieldVisibility 'badValue'. Value values are: [PUBLIC, PUBLIC_DEPRECATED, PRIVATE]") } } From b1234ea9f269e01e535a06384f17fae32c1f1945 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 1 Jun 2016 13:51:08 -0400 Subject: [PATCH 105/479] Restrict test heap size to try to get the new larger test corpus to run in Travis CI. --- build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle b/build.gradle index 353ec5c7a9b..19103c8720f 100644 --- a/build.gradle +++ b/build.gradle @@ -132,3 +132,9 @@ test { testVersionCompatibility.dependsOn newTask } } + +tasks.withType(Test) { + jvmArgs "-Xss320k" + minHeapSize "120m" + maxHeapSize "280m" +} From 6c66853abca1ed9138c06499e1fb3a2ac4661c78 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 1 Jun 2016 14:10:25 -0400 Subject: [PATCH 106/479] Restrict Gradle memory usage in Travis CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 46a6eae49b1..1072ced8c17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: java env: global: - TERM=dumb + - GRADLE_OPTS=-Xmx386m -Xms386m install: true script: ./gradlew build testVersionCompatibility jdk: From 5fd94d3fa64ef3c972789d61995793fadabec2b8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 1 Jun 2016 16:25:05 -0400 Subject: [PATCH 107/479] Attempt gradle parallel task execution on Travis CI. --- .travis.yml | 4 ++-- build.gradle | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1072ced8c17..92e3571a8ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,9 @@ language: java env: global: - TERM=dumb - - GRADLE_OPTS=-Xmx386m -Xms386m + - GRADLE_OPTS=-Xmx386m -Xms386m -Dorg.gradle.parallel.intra=true install: true -script: ./gradlew build testVersionCompatibility +script: ./gradlew --parallel --max-workers=2 build testVersionCompatibility jdk: - oraclejdk8 - oraclejdk7 diff --git a/build.gradle b/build.gradle index 19103c8720f..ce287f61d59 100644 --- a/build.gradle +++ b/build.gradle @@ -128,6 +128,10 @@ test { avroVersion: avroVersion, gradleVersion: gradleVersion, ] + reports { + html.destination = file("$buildDir/reports/tests-${avroVersion}-${gradleVersion}") + junitXml.destination = file("$buildDir/reports/tests-${avroVersion}-${gradleVersion}") + } } testVersionCompatibility.dependsOn newTask } From 64aca7433ad966aa227ce5e249d1591eb4745952 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 1 Jun 2016 16:57:10 -0400 Subject: [PATCH 108/479] Disable parallel execution in Travis CI; instead, restrict the number of versions tested. --- .travis.yml | 4 ++-- build.gradle | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 92e3571a8ce..cbaf77d50c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,9 @@ language: java env: global: - TERM=dumb - - GRADLE_OPTS=-Xmx386m -Xms386m -Dorg.gradle.parallel.intra=true + - GRADLE_OPTS=-Xmx386m -Xms386m install: true -script: ./gradlew --parallel --max-workers=2 build testVersionCompatibility +script: ./gradlew build testRecentVersionCompatibility jdk: - oraclejdk8 - oraclejdk7 diff --git a/build.gradle b/build.gradle index ce287f61d59..f77d9940248 100644 --- a/build.gradle +++ b/build.gradle @@ -113,6 +113,10 @@ tasks.create("testVersionCompatibility") { description = "Tests cross-compatibility of the plugin with different versions of Avro and Gradle" } +tasks.create("testRecentVersionCompatibility") { + description = "Tests cross-compatibility of the plugin with recent versions of Avro and Gradle" +} + test { systemProperties = [ avroVersion: compileAvroVersion, @@ -120,8 +124,11 @@ test { ] } -["1.8.0", "1.8.1"].each { def avroVersion -> - ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13"].each { def gradleVersion -> +def avroVersions = ["1.8.0", "1.8.1"] +def gradleVersions = ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13"] + +avroVersions.each { def avroVersion -> + gradleVersions.each { def gradleVersion -> def newTask = tasks.create(name: "testAvro${avroVersion}Gradle${gradleVersion}", type: Test) { description = "Test cross-compatibility of the plugin with Avro ${avroVersion} and Gradle ${gradleVersion}" systemProperties = [ @@ -134,6 +141,9 @@ test { } } testVersionCompatibility.dependsOn newTask + if (gradleVersions.indexOf(gradleVersion) >= gradleVersions.size() - 5) { + testRecentVersionCompatibility.dependsOn newTask + } } } From 7644f425b92e6da39c4ad489adaba48761f43a3f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 2 Jun 2016 08:41:02 -0400 Subject: [PATCH 109/479] version: 0.9.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 63845fc3a98..9973529d663 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.9.0 * Built using Avro 0.8.1 (#23) * Built using Gradle 2.13 * Added version cross-compatibility testing diff --git a/build.gradle b/build.gradle index f77d9940248..3f9258fb14f 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ tasks.withType(AbstractCompile) { } sourceCompatibility = 1.6 -version = "0.9.0-SNAPSHOT" +version = "0.9.0" group = "com.commercehub.gradle.plugin" pluginBundle { From 0f32abecdb29515fad5432c73e99aa648bad8155 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 2 Jun 2016 08:44:49 -0400 Subject: [PATCH 110/479] version: 0.9.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3f9258fb14f..19d8a055980 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ tasks.withType(AbstractCompile) { } sourceCompatibility = 1.6 -version = "0.9.0" +version = "0.9.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" pluginBundle { From adaf65c73c0d2797fcca3d58b9d28e6b8f486be4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 8 Jun 2016 16:19:34 -0400 Subject: [PATCH 111/479] fix changelog --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 9973529d663..acdcce7352e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,7 +3,7 @@ ## Unreleased ## 0.9.0 -* Built using Avro 0.8.1 (#23) +* Built using Avro 1.8.1 (#23) * Built using Gradle 2.13 * Added version cross-compatibility testing From 8ca4df550ee5d418bf450c4eee8c95d7d1cb88df Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 23 Jun 2016 16:26:26 -0700 Subject: [PATCH 112/479] Update Gradle build. * Use Gradle 2.14 * Update plugin publishing plugin to 0.9.4 --- CHANGES.md | 1 + README.md | 4 ++-- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.jar | Bin 53556 -> 53319 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- .../gradle/plugin/avro/FunctionalSpec.groovy | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index acdcce7352e..fe3e0226302 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Built using Gradle 2.14 ## 0.9.0 * Built using Avro 1.8.1 (#23) diff --git a/README.md b/README.md index a45ee528d9b..737d2fe2d37 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility * Java 6 or higher required -* Currently built against Gradle 2.13 - * Currently tested against Gradle 2.0-2.13; other versions may be compatible, but 1.x versions are unlikely to work +* Currently built against Gradle 2.14 + * Currently tested against Gradle 2.0-2.14; other versions may be compatible, but 1.x versions are unlikely to work * Currently built against Avro 1.8.1 * Currently tested against Avro 1.8.0-1.8.1; other versions may be compatible * If you need support for Avro 1.7.x, try plugin version 0.8.0; versions of Avro before that are unlikely to work diff --git a/build.gradle b/build.gradle index 19d8a055980..47a064ffde8 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { id "codenarc" id "idea" id "maven" - id "com.gradle.plugin-publish" version "0.9.1" + id "com.gradle.plugin-publish" version "0.9.4" } repositories { @@ -125,7 +125,7 @@ test { } def avroVersions = ["1.8.0", "1.8.1"] -def gradleVersions = ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13"] +def gradleVersions = ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14"] avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ca78035ef0501d802d4fc55381ef2d5c3ce0ec6e..d3b83982b9b1bccad955349d702be9b884c6e049 100644 GIT binary patch delta 3698 zcmZWrc|4Tc8-ESc=rZ<^waLD3kz7lQEfGo9$dZw5$QCYXF1pGR@|Gl&B5SspC=nWC z%w%h$1sRmBvXpGa@11wT#1Jm-1NnR7^Y*r~VK(Y99X9KQhoCnsQN z*>eRg&j}fe9oix#R}5T)a_7S4!`Og-Ia&~>REnKxx)fovq{%d(G8=M4{^ZA1SS)~52-CqE&HoXZUX=@9srOB8CYSkKt!0} zAwIyrp>A=)r7}p>+rZPp=ZK&bTlr8&ko9P`O1%KbRTYYju`o$^=F+vg$908HF^{Zg zRg7LVF2#ZUR|flzev92Gt^e@$q}A<9@+${tyJK_re#@Wjy4kR?-aE5_2;tdCV;H8H zT&<$owwkA9DUs2l1y0AVezA6OR<_h?CwO++xD@TUQ{xkP%9cToG)uav983w3aMi*; zBTUTID(>4!R+yuS?E7nn*(xcexAW&)5u35_-RImXK^Tuqqp4c5b9O==0v|P=&0(~@ zJ6w4pOd0T5Hy8SlHtMQ%PW%J^gvO!yA;l*O3LcL0ahUzKA^1j8)eZ$~>VxhFDS?D+ zRpg2OI_}szr3UE?MZL3soX3a71f2Ev3OK(=#|HD>7Yf zvsGx8kIb3U!rX?!t}mXV*oNSO&;Lj+OQx)r$sk>OcU+dE)>L2BH6!o!&fcAI(=1V5 zIwLoG%H6K7K*G(DFIVwnS!BdJQrZnV;Zv@c#&n>W$xp6jpCMfzNqo{E8Z2Eav5J%$ zdrTj!TMTkx+|XupPLi) zTygIA-%wNE|YF`sf*H2s;$R-2=`7NOf#q6kjnVAp7_?!o?szBPvk02X%6m`SBdjL zU+&zFz8h^%Mui@usEEnWnV<*eNJ%A{6;i4G?&Hnbdwz08=@_E&of<_c(G=BBXjgKE z*@VKfk|@n@`9`Jrd^oy=Z|eHPyCXjhszYk$RWL36nu#vM(}UwO%IEJg2o1~mDIWrt z+1E=MN0*5S>b!5{yL~#kjr+qcC){35RZJVLPVhU_HZOd`vG3)Z{A%Z_NB*Bzh*5X! zl|BhN(yZ|{nu7Nnsvd4{(J^oTQIVGO^ut^fI%+;QsoeCO)8JX%y$8^H2E7*&dpc5` zytKt>H|tXfe$gidG*eFY7vKo%rxJ>UC)fV(FJgz1BsKx0+(co>pjW1dY?MG`>WC3zM*9Gp{(oAQ=1br^v7u8 zuEYTfE;Yo0CRI`w*%DZA?79dUp zV*#9~@3KQgfrsap$qpI9LjXBDQI0-bwZFzUe>5X5Gwf0#KT=@kXj za_L$<2e8J`eAqihE0)We9eSzp^R2C8uY`tjL@bIuOkBxy{-=oj#l{!@;QUok3_gkU zJS-b8w@Y4A^vzEVqq4j+B`+LE1AO%2qyWy|qNJC5Ox2Sj3#&Q_9?!*izDU>GnV_6b zU@ndw(u=sLXCF#R>Pcm+HBx^}bu3NAys#a!#qFRv*$pwiTA)uFEQZAJF>-Kxq^tAi~^~~(!HOs)sU3&zJ7Pi~*-ODFO zXW3oIJ(q{rO?UfCkHA}Wsirwaa8F*Izv*Zq_D9>Sj@+DtVAL=vSQhQ(I(QRUGg3Jt04mOr_* zUvDJ&u5ce;uZkPI94c`L<^2^`w>Gt+8priyNo$=mM(bk6oGAgda)XMf%`0xYB&U&k zMSqoFHFom-xEychKC2+5hN_64cno{S;_yMeW-xg6{^$_eebim&= za8^_kI)Xkw(g;gD=T-a z(7LQ2Apa9s2~r+WnB$0ml*s_7=7}YA*77{v#Rv2?x12ilRnb_~dC<-6J1TvK|FETh z%&XafoaK(|>2+Pbc4h{z)x-{2=i$Qg;CZgeQ-ug7y`` z`h-d9f#i#KGOp>yJ=m$Orc8E?R10d(vefYM!vSjN4<-Jtdp~Q#| zUY8Ke0XX741p{5U4HzKy_)f6~jR7DVJY|c=a`H1*BM~TE+l>H#_s|1lFIY&F&GOqu zERUFA@vlZ1u=6l!(lN9XSx5l5fd*?5Fj+V*;;)!eBP@H&O(l* zRj~YQq?Zc7Q{{#8ETo`lgf)mSspo*F^efrf;lY9GIo6bR-AR@oka&>A8EEKZA?1(k zSsb<|kR8p;kavUZBm}iZ04!{gm)UIS$N#pG4I#w7`K$vaTXi7Hl?1&TrT@`DmJ}~!^LJPjxJD6z$pO0pGD&Oz z;K&XDdRxff?O}3(2paTo5CQ!=xM4w-x23o!CjeOS0)W&O!MYpBEr^5$uS zh%#HqjvnAG4>@o9 zO$-8a0pQ4={NMHgK+s6=4H{$8N*S{oOlZrf0V}V&E<_mn_;g zu(F#Kw+%uY??L@BV(w~~sN5rt2(N&$Q{P-&eQQm44wOzgv}?Ck^N%X9u;=e;LOOgc z6aeZ%9WT=zycCn?!k?z0s+{8j0K+Xy>8gVhOzLHIyQWv1jSuYVWmP~8*e&F~C*ZF> Kt!+{*O!R*iz94e| delta 4032 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 Date: Fri, 26 Aug 2016 11:19:46 -0400 Subject: [PATCH 113/479] Add license plugin and license headers --- LICENSE.txt => LICENSE | 0 build.gradle | 10 ++++++++++ gradle/DEFAULT_LICENSE_NOTICE | 13 +++++++++++++ .../gradle/plugin/avro/AvroBasePlugin.java | 15 +++++++++++++++ .../gradle/plugin/avro/AvroExtension.java | 15 +++++++++++++++ .../gradle/plugin/avro/AvroPlugin.java | 15 +++++++++++++++ .../gradle/plugin/avro/Constants.java | 15 +++++++++++++++ .../plugin/avro/DefaultAvroExtension.java | 17 ++++++++++++++++- .../commercehub/gradle/plugin/avro/Enums.java | 15 +++++++++++++++ .../gradle/plugin/avro/FileExtensionSpec.java | 15 +++++++++++++++ .../gradle/plugin/avro/FileState.java | 15 +++++++++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 15 +++++++++++++++ .../plugin/avro/GenerateAvroProtocolTask.java | 15 +++++++++++++++ .../gradle/plugin/avro/MapUtils.java | 15 +++++++++++++++ .../gradle/plugin/avro/OutputDirTask.java | 15 +++++++++++++++ .../gradle/plugin/avro/ProcessingState.java | 15 +++++++++++++++ .../gradle/plugin/avro/SetBuilder.java | 15 +++++++++++++++ .../gradle/plugin/avro/TypeState.java | 15 +++++++++++++++ ...mmercehub.gradle.plugin.avro-base.properties | 16 ++++++++++++++++ ...om.commercehub.gradle.plugin.avro.properties | 16 ++++++++++++++++ .../plugin/avro/AvroPluginFunctionalSpec.groovy | 15 +++++++++++++++ .../gradle/plugin/avro/AvroPluginSpec.groovy | 15 +++++++++++++++ .../avro/DuplicateHandlingFunctionalSpec.groovy | 15 +++++++++++++++ .../plugin/avro/EncodingFunctionalSpec.groovy | 15 +++++++++++++++ .../avro/EnumHandlingFunctionalSpec.groovy | 15 +++++++++++++++ .../gradle/plugin/avro/FunctionalSpec.groovy | 15 +++++++++++++++ .../plugin/avro/OptionsFunctionalSpec.groovy | 15 +++++++++++++++ 27 files changed, 386 insertions(+), 1 deletion(-) rename LICENSE.txt => LICENSE (100%) create mode 100644 gradle/DEFAULT_LICENSE_NOTICE diff --git a/LICENSE.txt b/LICENSE similarity index 100% rename from LICENSE.txt rename to LICENSE diff --git a/build.gradle b/build.gradle index 47a064ffde8..f1fda6e3679 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,7 @@ plugins { id "idea" id "maven" id "com.gradle.plugin-publish" version "0.9.4" + id "com.github.hierynomus.license" version "0.13.1" } repositories { @@ -152,3 +153,12 @@ tasks.withType(Test) { minHeapSize "120m" maxHeapSize "280m" } + +license { + header = file("gradle/DEFAULT_LICENSE_NOTICE") + skipExistingHeaders = true + mapping("avdl", "JAVADOC_STYLE") + excludes(["**/*.avsc", "**/*.avpr"]) // JSON doesn't allow comments + exclude("**/record.vm") // Existing header in different style + // dryRun = true +} diff --git a/gradle/DEFAULT_LICENSE_NOTICE b/gradle/DEFAULT_LICENSE_NOTICE new file mode 100644 index 00000000000..9104ff09113 --- /dev/null +++ b/gradle/DEFAULT_LICENSE_NOTICE @@ -0,0 +1,13 @@ +Copyright © 2016 Commerce Technologies, LLC. + +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. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 04c2552d418..fddd9e13747 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2014-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.gradle.api.Action; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 17ec54be45e..e22d81d2287 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2013-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; public interface AvroExtension { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index d79fbd5806b..0a58d9e3cc1 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2013-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.gradle.api.Action; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index c79015f31be..9b7b97e832f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2013-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 310c52c9464..78f51730f25 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2013-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.apache.avro.compiler.specific.SpecificCompiler; @@ -42,7 +57,7 @@ public void setStringType(GenericData.StringType stringType) { public String getFieldVisibility() { return fieldVisibility; } - + public void setFieldVisibility(String fieldVisibility) { this.fieldVisibility = fieldVisibility; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java b/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java index d43499e6a85..18677fe760e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import java.util.Arrays; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java index 03224700dc9..b3056893343 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2013-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.gradle.api.specs.Spec; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java index 234cfa06fb0..fb89e7c9d71 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import java.io.File; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 0c649392514..cdbe5629607 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2013-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.apache.avro.Protocol; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index b2079da40e6..83787fd2edf 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2013-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.apache.avro.compiler.idl.Idl; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java index 6cccfcfcc59..35cf47d378e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import java.util.LinkedHashMap; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java index 1fca25c69ce..939abd17edf 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2013 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.gradle.api.file.FileCollection; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java index 378759322cf..5a73af406b7 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.apache.avro.Schema; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java index b9054170050..1b7f8ee516a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2013-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import java.util.Collection; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java index be63e77744a..604a960cad7 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; import org.apache.avro.Schema; diff --git a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties index b9dc06f0a4f..48eb0524688 100644 --- a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties +++ b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties @@ -1 +1,17 @@ +# +# Copyright © 2014 Commerce Technologies, LLC. +# +# 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. +# + implementation-class=com.commercehub.gradle.plugin.avro.AvroBasePlugin diff --git a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties index 514cc66f7a7..1ba65ec1c95 100644 --- a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties +++ b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties @@ -1 +1,17 @@ +# +# Copyright © 2014 Commerce Technologies, LLC. +# +# 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. +# + implementation-class=com.commercehub.gradle.plugin.avro.AvroPlugin diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 8984b272316..d7220fd8d1f 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -1,3 +1,18 @@ +/* + * Copyright © 2015-2016 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.FAILED diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy index d065e1f79c7..ac8478269c1 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy @@ -1,3 +1,18 @@ +/* + * Copyright © 2013-2015 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro import org.gradle.api.Project diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index 0a0e81156ef..a2ee9729436 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -1,3 +1,18 @@ +/* + * Copyright © 2015-2016 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.FAILED diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy index 205596350ab..b1273b44903 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -1,3 +1,18 @@ +/* + * Copyright © 2015-2016 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro import spock.lang.Unroll diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index e115fa0e7ab..4c75f45c3c4 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -1,3 +1,18 @@ +/* + * Copyright © 2015-2016 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.SUCCESS diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 3c9d9620ea1..3dc4566f02d 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -1,3 +1,18 @@ +/* + * Copyright © 2015-2016 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro import org.gradle.testkit.runner.BuildResult diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 0abaa6d3eb7..2e401456fa7 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -1,3 +1,18 @@ +/* + * Copyright © 2015-2016 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility From bf0358b0f00c9dfd654dfb2ccb60edec83139779 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 26 Aug 2016 11:32:10 -0400 Subject: [PATCH 114/479] Add contribution guidelines --- CONTRIBUTING.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..563da1be7f6 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,19 @@ +Before starting work on an enhancement, it's highly recommended to open an [issue](https://github.com/commercehub-oss/gradle-avro-plugin/issues) to describe the intended change. +This allows for the project maintainers to provide feedback before you've done work that may not fit the project's vision. + +To run the project's build, run: + +* (Mac/Linux): `./gradlew build` +* (Windows): `gradlew.bat build` + +This will run static analysis against the project, run the project's tests, and build the project. +If any failures are detected, please correct them prior to submitting your pull request. + +All enhancements should be accompanied by test coverage. +Our tests are based on [Spock](https://github.com/spockframework/spock). +Generally, it's best to extend our `FunctionalSpec` class, which provides useful functions for running the plugin within Gradle. + +Note that the "build" task only tests the plugin against the a single version of Gradle/Avro. +If you want to test compatibility with a larger range, consider using the `testRecentVersionCompatibility` task or `testVersionCompatibility` task. + +For information on how to use GitHub to submit a pull request, see [Collaborating on projects using issues and pull requests](https://help.github.com/categories/collaborating-on-projects-using-issues-and-pull-requests/). From 091f1c0fad7a72e375652fc775b64c56c4592297 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 26 Aug 2016 12:53:16 -0400 Subject: [PATCH 115/479] Make license plugin only apply if greater than java 6 --- build.gradle | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index f1fda6e3679..df76965bc84 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,8 @@ +buildscript { + dependencies { + classpath "gradle.plugin.nl.javadude.gradle.plugins:license-gradle-plugin:0.13.1" + } +} plugins { id "groovy" id "checkstyle" @@ -5,7 +10,6 @@ plugins { id "idea" id "maven" id "com.gradle.plugin-publish" version "0.9.4" - id "com.github.hierynomus.license" version "0.13.1" } repositories { @@ -154,11 +158,14 @@ tasks.withType(Test) { maxHeapSize "280m" } -license { - header = file("gradle/DEFAULT_LICENSE_NOTICE") - skipExistingHeaders = true - mapping("avdl", "JAVADOC_STYLE") - excludes(["**/*.avsc", "**/*.avpr"]) // JSON doesn't allow comments - exclude("**/record.vm") // Existing header in different style - // dryRun = true +if (org.gradle.api.JavaVersion.current().isJava7Compatible()) { + apply plugin: "com.github.hierynomus.license" + license { + header = file("gradle/DEFAULT_LICENSE_NOTICE") + skipExistingHeaders = true + mapping("avdl", "JAVADOC_STYLE") + excludes(["**/*.avsc", "**/*.avpr"]) // JSON doesn't allow comments + exclude("**/record.vm") // Existing header in different style + // dryRun = true + } } From fde22c82ed9c7385e372ada93506bd1af2039127 Mon Sep 17 00:00:00 2001 From: Anthony Hsu Date: Sun, 20 Nov 2016 12:36:11 -0800 Subject: [PATCH 116/479] Fix typo: change com.commercehub.gradle.plugin.avro to com.commercehub.gradle.plugin.avro-base --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 737d2fe2d37..b0bff5809b5 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ If you do it in the other order, IntelliJ may not properly exclude some director # Alternate Usage If the defaults used by the plugin don't work for you, you can still use the tasks by themselves. -In this case, use the "com.commercehub.gradle.plugin.avro" plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. +In this case, use the `com.commercehub.gradle.plugin.avro-base` plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. Here's a short example of what this might look like: From 1fe59e84fbdd27674183052b65b5cd1b188ad1f1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 1 Feb 2017 14:22:39 -0500 Subject: [PATCH 117/479] Add design docs --- CONTRIBUTING.md | 2 ++ design-docs/external-schemata-and-protocols.md | 9 +++++++++ design-docs/run-avro-as-an-external-process.md | 16 ++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 design-docs/external-schemata-and-protocols.md create mode 100644 design-docs/run-avro-as-an-external-process.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 563da1be7f6..290ab710376 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,8 @@ Before starting work on an enhancement, it's highly recommended to open an [issue](https://github.com/commercehub-oss/gradle-avro-plugin/issues) to describe the intended change. This allows for the project maintainers to provide feedback before you've done work that may not fit the project's vision. +Some possible enhancements may have already been considered and documented. Check the design-docs folder for the design specification for such features. + To run the project's build, run: * (Mac/Linux): `./gradlew build` diff --git a/design-docs/external-schemata-and-protocols.md b/design-docs/external-schemata-and-protocols.md new file mode 100644 index 00000000000..5cb0ac4271a --- /dev/null +++ b/design-docs/external-schemata-and-protocols.md @@ -0,0 +1,9 @@ +Originally requested as [#4](https://github.com/commercehub-oss/gradle-avro-plugin/issues/4). +Some users would like the ability to have JAR files that contain Avro schema/protocol files, and have a way to declare a dependency on these, such that the plugin's generation capability can use them without needing to manual extract the archives. + +Intended approach: + +* The plugin defines a new `Avro` configuration for every source-set that it is working with. +* As with any configuration, the build script can define dependencies in the configuration, and the resolution mechanism will resolve the configuration against the configured repositories when it is resolved. +* A task would be added to extract all such archives to a `/unpacked--avro` directory, per source-set +* The plugin's generation tasks would be configured to use the relevant unpacked directories as additional source directories. diff --git a/design-docs/run-avro-as-an-external-process.md b/design-docs/run-avro-as-an-external-process.md new file mode 100644 index 00000000000..b0c0683c869 --- /dev/null +++ b/design-docs/run-avro-as-an-external-process.md @@ -0,0 +1,16 @@ +Originally reported as [#27](https://github.com/commercehub-oss/gradle-avro-plugin/issues/27). +Currently, Avro generation takes by running the avro-compiler library as part of the Gradle plugin process. +This is simple and works, but has a few drawbacks: + +* Custom templates need to be available on the classpath for the plugin, which isn't compatible with the new style of Gradle plugin declarations. +* The Gradle plugin may use a different version of Avro for generation than you're using on the compile classpath for compilation. + +Instead, here is an alternative view of how it could work. + +* There is an enhanced-avro-compiler library that externalizes most of the logic currently present in GenerateAvroJavaTask/GenerateAvroProtocolTask, and makes those calls accessible as JVM entry points (via `main` methods). + * This library would be published on JCenter and/or Maven Central, and potentially have multiple versions as needed for compatibility with multiple versions of Avro + * It's possible we might be able to get this logic pushed upstream into avro-compiler, in which case the need for this library would be eliminated. +* For a source-set, the plugin would take a single declaration of the desired Avro version, which is then used for both generation and compilation +* The plugin would use a configuration per source-set to resolve the appropriate version of enhanced-avro-compiler + * The build script could add additional dependencies to this configuration in order to pull in custom templates +* When doing generation, the plugin would use [JavaExec](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/JavaExec.html) to spawn a child JVM and execute the appropriate logic in enhanced-avro-compiler. From 389064487b5100a43162077c684dc65b3814cd4b Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 1 Feb 2017 14:54:57 -0500 Subject: [PATCH 118/479] Build with Gradle 3.3, update version cross-compatibility testing --- CHANGES.md | 3 ++- README.md | 5 ++--- build.gradle | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index fe3e0226302..d409d54dec2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,8 @@ # Change Log ## Unreleased -* Built using Gradle 2.14 +* Built using Gradle 3.3 +* Updated versions for cross-compatibility testing ## 0.9.0 * Built using Avro 1.8.1 (#23) diff --git a/README.md b/README.md index b0bff5809b5..8b5f4d52718 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,11 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility * Java 6 or higher required -* Currently built against Gradle 2.14 - * Currently tested against Gradle 2.0-2.14; other versions may be compatible, but 1.x versions are unlikely to work +* Currently built against Gradle 3.3 + * Currently tested against Gradle 2.0-2.14.1 and 3.0-3.3; other versions may be compatible, but 1.x versions are unlikely to work * Currently built against Avro 1.8.1 * Currently tested against Avro 1.8.0-1.8.1; other versions may be compatible * If you need support for Avro 1.7.x, try plugin version 0.8.0; versions of Avro before that are unlikely to work -* Currently tested against Avro 1.8.1; other versions may be compatible # Usage diff --git a/build.gradle b/build.gradle index df76965bc84..f123e1e4c85 100644 --- a/build.gradle +++ b/build.gradle @@ -130,7 +130,7 @@ test { } def avroVersions = ["1.8.0", "1.8.1"] -def gradleVersions = ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14"] +def gradleVersions = ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.14.1", "3.0", "3.1", "3.2", "3.2.1", "3.3"] avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> From 14ffc3cc9a681cecc26455b0e2a454a32aa3b236 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 1 Feb 2017 15:06:26 -0500 Subject: [PATCH 119/479] Don't try to test Gradle 3.x compatibility on Java 6 --- build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f123e1e4c85..bde12634311 100644 --- a/build.gradle +++ b/build.gradle @@ -130,7 +130,11 @@ test { } def avroVersions = ["1.8.0", "1.8.1"] -def gradleVersions = ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.14.1", "3.0", "3.1", "3.2", "3.2.1", "3.3"] +def gradleVersions = ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.14.1"] + +if (org.gradle.api.JavaVersion.current().isJava7Compatible()) { + gradleVersions.addAll("3.0", "3.1", "3.2", "3.2.1", "3.3") +} avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> From 26f0572a0a681137b376f4bff76af4c2114764b3 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 24 Aug 2017 16:47:57 -0400 Subject: [PATCH 120/479] Add code of conduct --- CODE_OF_CONDUCT.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 4 +++ 2 files changed, 82 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..bb0c27088f3 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,78 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at oss-conduct@commercehub.com. +We will endeavor to review submitted complaints and respond in a manner that +CommerceHub (in its sole discretion) deems necessary and appropriate to the +circumstances. In enforcing this Code of Conduct, Project maintainers may +(but shall not be obligated to) remove, edit, or reject comments, commits, +code, wiki edits, issues, and other contributions that are not aligned to +this Code of Conduct, or to ban temporarily or permanently any contributor +for other behaviors that they deem inappropriate, threatening, offensive, +or harmful. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 290ab710376..b526bccf217 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,7 @@ +# Contributing + +> Before contributing, please read our [code of conduct](https://github.com/commercehub-oss/gradle-avro-plugin/blob/master/CODE_OF_CONDUCT.md). + Before starting work on an enhancement, it's highly recommended to open an [issue](https://github.com/commercehub-oss/gradle-avro-plugin/issues) to describe the intended change. This allows for the project maintainers to provide feedback before you've done work that may not fit the project's vision. From faa40cf96bc9e39507287b88bce3c91bfc313e76 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 25 Aug 2017 09:25:26 -0400 Subject: [PATCH 121/479] Try to work around travis-ci failure On openjdk6 $ ./gradlew build testRecentVersionCompatibility Downloading https://services.gradle.org/distributions/gradle-2.14-bin.zip Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cbaf77d50c2..a3b9e9beec3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,9 @@ env: - TERM=dumb - GRADLE_OPTS=-Xmx386m -Xms386m install: true -script: ./gradlew build testRecentVersionCompatibility +script: + - ./gradlew clean + - ./gradlew build testRecentVersionCompatibility jdk: - oraclejdk8 - oraclejdk7 From 6340cfd3c4c1b6c6fc7ccd42fa6c473448e7e918 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 25 Aug 2017 09:27:05 -0400 Subject: [PATCH 122/479] Revert "Try to work around travis-ci failure" This reverts commit faa40cf96bc9e39507287b88bce3c91bfc313e76. --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index a3b9e9beec3..cbaf77d50c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,7 @@ env: - TERM=dumb - GRADLE_OPTS=-Xmx386m -Xms386m install: true -script: - - ./gradlew clean - - ./gradlew build testRecentVersionCompatibility +script: ./gradlew build testRecentVersionCompatibility jdk: - oraclejdk8 - oraclejdk7 From e86f41af3e54ef25a85eb02249bc8f8b87ad30eb Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 25 Aug 2017 12:57:15 -0400 Subject: [PATCH 123/479] Upgrade gradle to version 4.1 --- CHANGES.md | 2 +- README.md | 6 ++-- build.gradle | 4 +-- gradle/wrapper/gradle-wrapper.jar | Bin 53319 -> 54708 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 26 +++++++++----- gradlew.bat | 6 ---- .../avro/AvroPluginFunctionalSpec.groovy | 32 +++++++++--------- .../DuplicateHandlingFunctionalSpec.groovy | 12 +++---- .../avro/EnumHandlingFunctionalSpec.groovy | 14 ++++---- .../gradle/plugin/avro/FunctionalSpec.groovy | 8 +++++ 11 files changed, 61 insertions(+), 52 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d409d54dec2..23f62b5b343 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,7 @@ # Change Log ## Unreleased -* Built using Gradle 3.3 +* Built using Gradle 4.1 * Updated versions for cross-compatibility testing ## 0.9.0 diff --git a/README.md b/README.md index 8b5f4d52718..89544d61618 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Java 6 or higher required -* Currently built against Gradle 3.3 - * Currently tested against Gradle 2.0-2.14.1 and 3.0-3.3; other versions may be compatible, but 1.x versions are unlikely to work +* Currently tested against Java 6-8 +* Currently built against Gradle 4.1 + * Currently tested against Gradle 2.0-2.14.1, 3.0-3.51, and 4.0-4.1; other versions may be compatible, but 1.x versions are unlikely to work * Currently built against Avro 1.8.1 * Currently tested against Avro 1.8.0-1.8.1; other versions may be compatible * If you need support for Avro 1.7.x, try plugin version 0.8.0; versions of Avro before that are unlikely to work diff --git a/build.gradle b/build.gradle index bde12634311..0b342fdd28b 100644 --- a/build.gradle +++ b/build.gradle @@ -102,7 +102,7 @@ checkstyle { } // Nasty workaround for https://issues.gradle.org/browse/GRADLE-2888 def checkstyleWarningsFile = "build/reports/checkstyle/main.xml" -checkstyleMain << { +checkstyleMain.doLast { File warningsFile = file(checkstyleWarningsFile) if (warningsFile.exists() && warningsFile.text.contains(" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d3b83982b9b1bccad955349d702be9b884c6e049..7a3265ee94c0ab25cf079ac8ccdf87f41d455d42 100644 GIT binary patch delta 25563 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 delta 24167 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 K`jG<&(EkDPr&!Mb diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ba2eede98eb..f16d26666b0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Jun 23 14:18:28 PDT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip diff --git a/gradlew b/gradlew index 27309d92314..cccdd3d517f 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index f6d5974e72f..e95643d6a2c 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -49,7 +49,6 @@ goto fail @rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index d7220fd8d1f..7ab39d2f875 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -29,7 +29,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/example/avro/User.class").file + projectFile(buildOutputClassPath("example/avro/User.class")).file } def "can generate and compile java files from json protocol"() { @@ -45,8 +45,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/org/apache/avro/test/Mail.class").file - projectFile("build/classes/main/org/apache/avro/test/Message.class").file + projectFile(buildOutputClassPath("org/apache/avro/test/Mail.class")).file + projectFile(buildOutputClassPath("org/apache/avro/test/Message.class")).file } def "can generate and compile java files from IDL"() { @@ -60,11 +60,11 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { taskInfoAbsent || result.task(":generateAvroProtocol").outcome == SUCCESS taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/org/apache/avro/Foo.class").file - projectFile("build/classes/main/org/apache/avro/Interop.class").file - projectFile("build/classes/main/org/apache/avro/Kind.class").file - projectFile("build/classes/main/org/apache/avro/MD5.class").file - projectFile("build/classes/main/org/apache/avro/Node.class").file + projectFile(buildOutputClassPath("org/apache/avro/Foo.class")).file + projectFile(buildOutputClassPath("org/apache/avro/Interop.class")).file + projectFile(buildOutputClassPath("org/apache/avro/Kind.class")).file + projectFile(buildOutputClassPath("org/apache/avro/MD5.class")).file + projectFile(buildOutputClassPath("org/apache/avro/Node.class")).file } def "supports json schema files in subdirectories"() { @@ -77,7 +77,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/example/avro/User.class").file + projectFile(buildOutputClassPath("example/avro/User.class")).file } def "supports json protocol files in subdirectories"() { @@ -93,8 +93,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/org/apache/avro/test/Mail.class").file - projectFile("build/classes/main/org/apache/avro/test/Message.class").file + projectFile(buildOutputClassPath("org/apache/avro/test/Mail.class")).file + projectFile(buildOutputClassPath("org/apache/avro/test/Message.class")).file } def "supports IDL files in subdirectories"() { @@ -108,11 +108,11 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { taskInfoAbsent || result.task(":generateAvroProtocol").outcome == SUCCESS taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/org/apache/avro/Foo.class").file - projectFile("build/classes/main/org/apache/avro/Interop.class").file - projectFile("build/classes/main/org/apache/avro/Kind.class").file - projectFile("build/classes/main/org/apache/avro/MD5.class").file - projectFile("build/classes/main/org/apache/avro/Node.class").file + projectFile(buildOutputClassPath("org/apache/avro/Foo.class")).file + projectFile(buildOutputClassPath("org/apache/avro/Interop.class")).file + projectFile(buildOutputClassPath("org/apache/avro/Kind.class")).file + projectFile(buildOutputClassPath("org/apache/avro/MD5.class")).file + projectFile(buildOutputClassPath("org/apache/avro/Node.class")).file } def "gives a meaningful error message when presented a malformed schema file"() { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index a2ee9729436..ec686bac7f9 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -35,9 +35,9 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/example/Person.class").file - projectFile("build/classes/main/example/Cat.class").file - projectFile("build/classes/main/example/Gender.class").file + projectFile(buildOutputClassPath("example/Person.class")).file + projectFile(buildOutputClassPath("example/Cat.class")).file + projectFile(buildOutputClassPath("example/Gender.class")).file } def "Duplicate record definition succeeds if definition identical"() { @@ -50,9 +50,9 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/example/Person.class").file - projectFile("build/classes/main/example/Fish.class").file - projectFile("build/classes/main/example/Gender.class").file + projectFile(buildOutputClassPath("example/Person.class")).file + projectFile(buildOutputClassPath("example/Fish.class")).file + projectFile(buildOutputClassPath("example/Gender.class")).file } def "Duplicate enum definition fails if definition differs"() { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index 4c75f45c3c4..483585c4011 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -31,7 +31,7 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/example/avro/MyEnum.class").file + projectFile(buildOutputClassPath("example/avro/MyEnum.class")).file } def "supports enums defined within a record field"() { @@ -44,8 +44,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/example/avro/Test.class").file - projectFile("build/classes/main/example/avro/Gender.class").file + projectFile(buildOutputClassPath("example/avro/Test.class")).file + projectFile(buildOutputClassPath("example/avro/Gender.class")).file } def "supports enums defined within a union"() { @@ -58,8 +58,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/example/avro/Test.class").file - projectFile("build/classes/main/example/avro/Kind.class").file + projectFile(buildOutputClassPath("example/avro/Test.class")).file + projectFile(buildOutputClassPath("example/avro/Kind.class")).file } def "supports using enums defined in a separate schema file"() { @@ -73,7 +73,7 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS - projectFile("build/classes/main/example/avro/User.class").file - projectFile("build/classes/main/example/avro/MyEnum.class").file + projectFile(buildOutputClassPath("example/avro/User.class")).file + projectFile(buildOutputClassPath("example/avro/MyEnum.class")).file } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 3dc4566f02d..e3b729493fa 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -89,4 +89,12 @@ abstract class FunctionalSpec extends Specification { protected boolean isTaskInfoAbsent() { return gradleVersion < TestKitFeature.CAPTURE_BUILD_RESULT_TASKS.since } + + protected isMultipleClassDirectoriesUsed() { + return gradleVersion >= GradleVersion.version("4.0") + } + + protected String buildOutputClassPath(String suffix) { + return isMultipleClassDirectoriesUsed() ? "build/classes/java/main/${suffix}" : "build/classes/main/${suffix}" + } } From d682dc4a45593d1807905a872d7af47ef329722a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 25 Aug 2017 16:56:31 -0400 Subject: [PATCH 124/479] Raise permgen for oracle jdk7 --- .travis.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index cbaf77d50c2..7cfe9fc1b94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,11 @@ env: - GRADLE_OPTS=-Xmx386m -Xms386m install: true script: ./gradlew build testRecentVersionCompatibility -jdk: - - oraclejdk8 - - oraclejdk7 - - openjdk7 - - openjdk6 +matrix: + include: + - jdk: oraclejdk8 + - jdk: oraclejdk7 + env: + - GRADLE_OPTS=-Xmx386m -Xms386m -XX:MaxPermSize=128m + - jdk: openjdk7 + - jdk: openjdk6 From f3d0f3ea4072741ddcb902ca587e25e35d133049 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 25 Aug 2017 16:59:08 -0400 Subject: [PATCH 125/479] Travis: fix environment variables --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7cfe9fc1b94..a8aa7ec4484 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,8 @@ sudo: false language: java env: global: - - TERM=dumb - - GRADLE_OPTS=-Xmx386m -Xms386m + - TERM="dumb" + - GRADLE_OPTS="-Xmx386m -Xms386m" install: true script: ./gradlew build testRecentVersionCompatibility matrix: @@ -11,6 +11,6 @@ matrix: - jdk: oraclejdk8 - jdk: oraclejdk7 env: - - GRADLE_OPTS=-Xmx386m -Xms386m -XX:MaxPermSize=128m + - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" - jdk: openjdk7 - jdk: openjdk6 From 7d3b32b2ac3445f1e4b9e93add51274467954e5a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 09:27:56 -0400 Subject: [PATCH 126/479] Update description to note location of latest artifacts --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0b342fdd28b..59bbcd21a27 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ group = "com.commercehub.gradle.plugin" pluginBundle { website = "https://github.com/commercehub-oss/gradle-avro-plugin" vcsUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" - description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." + description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files. For the latest versions, please see https://bintray.com/commercehub-oss/main/gradle-avro-plugin" tags = ["serialization", "avro"] plugins { avro { From 9df041a7d65e85be5ac4d16f1588eefb3cb59e6b Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 09:30:08 -0400 Subject: [PATCH 127/479] version: 0.9.1 --- CHANGES.md | 2 ++ RELEASING.md | 2 +- build.gradle | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 23f62b5b343..9065696f1a6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.9.1 * Built using Gradle 4.1 * Updated versions for cross-compatibility testing diff --git a/RELEASING.md b/RELEASING.md index e108e11fd02..52a1f137562 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -4,7 +4,7 @@ 1. Update `CHANGES.md` 1. Ensure that there is a milestone for the version, and that appropriate issues are associated with the milestone. 1. Update the plugin version in `build.gradle` under "version" -1. Commit and tag with the version number +1. Commit and tag with the version number (don't push yet) 1. Run `./gradlew clean build publishPlugins` 1. Update the version the next SNAPSHOT and commit. 1. Push diff --git a/build.gradle b/build.gradle index 59bbcd21a27..a5e8e679545 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +33,7 @@ tasks.withType(AbstractCompile) { } sourceCompatibility = 1.6 -version = "0.9.1-SNAPSHOT" +version = "0.9.1" group = "com.commercehub.gradle.plugin" pluginBundle { From f5d69a29d43d883f301fd3e99c07ed32da87888c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 09:31:50 -0400 Subject: [PATCH 128/479] version: 0.10.0-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a5e8e679545..f63527bf5b5 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +33,7 @@ tasks.withType(AbstractCompile) { } sourceCompatibility = 1.6 -version = "0.9.1" +version = "0.10.0-SNAPSHOT" group = "com.commercehub.gradle.plugin" pluginBundle { From 60d4f025caec912124472f2dc84140ae366fea52 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 10:34:27 -0400 Subject: [PATCH 129/479] Modernize for new baseline compatibility * Remove support for Gradle 2.x * Remove support for Java 6 * Update to use Java 7 source compatibility * Use Java 7+ features where appropriate (multi-catch, new APIs) --- .travis.yml | 1 - CHANGES.md | 3 +++ README.md | 7 +++++-- build.gradle | 8 ++------ .../com/commercehub/gradle/plugin/avro/Constants.java | 9 --------- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 2 +- .../gradle/plugin/avro/GenerateAvroProtocolTask.java | 4 +--- 7 files changed, 12 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index a8aa7ec4484..8edcfae80de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,4 +13,3 @@ matrix: env: - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" - jdk: openjdk7 - - jdk: openjdk6 diff --git a/CHANGES.md b/CHANGES.md index 9065696f1a6..9f384afe12d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,9 @@ # Change Log ## Unreleased +* Drop support for Gradle 2.x +* As Gradle 3.0+ has a minimum Java version requiremenet of Java 7, drop support for Java 6 +* Update source compatibility to Java 7 ## 0.9.1 * Built using Gradle 4.1 diff --git a/README.md b/README.md index 89544d61618..a2250ee0b70 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,12 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Java 6-8 +* Currently tested against Java 7-8 + * If you need support for Java 6, version 0.9.1 was the last supported version * Currently built against Gradle 4.1 - * Currently tested against Gradle 2.0-2.14.1, 3.0-3.51, and 4.0-4.1; other versions may be compatible, but 1.x versions are unlikely to work + * Currently tested against Gradle 3.0-3.51 and 4.0-4.1 + * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility + * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.8.1 * Currently tested against Avro 1.8.0-1.8.1; other versions may be compatible * If you need support for Avro 1.7.x, try plugin version 0.8.0; versions of Avro before that are unlikely to work diff --git a/build.gradle b/build.gradle index f63527bf5b5..0dc367f70c6 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ dependencies { tasks.withType(AbstractCompile) { options.encoding = "UTF-8" } -sourceCompatibility = 1.6 +sourceCompatibility = 1.7 version = "0.10.0-SNAPSHOT" group = "com.commercehub.gradle.plugin" @@ -130,11 +130,7 @@ test { } def avroVersions = ["1.8.0", "1.8.1"] -def gradleVersions = ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.14.1"] - -if (org.gradle.api.JavaVersion.current().isJava7Compatible()) { - gradleVersions.addAll("3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1") -} +def gradleVersions = ["3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1"] avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 9b7b97e832f..d20aff4eb96 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -45,13 +45,4 @@ class Constants { static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; static final String OPTION_OUTPUT_CHARACTER_ENCODING = "outputCharacterEncoding"; - - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - - /** - * The system-dependent line separator string. In Java 7+, use System.lineSeparator() instead. - */ - static String lineSeparator() { - return LINE_SEPARATOR; - } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index cdbe5629607..98efd4998d4 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -189,7 +189,7 @@ private int processSchemaFiles() { for (FileState fileState : failedFiles) { String path = fileState.getPath(); String fileErrorMessage = fileState.getErrorMessage(); - errorMessage.append(lineSeparator()).append("* ").append(path).append(": ").append(fileErrorMessage); + errorMessage.append(System.lineSeparator()).append("* ").append(path).append(": ").append(fileErrorMessage); } throw new GradleException(errorMessage.toString()); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 83787fd2edf..6e1e2035cd1 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -74,9 +74,7 @@ private void processIDLFile(File idlFile, ClassLoader loader) { idl = new Idl(idlFile, loader); String protoJson = idl.CompilationUnit().toString(true); writeJsonFile(protoFile, protoJson); - } catch (IOException ex) { - throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); - } catch (ParseException ex) { + } catch (IOException | ParseException ex) { throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); } finally { if (idl != null) { From 7de7340828c54d17740ad58cb90a5eb37e137abe Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 10:34:45 -0400 Subject: [PATCH 130/479] Reduce access to utility methods not intended for re-use --- CHANGES.md | 1 + .../commercehub/gradle/plugin/avro/FileUtils.java | 4 ++-- .../gradle/plugin/avro/FilenameUtils.java | 12 ++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9f384afe12d..2d75430bfd4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ * Drop support for Gradle 2.x * As Gradle 3.0+ has a minimum Java version requiremenet of Java 7, drop support for Java 6 * Update source compatibility to Java 7 +* Reduce access to utility methods not intended for re-use ## 0.9.1 * Built using Gradle 4.1 diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java index 71e64462dca..89913f9dbbf 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java @@ -80,7 +80,7 @@ class FileUtils { * @throws IOException if a parent directory needs creating but that fails * @since Commons IO 1.3 */ - public static FileOutputStream openOutputStream(File file) throws IOException { + private static FileOutputStream openOutputStream(File file) throws IOException { if (file.exists()) { if (file.isDirectory()) { throw new IOException("File '" + file + "' exists but is a directory"); @@ -111,7 +111,7 @@ public static FileOutputStream openOutputStream(File file) throws IOException { * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM */ - public static void writeStringToFile(File file, String data, String encoding) throws IOException { + static void writeStringToFile(File file, String data, String encoding) throws IOException { if (encoding == null) { throw new IllegalArgumentException("Must specify encoding"); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java index 1ada6dbd164..875f54a99ac 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java @@ -115,7 +115,7 @@ class FilenameUtils { * @return the index of the last separator character, or -1 if there * is no such character */ - public static int indexOfLastSeparator(String filename) { + private static int indexOfLastSeparator(String filename) { if (filename == null) { return -1; } @@ -137,7 +137,7 @@ public static int indexOfLastSeparator(String filename) { * @return the index of the last separator character, or -1 if there * is no such character */ - public static int indexOfExtension(String filename) { + private static int indexOfExtension(String filename) { if (filename == null) { return -1; } @@ -163,7 +163,7 @@ public static int indexOfExtension(String filename) { * @param filename the filename to query, null returns null * @return the name of the file without the path, or an empty string if none exists */ - public static String getName(String filename) { + private static String getName(String filename) { if (filename == null) { return null; } @@ -188,7 +188,7 @@ public static String getName(String filename) { * @param filename the filename to query, null returns null * @return the name of the file without the path, or an empty string if none exists */ - public static String getBaseName(String filename) { + static String getBaseName(String filename) { return removeExtension(getName(filename)); } @@ -209,7 +209,7 @@ public static String getBaseName(String filename) { * @param filename the filename to retrieve the extension of. * @return the extension of the file or an empty string if none exists. */ - public static String getExtension(String filename) { + static String getExtension(String filename) { if (filename == null) { return null; } @@ -239,7 +239,7 @@ public static String getExtension(String filename) { * @param filename the filename to query, null returns null * @return the filename minus the extension */ - public static String removeExtension(String filename) { + private static String removeExtension(String filename) { if (filename == null) { return null; } From b720ff4d1a9303082d5542ffd78d3c95a75c8dd1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 11:28:49 -0400 Subject: [PATCH 131/479] Update license plugin Now that we have a minimum of Java 7, we don't need to apply the license plugin conditionally. This allows using the new plugins block. --- build.gradle | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 0dc367f70c6..e4e63c6c8a0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,3 @@ -buildscript { - dependencies { - classpath "gradle.plugin.nl.javadude.gradle.plugins:license-gradle-plugin:0.13.1" - } -} plugins { id "groovy" id "checkstyle" @@ -10,6 +5,7 @@ plugins { id "idea" id "maven" id "com.gradle.plugin-publish" version "0.9.4" + id "com.github.hierynomus.license" version "0.14.0" } repositories { @@ -158,14 +154,11 @@ tasks.withType(Test) { maxHeapSize "280m" } -if (org.gradle.api.JavaVersion.current().isJava7Compatible()) { - apply plugin: "com.github.hierynomus.license" - license { - header = file("gradle/DEFAULT_LICENSE_NOTICE") - skipExistingHeaders = true - mapping("avdl", "JAVADOC_STYLE") - excludes(["**/*.avsc", "**/*.avpr"]) // JSON doesn't allow comments - exclude("**/record.vm") // Existing header in different style - // dryRun = true - } +license { + header = file("gradle/DEFAULT_LICENSE_NOTICE") + skipExistingHeaders = true + mapping("avdl", "JAVADOC_STYLE") + excludes(["**/*.avsc", "**/*.avpr"]) // JSON doesn't allow comments + exclude("**/record.vm") // Existing header in different style + // dryRun = true } From 0ac5ee1bcae5bc952c1a37146f1514065b5462dd Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 13:20:11 -0400 Subject: [PATCH 132/479] Remove explicit type arguments that are no longer needed in Java 7 --- .../com/commercehub/gradle/plugin/avro/AvroPlugin.java | 2 +- .../gradle/plugin/avro/GenerateAvroProtocolTask.java | 4 ++-- .../java/com/commercehub/gradle/plugin/avro/MapUtils.java | 2 +- .../commercehub/gradle/plugin/avro/ProcessingState.java | 8 ++++---- .../com/commercehub/gradle/plugin/avro/TypeState.java | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 0a58d9e3cc1..122cde462a3 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -87,7 +87,7 @@ public void execute(Task task) { .build()); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. - SetBuilder excludeDirs = new SetBuilder(); + SetBuilder excludeDirs = new SetBuilder<>(); excludeDirs.addAll(module.getExcludeDirs()).remove(project.getBuildDir()); File buildDir = project.getBuildDir(); if (buildDir.isDirectory()) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 6e1e2035cd1..7e9811dc468 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -48,7 +48,7 @@ protected void process() { } private void failOnUnsupportedFiles() { - FileCollection unsupportedFiles = filterSources(new NotSpec(new FileExtensionSpec(IDL_EXTENSION))); + FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(IDL_EXTENSION))); if (!unsupportedFiles.isEmpty()) { throw new GradleException( String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); @@ -88,7 +88,7 @@ private void processIDLFile(File idlFile, ClassLoader loader) { } private ClassLoader getRuntimeClassLoader(Project project) { - List urls = new LinkedList(); + List urls = new LinkedList<>(); Configuration configuration = project.getConfigurations().getByName(JavaPlugin.RUNTIME_CONFIGURATION_NAME); for (File file : configuration) { try { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java index 35cf47d378e..f1b0a17a62a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java @@ -26,7 +26,7 @@ static Map asymmetricDifference(Map a, Map b) { if (b == null || b.isEmpty()) { return a; } - Map result = new LinkedHashMap(a); + Map result = new LinkedHashMap<>(a); result.keySet().removeAll(b.keySet()); return result; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java index 5a73af406b7..4cfb2b4edec 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -22,9 +22,9 @@ import java.util.*; class ProcessingState { - private final Map typeStates = new HashMap(); - private final Set delayedFiles = new LinkedHashSet(); - private final Queue filesToProcess = new LinkedList(); + private final Map typeStates = new HashMap<>(); + private final Set delayedFiles = new LinkedHashSet<>(); + private final Queue filesToProcess = new LinkedList<>(); private int processedTotal = 0; ProcessingState(Set files, Project project) { @@ -35,7 +35,7 @@ class ProcessingState { Map determineParserTypes(FileState fileState) { Set duplicateTypeNames = fileState.getDuplicateTypeNames(); - Map types = new HashMap(); + Map types = new HashMap<>(); for (TypeState typeState : typeStates.values()) { String typeName = typeState.getName(); if (!duplicateTypeNames.contains(typeName)) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java index 604a960cad7..fe90e67544f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java @@ -23,7 +23,7 @@ class TypeState { private final String name; - private final Set locations = new TreeSet(); + private final Set locations = new TreeSet<>(); private Schema schema; TypeState(String name) { From 575adf5e8f0df35eb4f2f8c213954ab3e3aa0db0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 13:28:08 -0400 Subject: [PATCH 133/479] Tag output directory for better input/output handling --- .../java/com/commercehub/gradle/plugin/avro/OutputDirTask.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java index 939abd17edf..8a4ee204292 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java @@ -17,6 +17,7 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.specs.Spec; +import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.SourceTask; import java.io.File; @@ -29,6 +30,7 @@ public void setOutputDir(File outputDir) { getOutputs().dir(outputDir); } + @OutputDirectory protected File getOutputDir() { return outputDir; } From 316458814f82c32b7e843cec1485218037dc1a51 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 13:28:49 -0400 Subject: [PATCH 134/479] Enable all compiler linting --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index e4e63c6c8a0..ed94a5a5be7 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,9 @@ dependencies { tasks.withType(AbstractCompile) { options.encoding = "UTF-8" } +tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" +} sourceCompatibility = 1.7 version = "0.10.0-SNAPSHOT" From b5f54a9eabed50bfad4540d434c491bed7995092 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 13:42:01 -0400 Subject: [PATCH 135/479] Fix java compiler warnings --- src/main/java/com/commercehub/gradle/plugin/avro/Enums.java | 2 +- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 2 +- .../java/com/commercehub/gradle/plugin/avro/SetBuilder.java | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java b/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java index 18677fe760e..9d6c77fe56f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java @@ -18,7 +18,7 @@ import java.util.Arrays; class Enums { - static T parseCaseInsensitive(String label, T[] values, String input) { + static > T parseCaseInsensitive(String label, T[] values, String input) { for (T value : values) { if (value.name().equalsIgnoreCase(input)) { return value; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 98efd4998d4..0b3552608a2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -47,7 +47,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { private static Pattern ERROR_UNKNOWN_TYPE = Pattern.compile("(?i).*(undefined name|not a defined name).*"); private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); - private static Set SUPPORTED_EXTENSIONS = SetBuilder.build(PROTOCOL_EXTENSION, SCHEMA_EXTENSION); + private static Set SUPPORTED_EXTENSIONS = new SetBuilder().add(PROTOCOL_EXTENSION).add(SCHEMA_EXTENSION).build(); private String outputCharacterEncoding; private String stringType = DEFAULT_STRING_TYPE; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java index 1b7f8ee516a..e14d3d9321b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java @@ -28,7 +28,7 @@ SetBuilder add(T e) { return this; } - final SetBuilder addAll(T... c) { + final SetBuilder addAll(T[] c) { Collections.addAll(set, c); return this; } @@ -46,8 +46,4 @@ SetBuilder remove(T e) { Set build() { return set; } - - static Set build(T... c) { - return new SetBuilder().addAll(c).build(); - } } From 64ad0660d477bd6339fb946ae2680453fb7db5d5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 14:22:29 -0400 Subject: [PATCH 136/479] Resolve deprecation warning caused by change in runtime configuration handling in Gradle 3.5 --- import-control.xml | 1 + .../commercehub/gradle/plugin/avro/Constants.java | 11 +++++++++++ .../gradle/plugin/avro/GenerateAvroProtocolTask.java | 12 ++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/import-control.xml b/import-control.xml index 6cb25369756..29c831a8f2c 100644 --- a/import-control.xml +++ b/import-control.xml @@ -18,6 +18,7 @@ + diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index d20aff4eb96..87ca8315db1 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -17,6 +17,7 @@ import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; import org.apache.avro.generic.GenericData.StringType; +import org.gradle.api.plugins.JavaPlugin; /** * Various constants needed by the plugin. @@ -45,4 +46,14 @@ class Constants { static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; static final String OPTION_OUTPUT_CHARACTER_ENCODING = "outputCharacterEncoding"; + + /** + * When our minimum supported version is 3.5+, we can remove this + */ + @SuppressWarnings("deprecation") + static final String RUNTIME_CONFIGURATION_NAME = JavaPlugin.RUNTIME_CONFIGURATION_NAME; + /** + * When our minimum supported version is 3.5+, we can use JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME + */ + static final String RUNTIME_CLASSPATH_CONFIGURATION_NAME = "runtimeClasspath"; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 7e9811dc468..e294c5cf16c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -21,9 +21,9 @@ import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.file.FileCollection; -import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.TaskAction; +import org.gradle.util.GradleVersion; import java.io.File; import java.io.IOException; @@ -89,7 +89,7 @@ private void processIDLFile(File idlFile, ClassLoader loader) { private ClassLoader getRuntimeClassLoader(Project project) { List urls = new LinkedList<>(); - Configuration configuration = project.getConfigurations().getByName(JavaPlugin.RUNTIME_CONFIGURATION_NAME); + Configuration configuration = project.getConfigurations().getByName(getRuntimeConfigurationName()); for (File file : configuration) { try { urls.add(file.toURI().toURL()); @@ -101,6 +101,14 @@ private ClassLoader getRuntimeClassLoader(Project project) { : new URLClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader()); } + /** + * Backwards-compatible logic to return the appropriate configuration name for resolving the runtime classpath + */ + private static String getRuntimeConfigurationName() { + return GradleVersion.current().compareTo(GradleVersion.version("3.5")) >= 0 + ? Constants.RUNTIME_CLASSPATH_CONFIGURATION_NAME : Constants.RUNTIME_CONFIGURATION_NAME; + } + /** * Writes a file in a manner appropriate for a JSON file. UTF-8 will be used, as it is the default encoding for JSON, and should be * maximally interoperable. From 2ea2a5262d810468d1b86d480a532dfc12c5c5a7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 28 Aug 2017 14:22:49 -0400 Subject: [PATCH 137/479] Treat compiler warnings as errors --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ed94a5a5be7..339d066a967 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ tasks.withType(AbstractCompile) { options.encoding = "UTF-8" } tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:all" + options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } sourceCompatibility = 1.7 From 31c7d30544d89b5868883fd8169edd48369147e1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 09:15:17 -0400 Subject: [PATCH 138/479] Update release process to use Bintray instead of Gradle Plugin Portal --- CHANGES.md | 2 + RELEASING.md | 3 +- build.gradle | 68 +++++++++++++++---- ...ercehub.gradle.plugin.avro-base.properties | 17 ----- ....commercehub.gradle.plugin.avro.properties | 17 ----- 5 files changed, 58 insertions(+), 49 deletions(-) delete mode 100644 src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties delete mode 100644 src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties diff --git a/CHANGES.md b/CHANGES.md index 2d75430bfd4..3149ac223c3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,8 @@ * As Gradle 3.0+ has a minimum Java version requiremenet of Java 7, drop support for Java 6 * Update source compatibility to Java 7 * Reduce access to utility methods not intended for re-use +* Stopped publishing to [Gradle plugin portal](https://plugins.gradle.org) +* Published [Bintray](https://bintray.com/commercehub-oss/main/gradle-avro-plugin) ## 0.9.1 * Built using Gradle 4.1 diff --git a/RELEASING.md b/RELEASING.md index 52a1f137562..80f7b951727 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -5,7 +5,8 @@ 1. Ensure that there is a milestone for the version, and that appropriate issues are associated with the milestone. 1. Update the plugin version in `build.gradle` under "version" 1. Commit and tag with the version number (don't push yet) -1. Run `./gradlew clean build publishPlugins` +1. Run `./gradlew clean bintrayUpload` +1. Go to the [Bintray page](https://bintray.com/commercehub-oss/main/gradle-avro-plugin), verify the files, and click "Publish". 1. Update the version the next SNAPSHOT and commit. 1. Push 1. If there was a issue requesting the release, close it. diff --git a/build.gradle b/build.gradle index 339d066a967..13d1ebb36a1 100644 --- a/build.gradle +++ b/build.gradle @@ -3,8 +3,9 @@ plugins { id "checkstyle" id "codenarc" id "idea" - id "maven" - id "com.gradle.plugin-publish" version "0.9.4" + id "maven-publish" + id "java-gradle-plugin" + id "com.jfrog.bintray" version "1.7.3" id "com.github.hierynomus.license" version "0.14.0" } @@ -15,7 +16,6 @@ repositories { def compileAvroVersion = "1.8.1" dependencies { - compile gradleApi() compile localGroovy() compile "org.apache.avro:avro-compiler:${compileAvroVersion}" testCompile("org.spockframework:spock-core:1.0-groovy-2.4") { @@ -35,25 +35,65 @@ sourceCompatibility = 1.7 version = "0.10.0-SNAPSHOT" group = "com.commercehub.gradle.plugin" -pluginBundle { - website = "https://github.com/commercehub-oss/gradle-avro-plugin" - vcsUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" - description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files. For the latest versions, please see https://bintray.com/commercehub-oss/main/gradle-avro-plugin" - tags = ["serialization", "avro"] +task sourcesJar(type: Jar, dependsOn: classes) { + from sourceSets.main.allSource + classifier "sources" + extension "jar" +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + from javadoc.destinationDir + classifier "javadoc" + extension "jar" +} + +publishing { + publications { + mainMaven(MavenPublication) { + from components.java + artifact sourcesJar + artifact javadocJar + } + } +} + +bintray { + // dryRun = true + // publish = true + user = project.hasProperty("bintrayUserName") ? bintrayUserName : null + key = project.hasProperty("bintrayApiKey") ? bintrayApiKey : null + publications = ["mainMaven", "avroBasePluginMarkerMaven", "avroPluginMarkerMaven"] + pkg { + repo = "main" + name = project.name + userOrg = "commercehub-oss" + licenses = ["Apache-2.0"] + desc = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." + websiteUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" + issueTrackerUrl = 'https://github.com/commercehub-oss/gradle-avro-plugin/issues' + vcsUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" + labels = ["serialization", "avro"] + githubRepo = "commercehub-oss/gradle-avro-plugin" + version { + name = project.version + vcsTag = project.version + } + } +} + +bintrayUpload.dependsOn build, { generatePomFileForAvroBasePluginMarkerMavenPublication }, { generatePomFileForAvroPluginMarkerMavenPublication } + +gradlePlugin { plugins { avro { id = "com.commercehub.gradle.plugin.avro" - displayName = "Avro Plugin" + implementationClass = "com.commercehub.gradle.plugin.avro.AvroPlugin" } avroBase { id = "com.commercehub.gradle.plugin.avro-base" - displayName = "Avro Base Plugin" + implementationClass = "com.commercehub.gradle.plugin.avro.AvroBasePlugin" } } - mavenCoordinates { - groupId = "com.commercehub.gradle.plugin" - artifactId = "gradle-avro-plugin" - } } idea { diff --git a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties deleted file mode 100644 index 48eb0524688..00000000000 --- a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro-base.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright © 2014 Commerce Technologies, LLC. -# -# 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. -# - -implementation-class=com.commercehub.gradle.plugin.avro.AvroBasePlugin diff --git a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties b/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties deleted file mode 100644 index 1ba65ec1c95..00000000000 --- a/src/main/resources/META-INF/gradle-plugins/com.commercehub.gradle.plugin.avro.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright © 2014 Commerce Technologies, LLC. -# -# 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. -# - -implementation-class=com.commercehub.gradle.plugin.avro.AvroPlugin From 23dd63d45db971b47a16e5bbe8565ac4b3063945 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 09:15:39 -0400 Subject: [PATCH 139/479] Make MapUtils package-protected --- CHANGES.md | 1 + src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 3149ac223c3..a9a969bb488 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ * Reduce access to utility methods not intended for re-use * Stopped publishing to [Gradle plugin portal](https://plugins.gradle.org) * Published [Bintray](https://bintray.com/commercehub-oss/main/gradle-avro-plugin) +* MapUtils class is no longer public ## 0.9.1 * Built using Gradle 4.1 diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java index f1b0a17a62a..e784770a043 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java @@ -18,7 +18,7 @@ import java.util.LinkedHashMap; import java.util.Map; -public class MapUtils { +class MapUtils { /** * Returns the map of all entries present in the first map but not present in the second map (by key). */ From 588764d7845001a0bed13e889af97d87f2ded766 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 09:21:25 -0400 Subject: [PATCH 140/479] Update release instructions to reflect process for configuring bintray publishing --- RELEASING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASING.md b/RELEASING.md index 80f7b951727..2ff4e74c633 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,6 +1,6 @@ # Release Process -1. Check that you've followed the setup steps listed [here](https://plugins.gradle.org/docs/submit) +1. Acquire permissions to publish the package to Bintray and set the keys "bintrayUserName" and "bintrayApiKey" in `~/.gradle/gradle.properties`. 1. Update `CHANGES.md` 1. Ensure that there is a milestone for the version, and that appropriate issues are associated with the milestone. 1. Update the plugin version in `build.gradle` under "version" From bea059cd6125ca06e17852b0e500f6e935a69809 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 09:23:46 -0400 Subject: [PATCH 141/479] version: 0.10.0 --- CHANGES.md | 4 +++- build.gradle | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a9a969bb488..bc8c8b1f5bb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,12 +1,14 @@ # Change Log ## Unreleased + +## 0.10.0 * Drop support for Gradle 2.x * As Gradle 3.0+ has a minimum Java version requiremenet of Java 7, drop support for Java 6 * Update source compatibility to Java 7 * Reduce access to utility methods not intended for re-use * Stopped publishing to [Gradle plugin portal](https://plugins.gradle.org) -* Published [Bintray](https://bintray.com/commercehub-oss/main/gradle-avro-plugin) +* Published to [Bintray](https://bintray.com/commercehub-oss/main/gradle-avro-plugin) * MapUtils class is no longer public ## 0.9.1 diff --git a/build.gradle b/build.gradle index 13d1ebb36a1..a46cb6774b9 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.10.0-SNAPSHOT" +version = "0.10.0" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 180de02a500adcd3b7590457a3e7fb0cf2445c83 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 09:26:17 -0400 Subject: [PATCH 142/479] version: 0.10.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a46cb6774b9..a0acbcbc36e 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.10.0" +version = "0.10.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From b12ac00ea50972ed7295d82df2a421717f1b97fa Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 09:43:41 -0400 Subject: [PATCH 143/479] Update readme to reflect published in jcenter --- README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/README.md b/README.md index a2250ee0b70..5b7c91eaae6 100644 --- a/README.md +++ b/README.md @@ -21,17 +21,9 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](https://github.com/commercehub-oss/gradle-avro-plugin/blob/master/CHANGES.md). ```groovy -// Gradle 2.1 and later -plugins { - id "com.commercehub.gradle.plugin.avro" version "VERSION" -} - -// Earlier versions of Gradle buildscript { repositories { - maven { - url "https://plugins.gradle.org/m2/" - } + jcenter() } dependencies { classpath "com.commercehub.gradle.plugin:gradle-avro-plugin:VERSION" From 1ff319310defe212531d8af9877f9adab82995a3 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 11:18:21 -0400 Subject: [PATCH 144/479] Start testing against java 9 --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8edcfae80de..3c32ae20d0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ sudo: false +dist: trusty language: java env: global: @@ -8,8 +9,11 @@ install: true script: ./gradlew build testRecentVersionCompatibility matrix: include: + - jdk: oraclejdk9 - jdk: oraclejdk8 - jdk: oraclejdk7 env: - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" - jdk: openjdk7 + allow_failures: + - jdk: oraclejdk9 From 119a026a5e35f500d4d1a944013b6083e07b4180 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 13:14:11 -0400 Subject: [PATCH 145/479] travis: switch back to precise trusty broke java 7 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3c32ae20d0a..d12e7220d81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: false -dist: trusty +dist: precise language: java env: global: From c3371d0bbbe7d3e27ffe6a2fb982bae55fb164c0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 13:16:32 -0400 Subject: [PATCH 146/479] travis: try to work around java9 only being available for trusty --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index d12e7220d81..9c074e79f5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,3 +17,7 @@ matrix: - jdk: openjdk7 allow_failures: - jdk: oraclejdk9 +addons: + apt: + packages: + - oracle-java9-installer From dceecb8998bcf2f85c0b04da029498910eb19b5f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 13:28:54 -0400 Subject: [PATCH 147/479] travis: try trusty again --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9c074e79f5a..7b19e5c8a24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: false -dist: precise +dist: trusty language: java env: global: From b57b0f3365132dfd99ea87e1b62ea00092cc17d2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 13:38:16 -0400 Subject: [PATCH 148/479] travis: go back to not doing java9, building on precise on trusty, oraclejdk7 isn't supported due to licensing, and openjdk7 has a distro-specific behavior of not supporting an SSL algorithm needed for gradle wrapper resolution on preceise, oraclejdk9 isn't currently supported for now java7 support is more important than java9 support, thus go back to trusty and skip java9 support --- .travis.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7b19e5c8a24..bab7e6006f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: false -dist: trusty +dist: precise language: java env: global: @@ -14,10 +14,3 @@ matrix: - jdk: oraclejdk7 env: - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" - - jdk: openjdk7 - allow_failures: - - jdk: oraclejdk9 -addons: - apt: - packages: - - oracle-java9-installer From 38c7b04f18f13d79b71311be4b61f751fc0925e3 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Aug 2017 15:07:08 -0400 Subject: [PATCH 149/479] travis: fix the specified jdks --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bab7e6006f4..0d414ce16b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,8 @@ install: true script: ./gradlew build testRecentVersionCompatibility matrix: include: - - jdk: oraclejdk9 - jdk: oraclejdk8 - jdk: oraclejdk7 env: - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" + - jdk: openjdk7 From 0b9719f4530ca980c0c43d157f81263840e2dbe8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 13 Oct 2017 14:46:26 -0400 Subject: [PATCH 150/479] Update the version of the publish-plugin to allow for actually publishing https://discuss.gradle.org/t/plugin-authors-please-use-the-latest-plugin-publish-plugin-others-may-result-in-a-broken-upload/23573 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a5e8e679545..c79a95ee167 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ plugins { id "codenarc" id "idea" id "maven" - id "com.gradle.plugin-publish" version "0.9.4" + id "com.gradle.plugin-publish" version "0.9.7" } repositories { From 8fd66b86d665f4af337ef8eff259da06a2aca320 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 13 Oct 2017 15:40:11 -0400 Subject: [PATCH 151/479] travis: try to work around build bufferoverflow in openjdk7 https://github.com/travis-ci/travis-ci/issues/5227 --- .travis.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0d414ce16b7..db8bdeeb4e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,29 @@ -sudo: false -dist: precise +sudo: true language: java env: global: - TERM="dumb" - - GRADLE_OPTS="-Xmx386m -Xms386m" +addons: + # OpenJDK7 fails with long host names; https://github.com/travis-ci/travis-ci/issues/5227 + hosts: + - buildhost + hostname: buildhost install: true script: ./gradlew build testRecentVersionCompatibility matrix: include: - jdk: oraclejdk8 + os: linux + dist: trusty + env: + - GRADLE_OPTS="-Xmx386m -Xms386m" - jdk: oraclejdk7 + os: linux + dist: precise # on trusty, Oracle JDK 7 is not provided because it reached End of Life in April 2015. env: - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" - jdk: openjdk7 + os: linux + dist: precise # on trusty, openjdk7 fails when connecting to Gradle distro site/plugin portal due to TLS configuration; java.security.NoSuchProviderException: no such provider: SunEC + env: + - GRADLE_OPTS="-Xmx386m -Xms386m" From 9a6619a93b0af873c88514cd20aa8c3a866967ef Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 13 Oct 2017 15:51:44 -0400 Subject: [PATCH 152/479] travis: try to add support for openjdk8 and oraclejdk9 --- .travis.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.travis.yml b/.travis.yml index db8bdeeb4e1..b8e276f488e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ sudo: true language: java +jdk: oraclejdk8 env: global: - TERM="dumb" @@ -11,7 +12,14 @@ addons: install: true script: ./gradlew build testRecentVersionCompatibility matrix: + allow_failures: + - jdk: oraclejdk9 include: + - jdk: oraclejdk9 + os: linux + dist: trusty + env: + - GRADLE_OPTS="-Xmx386m -Xms386m" - jdk: oraclejdk8 os: linux dist: trusty @@ -22,6 +30,11 @@ matrix: dist: precise # on trusty, Oracle JDK 7 is not provided because it reached End of Life in April 2015. env: - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" + - jdk: openjdk8 + os: linux + dist: trusty + env: + - GRADLE_OPTS="-Xmx386m -Xms386m" - jdk: openjdk7 os: linux dist: precise # on trusty, openjdk7 fails when connecting to Gradle distro site/plugin portal due to TLS configuration; java.security.NoSuchProviderException: no such provider: SunEC From f459f3c7607802d965da4a56bd1d5b974d831094 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 13 Oct 2017 15:53:44 -0400 Subject: [PATCH 153/479] travis: centralize default GRADLE_OPTS again --- .travis.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index b8e276f488e..ad819c52f51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,10 @@ -sudo: true +sudo: true # required for hostname addon; https://docs.travis-ci.com/user/hostname language: java jdk: oraclejdk8 env: global: - TERM="dumb" + - GRADLE_OPTS="-Xmx386m -Xms386m" addons: # OpenJDK7 fails with long host names; https://github.com/travis-ci/travis-ci/issues/5227 hosts: @@ -18,13 +19,9 @@ matrix: - jdk: oraclejdk9 os: linux dist: trusty - env: - - GRADLE_OPTS="-Xmx386m -Xms386m" - jdk: oraclejdk8 os: linux dist: trusty - env: - - GRADLE_OPTS="-Xmx386m -Xms386m" - jdk: oraclejdk7 os: linux dist: precise # on trusty, Oracle JDK 7 is not provided because it reached End of Life in April 2015. @@ -33,10 +30,6 @@ matrix: - jdk: openjdk8 os: linux dist: trusty - env: - - GRADLE_OPTS="-Xmx386m -Xms386m" - jdk: openjdk7 os: linux dist: precise # on trusty, openjdk7 fails when connecting to Gradle distro site/plugin portal due to TLS configuration; java.security.NoSuchProviderException: no such provider: SunEC - env: - - GRADLE_OPTS="-Xmx386m -Xms386m" From 6dfebb71a5d48c2c841608e6047abec9407339d4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 13 Oct 2017 16:07:37 -0400 Subject: [PATCH 154/479] build with gradle 4.2.1 --- README.md | 4 ++-- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 54708 -> 54712 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5b7c91eaae6..f14f23c3250 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Java 7-8 * If you need support for Java 6, version 0.9.1 was the last supported version -* Currently built against Gradle 4.1 - * Currently tested against Gradle 3.0-3.51 and 4.0-4.1 +* Currently built against Gradle 4.2.1 + * Currently tested against Gradle 3.0-3.51 and 4.0-4.2.1 * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.8.1 diff --git a/build.gradle b/build.gradle index a0acbcbc36e..a9fb2cb9edc 100644 --- a/build.gradle +++ b/build.gradle @@ -169,7 +169,7 @@ test { } def avroVersions = ["1.8.0", "1.8.1"] -def gradleVersions = ["3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1"] +def gradleVersions = ["3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2", "4.2.1"] avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7a3265ee94c0ab25cf079ac8ccdf87f41d455d42..ed88a042a287c140a32e1639edfc91b2a233da8c 100644 GIT binary patch delta 795 zcmYk4T}YEr7{}l9IOewecvrq|zRp&Pu)Rae%932Deb8trl2#f~U1)|>mXMGjAzer% z&iqrBDUui62!${~D9~`z+FbKvc2ief^yN(!L>FCjJZkP-{r}JJd7g95bB=#FVQe^| zd!KQ6Puiz4Ns><8FReCw%lO&6+{~nIb;N&j(mcOgCsleA4KI|~35Dlufje+)qXND_ zm7$-C zNCU=IXTZy;owQ_Gcc$r5`e0pgFlB6mGbH1oT~6Y=uC2Rv0WW0hF>X)8$7ziUve!Zu zJc`J0<;CaQ^8~EOOGO87rsT&%W4?ez`K!=b7!R`w1w3AuEGqAL;^8fifX_WiXnL#B zW-qtdsPJ0F5gg_6ru73$lC39HMV@L=&=@*Oj#?q#gbtJLtdKe35;E7rRiBGHVU1mb zKkR0MSPq|K8Y*WlQS>sNw%G7~ri|*Z3i&r?M|DJ{V3V+&k-hZf2A4Vb5-FgL7A_Cq z^gE5RTDf%Kd}}hsxHY$lq>8poajRWXl}@&cP)~a=Cl~ zP~a;;g!9j{Dl>u2)sgi94?593S4>K;kTtzYqOGnkepr7V3s~Hj&Nt9#zF)LW9We8L z8aW4rwJmt4VF>L*4siH;&A#wR+e7Y%>Eil69rB*$v$$2d$AZgkDa@W)gZKs0ud hdM7b5xg9l&a_0Yk%%8%#@f=)z#qC9x{!m~g_z#MO4vPQ) delta 660 zcmYL{T}V@59LCT4H#Q?>XANaLQ<7DtN0!d8mPQ(d#Y~%QMV3|&tMxU>NJ!X)MC3)G z_AvS;@^)P$R0w^LIgf76wz=)XuIk3JAY2z+_x7^#T>XB}bDkFt@0kb}ya*SJ>{#m@ zU2-)`lH?t2@#=o{<@%U3qKv<~Hf2~Nx!d%GuJFnw6Yq^^iMUqZ1|lBz0AC{x_70Y5 zCoN0JX(jMat5n7W9%2fr<1)_Z=GD{?PCPv++i~KVE1jt z?KzbNFfq4_9{cdxw+)7@jGb|Xs{C9nIO*RcqA?!LU&LUb44>kA=yZT%jcAU}D>T)M zFTGW0$;f!d_5M{{9^8l@^A5VvFHq}OaQvf6)&Zg21MBgIt05@V9klXR#`c85Jm^eZ zq1<&*EGJr-33bVHR5A?5-D-3XmtuEX#`mN`g?B_$n`)%ekiedhQM4~p3ZErYr`T^e z7S2=hkvQ%BLKAIyBCsNTfP7;dZMc=LV=~^RJ?tBdnJ)Gd7cyt*!z4aWHt`QsSqP2U Zdh7q6h+m|6^)fjv;byi**Btp9{sG{o{Gk8< diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f16d26666b0..74bb77845e0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip From 0b797300af08a6540c464edf13c5a54be38b2f4d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 13 Oct 2017 16:27:27 -0400 Subject: [PATCH 155/479] Document support for Java 9 --- .travis.yml | 2 -- CHANGES.md | 2 ++ README.md | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index ad819c52f51..cce355e071f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,6 @@ addons: install: true script: ./gradlew build testRecentVersionCompatibility matrix: - allow_failures: - - jdk: oraclejdk9 include: - jdk: oraclejdk9 os: linux diff --git a/CHANGES.md b/CHANGES.md index bc8c8b1f5bb..621d2a9de4f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased +* Built using Gradle 4.2.1 +* Began testing using Java 9 ## 0.10.0 * Drop support for Gradle 2.x diff --git a/README.md b/README.md index f14f23c3250..bbd10ccb41e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Java 7-8 +* Currently tested against Java 7-9 + * Java 9 support requires Gradle 4.2.1 or higher * If you need support for Java 6, version 0.9.1 was the last supported version * Currently built against Gradle 4.2.1 * Currently tested against Gradle 3.0-3.51 and 4.0-4.2.1 From 0548787765a3b0b613d72640d52333068a6e55e5 Mon Sep 17 00:00:00 2001 From: Evgeny Shepelyuk Date: Tue, 24 Oct 2017 09:51:40 +0300 Subject: [PATCH 156/479] - Fixing functional tests on Windows - Built with Avro 1.8.2 - Breaking compatibility changes, only compatible with Avro >=1.8.2 - Updated release information - Added `enableDecimalLogicalType` plugin option without passing to complier - Updated README - Processing `enableDecimalLogicalType` by Avro complier - Added Functional tests for `enableDecimalLogicalType` --- CHANGES.md | 3 ++ README.md | 31 ++++++++++++---- build.gradle | 4 +-- .../gradle/plugin/avro/AvroBasePlugin.java | 12 +++++++ .../gradle/plugin/avro/AvroExtension.java | 1 + .../gradle/plugin/avro/Constants.java | 2 ++ .../plugin/avro/DefaultAvroExtension.java | 10 ++++++ .../plugin/avro/GenerateAvroJavaTask.java | 13 +++++++ .../avro/AvroPluginFunctionalSpec.groovy | 4 +-- .../DuplicateHandlingFunctionalSpec.groovy | 9 +++-- .../plugin/avro/OptionsFunctionalSpec.groovy | 35 ++++++++++++++++++- .../commercehub/gradle/plugin/avro/user.avsc | 6 +++- 12 files changed, 114 insertions(+), 16 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 621d2a9de4f..10612e3a29f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,9 @@ ## Unreleased * Built using Gradle 4.2.1 * Began testing using Java 9 +* Built using Avro 1.8.2 +* Breaking backward compatibility with Avro versions older than 1.8.2 +* Add new configuration option "enableDecimalLogicalType" to generate `BigDecimal` for fields annotated with `logicalType` equals to `decimal` ## 0.10.0 * Drop support for Gradle 2.x diff --git a/README.md b/README.md index bbd10ccb41e..8f65d52564c 100644 --- a/README.md +++ b/README.md @@ -51,13 +51,14 @@ Actually, it will attempt to process an "avro" directory in every `SourceSet` (m There are a number of configuration options supported in the `avro` block. -| option | default | description | -| ----------------------- | --------------------- | ------------------------------------------------- | -| createSetters | `true` | `createSetters` passed to Avro compiler | -| fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | -| outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | -| stringType | `"String"` | `stringType` passed to Avro compiler | -| templateDirectory | see below | `templateDir` passed to Avro compiler | +| option | default | description | +| --------------------------| --------------------- | ------------------------------------------------- | +| createSetters | `true` | `createSetters` passed to Avro compiler | +| fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | +| outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | +| stringType | `"String"` | `stringType` passed to Avro compiler | +| templateDirectory | see below | `templateDir` passed to Avro compiler | +| enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | ## createSetters @@ -133,6 +134,22 @@ avro { } ``` +## enableDecimalLogicalType + +Valid values: `true` (default), `false`; supports equivalent `String` values + +By default, generated Java files will use [`java.math.BigDecimal`](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html) +for representing `fixed` or `bytes` fields annotated with `"logicalType": "decimal"`. +Set to `false` to use [`java.nio.ByteBuffer`](https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html) in generated classes. + +Example: + +```groovy +avro { + enableDecimalLogicalType = false +} +``` + # IntelliJ Integration The plugin attempts to make IntelliJ play more smoothly with generated sources when using Gradle-generated project files. diff --git a/build.gradle b/build.gradle index a9fb2cb9edc..90b6fee25a2 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ repositories { jcenter() } -def compileAvroVersion = "1.8.1" +def compileAvroVersion = "1.8.2" dependencies { compile localGroovy() @@ -168,7 +168,7 @@ test { ] } -def avroVersions = ["1.8.0", "1.8.1"] +def avroVersions = ["1.8.2"] def gradleVersions = ["3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2", "4.2.1"] avroVersions.each { def avroVersion -> diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index fddd9e13747..00e4657d7d9 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -52,6 +52,12 @@ public Boolean call() throws Exception { return DEFAULT_CREATE_SETTERS; } }); + extensionMapping.map(OPTION_ENABLE_DECIMAL_LOGICAL_TYPE, new Callable() { + @Override + public Boolean call() throws Exception { + return DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; + } + }); project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override public void execute(GenerateAvroJavaTask task) { @@ -86,6 +92,12 @@ public Boolean call() throws Exception { return avroExtension.isCreateSetters(); } }); + taskMapping.map(OPTION_ENABLE_DECIMAL_LOGICAL_TYPE, new Callable() { + @Override + public Boolean call() throws Exception { + return avroExtension.isEnableDecimalLogicalType(); + } + }); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index e22d81d2287..ed7b9cfb52d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -21,4 +21,5 @@ public interface AvroExtension { String getFieldVisibility(); String getTemplateDirectory(); boolean isCreateSetters(); + boolean isEnableDecimalLogicalType(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 87ca8315db1..5c3392e567d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -31,6 +31,7 @@ class Constants { static final String DEFAULT_STRING_TYPE = StringType.String.name(); static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); static final boolean DEFAULT_CREATE_SETTERS = true; + static final boolean DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE = true; static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; @@ -41,6 +42,7 @@ class Constants { static final String AVRO_EXTENSION_NAME = "avro"; + static final String OPTION_ENABLE_DECIMAL_LOGICAL_TYPE = "enableDecimalLogicalType"; static final String OPTION_CREATE_SETTERS = "createSetters"; static final String OPTION_TEMPLATE_DIRECTORY = "templateDirectory"; static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 78f51730f25..00f8e3f843a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -26,6 +26,7 @@ public class DefaultAvroExtension implements AvroExtension { private String fieldVisibility; private String templateDirectory; private boolean createSetters; + private boolean enableDecimalLogicalType; @Override public String getOutputCharacterEncoding() { @@ -83,4 +84,13 @@ public boolean isCreateSetters() { public void setCreateSetters(String createSetters) { this.createSetters = Boolean.parseBoolean(createSetters); } + + @Override + public boolean isEnableDecimalLogicalType() { + return enableDecimalLogicalType; + } + + public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { + this.enableDecimalLogicalType = Boolean.parseBoolean(enableDecimalLogicalType); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 0b3552608a2..b7db550f8e5 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -54,6 +54,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { private String fieldVisibility = DEFAULT_FIELD_VISIBILITY; private String templateDirectory; private boolean createSetters = DEFAULT_CREATE_SETTERS; + private boolean enableDecimalLogicalType = DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; private transient StringType parsedStringType; private transient FieldVisibility parsedFieldVisibility; @@ -117,6 +118,15 @@ public void setCreateSetters(String createSetters) { this.createSetters = Boolean.parseBoolean(createSetters); } + @Input + public boolean isEnableDecimalLogicalType() { + return enableDecimalLogicalType; + } + + public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { + this.enableDecimalLogicalType = Boolean.parseBoolean(enableDecimalLogicalType); + } + @TaskAction protected void process() { parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); @@ -127,6 +137,7 @@ protected void process() { getLogger().debug("Using fieldVisibility {}", parsedFieldVisibility.name()); getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); getLogger().debug("Using createSetters {}", isCreateSetters()); + getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); preClean(); @@ -255,6 +266,8 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept compiler.setTemplateDir(templateDirectory); } compiler.setCreateSetters(isCreateSetters()); + compiler.setEnableDecimalLogicalType(isEnableDecimalLogicalType()); + compiler.compileToDestination(sourceFile, getOutputDir()); } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 7ab39d2f875..277049796d8 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -118,14 +118,14 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def "gives a meaningful error message when presented a malformed schema file"() { given: copyResource("enumMalformed.avsc", avroDir) - + def errorFilePath = new File("src/main/avro/enumMalformed.avsc").path when: def result = runAndFail() then: taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED result.output.contains("> Could not compile schema definition files:") - result.output.contains("* src/main/avro/enumMalformed.avsc: \"enum\" is not a defined name. The type of the \"gender\" " + + result.output.contains("* $errorFilePath: \"enum\" is not a defined name. The type of the \"gender\" " + "field must be a defined name or a {\"type\": ...} expression.") } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index ec686bac7f9..d777cbae23c 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -58,6 +58,8 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def "Duplicate enum definition fails if definition differs"() { given: copyDifferentEnum() + def errorFilePath1 = new File("src/main/avro/duplicate/Dog.avsc").path + def errorFilePath2 = new File("src/main/avro/duplicate/Person.avsc").path when: def result = runAndFail() @@ -65,20 +67,21 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED result.output.contains("Found conflicting definition of type example.Gender in " - + "[src/main/avro/duplicate/Dog.avsc, src/main/avro/duplicate/Person.avsc]") + + "[$errorFilePath1, $errorFilePath2]") } def "Duplicate record definition fails if definition differs"() { given: copyDifferentRecord() - + def errorFilePath1 = new File("src/main/avro/duplicate/Person.avsc").path + def errorFilePath2 = new File("src/main/avro/duplicate/Spider.avsc").path when: def result = runAndFail() then: taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED result.output.contains("Found conflicting definition of type example.Person in " - + "[src/main/avro/duplicate/Person.avsc, src/main/avro/duplicate/Spider.avsc]") + + "[$errorFilePath1, $errorFilePath2]") } private void copyIdenticalEnum() { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 2e401456fa7..26a55fc4851 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -48,6 +48,9 @@ class OptionsFunctionalSpec extends FunctionalSpec { and: "createSetters is enabled" content.contains("public void setName(java.lang.String value)") + + and: "enableDecimalLogicalType is enabled" + content.contains("public void setSalary(${BigDecimal.name} value)") } @Unroll @@ -146,7 +149,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { buildFile << """ |buildscript { | dependencies { - | classpath files(["${templatesDir.parentFile.absolutePath}"]) + | classpath files(["${templatesDir.parentFile.toURI()}"]) | } |} |avro { @@ -198,4 +201,34 @@ class OptionsFunctionalSpec extends FunctionalSpec { taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED result.output.contains("Invalid fieldVisibility 'badValue'. Value values are: [PUBLIC, PUBLIC_DEPRECATED, PRIVATE]") } + + @Unroll + def "supports configuring enableDecimalLogicalType to #enableDecimalLogicalType"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | enableDecimalLogicalType = $enableDecimalLogicalType + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "the task succeeds" + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + + and: "the specified enableDecimalLogicalType is used" + content.contains("public void setSalary(${BigDecimal.name} value)") == expectedPresent + + where: + enableDecimalLogicalType | expectedPresent + "Boolean.TRUE" | true + "Boolean.FALSE" | false + "true" | true + "false" | false + "'true'" | true + "'false'" | false + } } diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc index 117ea70ee06..cebed396766 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc @@ -4,6 +4,10 @@ "fields": [ {"name": "name", "type": "string"}, {"name": "favorite_number", "type": ["int", "null"]}, - {"name": "favorite_color", "type": ["string", "null"]} + {"name": "favorite_color", "type": ["string", "null"]}, + { + "name": "salary", + "type": { "type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2 } + } ] } From 82a8394c37e6e00b176d76e79c2fe13f5d79d102 Mon Sep 17 00:00:00 2001 From: Ievgenii Shepeliuk Date: Wed, 25 Oct 2017 21:19:42 +0300 Subject: [PATCH 157/479] Apply PR review --- .../plugin/avro/OptionsFunctionalSpec.groovy | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 26a55fc4851..634b64e2701 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -19,6 +19,8 @@ import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility import org.apache.avro.generic.GenericData.StringType import spock.lang.Unroll +import java.nio.ByteBuffer + import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -220,15 +222,15 @@ class OptionsFunctionalSpec extends FunctionalSpec { def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified enableDecimalLogicalType is used" - content.contains("public void setSalary(${BigDecimal.name} value)") == expectedPresent + content.contains("public void setSalary(${fieldClz.name} value)") where: - enableDecimalLogicalType | expectedPresent - "Boolean.TRUE" | true - "Boolean.FALSE" | false - "true" | true - "false" | false - "'true'" | true - "'false'" | false + enableDecimalLogicalType | fieldClz + "Boolean.TRUE" | BigDecimal + "Boolean.FALSE" | ByteBuffer + "true" | BigDecimal + "false" | ByteBuffer + "'true'" | BigDecimal + "'false'" | ByteBuffer } } From 219d337a44ad0732aa020939b47db28ee9d151df Mon Sep 17 00:00:00 2001 From: Ievgenii Shepeliuk Date: Wed, 25 Oct 2017 22:00:11 +0300 Subject: [PATCH 158/479] Improving CHANGES.md on PR --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 10612e3a29f..cc5a2ee88a0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ * Built using Avro 1.8.2 * Breaking backward compatibility with Avro versions older than 1.8.2 * Add new configuration option "enableDecimalLogicalType" to generate `BigDecimal` for fields annotated with `logicalType` equals to `decimal` +* Breaking backward compatibility caused by "enableDecimalLogicalType" default value set `true`. `BigDecimal` will be used instead of old usage of `ByteBuffer` ## 0.10.0 * Drop support for Gradle 2.x From b326a914de0edb0f9b03ed522d687ca077957e0d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 27 Oct 2017 15:34:28 -0400 Subject: [PATCH 159/479] version: 0.11.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index cc5a2ee88a0..ee04912a64c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.11.0 * Built using Gradle 4.2.1 * Began testing using Java 9 * Built using Avro 1.8.2 diff --git a/build.gradle b/build.gradle index 90b6fee25a2..8343345cc5a 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.10.1-SNAPSHOT" +version = "0.11.0" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From cda248e055b957ca5abdae5d408e1763667cc3ed Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 27 Oct 2017 15:36:30 -0400 Subject: [PATCH 160/479] version: 0.11.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8343345cc5a..e8db0ba8c20 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.11.0" +version = "0.11.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 5f8e708b4e9d5cdceec0c670e1b858e40375dc36 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 9 Nov 2017 14:26:33 -0500 Subject: [PATCH 161/479] Try to improve compatibility with kotlin-gradle-plugin (#36) --- CHANGES.md | 1 + README.md | 4 ++ .../gradle/plugin/avro/AvroPlugin.java | 34 +++++++++++-- .../avro/AvroPluginFunctionalSpec.groovy | 27 ++++++++++ .../gradle/plugin/avro/FunctionalSpec.groovy | 4 +- .../KotlinCompatibilityFunctionalSpec.groovy | 49 +++++++++++++++++++ .../gradle/plugin/avro/helloWorld.kt | 8 +++ 7 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt diff --git a/CHANGES.md b/CHANGES.md index ee04912a64c..467d9b4c568 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Improve support for Kotlin ## 0.11.0 * Built using Gradle 4.2.1 diff --git a/README.md b/README.md index 8f65d52564c..170f524b090 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,10 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently built against Avro 1.8.1 * Currently tested against Avro 1.8.0-1.8.1; other versions may be compatible * If you need support for Avro 1.7.x, try plugin version 0.8.0; versions of Avro before that are unlikely to work +* Incubating: support for Kotlin + * Currently tested against Kotlin 1.1.51 + * Kotlin 1.1.2 and higher requires Java 8+ + * Doesn't work with Gradle 3.2-3.2.1 # Usage diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 122cde462a3..5a240341aa0 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -21,10 +21,13 @@ import org.gradle.api.Task; import org.gradle.api.internal.ConventionMapping; import org.gradle.api.internal.IConventionAware; +import org.gradle.api.plugins.AppliedPlugin; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.specs.Spec; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.api.tasks.SourceTask; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.plugins.ide.idea.GenerateIdeaModule; import org.gradle.plugins.ide.idea.IdeaPlugin; @@ -49,7 +52,8 @@ private static void configureTasks(final Project project) { getSourceSets(project).all(new Action() { public void execute(SourceSet sourceSet) { GenerateAvroProtocolTask protoTask = configureProtocolGenerationTask(project, sourceSet); - configureJavaGenerationTask(project, sourceSet, protoTask); + GenerateAvroJavaTask javaTask = configureJavaGenerationTask(project, sourceSet, protoTask); + configureTaskDependencies(project, sourceSet, javaTask); } }); } @@ -78,12 +82,10 @@ public void execute(Task task) { module.setSourceDirs(new SetBuilder() .addAll(module.getSourceDirs()) .add(getAvroSourceDir(project, mainSourceSet)) - .add(mainGeneratedOutputDir) .build()); module.setTestSourceDirs(new SetBuilder() .addAll(module.getTestSourceDirs()) .add(getAvroSourceDir(project, testSourceSet)) - .add(testGeneratedOutputDir) .build()); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. @@ -133,6 +135,8 @@ public File call() throws Exception { } }); + sourceSet.getJava().srcDir(task.getOutputDir()); + final JavaCompile compileJavaTask = getCompileJavaTask(project, sourceSet); compileJavaTask.source(task.getOutputDir()); compileJavaTask.source(task.getOutputs()); @@ -150,6 +154,30 @@ public String call() throws Exception { return task; } + private static void configureTaskDependencies(final Project project, final SourceSet sourceSet, final GenerateAvroJavaTask javaTask) { + project.getPluginManager().withPlugin("org.jetbrains.kotlin.jvm", new Action() { + @Override + public void execute(AppliedPlugin appliedPlugin) { + project.getTasks().matching(new Spec() { + @Override + public boolean isSatisfiedBy(Task task) { + String compilationTaskName = sourceSet.getCompileTaskName("kotlin"); + return compilationTaskName.equals(task.getName()); + } + }).all(new Action() { + @Override + public void execute(Task task) { + if (task instanceof SourceTask) { + ((SourceTask) task).source(javaTask.getOutputs()); + } else { + task.dependsOn(javaTask); + } + } + }); + } + }); + } + private static File getAvroSourceDir(Project project, SourceSet sourceSet) { return project.file(String.format("src/%s/avro", sourceSet.getName())); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 277049796d8..79f8c51bd9e 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -119,6 +119,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { given: copyResource("enumMalformed.avsc", avroDir) def errorFilePath = new File("src/main/avro/enumMalformed.avsc").path + when: def result = runAndFail() @@ -128,4 +129,30 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { result.output.contains("* $errorFilePath: \"enum\" is not a defined name. The type of the \"gender\" " + "field must be a defined name or a {\"type\": ...} expression.") } + + def "generated intellij project files include source directories for generated source"() { + given: + buildFile << """ + apply plugin: "idea" + """ + copyResource("user.avsc", avroDir) + testProjectDir.newFolder("src", "main", "java") + testProjectDir.newFolder("src", "test", "java") + testProjectDir.newFolder("src", "test", "avro") + + when: + run("idea") + + then: + def moduleFile = new File(testProjectDir.root, "${testProjectDir.root.name}.iml") + def module = new XmlSlurper().parseText(moduleFile.text) + module.component.content.sourceFolder.findAll { it.@isTestSource.text() == "false" }.@url*.text().sort() == [ + 'file://$MODULE_DIR\$/build/generated-main-avro-java', + 'file://$MODULE_DIR\$/src/main/avro', 'file://$MODULE_DIR\$/src/main/java', + ] + module.component.content.sourceFolder.findAll { it.@isTestSource.text() == "true" }.@url*.text().sort() == [ + 'file://$MODULE_DIR\$/build/generated-test-avro-java', + 'file://$MODULE_DIR\$/src/test/avro', 'file://$MODULE_DIR\$/src/test/java', + ] + } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index e3b729493fa..0a622426264 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -25,8 +25,8 @@ import spock.lang.Specification @SuppressWarnings(["Println"]) abstract class FunctionalSpec extends Specification { - protected final String avroVersion = System.getProperty("avroVersion") - protected final GradleVersion gradleVersion = GradleVersion.version(System.getProperty("gradleVersion")) + protected static final String avroVersion = System.getProperty("avroVersion") + protected static final GradleVersion gradleVersion = GradleVersion.version(System.getProperty("gradleVersion")) @Rule TemporaryFolder testProjectDir diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy new file mode 100644 index 00000000000..d73949b8d23 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy @@ -0,0 +1,49 @@ +package com.commercehub.gradle.plugin.avro + +import org.gradle.util.GradleVersion +import spock.lang.IgnoreIf + +class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { + /** + * Since Kotlin 1.1.2, the Kotlin compiler requires Java 8+ + * https://blog.jetbrains.com/kotlin/2017/04/kotlin-1-1-2-is-out/ + * + * Kotlin support appears broken on Gradle 3.2-3.2.1 + * https://discuss.kotlinlang.org/t/1-1-50-js-compiler-requires-kotlin-reflect/4699 + */ + @IgnoreIf({ javaVersion < 1.8 || + (gradleVersion >= GradleVersion.version("3.2") && gradleVersion <= GradleVersion.version("3.2.1")) } + ) + def "works with kotlin-gradle-plugin"() { + given: + File kotlinDir = testProjectDir.newFolder("src", "main", "kotlin") + buildFile << """ + buildscript { + repositories { + jcenter() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.51" + } + } + apply plugin: "kotlin" + apply plugin: "application" + repositories { + jcenter() + } + dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib" + runtime "joda-time:joda-time:2.9.9" + } + mainClassName = "demo.HelloWorldKt" + """ + copyResource("user.avsc", avroDir) + copyResource("helloWorld.kt", kotlinDir) + + when: + def result = run("run") + + then: + result.output.contains("Hello, David") + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt b/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt new file mode 100644 index 00000000000..c56be2acabb --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt @@ -0,0 +1,8 @@ +package demo + +import example.avro.User + +fun main(args : Array) { + val user = User("David", 24, "blue", null) + println("Hello, ${user.getName()}") +} From 071081239e82000947f313c5560ce5930e098f10 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 9 Nov 2017 14:41:59 -0500 Subject: [PATCH 162/479] Fix style issues --- .../gradle/plugin/avro/AvroPlugin.java | 19 ++++++++-------- .../avro/AvroPluginFunctionalSpec.groovy | 2 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 2 ++ .../KotlinCompatibilityFunctionalSpec.groovy | 22 ++++++++++++++++--- .../gradle/plugin/avro/helloWorld.kt | 16 ++++++++++++++ 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 5a240341aa0..63044c627d3 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -164,16 +164,17 @@ public boolean isSatisfiedBy(Task task) { String compilationTaskName = sourceSet.getCompileTaskName("kotlin"); return compilationTaskName.equals(task.getName()); } - }).all(new Action() { - @Override - public void execute(Task task) { - if (task instanceof SourceTask) { - ((SourceTask) task).source(javaTask.getOutputs()); - } else { - task.dependsOn(javaTask); + }) + .all(new Action() { + @Override + public void execute(Task task) { + if (task instanceof SourceTask) { + ((SourceTask) task).source(javaTask.getOutputs()); + } else { + task.dependsOn(javaTask); + } } - } - }); + }); } }); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 79f8c51bd9e..e3dafc7604d 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright © 2015-2016 Commerce Technologies, LLC. + * Copyright © 2015-2017 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 0a622426264..63cbaf72497 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -25,7 +25,9 @@ import spock.lang.Specification @SuppressWarnings(["Println"]) abstract class FunctionalSpec extends Specification { + @SuppressWarnings(["FieldName"]) protected static final String avroVersion = System.getProperty("avroVersion") + @SuppressWarnings(["FieldName"]) protected static final GradleVersion gradleVersion = GradleVersion.version(System.getProperty("gradleVersion")) @Rule diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy index d73949b8d23..5457e347204 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy @@ -1,3 +1,18 @@ +/* + * Copyright © 2017 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro import org.gradle.util.GradleVersion @@ -11,9 +26,10 @@ class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { * Kotlin support appears broken on Gradle 3.2-3.2.1 * https://discuss.kotlinlang.org/t/1-1-50-js-compiler-requires-kotlin-reflect/4699 */ - @IgnoreIf({ javaVersion < 1.8 || - (gradleVersion >= GradleVersion.version("3.2") && gradleVersion <= GradleVersion.version("3.2.1")) } - ) + @IgnoreIf({ + javaVersion < 1.8 || + (gradleVersion >= GradleVersion.version("3.2") && gradleVersion <= GradleVersion.version("3.2.1")) + }) def "works with kotlin-gradle-plugin"() { given: File kotlinDir = testProjectDir.newFolder("src", "main", "kotlin") diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt b/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt index c56be2acabb..ed9f0034b99 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt @@ -1,3 +1,19 @@ +/* + * Copyright © 2017 Commerce Technologies, LLC. + * + * 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 demo import example.avro.User From 8bc4a34d0cd10027157fa7ff07dfd2628490be75 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 16 Nov 2017 09:14:25 -0500 Subject: [PATCH 163/479] version: 0.12.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 467d9b4c568..c21fcee4c4e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +# 0.12.0 * Improve support for Kotlin ## 0.11.0 diff --git a/build.gradle b/build.gradle index e8db0ba8c20..95eb8ce39a6 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.11.1-SNAPSHOT" +version = "0.12.0" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 753a9c4486fa985939f712da0978962c12e7918b Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 16 Nov 2017 09:18:38 -0500 Subject: [PATCH 164/479] version: 0.12.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 95eb8ce39a6..c260d7c0299 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.12.0" +version = "0.12.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From d1cdc5b7494169568e0c70d9417d798322bbca5b Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 20 Nov 2017 09:20:55 -0500 Subject: [PATCH 165/479] Improve documentation (#37) --- CHANGES.md | 2 +- README.md | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c21fcee4c4e..f4995a349a0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,7 +3,7 @@ ## Unreleased # 0.12.0 -* Improve support for Kotlin +* Improve support for Kotlin (#36) ## 0.11.0 * Built using Gradle 4.2.1 diff --git a/README.md b/README.md index 170f524b090..08f75564d76 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ avro { Valid values: `true` (default), `false`; supports equivalent `String` values -By default, generated Java files will use [`java.math.BigDecimal`](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html) +By default, generated Java files will use [`java.math.BigDecimal`](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html) for representing `fixed` or `bytes` fields annotated with `"logicalType": "decimal"`. Set to `false` to use [`java.nio.ByteBuffer`](https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html) in generated classes. @@ -238,3 +238,10 @@ and `Cat.avsc`: There may be cases where the schema files contain inline type definitions and it is undesirable to modify them. In this case, the plugin will automatically recognize any duplicate type definitions and check if they match. If any conflicts are identified, it will cause a build failure. + +# Kotlin Support + +The Java classes generated from your Avro files should be automatically accessible in the classpath to Kotlin classes in the same sourceset, and transitively to any sourcesets that depend on that sourceset. +This is accomplished by this plugin detecting that the Kotlin plugin has been applied, and informing the Kotlin compilation tasks of the presence of the generated sources directories for cross-compilation. + +This support does *not* support producing the Avro generated classes as Kotlin classes, as that functionality is not currently provided by the upstream Avro library. From 7ab22952f0fdb4a720ae3a4c9c504f1a45511045 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 30 Nov 2017 09:15:20 -0500 Subject: [PATCH 166/479] Correct compatibility notes in README (closes #39) --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 08f75564d76..29264bc6c47 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,9 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Gradle 3.0-3.51 and 4.0-4.2.1 * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility * Other versions may be compatible, but Gradle 1.x versions are unlikely to work -* Currently built against Avro 1.8.1 - * Currently tested against Avro 1.8.0-1.8.1; other versions may be compatible +* Currently built against Avro 1.8.2 + * Currently tested against Avro 1.8.2; other versions may be compatible + * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.x, try plugin version 0.8.0; versions of Avro before that are unlikely to work * Incubating: support for Kotlin * Currently tested against Kotlin 1.1.51 @@ -44,7 +45,7 @@ repositories { jcenter() } dependencies { - compile "org.apache.avro:avro:1.8.1" + compile "org.apache.avro:avro:1.8.2" } ``` @@ -172,7 +173,7 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - compile "org.apache.avro:avro:1.8.1" + compile "org.apache.avro:avro:1.8.2" } task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { From 54de99c07c270374b570073965269bf45b13fa9b Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 30 Nov 2017 10:38:09 -0500 Subject: [PATCH 167/479] Upgrade CodeNarc to 1.0 to avoid a build-time Java 7 incompatibility The build was failing in Java 7 (discovered in TravisCI). The root cause was a new version of Groovy being published (3.0.0-alpha-1) which requires Java 8+. This version was being pulled in because CodeNarc 0.24.1 depends on GMetrics 0.7, which has an open-ended dependency on Groovy. CodeNarc 1.0 depends on GMetrics 1.0 which doesn't have this issue. Error: Execution failed for task ':codenarcTest'. > groovy/lang/GroovySystem : Unsupported major.minor version 52.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c260d7c0299..a2b2316db62 100644 --- a/build.gradle +++ b/build.gradle @@ -149,7 +149,7 @@ checkstyleMain.doLast { } codenarc { - toolVersion = "0.24.1" + toolVersion = "1.0" config = project.resources.text.fromFile("config/codenarc/codenarc.groovy") } From fe2f819b13e6c453114e6c325696702e9f21595e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 14 Dec 2017 14:00:01 -0500 Subject: [PATCH 168/479] Add notes about how to use with plugin DSL (#40) --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 29264bc6c47..62946f4e79b 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,29 @@ dependencies { If you now run `gradle build`, Java classes will be compiled from Avro files in `src/main/avro`. Actually, it will attempt to process an "avro" directory in every `SourceSet` (main, test, etc.) +Alternatively, if you prefer to use the incubating plugins DSL, see the following example: + +`settings.gradle`: +```groovy +pluginManagement { + repositories { + gradlePluginPortal() + jcenter() + maven { + name "JCenter Gradle Plugins" + url "https://dl.bintray.com/gradle/gradle-plugins" + } + } +} +``` + +`build.gradle`: +```groovy +plugins { + id "com.commercehub.gradle.plugin.avro" version "VERSION" +} +``` + # Configuration There are a number of configuration options supported in the `avro` block. From c4ba0ea9cfd937a665f2f7f1312e1d19e83a6a93 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 18 Dec 2017 10:04:13 -0500 Subject: [PATCH 169/479] Try to fix travis build; java 9 was failing due to an image change --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cce355e071f..bd0befbd3fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ sudo: true # required for hostname addon; https://docs.travis-ci.com/user/hostname language: java +group: stable jdk: oraclejdk8 env: global: @@ -11,12 +12,13 @@ addons: - buildhost hostname: buildhost install: true -script: ./gradlew build testRecentVersionCompatibility +script: ./gradlew build testRecentVersionCompatibility --info matrix: include: - jdk: oraclejdk9 os: linux dist: trusty + group: deprecated-2017Q4 - jdk: oraclejdk8 os: linux dist: trusty From 334b8bc83530e13d2907fef7022c8ef495d03873 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 18 Dec 2017 10:12:32 -0500 Subject: [PATCH 170/479] Update commits in travis build --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index bd0befbd3fa..0f1e7345dff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,8 @@ matrix: os: linux dist: trusty group: deprecated-2017Q4 + # Looks like Java 9.0.1 introduced new Gradle incompatibilities resolved in 4.2.1 and 4.3 + # https://discuss.gradle.org/t/could-not-determine-java-version-from-9-0-1/24457 - jdk: oraclejdk8 os: linux dist: trusty From b96484940dda8c49bdf40046f9834ed137768dd3 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 26 Dec 2017 10:11:19 -0500 Subject: [PATCH 171/479] Add warning to README about pre-cleaning behavior (#41) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 62946f4e79b..ba1a0e847c7 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,12 @@ If you do it in the other order, IntelliJ may not properly exclude some director If the defaults used by the plugin don't work for you, you can still use the tasks by themselves. In this case, use the `com.commercehub.gradle.plugin.avro-base` plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. +

+ Here's a short example of what this might look like: ```groovy From 9c66c30831808cff21bfc7ad07da8e4b6a032582 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 26 Dec 2017 10:38:48 -0500 Subject: [PATCH 172/479] Update formatting in README --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index ba1a0e847c7..dead7ff68a7 100644 --- a/README.md +++ b/README.md @@ -189,11 +189,9 @@ If you do it in the other order, IntelliJ may not properly exclude some director If the defaults used by the plugin don't work for you, you can still use the tasks by themselves. In this case, use the `com.commercehub.gradle.plugin.avro-base` plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. - Here's a short example of what this might look like: From 28e3f7d69f183f737630760a440876bd4d487523 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 26 Dec 2017 11:10:00 -0500 Subject: [PATCH 173/479] Remove pre-cleaning behavior (#41) --- CHANGES.md | 3 ++- README.md | 4 ---- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 12 ------------ 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f4995a349a0..4672323a982 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,8 +1,9 @@ # Change Log ## Unreleased +* Remove pre-cleaning behavior from `GenerateAvroJavaTask` (#41) -# 0.12.0 +## 0.12.0 * Improve support for Kotlin (#36) ## 0.11.0 diff --git a/README.md b/README.md index dead7ff68a7..62946f4e79b 100644 --- a/README.md +++ b/README.md @@ -189,10 +189,6 @@ If you do it in the other order, IntelliJ may not properly exclude some director If the defaults used by the plugin don't work for you, you can still use the tasks by themselves. In this case, use the `com.commercehub.gradle.plugin.avro-base` plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. -**WARNING**: `GenerateAvroJavaTask` deletes the contents of the `outputDir` on every execution. -This is neccesary in order to work around a behavior in the upstream Avro compiler where Java files will not be re-generated if they have a newer "last modified" date than their corresponding schema file, regardless of whether other schema files used in the process have been modified. -To avoid data loss, set the `outputDir` to a directory within the project `buildDir` dedicated to usage by this task. - Here's a short example of what this might look like: ```groovy diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index b7db550f8e5..e2a2b06b4c2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -140,7 +140,6 @@ protected void process() { getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); - preClean(); processFiles(); } @@ -152,17 +151,6 @@ private void failOnUnsupportedFiles() { } } - /** - * We need to remove all previously generated Java classes. Otherwise, when we call - * {@link SpecificCompiler#compileToDestination(java.io.File, java.io.File)}, it will skip generating classes for any schema files where - * the generated class is newer than the schema file. That seems like a useful performance optimization, but it can cause problems in - * the case where the schema file for this class hasn't changed, but the schema definition for one of the types it depends on has, - * resulting in some usages of a type now having outdated schema. - */ - private void preClean() { - getProject().delete(getOutputDir()); - } - private void processFiles() { int processedFileCount = 0; processedFileCount += processProtoFiles(); From 229af127838b88385ecad9c4dd11343c5ae451ab Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 26 Dec 2017 11:54:59 -0500 Subject: [PATCH 174/479] version: 0.13.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 4672323a982..f1ce43c8b39 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.13.0 * Remove pre-cleaning behavior from `GenerateAvroJavaTask` (#41) ## 0.12.0 diff --git a/build.gradle b/build.gradle index a2b2316db62..fd44bb46b5c 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.12.1-SNAPSHOT" +version = "0.13.0" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From b2570eb86383eefbdc66b04680715e9a976954d1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 26 Dec 2017 11:57:57 -0500 Subject: [PATCH 175/479] version: 0.13.1-SNAPSHOT --- RELEASING.md | 2 +- build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 2ff4e74c633..347dda44f70 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -7,7 +7,7 @@ 1. Commit and tag with the version number (don't push yet) 1. Run `./gradlew clean bintrayUpload` 1. Go to the [Bintray page](https://bintray.com/commercehub-oss/main/gradle-avro-plugin), verify the files, and click "Publish". -1. Update the version the next SNAPSHOT and commit. +1. Update the version in `build.gradle` to the next SNAPSHOT and commit. 1. Push 1. If there was a issue requesting the release, close it. 1. Close the milestone. diff --git a/build.gradle b/build.gradle index fd44bb46b5c..13824a15ae8 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.13.0" +version = "0.13.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From ae1fd81ef5120e4dfddfdc32a57526243c135061 Mon Sep 17 00:00:00 2001 From: Rafal Glowinski Date: Sat, 27 Jan 2018 00:50:05 +0100 Subject: [PATCH 176/479] Support for validation of default values in schema (#42) --- README.md | 16 +++++ .../gradle/plugin/avro/AvroBasePlugin.java | 6 ++ .../gradle/plugin/avro/AvroExtension.java | 1 + .../gradle/plugin/avro/Constants.java | 2 + .../plugin/avro/DefaultAvroExtension.java | 10 ++++ .../plugin/avro/GenerateAvroJavaTask.java | 13 ++++ .../plugin/avro/OptionsFunctionalSpec.groovy | 59 +++++++++++++++++++ .../plugin/avro/userWithInvalidDefaults.avsc | 13 ++++ 8 files changed, 120 insertions(+) create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/userWithInvalidDefaults.avsc diff --git a/README.md b/README.md index 62946f4e79b..ce2fe696ac3 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ There are a number of configuration options supported in the `avro` block. | stringType | `"String"` | `stringType` passed to Avro compiler | | templateDirectory | see below | `templateDir` passed to Avro compiler | | enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | +| validateDefaults | `false` | `setValidateDefaults` set on Avro Schema Parser | ## createSetters @@ -178,6 +179,21 @@ avro { } ``` +## validateDefaults + +Valid values: `false` (default), `true`; supports equivalent `String` values + +Set to `true` to force validation of default values in schema files. Each validation error will cause the build to fail. +Due to backward compatibility requirements this option is disabled by default. + +Example: + +```groovy +avro { + validateDefaults = true +} +``` + # IntelliJ Integration The plugin attempts to make IntelliJ play more smoothly with generated sources when using Gradle-generated project files. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 00e4657d7d9..c722e8e2257 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -98,6 +98,12 @@ public Boolean call() throws Exception { return avroExtension.isEnableDecimalLogicalType(); } }); + taskMapping.map(OPTION_ENABLE_VALIDATE_DEFAULTS, new Callable() { + @Override + public Boolean call() throws Exception { + return avroExtension.isValidateDefaults(); + } + }); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index ed7b9cfb52d..ec69794545a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -22,4 +22,5 @@ public interface AvroExtension { String getTemplateDirectory(); boolean isCreateSetters(); boolean isEnableDecimalLogicalType(); + boolean isValidateDefaults(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 5c3392e567d..cc0585716c2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -32,6 +32,7 @@ class Constants { static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); static final boolean DEFAULT_CREATE_SETTERS = true; static final boolean DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE = true; + static final boolean DEFAULT_VALIDATE_DEFAULTS = false; static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; @@ -42,6 +43,7 @@ class Constants { static final String AVRO_EXTENSION_NAME = "avro"; + static final String OPTION_ENABLE_VALIDATE_DEFAULTS = "validateDefaults"; static final String OPTION_ENABLE_DECIMAL_LOGICAL_TYPE = "enableDecimalLogicalType"; static final String OPTION_CREATE_SETTERS = "createSetters"; static final String OPTION_TEMPLATE_DIRECTORY = "templateDirectory"; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 00f8e3f843a..093a7eb35a1 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -27,6 +27,7 @@ public class DefaultAvroExtension implements AvroExtension { private String templateDirectory; private boolean createSetters; private boolean enableDecimalLogicalType; + private boolean validateDefaults; @Override public String getOutputCharacterEncoding() { @@ -93,4 +94,13 @@ public boolean isEnableDecimalLogicalType() { public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { this.enableDecimalLogicalType = Boolean.parseBoolean(enableDecimalLogicalType); } + + @Override + public boolean isValidateDefaults() { + return validateDefaults; + } + + public void setValidateDefaults(boolean validateDefaults) { + this.validateDefaults = validateDefaults; + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index e2a2b06b4c2..44709f35b2b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -55,6 +55,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { private String templateDirectory; private boolean createSetters = DEFAULT_CREATE_SETTERS; private boolean enableDecimalLogicalType = DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; + private boolean validateDefaults = DEFAULT_VALIDATE_DEFAULTS; private transient StringType parsedStringType; private transient FieldVisibility parsedFieldVisibility; @@ -127,6 +128,15 @@ public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { this.enableDecimalLogicalType = Boolean.parseBoolean(enableDecimalLogicalType); } + @Input + public boolean isValidateDefaults() { + return validateDefaults; + } + + public void setValidateDefaults(boolean validateDefaults) { + this.validateDefaults = validateDefaults; + } + @TaskAction protected void process() { parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); @@ -138,6 +148,7 @@ protected void process() { getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); getLogger().debug("Using createSetters {}", isCreateSetters()); getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType()); + getLogger().debug("Using validateDefaults {}", isValidateDefaults()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); processFiles(); @@ -203,6 +214,8 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt try { Schema.Parser parser = new Schema.Parser(); parser.addTypes(parserTypes); + parser.setValidateDefaults(isValidateDefaults()); + compile(parser.parse(sourceFile), sourceFile); Map typesDefinedInFile = asymmetricDifference(parser.getTypes(), parserTypes); processingState.processTypeDefinitions(fileState, typesDefinedInFile); diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 634b64e2701..bf97b0cbb4c 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -233,4 +233,63 @@ class OptionsFunctionalSpec extends FunctionalSpec { "'true'" | BigDecimal "'false'" | ByteBuffer } + + @Unroll + def "supports configuring validateDefaults to #validateDefaults"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | validateDefaults = $validateDefaults + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "the task succeeds" + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + + where: + validateDefaults | fieldClz + "Boolean.TRUE" | BigDecimal + "Boolean.FALSE" | ByteBuffer + "true" | BigDecimal + "false" | ByteBuffer + "'true'" | BigDecimal + "'false'" | ByteBuffer + } + + def "validation of default values should cause the build to fail for invalid schema file"() { + given: + copyResource("userWithInvalidDefaults.avsc", avroDir) + buildFile << """ + |avro { + | validateDefaults = true + |} + |""".stripMargin() + + when: + def result = runAndFail("generateAvroJava") + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.output.contains("Invalid default for field name: null not a \"string\"") + } + + def "lack of validation of default values should cause the build to succeed for invalid schema file"() { + given: + copyResource("userWithInvalidDefaults.avsc", avroDir) + buildFile << """ + |avro { + | validateDefaults = false + |} + |""".stripMargin() + + when: + def result = runAndFail("generateAvroJava") + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + } } diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/userWithInvalidDefaults.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/userWithInvalidDefaults.avsc new file mode 100644 index 00000000000..efc9ca78b4d --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/userWithInvalidDefaults.avsc @@ -0,0 +1,13 @@ +{"namespace": "example.avro", + "type": "record", + "name": "User", + "fields": [ + {"name": "name", "type": "string", "default": null}, + {"name": "favorite_number", "type": ["int", "null"]}, + {"name": "favorite_color", "type": ["string", "null"]}, + { + "name": "salary", + "type": { "type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2 } + } + ] +} From f2eb735977f9c566d0b0494f4df4bc2921ed5fe2 Mon Sep 17 00:00:00 2001 From: Rafal Glowinski Date: Sat, 27 Jan 2018 00:59:25 +0100 Subject: [PATCH 177/479] Failing test fix (#42) --- .../commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index bf97b0cbb4c..25e851369c3 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -287,7 +287,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { |""".stripMargin() when: - def result = runAndFail("generateAvroJava") + def result = run("generateAvroJava") then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS From 091c544ee271a4f4a3781de7490a9da979c9747c Mon Sep 17 00:00:00 2001 From: Rafal Glowinski Date: Wed, 31 Jan 2018 10:02:08 +0100 Subject: [PATCH 178/479] Add info in changes.md and make it clear that validation of defaults will be always 'on' in future versions. (#42) --- CHANGES.md | 1 + README.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index f1ce43c8b39..2c6be70475f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Support for validation of default values in schema (#42) ## 0.13.0 * Remove pre-cleaning behavior from `GenerateAvroJavaTask` (#41) diff --git a/README.md b/README.md index ce2fe696ac3..3bcb5bd765e 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,8 @@ avro { Valid values: `false` (default), `true`; supports equivalent `String` values Set to `true` to force validation of default values in schema files. Each validation error will cause the build to fail. -Due to backward compatibility requirements this option is disabled by default. +In order to maintain backward compatibility this option is disabled by default, but in the next big release, this option will +be removed and schema validation will always be enabled. Example: From a667538bb11bded948e13aad85af5439eb9bdfc7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 5 Feb 2018 10:28:38 -0500 Subject: [PATCH 179/479] Improvde task documentation in plugin build --- build.gradle | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 13824a15ae8..672943d1c28 100644 --- a/build.gradle +++ b/build.gradle @@ -154,11 +154,13 @@ codenarc { } tasks.create("testVersionCompatibility") { - description = "Tests cross-compatibility of the plugin with different versions of Avro and Gradle" + description = "Tests cross-compatibility of the plugin with different versions of Avro and Gradle." + group = "Verification" } tasks.create("testRecentVersionCompatibility") { - description = "Tests cross-compatibility of the plugin with recent versions of Avro and Gradle" + description = "Tests cross-compatibility of the plugin with recent versions of Avro and Gradle." + group = "Verification" } test { From e9214858de07faabe562bf9b5cbb43a98e018db6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 5 Feb 2018 11:24:24 -0500 Subject: [PATCH 180/479] Upgrade gradle to 4.5, update testing compatibility --- CHANGES.md | 4 +++- README.md | 4 ++-- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 54712 -> 54329 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 2c6be70475f..09d0485e78c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,9 @@ # Change Log ## Unreleased -* Support for validation of default values in schema (#42) +* Built using Gradle 4.5 +* Updated compatibility testing through Gradle 4.5 +* Support for validation of default values in schema (#42) ## 0.13.0 * Remove pre-cleaning behavior from `GenerateAvroJavaTask` (#41) diff --git a/README.md b/README.md index 3bcb5bd765e..3e0b52fb9e0 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Java 7-9 * Java 9 support requires Gradle 4.2.1 or higher * If you need support for Java 6, version 0.9.1 was the last supported version -* Currently built against Gradle 4.2.1 - * Currently tested against Gradle 3.0-3.51 and 4.0-4.2.1 +* Currently built against Gradle 4.5 + * Currently tested against Gradle 3.0-3.51 and 4.0-4.5 * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.8.2 diff --git a/build.gradle b/build.gradle index 672943d1c28..fc79cfe24dd 100644 --- a/build.gradle +++ b/build.gradle @@ -171,7 +171,7 @@ test { } def avroVersions = ["1.8.2"] -def gradleVersions = ["3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2", "4.2.1"] +def gradleVersions = ["3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2", "4.2.1", "4.3", "4.3.1", "4.4", "4.4.1", "4.5"] avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ed88a042a287c140a32e1639edfc91b2a233da8c..a5fe1cb94b9ee5ce57e6113458225bcba12d83e3 100644 GIT binary patch delta 16093 zcmZ9zV|XQ9vp*bXV%xTD+qP{Rdt!6Pb|$tl6Wg|JCzDL(&2yjgf1m3<{bkpxRaM<< zclE-rs@ki-JAQyCa>2ZES^g9P0Rd4@5>|uGym!5G1qDgOZD=KMf^EK903Cn?0pUUf z0*Z)%iBs@^TunVMG!67mN`y>yoOM*|1y?NC5*UX?U141j>NZ;@X*)WJP#e~=kOlb+ z`S!@@mkXxdA+Dn#XlIz}ab3oI|68k9vBewtGN24)5+jkXW&XtHv)A+Iv(4wn`^pYT z_xBsq)gVY5ry=BiQNGp#Q$9==8EvPSJy-mjU0Hm9R$;V>j3i?`KReFNIQ8JH%9Ac; z8e_GcN;lTQ3NkR2I@)vuT}%dkC9I7iyb)ecQX<$s&3=nMjlx~gP|fMbT67KGn$8qq z>a1WDR&=F713Qf0h1W=>nivCSV^eD>7F_YjY2gpe!p0(utBwr{UWfZ!T&_jeOsQ7( z+PG3cm=%9rs$1H1Vp8I_e!0lAA$<#(79JomL$XmHD_tq%mSGz6=IBf_>{@W?F#M`ID@1JG9`+a;LW-^{1R+=gdq`5u+j%vYr?K}NdFe~-$3N;Mtc!QI$U)O&N% zj#MKwv$mSvW;tgSEp#f!cCsps@%Y+w(7g_THvire!v{~GywNO8V$XCj`I%>hRy&hB zA}6X8;9Ry%F?&hKK%1`fqLUP%Ez)GQ9NI*~ft)zqJKTb4axh{07FvY^Lss$K7-|`q zP6jGOQt8q0T)ylfe|LA7%IE!8EwIl~r^~6woGeYV7Q0)=$oR!vg6lp@`Ilsi`g}Ct zjiyFl6Ruj9bLsxplsS@GswDcCqoEG?8Sx%(ctr4ziwWgmF98$mV+8=%x+=K+ubS;; zbf=1R_$e>(IhlfGgB-=z-&%ziYr6085KoP@P>LnEB~ia}p1a z5Q+#e>X6VbAw_i(+~sNMI1+t|m&q;wwLXSRje03~aMPpK;1?IEVQ5&v!IaRmMd@%g0!swdVVpgjpR!PjI27rU1q7B?zHD1^H0f*wG1u~O@4l_yAPW*>epI;bmaLp z+$jG_>h=pOWpI@`w}(K@mg%DN+}om;VQR8za_0l=jceN_b>KoG|RO|IIx?d{yA7UGeRcR59=ple);=$K{B_Vc+?K9 z63-WvFHYq<7vgZ(16O?L9=;5r#6N>(lZP#l^E3Q;fo&)ki$y-rJS?3V0LHznh)?=3 z(2NmSMJLt$-XniOty0-G?n*grkGx384c(}SI!{`I^3e=JPGL&Vk9D} zXeCZb==~DSGXd_d$fqo@WJaj9RwEx*rG56&PUzL&J+2bUGl}6+CeVX(*CI?}R6x>c z6_B&BC5)=b4!O1pZ@#(*Sb;wzA2vwjs}6B{rs36ooR+byyFjAGxeJI@fU_~7K+VoK zjxqD3^0l@kB-4RwOVxpbL$i?K)k!uq^k8!16|ZeEN9fusMn9s-p$tm&uGA-8;Xy09 z+z3RH>3<1K&@QukF?(b%hk{IsFl;B(1P%R$My?nMk>6x!Yo?$DfVexKKM6-&<~gT7 z)JBUxC;#1j9WHdu(fNtBAat{J<iq{vbQxXb7}X zcll8X`(oH9mzeaJoneWuCzCmuJUf}0xtRh&0Kgw8;vfr{n#63IC^_p8`Xu|&2$M}T z7Sesel~@^M7RLRcNEjGFdD+BU=|M9T8bG+@MT;iv5RUIcxK1KmS)-x)k-rMCJg$a8 z!br)kv$G_FVo5&vDYVRPnS8+hXV=?L%vSH7eny`9{@q;8WsPu7#?edrnu=pLiyG$S$}_D5KNvY){AKS=*bmg8xz&{* zTLL^gBw>n7x{>&7lrY@|qaMJMB~NbFF4D&H<7N(mX-@r>EOh2p@@Ij_FE4gWQ=wTG z5El;7tTN^esfTUQ5)DT$kR4lcSyI5I@>-+Up)54Cd5pCcj(Y>WsQsEJ)uq1sp(1SC zoSdWcHKGd`B!Sd7uRR#&l+VT(9oV>h^s9`uoeaD;6HYZyM#7*NY+_YzOE(if+i3~p zmL}XL7ATjnQ*?`hR73qO@(!8DG%Zmg6^N`;aj@cDr5cFjk{6VKZ=cd~#^ZFxLDuVZ ze?XPxz#-5!49*Z37l-Y0ZwxKW*h*Yzn{T{QRHyd-V*y_I zv~1*Bo3wpy^YyKIJFVST{u?9{#$z?k<&y$>=Y=e1H>(KYmp$pdM*=x?aUFab-x4Mf z6RymV2NZKP;X%g1*iZpRN)OK)Eo&@+6--F$^|dd?MInQpS^JcgCT6Atl+Igck^~bw z1{{1$!z03-Zu^aR!~)(KCxzLjx(i*5#HM8ij|vj2e7^ZR&au)qfqTe-7a-N7=t{gR zSBqpiVNa~w@GlYqn!^x4p^brY%h<3+aP>jJ@OZj*>4;2OGN?DhX7rgTMLYb{B=1yjc^`JwT4F3~IB-~1!R5&!!Y z(U>z?vPtET%${t$gDUQTcjDZV@exEWdcguu1v9g-p_L7PdWw)RI8C}W{cNOv)@Klu zWx*e)e|xD~8RywKI0%S890&+M&^d@4s2somur3iHW(ozNl~IOUY(tH5Na6h9z-6MK z1vIc~s`w214E==TTR_wuZr$NsVERM!2PHSJ3r~zW2qB*BkE_viz%|cI!1HF)OWoHR zfFO*EWRWvC&tl8U+ONGoI+j>ZPZlEwsy~bouQX^LW~T8=FqPzhcBF+w|D>JdfKm_$ zV2SmJ?~X<0!-2ZGd6aaIHz9S>T~c3CZL`y@R9#TBv+SwG-SF9(b*$19YjO=W zTt?XHopcUZ$NQx0XL0h{b!E$jpU>*3VaY)bkF)Hl*6~_&jiWE@)={y`t}Ko5nV^R0 zgx}M+Dzvd#aj!DL%05a{f;uWQv0l~%C^)dQ2Q&C2$3DA@Qz5877YGcV3BnE3+n_rv zHNq*`Z?SXt8e_YRIMVAjkF6}be%-!Jg zbR!cnPuvyy8cYH1y{sY-yp15iU0TC>h?_oJUp~Hg6eN7)hCH=fr##pFK_D9qprFhC z06!P_%rYv`WTQc?AdVRCX<`|+39D!#-$%WD(ms&LpB!uYU;vr@ntVV9Nny_--c7FV zjP!!TnwNBqn}G08F-L}@M9^HaOHT<=<%GQt4Xxc!In`;os+F(Nyj(7{;fiBZD$yv} z9+~ZyR53QZNH6BhBm{RPr8{&Cc-0JwZj976X+QNTc>+gdU-uJvE&c7hcXciz6uOy6 zr=%gbp>$dh_Ev1<+^MyF=4-v*P8|N!8?F2^T~?D0qh>CWacb^J_w+z;roADn)lhCr zH9vB{V@5cvx^fNvgx97s^WN8~+$KRpk~!ltq7M`L3}?0c8mUL!2fDNz&?Na%Wpk@Q zsoqD!aX~wleAf4{y(imJ<o0}lKD8lAA+$!uwh28p`cbZA z;H!8``Og(-_AU`Op(k1TPdNVuZ&T>ceCz9hh($syJ9|)YdlXPlLZT#xl;v*;F82sl z;!A1v@I(jt6Bj$!{UA^40LBtk{ytCUdX#sZUMy_+ZitsXBzTKbmNTUigNFtpl=U$E z=mmCUvhI6-tbx*5mop5-l#j7}I0!H1`*%iBiUu+s${xwymu`g@cJ8?;g z1px+u1_4L7yBaU6H4C}y5n8zU1_5k%ORf9h17NJ3soQM3jVAe~6WlT1S*g+wUmmKi zWTt-Mxc8L1*V!Lu)NKxq|4iG#%YRsau$?eu&INz3#o_ur7&Xt+V1|_;0m;Dx(cT8t zb27KE@^`Xd?`^akH6HwL;%*hZ_tI+`p_8&Hf{EC~xHstzF`jE3VuSM9$4OAjgaqj| zWk9?ne6?HDABn%}@WI3WC7W}1-$6+ND>{9}5cK>4MwLIX*avKtbPtHXLACoMGr3eyYAJHm|I3K}tgBF_WUOf@f~3 zAX_Gl6Qp9C&)R8hF0quYCis%AHrYuWq?!b&g^sdVE8iq&j89X{}5vhm}v7S~% zpm?R^U$~NTfDJ!h>S&O<(+GLOsBMF7tF{LT*yL}yJxx7an*ARqvR|&dHr}`Vb^^w3{`x-hk-%_e@#um>uDy(QUaTIE&*}^Qg;aPSA1RZG`LUoB0teWJf`HMj(ms~UgdSF)>O^R;lf^2k3Xt}eI(JzJDy z$lp?it~OEyO9gH0qJDc$HQG2ymSe79@Yy8qH_B{OZFz{!9XxG!Wb5Q^)#z9tUgo))!gH)>uhzEFwdDz>r_x|0d>jbl~NpPvcqd7A8ed5~khP z$41z_5oQGA!fKZ%u@|2+;FiC2!{_lLX2n`=Qk!u&?yl*9xebf1nP!b6_F8!Z?DAtT z>QyB<&MnvrR3y>T#cyh?*^~C+T+%AX(=ccajlt8Kw=y{HB*8XACAlg$l zS3b0;eJU~lFTrHosn}0~6X7Bbkc7Cfz?X=K^_nHwGYC53A-S2Qk7*pA!sl)D0;HIi zHqG25El0Z0#E*Lujgb2jABf?n-=QGNa+4gG`I8=~AxgSQv6|SaSJ_-?{xITLqPh4B zpD*_+IxI81i{6{_y+==wwbyj@=Wt@ENsw}_X);Uj0vH|R9WRD;mZ^sl068l+Op~w1 zPPD+1mqXEk%gX~+{jhhsyX(875iT5!u>h>WFkMq~Qq2_*E`(Pu?OHjx2D0Hkv~uLi zaYPf3<9pN$JSknnD*0IojxD^%ITk}y=v=-d&Y}{^i@-n4bi&jX6CighO!ZeB#efZ`zdVx^l=DZnE5w*8uDvP4zWoeon-Vbo;nZL+3% zT%HzDho1BKGjS|kPl0T$OX7e$SD??ld>o983R!wk-7mKH(Pe@Ofcc2No{dsOBxLg2 zMI(}!i#H3hV}-}a)@wSQH}9d;QMxYq!X__5V`ykolwgei`bV=HTFo;_KDDqyyYDw2 z6PDnQTb$QUNoD5He&;FV66Y)Ak3H2LWXn*wC|vF%Yx_bM6ms8Jd|}~BsVMG9$bIBm z)Cd*E_yS%0A>4f(KseZPf@U>j4$gb-$>i#TztwQ>dk&7Dk?{6bu-<~8EFyrMKeh;5 z+Z)PN%em}EZ}NN`34l=Xz|M##a`&<{kdeENXz94nUGIzTc3&TcJ|&PTI0Pms+>IoI zPj(|Ti0XnrwGXjAI5G`$+_Ahs6=_VcKFSreQNR7*0_URyNDxi|V*F*6g;E)RmSj;f zMrNBa4#W!admD=?v%0$*!W#5ICAlj#Q}o2}IfnRYz)z+SucFMZPnKWygwC4#m@xLf zaG#U{G(`g)BmUbbj96rv6TxU(s-u$Kcd?+ot81`&9c>_jRB57rCQo=vAeZZ}LJOv4 zk?@N;7ma`eP~4t1l{R~b8$?vkt!ls*+j#Kz^Qe-BsFXSO&LD5UDzaW|P}k>UN5}>j zd!R8&5zz(HZLlrHUr6~IVDQgA)nkm?qwrsxkbQo{C?glmk8rnruMg5s=UZFK$7j`X zhk}A*Gb~I~GDoUhE0_Vk90&oCsO$M}d`K&n-O-BnfMDw5H%ul`%Clr{sJ-*7byXvq zzHfsSGAio_+6E{0r9jzX1NFTAOb;JO(gVjjVRQQ@Sn**2#h}|u!_AYFhd=RQ(8?zT z%F+_--*q9J83NMZU;ie9Zp!0(&0`G(PL|&&-WsujdkCtHe3G(Z&U8CjEA`AO{ON7$x=C2AfTD7Y${4V-p@!l zzzjLQ^iCt&*EYru+?!zPa98L6T)WJeGv~pYj7LuythnP~R>oIjT_msAH?=$H4Mi_l zJF8Ub_QQXa#fxZCk5^LA-w=xNY#ff zka48zPza|^_ekAoNQV!JKNYt36mbuFUip(kwv6wBO}oUh1HI*XLr}&hypG~PnIIl# zJ9Esr-#!Hr&J}>r)21|L6gwKh<3YzFpF0>PV&vs{)cUrn8pG;2X{q@%@C$kVywzHG z1P9zA7EimM06g7!?H4O0V4rx|6yP_=?3RVeHkscW1P|=l=wl8D-h+r!)V|(BJp26R zWv>>NIg#gU;{Fq(3qj2rKGSe|bQYQ(rbU*_7MI*6@(0Y^7_*I%bj&PUsugtPA)FA( z78Qr+G4TVn&$aRQo``Ak>G?Hn<9IjnzI61oIS;}E5_g_Z+c!}(K!X!Q9#qSsp96l) z(3~?URsf=d%&3p#9Su1AF@Sh|P}rml=IR|~lZq%E241hd54oH?x8&QH7BfolO*jlC zMuuxFQCOhk1j|}5r5=x^GlO_)fPlD4eBIwRC9UgAIMmCk1U9e%kaQ>o6WUOI@(JtN zdhq%`WMk~>wDwM`LLNWwWIKaweil{VWEN)y$qZU^Q(&_^q0yP3pJQqEYs^!fMY-=2 z{o8#*ej`_8ew`O8p}zKV3_$$^Y`~i1f-J{e6b9JuabcO&C#{uP%1sT$z~E>xHBzvXJ=&J`6#>QeJd|Rs zm(i9DG~NT8F&-PVg8Th!c-a7EJ9w7AnMX&MPz8R@xuPU<7ing1Z8(I71ABY-VYDHQ zXPiIQQs6I}^*Ge{k2$hQ$t>EYuV}H-9zzO9H!Mc^{rB{0o9?1xglqQQ^6!7Q9%Ps< z9Oqe~I#M)GY#LMkt~yL!{M9$ zx~9=ye<9Ai{w;1Xxl3_++c$lRp;x>E%uejrKc6A%T)P}TEixs^w0v2` zaz}PZJiZS)?%EP{W@VWhyG1s=5pJn!wV|I%I=83+hj<#HXqc$Z-d#1LW_2)~C6bIX z!7O2ti1o;~FU*tT|NftY$l|appbtopEdD=pZ{YRvoC+s)-MGJq%Q$Q-t1xo(w`uD% zdSh0x{SnqIADNZpRvvdVi@I?+FjujLxSqEpM2LW=AMWF*Q*reF4pbg zH|_8hjSkt4W32o$Ti{KkQx5G$XVk~py{wp7%fq52X8~$>A08eHNWrrn z_>)x*X387^f5w|2=;4d6?igZRVNdtjKh>Z8OS604f1TN$m>YHqe*spDKP)B}^s4h6 zXF+F0F znP`JE#61?}(*B||Jcn0nh)Y@S;U%jtn8T%L)FW7Pzfq|6Z?G+en1=#eix?p%P1H%Y z`mZ!8C)&l5Z~eb_Wf1Ss@U99ZmrP<>cnM89hS3kkJU&kH{I)#P1OzYMVMxhC_p$D$ z!^vpc#DzVXY+bNnf-tfw?2-^B85~mF`uwQzz~!>eEy*fXA+DnzgN#lkR|vvQDpgVh zO-TBK@b8H^m(0BxNSo>c0VotIZ^};%1%*U#j}=V;Qm0D-njF4DQWgwGMb@yIHf<@T zk@>{9cJi?h^32#DT+Mbmjav?$Sj7qZXs=kPLE>mczrNxX~MkKLp&l(INYwfu2D+U{t9q}4Z z*$UT75;1N3->!%OxJqEG2z8Po6 z#t1Kz3G#!h&JY?wjJ7E@pV9B3+JogQ;Sn|Zi}olOD9vRTa5UOHmJ}w5+`d;MfP>vg ztpq$kt;b5zse^dfA;(Ipb0890<#ju%6-TmD-|-H-$93Cw%`o@WlW#UDnqxuTt*4zt zN{CVHr$%AaJonf{G|fU*atDd8+W@+QYD$5}EWcpo1V_99x_9Ct0QfLD3BzWuWL5zo>5LpA@TR ze9`ytyMwqOHatJ7oZsRMWwM06U5=9>QRT=l&DI!xG!MwXed+^Yb8JHpNI0=VR-_4G zB5czv;|nhH!wwQcv#-dg*pyjtW`u`Qa)NFh$r3`7h6y&Wj3xJ72cBD!11p?u+Q~;hEVWnZw$`}l!n$|Rp=*Xh7ktIt`yOp-?TjW9Q$wZ%2KrNno-60?f`?!uy3L`hjlaRCiS=t5)xK$Phu{l_*&iy&ms8gpCJZdr#=J+|%E( zCBi>`7T`d6sV|_Z$Pon`D23`Kx#s5oSw9uHrYvpr`p}$BoJr~JvRCSWBuEj3Jws1x zFx`V0Sm?#CB2D37N-_LF>Otxku^UJfTFaf<&)o>0S=EiR{OM*HD7S2bIk4)nWeUi+ z2B5KH)jnp;iF~M9x0n4MGEU0NQgCAtM_PbbiKDQ~ppPJrgGY74+9i_S!!G2g$lVkU ze^iJ5j)xsW$Y`s?^(p{=53X10hJCE3eax3JeEdClSfU0Y-yrU$ooV8k3(YozxZvGj>0?i z*EYB73l?YnCo=YH9)%%QZO3U|8U0g{1|7}~vaP~RWmDPMe(}wcIZK+Ig=7PDlJMCx zDBOdl?YNZi0Zf zH};FblgK0Zb4u5qFa(w8+j<`N)azuzw=lCpQl%$Tl%}RvLs=ycFcb+wqSnqr+zv8| z@Sqb!u$`;WgN8&g1CpsK#nLvIX>I>AKl_T;Q?tv6!M>0 z>V2R)PBMyZiO%#Oil!(}n59X&vh0&xx6%oErkbY>88OFtaP?e?4R9UdDC!B!C$H^gTNdVX z^s3aDXiR+@K;Cb2>nA9|(@c+uym#-%AlP4N0JfXW30Z^@i!pzNYRmz1OhA;R$Q9g4}?N= z6&{&G77QC=fOMOjYwQ;@niZv}{<&dQ%X%kf_0qg;<HFbn1|y+DH?L(B6LH{EZH1Ju%HjDbmH@Gj?T~T;jV*-`v06n8I)r%^Wf-sQ z9ivj(S=QvNO1Kxe>Y$2c~+++OY;1}aW;_3&4Q5VRT*eX;NjXx z`QSkhgv?5@R;@G(%PA^0#H1Z(RT%fEF2pJkl?qv}0Lm&uJASETuXRupQLXkO97 z5?3nfR1?a%^JpllHI-&99+?#95GGn=(Q7UEdK^Z7uU7Z1gB`Vf>Xihtxion5shif#(A~n4xa_-j46Mn`)$DH)WHnLR)bl-zopmd*nNimAzz4{OGL=oN!MmuXF4y;pjVu?ve)&9lxSHi6>r$Gp zz~m=RQ{(g&&FF;g>JT_v4@E|=%R*XN97C5LZWf-GlkI9_>0LLbh%;b-@By`{l?erQ zWw_e$LipV={gHS7uZ?t)kKbms2-$>aX(T)tDT;Dck!a3&hdt1SJ; zW#pREg_ui|fc;$5XDXmjnz})Emxj(NrRSn3H*G$js^#&@uFX^ry|BPpta$+5iNlQK zDNp~A(pNNv|F7AiM~;F;K#wgYcaQyux8KBwZ2cN9+o7_k;m9f7lnaWOwk`jxNvZ0I zXkTL^d?n?u9F1Vd0leN`i4|nIg0=ZrJAXO)PmD8jM>b{!`Cx!G?Lvx}!D4!%uv;W1 zkSmLS!;BV&rx0~nRPuWDxn5AKB)w_MJp3`9W0FGGarlDMtdZ1?l2c&gG;?iiekWTN zyUn`2Zx0$XpF$OxbzgDg!2x5R``MVc2UR-+jVUv61for6Dr+S5$$61aJ3i5!xdWOI6D z5zeO}@xffAqs>c(d(muKLF%fRs@ua-HGwE$TS_cegHYH$zu2^LPGzre8vgG6VUTCsgsLTYlV=@?)7nTM0x)35Z{@v=>?&=B(|(Kmq#eza zZfyua3Zvd^;yO4}jui+gjMO_z8`#-iSt>PU_1hG&yCU$=Pyan@1&ES@tgTiKuW@OU zc2J!Ep#;#MJ5ybpibtd)WYX!hPAX`&H$|pCDd#=;RirX)5&f_@<{WRwq)M7bhZ2-( z?$&$mYuC)Q+(#%=cr)peY@31)-nNek&b3bop0C!#w96?ve~Mz2eMd-GJmx6Ih&m5I zF~USw3hg{Fuh(U_;VKd1^@-Fz7eTJczP;FAKLyZSJ1Y3X2eQ9dH?AbsU$T*ts`QVo zBIC}}VJ&PeErkz;+UN-E6=pj8;Eky$*U-9YcV4QM75jZ?D#n=fCmcU9P>eBkA`;KS zZvRLoT7v^4T%S>kx=0DfwNziizWHUTb$#f>1-?J7jY$CgB>>2=~Wq!*Ol$R|M+8cWB7q z;r()vaTq;0g1c^J)U?rm)n3uQ$FUe=nJP54*p1ICtqH@fyvg;RCMXtl4=` zvLznz$n2RpafEMDcv)r6BgbU^fz9N2BL$!pSFZjN+RI1a`GM~(ea&(x=h{a3g8SOw zzn1tuTwmU|p7^dY>?3zjnp8dLRxq1bC%u?BaIZnAYAbbSCtu?2(qPJb2&!Snwk4tj zgvR&-;ujRF8CkIG5Wc4Ne09LZvUSrqJhLEJsuP#7$Oje)rMB1pZ-v{S{t|y z;~>heSG?tTOCw33kx-=F=s3R5?E$27gwni36P)QhT^nE=h4V8i%~qftqx#*lQIcof z3ikMmqKtIuDpBriF>MD^s>i(4N62@4GvC7gbLQAxBqc{eJ1zXQ&B%5WR8Q4uo>z#wB*aFyZ+N|r{ zT;q$vG~4G}8cgpWdbSBWXfcjKmEAUg3Dh~Z*tCHgsYB)QoAi$HAU64H+y^y|*I;Cs zlG^1_2>Cww>FE&{N1?h>S;U(D>Dblz!)Vhg{J`v+>K>`c0(ae?E5W%}jH^?XzNxsE zmJuM2miqGHI#5x?Cex(f6AOU$nP&In0txeNY#;@AMZ}1yuy4qJ{8<-9n!60@A@V$5 zLWyxe>9ydFCw}RQTI~ThMJ2$;^rjJ&UsanBxX}Bj;nTo^s64+YLzpzHcQCD^GH=I$ zVl_RsvW`zcVO7=p;AE(mZ_ccoh9D6uu34O{0t9n4g@z3`H89U{i4TywpXTQnl?#gL zxp1_Hl|Hse5cB-x2v^|-$5tq^^+#iyA*cNwh{Fq|qiV$FH#0MU+rO6(M3fez7&6aw zYNNw({eha4ANM_8Y(?)bUYq)kxo-@_UpOyqC{rjJ$ zUYypJ5-vjf0~KC`dJw0sbZvA_dW7;ux;kA2PGV6T_EC2Q|kA@H0svuiBo z{$8oX&QrCkh)k?@-*&@813(GjMaR=>+ikP8yy9bji7QgOHSpcIk2Tc^gE%99nc0X0W>?H%GB1$G z!YVh3wMV=g?Qa4m?hHTgj;D)h7TvI>CX2CezPWBl7PM*bhvk?Y!h{>co5((VyWgO# zH2mr!zlwg>>PsB%J3Knu_=+W26W0ort2l{BPpswB;nGLDP7@}z%{o*nW zv?G0@Pb9|~nJSU>l%-LOqeQu&W1i*2mTSM@8z7?^jqv-!rqf5sxQ_%qsWWsjB9SXtHT)puCNWI>DbT`m zRwy=%=kZ0JVj`b^ZW&QXVZ3(5UY0?|$K&bSIQ5V2dQ;@o=yq3R4O{*SL1cLNqTj@@ zAwek}>X2N3ilZz{BLhd3T34Mb6Z&Eee>G2xm5VjfrxIxahQ_j^PJJBi=S`4hWvnrE zt`4E^^HGng;++JI5)9x(43&g~`?RS_gnapV!WjA4EZJf8AT`#%Fmpm4-Zo*;HtMmk z3WyxqQ8#oD`7*rt?m#^EX!Ik04mf^bW9?y;_=8^oyom_7!xb~Z@nn~&T>Xn{}X?spn>6{xjLo@gz+xh!n${UP&;{ts^)5oh`Q@X?Gj=b76Kfhlb z)wPQV_Q&z?&?}|BhftRo25v^YzjdQM++yG#UxLcFtgzc!a(68b6)t$M`}<=Ug)q8Q zlU$hq4ppl>{kVR)xdEG8yF;O6%2l8vxP&LR2S8RntP`znJ*NGCq~!0C@K4&B8I+zU zHi^AL**Ud#$4T8%SGfm$;O-2zoj#1HhB>JTHup#Y`?mZFOdF(wa#I|&SL*F7p%hc83`g1ZMS_EZf5w4p#7~y?i)z9h2Zxw7hISk*_Btt7&_H zZ)e>Z;i|(Y%nY0I(I)%@EgBhSBa>!w(k3U0v8$^%#>W7>nR&JfX&yQ$2dcmb*$u)w z`x5@5iVtUqiFMkD`kY%GC2fN_NpyXlPz{D98-Idf+fGvmyVFj#^PZ(vuJb4p89;ZD zrA)*t0Skicq;7OWQXO~LHLkK8WEY5Hy zI_Gzv;th#|wgdrec=S9E2&)J5%Gr{^-tYW+&m`7iC(eC%lL+Sn+$+VWSS%!q5vC!H zIyNU-W5#w|T2smEHWGqiN-a{e`X^?-)M;sV^gT9dapQ0UtL9A`5&7C0?Q8D<`f0m| zA90!@7sRcz1xFe*e$(YN5)eH#VH^0x{yK*a+a=-=cdJwK18{^&<-4Ww^!46uI=v!k zjyy45Flwe~a?9pXlG;V@IwoEX(${90_!j+tV$YuB%Eq(h^S#>dK^Kn5{FU7O^Alfl z(06@!5ST`Byj7O>D9(nF%!LdAX?l0j{0T&3a^4z-B=)7dSB%wEgQ(Tc7@%6E_KY)u z-*$@q$Ti!c7|v@30-Y9r1Jr6E%JdzDExfN8r~cec9FMZ%9uA2*~wlWL6aM z#1$8x2$ej2NCj8AEi1Jjk8)?F-KnLO)&|BYJPZBYmlklI{(%dwlBC(yceuLlj7lQsMvsT2N2p~KE7+cygE%&R} z1;WFj@(Ew`N5?o+zWhg?UM{0WT}^r$Z5W7?dR(C4`6>mtlL^!|Wy#Nh=@+iYDW^5% z?g+*Y!gRMA+>ad+ZvqBC(eOk2v>x^-&FC|dk%9= zPg>Ha9A$9V6UqwzSOZYkolN{S6b{iLZk=9V4p$n|ilbxi>rawc0-on%Z;Fuq7D6Py z3F){VWV#J=o?TD=J@Rdo-#5?t*g2z<%IyKqVJ7f{YDjm!B>2AaK#qwXo?yHKtS4;S z_&#^@p<3ocVD;B5|MBN(i-{v`p?yM)Huy-44@$I4tebuxOCMiD!U07}L;eA%>$6+; zV$}g_e7aiz<_H~kVDv%i=FEvV#z+;9;lWg23w|BhpC^1Fh0eHFGQ<0mPoXB%76K$B zNDyT?=x=IHxwdFuxv(fe;X&E|mdFBugKD5zz>`51&|VfKzW;RS z`=SE7r;#E4Q|bVmoyG(c4)}+!9Dw&91-$>8|NLL$p+J=x9sK|1u7ZFF{I~Oqq6q!R z(Af+<{y#ZAUuf~mSCT9Lzl4lpfGo3$`2WqC_`g;R;(;vbG+%iXm_We=WXS)CP~XgA zfT<+?)4?=HjQ^j|UO6ZTNZHpv!2K`tRw@4o8Kk28M;rg2fZx}1L7oZG~S#q`=q(X0X&IVDEw|m_rwkv4s>!-2?yi?rFi?dV%(fmS9r9 rfV+KsUoP|Iru{&^B^Lbu|GWIUBldsq`bF9G10$Dcp$7Z^!~OpN3P=;B delta 16582 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 Ogj=MCmKgkJ_WuEs-6Qw_ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 74bb77845e0..be280bec023 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-bin.zip From 9fda9c68707070f7ff8770baf07f7def385c8f19 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 5 Feb 2018 11:29:24 -0500 Subject: [PATCH 181/479] version: 0.14.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 09d0485e78c..bf24660d9da 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.14.0 * Built using Gradle 4.5 * Updated compatibility testing through Gradle 4.5 * Support for validation of default values in schema (#42) diff --git a/build.gradle b/build.gradle index fc79cfe24dd..a8b7f6e2ee7 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.13.1-SNAPSHOT" +version = "0.14.0" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 608c7e8c4b7d49a5e984a0b991f1034d29c9c4cf Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 5 Feb 2018 11:34:11 -0500 Subject: [PATCH 182/479] version: 0.14.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a8b7f6e2ee7..bb46b4ebf17 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.14.0" +version = "0.14.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From c8fcd4d0e160fdea0f5ddd046cf53ace12dcf6a8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 23 Mar 2018 10:15:53 -0400 Subject: [PATCH 183/479] Update Gradle to 4.6, update compatibility testing to include up to Gradle 4.6 and Java 10 --- .gitignore | 3 +++ CHANGES.md | 3 +++ README.md | 6 +++--- build.gradle | 7 ++++++- gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 54329 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index caf72a94d98..f92a2e4f5f7 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,6 @@ atlassian-ide-plugin.xml # Specifically include the gradle wrapper jar !/gradle/wrapper/gradle-wrapper.jar + +# Scripts for use on the local machine +/local-*.sh diff --git a/CHANGES.md b/CHANGES.md index bf24660d9da..78df5115945 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,9 @@ # Change Log ## Unreleased +* Built using Gradle 4.6 +* Updated compatibility testing through Gradle 4.6 +* Began testing using Java 10 ## 0.14.0 * Built using Gradle 4.5 diff --git a/README.md b/README.md index 3e0b52fb9e0..e77428ba3e5 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Java 7-9 +* Currently tested against Java 7-10 * Java 9 support requires Gradle 4.2.1 or higher * If you need support for Java 6, version 0.9.1 was the last supported version -* Currently built against Gradle 4.5 - * Currently tested against Gradle 3.0-3.51 and 4.0-4.5 +* Currently built against Gradle 4.6 + * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.6 * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.8.2 diff --git a/build.gradle b/build.gradle index bb46b4ebf17..ac7d2baa3fd 100644 --- a/build.gradle +++ b/build.gradle @@ -171,7 +171,12 @@ test { } def avroVersions = ["1.8.2"] -def gradleVersions = ["3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2", "4.2.1", "4.3", "4.3.1", "4.4", "4.4.1", "4.5"] +def gradleVersions = [] +if (!org.gradle.api.JavaVersion.current().isJava9Compatible()) { // Gradle 4.2.1 is the first version that appears to support running on Java 9 + gradleVersions.addAll("3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2") +} +gradleVersions.addAll("4.2.1", "4.3", "4.3.1", "4.4", "4.4.1", "4.5", "4.5.1", "4.6") +// Support for running Gradle on Java 7 is deprecated and will be removed in Gradle 5, as per https://docs.gradle.org/4.2.1/release-notes.html avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a5fe1cb94b9ee5ce57e6113458225bcba12d83e3..f6b961fd5a86aa5fbfe90f707c3138408be7c718 100644 GIT binary patch delta 63 zcmdnFf_di(<_YF38otMVOtg+<`&jg`h>>A})W$9U4stOw1bDM^ytJG0dGek^{$Mqm P`48U{U;zt#yzBu0axWc6 delta 63 zcmdnFf_di(<_YF3Kg`qiPqdC?`&9I?h>>A})W$9U4sx+F1bDM^1n1Aqn!M+bKUmFX P{=@eKSinLbFM9w0VoDpr diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index be280bec023..bf3de218305 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-4.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-bin.zip From f9bbac9ea0516f74201622d560f3403c6b401fd9 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 23 Mar 2018 10:24:34 -0400 Subject: [PATCH 184/479] Comment on version compatibility --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ac7d2baa3fd..7d755ea8a57 100644 --- a/build.gradle +++ b/build.gradle @@ -172,7 +172,7 @@ test { def avroVersions = ["1.8.2"] def gradleVersions = [] -if (!org.gradle.api.JavaVersion.current().isJava9Compatible()) { // Gradle 4.2.1 is the first version that appears to support running on Java 9 +if (!org.gradle.api.JavaVersion.current().isJava9Compatible()) { // Gradle 4.2.1 is the first version that supports modern Java 9, as per https://discuss.gradle.org/t/could-not-determine-java-version-from-9-0-1/24457 gradleVersions.addAll("3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2") } gradleVersions.addAll("4.2.1", "4.3", "4.3.1", "4.4", "4.4.1", "4.5", "4.5.1", "4.6") From 444b08e19ec95d8f545667481c8d981205b2599c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 23 Mar 2018 10:25:06 -0400 Subject: [PATCH 185/479] Try to add Java 10 and Java 11 support to Travis CI build; drops Java 7 support from Travis CI build --- .travis.yml | 73 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0f1e7345dff..2b0b05b1299 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,37 +1,46 @@ -sudo: true # required for hostname addon; https://docs.travis-ci.com/user/hostname +sudo: false +dist: trusty language: java -group: stable -jdk: oraclejdk8 + +before_install: + - wget https://raw.githubusercontent.com/sormuras/bach/master/install-jdk.sh + +install: true + +matrix: + include: +# 7 isn't included because it reached End of Life in April 2015 and requires +# various work-arounds on Travis CI to be compatible with Gradle +# 8 + - env: JDK='Oracle JDK 8' + jdk: oraclejdk8 + - env: JDK='OpenJDK 8' + jdk: openjdk8 +# 9 + - env: JDK='Oracle JDK 9' + jdk: oraclejdk9 + - env: JDK='OpenJDK 9' + install: . ./install-jdk.sh -F 9 +# 10 + - env: JDK='Oracle JDK 10' + jdk: oraclejdk10 + - env: JDK='OpenJDK 10' + install: . ./install-jdk.sh -F 10 -L GPL +# 11 + - env: JDK='Oracle JDK 11' + install: . ./install-jdk.sh -F 11 -L BCL + - env: JDK='OpenJDK 11' + install: . ./install-jdk.sh -F 11 -L GPL +# allow_failures: +# - env: JDK='Oracle JDK 10' + env: global: - TERM="dumb" - GRADLE_OPTS="-Xmx386m -Xms386m" -addons: - # OpenJDK7 fails with long host names; https://github.com/travis-ci/travis-ci/issues/5227 - hosts: - - buildhost - hostname: buildhost -install: true -script: ./gradlew build testRecentVersionCompatibility --info -matrix: - include: - - jdk: oraclejdk9 - os: linux - dist: trusty - group: deprecated-2017Q4 - # Looks like Java 9.0.1 introduced new Gradle incompatibilities resolved in 4.2.1 and 4.3 - # https://discuss.gradle.org/t/could-not-determine-java-version-from-9-0-1/24457 - - jdk: oraclejdk8 - os: linux - dist: trusty - - jdk: oraclejdk7 - os: linux - dist: precise # on trusty, Oracle JDK 7 is not provided because it reached End of Life in April 2015. - env: - - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" - - jdk: openjdk8 - os: linux - dist: trusty - - jdk: openjdk7 - os: linux - dist: precise # on trusty, openjdk7 fails when connecting to Gradle distro site/plugin portal due to TLS configuration; java.security.NoSuchProviderException: no such provider: SunEC + +script: + - echo PATH = ${PATH} + - echo JAVA_HOME = ${JAVA_HOME} + - java -version + - ./gradlew build testRecentVersionCompatibility --info From 805b6e1c5a7e2a112567c143779ea49c778d4c99 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 23 Mar 2018 10:38:34 -0400 Subject: [PATCH 186/479] Update Travis CI config to reflect that Oracle JDK 10 isn't supported yet --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2b0b05b1299..ff579279357 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ install: true matrix: include: +# Based on https://sormuras.github.io/blog/2018-03-20-jdk-matrix.html # 7 isn't included because it reached End of Life in April 2015 and requires # various work-arounds on Travis CI to be compatible with Gradle # 8 @@ -31,8 +32,8 @@ matrix: install: . ./install-jdk.sh -F 11 -L BCL - env: JDK='OpenJDK 11' install: . ./install-jdk.sh -F 11 -L GPL -# allow_failures: -# - env: JDK='Oracle JDK 10' + allow_failures: # Oracle JDK 10 not yet supported; see https://github.com/travis-ci/travis-ci/issues/9368 + - env: JDK='Oracle JDK 10' env: global: From 98e7a9c5deb858dea5be213c642f43c1290c32ca Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 23 Mar 2018 10:57:36 -0400 Subject: [PATCH 187/479] Upgrade the version of Kotlin we test against to 1.2.31 --- README.md | 2 +- .../gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e77428ba3e5..62151aaa357 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.x, try plugin version 0.8.0; versions of Avro before that are unlikely to work * Incubating: support for Kotlin - * Currently tested against Kotlin 1.1.51 + * Currently tested against Kotlin 1.2.31 * Kotlin 1.1.2 and higher requires Java 8+ * Doesn't work with Gradle 3.2-3.2.1 diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy index 5457e347204..f027f13cc76 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy @@ -39,7 +39,7 @@ class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { jcenter() } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.51" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.31" } } apply plugin: "kotlin" From e82f89b2a91a0be866fe0ccd3d34886543f00ef0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 23 Mar 2018 10:58:16 -0400 Subject: [PATCH 188/479] Correct change log (missing kotlin testing change) --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 78df5115945..54597d56ddf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ * Built using Gradle 4.6 * Updated compatibility testing through Gradle 4.6 * Began testing using Java 10 +* Began testing using Kotlin 1.2.31 ## 0.14.0 * Built using Gradle 4.5 From 7904d26d6772348d2df65dac2f686cd90c0aced9 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 23 Mar 2018 11:11:44 -0400 Subject: [PATCH 189/479] Update travis config to allow failures in Java 11, as it won't be supported until Gradle 4.7 --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ff579279357..b67c8c35bbb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,8 +32,10 @@ matrix: install: . ./install-jdk.sh -F 11 -L BCL - env: JDK='OpenJDK 11' install: . ./install-jdk.sh -F 11 -L GPL - allow_failures: # Oracle JDK 10 not yet supported; see https://github.com/travis-ci/travis-ci/issues/9368 - - env: JDK='Oracle JDK 10' + allow_failures: + - env: JDK='Oracle JDK 10' # Oracle JDK 10 not yet supported; see https://github.com/travis-ci/travis-ci/issues/9368 + - env: JDK='Oracle JDK 11' # Gradle 4.6 doesn't recognize Java 11 EA versions; should be fixed in Gradle 4.7; https://github.com/gradle/gradle/issues/4515 + - env: JDK='OpenJDK 11' # Gradle 4.6 doesn't recognize Java 11 EA versions; should be fixed in Gradle 4.7; https://github.com/gradle/gradle/issues/4515 env: global: From 10f45ebc4f18b38ee7da228d5fcc5e38ab508d01 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 23 Mar 2018 11:51:18 -0400 Subject: [PATCH 190/479] Travis: see if turning sudo on fixed openjdk 9 download issue --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b67c8c35bbb..d8c23373815 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -sudo: false +sudo: true dist: trusty language: java From ebe6739a31fae31efd5e20551ec70a503d021442 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 10 Apr 2018 13:38:02 -0400 Subject: [PATCH 191/479] Fixed infinite loop when a schema file contains multiple definitions of the same type (#47) --- CHANGES.md | 1 + .../gradle/plugin/avro/FileState.java | 4 ++ .../plugin/avro/GenerateAvroJavaTask.java | 14 +++++-- .../DuplicateHandlingFunctionalSpec.groovy | 14 +++++++ .../avro/duplicate/duplicateInSingleFile.avsc | 38 +++++++++++++++++++ 5 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc diff --git a/CHANGES.md b/CHANGES.md index 54597d56ddf..bc6d254965c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ * Updated compatibility testing through Gradle 4.6 * Began testing using Java 10 * Began testing using Kotlin 1.2.31 +* Fixed infinite loop when a schema file contains multiple definitions of the same type (#47) ## 0.14.0 * Built using Gradle 4.5 diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java index fb89e7c9d71..c571b45669c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java @@ -50,6 +50,10 @@ void addDuplicateTypeName(String typeName) { duplicateTypeNames.add(typeName); } + public boolean containsDuplicateTypeName(String typeName) { + return duplicateTypeNames.contains(typeName); + } + public String getPath() { return path; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 44709f35b2b..303a3402831 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -234,10 +234,16 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt getLogger().debug("Found undefined name in {} ({}); will try again", path, errorMessage); } else if (duplicateTypeMatcher.matches()) { String typeName = duplicateTypeMatcher.group(1); - fileState.setError(ex); - fileState.addDuplicateTypeName(typeName); - processingState.queueForProcessing(fileState); - getLogger().debug("Identified duplicate type {} in {}; will re-process excluding it", typeName, path); + if (fileState.containsDuplicateTypeName(typeName)) { + throw new GradleException( + String.format("Failed to compile schema definition file %s; contains duplicate type definition %s", path, typeName), + ex); + } else { + fileState.setError(ex); + fileState.addDuplicateTypeName(typeName); + processingState.queueForProcessing(fileState); + getLogger().debug("Identified duplicate type {} in {}; will re-process excluding it", typeName, path); + } } else { throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index d777cbae23c..a1f5fd2587a 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -84,6 +84,20 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { + "[$errorFilePath1, $errorFilePath2]") } + def "Duplicate record definition in single file fails with clear error"() { + given: + copyResource("duplicate/duplicateInSingleFile.avsc", avroDir) + def errorFilePath = new File("src/main/avro/duplicate/duplicateInSingleFile.avsc").path + + when: + def result = runAndFail() + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.output.contains("Failed to compile schema definition file $errorFilePath; " + + "contains duplicate type definition example.avro.date") + } + private void copyIdenticalEnum() { copyResource("duplicate/Person.avsc", avroDir) copyResource("duplicate/Cat.avsc", avroDir) diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc new file mode 100644 index 00000000000..581ca1175f1 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc @@ -0,0 +1,38 @@ +{ + "type" : "record", + "name" : "Fail", + "namespace" : "example.avro", + "fields" : [ { + "name" : "start_date", + "type" : { + "type" : "record", + "name" : "date", + "fields" : [ { + "name" : "day", + "type" : ["null", "int"] + }, { + "name" : "month", + "type" : ["null", "int"] + }, { + "name" : "year", + "type" : ["null", "int"] + } ] + } + }, { + "name" : "end_date", + "type" : { + "type" : "record", + "name" : "date", + "fields" : [ { + "name" : "day", + "type" : ["null", "int"] + }, { + "name" : "month", + "type" : ["null", "int"] + }, { + "name" : "year", + "type" : ["null", "int"] + } ] + } + } ] +} From f6fdb1b419eda2931042c39a6745b34d0fad9d76 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 10 Apr 2018 13:53:31 -0400 Subject: [PATCH 192/479] version: 0.14.1 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index bc6d254965c..f79d5308bf0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.14.1 * Built using Gradle 4.6 * Updated compatibility testing through Gradle 4.6 * Began testing using Java 10 diff --git a/build.gradle b/build.gradle index 7d755ea8a57..1b324aa8681 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.14.1-SNAPSHOT" +version = "0.14.1" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 4ac3e9a76ed335cb9cfa39e614de767c47e9d54f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 10 Apr 2018 13:56:01 -0400 Subject: [PATCH 193/479] version: 0.14.2-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1b324aa8681..41f8790ea63 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.14.1" +version = "0.14.2-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From f16f9924ab25a0da63314eb796a8de2853a7f243 Mon Sep 17 00:00:00 2001 From: Denis Cabasson Date: Mon, 30 Apr 2018 20:05:38 -0400 Subject: [PATCH 194/479] Fixing avro plugin cache --- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 8 ++++---- .../gradle/plugin/avro/GenerateAvroProtocolTask.java | 4 +++- .../gradle/plugin/avro/OutputDirTask.java | 12 +++++++++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 303a3402831..1e1030be2b3 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -25,9 +25,7 @@ import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.*; import java.io.File; import java.io.IOException; @@ -44,6 +42,7 @@ * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and * {@link SpecificCompiler}. */ +@CacheableTask public class GenerateAvroJavaTask extends OutputDirTask { private static Pattern ERROR_UNKNOWN_TYPE = Pattern.compile("(?i).*(undefined name|not a defined name).*"); private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); @@ -101,7 +100,8 @@ public void setFieldVisibility(SpecificCompiler.FieldVisibility fieldVisibility) } @Optional - @Input + @InputDirectory + @PathSensitive(PathSensitivity.RELATIVE) public String getTemplateDirectory() { return templateDirectory; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index e294c5cf16c..4acd9dee901 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -22,6 +22,7 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; +import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.TaskAction; import org.gradle.util.GradleVersion; @@ -39,10 +40,11 @@ /** * Task to convert Avro IDL files into Avro protocol files using {@link Idl}. */ +@CacheableTask public class GenerateAvroProtocolTask extends OutputDirTask { @TaskAction protected void process() { - getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); + getLogger().info("Found {} files", getSource().getFiles().size()); failOnUnsupportedFiles(); processFiles(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java index 8a4ee204292..64f59ad207d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java @@ -16,12 +16,17 @@ package com.commercehub.gradle.plugin.avro; import org.gradle.api.file.FileCollection; +import org.gradle.api.file.FileTree; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.SourceTask; import java.io.File; +import static org.gradle.api.tasks.PathSensitivity.NAME_ONLY; +import static org.gradle.api.tasks.PathSensitivity.RELATIVE; + class OutputDirTask extends SourceTask { private File outputDir; @@ -30,12 +35,17 @@ public void setOutputDir(File outputDir) { getOutputs().dir(outputDir); } + @PathSensitive(value=RELATIVE) + public FileTree getSource() { + return super.getSource(); + } + @OutputDirectory protected File getOutputDir() { return outputDir; } protected FileCollection filterSources(Spec spec) { - return getInputs().getSourceFiles().filter(spec); + return getSource().filter(spec); } } From 79d6a4f078cdb7520291ade3cf39674eb8a37f37 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 1 Jun 2018 10:55:24 -0400 Subject: [PATCH 195/479] Stop creating default generated output directories when `outputDir` is customized and IntelliJ integration is used (#52) --- CHANGES.md | 1 + .../gradle/plugin/avro/AvroPlugin.java | 16 ++-- .../avro/AvroPluginFunctionalSpec.groovy | 26 ------ .../plugin/avro/IntellijFunctionalSpec.groovy | 83 +++++++++++++++++++ 4 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy diff --git a/CHANGES.md b/CHANGES.md index f79d5308bf0..4523d86392e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Stop creating default generated output directories when `outputDir` is customized and IntelliJ integration is used (#52) ## 0.14.1 * Built using Gradle 4.6 diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 63044c627d3..f299ef3cba8 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -64,16 +64,18 @@ private static void configureIntelliJ(final Project project) { public void execute(IdeaPlugin ideaPlugin) { SourceSet mainSourceSet = getMainSourceSet(project); SourceSet testSourceSet = getTestSourceSet(project); - final File mainGeneratedOutputDir = getGeneratedOutputDir(project, mainSourceSet, JAVA_EXTENSION); - final File testGeneratedOutputDir = getGeneratedOutputDir(project, testSourceSet, JAVA_EXTENSION); project.getTasks().withType(GenerateIdeaModule.class).all(new Action() { @Override - public void execute(GenerateIdeaModule generateIdeaModule) { - generateIdeaModule.doFirst(new Action() { + public void execute(final GenerateIdeaModule generateIdeaModule) { + project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override - public void execute(Task task) { - project.mkdir(mainGeneratedOutputDir); - project.mkdir(testGeneratedOutputDir); + public void execute(final GenerateAvroJavaTask generateAvroJavaTask) { + generateIdeaModule.doFirst(new Action() { + @Override + public void execute(Task task) { + project.mkdir(generateAvroJavaTask.getOutputDir()); + } + }); } }); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index e3dafc7604d..6006256f629 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -129,30 +129,4 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { result.output.contains("* $errorFilePath: \"enum\" is not a defined name. The type of the \"gender\" " + "field must be a defined name or a {\"type\": ...} expression.") } - - def "generated intellij project files include source directories for generated source"() { - given: - buildFile << """ - apply plugin: "idea" - """ - copyResource("user.avsc", avroDir) - testProjectDir.newFolder("src", "main", "java") - testProjectDir.newFolder("src", "test", "java") - testProjectDir.newFolder("src", "test", "avro") - - when: - run("idea") - - then: - def moduleFile = new File(testProjectDir.root, "${testProjectDir.root.name}.iml") - def module = new XmlSlurper().parseText(moduleFile.text) - module.component.content.sourceFolder.findAll { it.@isTestSource.text() == "false" }.@url*.text().sort() == [ - 'file://$MODULE_DIR\$/build/generated-main-avro-java', - 'file://$MODULE_DIR\$/src/main/avro', 'file://$MODULE_DIR\$/src/main/java', - ] - module.component.content.sourceFolder.findAll { it.@isTestSource.text() == "true" }.@url*.text().sort() == [ - 'file://$MODULE_DIR\$/build/generated-test-avro-java', - 'file://$MODULE_DIR\$/src/test/avro', 'file://$MODULE_DIR\$/src/test/java', - ] - } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy new file mode 100644 index 00000000000..7f80be96335 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy @@ -0,0 +1,83 @@ +/* + * Copyright © 2018 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class IntellijFunctionalSpec extends FunctionalSpec { + def "generated intellij project files include source directories for generated source"() { + given: + buildFile << """ + apply plugin: "idea" + """ + copyResource("user.avsc", avroDir) + testProjectDir.newFolder("src", "main", "java") + testProjectDir.newFolder("src", "test", "java") + testProjectDir.newFolder("src", "test", "avro") + + when: + run("idea") + + then: + def moduleFile = new File(testProjectDir.root, "${testProjectDir.root.name}.iml") + def module = new XmlSlurper().parseText(moduleFile.text) + module.component.content.sourceFolder.findAll { it.@isTestSource.text() == "false" }.@url*.text().sort() == [ + 'file://$MODULE_DIR\$/build/generated-main-avro-java', + 'file://$MODULE_DIR\$/src/main/avro', 'file://$MODULE_DIR\$/src/main/java', + ] + module.component.content.sourceFolder.findAll { it.@isTestSource.text() == "true" }.@url*.text().sort() == [ + 'file://$MODULE_DIR\$/build/generated-test-avro-java', + 'file://$MODULE_DIR\$/src/test/avro', 'file://$MODULE_DIR\$/src/test/java', + ] + } + + def "generated output directories are created by default"() { + given: + buildFile << """ + apply plugin: "idea" + """ + when: + def result = run("idea") + + then: + taskInfoAbsent || result.task(":idea").outcome == SUCCESS + projectFile("build/generated-main-avro-java").directory + projectFile("build/generated-test-avro-java").directory + } + + def "overriding task's outputDir doesn't result in default directory still being created"() { + given: + buildFile << """ + apply plugin: "idea" + generateAvroJava { + outputDir = file("build/generatedMainAvro") + } + generateTestAvroJava { + outputDir = file("build/generatedTestAvro") + } + """ + + when: + def result = run("idea") + + then: + taskInfoAbsent || result.task(":idea").outcome == SUCCESS + !projectFile("build/generated-main-avro-java").directory + !projectFile("build/generated-test-avro-java").directory + projectFile("build/generatedMainAvro").directory + projectFile("build/generatedTestAvro").directory + } +} From 5705b11241cc0e58197197f41c5853ef386b3787 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 1 Jun 2018 12:49:44 -0400 Subject: [PATCH 196/479] version: 0.14.2 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 4523d86392e..d9204522b6d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.14.2 * Stop creating default generated output directories when `outputDir` is customized and IntelliJ integration is used (#52) ## 0.14.1 diff --git a/build.gradle b/build.gradle index 41f8790ea63..ac31eae37ff 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.14.2-SNAPSHOT" +version = "0.14.2" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 2f7dff1a4451982fd4c2a9c810f1fa202f3abe8f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 1 Jun 2018 12:53:18 -0400 Subject: [PATCH 197/479] version: 0.14.3-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ac31eae37ff..91bd148612d 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.14.2" +version = "0.14.3-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 64b1f3a9d262cb95ceaf46af77b0ddcda6c72c53 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 7 Jun 2018 07:55:16 -0400 Subject: [PATCH 198/479] Try expanding JDK version coverage in travis --- .travis.yml | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index d8c23373815..70587ea4342 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,16 +2,15 @@ sudo: true dist: trusty language: java -before_install: - - wget https://raw.githubusercontent.com/sormuras/bach/master/install-jdk.sh - install: true matrix: include: -# Based on https://sormuras.github.io/blog/2018-03-20-jdk-matrix.html -# 7 isn't included because it reached End of Life in April 2015 and requires -# various work-arounds on Travis CI to be compatible with Gradle +# 7 + - env: JDK='Oracle JDK 7' + jdk: oraclejdk7 + - env: JDK='OpenJDK 7' + jdk: openjdk7 # 8 - env: JDK='Oracle JDK 8' jdk: oraclejdk8 @@ -21,29 +20,32 @@ matrix: - env: JDK='Oracle JDK 9' jdk: oraclejdk9 - env: JDK='OpenJDK 9' - install: . ./install-jdk.sh -F 9 + jdk: openjdk9 # 10 - env: JDK='Oracle JDK 10' jdk: oraclejdk10 - env: JDK='OpenJDK 10' - install: . ./install-jdk.sh -F 10 -L GPL + jdk: openjdk10 # 11 - env: JDK='Oracle JDK 11' - install: . ./install-jdk.sh -F 11 -L BCL + jdk: oraclejdk11 - env: JDK='OpenJDK 11' - install: . ./install-jdk.sh -F 11 -L GPL + jdk: openjdk11 allow_failures: - - env: JDK='Oracle JDK 10' # Oracle JDK 10 not yet supported; see https://github.com/travis-ci/travis-ci/issues/9368 - - env: JDK='Oracle JDK 11' # Gradle 4.6 doesn't recognize Java 11 EA versions; should be fixed in Gradle 4.7; https://github.com/gradle/gradle/issues/4515 - - env: JDK='OpenJDK 11' # Gradle 4.6 doesn't recognize Java 11 EA versions; should be fixed in Gradle 4.7; https://github.com/gradle/gradle/issues/4515 + - env: JDK='Oracle JDK 7' + - env: JDK='OpenJDK 7' + - env: JDK='OpenJDK 9' + - env: JDK='Oracle JDK 10' + - env: JDK='OpenJDK 10' + - env: JDK='Oracle JDK 11' + - env: JDK='OpenJDK 11' env: global: - - TERM="dumb" - GRADLE_OPTS="-Xmx386m -Xms386m" script: - echo PATH = ${PATH} - echo JAVA_HOME = ${JAVA_HOME} - - java -version + - java -Xmx32m -version - ./gradlew build testRecentVersionCompatibility --info From df2c16cac638b2daf3090a186a7b57384e5fe52d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 7 Jun 2018 08:24:43 -0400 Subject: [PATCH 199/479] travis: Remove working JDKs from allow_failures, try a workaround for openjdk7 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 70587ea4342..9c9307c8f84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ matrix: jdk: oraclejdk7 - env: JDK='OpenJDK 7' jdk: openjdk7 + before_script: # Try a workaround for https://github.com/travis-ci/travis-ci/issues/8503 + - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security # 8 - env: JDK='Oracle JDK 8' jdk: oraclejdk8 @@ -34,9 +36,6 @@ matrix: allow_failures: - env: JDK='Oracle JDK 7' - env: JDK='OpenJDK 7' - - env: JDK='OpenJDK 9' - - env: JDK='Oracle JDK 10' - - env: JDK='OpenJDK 10' - env: JDK='Oracle JDK 11' - env: JDK='OpenJDK 11' @@ -47,5 +46,6 @@ env: script: - echo PATH = ${PATH} - echo JAVA_HOME = ${JAVA_HOME} + - ls -LRl $JAVA_HOME - java -Xmx32m -version - ./gradlew build testRecentVersionCompatibility --info From fdd357ccd6bb3961454c1076354f803503bc00db Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 7 Jun 2018 08:47:50 -0400 Subject: [PATCH 200/479] travis: more jdk compatibility tweaks remove listing of JAVA_HOME (was causing errors and no longer needed for troubleshooting) try oracle7 on precise --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9c9307c8f84..b82ee3e46a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,10 @@ matrix: # 7 - env: JDK='Oracle JDK 7' jdk: oraclejdk7 + dist: precise # Doesn't exist in trusty any more - env: JDK='OpenJDK 7' jdk: openjdk7 - before_script: # Try a workaround for https://github.com/travis-ci/travis-ci/issues/8503 + before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security # 8 - env: JDK='Oracle JDK 8' @@ -46,6 +47,5 @@ env: script: - echo PATH = ${PATH} - echo JAVA_HOME = ${JAVA_HOME} - - ls -LRl $JAVA_HOME - java -Xmx32m -version - ./gradlew build testRecentVersionCompatibility --info From f0a60f2c1e0104d57bd55bc5dd22e7b53f43075e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 11 Jun 2018 10:29:49 -0400 Subject: [PATCH 201/479] travis: tweak memory settings for java 7 --- .travis.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b82ee3e46a5..20458993b7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,13 +7,17 @@ install: true matrix: include: # 7 - - env: JDK='Oracle JDK 7' + - env: + - JDK='Oracle JDK 7' + - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" jdk: oraclejdk7 dist: precise # Doesn't exist in trusty any more - - env: JDK='OpenJDK 7' + - env: + - JDK='OpenJDK 7' + - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" jdk: openjdk7 before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 - - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security + - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security # 8 - env: JDK='Oracle JDK 8' jdk: oraclejdk8 From 8c4646c28e926ab50d1c461e6d6ecf992713f7fb Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 11 Jun 2018 10:32:43 -0400 Subject: [PATCH 202/479] travis: tidy up matrix builds --- .travis.yml | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/.travis.yml b/.travis.yml index 20458993b7f..061dd2b4b57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,42 +7,30 @@ install: true matrix: include: # 7 - - env: - - JDK='Oracle JDK 7' - - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" - jdk: oraclejdk7 + - jdk: oraclejdk7 + env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen dist: precise # Doesn't exist in trusty any more - - env: - - JDK='OpenJDK 7' - - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" - jdk: openjdk7 + - jdk: openjdk7 + env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security # 8 - - env: JDK='Oracle JDK 8' - jdk: oraclejdk8 - - env: JDK='OpenJDK 8' - jdk: openjdk8 + - jdk: oraclejdk8 + - jdk: openjdk8 # 9 - - env: JDK='Oracle JDK 9' - jdk: oraclejdk9 - - env: JDK='OpenJDK 9' - jdk: openjdk9 + - jdk: oraclejdk9 + - jdk: openjdk9 # 10 - - env: JDK='Oracle JDK 10' - jdk: oraclejdk10 - - env: JDK='OpenJDK 10' - jdk: openjdk10 + - jdk: oraclejdk10 + - jdk: openjdk10 # 11 - - env: JDK='Oracle JDK 11' - jdk: oraclejdk11 - - env: JDK='OpenJDK 11' - jdk: openjdk11 + - jdk: oraclejdk11 + - jdk: openjdk11 allow_failures: - - env: JDK='Oracle JDK 7' - - env: JDK='OpenJDK 7' - - env: JDK='Oracle JDK 11' - - env: JDK='OpenJDK 11' + - jdk: oraclejdk7 + - jdk: openjdk7 + - jdk: oraclejdk11 + - jdk: openjdk11 env: global: From edcef8100d03ae41ebb28b4cc981db33182d81e2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 11 Jun 2018 10:51:06 -0400 Subject: [PATCH 203/479] travis: don't allow java 7 failures --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 061dd2b4b57..f178351043d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,8 +27,6 @@ matrix: - jdk: oraclejdk11 - jdk: openjdk11 allow_failures: - - jdk: oraclejdk7 - - jdk: openjdk7 - jdk: oraclejdk11 - jdk: openjdk11 From f59e11e20c7a77ba270ba59965d01c6b3c6df8ca Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 11 Jun 2018 12:28:04 -0400 Subject: [PATCH 204/479] Update Gradle to 4.8, address Java 11 compatibility issues --- CHANGES.md | 3 +++ README.md | 7 ++++--- build.gradle | 9 ++++++++- config/checkstyle/checkstyle.xml | 2 +- .../checkstyle/import-control.xml | 0 gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 54413 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 4 ++-- 8 files changed, 19 insertions(+), 8 deletions(-) rename import-control.xml => config/checkstyle/import-control.xml (100%) diff --git a/CHANGES.md b/CHANGES.md index d9204522b6d..f24672df3de 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,9 @@ # Change Log ## Unreleased +* Built using Gradle 4.8 +* Updated compatibility testing through Gradle 4.8 +* Began testing using Java 11 ## 0.14.2 * Stop creating default generated output directories when `outputDir` is customized and IntelliJ integration is used (#52) diff --git a/README.md b/README.md index 62151aaa357..bcf3547f578 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,12 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Java 7-10 +* Currently tested against Java 7-11 + * Java 11 support requires Gradle 4.8 or higher * Java 9 support requires Gradle 4.2.1 or higher * If you need support for Java 6, version 0.9.1 was the last supported version -* Currently built against Gradle 4.6 - * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.6 +* Currently built against Gradle 4.8 + * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.8 * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.8.2 diff --git a/build.gradle b/build.gradle index 91bd148612d..6c3487344de 100644 --- a/build.gradle +++ b/build.gradle @@ -147,6 +147,10 @@ checkstyleMain.doLast { throw new GradleException("There were checkstyle warnings! For more info check ${warningsFile}") } } +// In Gradle 4.8 the checkstyle basedir changed to no longer be the project root by default; thus we need to specify +checkstyleMain { + configProperties = ['basedir': "$rootDir/config/checkstyle"] +} codenarc { toolVersion = "1.0" @@ -175,7 +179,10 @@ def gradleVersions = [] if (!org.gradle.api.JavaVersion.current().isJava9Compatible()) { // Gradle 4.2.1 is the first version that supports modern Java 9, as per https://discuss.gradle.org/t/could-not-determine-java-version-from-9-0-1/24457 gradleVersions.addAll("3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2") } -gradleVersions.addAll("4.2.1", "4.3", "4.3.1", "4.4", "4.4.1", "4.5", "4.5.1", "4.6") +if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 appears to be the first version that supports Java 11, as per https://github.com/gradle/gradle/pull/4759 and testing + gradleVersions.addAll("4.2.1", "4.3", "4.3.1", "4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") +} +gradleVersions.addAll("4.8") // Support for running Gradle on Java 7 is deprecated and will be removed in Gradle 5, as per https://docs.gradle.org/4.2.1/release-notes.html avroVersions.each { def avroVersion -> diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 58216aa0194..6c5c934b6de 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -58,7 +58,7 @@
- + diff --git a/import-control.xml b/config/checkstyle/import-control.xml similarity index 100% rename from import-control.xml rename to config/checkstyle/import-control.xml diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f6b961fd5a86aa5fbfe90f707c3138408be7c718..1948b9074f1016d15d505d185bc3f73deb82d8c8 100644 GIT binary patch delta 7399 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 Da{n=i delta 7286 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bf3de218305..d2c45a4b260 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-4.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 63cbaf72497..e3120462a52 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -81,11 +81,11 @@ abstract class FunctionalSpec extends Specification { } protected BuildResult run(String... args = ["build"]) { - return createGradleRunner().withArguments(args).build() + return createGradleRunner().withArguments(Arrays.asList(args) + "--stacktrace").build() } protected BuildResult runAndFail(String... args = ["build"]) { - return createGradleRunner().withArguments(args).buildAndFail() + return createGradleRunner().withArguments(Arrays.asList(args) + "--stacktrace").buildAndFail() } protected boolean isTaskInfoAbsent() { From d9de84d3e82d32358744752c0106f65f6ab2762d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 11 Jun 2018 13:06:20 -0400 Subject: [PATCH 205/479] travis: don't allow failures in java 11 --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f178351043d..5d43aa7305c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,9 +26,6 @@ matrix: # 11 - jdk: oraclejdk11 - jdk: openjdk11 - allow_failures: - - jdk: oraclejdk11 - - jdk: openjdk11 env: global: From 176cdb386ed1d6ba9d80f7470c46feb022345cce Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 11 Jun 2018 13:56:25 -0400 Subject: [PATCH 206/479] gitlab: try to get CI working --- .gitlab-ci.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000000..3524e8b6159 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,30 @@ +.job_template: &job_definition + variables: + - GRADLE_OPTS="-Xmx386m -Xms386m" + script: + - echo PATH = ${PATH} + - echo JAVA_HOME = ${JAVA_HOME} + - java -Xmx32m -version + - ./gradlew build testRecentVersionCompatibility --info + +openjdk7: + <<: *job_definition + image: openjdk:7-jdk + variables: + - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen + +openjdk8: + <<: *job_definition + image: openjdk:8-jdk + +openjdk9: + <<: *job_definition + image: openjdk:9-jdk + +openjdk10: + <<: *job_definition + image: openjdk:10-jdk + +openjdk11: + <<: *job_definition + image: openjdk:11-jdk From 0ad469fd46c1d619cbbabe70f05004df6812ab8a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 11 Jun 2018 13:58:15 -0400 Subject: [PATCH 207/479] gitlab: correct variables syntax --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3524e8b6159..c6427bb5750 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,6 @@ .job_template: &job_definition variables: - - GRADLE_OPTS="-Xmx386m -Xms386m" + GRADLE_OPTS: "-Xmx386m -Xms386m" script: - echo PATH = ${PATH} - echo JAVA_HOME = ${JAVA_HOME} @@ -11,7 +11,7 @@ openjdk7: <<: *job_definition image: openjdk:7-jdk variables: - - GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen + GRADLE_OPTS: "-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen openjdk8: <<: *job_definition From f6342212923966e0d261f638a45362e39bea7bec Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 11 Jun 2018 14:32:01 -0400 Subject: [PATCH 208/479] gitlab-ci: try to fix encryption error with java7 --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c6427bb5750..b8c9f116e85 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,6 +10,8 @@ openjdk7: <<: *job_definition image: openjdk:7-jdk + before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 + - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security variables: GRADLE_OPTS: "-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen From 27e308cfe1376488199f2e4f4dc46560edab885c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 11 Jun 2018 14:34:05 -0400 Subject: [PATCH 209/479] gitlab-ci: try to fix encryption error with java7 --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b8c9f116e85..508844a6ed5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,7 @@ openjdk7: <<: *job_definition image: openjdk:7-jdk before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 - - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security + - sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security variables: GRADLE_OPTS: "-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen From b0271686780dc8629ca12abb2adcf5b5fe80ee9d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 14 Jun 2018 14:48:20 -0400 Subject: [PATCH 210/479] Add security policy --- CONTRIBUTING.md | 2 ++ README.md | 2 ++ SECURITY.md | 6 ++++++ 3 files changed, 10 insertions(+) create mode 100644 SECURITY.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b526bccf217..337dd324b8e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,8 @@ > Before contributing, please read our [code of conduct](https://github.com/commercehub-oss/gradle-avro-plugin/blob/master/CODE_OF_CONDUCT.md). +> See [our security policy](SECURITY.md) for handling of security-related matters. + Before starting work on an enhancement, it's highly recommended to open an [issue](https://github.com/commercehub-oss/gradle-avro-plugin/issues) to describe the intended change. This allows for the project maintainers to provide feedback before you've done work that may not fit the project's vision. diff --git a/README.md b/README.md index bcf3547f578..c0867029e9a 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav [![Build Status](https://travis-ci.org/commercehub-oss/gradle-avro-plugin.svg?branch=master)](https://travis-ci.org/commercehub-oss/gradle-avro-plugin) +> See [our security policy](SECURITY.md) for handling of security-related matters. + # Compatibility * Currently tested against Java 7-11 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..d223e0d95ac --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,6 @@ +# How to report a security vulnerability? + +If you believe you’ve found a security vulnerability in this project, please send it to us by emailing . Please include the following details with your report: + +* Description of the location and potential impact of the vulnerability; +* A detailed description of the steps required to reproduce the vulnerability (POC scripts, screenshots, and compressed screen captures are all helpful to us) From 92f2e369192a7067fce229c8be594782da84ade7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 26 Jun 2018 14:56:55 -0400 Subject: [PATCH 211/479] gitlab: try to integrate code_quality --- .gitlab-ci.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 508844a6ed5..303ce2d7e80 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -30,3 +30,21 @@ openjdk10: openjdk11: <<: *job_definition image: openjdk:11-jdk + + +code_quality: + image: docker:stable + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:stable-dind + script: + - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') + - docker run + --env SOURCE_CODE="$PWD" + --volume "$PWD":/code + --volume /var/run/docker.sock:/var/run/docker.sock + "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code + artifacts: + paths: [gl-code-quality-report.json] From d2c140203bb2ac73854136463242fc1857e510e0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 14 Aug 2018 14:28:29 -0400 Subject: [PATCH 212/479] Add support for generating schema files (#56) Also fix a bug where GenerateAvroProtocolTask can't be used without a runtime configuration --- CHANGES.md | 2 + README.md | 17 ++++ .../gradle/plugin/avro/FileUtils.java | 10 +++ .../plugin/avro/GenerateAvroProtocolTask.java | 31 ++++---- .../plugin/avro/GenerateAvroSchemaTask.java | 72 +++++++++++++++++ .../avro/AvroBasePluginFunctionalSpec.groovy | 77 +++++++++++++++++++ .../avro/AvroPluginFunctionalSpec.groovy | 5 ++ .../DuplicateHandlingFunctionalSpec.groovy | 5 ++ .../plugin/avro/EncodingFunctionalSpec.groovy | 5 ++ .../avro/EnumHandlingFunctionalSpec.groovy | 5 ++ .../gradle/plugin/avro/FunctionalSpec.groovy | 28 +++++-- .../plugin/avro/IntellijFunctionalSpec.groovy | 4 + .../KotlinCompatibilityFunctionalSpec.groovy | 5 ++ .../plugin/avro/OptionsFunctionalSpec.groovy | 4 + .../gradle/plugin/avro/Message.avsc | 15 ++++ 15 files changed, 263 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/Message.avsc diff --git a/CHANGES.md b/CHANGES.md index f24672df3de..6cd0598f0cd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,8 @@ * Built using Gradle 4.8 * Updated compatibility testing through Gradle 4.8 * Began testing using Java 11 +* Add support for generating schema files (#56) +* Fix bug where `GenerateAvroProtocolTask` can't be used without a runtime configuration ## 0.14.2 * Stop creating default generated output directories when `outputDir` is customized and IntelliJ integration is used (#52) diff --git a/README.md b/README.md index c0867029e9a..f23ff72ea70 100644 --- a/README.md +++ b/README.md @@ -289,3 +289,20 @@ The Java classes generated from your Avro files should be automatically accessib This is accomplished by this plugin detecting that the Kotlin plugin has been applied, and informing the Kotlin compilation tasks of the presence of the generated sources directories for cross-compilation. This support does *not* support producing the Avro generated classes as Kotlin classes, as that functionality is not currently provided by the upstream Avro library. + +# Generating schema files + +If desired, you can generate JSON schema files based on IDL or JSON protocol files. +To do this, apply the plugin (either `avro` or `avro-base`), and define a custom task for the schema generation. + +Example: + +```groovy +apply plugin: "com.commercehub.gradle.plugin.avro-base" + +task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + source file("src/main/avro") + include("**/*.avpr") + outputDir = file("build/generated-main-avro-avsc") +} +``` diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java index 89913f9dbbf..1533066ea69 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java @@ -131,4 +131,14 @@ static void writeStringToFile(File file, String data, String encoding) throws IO } } } + + /** + * Writes a file in a manner appropriate for a JSON file. UTF-8 will be used, as it is the default encoding for JSON, and should be + * maximally interoperable. + * + * @see JSON Character Encoding + */ + static void writeJsonFile(File file, String data) throws IOException { + writeStringToFile(file, data, Constants.UTF8_ENCODING); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index e294c5cf16c..2628c6cc94f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -20,6 +20,7 @@ import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.UnknownConfigurationException; import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.TaskAction; @@ -73,7 +74,8 @@ private void processIDLFile(File idlFile, ClassLoader loader) { try { idl = new Idl(idlFile, loader); String protoJson = idl.CompilationUnit().toString(true); - writeJsonFile(protoFile, protoJson); + FileUtils.writeJsonFile(protoFile, protoJson); + getLogger().debug("Wrote {}", protoFile.getPath()); } catch (IOException | ParseException ex) { throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); } finally { @@ -89,13 +91,18 @@ private void processIDLFile(File idlFile, ClassLoader loader) { private ClassLoader getRuntimeClassLoader(Project project) { List urls = new LinkedList<>(); - Configuration configuration = project.getConfigurations().getByName(getRuntimeConfigurationName()); - for (File file : configuration) { - try { - urls.add(file.toURI().toURL()); - } catch (MalformedURLException e) { - getLogger().debug(e.getMessage()); + String configurationName = getRuntimeConfigurationName(); + try { + Configuration configuration = project.getConfigurations().getByName(configurationName); + for (File file : configuration) { + try { + urls.add(file.toURI().toURL()); + } catch (MalformedURLException e) { + getLogger().debug(e.getMessage()); + } } + } catch (UnknownConfigurationException ex) { + getLogger().debug("No configuration found with name {}; defaulting to system classloader", configurationName); } return urls.isEmpty() ? ClassLoader.getSystemClassLoader() : new URLClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader()); @@ -108,14 +115,4 @@ private static String getRuntimeConfigurationName() { return GradleVersion.current().compareTo(GradleVersion.version("3.5")) >= 0 ? Constants.RUNTIME_CLASSPATH_CONFIGURATION_NAME : Constants.RUNTIME_CONFIGURATION_NAME; } - - /** - * Writes a file in a manner appropriate for a JSON file. UTF-8 will be used, as it is the default encoding for JSON, and should be - * maximally interoperable. - * - * @see JSON Character Encoding - */ - private void writeJsonFile(File file, String data) throws IOException { - FileUtils.writeStringToFile(file, data, Constants.UTF8_ENCODING); - } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java new file mode 100644 index 00000000000..17b020ce991 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java @@ -0,0 +1,72 @@ +/* + * Copyright © 2018 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; + +import org.apache.avro.Protocol; +import org.apache.avro.Schema; +import org.gradle.api.GradleException; +import org.gradle.api.file.FileCollection; +import org.gradle.api.specs.NotSpec; +import org.gradle.api.tasks.TaskAction; + +import java.io.File; +import java.io.IOException; +import java.util.regex.Pattern; + +import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; +import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; + +public class GenerateAvroSchemaTask extends OutputDirTask { + @TaskAction + protected void process() { + getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); + failOnUnsupportedFiles(); + processFiles(); + } + + private void failOnUnsupportedFiles() { + FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(PROTOCOL_EXTENSION))); + if (!unsupportedFiles.isEmpty()) { + throw new GradleException( + String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); + } + } + + private void processFiles() { + int processedFileCount = 0; + for (File sourceFile : filterSources(new FileExtensionSpec(PROTOCOL_EXTENSION))) { + processProtoFile(sourceFile); + processedFileCount++; + } + setDidWork(processedFileCount > 0); + } + + private void processProtoFile(File sourceFile) { + getLogger().info("Processing {}", sourceFile); + try { + Protocol protocol = Protocol.parse(sourceFile); + for (Schema schema : protocol.getTypes()) { + String path = schema.getNamespace().replaceAll(Pattern.quote("."), "/"); + File schemaFile = new File(getOutputDir(), path + "/" + schema.getName() + "." + SCHEMA_EXTENSION); + String schemaJson = schema.toString(true); + FileUtils.writeJsonFile(schemaFile, schemaJson); + getLogger().debug("Wrote {}", schemaFile.getPath()); + } + } catch (IOException ex) { + throw new GradleException(String.format("Failed to process protocol definition file %s", sourceFile), ex); + } + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy new file mode 100644 index 00000000000..7047a18433b --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy @@ -0,0 +1,77 @@ +/* + * Copyright © 2018 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class AvroBasePluginFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroBasePlugin() + } + + def "can generate json schema files from json protocol"() { + given: + buildFile << """ + task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + source file("src/main/avro") + include("**/*.avpr") + outputDir = file("build/generated-main-avro-avsc") + } + """ + + copyResource("mail.avpr", avroDir) + + when: + def result = run("generateSchema") + + then: + taskInfoAbsent || result.task(":generateSchema").outcome == SUCCESS + def expectedFileContents = getClass().getResource("Message.avsc").text.trim() + def generateFileContents = new File(testProjectDir.root, + "build/generated-main-avro-avsc/org/apache/avro/test/Message.avsc").text.trim() + expectedFileContents == generateFileContents + } + + def "can generate json schema files from IDL"() { + given: + buildFile << """ + task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + source file("src/main/avro") + outputDir = file("build/generated-avro-main-avpr") + } + + task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + dependsOn generateProtocol + source file("build/generated-avro-main-avpr") + include("**/*.avpr") + outputDir = file("build/generated-main-avro-avsc") + } + """ + + copyResource("interop.avdl", avroDir) + + when: + def result = run("generateSchema") + + then: + taskInfoAbsent || result.task(":generateSchema").outcome == SUCCESS + projectFile("build/generated-main-avro-avsc/org/apache/avro/Foo.avsc").file + projectFile("build/generated-main-avro-avsc/org/apache/avro/Kind.avsc").file + projectFile("build/generated-main-avro-avsc/org/apache/avro/MD5.avsc").file + projectFile("build/generated-main-avro-avsc/org/apache/avro/Node.avsc").file + projectFile("build/generated-main-avro-avsc/org/apache/avro/Interop.avsc").file + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 6006256f629..d0eb78bdd67 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -19,6 +19,11 @@ import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class AvroPluginFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroPlugin() + addAvroDependency() + } + def "can generate and compile java files from json schema"() { given: copyResource("user.avsc", avroDir) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index a1f5fd2587a..1fd9dccdcc4 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -25,6 +25,11 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS * are used in more than one file.

*/ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroPlugin() + addAvroDependency() + } + def "Duplicate enum definition succeeds if definition identical"() { given: copyIdenticalEnum() diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy index b1273b44903..38cdc11fac1 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -27,6 +27,11 @@ class EncodingFunctionalSpec extends FunctionalSpec { private static final List AVAILABLE_ENCODINGS = ["UTF-8", "UTF-16", "UTF-32", "windows-1252", "X-MacRoman"].findAll { Charset.isSupported(it) } + def "setup"() { + applyAvroPlugin() + addAvroDependency() + } + def "default encoding matches default compilation behavior"() { given: copyResource("idioma.avsc", avroDir) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index 483585c4011..aa90af21665 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -21,6 +21,11 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS * Functional tests relating to handling of enums. */ class EnumHandlingFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroPlugin() + addAvroDependency() + } + def "supports simple enums"() { given: copyResource("enumSimple.avsc", avroDir) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index e3120462a52..da28f668528 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright © 2015-2016 Commerce Technologies, LLC. + * Copyright © 2015-2018 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,9 +26,9 @@ import spock.lang.Specification @SuppressWarnings(["Println"]) abstract class FunctionalSpec extends Specification { @SuppressWarnings(["FieldName"]) - protected static final String avroVersion = System.getProperty("avroVersion") + protected static final String avroVersion = System.getProperty("avroVersion", "undefined") @SuppressWarnings(["FieldName"]) - protected static final GradleVersion gradleVersion = GradleVersion.version(System.getProperty("gradleVersion")) + protected static final GradleVersion gradleVersion = GradleVersion.version(System.getProperty("gradleVersion", "undefined")) @Rule TemporaryFolder testProjectDir @@ -60,12 +60,30 @@ abstract class FunctionalSpec extends Specification { classpath files($pluginClasspath) } } - apply plugin: "com.commercehub.gradle.plugin.avro" repositories { jcenter() } - dependencies { compile "org.apache.avro:avro:${avroVersion}" } """ } + protected void applyAvroPlugin() { + applyPlugin("com.commercehub.gradle.plugin.avro") + } + + protected void applyAvroBasePlugin() { + applyPlugin("com.commercehub.gradle.plugin.avro-base") + } + + private void applyPlugin(String pluginId) { + buildFile << "apply plugin: \"${pluginId}\"\n" + } + + protected void addDependency(String dependencySpec) { + buildFile << "dependencies { compile \"${dependencySpec}\" }\n" + } + + protected void addAvroDependency() { + addDependency("org.apache.avro:avro:${avroVersion}") + } + protected void copyResource(String name, File targetFolder) { def file = new File(targetFolder, name) file.parentFile.mkdirs() diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy index 7f80be96335..bd05de213eb 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy @@ -18,6 +18,10 @@ package com.commercehub.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class IntellijFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroPlugin() + } + def "generated intellij project files include source directories for generated source"() { given: buildFile << """ diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy index f027f13cc76..f24c020c753 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy @@ -19,6 +19,11 @@ import org.gradle.util.GradleVersion import spock.lang.IgnoreIf class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroPlugin() + addAvroDependency() + } + /** * Since Kotlin 1.1.2, the Kotlin compiler requires Java 8+ * https://blog.jetbrains.com/kotlin/2017/04/kotlin-1-1-2-is-out/ diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 25e851369c3..cbbb4e67670 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -28,6 +28,10 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS * Functional tests for most functions. Encoding tests have been pulled out into {@link EncodingFunctionalSpec}. */ class OptionsFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroPlugin() + } + def "works with default options"() { given: copyResource("user.avsc", avroDir) diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/Message.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/Message.avsc new file mode 100644 index 00000000000..fefda8fe4a8 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/Message.avsc @@ -0,0 +1,15 @@ +{ + "type" : "record", + "name" : "Message", + "namespace" : "org.apache.avro.test", + "fields" : [ { + "name" : "to", + "type" : "string" + }, { + "name" : "from", + "type" : "string" + }, { + "name" : "body", + "type" : "string" + } ] +} From 4f9385f9d4a900e6ed873f5c61034539a9cbf862 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 16 Aug 2018 16:16:24 -0400 Subject: [PATCH 213/479] travis: try to fix ssl issue for oraclejdk7 --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5d43aa7305c..d5ff94abc1c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,6 @@ install: true matrix: include: # 7 - - jdk: oraclejdk7 - env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen - dist: precise # Doesn't exist in trusty any more - jdk: openjdk7 env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 From bd1fdbe0fbd5bda0e399064f0d182a29c6cd1efd Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 16 Aug 2018 16:16:42 -0400 Subject: [PATCH 214/479] travis: try to fix ssl issue for oraclejdk7 --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index d5ff94abc1c..d2e1b3c4bc4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,11 @@ install: true matrix: include: # 7 + - jdk: oraclejdk7 + env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen + dist: precise # Doesn't exist in trusty any more + before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 + - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security - jdk: openjdk7 env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 From 15fe64805b09cf615c149302281c59d6117a2378 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 16 Aug 2018 16:23:25 -0400 Subject: [PATCH 215/479] Update instructions for historical versions --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f23ff72ea70..0b87ea2e553 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,16 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Java 7-11 * Java 11 support requires Gradle 4.8 or higher * Java 9 support requires Gradle 4.2.1 or higher - * If you need support for Java 6, version 0.9.1 was the last supported version + * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Gradle 4.8 * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.8 - * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility + * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.8.2 * Currently tested against Avro 1.8.2; other versions may be compatible * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 - * If you need support for Avro 1.7.x, try plugin version 0.8.0; versions of Avro before that are unlikely to work + * If you need support for Avro 1.7.x, try plugin version 0.8.0; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) + * Versions of Avro prior to 1.7.x are unlikely to work * Incubating: support for Kotlin * Currently tested against Kotlin 1.2.31 * Kotlin 1.1.2 and higher requires Java 8+ From 9bd66735ded05c9eb54042fe186e94129dec6ed5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 16 Aug 2018 16:37:25 -0400 Subject: [PATCH 216/479] travis: remove oraclejdk7 build It's broken, deprecated, and probably not long for this world even if I could get it working again https://blog.travis-ci.com/2017-08-31-trusty-as-default-status --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index d2e1b3c4bc4..d5ff94abc1c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,11 +7,6 @@ install: true matrix: include: # 7 - - jdk: oraclejdk7 - env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen - dist: precise # Doesn't exist in trusty any more - before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 - - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security - jdk: openjdk7 env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 From 8892df806b1fcabd3d8c5cd2f1aa16a3bb1b95cf Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 21 Aug 2018 11:14:26 -0400 Subject: [PATCH 217/479] Clarify instructions for generating schema files (#56) --- README.md | 16 +++++++-- .../avro/AvroBasePluginFunctionalSpec.groovy | 34 +++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0b87ea2e553..39ffc2e3929 100644 --- a/README.md +++ b/README.md @@ -293,16 +293,26 @@ This support does *not* support producing the Avro generated classes as Kotlin c # Generating schema files -If desired, you can generate JSON schema files based on IDL or JSON protocol files. -To do this, apply the plugin (either `avro` or `avro-base`), and define a custom task for the schema generation. +If desired, you can generate JSON schema files. +To do this, apply the plugin (either `avro` or `avro-base`), and define custom tasks as needed for the schema generation. +From JSON protocol files, all that's needed is the `GenerateAvroSchemaTask`. +From IDL files, first use `GenerateAvroProtocolTask` to convert the IDL files to JSON protocol files, then use `GenerateAvroSchemaTask`. -Example: +Example using base plugin with support for both IDL and JSON protocol files in `src/main/avro`: ```groovy apply plugin: "com.commercehub.gradle.plugin.avro-base" +task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + source file("src/main/avro") + include("**/*.avdl") + outputDir = file("build/generated-avro-main-avpr") +} + task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + dependsOn generateProtocol source file("src/main/avro") + source file("build/generated-avro-main-avpr") include("**/*.avpr") outputDir = file("build/generated-main-avro-avsc") } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy index 7047a18433b..caf22d6e028 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy @@ -74,4 +74,38 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { projectFile("build/generated-main-avro-avsc/org/apache/avro/Node.avsc").file projectFile("build/generated-main-avro-avsc/org/apache/avro/Interop.avsc").file } + + def "example of converting both IDL and json protocol simultaneously"() { + given: + buildFile << """ + task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + source file("src/main/avro") + include("**/*.avdl") + outputDir = file("build/generated-avro-main-avpr") + } + + task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + dependsOn generateProtocol + source file("src/main/avro") + source file("build/generated-avro-main-avpr") + include("**/*.avpr") + outputDir = file("build/generated-main-avro-avsc") + } + """ + + copyResource("mail.avpr", avroDir) + copyResource("interop.avdl", avroDir) + + when: + def result = run("generateSchema") + + then: + taskInfoAbsent || result.task(":generateSchema").outcome == SUCCESS + projectFile("build/generated-main-avro-avsc/org/apache/avro/test/Message.avsc").file + projectFile("build/generated-main-avro-avsc/org/apache/avro/Foo.avsc").file + projectFile("build/generated-main-avro-avsc/org/apache/avro/Kind.avsc").file + projectFile("build/generated-main-avro-avsc/org/apache/avro/MD5.avsc").file + projectFile("build/generated-main-avro-avsc/org/apache/avro/Node.avsc").file + projectFile("build/generated-main-avro-avsc/org/apache/avro/Interop.avsc").file + } } From 34a9fc786f00f8c4382575997df7657ba38172f2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 22 Aug 2018 12:12:36 -0400 Subject: [PATCH 218/479] Upgrade to gradle 4.9 --- CHANGES.md | 4 ++-- README.md | 4 ++-- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 54413 -> 54413 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6cd0598f0cd..3f1f61b44d7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,8 +1,8 @@ # Change Log ## Unreleased -* Built using Gradle 4.8 -* Updated compatibility testing through Gradle 4.8 +* Built using Gradle 4.9 +* Updated compatibility testing through Gradle 4.9 * Began testing using Java 11 * Add support for generating schema files (#56) * Fix bug where `GenerateAvroProtocolTask` can't be used without a runtime configuration diff --git a/README.md b/README.md index 39ffc2e3929..c0138a4ee08 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 11 support requires Gradle 4.8 or higher * Java 9 support requires Gradle 4.2.1 or higher * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Gradle 4.8 - * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.8 +* Currently built against Gradle 4.9 + * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.9 * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.8.2 diff --git a/build.gradle b/build.gradle index 6c3487344de..2d035879030 100644 --- a/build.gradle +++ b/build.gradle @@ -182,7 +182,7 @@ if (!org.gradle.api.JavaVersion.current().isJava9Compatible()) { // Gradle 4.2.1 if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 appears to be the first version that supports Java 11, as per https://github.com/gradle/gradle/pull/4759 and testing gradleVersions.addAll("4.2.1", "4.3", "4.3.1", "4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") } -gradleVersions.addAll("4.8") +gradleVersions.addAll("4.8", "4.8.1", "4.9") // Support for running Gradle on Java 7 is deprecated and will be removed in Gradle 5, as per https://docs.gradle.org/4.2.1/release-notes.html avroVersions.each { def avroVersion -> diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1948b9074f1016d15d505d185bc3f73deb82d8c8..0d4a9516871afd710a9d84d89e31ba77745607bd 100644 GIT binary patch delta 64 zcmeBO$=th=d4f61&s)=~CR#_bek%G{#5nn2s`SP!L5H|l7y`W6IVzO3lP3!t_6IB4 PoP7A601H^i^@;}ochnli delta 64 zcmeBO$=th=d4f5M=jU(k6RjgzKNNi|Vw`+1ReIx=phH{?3<2Kk9Pfm6L?#Oy_6IB4 PoP7A601H^i^@;}oU3MB9 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d2c45a4b260..a95009c3b9e 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-4.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From fb7849dcf944f02c0d8092dd682a5917adf20997 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 22 Aug 2018 12:17:11 -0400 Subject: [PATCH 219/479] version: 0.15.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 3f1f61b44d7..1027f16404d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.15.0 * Built using Gradle 4.9 * Updated compatibility testing through Gradle 4.9 * Began testing using Java 11 diff --git a/build.gradle b/build.gradle index 2d035879030..d9ea01a0a08 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.14.3-SNAPSHOT" +version = "0.15.0" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 1917604ce17ae798b5c5ea37dba5dcad9bca78d5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 22 Aug 2018 12:27:34 -0400 Subject: [PATCH 220/479] Upgrade gradle-bintray-plugin to 1.8.1 Fixes "message:Unable to upload files: Maven group, artifact or version defined in the pom file do not match the file path" error https://github.com/bintray/gradle-bintray-plugin/issues/242 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d9ea01a0a08..db11d24b770 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { id "idea" id "maven-publish" id "java-gradle-plugin" - id "com.jfrog.bintray" version "1.7.3" + id "com.jfrog.bintray" version "1.8.1" id "com.github.hierynomus.license" version "0.14.0" } From e8f2c90723747c024aa63648ee751a54a52ab3b5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 22 Aug 2018 12:30:20 -0400 Subject: [PATCH 221/479] version: 0.15.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index db11d24b770..2321462885b 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.15.0" +version = "0.15.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From facac2297132c6a1a7c93c435a25c45477900c30 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 12 Sep 2018 13:54:52 -0400 Subject: [PATCH 222/479] Improve kotlin DSL support (fix boolean settings compatibility) --- CHANGES.md | 1 + README.md | 9 +++++++++ .../gradle/plugin/avro/DefaultAvroExtension.java | 16 ++++++++++++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1027f16404d..0d958957b04 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Fix "Boolean configuration cannot be set with boolean values from Kotlin DSL" (#60) ## 0.15.0 * Built using Gradle 4.9 diff --git a/README.md b/README.md index c0138a4ee08..e6ce953582b 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Kotlin 1.2.31 * Kotlin 1.1.2 and higher requires Java 8+ * Doesn't work with Gradle 3.2-3.2.1 +* Incubating: support for Gradle Kotlin DSL + * No test coverage yet; will attempt to address incompatibilities as they are discovered # Usage @@ -291,6 +293,13 @@ This is accomplished by this plugin detecting that the Kotlin plugin has been ap This support does *not* support producing the Avro generated classes as Kotlin classes, as that functionality is not currently provided by the upstream Avro library. +# Kotlin DSL Support + +Special notes relevant to using this plugin via the Gradle Kotlin DSL: + +* Apply the plugin declaratively using the `plugins {}` block. Otherwise, various features may not work as intended. See [Configuring Plugins in the Gradle Kotlin DSL](https://github.com/gradle/kotlin-dsl/blob/master/doc/getting-started/Configuring-Plugins.md) for more details. +* Most configuration in the `avro {}` block can be used identically to the Groovy DSL. Boolean settings are an exception, as they require an "is" prefix. For example, instead of `createSetters = false`, one would use `isCreateSetters = false`. See [Getters and Setters](https://kotlinlang.org/docs/reference/java-interop.html#getters-and-setters) for more details. + # Generating schema files If desired, you can generate JSON schema files. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 093a7eb35a1..da40f1889eb 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -83,7 +83,11 @@ public boolean isCreateSetters() { } public void setCreateSetters(String createSetters) { - this.createSetters = Boolean.parseBoolean(createSetters); + setCreateSetters(Boolean.parseBoolean(createSetters)); + } + + public void setCreateSetters(boolean createSetters) { + this.createSetters = createSetters; } @Override @@ -92,7 +96,11 @@ public boolean isEnableDecimalLogicalType() { } public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { - this.enableDecimalLogicalType = Boolean.parseBoolean(enableDecimalLogicalType); + setEnableDecimalLogicalType(Boolean.parseBoolean(enableDecimalLogicalType)); + } + + public void setEnableDecimalLogicalType(boolean enableDecimalLogicalType) { + this.enableDecimalLogicalType = enableDecimalLogicalType; } @Override @@ -100,6 +108,10 @@ public boolean isValidateDefaults() { return validateDefaults; } + public void setValidateDefaults(String validateDefaults) { + setValidateDefaults(Boolean.parseBoolean(validateDefaults)); + } + public void setValidateDefaults(boolean validateDefaults) { this.validateDefaults = validateDefaults; } From 73764a664678331feacb9e535d6514ce710bf488 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 12 Sep 2018 14:15:49 -0400 Subject: [PATCH 223/479] version: 0.15.1 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 0d958957b04..84c7c6cba41 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.15.1 * Fix "Boolean configuration cannot be set with boolean values from Kotlin DSL" (#60) ## 0.15.0 diff --git a/build.gradle b/build.gradle index 2321462885b..4c1f0510c14 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.15.1-SNAPSHOT" +version = "0.15.1" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From fcc4879addc68f8538ea643537b13b462c9488af Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 12 Sep 2018 14:17:42 -0400 Subject: [PATCH 224/479] version: 0.15.2-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4c1f0510c14..e6f06ef04cc 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.15.1" +version = "0.15.2-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 82fd691cacaa03ae16c6a3c9a463bda20367a4b5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 25 Oct 2018 13:04:43 -0400 Subject: [PATCH 225/479] Add tests for build cache support --- CHANGES.md | 2 + build.gradle | 2 +- .../avro/AvroPluginFunctionalSpec.groovy | 8 +- .../BuildCacheSupportFunctionalSpec.groovy | 103 ++++++++++++++++++ .../gradle/plugin/avro/FunctionalSpec.groovy | 8 +- .../plugin/avro/IntellijFunctionalSpec.groovy | 9 +- 6 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy diff --git a/CHANGES.md b/CHANGES.md index 84c7c6cba41..0e6be739ee7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased +* Upgrade Spock from 1.0 to 1.2 +* Add tests for pending support for the Gradle [Build Cache](https://docs.gradle.org/current/userguide/build_cache.html) ## 0.15.1 * Fix "Boolean configuration cannot be set with boolean values from Kotlin DSL" (#60) diff --git a/build.gradle b/build.gradle index e6f06ef04cc..dbf19c5f85a 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ def compileAvroVersion = "1.8.2" dependencies { compile localGroovy() compile "org.apache.avro:avro-compiler:${compileAvroVersion}" - testCompile("org.spockframework:spock-core:1.0-groovy-2.4") { + testCompile("org.spockframework:spock-core:1.2-groovy-2.4") { exclude module: "groovy-all" } testCompile gradleTestKit() diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index d0eb78bdd67..a7c4a1622e6 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -39,9 +39,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def "can generate and compile java files from json protocol"() { given: - buildFile << """ - dependencies { compile "org.apache.avro:avro-ipc:${avroVersion}" } - """ + addAvroIpcDependency() copyResource("mail.avpr", avroDir) when: @@ -87,9 +85,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def "supports json protocol files in subdirectories"() { given: - buildFile << """ - dependencies { compile "org.apache.avro:avro-ipc:${avroVersion}" } - """ + addAvroIpcDependency() copyResource("mail.avpr", avroSubDir) when: diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy new file mode 100644 index 00000000000..0c85f87c2de --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy @@ -0,0 +1,103 @@ +/* + * Copyright © 2018 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro + +import org.gradle.util.GradleVersion +import spock.lang.IgnoreIf +import spock.lang.PendingFeature + +import static org.gradle.testkit.runner.TaskOutcome.FROM_CACHE + +/** + * Testing for Build Cache feature support. + * + * Only run if on a version of Gradle after Build Cache support was introduced. + */ +@IgnoreIf({ gradleVersion < GradleVersion.version("3.5") }) +class BuildCacheSupportFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroPlugin() + addAvroDependency() + } + + @PendingFeature + def "supports build cache for schema/protocol java source generation"() { + given: "a project is built once with build cache enabled" + copyResource("user.avsc", avroDir) + copyResource("mail.avpr", avroDir) + addAvroIpcDependency() + run("build", "--build-cache") + + and: "the project is cleaned" + run("clean") + + when: "the project is built again with build cache enabled" + def result = run("build", "--build-cache") + + then: "the expected outputs were produced from the build cache" + taskInfoAbsent || result.task(":generateAvroJava").outcome == FROM_CACHE + taskInfoAbsent || result.task(":compileJava").outcome == FROM_CACHE + projectFile("build/generated-main-avro-java/example/avro/User.java").file + projectFile("build/generated-main-avro-java/org/apache/avro/test/Mail.java").file + projectFile(buildOutputClassPath("example/avro/User.class")).file + projectFile(buildOutputClassPath("org/apache/avro/test/Mail.class")).file + } + + @PendingFeature + def "supports build cache for IDL to protocol conversion"() { + given: "a project is built once with build cache enabled" + copyResource("interop.avdl", avroDir) + run("build", "--build-cache") + + and: "the project is cleaned" + run("clean") + + when: "the project is built again with build cache enabled" + def result = run("build", "--build-cache") + + then: "the expected outputs were produced from the build cache" + taskInfoAbsent || result.task(":generateAvroProtocol").outcome == FROM_CACHE + taskInfoAbsent || result.task(":generateAvroJava").outcome == FROM_CACHE + taskInfoAbsent || result.task(":compileJava").outcome == FROM_CACHE + projectFile("build/generated-main-avro-avpr/interop.avpr").file + projectFile("build/generated-main-avro-java/org/apache/avro/Interop.java").file + projectFile(buildOutputClassPath("org/apache/avro/Interop.class")).file + } + + @PendingFeature + def "supports build cache for protocol to schema conversion"() { + given: "a project is built once with build cache enabled" + copyResource("mail.avpr", avroDir) + buildFile << """ + task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + source file("src/main/avro") + include("**/*.avpr") + outputDir = file("build/generated-main-avro-avsc") + } + """ + run("generateSchema", "--build-cache") + + and: "the project is cleaned" + run("clean") + + when: "the project is built again with build cache enabled" + def result = run("generateSchema", "--build-cache") + + then: "the expected outputs were produced from the build cache" + taskInfoAbsent || result.task(":generateSchema").outcome == FROM_CACHE + projectFile("build/generated-main-avro-avsc/org/apache/avro/test/Message.avsc").file + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index da28f668528..ba771e5255c 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -41,7 +41,7 @@ abstract class FunctionalSpec extends Specification { println "Testing using Avro version ${avroVersion}." println "Testing using Gradle version ${gradleVersion}." - buildFile = testProjectDir.newFile('build.gradle') + buildFile = testProjectDir.newFile("build.gradle") avroDir = testProjectDir.newFolder("src", "main", "avro") avroSubDir = testProjectDir.newFolder("src", "main", "avro", "foo") @@ -72,7 +72,7 @@ abstract class FunctionalSpec extends Specification { applyPlugin("com.commercehub.gradle.plugin.avro-base") } - private void applyPlugin(String pluginId) { + protected void applyPlugin(String pluginId) { buildFile << "apply plugin: \"${pluginId}\"\n" } @@ -84,6 +84,10 @@ abstract class FunctionalSpec extends Specification { addDependency("org.apache.avro:avro:${avroVersion}") } + protected void addAvroIpcDependency() { + addDependency("org.apache.avro:avro-ipc:${avroVersion}") + } + protected void copyResource(String name, File targetFolder) { def file = new File(targetFolder, name) file.parentFile.mkdirs() diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy index bd05de213eb..70dab02e77a 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy @@ -20,13 +20,11 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class IntellijFunctionalSpec extends FunctionalSpec { def "setup"() { applyAvroPlugin() + applyPlugin("idea") } def "generated intellij project files include source directories for generated source"() { given: - buildFile << """ - apply plugin: "idea" - """ copyResource("user.avsc", avroDir) testProjectDir.newFolder("src", "main", "java") testProjectDir.newFolder("src", "test", "java") @@ -49,10 +47,6 @@ class IntellijFunctionalSpec extends FunctionalSpec { } def "generated output directories are created by default"() { - given: - buildFile << """ - apply plugin: "idea" - """ when: def result = run("idea") @@ -65,7 +59,6 @@ class IntellijFunctionalSpec extends FunctionalSpec { def "overriding task's outputDir doesn't result in default directory still being created"() { given: buildFile << """ - apply plugin: "idea" generateAvroJava { outputDir = file("build/generatedMainAvro") } From 35059196770298a8f506f201fbcf9ef3a735d1be Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 25 Oct 2018 13:15:08 -0400 Subject: [PATCH 226/479] Update contribution to complete support for gradle build cache (#48) * Update change log * Remove @PendingFeature from tests * Fix handling of templateDirectory * Add support for caching GenerateAvroSchemaTask * Fix checkstyle violations --- CHANGES.md | 2 +- .../commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java | 3 +-- .../gradle/plugin/avro/GenerateAvroSchemaTask.java | 4 +++- .../com/commercehub/gradle/plugin/avro/OutputDirTask.java | 3 +-- .../gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy | 4 ---- 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0e6be739ee7..7b844c762ef 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ ## Unreleased * Upgrade Spock from 1.0 to 1.2 -* Add tests for pending support for the Gradle [Build Cache](https://docs.gradle.org/current/userguide/build_cache.html) +* Added support for the Gradle [Build Cache](https://docs.gradle.org/current/userguide/build_cache.html) (#48); contribution from [dcabasson](https://github.com/dcabasson) ## 0.15.1 * Fix "Boolean configuration cannot be set with boolean values from Kotlin DSL" (#60) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 1e1030be2b3..7ff7cc064de 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -100,8 +100,7 @@ public void setFieldVisibility(SpecificCompiler.FieldVisibility fieldVisibility) } @Optional - @InputDirectory - @PathSensitive(PathSensitivity.RELATIVE) + @Input public String getTemplateDirectory() { return templateDirectory; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java index 17b020ce991..95e831ceb76 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java @@ -20,6 +20,7 @@ import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; +import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.TaskAction; import java.io.File; @@ -29,10 +30,11 @@ import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; +@CacheableTask public class GenerateAvroSchemaTask extends OutputDirTask { @TaskAction protected void process() { - getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); + getLogger().info("Found {} files", getSource().getFiles().size()); failOnUnsupportedFiles(); processFiles(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java index 64f59ad207d..fc440d2baac 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java @@ -24,7 +24,6 @@ import java.io.File; -import static org.gradle.api.tasks.PathSensitivity.NAME_ONLY; import static org.gradle.api.tasks.PathSensitivity.RELATIVE; class OutputDirTask extends SourceTask { @@ -35,7 +34,7 @@ public void setOutputDir(File outputDir) { getOutputs().dir(outputDir); } - @PathSensitive(value=RELATIVE) + @PathSensitive(value = RELATIVE) public FileTree getSource() { return super.getSource(); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy index 0c85f87c2de..48a52cb0ec2 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy @@ -17,7 +17,6 @@ package com.commercehub.gradle.plugin.avro import org.gradle.util.GradleVersion import spock.lang.IgnoreIf -import spock.lang.PendingFeature import static org.gradle.testkit.runner.TaskOutcome.FROM_CACHE @@ -33,7 +32,6 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { addAvroDependency() } - @PendingFeature def "supports build cache for schema/protocol java source generation"() { given: "a project is built once with build cache enabled" copyResource("user.avsc", avroDir) @@ -56,7 +54,6 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { projectFile(buildOutputClassPath("org/apache/avro/test/Mail.class")).file } - @PendingFeature def "supports build cache for IDL to protocol conversion"() { given: "a project is built once with build cache enabled" copyResource("interop.avdl", avroDir) @@ -77,7 +74,6 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { projectFile(buildOutputClassPath("org/apache/avro/Interop.class")).file } - @PendingFeature def "supports build cache for protocol to schema conversion"() { given: "a project is built once with build cache enabled" copyResource("mail.avpr", avroDir) From 4967917dc77536620a9e2077cdfac424e24b86ea Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 25 Oct 2018 13:21:20 -0400 Subject: [PATCH 227/479] Update plugin publishing mode to address Gradle 5.0 deprecation warning --- CHANGES.md | 1 + gradle.properties | 1 + settings.gradle | 2 ++ 3 files changed, 4 insertions(+) create mode 100644 gradle.properties diff --git a/CHANGES.md b/CHANGES.md index 7b844c762ef..ac66fdefa3c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ ## Unreleased * Upgrade Spock from 1.0 to 1.2 * Added support for the Gradle [Build Cache](https://docs.gradle.org/current/userguide/build_cache.html) (#48); contribution from [dcabasson](https://github.com/dcabasson) +* Update plugin publishing mode to address Gradle 5.0 deprecation warning ## 0.15.1 * Fix "Boolean configuration cannot be set with boolean values from Kotlin DSL" (#60) diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000000..55a902b413b --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +org.gradle.warning.mode=all diff --git a/settings.gradle b/settings.gradle index cf064976db5..31f651b27a1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,3 @@ rootProject.name = "gradle-avro-plugin" + +enableFeaturePreview("STABLE_PUBLISHING") From 0b825c788134d506d3efe35f395645123b63c81d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 25 Oct 2018 13:25:06 -0400 Subject: [PATCH 228/479] Update gradle wrapper/testing to version 4.10.2 --- CHANGES.md | 4 +++- README.md | 4 ++-- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 54413 -> 56177 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ac66fdefa3c..1fa8e02752a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,8 +1,10 @@ # Change Log ## Unreleased -* Upgrade Spock from 1.0 to 1.2 +* Built using Gradle 4.10.2 +* Updated compatibility testing through Gradle 4.10.2 * Added support for the Gradle [Build Cache](https://docs.gradle.org/current/userguide/build_cache.html) (#48); contribution from [dcabasson](https://github.com/dcabasson) +* Upgrade Spock from 1.0 to 1.2 * Update plugin publishing mode to address Gradle 5.0 deprecation warning ## 0.15.1 diff --git a/README.md b/README.md index e6ce953582b..2db68048092 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 11 support requires Gradle 4.8 or higher * Java 9 support requires Gradle 4.2.1 or higher * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Gradle 4.9 - * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.9 +* Currently built against Gradle 4.10.2 + * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.10.2 * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.8.2 diff --git a/build.gradle b/build.gradle index dbf19c5f85a..e938aaf7832 100644 --- a/build.gradle +++ b/build.gradle @@ -182,7 +182,7 @@ if (!org.gradle.api.JavaVersion.current().isJava9Compatible()) { // Gradle 4.2.1 if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 appears to be the first version that supports Java 11, as per https://github.com/gradle/gradle/pull/4759 and testing gradleVersions.addAll("4.2.1", "4.3", "4.3.1", "4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") } -gradleVersions.addAll("4.8", "4.8.1", "4.9") +gradleVersions.addAll("4.8", "4.8.1", "4.9", "4.10", "4.10.1", "4.10.2") // Support for running Gradle on Java 7 is deprecated and will be removed in Gradle 5, as per https://docs.gradle.org/4.2.1/release-notes.html avroVersions.each { def avroVersion -> diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0d4a9516871afd710a9d84d89e31ba77745607bd..29953ea141f55e3b8fc691d31b5ca8816d89fa87 100644 GIT binary patch delta 49463 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

Gauk6VzRKaGELdj)1bl0ug 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 Date: Thu, 25 Oct 2018 15:23:54 -0400 Subject: [PATCH 229/479] travis: Remove oracle JDKs from config This time, oraclejdk10 fails with a "oraclejdk10 is deprecated." message. It's just going to get worse over time and isn't worth the effort to maintain on travis. --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index d5ff94abc1c..006cf443e37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,22 +6,13 @@ install: true matrix: include: -# 7 - jdk: openjdk7 env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security -# 8 - - jdk: oraclejdk8 - jdk: openjdk8 -# 9 - - jdk: oraclejdk9 - jdk: openjdk9 -# 10 - - jdk: oraclejdk10 - jdk: openjdk10 -# 11 - - jdk: oraclejdk11 - jdk: openjdk11 env: From c8a270e16dbc5b9dd07afad5cd1f28f4c0cd0c0e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Nov 2018 09:26:31 -0500 Subject: [PATCH 230/479] version: 0.16.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 1fa8e02752a..a95accf24b4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.16.0 * Built using Gradle 4.10.2 * Updated compatibility testing through Gradle 4.10.2 * Added support for the Gradle [Build Cache](https://docs.gradle.org/current/userguide/build_cache.html) (#48); contribution from [dcabasson](https://github.com/dcabasson) diff --git a/build.gradle b/build.gradle index e938aaf7832..026f782e10a 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.15.2-SNAPSHOT" +version = "0.16.0" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 730cc46395ce92ba6bcf939bf2dcde649e842404 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 13 Nov 2018 09:35:09 -0500 Subject: [PATCH 231/479] version: 0.16.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 026f782e10a..ede05b60410 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.16.0" +version = "0.16.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 8f63bb4260228ae820d40fc8708357f39d72e530 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 14 Nov 2018 13:09:30 -0500 Subject: [PATCH 232/479] Add test to validate examples --- .../plugin/avro/ExamplesFunctionalSpec.groovy | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy new file mode 100644 index 00000000000..4b87b4df482 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy @@ -0,0 +1,54 @@ +/* + * Copyright © 2018 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class ExamplesFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroPlugin() + addAvroDependency() + } + + def "inline example is valid"() { + given: + copyResource("/examples/inline/Cat.avsc", avroDir) + + when: + def result = run() + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + projectFile(buildOutputClassPath("example/Cat.class")).file + projectFile(buildOutputClassPath("example/Breed.class")).file + } + + def "separate example is valid"() { + given: + copyResource("/examples/separate/Breed.avsc", avroDir) + copyResource("/examples/separate/Cat.avsc", avroDir) + + when: + def result = run() + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + projectFile(buildOutputClassPath("example/Cat.class")).file + projectFile(buildOutputClassPath("example/Breed.class")).file + } +} From 529717845b4c2204c81962472ee7fe6b472b3e15 Mon Sep 17 00:00:00 2001 From: Raman Gupta Date: Wed, 27 Mar 2019 23:36:08 -0400 Subject: [PATCH 233/479] Avro 1.9.0-SNAPSHOT, with jsr310 enabled JSR310 is enabled in this initial commit. TODO add configuration to default to the Avro default, but allow enabling JSR310 or JODA explicitly. --- CHANGES.md | 1 + README.md | 9 +++++---- build.gradle | 7 +++++-- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 4 ++-- .../commercehub/gradle/plugin/avro/FunctionalSpec.groovy | 7 ++++++- .../gradle/plugin/avro/OptionsFunctionalSpec.groovy | 4 ++++ 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a95accf24b4..1544ac8cd38 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Built using Avro 1.9.0-SNAPSHOT ## 0.16.0 * Built using Gradle 4.10.2 diff --git a/README.md b/README.md index 2db68048092..c4e656fa362 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,9 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.10.2 * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Other versions may be compatible, but Gradle 1.x versions are unlikely to work -* Currently built against Avro 1.8.2 - * Currently tested against Avro 1.8.2; other versions may be compatible +* Currently built against Avro 1.9.0-SNAPSHOT + * Currently tested against Avro 1.9.0-SNAPSHOT; other versions may be compatible + * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.x, try plugin version 0.8.0; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Versions of Avro prior to 1.7.x are unlikely to work @@ -51,7 +52,7 @@ repositories { jcenter() } dependencies { - compile "org.apache.avro:avro:1.8.2" + compile "org.apache.avro:avro:1.9.0-SNAPSHOT" } ``` @@ -219,7 +220,7 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - compile "org.apache.avro:avro:1.8.2" + compile "org.apache.avro:avro:1.9.0-SNAPSHOT" } task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { diff --git a/build.gradle b/build.gradle index ede05b60410..765c5bca446 100644 --- a/build.gradle +++ b/build.gradle @@ -11,9 +11,12 @@ plugins { repositories { jcenter() + maven { + url 'https://repository.apache.org/content/repositories/snapshots/' + } } -def compileAvroVersion = "1.8.2" +def compileAvroVersion = "1.9.0-SNAPSHOT" dependencies { compile localGroovy() @@ -174,7 +177,7 @@ test { ] } -def avroVersions = ["1.8.2"] +def avroVersions = ["1.9.0-SNAPSHOT"] def gradleVersions = [] if (!org.gradle.api.JavaVersion.current().isJava9Compatible()) { // Gradle 4.2.1 is the first version that supports modern Java 9, as per https://discuss.gradle.org/t/could-not-determine-java-version-from-9-0-1/24457 gradleVersions.addAll("3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2") diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 7ff7cc064de..fb267c9cf77 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -256,11 +256,11 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt } private void compile(Protocol protocol, File sourceFile) throws IOException { - compile(new SpecificCompiler(protocol), sourceFile); + compile(new SpecificCompiler(protocol, SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT), sourceFile); } private void compile(Schema schema, File sourceFile) throws IOException { - compile(new SpecificCompiler(schema), sourceFile); + compile(new SpecificCompiler(schema, SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT), sourceFile); } private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index ba771e5255c..d789219c9a3 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -60,7 +60,12 @@ abstract class FunctionalSpec extends Specification { classpath files($pluginClasspath) } } - repositories { jcenter() } + repositories { + jcenter() + maven { + url 'https://repository.apache.org/content/repositories/snapshots/' + } + } """ } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index cbbb4e67670..a9947bcd0ea 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -17,6 +17,7 @@ package com.commercehub.gradle.plugin.avro import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility import org.apache.avro.generic.GenericData.StringType +import spock.lang.Ignore import spock.lang.Unroll import java.nio.ByteBuffer @@ -147,6 +148,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { "'false'" | false } + @Ignore("Velocity error, for some reason \$velocityCount is unset in a foreach") def "supports configuring templateDirectory"() { given: def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") @@ -281,6 +283,8 @@ class OptionsFunctionalSpec extends FunctionalSpec { result.output.contains("Invalid default for field name: null not a \"string\"") } + // TODO To be cleaned up post-merge, validateDefaults doesn't make sense in 1.9+ + @Ignore("1.9 compiler validates defaults all the time so the build never succeeds") def "lack of validation of default values should cause the build to succeed for invalid schema file"() { given: copyResource("userWithInvalidDefaults.avsc", avroDir) From 3ae8dedb0b55ead8c181c35b3dda5a3a09059678 Mon Sep 17 00:00:00 2001 From: Raman Gupta Date: Mon, 1 Apr 2019 13:07:44 -0400 Subject: [PATCH 234/479] Support configuration of date/time logical type --- README.md | 16 ++++++ .../gradle/plugin/avro/AvroBasePlugin.java | 12 +++++ .../gradle/plugin/avro/AvroExtension.java | 1 + .../gradle/plugin/avro/Constants.java | 3 ++ .../plugin/avro/DefaultAvroExtension.java | 14 ++++++ .../plugin/avro/GenerateAvroJavaTask.java | 24 ++++++++- .../plugin/avro/OptionsFunctionalSpec.groovy | 50 +++++++++++++++++++ .../gradle/plugin/avro/helloWorld.kt | 3 +- .../commercehub/gradle/plugin/avro/user.avsc | 4 ++ 9 files changed, 124 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c4e656fa362..827eb5c8ce7 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ There are a number of configuration options supported in the `avro` block. | templateDirectory | see below | `templateDir` passed to Avro compiler | | enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | | validateDefaults | `false` | `setValidateDefaults` set on Avro Schema Parser | +| dateTimeLogicalType | see below | `dateTimeLogicalType` passed to Avro compiler | ## createSetters @@ -202,6 +203,21 @@ avro { } ``` +## dateTimeLogicalType + +Valid values: `JSR310`, `JODA` + +By default, generated Java files will use the upstream Avro default date/time types. At time of writing this is JSR310. +See `DateTimeLogicalTypeImplementation.DEFAULT` in the upstream code. + +Example: + +```groovy +avro { + dateTimeLogicalType = 'JSR310' +} +``` + # IntelliJ Integration The plugin attempts to make IntelliJ play more smoothly with generated sources when using Gradle-generated project files. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index c722e8e2257..132bc62b9a5 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -58,6 +58,12 @@ public Boolean call() throws Exception { return DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; } }); + extensionMapping.map(OPTION_DATE_TIME_LOGICAL_TYPE, new Callable() { + @Override + public String call() throws Exception { + return DEFAULT_DATE_TIME_LOGICAL_TYPE; + } + }); project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { @Override public void execute(GenerateAvroJavaTask task) { @@ -104,6 +110,12 @@ public Boolean call() throws Exception { return avroExtension.isValidateDefaults(); } }); + taskMapping.map(OPTION_DATE_TIME_LOGICAL_TYPE, new Callable() { + @Override + public String call() throws Exception { + return avroExtension.getDateTimeLogicalType(); + } + }); } }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index ec69794545a..6e4b8a2c349 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -23,4 +23,5 @@ public interface AvroExtension { boolean isCreateSetters(); boolean isEnableDecimalLogicalType(); boolean isValidateDefaults(); + String getDateTimeLogicalType(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index cc0585716c2..42d4e943248 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -15,6 +15,7 @@ */ package com.commercehub.gradle.plugin.avro; +import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; import org.apache.avro.generic.GenericData.StringType; import org.gradle.api.plugins.JavaPlugin; @@ -33,6 +34,7 @@ class Constants { static final boolean DEFAULT_CREATE_SETTERS = true; static final boolean DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE = true; static final boolean DEFAULT_VALIDATE_DEFAULTS = false; + static final String DEFAULT_DATE_TIME_LOGICAL_TYPE = SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT.name(); static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; @@ -50,6 +52,7 @@ class Constants { static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; static final String OPTION_OUTPUT_CHARACTER_ENCODING = "outputCharacterEncoding"; + static final String OPTION_DATE_TIME_LOGICAL_TYPE = "dateTimeLogicalType"; /** * When our minimum supported version is 3.5+, we can remove this diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index da40f1889eb..028da629390 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -28,6 +28,7 @@ public class DefaultAvroExtension implements AvroExtension { private boolean createSetters; private boolean enableDecimalLogicalType; private boolean validateDefaults; + private String dateTimeLogicalType; @Override public String getOutputCharacterEncoding() { @@ -115,4 +116,17 @@ public void setValidateDefaults(String validateDefaults) { public void setValidateDefaults(boolean validateDefaults) { this.validateDefaults = validateDefaults; } + + @Override + public String getDateTimeLogicalType() { + return dateTimeLogicalType; + } + + public void setDateTimeLogicalType(String dateTimeLogicalType) { + this.dateTimeLogicalType = dateTimeLogicalType; + } + + public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplementation dateTimeLogicalType) { + setDateTimeLogicalType(dateTimeLogicalType.name()); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index fb267c9cf77..9f4a19437d5 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -55,9 +55,11 @@ public class GenerateAvroJavaTask extends OutputDirTask { private boolean createSetters = DEFAULT_CREATE_SETTERS; private boolean enableDecimalLogicalType = DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; private boolean validateDefaults = DEFAULT_VALIDATE_DEFAULTS; + private String dateTimeLogicalType = DEFAULT_DATE_TIME_LOGICAL_TYPE; private transient StringType parsedStringType; private transient FieldVisibility parsedFieldVisibility; + private transient SpecificCompiler.DateTimeLogicalTypeImplementation parsedDateTimeLogicalTypeImplementation; @Optional @Input @@ -136,11 +138,28 @@ public void setValidateDefaults(boolean validateDefaults) { this.validateDefaults = validateDefaults; } + @Optional + @Input + public String getDateTimeLogicalType() { + return dateTimeLogicalType; + } + + public void setDateTimeLogicalType(String dateTimeLogicalType) { + this.dateTimeLogicalType = dateTimeLogicalType; + } + + public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplementation dateTimeLogicalType) { + setDateTimeLogicalType(dateTimeLogicalType.name()); + } + @TaskAction protected void process() { parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); parsedFieldVisibility = Enums.parseCaseInsensitive(OPTION_FIELD_VISIBILITY, FieldVisibility.values(), getFieldVisibility()); + parsedDateTimeLogicalTypeImplementation = + Enums.parseCaseInsensitive(OPTION_DATE_TIME_LOGICAL_TYPE, SpecificCompiler.DateTimeLogicalTypeImplementation.values(), getDateTimeLogicalType()); + getLogger().debug("Using outputCharacterEncoding {}", getOutputCharacterEncoding()); getLogger().debug("Using stringType {}", parsedStringType.name()); getLogger().debug("Using fieldVisibility {}", parsedFieldVisibility.name()); @@ -148,6 +167,7 @@ protected void process() { getLogger().debug("Using createSetters {}", isCreateSetters()); getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType()); getLogger().debug("Using validateDefaults {}", isValidateDefaults()); + getLogger().debug("Using dateTimeLogicalType {}", parsedDateTimeLogicalTypeImplementation.name()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); processFiles(); @@ -256,11 +276,11 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt } private void compile(Protocol protocol, File sourceFile) throws IOException { - compile(new SpecificCompiler(protocol, SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT), sourceFile); + compile(new SpecificCompiler(protocol, parsedDateTimeLogicalTypeImplementation), sourceFile); } private void compile(Schema schema, File sourceFile) throws IOException { - compile(new SpecificCompiler(schema, SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT), sourceFile); + compile(new SpecificCompiler(schema, parsedDateTimeLogicalTypeImplementation), sourceFile); } private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index a9947bcd0ea..9e21eb0137e 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -15,6 +15,7 @@ */ package com.commercehub.gradle.plugin.avro +import org.apache.avro.compiler.specific.SpecificCompiler import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility import org.apache.avro.generic.GenericData.StringType import spock.lang.Ignore @@ -29,6 +30,8 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS * Functional tests for most functions. Encoding tests have been pulled out into {@link EncodingFunctionalSpec}. */ class OptionsFunctionalSpec extends FunctionalSpec { + static def actualDateTimeImplementationDefault = SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT == SpecificCompiler.DateTimeLogicalTypeImplementation.JSR310 ? "java.time.LocalDate" : "org.joda.time.LocalDate" + def "setup"() { applyAvroPlugin() } @@ -58,6 +61,9 @@ class OptionsFunctionalSpec extends FunctionalSpec { and: "enableDecimalLogicalType is enabled" content.contains("public void setSalary(${BigDecimal.name} value)") + + and: "getDateTimeLogicalType is ?" + content.contains("public void setBirthDate(${actualDateTimeImplementationDefault} value)") } @Unroll @@ -300,4 +306,48 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS } + + @Unroll + def "supports configuration of dateTimeLogicalType to #dateTimeLogicalType"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | dateTimeLogicalType = "${dateTimeLogicalType}" + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "the task succeeds" + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + + and: "the specified dateTimeLogicalType is used" + content.contains("public void setBirthDate(${fieldClz} value)") + + where: + dateTimeLogicalType | fieldClz + SpecificCompiler.DateTimeLogicalTypeImplementation.JODA.name() | "org.joda.time.LocalDate" + SpecificCompiler.DateTimeLogicalTypeImplementation.JODA.name().toLowerCase() | "org.joda.time.LocalDate" + SpecificCompiler.DateTimeLogicalTypeImplementation.JSR310.name() | "java.time.LocalDate" + } + + def "rejects unsupported dateTimeLogicalType values"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | dateTimeLogicalType = "badValue" + |} + |""".stripMargin() + + when: + def result = runAndFail("generateAvroJava") + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.output.contains("Invalid dateTimeLogicalType 'badValue'. Value values are: [JODA, JSR310]") + } } diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt b/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt index ed9f0034b99..7557b3de4a2 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt @@ -17,8 +17,9 @@ package demo import example.avro.User +import java.time.LocalDate fun main(args : Array) { - val user = User("David", 24, "blue", null) + val user = User("David", 24, "blue", null, LocalDate.of(2019, 1, 1)) println("Hello, ${user.getName()}") } diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc index cebed396766..5e3f4d01670 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc @@ -8,6 +8,10 @@ { "name": "salary", "type": { "type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2 } + }, + { + "name": "birth_date", + "type": { "type": "int", "logicalType": "date" } } ] } From 3d2666f760b4834bcfdf2d2a96d6a277972d24c7 Mon Sep 17 00:00:00 2001 From: Raman Gupta Date: Mon, 1 Apr 2019 13:44:23 -0400 Subject: [PATCH 235/479] Update custom record.vm to match upstream Avro 1.9 --- .../plugin/avro/OptionsFunctionalSpec.groovy | 1 - .../commercehub/gradle/plugin/avro/record.vm | 651 +++++++++++++++++- 2 files changed, 622 insertions(+), 30 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 9e21eb0137e..cb1beb9c9e0 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -154,7 +154,6 @@ class OptionsFunctionalSpec extends FunctionalSpec { "'false'" | false } - @Ignore("Velocity error, for some reason \$velocityCount is unset in a foreach") def "supports configuring templateDirectory"() { given: def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm b/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm index ff93a4adca7..1d6aeac6b8a 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm @@ -16,9 +16,19 @@ ## limitations under the License. ## #if ($schema.getNamespace()) -package $schema.getNamespace(); +package $schema.getNamespace(); #end -@SuppressWarnings("all") + +import org.apache.avro.generic.GenericArray; +import org.apache.avro.specific.SpecificData; +import org.apache.avro.util.Utf8; +#if (!$schema.isError()) +import org.apache.avro.message.BinaryMessageEncoder; +import org.apache.avro.message.BinaryMessageDecoder; +import org.apache.avro.message.SchemaStore; +#end +#if (${this.gettersReturnOptional} || ${this.createOptionalGetters})import java.util.Optional;#end + #if ($schema.getDoc()) /** $schema.getDoc() */ #end @@ -28,8 +38,73 @@ package $schema.getNamespace(); @org.apache.avro.specific.AvroGenerated public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends org.apache.avro.specific.SpecificExceptionBase#else extends org.apache.avro.specific.SpecificRecordBase#end implements org.apache.avro.specific.SpecificRecord { // Custom template + private static final long serialVersionUID = ${this.fingerprint64($schema)}L; public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse(${this.javaSplit($schema.toString())}); public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; } + + private static SpecificData MODEL$ = new SpecificData(); +#set ($usedConversions = $this.getUsedConversionClasses($schema)) +#if (!$usedConversions.isEmpty()) +static { +#foreach ($conversion in $usedConversions) + MODEL$.addLogicalTypeConversion(new ${conversion}()); +#end + } +#end + +#if (!$schema.isError()) + private static final BinaryMessageEncoder<${this.mangle($schema.getName())}> ENCODER = + new BinaryMessageEncoder<${this.mangle($schema.getName())}>(MODEL$, SCHEMA$); + + private static final BinaryMessageDecoder<${this.mangle($schema.getName())}> DECODER = + new BinaryMessageDecoder<${this.mangle($schema.getName())}>(MODEL$, SCHEMA$); + + /** + * Return the BinaryMessageEncoder instance used by this class. + * @return the message encoder used by this class + */ + public static BinaryMessageEncoder<${this.mangle($schema.getName())}> getEncoder() { + return ENCODER; + } + + /** + * Return the BinaryMessageDecoder instance used by this class. + * @return the message decoder used by this class + */ + public static BinaryMessageDecoder<${this.mangle($schema.getName())}> getDecoder() { + return DECODER; + } + + /** + * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}. + * @param resolver a {@link SchemaStore} used to find schemas by fingerprint + * @return a BinaryMessageDecoder instance for this class backed by the given SchemaStore + */ + public static BinaryMessageDecoder<${this.mangle($schema.getName())}> createDecoder(SchemaStore resolver) { + return new BinaryMessageDecoder<${this.mangle($schema.getName())}>(MODEL$, SCHEMA$, resolver); + } + + /** + * Serializes this ${schema.getName()} to a ByteBuffer. + * @return a buffer holding the serialized data for this instance + * @throws java.io.IOException if this instance could not be serialized + */ + public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException { + return ENCODER.encode(this); + } + + /** + * Deserializes a ${schema.getName()} from a ByteBuffer. + * @param b a byte buffer holding serialized data for an instance of this class + * @return a ${schema.getName()} instance decoded from the given buffer + * @throws java.io.IOException if the given bytes could not be deserialized into an instance of this class + */ + public static ${this.mangle($schema.getName())} fromByteBuffer( + java.nio.ByteBuffer b) throws java.io.IOException { + return DECODER.decode(b); + } +#end + #foreach ($field in $schema.getFields()) #if ($field.doc()) /** $field.doc() */ @@ -66,18 +141,33 @@ public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends or * one should use newBuilder(). */ public ${this.mangle($schema.getName())}() {} +#if ($this.isCreateAllArgsConstructor()) /** * All-args constructor. +#foreach ($field in $schema.getFields()) +#if ($field.doc()) * @param ${this.mangle($field.name())} $field.doc() +#else * @param ${this.mangle($field.name())} The new value for ${field.name()} +#end +#end */ - public ${this.mangle($schema.getName())}(#foreach($field in $schema.getFields())${this.javaType($field.schema())} ${this.mangle($field.name())}#if($velocityCount < $schema.getFields().size()), #end#end) { + public ${this.mangle($schema.getName())}(#foreach($field in $schema.getFields())${this.javaType($field.schema())} ${this.mangle($field.name())}#if($foreach.count < $schema.getFields().size()), #end#end) { #foreach ($field in $schema.getFields()) - this.${this.mangle($field.name())} = ${this.mangle($field.name())}; + ${this.generateSetterCode($field.schema(), ${this.mangle($field.name())}, ${this.mangle($field.name())})} #end } +#else + /** + * This schema contains more than 254 fields which exceeds the maximum number + * of permitted constructor parameters in the JVM. An all-args constructor + * will not be generated. Please use newBuilder() to instantiate + * objects instead. + */ +#end #end #end + public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; } public org.apache.avro.Schema getSchema() { return SCHEMA$; } // Used by DatumWriter. Applications should not call. public java.lang.Object get(int field$) { @@ -90,13 +180,29 @@ public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends or default: throw new org.apache.avro.AvroRuntimeException("Bad index"); } } + +#if ($this.hasLogicalTypeField($schema)) + private static final org.apache.avro.Conversion[] conversions = + new org.apache.avro.Conversion[] { +#foreach ($field in $schema.getFields()) + ${this.conversionInstance($field.schema())}, +#end + null + }; + + @Override + public org.apache.avro.Conversion getConversion(int field) { + return conversions[field]; + } + +#end // Used by DatumReader. Applications should not call. @SuppressWarnings(value="unchecked") public void put(int field$, java.lang.Object value$) { switch (field$) { #set ($i = 0) #foreach ($field in $schema.getFields()) - case $i: ${this.mangle($field.name(), $schema.isError())} = (${this.javaType($field.schema())})value$; break; + case $i: ${this.mangle($field.name(), $schema.isError())} = #if(${this.javaType($field.schema())} != "java.lang.Object")(${this.javaType($field.schema())})#{end}value$; break; #set ($i = $i + 1) #end default: throw new org.apache.avro.AvroRuntimeException("Bad index"); @@ -104,39 +210,85 @@ public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends or } #foreach ($field in $schema.getFields()) +#if (${this.gettersReturnOptional}) + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. +#if ($field.doc()) * $field.doc() +#end + * @return The value wrapped in an Optional<${this.javaType($field.schema())}>. + */ + public Optional<${this.javaType($field.schema())}> ${this.generateGetMethod($schema, $field)}() { + return Optional.<${this.javaType($field.schema())}>ofNullable(${this.mangle($field.name(), $schema.isError())}); + } +#else /** * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field. -#if ($field.doc()) * $field.doc()#end +#if ($field.doc()) * @return $field.doc() +#else * @return The value of the '${this.mangle($field.name(), $schema.isError())}' field. +#end */ - public ${this.javaType($field.schema())} ${this.generateGetMethod($schema, $field)}() { + public ${this.javaUnbox($field.schema())} ${this.generateGetMethod($schema, $field)}() { return ${this.mangle($field.name(), $schema.isError())}; } +#end + +#if (${this.createOptionalGetters}) + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. +#if ($field.doc()) * $field.doc() +#end + * @return The value wrapped in an Optional<${this.javaType($field.schema())}>. + */ + public Optional<${this.javaType($field.schema())}> ${this.generateGetOptionalMethod($schema, $field)}() { + return Optional.<${this.javaType($field.schema())}>ofNullable(${this.mangle($field.name(), $schema.isError())}); + } +#end #if ($this.createSetters) /** * Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field. -#if ($field.doc()) * $field.doc()#end +#if ($field.doc()) * $field.doc() +#end * @param value the value to set. */ - public void ${this.generateSetMethod($schema, $field)}(${this.javaType($field.schema())} value) { - this.${this.mangle($field.name(), $schema.isError())} = value; + public void ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema())} value) { + ${this.generateSetterCode($field.schema(), ${this.mangle($field.name(), $schema.isError())}, "value")} } #end #end - /** Creates a new ${this.mangle($schema.getName())} RecordBuilder */ + /** + * Creates a new ${this.mangle($schema.getName())} RecordBuilder. + * @return A new ${this.mangle($schema.getName())} RecordBuilder + */ public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder() { return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(); } - /** Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing Builder */ + /** + * Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing Builder. + * @param other The existing builder to copy. + * @return A new ${this.mangle($schema.getName())} RecordBuilder + */ public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder other) { - return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other); + if (other == null) { + return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(); + } else { + return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other); + } } - /** Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing $this.mangle($schema.getName()) instance */ + /** + * Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing $this.mangle($schema.getName()) instance. + * @param other The existing instance to copy. + * @return A new ${this.mangle($schema.getName())} RecordBuilder + */ public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())} other) { - return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other); + if (other == null) { + return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(); + } else { + return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other); + } } /** @@ -147,34 +299,54 @@ public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends or implements#if ($schema.isError()) org.apache.avro.data.ErrorBuilder<${this.mangle($schema.getName())}>#else org.apache.avro.data.RecordBuilder<${this.mangle($schema.getName())}>#end { #foreach ($field in $schema.getFields()) +#if ($field.doc()) + /** $field.doc() */ +#end private ${this.javaUnbox($field.schema())} ${this.mangle($field.name(), $schema.isError())}; +#if (${this.hasBuilder($field.schema())}) + private ${this.javaUnbox($field.schema())}.Builder ${this.mangle($field.name(), $schema.isError())}Builder; +#end #end /** Creates a new Builder */ private Builder() { - super(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.SCHEMA$); + super(SCHEMA$); } - /** Creates a Builder by copying an existing Builder */ + /** + * Creates a Builder by copying an existing Builder. + * @param other The existing Builder to copy. + */ private Builder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder other) { super(other); #foreach ($field in $schema.getFields()) if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) { this.${this.mangle($field.name(), $schema.isError())} = data().deepCopy(fields()[$field.pos()].schema(), other.${this.mangle($field.name(), $schema.isError())}); - fieldSetFlags()[$field.pos()] = true; + fieldSetFlags()[$field.pos()] = other.fieldSetFlags()[$field.pos()]; } +#if (${this.hasBuilder($field.schema())}) + if (other.${this.generateHasBuilderMethod($schema, $field)}()) { + this.${this.mangle($field.name(), $schema.isError())}Builder = ${this.javaType($field.schema())}.newBuilder(other.${this.generateGetBuilderMethod($schema, $field)}()); + } +#end #end } - /** Creates a Builder by copying an existing $this.mangle($schema.getName()) instance */ + /** + * Creates a Builder by copying an existing $this.mangle($schema.getName()) instance + * @param other The existing instance to copy. + */ private Builder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())} other) { - #if ($schema.isError())super(other)#else - super(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.SCHEMA$)#end; +#if ($schema.isError()) super(other)#else + super(SCHEMA$)#end; #foreach ($field in $schema.getFields()) if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) { this.${this.mangle($field.name(), $schema.isError())} = data().deepCopy(fields()[$field.pos()].schema(), other.${this.mangle($field.name(), $schema.isError())}); fieldSetFlags()[$field.pos()] = true; } +#if (${this.hasBuilder($field.schema())}) + this.${this.mangle($field.name(), $schema.isError())}Builder = null; +#end #end } #if ($schema.isError()) @@ -205,28 +377,109 @@ public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends or #end #foreach ($field in $schema.getFields()) - /** Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field */ - public ${this.javaType($field.schema())} ${this.generateGetMethod($schema, $field)}() { + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * $field.doc() +#end + * @return The value. + */ + public ${this.javaUnbox($field.schema())} ${this.generateGetMethod($schema, $field)}() { return ${this.mangle($field.name(), $schema.isError())}; } - /** Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field */ +#if (${this.createOptionalGetters}) + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. +#if ($field.doc()) * $field.doc() +#end + * @return The Optional<value>. + */ + public Optional<${this.javaType($field.schema())}> ${this.generateGetOptionalMethod($schema, $field)}() { + return Optional.<${this.javaType($field.schema())}>ofNullable(${this.mangle($field.name(), $schema.isError())}); + } +#end + + /** + * Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * $field.doc() +#end + * @param value The value of '${this.mangle($field.name(), $schema.isError())}'. + * @return This builder. + */ public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema())} value) { validate(fields()[$field.pos()], value); - this.${this.mangle($field.name(), $schema.isError())} = value; +#if (${this.hasBuilder($field.schema())}) + this.${this.mangle($field.name(), $schema.isError())}Builder = null; +#end + ${this.generateSetterCode($field.schema(), ${this.mangle($field.name(), $schema.isError())}, "value")} fieldSetFlags()[$field.pos()] = true; return this; } - /** Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has been set */ + /** + * Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has been set. +#if ($field.doc()) * $field.doc() +#end + * @return True if the '${this.mangle($field.name(), $schema.isError())}' field has been set, false otherwise. + */ public boolean ${this.generateHasMethod($schema, $field)}() { return fieldSetFlags()[$field.pos()]; } - /** Clears the value of the '${this.mangle($field.name(), $schema.isError())}' field */ +#if (${this.hasBuilder($field.schema())}) + /** + * Gets the Builder instance for the '${this.mangle($field.name(), $schema.isError())}' field and creates one if it doesn't exist yet. +#if ($field.doc()) * $field.doc() +#end + * @return This builder. + */ + public ${this.javaType($field.schema())}.Builder ${this.generateGetBuilderMethod($schema, $field)}() { + if (${this.mangle($field.name(), $schema.isError())}Builder == null) { + if (${this.generateHasMethod($schema, $field)}()) { + ${this.generateSetBuilderMethod($schema, $field)}(${this.javaType($field.schema())}.newBuilder(${this.mangle($field.name(), $schema.isError())})); + } else { + ${this.generateSetBuilderMethod($schema, $field)}(${this.javaType($field.schema())}.newBuilder()); + } + } + return ${this.mangle($field.name(), $schema.isError())}Builder; + } + + /** + * Sets the Builder instance for the '${this.mangle($field.name(), $schema.isError())}' field +#if ($field.doc()) * $field.doc() +#end + * @param value The builder instance that must be set. + * @return This builder. + */ + public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateSetBuilderMethod($schema, $field)}(${this.javaUnbox($field.schema())}.Builder value) { + ${this.generateClearMethod($schema, $field)}(); + ${this.mangle($field.name(), $schema.isError())}Builder = value; + return this; + } + + /** + * Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has an active Builder instance +#if ($field.doc()) * $field.doc() +#end + * @return True if the '${this.mangle($field.name(), $schema.isError())}' field has an active Builder instance + */ + public boolean ${this.generateHasBuilderMethod($schema, $field)}() { + return ${this.mangle($field.name(), $schema.isError())}Builder != null; + } +#end + + /** + * Clears the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * $field.doc() +#end + * @return This builder. + */ public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateClearMethod($schema, $field)}() { #if (${this.isUnboxedJavaTypeNullable($field.schema())}) ${this.mangle($field.name(), $schema.isError())} = null; +#end +#if (${this.hasBuilder($field.schema())}) + ${this.mangle($field.name(), $schema.isError())}Builder = null; #end fieldSetFlags()[$field.pos()] = false; return this; @@ -234,16 +487,356 @@ public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends or #end @Override + @SuppressWarnings("unchecked") public ${this.mangle($schema.getName())} build() { try { ${this.mangle($schema.getName())} record = new ${this.mangle($schema.getName())}(#if ($schema.isError())getValue(), getCause()#end); #foreach ($field in $schema.getFields()) - record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : (${this.javaType($field.schema())}) defaultValue(fields()[$field.pos()]); +#if (${this.hasBuilder($field.schema())}) + if (${this.mangle($field.name(), $schema.isError())}Builder != null) { + try { + record.${this.mangle($field.name(), $schema.isError())} = this.${this.mangle($field.name(), $schema.isError())}Builder.build(); + } catch (org.apache.avro.AvroMissingFieldException e) { + e.addParentField(record.getSchema().getField("${this.mangle($field.name(), $schema.isError())}")); + throw e; + } + } else { + record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : #if(${this.javaType($field.schema())} != "java.lang.Object")(${this.javaType($field.schema())})#{end} defaultValue(fields()[$field.pos()]); + } +#else + record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : #if(${this.javaType($field.schema())} != "java.lang.Object")(${this.javaType($field.schema())})#{end} defaultValue(fields()[$field.pos()]); +#end #end return record; - } catch (Exception e) { + } catch (org.apache.avro.AvroMissingFieldException e) { + throw e; + } catch (java.lang.Exception e) { throw new org.apache.avro.AvroRuntimeException(e); } } } + + @SuppressWarnings("unchecked") + private static final org.apache.avro.io.DatumWriter<${this.mangle($schema.getName())}> + WRITER$ = (org.apache.avro.io.DatumWriter<${this.mangle($schema.getName())}>)MODEL$.createDatumWriter(SCHEMA$); + + @Override public void writeExternal(java.io.ObjectOutput out) + throws java.io.IOException { + WRITER$.write(this, SpecificData.getEncoder(out)); + } + + @SuppressWarnings("unchecked") + private static final org.apache.avro.io.DatumReader<${this.mangle($schema.getName())}> + READER$ = (org.apache.avro.io.DatumReader<${this.mangle($schema.getName())}>)MODEL$.createDatumReader(SCHEMA$); + + @Override public void readExternal(java.io.ObjectInput in) + throws java.io.IOException { + READER$.read(this, SpecificData.getDecoder(in)); + } + +#if ($this.isCustomCodable($schema)) + @Override protected boolean hasCustomCoders() { return true; } + + @Override protected void customEncode(org.apache.avro.io.Encoder out) + throws java.io.IOException + { +#set ($nv = 0)## Counter to ensure unique var-names +#set ($maxnv = 0)## Holds high-water mark during recursion +#foreach ($field in $schema.getFields()) +#set ($n = $this.mangle($field.name(), $schema.isError())) +#set ($s = $field.schema()) +#encodeVar(0 "this.${n}" $s) + +#set ($nv = $maxnv) +#end + } + + @Override protected void customDecode(org.apache.avro.io.ResolvingDecoder in) + throws java.io.IOException + { + org.apache.avro.Schema.Field[] fieldOrder = in.readFieldOrderIfDiff(); + if (fieldOrder == null) { +## Common case: order of fields hasn't changed, so read them in a +## fixed order according to reader's schema +#set ($nv = 0)## Counter to ensure unique var-names +#set ($maxnv = 0)## Holds high-water mark during recursion +#foreach ($field in $schema.getFields()) +#set ($n = $this.mangle($field.name(), $schema.isError())) +#set ($s = $field.schema()) +#set ($rs = "SCHEMA$.getField(""${n}"").schema()") +#decodeVar(2 "this.${n}" $s $rs) + +#set ($nv = $maxnv) +#end + } else { + for (int i = 0; i < $schema.getFields().size(); i++) { + switch (fieldOrder[i].pos()) { +#set ($fieldno = 0) +#set ($nv = 0)## Counter to ensure unique var-names +#set ($maxnv = 0)## Holds high-water mark during recursion +#foreach ($field in $schema.getFields()) + case $fieldno: +#set ($n = $this.mangle($field.name(), $schema.isError())) +#set ($s = $field.schema()) +#set ($rs = "SCHEMA$.getField(""${n}"").schema()") +#decodeVar(6 "this.${n}" $s $rs) + break; + +#set ($nv = $maxnv) +#set ($fieldno = $fieldno + 1) +#end + default: + throw new java.io.IOException("Corrupt ResolvingDecoder."); + } + } + } + } +#end } + +#macro( encodeVar $indent $var $s ) +#set ($I = $this.indent($indent)) +##### Compound types (array, map, and union) require calls +##### that will recurse back into this encodeVar macro: +#if ($s.Type.Name.equals("array")) +#encodeArray($indent $var $s) +#elseif ($s.Type.Name.equals("map")) +#encodeMap($indent $var $s) +#elseif ($s.Type.Name.equals("union")) +#encodeUnion($indent $var $s) +##### Use the generated "encode" method as fast way to write +##### (specific) record types: +#elseif ($s.Type.Name.equals("record")) +$I ${var}.customEncode(out); +##### For rest of cases, generate calls out.writeXYZ: +#elseif ($s.Type.Name.equals("null")) +$I out.writeNull(); +#elseif ($s.Type.Name.equals("boolean")) +$I out.writeBoolean(${var}); +#elseif ($s.Type.Name.equals("int")) +$I out.writeInt(${var}); +#elseif ($s.Type.Name.equals("long")) +$I out.writeLong(${var}); +#elseif ($s.Type.Name.equals("float")) +$I out.writeFloat(${var}); +#elseif ($s.Type.Name.equals("double")) +$I out.writeDouble(${var}); +#elseif ($s.Type.Name.equals("string")) +#if ($this.isStringable($s)) +$I out.writeString(${var}.toString()); +#else +$I out.writeString(${var}); +#end +#elseif ($s.Type.Name.equals("bytes")) +$I out.writeBytes(${var}); +#elseif ($s.Type.Name.equals("fixed")) +$I out.writeFixed(${var}.bytes(), 0, ${s.FixedSize}); +#elseif ($s.Type.Name.equals("enum")) +$I out.writeEnum(${var}.ordinal()); +#else +## TODO -- singal a code-gen-time error +#end +#end + +#macro( encodeArray $indent $var $s ) +#set ($I = $this.indent($indent)) +#set ($et = $this.javaType($s.ElementType)) +$I long size${nv} = ${var}.size(); +$I out.writeArrayStart(); +$I out.setItemCount(size${nv}); +$I long actualSize${nv} = 0; +$I for ($et e${nv}: ${var}) { +$I actualSize${nv}++; +$I out.startItem(); +#set ($var = "e${nv}") +#set ($nv = $nv + 1) +#set ($maxnv = $nv) +#set ($indent = $indent + 2) +#encodeVar($indent $var $s.ElementType) +#set ($nv = $nv - 1) +#set ($indent = $indent - 2) +#set ($I = $this.indent($indent)) +$I } +$I out.writeArrayEnd(); +$I if (actualSize${nv} != size${nv}) +$I throw new java.util.ConcurrentModificationException("Array-size written was " + size${nv} + ", but element count was " + actualSize${nv} + "."); +#end + +#macro( encodeMap $indent $var $s ) +#set ($I = $this.indent($indent)) +#set ($kt = $this.getStringType($s)) +#set ($vt = $this.javaType($s.ValueType)) +$I long size${nv} = ${var}.size(); +$I out.writeMapStart(); +$I out.setItemCount(size${nv}); +$I long actualSize${nv} = 0; +$I for (java.util.Map.Entry<$kt, $vt> e${nv}: ${var}.entrySet()) { +$I actualSize${nv}++; +$I out.startItem(); +#if ($this.isStringable($s)) +$I out.writeString(e${nv}.getKey().toString()); +#else +$I out.writeString(e${nv}.getKey()); +#end +$I $vt v${nv} = e${nv}.getValue(); +#set ($var = "v${nv}") +#set ($nv = $nv + 1) +#set ($maxnv = $nv) +#set ($indent = $indent + 2) +#encodeVar($indent $var $s.ValueType) +#set ($nv = $nv - 1) +#set ($indent = $indent - 2) +#set ($I = $this.indent($indent)) +$I } +$I out.writeMapEnd(); +$I if (actualSize${nv} != size${nv}) + throw new java.util.ConcurrentModificationException("Map-size written was " + size${nv} + ", but element count was " + actualSize${nv} + "."); +#end + +#macro( encodeUnion $indent $var $s ) +#set ($I = $this.indent($indent)) +#set ($et = $this.javaType($s.Types.get($this.getNonNullIndex($s)))) +$I if (${var} == null) { +$I out.writeIndex(#if($this.getNonNullIndex($s)==0)1#{else}0#end); +$I out.writeNull(); +$I } else { +$I out.writeIndex(${this.getNonNullIndex($s)}); +#set ($indent = $indent + 2) +#encodeVar($indent $var $s.Types.get($this.getNonNullIndex($s))) +#set ($indent = $indent - 2) +#set ($I = $this.indent($indent)) +$I } +#end + + +#macro( decodeVar $indent $var $s $rs ) +#set ($I = $this.indent($indent)) +##### Compound types (array, map, and union) require calls +##### that will recurse back into this decodeVar macro: +#if ($s.Type.Name.equals("array")) +#decodeArray($indent $var $s $rs) +#elseif ($s.Type.Name.equals("map")) +#decodeMap($indent $var $s $rs) +#elseif ($s.Type.Name.equals("union")) +#decodeUnion($indent $var $s $rs) +##### Use the generated "decode" method as fast way to write +##### (specific) record types: +#elseif ($s.Type.Name.equals("record")) +$I if (${var} == null) { +$I ${var} = new ${this.javaType($s)}(); +$I } +$I ${var}.customDecode(in); +##### For rest of cases, generate calls in.readXYZ: +#elseif ($s.Type.Name.equals("null")) +$I in.readNull(); +#elseif ($s.Type.Name.equals("boolean")) +$I $var = in.readBoolean(); +#elseif ($s.Type.Name.equals("int")) +$I $var = in.readInt(); +#elseif ($s.Type.Name.equals("long")) +$I $var = in.readLong(); +#elseif ($s.Type.Name.equals("float")) +$I $var = in.readFloat(); +#elseif ($s.Type.Name.equals("double")) +$I $var = in.readDouble(); +#elseif ($s.Type.Name.equals("string")) +#decodeString( "$I" $var $s ) +#elseif ($s.Type.Name.equals("bytes")) +$I $var = in.readBytes(${var}); +#elseif ($s.Type.Name.equals("fixed")) +$I if (${var} == null) { +$I ${var} = new ${this.javaType($s)}(); +$I } +$I in.readFixed(${var}.bytes(), 0, ${s.FixedSize}); +#elseif ($s.Type.Name.equals("enum")) +$I $var = ${this.javaType($s)}.values()[in.readEnum()]; +#else +## TODO -- singal a code-gen-time error +#end +#end + +#macro( decodeString $II $var $s ) +#set ($st = ${this.getStringType($s)}) +#if ($this.isStringable($s)) +$II ${var} = new ${st}(in.readString()); +#elseif ($st.equals("java.lang.String")) +$II $var = in.readString(); +#elseif ($st.equals("org.apache.avro.util.Utf8")) +$II $var = in.readString(${var}); +#else +$II $var = in.readString(${var} instanceof Utf8 ? (Utf8)${var} : null); +#end +#end + +#macro( decodeArray $indent $var $s $rs ) +#set ($I = $this.indent($indent)) +#set ($t = $this.javaType($s)) +#set ($et = $this.javaType($s.ElementType)) +#set ($gat = "SpecificData.Array<${et}>") +$I long size${nv} = in.readArrayStart(); +## Need fresh variable name due to limitation of macro system +$I $t a${nv} = ${var}; +$I if (a${nv} == null) { +$I a${nv} = new ${gat}((int)size${nv}, ${rs}); +$I $var = a${nv}; +$I } else a${nv}.clear(); +$I $gat ga${nv} = (a${nv} instanceof SpecificData.Array ? (${gat})a${nv} : null); +$I for ( ; 0 < size${nv}; size${nv} = in.arrayNext()) { +$I for ( ; size${nv} != 0; size${nv}--) { +$I $et e${nv} = (ga${nv} != null ? ga${nv}.peek() : null); +#set ($var = "e${nv}") +#set ($nv = $nv + 1) +#set ($maxnv = $nv) +#set ($indent = $indent + 4) +#decodeVar($indent $var $s.ElementType "${rs}.getElementType()") +#set ($nv = $nv - 1) +#set ($indent = $indent - 4) +#set ($I = $this.indent($indent)) +$I a${nv}.add(e${nv}); +$I } +$I } +#end + +#macro( decodeMap $indent $var $s $rs ) +#set ($I = $this.indent($indent)) +#set ($t = $this.javaType($s)) +#set ($kt = $this.getStringType($s)) +#set ($vt = $this.javaType($s.ValueType)) +$I long size${nv} = in.readMapStart(); +$I $t m${nv} = ${var}; // Need fresh name due to limitation of macro system +$I if (m${nv} == null) { +$I m${nv} = new java.util.HashMap<${kt},${vt}>((int)size${nv}); +$I $var = m${nv}; +$I } else m${nv}.clear(); +$I for ( ; 0 < size${nv}; size${nv} = in.mapNext()) { +$I for ( ; size${nv} != 0; size${nv}--) { +$I $kt k${nv} = null; +#decodeString( "$I " "k${nv}" $s ) +$I $vt v${nv} = null; +#set ($var = "v${nv}") +#set ($nv = $nv + 1) +#set ($maxnv = $nv) +#set ($indent = $indent + 4) +#decodeVar($indent $var $s.ValueType "${rs}.getValueType()") +#set ($nv = $nv - 1) +#set ($indent = $indent - 4) +#set ($I = $this.indent($indent)) +$I m${nv}.put(k${nv}, v${nv}); +$I } +$I } +#end + +#macro( decodeUnion $indent $var $s $rs ) +#set ($I = $this.indent($indent)) +#set ($et = $this.javaType($s.Types.get($this.getNonNullIndex($s)))) +#set ($si = $this.getNonNullIndex($s)) +$I if (in.readIndex() != ${si}) { +$I in.readNull(); +$I ${var} = null; +$I } else { +#set ($indent = $indent + 2) +#decodeVar($indent $var $s.Types.get($si) "${rs}.getTypes().get(${si})") +#set ($indent = $indent - 2) +#set ($I = $this.indent($indent)) +$I } +#end From 362a6f952a9ba455822e9613e0bf3441e0187c51 Mon Sep 17 00:00:00 2001 From: Raman Gupta Date: Mon, 1 Apr 2019 19:13:13 -0400 Subject: [PATCH 236/479] Remove validateDefaults option The validateDefaults option in Avro 1.9 no longer affects compiler behavior, only the parser. Therefore this option is no longer relevant. --- README.md | 17 ------ .../gradle/plugin/avro/AvroBasePlugin.java | 6 -- .../gradle/plugin/avro/AvroExtension.java | 1 - .../gradle/plugin/avro/Constants.java | 2 - .../plugin/avro/DefaultAvroExtension.java | 14 ----- .../plugin/avro/GenerateAvroJavaTask.java | 12 ---- .../plugin/avro/OptionsFunctionalSpec.groovy | 61 ------------------- .../plugin/avro/userWithInvalidDefaults.avsc | 13 ---- 8 files changed, 126 deletions(-) delete mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/userWithInvalidDefaults.avsc diff --git a/README.md b/README.md index 827eb5c8ce7..410d7d93d8d 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,6 @@ There are a number of configuration options supported in the `avro` block. | stringType | `"String"` | `stringType` passed to Avro compiler | | templateDirectory | see below | `templateDir` passed to Avro compiler | | enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | -| validateDefaults | `false` | `setValidateDefaults` set on Avro Schema Parser | | dateTimeLogicalType | see below | `dateTimeLogicalType` passed to Avro compiler | ## createSetters @@ -187,22 +186,6 @@ avro { } ``` -## validateDefaults - -Valid values: `false` (default), `true`; supports equivalent `String` values - -Set to `true` to force validation of default values in schema files. Each validation error will cause the build to fail. -In order to maintain backward compatibility this option is disabled by default, but in the next big release, this option will -be removed and schema validation will always be enabled. - -Example: - -```groovy -avro { - validateDefaults = true -} -``` - ## dateTimeLogicalType Valid values: `JSR310`, `JODA` diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 132bc62b9a5..e8d9c005daf 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -104,12 +104,6 @@ public Boolean call() throws Exception { return avroExtension.isEnableDecimalLogicalType(); } }); - taskMapping.map(OPTION_ENABLE_VALIDATE_DEFAULTS, new Callable() { - @Override - public Boolean call() throws Exception { - return avroExtension.isValidateDefaults(); - } - }); taskMapping.map(OPTION_DATE_TIME_LOGICAL_TYPE, new Callable() { @Override public String call() throws Exception { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 6e4b8a2c349..bb235a7bf54 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -22,6 +22,5 @@ public interface AvroExtension { String getTemplateDirectory(); boolean isCreateSetters(); boolean isEnableDecimalLogicalType(); - boolean isValidateDefaults(); String getDateTimeLogicalType(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 42d4e943248..d2d0bd66114 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -33,7 +33,6 @@ class Constants { static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); static final boolean DEFAULT_CREATE_SETTERS = true; static final boolean DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE = true; - static final boolean DEFAULT_VALIDATE_DEFAULTS = false; static final String DEFAULT_DATE_TIME_LOGICAL_TYPE = SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT.name(); static final String SCHEMA_EXTENSION = "avsc"; @@ -45,7 +44,6 @@ class Constants { static final String AVRO_EXTENSION_NAME = "avro"; - static final String OPTION_ENABLE_VALIDATE_DEFAULTS = "validateDefaults"; static final String OPTION_ENABLE_DECIMAL_LOGICAL_TYPE = "enableDecimalLogicalType"; static final String OPTION_CREATE_SETTERS = "createSetters"; static final String OPTION_TEMPLATE_DIRECTORY = "templateDirectory"; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 028da629390..0ac837b3851 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -27,7 +27,6 @@ public class DefaultAvroExtension implements AvroExtension { private String templateDirectory; private boolean createSetters; private boolean enableDecimalLogicalType; - private boolean validateDefaults; private String dateTimeLogicalType; @Override @@ -104,19 +103,6 @@ public void setEnableDecimalLogicalType(boolean enableDecimalLogicalType) { this.enableDecimalLogicalType = enableDecimalLogicalType; } - @Override - public boolean isValidateDefaults() { - return validateDefaults; - } - - public void setValidateDefaults(String validateDefaults) { - setValidateDefaults(Boolean.parseBoolean(validateDefaults)); - } - - public void setValidateDefaults(boolean validateDefaults) { - this.validateDefaults = validateDefaults; - } - @Override public String getDateTimeLogicalType() { return dateTimeLogicalType; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 9f4a19437d5..0dd117e0b2d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -54,7 +54,6 @@ public class GenerateAvroJavaTask extends OutputDirTask { private String templateDirectory; private boolean createSetters = DEFAULT_CREATE_SETTERS; private boolean enableDecimalLogicalType = DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; - private boolean validateDefaults = DEFAULT_VALIDATE_DEFAULTS; private String dateTimeLogicalType = DEFAULT_DATE_TIME_LOGICAL_TYPE; private transient StringType parsedStringType; @@ -129,15 +128,6 @@ public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { this.enableDecimalLogicalType = Boolean.parseBoolean(enableDecimalLogicalType); } - @Input - public boolean isValidateDefaults() { - return validateDefaults; - } - - public void setValidateDefaults(boolean validateDefaults) { - this.validateDefaults = validateDefaults; - } - @Optional @Input public String getDateTimeLogicalType() { @@ -166,7 +156,6 @@ protected void process() { getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); getLogger().debug("Using createSetters {}", isCreateSetters()); getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType()); - getLogger().debug("Using validateDefaults {}", isValidateDefaults()); getLogger().debug("Using dateTimeLogicalType {}", parsedDateTimeLogicalTypeImplementation.name()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); @@ -233,7 +222,6 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt try { Schema.Parser parser = new Schema.Parser(); parser.addTypes(parserTypes); - parser.setValidateDefaults(isValidateDefaults()); compile(parser.parse(sourceFile), sourceFile); Map typesDefinedInFile = asymmetricDifference(parser.getTypes(), parserTypes); diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index cb1beb9c9e0..fb75cbd4bd5 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -245,67 +245,6 @@ class OptionsFunctionalSpec extends FunctionalSpec { "'false'" | ByteBuffer } - @Unroll - def "supports configuring validateDefaults to #validateDefaults"() { - given: - copyResource("user.avsc", avroDir) - buildFile << """ - |avro { - | validateDefaults = $validateDefaults - |} - |""".stripMargin() - - when: - def result = run("generateAvroJava") - - then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - - where: - validateDefaults | fieldClz - "Boolean.TRUE" | BigDecimal - "Boolean.FALSE" | ByteBuffer - "true" | BigDecimal - "false" | ByteBuffer - "'true'" | BigDecimal - "'false'" | ByteBuffer - } - - def "validation of default values should cause the build to fail for invalid schema file"() { - given: - copyResource("userWithInvalidDefaults.avsc", avroDir) - buildFile << """ - |avro { - | validateDefaults = true - |} - |""".stripMargin() - - when: - def result = runAndFail("generateAvroJava") - - then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED - result.output.contains("Invalid default for field name: null not a \"string\"") - } - - // TODO To be cleaned up post-merge, validateDefaults doesn't make sense in 1.9+ - @Ignore("1.9 compiler validates defaults all the time so the build never succeeds") - def "lack of validation of default values should cause the build to succeed for invalid schema file"() { - given: - copyResource("userWithInvalidDefaults.avsc", avroDir) - buildFile << """ - |avro { - | validateDefaults = false - |} - |""".stripMargin() - - when: - def result = run("generateAvroJava") - - then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - } - @Unroll def "supports configuration of dateTimeLogicalType to #dateTimeLogicalType"() { given: diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/userWithInvalidDefaults.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/userWithInvalidDefaults.avsc deleted file mode 100644 index efc9ca78b4d..00000000000 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/userWithInvalidDefaults.avsc +++ /dev/null @@ -1,13 +0,0 @@ -{"namespace": "example.avro", - "type": "record", - "name": "User", - "fields": [ - {"name": "name", "type": "string", "default": null}, - {"name": "favorite_number", "type": ["int", "null"]}, - {"name": "favorite_color", "type": ["string", "null"]}, - { - "name": "salary", - "type": { "type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2 } - } - ] -} From 0d63e661c76cbde9c8e5d9a0db2734bbe740ff37 Mon Sep 17 00:00:00 2001 From: Raman Gupta Date: Sat, 27 Apr 2019 22:45:57 -0400 Subject: [PATCH 237/479] Fix code style violations --- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 6 ++++-- .../gradle/plugin/avro/OptionsFunctionalSpec.groovy | 13 ++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 0dd117e0b2d..cea8f94843c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -147,8 +147,10 @@ protected void process() { parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); parsedFieldVisibility = Enums.parseCaseInsensitive(OPTION_FIELD_VISIBILITY, FieldVisibility.values(), getFieldVisibility()); - parsedDateTimeLogicalTypeImplementation = - Enums.parseCaseInsensitive(OPTION_DATE_TIME_LOGICAL_TYPE, SpecificCompiler.DateTimeLogicalTypeImplementation.values(), getDateTimeLogicalType()); + parsedDateTimeLogicalTypeImplementation = Enums.parseCaseInsensitive( + OPTION_DATE_TIME_LOGICAL_TYPE, + SpecificCompiler.DateTimeLogicalTypeImplementation.values(), getDateTimeLogicalType() + ); getLogger().debug("Using outputCharacterEncoding {}", getOutputCharacterEncoding()); getLogger().debug("Using stringType {}", parsedStringType.name()); diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index fb75cbd4bd5..670839ae99c 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -15,14 +15,13 @@ */ package com.commercehub.gradle.plugin.avro -import org.apache.avro.compiler.specific.SpecificCompiler import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility import org.apache.avro.generic.GenericData.StringType -import spock.lang.Ignore import spock.lang.Unroll import java.nio.ByteBuffer +import static org.apache.avro.compiler.specific.SpecificCompiler.DateTimeLogicalTypeImplementation.* import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -30,7 +29,7 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS * Functional tests for most functions. Encoding tests have been pulled out into {@link EncodingFunctionalSpec}. */ class OptionsFunctionalSpec extends FunctionalSpec { - static def actualDateTimeImplementationDefault = SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT == SpecificCompiler.DateTimeLogicalTypeImplementation.JSR310 ? "java.time.LocalDate" : "org.joda.time.LocalDate" + static actualDateTimeImplementationDefault = DEFAULT == JSR310 ? "java.time.LocalDate" : "org.joda.time.LocalDate" def "setup"() { applyAvroPlugin() @@ -266,10 +265,10 @@ class OptionsFunctionalSpec extends FunctionalSpec { content.contains("public void setBirthDate(${fieldClz} value)") where: - dateTimeLogicalType | fieldClz - SpecificCompiler.DateTimeLogicalTypeImplementation.JODA.name() | "org.joda.time.LocalDate" - SpecificCompiler.DateTimeLogicalTypeImplementation.JODA.name().toLowerCase() | "org.joda.time.LocalDate" - SpecificCompiler.DateTimeLogicalTypeImplementation.JSR310.name() | "java.time.LocalDate" + dateTimeLogicalType | fieldClz + JODA.name() | "org.joda.time.LocalDate" + JODA.name().toLowerCase() | "org.joda.time.LocalDate" + JSR310.name() | "java.time.LocalDate" } def "rejects unsupported dateTimeLogicalType values"() { From cb47361e20485cfc704ed748509ac104f92844e5 Mon Sep 17 00:00:00 2001 From: Raman Gupta Date: Sat, 27 Apr 2019 22:46:11 -0400 Subject: [PATCH 238/479] Build against Avro 1.9 release candidate --- CHANGES.md | 2 +- README.md | 8 ++++---- build.gradle | 6 +++--- .../commercehub/gradle/plugin/avro/FunctionalSpec.groovy | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1544ac8cd38..61851274762 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,7 @@ # Change Log ## Unreleased -* Built using Avro 1.9.0-SNAPSHOT +* Built using Avro 1.9.0 ## 0.16.0 * Built using Gradle 4.10.2 diff --git a/README.md b/README.md index 410d7d93d8d..bde96878f84 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.10.2 * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Other versions may be compatible, but Gradle 1.x versions are unlikely to work -* Currently built against Avro 1.9.0-SNAPSHOT - * Currently tested against Avro 1.9.0-SNAPSHOT; other versions may be compatible +* Currently built against Avro 1.9.0 + * Currently tested against Avro 1.9.0; other versions may be compatible * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.x, try plugin version 0.8.0; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) @@ -52,7 +52,7 @@ repositories { jcenter() } dependencies { - compile "org.apache.avro:avro:1.9.0-SNAPSHOT" + compile "org.apache.avro:avro:1.9.0" } ``` @@ -219,7 +219,7 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - compile "org.apache.avro:avro:1.9.0-SNAPSHOT" + compile "org.apache.avro:avro:1.9.0" } task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { diff --git a/build.gradle b/build.gradle index 765c5bca446..f665da6eece 100644 --- a/build.gradle +++ b/build.gradle @@ -12,11 +12,11 @@ plugins { repositories { jcenter() maven { - url 'https://repository.apache.org/content/repositories/snapshots/' + url 'https://repository.apache.org/content/repositories/staging/' } } -def compileAvroVersion = "1.9.0-SNAPSHOT" +def compileAvroVersion = "1.9.0" dependencies { compile localGroovy() @@ -177,7 +177,7 @@ test { ] } -def avroVersions = ["1.9.0-SNAPSHOT"] +def avroVersions = ["1.9.0"] def gradleVersions = [] if (!org.gradle.api.JavaVersion.current().isJava9Compatible()) { // Gradle 4.2.1 is the first version that supports modern Java 9, as per https://discuss.gradle.org/t/could-not-determine-java-version-from-9-0-1/24457 gradleVersions.addAll("3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index d789219c9a3..3014643d822 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -63,7 +63,7 @@ abstract class FunctionalSpec extends Specification { repositories { jcenter() maven { - url 'https://repository.apache.org/content/repositories/snapshots/' + url 'https://repository.apache.org/content/repositories/staging/' } } """ From e69dc041850b740fc9c5fe4f0874379bd6a4f6a1 Mon Sep 17 00:00:00 2001 From: Raman Gupta Date: Fri, 17 May 2019 14:24:50 -0400 Subject: [PATCH 239/479] Use release version of Avro 1.9 --- build.gradle | 3 --- .../com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy | 3 --- 2 files changed, 6 deletions(-) diff --git a/build.gradle b/build.gradle index f665da6eece..254dadcfa04 100644 --- a/build.gradle +++ b/build.gradle @@ -11,9 +11,6 @@ plugins { repositories { jcenter() - maven { - url 'https://repository.apache.org/content/repositories/staging/' - } } def compileAvroVersion = "1.9.0" diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 3014643d822..739ace96890 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -62,9 +62,6 @@ abstract class FunctionalSpec extends Specification { } repositories { jcenter() - maven { - url 'https://repository.apache.org/content/repositories/staging/' - } } """ } From 56fa2fa722d2fcd31079390d5ec03ad4cfc47281 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 17 May 2019 15:44:57 -0400 Subject: [PATCH 240/479] Update readme, changelog, and travis config; remove jdk7 add jdk12/ea Also, note the removal of validateDefaults setting --- .travis.yml | 8 ++++---- CHANGES.md | 3 +++ README.md | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 006cf443e37..51343af2734 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,14 +6,14 @@ install: true matrix: include: - - jdk: openjdk7 - env: GRADLE_OPTS="-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen - before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 - - sudo sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security - jdk: openjdk8 - jdk: openjdk9 - jdk: openjdk10 - jdk: openjdk11 + - jdk: openjdk12 + - jdk: openjdk-ea + allow_failures: + - jdk: openjdk-ea env: global: diff --git a/CHANGES.md b/CHANGES.md index 61851274762..c06be021323 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,9 @@ ## Unreleased * Built using Avro 1.9.0 +* Removed configuration setting `validateDefaults`; defaults are now always validated due to an upstream change +* Java 7 is no longer supported, as Avro 1.9.0 is now Java 8+ +* Began testing using Java 12 ## 0.16.0 * Built using Gradle 4.10.2 diff --git a/README.md b/README.md index bde96878f84..b0265b5101b 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,10 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Java 7-11 +* Currently tested against Java 8-12 * Java 11 support requires Gradle 4.8 or higher * Java 9 support requires Gradle 4.2.1 or higher + * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Gradle 4.10.2 * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.10.2 From 5bf0c52b832c12efcd301873a0daf21a00bf1056 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 22 May 2019 16:38:26 -0400 Subject: [PATCH 241/479] version: 0.17.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index c06be021323..cc22ec13b0d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.17.0 * Built using Avro 1.9.0 * Removed configuration setting `validateDefaults`; defaults are now always validated due to an upstream change * Java 7 is no longer supported, as Avro 1.9.0 is now Java 8+ diff --git a/build.gradle b/build.gradle index 254dadcfa04..2cb31c1268f 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.16.1-SNAPSHOT" +version = "0.17.0" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From 55b4ec176120194fd40c31b877d620533adb49c5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 22 May 2019 16:40:58 -0400 Subject: [PATCH 242/479] version: 0.17.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2cb31c1268f..1663eb23abc 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ tasks.withType(JavaCompile) { } sourceCompatibility = 1.7 -version = "0.17.0" +version = "0.17.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" task sourcesJar(type: Jar, dependsOn: classes) { From b4325d89acb246350eabd8d6386131625256a0c6 Mon Sep 17 00:00:00 2001 From: Jeff Stein Date: Wed, 19 Jun 2019 18:33:38 -0400 Subject: [PATCH 243/479] added a kotlin DSL example - becuase it took me a while to get it working --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index b0265b5101b..71c871b5518 100644 --- a/README.md +++ b/README.md @@ -301,6 +301,29 @@ Special notes relevant to using this plugin via the Gradle Kotlin DSL: * Apply the plugin declaratively using the `plugins {}` block. Otherwise, various features may not work as intended. See [Configuring Plugins in the Gradle Kotlin DSL](https://github.com/gradle/kotlin-dsl/blob/master/doc/getting-started/Configuring-Plugins.md) for more details. * Most configuration in the `avro {}` block can be used identically to the Groovy DSL. Boolean settings are an exception, as they require an "is" prefix. For example, instead of `createSetters = false`, one would use `isCreateSetters = false`. See [Getters and Setters](https://kotlinlang.org/docs/reference/java-interop.html#getters-and-setters) for more details. +### Example Kotlin DSL Setup: + +In `gradle.build.kts` add: + +```kotlin +plugins { + // Find latest release here: https://github.com/commercehub-oss/gradle-avro-plugin/releases + id("com.commercehub.gradle.plugin.avro") version "0.17.0" +} +``` + +And then in your `settings.gradle.kts` add: + +```kotlin +pluginManagement { + repositories { + gradlePluginPortal() + jcenter() + maven (url="https://dl.bintray.com/gradle/gradle-plugins") + } +} +``` + # Generating schema files If desired, you can generate JSON schema files. From 6b6f81ec114d20ff8f0d2b3a0226bf7f21bcbc83 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 21 Aug 2019 13:57:10 -0400 Subject: [PATCH 244/479] Various updates * Use reproducible file order for plugin archives * Built using Gradle 5.1 * Upgrade Spock from 1.2 to 1.3 * Upgrade Checkstyle from 6.1.1 to 8.23 and adjust rules used * Upgrade Codenarc from 1.0 to 1.4 and adjust rules used --- CHANGES.md | 8 ++ README.md | 7 +- build.gradle | 50 ++++++----- config/checkstyle/checkstyle.xml | 81 +++++++++++++----- config/checkstyle/import-control.xml | 4 +- config/codenarc/codenarc.groovy | 3 +- gradle/wrapper/gradle-wrapper.jar | Bin 56177 -> 55190 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- gradlew.bat | 2 +- settings.gradle | 2 - .../gradle/plugin/avro/AvroBasePlugin.java | 17 +++- .../gradle/plugin/avro/AvroPlugin.java | 14 +-- .../plugin/avro/DefaultAvroExtension.java | 3 +- .../gradle/plugin/avro/FileExtensionSpec.java | 3 +- .../plugin/avro/GenerateAvroJavaTask.java | 39 ++++++--- .../plugin/avro/GenerateAvroProtocolTask.java | 15 ++-- .../plugin/avro/GenerateAvroSchemaTask.java | 7 +- .../gradle/plugin/avro/OutputDirTask.java | 3 +- .../gradle/plugin/avro/ProcessingState.java | 12 ++- .../gradle/plugin/avro/TypeState.java | 11 ++- .../gradle/plugin/avro/FunctionalSpec.groovy | 1 + 22 files changed, 183 insertions(+), 103 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index cc22ec13b0d..6eafa412452 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,11 @@ # Change Log ## Unreleased +* Use reproducible file order for plugin archives +* Built using Gradle 5.1 +* Upgrade Spock from 1.2 to 1.3 +* Upgrade Checkstyle from 6.1.1 to 8.23 and adjust rules used +* Upgrade Codenarc from 1.0 to 1.4 and adjust rules used ## 0.17.0 * Built using Avro 1.9.0 @@ -72,6 +77,9 @@ * Built using Gradle 2.13 * Added version cross-compatibility testing +## 0.8.1 +* Compatible at runtime with Gradle 5; no functional changes. Compiled with Gradle 5.6. + ## 0.8.0 * Add support for Java 6 (#21) diff --git a/README.md b/README.md index 71c871b5518..6ec8d01b5d2 100644 --- a/README.md +++ b/README.md @@ -13,15 +13,16 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 9 support requires Gradle 4.2.1 or higher * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Gradle 4.10.2 - * Currently tested against Gradle 3.0-3.5.1 and 4.0-4.10.2 +* Currently built against Gradle 5.1 + * Currently tested against Gradle 3.0-3.5.1, 4.0-4.10.3, and 5.0-5.1 + * Gradle 5.2+ is *mostly* supported; there is an incompatibility with setting `outputDir` that has not yet been addressed. * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.9.0 * Currently tested against Avro 1.9.0; other versions may be compatible * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 - * If you need support for Avro 1.7.x, try plugin version 0.8.0; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) + * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) * Versions of Avro prior to 1.7.x are unlikely to work * Incubating: support for Kotlin * Currently tested against Kotlin 1.2.31 diff --git a/build.gradle b/build.gradle index 1663eb23abc..9df4dd2c95b 100644 --- a/build.gradle +++ b/build.gradle @@ -18,9 +18,7 @@ def compileAvroVersion = "1.9.0" dependencies { compile localGroovy() compile "org.apache.avro:avro-compiler:${compileAvroVersion}" - testCompile("org.spockframework:spock-core:1.2-groovy-2.4") { - exclude module: "groovy-all" - } + testCompile "org.spockframework:spock-core:1.3-groovy-2.5" testCompile gradleTestKit() } @@ -35,6 +33,11 @@ sourceCompatibility = 1.7 version = "0.17.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" +tasks.withType(AbstractArchiveTask) { + preserveFileTimestamps = false + reproducibleFileOrder = true +} + task sourcesJar(type: Jar, dependsOn: classes) { from sourceSets.main.allSource classifier "sources" @@ -137,15 +140,11 @@ dependencies { } checkstyle { - toolVersion = "6.1.1" // Last version of checkstyle to support Java 6 -} -// Nasty workaround for https://issues.gradle.org/browse/GRADLE-2888 -def checkstyleWarningsFile = "build/reports/checkstyle/main.xml" -checkstyleMain.doLast { - File warningsFile = file(checkstyleWarningsFile) - if (warningsFile.exists() && warningsFile.text.contains(" gradleVersions.each { def gradleVersion -> diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 6c5c934b6de..ce9b2420e69 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -1,65 +1,101 @@ + "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" + "https://checkstyle.org/dtds/configuration_1_3.dtd"> + + + - - + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + - - + + - - - - - + + + + + + - + + - - + + + + + - - - - - + + + + + + + + + + + @@ -93,6 +129,7 @@ + diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 29c831a8f2c..8ceb0caed49 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -1,6 +1,6 @@ + "-//Checkstyle//DTD ImportControl Configuration 1.4//EN" + "https://checkstyle.org/dtds/import_control_1_4.dtd"> diff --git a/config/codenarc/codenarc.groovy b/config/codenarc/codenarc.groovy index 69e141ffb8a..3b4ffd2de42 100644 --- a/config/codenarc/codenarc.groovy +++ b/config/codenarc/codenarc.groovy @@ -212,7 +212,8 @@ ruleset { JUnitFailWithoutMessage JUnitLostTest JUnitPublicField - JUnitPublicNonTestMethod + // Triggers incorrectly for Spock methods + // JUnitPublicNonTestMethod JUnitSetUpCallsSuper JUnitStyleAssertions JUnitTearDownCallsSuper diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 29953ea141f55e3b8fc691d31b5ca8816d89fa87..87b738cbd051603d91cc39de6cb000dd98fe6b02 100644 GIT binary patch delta 46897 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 delta 47854 zcmY(KQ*DWo<_WjQ}7Y{XRz3dwMVU4-Q zn%}IHTCm#|FbG8%FmSZ^JoI=RR8%w&kni6?KtO~*dN9W%g#T3<@q%*b#-shs8K>Ad zr`Wenw@%+c{`&~&xBr}5L;ue^5&RoI=KuWw38x$_I|K*_BMb-#ePSFbMxy*Te87D{ z9O*B{gu1cl_hD#GL1RfGHwO0Nq?DkNU&Lg);5Z^>(8W|w>&T-Ht)1=jBnuC$yK|!S;vP}>MV^c_r5GVcLs=nH^?rC-*=KA7NJXV?cuDb zS0XP*_AqA;t}qDGK_~w2gbd*IVL+s@XEB%-ar>e_Id-a96hu9C?RXo?piLW%$X3{o z6thF_ILtq7nlQ%HZieLF;a5y`uYWPL6cf4i#ThY!$5@7#D=@tn--Z8>zpi^Ws~JMrK>!OEzJ*l%TcY-YNr$DuvZ&5SeAQcQ`&2vpVPD^i~w>A3>y#3 zrPkuZ>hzg9iEw`#R+-_3Qs!3{ajlg#qK%nNbTX8(T*x!hvzA@>&khT<#UkpOqnSiz z;kisws8VZ&2jH@6o|>$cp12n3Ug>#?E03JkRqwNcke`G4t`38PU9zR|7?hS{!i;3} zY$eEqVL$O&H70pQ46^-)U;*x#H7N~=l&#8xMtrDfSdx&zk=RUwu;t7hXv^|m9!t5~+VRoN)j*{uEY6gE+W6zvCY z4#_@qY<5c#W_iWMD6M)YpLH%QD~Zvgm&QqmFBty5yi})XlHatyTj=KBRr@Snbo(%05sx7WMs$AydwDW?C

ohmj(wKVBMg2V`Or6Dh zY(8IG;tK2>&RQkxrlW`(B>Zh10(q(zjGgesZVRlxxvdFC?}=}zKetWP^cws&I_m^K z=kOy}3<}o9hR>&$=@#fytQsz@Dq>d%_efe4ipnjrD^+%5~%9N~XNVeysgFbS)>q+Jp7 zq?-oE*R$EC^&lFkzu_w{bLa>6LgbR}ON}`OviJ$pi423;V_PY`;p03WLFt2#5oBNVb$jVhWTr63EG?f;!`v`Nk_# z7CaN^5d%~qEVVhf&LsYUNO%b3D==(`8eslyCd>Ji$Q(235&xhfzYNEyMD{kmX!(`d z05f|(>HA{SF7P)zeC%u})IiRmBqb;5)4el{oY zTu+O8{@nIE)SpfC%fXuV^sIOhTuKR)PrmMX;jboA-}XrnDv>8g4632PZ^_JlXlXmx zY~FCIJEW37oMJpuMXmB1*r9aCf`0<8iTjz&u{LfQJ&n>_aZVn9|H$tDQD}97(xJkC z3cd92A^nfQ0#MM2#gHhV+O&!7kc5Eeq&IKctN!%}YA+5nm`ND)?b^03#dB~<(Csq2 zxK2Eyj3Z{y*tF^TTYp($RV}*(7P9#=bxqc2^Ie-N?Lu*qmR#Cj|DyX}r@K5`L_rw&n9RZgFF$PYewNvt?SlQ!Em8k#kgPbFb|Zp< zfCz$vfUy4eHOT;b6d^P|u%sa~D@V1uWobJby^4m#TFW04;3mexvWeEH3#HVuhEr~# zaDhn%ru&KAtKz7@FM)9ns4^63?XA#u_di_E)9ua{z~8qguwGx@mU!{LkidZ8WVD~_ znnT(!7u0k(&neOHn=Qzp7DfyG_#ualL@*D|A#EC)W|F|7smc$!#X!lReFJ(mppAr3sK4=Dpf}X-92Bq4TEbjrceQCCPt?$$)nGkaX~R@%WR~u9A~;0$ zp3$#eg6<4P{m`Vhbp`bD`s-FvyfWwCmDwok1jXTO^y~lT0K0x>Zk|EJ`Or|hQrp_^$uAzMAf12jMdgcQ9*tQt~1SA$81cdm%d*(a9U}9_J?3}Fy zZHTtw`Pa{?nMFG~NYjxXOA~HYxU>(;))9-0!JjM$LkN8Mi72`#c&Ub$Co(RZlOl;- z0@sU7URZ@kev{iS3$4^BSk8yc$}ywm&sLM1SCO69@3XC@X#68@d&Dbg+$HEdj_a45 z_v`CV1)rl1#!hg0Ac5~=qZ z;^zG&5acfsP?S+ilOdo!l?(0w^>?v%17x#x2h|q^82;kqNIHh+SpyvwohWi3wFN`1V z=-ts@(7V7bKq0<3>AomsUzW}R*I6F)T4Pgc(;^`!@5IS`g8Cfmsab~b<4l=a3qlW$@ zoyBrmcrCM0YZaisq>AZKU1b?^mhnPX%YNMMd~+k2?6Ji5M{!@0xJrhs6?^eelDcaz zeuyorX(F*Z3{f5Tf#b+k*xFc8A{w~&*5K>d7Pb9ixc8jUhD=*P#&-9>`}>nP38D+$ z=`|NwoV<{$1WC@rWt;nCOmUWznS_v<_gA;C_d7wDOAfHAgRtm4PAC%<#mQ?XrqPdY zh3|NkpSHlgw|;OCv$0-`*$NF8<9*2#O5&1TKeJZN#KS+2bGvEj6EyLSfzWx=loc6s zF{UFNc}0q%qd;mVymBB@2EUt<2|1ShGJjj^kawns4=2`(2jc4SK8#Hxp`8Uc2HFQd zoLIU$j~2jj_fj?~#eXjI$OVV9ChSq z&e}R8vTW1lZ%b7M255}OtjTvnT%!$$0w2*Zu#5b{33zUD|iH@Vvja52x9z~b(;%wEAwCQ3TJq^7sO}|VQjH`57 zjRNK(f0#`piFM%Hbu7O4(0Hv7c|L!t)>)^_aZIw)(W9~zMGMcqT)8oGb8gh*O266F zu#X4&_kE;wYb;+yAyS5smR=P#n%!@|zNZcIEf zux^%Vm-DbLh+owhbfy7_CB`i$4=2%%HdeW4HZ{?hD{&Sv_nYBCGQk02BWI)NbQO%A z!h%!y&if)TMU~8fbfOGdTH`aXsAF*b>J$mVi5*))kUm5SlI?*p(j3E{45K=WTmS~e zO_?=8qF4*fqlcwFWljznc+Fiv2+=i_Ld=K?mW<=HMOz*9@*h|(! zeHpj0pW;2_SMx?=1Zy^Xd~KF{s2=MHz74q^$ugO4*$dN(Movt$u*5|UQuUm98S>^y zL!JDld)Pkn{gEEwA&UDPHWMsYbii4{PZ_VnI`S^3AT3L&Tv0eKYpEW*#=|z0OGi&! zJ|s24y^>)*i_y4mGV-HRLVEnIh$mq3NaI>WyhfA*5V$%?x|pWFuI2?MV*R%2<3 zNirku&yOxomx#}l*y?*=60uJqY_dU-jwD%}Cv8SN@>Yq{M2z7#aA-kYqMV^)Mn7S$ zSNi5PZ~eq-6E zz96IXftk@}u4(d-)Rjr-4+6^7ymdy|m*;C7!`G~(q^IY)Sbm8lyjH>XUh)z|INt zD!hN;&wv|2)#psdAyiNd$^UUe0gbg6IP%+dlwbOEoXk^(eM}AKcAh%tatbv2Zi|QB zQY#zPN0gq{q; zXon;-A_cOBbd}pQT`iD>ILm&Vz#Pc~eyyw_0I%|vKo1_}@y*ky#2r0&dQORhDZYG2 z9j#x;l=;uv32cC&<5*-BCo`oMbAk?fV$iJYRHu}0_Ecp91DyFo`lHu(GJN}37TZ!| z*-3N=4in^T{zC2gW<7axS&ht&XY+Hxuhq5uvdqP$Q|OYk)LGzZRAoBJ5BB0@IXC}p zJ~&OgGXM9jumoMMtGSXMW|6w@v-T!KQ9LVG5=(a(xXkd>q1cZ!q-0H{)6rh&9#>gASpE_aKEk5PJ^J=07Vp_)SM$obQ#xK1oRGc{tO# zeZg~lpBw>nr(;F{oO>~A+jQvCniWAXS~OLCNWY04c1N7D`m~-*K*oOzJ9Zjo2`cj8 zts+*m2LAP0V>CeefRyC%zqh62I+uX(`A}zPl~%b&JLK}69LT7PvcsZS6X@3$2|=0r^#XHY zhv9bAeyrAzx4QD$^I1FKV(hsEDaIzR=9#T!aWOGYRCLl+Hf5OoKC#wPRggM5pxaT< zDo3!P_7@Yn=cchQIEDlTV-Bvks7sIrAJ6vx+Qv!`ujoOll?N#>UChQ%Bs zF z$Flfd_E3&g`H%++e@fS7D3rED3}2MVnHXh$K?Z)0D!2|8?{E%$U5c{v`Dd)quF(0o>FD>r{{jaKv9g=S^@dq~B!AjTSTJtsS9-X+%c7?21HLTpye@?YMlwzy*Zt2>S4!LCjP++E%U|0Iw zUYOYpxEr(6J@}`C`VYp0B&)F|oV|3Hro;HAVfe;Wt_#$BZIg<>g)2%O!Dr^#dW6pz z6W-Y1b}KpkYY)h}{Z(El{*h=o);BQQk3-?$`cgk*_bJz4<5oytsLxf!Voq*ZF4a^LHEzH8C>B?$p7e)z z*>cvWLYFd^_aD3Co&?3+cDqD*^wJQ)6A*v2)(nCKhBVo@ye-W7ND1TGTq!-QRrM{C2ta<)TNj3lh4pg z;;4KIlV;|JT8brW+x*;(@eg5Thsl)tXipT#e09bIT4aqbmVBn)9z$3lu<9TM6cVTF zULchD0~O4*e7Iq&d2n$`9ozwh`^p=!PWUrpY7w$YhfSf$%)ZlXPq?-8k+|#^G43>RAY47Y>N$l6uCro)16_PqMJFl-ffv z8u68rfT~tRBdF1?+niX)9f!{jo!Fo(pmGcBD7tUJ>LDTT1Rbw^yc)Ur@wBR%I5&yJ z{(ejFOYkNwp!R@KMKTe3Wuyn$_zl93Mcq2jPOw@I@|8KnlNQ~ERQrjkohq^hE*mB@}Nj=z| z)%s*+r-gxc=nZc*US_)))?h`R6C+PCkOXsnv0&-XC@=)gH$gvh5PXU58ccdL9o^S@ z8*z?+Pu#Glg*tbGN+y)W{@?uL9r~$KaFI0EC4<7zJ!5 z2WYOPrTP`dm}Af-y@Yhn&_bGFP#t z;xDkW#s*{wc=d$1a*KipO^oi*Yyx9h5c&IP_N=Nm{G$Z5wmvvxQkyO4h9_yYTZxEw zVYOS4o{&yeeUZ!we8an7avC9e#&dF$dP=x<2Fn-<#(zxOfHYGq0^#DwF9iSDeG_j+ zu@hIZmj53Mp4zKupc4`VBs{SXn+H(eaK_cZ{=(OqU%%sa+Z?RU*x;7Z84Is&f>1U^ z-EVV@GvTp1O#2NjwK5;xb!)9rrS3RcttbiI3R)b@p42is&;KLa%Azb`*Z&5bg?Hcv z^JW!OKh6K!v%4GlNNZ5J1i$yRd-wbEd-qn)$F(~Ea`Sy#ewR4QsxOeUG6i6?{IPHGe=u&ETdAU$6RDCOwoc@XJM$g(gnq@LseCq-(?+;Gpsb;iEsin z2rB(a1N~CQevmNFu@f~>t=XH3^1|Gm(5rFVjJ0U+9zRg+0co&u0}nrA{Zb-0avGk0 za1!cVC^2)QfQWdKgLaD7WeMmrv$UK|n%;F=aIt)X+KJSt+{%sQvR+l7S>9GBxK#et z6caoIXHVAKnC9w!U`THv8HS=8xkH2=RBqSxQYPX)#Gqc~x8`!{)XqrR4&t(tF`J=J zdn!89I@hHX|I~`qW-hGZNKC(-ETCt(&(UI#VRU|Q>Z?(&l5tvXI06jwiD;9V7MLuG zBqR>Z1(C31gB>-0ir+qlmR8uWr3YM~Rpe0O3$U23w=}Hg>LWjfpG7w8(wf~lt=(Z@ z?SI#6*y_*feTtjQ-|nwE-?e*r{V-c#+ewVfqgwYN6R7A{DzU=RSSohiP68roYfF7J>Yq%>Fu)Nxs_aMh@4-z zF;U9`YFcKJ|5e!C&X7Z`@+_A5xiyag3<)EOzSC|q~rx(0;`*{slG#arQk z$zk=iN|H;KC$MGL0EqvM27BgHn#FmgSE6+kL4yTI{hDyVwn54*?l-1C~S~axb;VH zgOXwl_A5dR&OA^(;qA{}*lHRyTMG@4-L6M6XfB(Z0ZX)1M~xS@Ki7*U(G9koV(OlJ zOc(9<`O^Dt%%b;Wd6GscJj!Ryq~fF#ZCd+BDXLzDRsxSrs*Ulewjs4W+deGJmHB$=^mS&M4zvoX#Pmc>kR*opC&(d@%u|s=`NOmH zV~=ILgWt4`VAm>wSMD4v?}S@)rUen{Z0+y23}72Eh!A10K)0j)k2vg;A?nke4CD`C zCf*2zAOj?SY~;(N{O`}XgQcTlEb%*}A?$*@En%mN-8jaPVG4So!*7wyfCI`Byju>N9e+d1`zcwfWx2_$sbz(^F_9?iM0XIXWb`sB4@eYxDOyqBUty zY(Tu7RLci;V8n89*9#2-gYku`y~T>_W@a?G3EO6BH01#s8Q5@f5BULy1He2SOp{Tw z+1uit^0!R&p@y|9n>{%k$Ia!>q2CS-$J5RrgTF0_Q~)wnk%qrKx5tJc^R0f1t4YqX zj+QS(p7hjhp)!*bdla5&Y=mXtC$j;qlIBa5(6g1UxL20`Txi`vujYsd&b_rQJx zr6o^Hgn=_ANECjAElQj%>f2XeJipAq3rdIhMjRrX3m)aU?>z{ZO7t!G*K17W^DJo} z{;Ut!mQG#A!yl*nL9n+oB5bcw6BR_>{A~}{S7#sb0D=$Hb+4bswY@xHG2IGINl|vJ z8)#)0!gQ8vRMT;OF&q|au?n?{J26r|ISR?p@bOIW3d{m%N(6k5$p637oBcEf?)8rj zg#4oe|C`lJh8-mNJZJ;Q`;m9h5-h@6ggs(cy+; z@IoW})EH6nNFM7EKT9gkt5B)@c@1S)8Ve7cr>oq7ug_c5UN{W2hyC!VQW%OK)WkJJ zK|xVPngWq|P&4GR)M4KhrA_sQVdG25CneL&uyongG29n;f|n-u0jG7UOY>-1BRiV` z!`XSL>_e zz3DvC{0l1L%^Pp>oxYv?EsxTU%cs$;X`~C^dFHr3REPB{>rBgd%QED{w{kpAvO`~s z(c66N_>FR=O0}&NsD+%^qIq84B+YT#8qf}|a!<{CgX_8#^%b31(xA&kEup>092$Uc zL>ZOz7$cg&yb4hwzgX@h!PE@Vq)kuSRhf(ZR#1CUY#k(dg(})li(bn#lBb`Fe!~IY z)2>3ZZ7e^;X9)+!0St{~n5DLjAhj20+#;|BRF$6h(;VLd{zi8(JfaAHBWt`gxkS7|sE_X69?@Kvy# zt|o7RZDHKl)1MFX_|_7#wm;OE9+W6}m+T&fk-AzCP!qy;q#fh9xy{7eNj)K-*nSOC zg#?lWVr&6d2M|@xQM_?np>QkPF4V+EEbv|PVkJhCvH(7)E7)HG zbnl1vYrkxN7{h>i7||L**b1MoLc%q`ucl!o#EJ0R`d6{chtE~juv%p@%$Lahw#cZ7 zYf9eYgg%qa{IgZ!eciPY^>-(m%m#1Q0MNYt<9oev;X8sl!}~z>tJyd*qPk6HNV`*> zp*D453+9iK5=~#RM_>Sl*FUSDahuNFUg=i7b1Jgc`xXJ>T9rx1cxt%gaIZscGxC|L zO+hRg%&#`W&Lj8m)vw)0kbzLuQDB=S(9tt*)X)tER=Qq7ie5`Fca(4JUf=LNUy67?YD^!BFn1E8y03>2(LNN{ zolg3ARH2tG*{b~zX?;Aq|2P6mO5H;mTbV>+ zh+tk=XQNGC7ti8S`jJYu_*!FahYb;|UKSKR3C#vdxL8#+DET9NAZQMPbK1OlC<#*` z2bbGw7~*MYVTkHH+{K&_A3^*(>#Rw%I0|T`h`A3LC(24_As~KZs!K@7vEO&~#2m}d^}nTH1e{uCGQmGZiHrc!M}0)_|w-iEgi%fo9^Lp6!0 z!rOV!hmd~FX*rujS`&F+|W?LW-d7%Vlz2!7MtSeA)hN z&xG%-Eqlr>@`XjKI2aM-uL%L;u4s~)TV=pV^);)ZsgL(b)+5*pKCr^4ZdPaEo7 zVr)HSK!r|`ApFX%HauyY)_`1_(ty(DXo_pS^}-FuM|KYF1H-_`4qj*zm(=93l6g!B zu$v3>w|H;o1<^4EHi;wQ+M9 z>gsy_h;a!z7W-)o6NNAl-V$oKqZhlwU=-B+IiyDyc+B8by&; znQe|FAfruHm!dA7cfOhusnJ`3i0Nk#sRYTe0}%=j;ul5>s$A7j^W`4HR!IECkHn&h zXT@PkD^L3QRo4j3+HiPd(g`KqnlQPH)u;`$Ihu9_}=_|=S4oyMvP zO(PNsCgPL7)2y|+osKzCu%(8r4k`*_^lYO#m1VBV%}bWsV(__4-Fgm-*^M>ZTmJ-1 zZfWp_QJrx~?N(rKGI8mys&3%G08dVmGTK)SMsMe^j#ifuk+C$YDQ2BL4o(g@TW-DVIPCiN>@q3i9z4bUBb0;0D5Bu-}Ud1bist%9Nrv;>q8x=bKyAWtVBc^$hI zuR1X};(x;E&7Sr*+(c~msfLdWRb+5^++sI!23~G19aQm99v`iBby~nz0vf3Ur5GH; zg}<{b_Mr)ED{_^vwjg_dr^nBKtS!tUc%E>w&vQq%e&-P^J@dh=9#z!|sE?GWTIdtT zi_r5jf*V1+qn%FQc=@I|==zrQfsu6`)fJT`yoSxgZ;ySxUn7Yc#as0^E49W2=JCmoaK48zf8MsEIa)AUUkcq?Z0uk{~5@@`ZGTBMA!y1 zI-6;^3^lh)?A|93cgxeuGejQZX0Ab5dsXCxR? zLn+W4%fr!(fk^{u?p;SWxfAR9lC9OtJnf^Q&}RPYdXIhg=gd1e0+4=Of5^$F59Apk zP1IxPeDl~HA$k(owfQ-r+x?k{ny0&t~}PXb|wqf6bVhSCYZG)i%mHZK~`Se?A_MN_|MPf#drRlJ}J zPn0N%BzaO#D&#NEBtlf{_q2MV__b@TYImEXL~5(`taAnriTu5zrrSH$;SM)L{Vr?t z8n?sakB-`A3PU?)r3O=3dbJHrxT5BAZ>_B@;m($a5v>_O0aT6PTnfTI&01+3Fu$4O z!wD-Gk^bzX*o;u$^rzPU~}OOIu7P5s`E(9D|t}c@d>OY9J+;gW%o)AA0*LB#SweP^?#RG&GPd1vq*xW9%DcuL!i8g5-uh z_|4JEN6(JhyCE+6YH@mr_wFr39lxC$D*K;cNB2wUBA;0GtE(MgY+h`hnqLB_b-Dc~ zVAdWF>nf)j4qCl4w$St_AGfulo2jd0jC^5ml~>y?0DaYvk~*t0E6~gtCGpBy`e6EJ zLx1qMnj7ALY7z42&%`z-&>5~&^%7rDjqGN#seF5e(o}>sh(d=eO53>EZ;OV6Di#8X zr`GD%-*g5*98YfCVRJ_G-~*q1I)7!QNLb1P(GPsrJbC%3Z$jzOqt|P7L+@_2NFX32|B3A&GN1tNxEknxbJ*so z?%EtTDa7RFan30kly$T+f;eHNu97mw<*i4Uq`+M0-JECI^w{Imsmqy+DSUW`yZ->^Xy~` zY2CY0+N9OkCf3--9_l!ZcOP*e+$PodV?PAuQETdvo7LTePS^{jb4$!iH5OX<5~j*UU9cnuu z6CDkAH_JSh;&@qTUUPV!ppeIN)z+>$z0{Zz&%JjZ9Pp3(2iEuGB%d5aTZ`Yn4NvKa z%cy|j`!mb5Is@fO%&S}kVIH21tIhg`YAp1DZgUItGIv)$>=ri29Sn?_hF^s&*(=|? z*5v7%e!u7an!h&1ek`_HU=NW|K@IU1%#HIrm7Hk8ThvpTrj3kvPzC{A&$CkrEXIt4 z)Tl8SOs|1|(8>QnQNcI2m9~?{p;l%lkd!R-lc@u|1{%P^_N8Sz#eV2_9Ag-5?xZkr z*x63RE>s-Twv~3Lgy%q7GRGBf;oQxtqnDVu+chdEEhA)u#F;Dflqa^sTX)0 zmQU2szUGdhtTXnLl}E2|JhSC&FzHV0penFiTwqBQ@#+)ke^a|PLpM;mRZD@Bt9?~c zy=C(wHm1qM}$$$I8+hU26}O&vJs{T+NX_(i1LlT2jv~PK)O$)Q7~g6Ec|s z!mN^m9;Mlhjcc>(vq<8ZO+7p*EBB*9Y7cO6-1gXT*i9lssuMbKHdr5wIzsSQ%Z)g? zrL-O^Sbbn?QQKOO{aaIHX>HnY2>M#te4t`cK!C34qL4XOWUp5j4DHQwSqsF(Z@!aXZ=f#n-i-om|q>rzPW zftI=80OJkbLf&4g@^tMFp)5G8lszfpK~k`bwok)m=2|*^)u>HNd^q!_iDIL<+=RAwPMZ5#39LL7Z4dHd| z+oj{(9LE{9i{Y;;67C06*kjVCxX#NzKxYd3B#P@cr$neq@x6DXOR-O0GeBz>e71FB+lrGWBZ=r~ZkcLvD zs#Dt!JySn9J8w!NGMeZ0;!l721y^`>aoT2?y3(`=sKU32;mkUdL(aZ6r)up8i7gs* zyUzG?eW=;3(b=`%GuxI!^&O$v0cw31<%aKHpD_1gbNR&M^Uki14UZ9lRGGT7ETPe; zPSDvtl=l0y7Z{@J8%J`m4x8H8o;z=(wYtDz^+jxF$}1Sj;Mdmbz(VVtjevHZlWw9e z2UvWkCnWt?4t7w2qZy<$GeM3JCwA;4Q35aGBa>50UM_3@eXkc>ob}&l0OxY(D$ZVD zTj8+aK@rP{TCdXsc}`@^*^=61Ol%M#Tf*kY!nox{TSQS*@yTn$zI9oY*@9+QO;n6k z)owssWZ&>oW81N;es&gZqb7f+HBMsWxt7wxLg`>Ka}9p#yv1z+$ik(adNyqE-sVD?g;7r9E>YUNzGiR z2y?B8DJznEHg%7-jDHc2p=4wqO-xX;j=X=2BhELAjyOXiR(~-99PBkB6&OT?G5rlv z@sVBCJo^%qL(1F;n_@-w46>X=3HLO+nUsZbfQ5o+tjQbUyYCnkR?0+^Gw|&e6ya@^XPmI4l==d}*dV{ib@6xb z=?9N{=#Qu$y(EGX~LvWp)YKZPI2i_|ukT68+$6v{a7m{Te}0wXy7qJEC3cAgo)^=+A|d1%`2 z4D6?Uj{u{t8SRH=vBRBaP}bUuSYl%;!p;?d9UzP)Ik`SEqS$Z#h={i#{pk4u{r|n! zd$UJdhJQcon9_oP5dHVKhWbA#TPQ=-BmA!~=L5YMC}E;rCIwSd6m}Fecw$Lba56YB zH6JPcgh1TeKlo(UmCc$}ddq5a+~@s5YN{wdK$rb-H>^{ewJoYUnrk9TdcL0jFr*$L z#l>B}Z*%>5ttf1C_lt>n#hw(FJTgK{y*(jk7Cll@#cymG z2`8LQOH?!3aR^U}>wTh9V^2KwX%0{i??tV~i_&*uCp`U!(Fyd+ZlxMb;!`Ocizjn0 z_f(2%QJgR*0PW_~kXsZ)#^k??w)(?t`ufwfomkb29?7ZZV3^DDi6!b8OQ1&4f-f+V&x|FDo`rPrjMND0rqjESLHh6J++>B~>UX1kndBenv^cbg+oR@oH zK24G=1_zCussl>VCi>dMT}Q=gK2f0u^Y(G(-KiW-KxOC#uTKk-w>*39#148&_sQOU zk$?f!Yxgjw$5;^7+(#av{XT5*YyNO%S5u6JjB~v0NBl6R&4&r2n5lglKmz4Qqx*Mq zLf}N^@E!&GQy9%Dd^nXEIZ+=QA#?674>>ZOiDD-pBG`*xc0f;LsP zR!_SH@Ih9QU*a|iR6=3xmm_CWXGQv%F|pXgixQ(HzN&2neozw1XyOD#Dko>2WM!&G zwyrvl#)cDMJ~mu7H*YL1Q?W=Q?}bBxJJ1(4*UL(=Fgy+s?%FqRtT|;y#H5OeHhRE} zubI&e6)K)q{n+P0SJ$VD^*zJv@zI>FW%WBQ5Ydt#i$sIq1+u$20@44?hG5~J9QLko zI6GN3+-op%O_0JML1Ku3#e0#q&4)oA@-Uq>Wq{3YmPMtBar6&WZKj6AyFfzhtZrbtfb!|;-Ya{gS=S+ zc?=9Yv;{&X-`HR3tdgrV)x+uA&vdLaqODjgmIg&+0|WZs0-D648An{yuB}S2LzC`a z_)C9jp-#er&Y>x7@m|2Zo(o3$h@{k^Hj2dzv37%6_Zj>0e!ne2=4Gg*O!|=BKCooh zN$32vBW>BBMndY zN+yPM*XyiTlI63R^6}8o!)>zHgj8XVTSxl=e=V})<0_4&XM+8Bfr(2$K8?hPw87S` zd|+Vh0#(2XN>Noa)->J^PdjCqS5L2(H$j4owVtFed`cV0|HMYO1%i=Q|7Mv73@ukS z5+gy(fL)<#BBrQ9B>f0^dWdXEDYAd@zT&H)Z1Efw*Vuc3%=`#SP2tFVyf7&kNcZ%G z<|h+zFr+uNfo)(vuWmzD#fZm`94ve+X?XWDw~5rUPlvZ2LT!>m+ zw9sDAahcA;9u`(N>=cg$Gmy&zsBJZG%hoiIyZWAx;bck8wb85V1Y}Ix7o$Qz>(f?w zJ8L+ak^|UMm?w#XM$DA$#2m&eX`BWl+ z4vzYPr#uoa$+{O(p}$&C5rCAycgH)3A65+$6uY8s+OcV-Xfl&;iFFZKo)ze68!1#0pf5shBqzXHB@&WH zR)q~(`66jp{fD1d1tHf9D>Rn%!@ODkdYDoIuE_cONsX4O zdQ=8fvj6nP3x~tq1H4r?3{ex|QsA`v?H2dWz=msg>a|GGm~McjPtP<@o8Ae+cKJPn zpJ0Z3HX#~9&AcZ^SGeq)uZI?|ErhT+O#w@`XM*u)uD)+YC)L59+_6Y+wJyz*&I>*QHCCBW8PYsXv>|MNrUeA!6*gs)Qr z{3&j_=O|mYlrSj_{129*=tsW2g#R?+Jt?=I#O!t9N80o|5&BPc2(3K*ArqizE;l?x z91O;q(@WR`5N^X@&u~;2wY=xR#gzrJtwKIikgem3{_J4YWl$=7uYBXjxzm{n2_Ak> z7}xAlxN8+9<+N;mB|c;CGt<#_?4PHgT<&Wzur>sUAooOrC8$b-VqT)DBxOWdR>Oo- zIse#4i3|G;*oz%7#i#07$YBhBoUxS?7HgCP!nVQyCpN~XGUs>#Uv`3rZvi-+S_CK- zkX~`{MtAzrrg?zMEik5F_0cpv6Skjw^eMT$WzpQ z%UsQyi(l%_!mICJ5HZVPZi!Nb7m-D7Zh)-fi{p#3JdXb{ZJJQT|HFVON~z1WrAQ*5 zotJOBgfaX#Kk}7tMPZ%kqB=J)ymJ1*WiPSI>(MK5o0)|Sh!=BQjoL3tfhkJMssR7W zwv`fGIj>ueJd1AuB)?-V9^yQ;nZ{YkRKiySe;-ZFjf%hbhxO}K9CeOMpHbo;FF?Ym zZw7ih3H)H}dEOYl(a)UMhYdM2^C7$;l>Q@Y6MIO1qQe(;_&}ngXQF)RirJ@sDbp2i z`?id(p-_&`?wl?o)EeKWnQYcc0#Mrs;e;^lcbg?A1#&V45!AA|=|cs6_U7#q=^`SO zntR}l3Jg|8qqeLNJvE#A`H`1Jwz6WSs4At^$xUy?-GE!@cXw{UonzB1ZI}trHk7?X zQ*zWY7hbhFURX6`B+J1v#HZ_;N*pIYZ{>PDQgd@^q_=oiNhToBBUOHH1~l7Df8(lY zD{AEO_bxvq+lt>gvmlei7S{K!?U&7p5pJtwIAvN8w~TlRNfjhkw)>K{;JtSr@c^!%o~^&7MwX5*-K}<2(Wi}R^GRgH0RsLR6GAXX(Me&=dYDS3BsT> z*oi<~NK0gt=?>f;IzlF%Hx2z&9B!OqwQtmyo7qIo<1ZDI>|TS;29yhw7tv3u{n7gu zgnS9HF2;roL`*~w0{lkLpX zy4Z)rDL!^O-#PrO19%xPxK@hMEoGXH?`S@Eq*dpu89jwExiAz6YURCb)F?uJ8Xpe?5``BfgwwYINU4FtcL|8Zb;UsQYO}K zh2ak-RcNa}&L|&LNZ3#^G^2wm=-5zxPr#nm|mR}y_|Kb&}C z+qONiZQI6)lM~w~n%K$2p4hf+XEL!hdGp>|x9a|HRe$N~{?xU5ueE<`Jq4#bdK747ABb2}&L!-}blj=k#$xrXc*}TMjM^MV$kDLQI>BpAB6vy* zIO1!pDN`8|(&CTHJemX;t~{tD%^ZzFgNlB8bg3*Vn#uMZt*(E+O}CBL$<06xAod1R89y3o`! z6pL6Z!K_)$sx)Dhx=^WG&uUi`$*3cXaL(2*Lb*VlQs_!eSPObU-C!0r(ug`_@Fx_? zhQ=8yEAD`iS}crlfC3b_lch2gqaH-t;Y5S&b{D7I5klQC9P;&S=ugKAaJItH6?OJ3kaW!4+BC+UusO=eF>+isn4xE-m6N$?@(uk@|lWy}f`b zELx9XFZM(zuKyx8F;jxf(6$1AtM64XZA+lz{vp_w0ol6UW_Qr`EUTzDf_72DeCu^X zon8G++ghI*%&--v3qz-P7wjF$*EQ?bzVQpgV0kj74sdt)1B>`5vu!QpswDaAnGvY5 z=a_uJ`p*WdYM`jukxeBB6BTq|tUDz;M(&MWkS`SKo}tWX#MLpbif)4ozthnIuwr)P z+cHZBic4$8f0oiJ!rR&AWMmksozvC)0=#AS>-;)5%p}F)U1$SYIw<{|;wf212y{k& z2vLn7$$dtV1ICBdX2Uw^{LrHNegghdpZ`Yce9%A5d#}f*r3@a_7uV&h2pE%1n8V|GElK!`^ zztW`oduB_~?RTQ#q1#pAL4)-Y753(SYN2CwoC?_QK;S@SL9-nVa(Nlp1wpJ*pbT}9 z1d;v;)zOVudE(>TLB1zX_A#7AKY76gHLEL}3$5V<8r~yV<|!wAiI(rN$Rz9x`Pf_- zmBn@kr%yC#;anc%?gCx8V91V@O%GvbBLN9H{@t5#?1&TT$)h5krd|enZHS`w7L^ra-hdb~7%xp4A>=M#*i`M?h*_!Tm+1%1yKdvPu5`kf@eV<7jD zZm6YKTB}bcuV_c4(26YSBljPe{S-%LZiI|apbc)<4`67t+!@9z`Ufsv8;l_%1|sEro7Edv3o}P1?fi}n-*AW|90Z_V#g54{ zDDSjqYY!ia_b!S_EQ@DS=F;Kt!HaDO$xc2<!^MYao z5e)uHjrx7(J;TlXh6EeM9_R?+@e#8Pjt;r&p6o`z!=AKV@`M4|sOFQQa78Z&3xxa_ zyTL@7J%uFtfDSYt+o3>fdzB%X6wJW{ zBI3ODesqKZm60DwiWsCYEcu!o0<-3vzFlPbQa)nWzoH=(r=#W=1vwjrT^kl1oB_no zeuJGk^!mWqyc_)Rfob8-Eu(zoFn(+@o0a@Jf zEmR0va+HqpQ0}Zz9IGQmNNbo0kkU1SAoU*n4~9t``kRf>+>f~K#nWDJI^f)CB~zxX zZl?bPd@1K^X5v;ycmCfhChLvV_22|Z+g}KHZV!BL7-Ll`Vmh}(8KZbBrizp9{Up?~ zwSW3eQ}mk~vsY#V3r#hg9ah&Lgb-cH`$0=N4}bmsv92qTZp|p)d?0IFr6*1WrLaO+ z%c7z4AcP@RCPAWs{Dd?yxq#m@{;+sd$h)N9G9J2!zrB4|X7WTAoE>2DppLBRrA=zm zRE`w5JY#a$f*+EW2;SL-h+3tv{wqTxc3`ieT6{|r=-X!0?;6UDn2SMyOtK~s3**`ngM*B$f+}RN-zLCO#Mj7H^kNAx%qdl@Pc;z` z0I~3}{|$kKjNb=+2n0`Swvi(At^D((#GYr4`b7RO{@8dUQwj0EWDcP=!e9;HU|^b{ zT6r1Z)>7+I>x1S6r7rQl<`$X18k7nY>8fZ9vJeK<7z(w4=YV<9b1epPP&c zTjSR^B6EHA4;j0c7DzG~RTb()fEioWPZUIo(4{J-WV3?Qu{Vho97_4MZJ~{oisdPd zG_>FWj#M9JRE8;Xqi|ilmxRzAEG~N@`I9b_{%nhL{XPgRxYx2$k5;#`P8 zrXQ#W;1CSZI0M#T#6?1Ba9PYxqmEUn;>Aj;H-cze`OXjNn~f3LZl{_I(2UtelLit zeVu|kb$ZtuQT$ggl=m?INt0FcTcEMOioYgbos(4mMU#al(SfO&He&cIn1YbWl9AwM zxPJplQ&|;4p~^k*e{)9ZwXDjbwA#~ppt0rG1Q#+8g z6~y&CaRc~0EfWJHsa{yFww{i=eWwk!b6!q>+g|9sI-7CM+D?7A8L0Xraj+$wi1=*U zbnp!ZDMJf%e}S-M+UYsT(uz11Kb<7=_tWg1#_LM<(NPHosL7vGI{8DCB5r=d3dPJw zTq6oG&tt3msT^;hW)C*936$;2(RC9HYmr6nRhsxIr1UTia1YLMOT230?4-TCuymsj zdy+pBbu;fWhu(y+7^Z-j%byFPiD`NG473;SK$c_mQ=nrd8Q|lDTVsN}0>h$W^NGD+ z7B`k$xc{#@QoLN;#zddhNqi1epV=n)li=Xv=iTJsUU5>nX7Ytni^&vjO(b6tqbdAg z=EHRNjg;mdT<2wlhRZyr)wUFv)OL&Wp+b`~rt|4noUZl!Qic4Yn~&LG4+<-uw}W~# zC-ZYwr_$dmlb{-9CLnX`Z3(@lN}v6E^_nks0M}@zZp&Tz{X8G#@GR)kE^z+Zc_Unf z?u^%LeiD~bN+hpLoo#u%<;=c>&DTgxxV8OA8o*^hsFgoEQX{BY#40~(k1MQLmLeep_{ht8LT!tz)dPwXUM+P(ULiziicmWB*ERuNtB86?9*;_E( z+XuO0`FWhd8JV0P$B%{(S_DoNHUg;E!dtMEBS| zM^G4JI5m(_-kq3L)nw>Ir&i-@?qQ7$ZZm}rR`IiU_-tvrJvvOig#~=_cMb^<5DRD* zjeKwFaryn1?*Pf}Bfnv`1PEbKpC7(6cl1;#ulrMN^^%SzM=AZm?<`QT)?Nyx_HXTGH89!C-bKuhkj%Ns1()iA7 zC&^9J%S-c2qNNb&_E8{s4n_PZGH!BN&*o6 zd`!Dngmb{~ZP*_YSxwEI+>|8Ak5BP&}>D`bf4ipK*P z8~O4N(N-D$R@u3%*n?OBA%UKvJ4}a|hP&g+=9x&OS#}NLJ}kKpgiJC~KUKKF3X^xS zUCq`o#=wB?UeBq-abZ-Mqv|=qfGY%+u*Q!QoJ_dzThwq8X?_Q<6xGPgcb=C%8duC+ zfkcvlWBB$89wD`-L2}{0NjpM`z3lRvI_Y}-jVcFRySK{vHscC~;l7D3ZJcA=qf)@I zlfy&l`$0lbnK~)3#_k0}?H|#4<%nbK0gvvP8w_Ym>2P5XD}Xrvlk|R{O-S-xbJ*(p zoq%uVEd-W}(aEBc4WG*cv<-GPayBXIyUeNE>JJ@=-?{)l!?^yrjWLHMydf$@PZ15D zbx$T1TkeVy_eHcsyh12xI0Fekcm%)sBhCxQ5qZp((R`F!RhA9s!_a$0P#VDP4XD0P3P!-+4e=`#2xxve90nLSW{7LLURoDhsvvUgwWDwLrQP;?0=pT3dxeq_7*nsVi@X>7?b{&fhbGCWayY*|^t7@`HpP0R zTKewTAioy=@BhTEi#H8##y>6@9#R7FAB)=R(VG2? z_1Kk^(t4P-G*GfMkzK1|JXBHxyk}!kKb#%|YL#-PS0lOsf91>AA1S|ElnQy23XkzM z?+8Va!p-shtoqulb_{(loT|H$dp63VXyDHZfOe;FwgSf6<{Ir`=qHPmMKR^hLOE?EnGi6 z#gN+J5b7H>BR{6h+PbS`Le;u1SLH_1pwIN2mZg0R!pN+f6(`6ti`2c?y=%Cf%s^g1O~h!JBE=UQA6`h!;Bm(Lpzzz}sHUn}!%5)k4rHkQx1_4mwjV5+KR= z^^qk>^jyxjFpn9z3g?xFo_rpKPDUyS)O>PaJ*w3-@KCI;W`-O4wV-Ksa7-6ognelb^2uf!i)aDS_+-Iv8RB%v2&@vcBeml<*! z%eKGJ?Sa_#wB=1R%jtWkvU4$Qy09V%3X z3OS$W-2!m7ue2pF5$Kx;rNx2399XLJ+5O?2(aYpnLhq095mAk%Xgll!?(xHmnqVys ze9G#h{a3s>!v(^MA_nfNoMzVBrTVcAMaMqpdHaY5FY`=1_V%C2V3v%-D|r*lN3w7H zV)gBzUaD-*%ERa=R5;rL_t6kr&+z;?XM?qHD-04UR8lLCPuR(Yf7gCu&??H0lM7Iy&+-v zPh8&|`^AKOP%U>&2mm7_@n$$vo$;N11cWJXdn4dY$s=5BI21rZ^Xl|G@OiXjuk1#X zc{EB^1RT@fhzE4IU6QrJyE5;=R@e0LZ4}e@iorBt1P} z3AvVtcvP)-IMu~z>jwlM&$!gr1Zt>*PXe6d7_lkIYE3zZ_KP10M?EoI&@(#+q=wMU z&K0{7&}AeT+1-$zw9r=VmxVHYtHL-vVoC>&`$mNkjh76M#Q&MbU&`UbBz+0;UcN#8 zk8kVsBpxsh^CVf9BO4-8zQI=U&sSrs}@#;ZK~mudNreSFujMgm$bSI?zE zrIM()DCT#t0GflpTM!rR3V!VD{Oq4=JJZcQpYQL``N2{)`u%?J2x8I$(tAWtF`MeG zZ8KAlj%mr-iuoz=B%zwyM2>e`>VLy5?~x}^&o zf7IPFU3d5wgiUeI6_yev$LC$U-1-yWP4mJ*UKo#5xohzkwJhRtM+V`mK5vPCer8^1 zJMmK^P53);>Go}1KsGkpwQ~u_m`@5f2!^{>UvR~h+7Y!d95mYH=IYkeW4}JM+|4<9 z=!1ZbD2}BzFZlkg?x40`B4?#NST^a|>c9H1Gtu4VqM#cjLv zk>dmK{ajkkst89l#|fY5M)^$j!fP0{9(4n%?Me>Rg%dbsf6Ua%Y8f!NRJzy`KGOt$ zk_JMN`H@MW2Keqa_Me2#AQ-{Ev*4Ui^DCAKjVHns${b1$g6UM!HwJQk&MeHS+xdN?xTeW)DAsdN&5>Dr=bKRxV-BN#MuEw zJ4Lrpx2tCWN$o#mVAjZN9KWFt4=}L?N$Fl|hM%_wt8D}=%#QDMH52uu})#4YIf(&#^zuJ-J? z1oKw}=L3-#vI1X#3&*&hboJy?kzn7!(M0V;!OZxfXq0Q_lTajE2n@4-ptqMqS5rWY zxLV*!cR14Xx7TM?>)CjEz;xhqNozNz<}&yNFx`}pgNP3wt*D;Q>2{|gL;&mNKWa>G3;nq zyG@av(%PX5&4VwBL_|k>27WhN0s_N}jidt8cj$h%M2215p-(sO0YpM5{V?7E$z#O( zOA%tvurtI*d-|}%2QLQ#exifaV$T@#*EW`)v7!9e7?nH&m3N)5_ON+o56mnB5~z&= zGpsMMkw7`LmV-O_0Ns9p?%w#fl|ZyPv0s6p+wfd1BsDbzh_tl|Yz4-R zT=yB7k9M>ba7MY;m9^~5?P=fra+&is7YEVaaH6dY>pYeec})jl6B_UKm4MY;e#YFw zf{e`EBDsfyb`jV33LCc`%h_`L1&9{Oi9VcC;`73YLp&4vgJv4bwRQ4fCCv9jU_$c!o$caw4T`4OMgPPbaigtUdpE{J6<>$9tN zqzEWj_v${-m-Jx4cKhZ>Z}#HoP4#cnLW3Z6@02}^%FcpgOtGz6Oq#LbXha@!YX~eU z?$v(RiZvmQ*{MF-Qweed_zg~Y3nB0RC14rJKD~K;0Ua)a1~FTMJ9Q=f&thshQQi1k zU5!%x#!;B9Hov*11h~gavTmw7>ND3Pih% z@P@VTf7HzHAYAj%5$RF^bLXiWyJfY1F|OV7`f2$6F1P4ZB?+~n*X-i#PZ&w#o<+kD zAO4Xo`G?z@i~qRh5sPk>^_FO>#<#51q(QM8Go-bkY%s`_qlY&qk3pHe?U9SBx?Zjc zw1)2Ka&T+Gm)lYrCh1lz{D{u6*#YjFNDsR`Q$5@yPeBf4|5Etn_zO;&hfhLwH_1hn zsv*F^#Gj&QfvYSF^?^cTMv^WIP4g3no9Px5>$JDQaLvCM?^qvb-U-W`<^sl?;)1fp zHmtLiZlXTyc_Ww%x>2`_P*wh_a0@58pdpVxlgiN@NYfn`#}c!SB>Y_6r398zVftjL z4$6xFh-YtU;X`fZo^jQHhLUwbz`jr;wu0?4U@|)YgDIC8Z*+(HVQ7L9 zlK=SandIYQt$Dfqc`fcU_j7gZ&dr}EoD#!STDuY*O)uSHT6v=h>@p`^C?EAM-orB> z!wE9m7eP=VPr0#DjAoFO0KQ8M8{KfD0@H7h-_?4%g#=BH{0>7c6(!?;EqGibcym_A z+1XMR9{DM>r%|O~(|1Lel)9C=&L8CYB=+(8T?{nVID$O>i&HRZD_%64?c!(?h??odg$VGn~4;2)u@b4F(CNuIEDH?!sxE3txoigq?S%) zIhJ4d#p4Nmq5-O>a%5KPQ?nm|H2zzht$%6xxfk4n`f)e_w{~N5m(=(@dHPA_7K=~# zLA=3dRnuIYThGvxK>US4C*3?=&GpSc5&ZzJXMl7McKSVCMjD{Hdj}gc+?4afQ~Sqf zlI>h%S8J9BbG`v4*IYoJRZsRKVeW_Qx~I?M@40{;s~yodrkMc7{>>H}!sBU&sl^E! zL+J+JS-EWgrgL$m>cC-d*nzupy!f!n6O;@oXRq&^ZYWj^z}5gfhhc#9Jk3V>H5x)Y z79`Uylz2>9UO+2O=G~ zk=T?WdX5Egr!q$M)(9r3Q*$b=2tEiy@!l9_QyB&q)IIHYvOfpKQ##pE)J!Hee<4(k zXIWw_mf1S9fn_>X8Da+vnSUEoA9Wf5E#pERQ$ig%0vJDsY~SjJg!Ii=Th^`YE*b&L zYp-tBe;POI`aHz4w`RE_R*&wAflvwitm1?)?#8TfS)-Yp_e!qpY4bg2lCPDxeO%FJ z9)+7SE;~WKb?9oVVG;FNmsgabf;=%D*BC>>Hf=0FfNvH&p#y1hR;R-(#?`Ay!Oi=K zzZ&%05j8$Z6Kzq+$>Jkhv4bPi=V^N$Ib5xg`l|}tQnRtINE4`PT(^~{^?!UYte={H z88k7hTkV%5hF6ce&kG-Z>?%cJCFeC!vZWPiq5M7&qAA9hJZA%z0~hcouzWp}(jP5J?R(BI?WS_<)75+C@W1Qux)!+13SN z%HCvDal|0C*)MMdfpi1`qC{i5ZRc_m`SxRc0zG#^nCHqpg_z})kyBF{y<@CM_ zc!X0oGPbJBzywupP46)3%f@;ri?|0~31XWM`92RWTG5h(79d?p9l1h&^XI6kqJf3j zl_js(V77vK+>|bNsskb}h`!tgagw5jBqKuyfYn^jL-`P^EPII64^bd(eni%fjDE}3 zuOFnP%GMQqS|$)+4*=Nw|I2-EiC+8^>#aV@aa)1QHCd)SfXD~n2C#_#o`Wf zb_Fygi^Ji_3eYz69*sKvqN{No_=vB<&zHR2PtD!pHw1$IkHYgs%WYYSRQAQRBZr3p zlQ{`Hlbb)Yc0ON@xWTUW^x(u=DNR-SNgVG?WcmsHDE64<{oYuOwm^w}4WXD-k3eIj zy!%}>^B3nHgglvRlP&~&L7d(bzs9i$7&0Q)7b&uCl=>l*>;`DOAAwB+fD-NH zG&)MTMh9%wRs#`L z4b$ExKD2km*ZRvUi-O6{50THwIdV^-;-kQuf(Fe!x9a{0O5ytyg?t6|S zf%;=hn>D3;jV{blq@PC3E5Mrlx64QvhQ!)>WzXdd=M&aNfSEi!ST667P?$1(07>jSC zJiRMybUcRx-0oVs@2RLG7zUl}0D9LqOfm(FlWNA=XsS8rO6BbpL|~aq0`9QkvUmBz zFp-ZM)>ScFPT_ki`j`8wKVrDnZ8IA1Q-7^BnC;9K?x^bZs-JLi*|SAjmOeQyL1poDV&alwxj^%=8U z;Zq&+-`~<7pu}pjy6h^l*6iYHZHbj(gh~@wj(C(=mDgOU6d;2ulo_W3C)6dKtgxh? z|6-6S#gx|_36tXouMYBjXX>s;+sW4Zraj3^X>HO&HIutnAgi5dKfcy88L$wBy)^cWLX_2`|RfA6M8MO7QXjx z3T~mk+a39PSYqTkkeqVg{}CqqUvUvW6GyntWLrVkTF(!bW1FD?x3E|jw|RB4moM3g zcy4a8$FJ{y!W4}R&S9QsbFlyY_XL~&nTr4#nnrDuck%-V#{dz`;DX%q@IVGL$c+dt zgy8>c?}DsE`at|L*USE|a-~ZiAxPi#J5a`RK@;QOAy1lF30O$FCnG*qNm=ig6uhjG=@q;EeCG6w_9M4y^j6)q zJ<@$=p=0OcvTMhG`s#~(AOxP=D8S;o7!HS_`0?xnBY9OrW4p*`S9ncEB#H7N0+DKC zq$Gz$arl@fTFC}r3z`p`X{xH~TtyDW{ERRW*dv3VO{1h#1Zv=}&i7r!hQCIqNGG~^ z%gtCIpsf!xRjw?W&&|gjrdT4$TK}A9*IA;=%nZFqHHwgx6PvP3R!jS3#U3(nudL3l zroY&*d_N_Sqv@*{hhtmNOKw;B1PtHrXU|@Sr&aqsCLOuhF9&m1HzL ziFw!9-b_-^lW8Xq2oEVLN2i-ZFfvUo$a7<=gpW!v;q&!IS@}}hBPy? zG>l3Jmx97`7BfLoeW)+us>JwbJQ~BKJpzf`b4xFzRGT@%E$7W9JL-?O*d2k2I~t7= zQF>ACn&zobp};z1bF$8yvy`dEAM~SD^fzMdmWDD{3HB1gl_6umGBA6cQ5o}Zzuuxh zZ@)})T`vthmq}ynZ_Lh+3;32OsoK@Hl3jz&5fQa(p=p|DFk)HjTF3C%1Ps4erPX$} z`wYYUfI_6hd}Ekg6_$7T{G>u}H?Lg&QU3k#xV#W0Ug>Cig;cn{`%ryHEq*q8o)!{afP6j>E_?xp zI3nb&56us~F_5!Pa)vp#38i?Cz7~I{ett{Ke`fK08q0f%I+jYFae%#Ti>jnqpAA#2 zqQ08Kp(s0Ok_3A1>*Pk>4U+VG#lL5by3l`G{h=0a=tsZ-v$sQkOnfn1hu5w4LX2Rp#Wbn9|-;X<xvF(Qu5qylyE~46@uOEj-$=as;* zH^TOH!2V|V5!`C<#{&YvF1!79Z8?;2=A)(4Kglv6Z;&=(RHT+<-A-0udKVoDinLTy z`j%sw$9N<=zPT|Te0t9_@xyb^sr`gXP4ygCX#u!SIQY@x>R%lJb*Szy{b%>>TOzws zhnAuFC+*DKNj8jvhemUwkhm1mpoFM?1p?~@)iL48Xjg@c;tH-6TrWN@dyhLKsuftvl`WrKB1%Q)&lsym~kAX*}U{?=FTZ7$cqm`7Xj4eMGW*i1`17f zuDsnq)kzYNA)=xdHny#0|4udSXJA(#2h`VcnYnke0z70V6cp zb1-@qp(`p-qDj3?y1+OU>eFGPnJMMVo;134*XC)`2K^ zqZM8?L*p|ioz7+<{q3Z)V%(>Y1T%)sCT{6rP7NVq-`yOU)2_G_$cGm0p`d`D>{#4_ zD4_-|U~<~O1#`F@ZNKPMR3@s!?MlnxEFDlY~dL$9F1ot2^jbt6=(% zL}h@;X~IZ=4_H@?j#nt|3>B zbJLO{5xad3{kRm4^s7!@P@66;@=j}e7&5%^UmnjkgqHbXV)Z}a)%t^I!G$2Kj;EcD z1Fs-(SltLXSVddK-7_aWWbm1u6fIR8T{w_<+{;l*YD*G+nBz?FWYZ0J zlI=U=@ZY1Z1kyOlGZqtv)tP15qiv96CT&?*%L>a)b4k@)&H+pnlzQ5TMU*R*KRJO3 zT7(l-JS{INzDSkruBVNIiS1?x8$A;&Lbz8#8kW*Ets226#U>8FyB)k|o?FDy`jYkb z6o2}*EQ*=U@6_WXuK6hF9@!`JI{8n(ja<t`O0Sv={v7VYRKVw$H8{c(RO z6|5;Fg}f0u+>%JX;k-cToecqmkTJy-EMvtG#kNi{l-)OrNe%7{WhO%`8B!i~r817) z^&9n)r>Eg_-AUTyxSx?8Mf4SF2B!zFn{{^pcOzAn#gex48^z)r;Ws2jm3`xI ze6&Bx+*D1B13RbZy_jf$f!~QZLxqVP?&{>q7Nq-VoJ+}r5e;k^^t5bq*7NB%fRg& zCM3E;mSYo9ED!p3F27R2k|=CRfn68Tjw*903d$hb=sb zUnGwb7xj=rKaF%hI@ZFEU=UuDvg)Rf8Vy+E`um*Cd^6G64J=PqJ3VQH5jSKtQ8^KH z*a}T3UD^E9lL#knm0`eZyP@)|qFU3|N4FC9jI+{EYf5&TR<0-55AlRYE!oDr>o&QQvlu4j{?s@Dn#(58rMI3`*UkLHNr`U zfKE6(tnY{mT~yl$0*jIw1*r!#oZdj8Y!=aKhaFYowg|aQDpWZVg+P92vs(>p z7 zA}Xn8Dzh}o{D+p6k9RI3+XVKavPC(d+%6tUK?Is_#w%|x`6_K0d2Lqu363b80(di3 zA zjJjtqS^|X>;&Q8%dudvSAw>HxT&?6s#WP|7A!662MC+hdvE-0e?v((5duT5=NZh#* z3V>?H5aH4iN}(qiZvgD0(gW>^&@tfEL=*4 z0iTOJH2XK5Va50T>^h)tF@L4%|63ITeh9Ekv_>7|P8gcPVV??QY;>Hmjryk7?dB>k z$JIw7|1zNDia1;I3uj=pr568JWhfbJID>18iU$VNG=czBRsD*8w;+>HC7^=S!VeVxbH7%&??^WI`O3Po1uun)V}#to7HZ#o{`&}Y0+Q?e*!~kh#Olp)Ky{8V6G;oyS>?+I^SO2A`-y3Zb%T& zJsUIT&^YCv|SO6j0dS-fQs8^7@J|DgdM@!^YJ{EeCyo$K7sXAt@8vlsQt7w^9 z9N^ww#9jUeJ(YMiUN8}owA}Mh7A_g&{?|xsBXhA+L4B=;Th;$Y-WD(v<%-WYCW@8L zuv)HX9k@REsc2#H{f^4oBjNMuB-bnfignVcIMM|0+JtkwUkPkDZ;q%b3$2-{bM9-N zOQ&!Px77YAnZPGlj{7==>*FDVF=*k*hb*iBV#CdD9i;S2&AzcloX<{`FXT_$XVX2{bI?$2=HTWiVP7%*;eXM1mm!; zrruO^@d^wv9Lv&b(nS+|;5PkUHwxB%5D5`t0UUBz9VGJIG&!k2^hn0d4N0!?IH<%6 zUg_>SHq^@djdwes8-saQ29CMmR1VEB?K(Qp{ySg0%{^b5BLzjLY)UhT=6=lqCvz$F z>)6l;txFCpO|@3gwiWo*Je=%fm(I(Qk9QO4Xw6-oR;|McI%3AAd1Qdi27Xgf3U8G& zLmwm{tBHE15J97DAY7WG_)BIp6J|&S+jRH@KojoZE2dKO8*do31V}q5@cJ}x7H)jM zNWK39Ck9Z(qOJMa(l!64SRq-sBGlffD7^qqQa=e8U#7Mf@DoA^FP~WDSzz3f z=MkT-1+C3eqnxrGgf8n$qA4KR&sSwFDaaJ2NKIyB{#9el>G3xWoI@+uH_I3ZKUqq# zt{J`h;i%HjWsaAlNyeFv8{fP1u(oHL;ZOm!6x)4k4}frsWNj&tBD`1PPB$yiRaD>j zlSmJQaCm5J;pHyit<><{rwDsM`rQ^mKGs(}OoQ1*%b=XU0?Uw*QnnRu`73_xr=~66 zM`rUfvz+%V65y4c{-uGfZw3dhR%VsaBmoTS-@7n{L%?N;qbat%!+{Ac@`V7yfe9}% z_RR$gBqv6TA-ly;lN~@YVVofs>w8Y@cYRu*8D-7xl3~ybI`~Bs0|0+VsIysVxI~+@ z2(_ARy-vNfyGef7RiCT~MkQ!?;VoslOheBsGY@Lw{of zr1IN3+Lq>w&$>X*t?>J@<9gN5XyXS@?`0R$0TKa*_L>dNdT)LsBY7!eWec12Pca{$ zehj^5RvH?A+!+>})3_Ic(}Z?RWUN@^*T`HIxGQ-5Z0uX2trptK&dCDux8Jf7ihOT= z8BLN?pZn#pPtM}~Z)`%n5o|*JA{Cgp#0TiOQoJ~Xg1?H3)P^jZHpc5LZP=HAhe0b%i|2k|2-)X^C)hISK@&ft{ZwW$;->C8f6i%x3f*XYu+ zwzn!fnqrS#Wme|sVi`ixl9ykm`#K_Ly6Yd_oUvlwY#aW?BFZhpAq~IbrrT*CZJo(C zWAmrKKOwX$hD|daRu~MnB|TkNVjV1A1HMy~5!2C&opMU&m)spr6ZD>38R%?%y8EXY zO11MbMYQD*50@e^g8%W3bt@E(CwQ(PTV( za1*5!DQ{WZIJvmXm$P8Mjd20&!b6z+DN2GWhtCqhma6GnT32%OCqz^@s{bBTiF34h zYOOKdHJ$TotBoBX;92S@U7I{%Z4fvyG2R;1o(#RIVsk?Gx*jH42&S+%jEWIDgabc7 zjiN0aUWkejktInImL-LPs0A&lj8;Qtdzw*M4;mgyJl$)=CauTEG$jUB3rQYN5}#V$=t?n_%wNtX@HQ4&`FE(?1G+-Mo?AUh3+fym=*7u>d&)qUXD`-63vY zZ+U~5Sv~ztp53IoMqHM0#=9K}hC1&(ydSx$WAH~t_WeILS%2!zsQe zJzedKy5JD*!?q8-T>|0g1kZn>i`V0A9d0}{ea|-@Gu5pX8GP~}pF8D^)NQ~fkQgFT zuRn58hyUA`jjr9AYa;Y^s!n~(hO&>o&j&Bz_XjUcP@;S9+`zB^B`KG^yV)c2C+(@; z8w+}tX(^}xPC~>eX?G-qnpriJ@!%i6SqBUNr2i0DH4bME2LuvJHCq8x2GRK=wzZ3R zRt)SB31r3UcnDJ{+d|kBVI-9nc&5!7F`IadcJcL59PEiCruKmUt``^M)y%1$rxov( zB-ThxtA*cZu9^@P0@oF(BY2`-_T|P$oM}SR;Jd-Q{IT;>h4@Fdhc3se?R}Mk8HTW zSe8EJ4?}}H|0nuDJ9@dl$!6I-giPk!kR42U6`%mL0%fbM_Gc-#S zCLtV#D}{=DB1h$H2A^u0iUlQQ@=jXJ4pz{ftxpR1cA5!}_tpq=tE+;}&lU?d9HkJJ z-LkO{3$D0(WwEwNc!>*k^$lk4i!@4>zUS*V2IJl-WPfB(OTv`XUKb1v(G&jo#3yDu z_gPISXc*vVSJG-VtmQjX4BRTK?>lj0Vk`;^V?C>sIE)o&)>}Y}0rN88>Mp}-vzVF! z$_{bd4=4aR4x!FyWUC%x&n^?kBns4jQnWJebK~UeajE-L>$4RSIziS>flq-i8{DeJ zYP<9rmCh#I3mqi++_FePm=a8xUrNt@zR~j+j0LP98hXwwOtw9$KlO$C(v-gsF}mbn zLi8S6N_f9#BF8v<0GEL~hYS%kSh~^=dUZcmz6yg$Sm0?{S4Z^iW@S zlx4*S0+;GbbCA&wj2<|=teVvx!s+J#hm~S@wejnAmMriTzI!Ma68 zoJfE~4)NLG1Jm#Z>OzTwbh;V{arnNR@Y4i5QkQtIB!OnuZ|hon&h-)1fv!NSj+w2G``=%VhvHjlK$qaf)UeH1mA_$|b4ZL&mCSJZZ zX;Bhl!pCWHJVYs>$SQ;#(qbVBJPU=R!b}4=M-zwn+mEm=1ya4|HFshZXT0+c&nGbW z<&aagx`a)!s6}i684At>@u}Ms)=N5ND%S|c&}Sggs!3yUz2?Y&C)pK3&0m6dgI$Re z0zG`nk&eaq2eoDw>@0IdV0od^Bzk(U@axIm*UH+98jzI^gSKmdE(v0QKdWl~r<(JX z^!8+<*uGt?rncV35Oq zN*Ke4Fz`O*-EW<6@t$ZsnK0M@fYBIphVt}t9JG*X?cfQ5vC8EL zmDQcp`WQn!$Lt$hGyu%$DP8eQOZh66u=);oA-XdR0=wO;KWqRja)_w6MTe&5-nsma z>yo5XBgJN4JaCE3gSNUZ(J`UT#;Vk6;cypio6ABy`^yy~5tEMb95h>4iq2p#b(q9{ z48__k&kr+UcjzwdGVNX?jj;9V0{LS_T0*|jv42fJ_yA;lX#!ZsQ?EiG_9!=9MRx9m zP&MO))X~eA*K%BBl8#D(@D?6!vQt z$VGOPzV2K<1aX7Zsn>1s0qNDU+#0ET*O?2}p*yB~<_Ao1S)1;|t!ppL&3A_ZA*j=hyl$Y;k zP$xwKa$+V0(lv;oG%5K6C!{{8=bEbI;+d%|$L!3B%qj_bF9=DoxOaC_Y-}VMmL?M=LvsAG<&nT?w*i?msJRSxMLcjlb-AeoBQ4r+U~|#Az5ln(ZA*B<#3l z3WFh=*!BRMy}8UnViWlbA^_Il>5U{>kHxPTl}@~g5BQn3s`5?iE)!nkF5{pzO&5%G2bBwDfDPnW8QQCNx>fCTB+$gpb42nLX2s2#zH!tG-Wzn3td}0%TFIE{Z z&|(7Br)<)c7CG#Q>hc*5-1t7LekR8{g}7xroIT5&dTPgFMc+Hw1w%*2^BnlxhpY(j zs1` z=hy;2r?pN$AB67RU>%0rRLbI`SLmwSB;r?%dV73-wb{zc>flcuR#t$>uS6fBkn%Ol z6lW?gQj0BLw59HNMY2SpgJ=c%LZdAZ=@)E$l}Bz+@s8|Ko_KLHXl=K60b}dC?ku*F zp$xc0%qv9Af-~H4o)*Uuu;TDLG_0#pWuLy8;YR)vdPY}(tAZ~Oe_;_l$I?hI@Dnl{9PUF8;!lFo|v`D!BfB> zS_9KWCW$}vAtS%UHoEsXsl$YO>3ktOMPElV3scrR-j4A3I385M0LxJjQ&m zDX5)#(si;n3>C;n`Z={=jtN$8kT1fI$(REs#Ox|(T11X0<``n$c$vvCDOXTf!Ow;> z_&LLSMj!u=p=Tpp?v;YH9g0Cal01J5y)qRCp!z`$Uj#$2UZ?($s-I#`y3=+RqaeI| zJE{QSRj+%V?r?1=X6#0 zsT0C6T1kj)@qEj;M{KNzO6;ayeL9oX6t7JS(VqSkAv77}CvD7e4F3%DARks=c8Ze% zXz9uMFI0tTIZN72_f|JR(+ksIO>94{GBNLB~D>W5i%|cE*cr%<1j%A3KFc?%V zqe)iXvYOT!V^)kke5K+t)4l2jR1JM8KsPKhXd1C-HM$^Vy{y2)9fo+FTJu?jn&>e5 zj_yRYj6D;A-w0f8(7TkKfVl%cbb7XE0e~p7G)*VR$h+qM^zuba$gp1_FNc z)*n-hBotA#4Y$bS2Ji&mRTHnDv8rj9qT$YK5nCF#lGG|T-6G4i9W)dtLlUW5H4?X!cA^`KokJTq;PDn)egcYheK1D8exdrD&D>^|19JGz_8|G;Fm) z{b!e}EFB%7cA|)`f+Fa#QfH~K0~y(XU`CsN7Z5p{hJz}vjQG-K%WdY=wsOoQ zN!&+$&P?$pf=cM)S)tSETA*PDn6UdP$itJ}!u<5*;pa2;M_vYxe0(*$2rDGqq+niP z=w~A=GfWpe^`zhy#$I1M5Aovse%x`KU3p{9M+%ZP&Xu@=>*^UcSbNE^;}DnrdJZCwyjiwYKO%kHAk zehOI8MuWavUhc|HUO3CHpdBfZu?nd6AIrtNeCB=C3$0q1l=?qO8iJkI*Cs z7ai{b`x^Qse10LuZIW#Z!Pk}+z~~t3 z(@mAS3cUFm-SsOk)q}9v8ip_1P-Xx&6jxgYFyMw*?m4Xd1;Z`$Soo>2l5iz*yd}1v zf1H^7>s{dDM=VK!@NN&qhOx;F^VYuGt8=dcBOi_Y6{g(2x#RR=K5rt_=xL?2JYwy< zh-n^~kqFwE^u!K*Zx=sPyTs(&`T-u%?liu4(`iCrE2*EK*%)QcfG?!Qxj@QzBN@ba z0DwcWholNz72PatR-81%by>1rp2p5_>Mqoj$t^sV8RrGu?I*02k$Ym!loRX;eP}H6 zmvOyg6@O9ZA1K=L$pTk6%|koTesoC@&2;wDeS>h|Kt zLi6(a1z%(WY~>Y*MV5p!VmH{_6#Y9G6O*%9%WEKUGrM~fd z_x9z~u37ZZkW5|zCJ^>9APHP_5H^5;REMq4G*oX7WbF#Pr2f!Xl+E(-sVeZ4wdi zWbv?Y6OWo~!tfDgnL0;uH398@QAVZaZSynpQ`x)1*gkK)LT&WLc-p#~i`JaVwgL!Q zOx{G zA#o@pitI0^-fo#WN$%$N3DYEJ@bJ0RK$1fYKNoytOx~TnKY|K91c9}Vteyl8#O?~4Ppf8 zcv7hLOR8}`jHqTN2MZt)QS8BE9kKjZtC&_|Uym_PtGzCw+Sgxj%jg5n8CxP(&X!B3 zw~<|M1O>Bhj6V{U!85_g&6DU*$>`!zz+-QoNpIogv(skjiF|S;hu(yiBuS0xpMiTp z40-ydc|j2Q0R8C!tE`Uow!AUlTq!TE3^bs)-^iDhNSB@PY+cZ%1Bx@V-{C+tY`XVOu%UZ* zo|N{BHxbpkP-nasRa2BV#M~%VS@zndU1=X9UCrHzpM7yO4`sMVSwGPa zz+RnGw2v|TIlkH1GEW99PtySLy1la5&evbE^hJrI>of%0dh_eg>uqjxW8E)#WDMWo zG@spO7acemk1=cG5<{?z9MW%E+5ixIKXQD6(j04^zQe6VWwdEBtU=$hU|np=8*C1f zLDqKzwBA0{8XlmYquJN))_sp5X?uj|2XJd5E<-u}oMIfa6Gbi?;c=7~DaCT(!uFp0SZJ+EkpT0)J>Z z7zXUcW{8n_&ptGck#mfh!$6dmSSYBt-RzXHOU34^+7oHzB8lXoV_zE#{Dq(_hY0}* z()5Rg1$n56fJK8@rEGyL!yed`Ck;?g10CV^s~@5=s(%NIa)E%Vl1PaHn@bi>R#c>c zp&R17$wl%0=!bdgvTai5Cg6fZ!&lww9LDoEJ)s@f8 z&oA{}zaCHc!Ms*AQF>Ye-^#mA(ov5VvZ!s7R2$;4tLVjS;|1y6w3JA(4xj)4y=!%+ zRS{r858s;HJeIb1>-5djw4L z0bMRw%`vN=_CGa=NL_T3rWoDP)K92Y>`+Uab~PwCB#0;xTi7a2>R+V0g`U@`6>fi# z7`85I_}mtEUtAQ0%?o8;>9PR8cqGBO$^Jw!{SE!G^`yOl*xswyt1q&{ka|Yct^h7m}D?575o^ zCAiV(yyMmLa^?D1pbNB>ozSCHR*lmh_YVyRx%;@lt~tWZR#4OZTgF0+aTJ=Dqw~zg zzD*8A^|h^Jk1Vum6MFkT9}MfgG{S`sVR3ZKX} zAOO!67Qrd(Y>`PB+rnx9Tpci8VQ(o42a8E&q5;99LLx>vQ)3;uaejTYd^2T`INxx; z8AKqYccN*@zQ|&r=O5@~B2Gn6~G+Nrg2W-bx3iJOq^LpHLFjtlmCm1s-Hhsr;xx&LUe@^(CCi3ER~e$J6H;f zb%XA7Q(jdlo}A1#9W?^J08K0XKvo=MHh}!iJy!j?YhXg%#ag4!k#dqZbPA-NGu<(6 zoP5DgZZv8!k`H`hk=RZP!NdBMR?nlLp-&bUjFX|GhfELnM+Dd3_CH7|)>4E92Bt#y zTa?Txha6Zl2Mx&5@iI)BYy6cpda2OiYa0Moz<`Q2Bnw6=stq9yB?A^@sNG9?FAW`< z&clwn9V_?2I&Z!R%ErcubI$rm60Bg6u4-bwW1(YVSHrKPuessO&C9P+mE_FhjGH}O z1{(cQ>h!D28Sj3!%PDWC&uMD&M7txwHwG_8Y<@>s&JuuzOMkD~0VgDtzyYTO#X#>{ zC){nWULdtTt9;rvdjfrHXc|?hoPM@88-r5l2<#jvbWu{od&&*!0)^-l)=-Qz9BLCk zHpOS6YP`;To&oWa%p)M2wRyfZ)#vmfA=*MF=WL~79JV=eR`0oSiBOCT8j)(HaSP@d zb+vpRSq*?%F=P^bD`wf}!tA#jR|20Cam#Sc2j$V{*hbi*d>ob=K5r%b)BEo(27FHsp(D$hl?u{_{0iG1rgYI45%>vTCk`dJR)EWwS#;oN?vrKO(?%QBS zcM7xv*a?;h-LV!R^I7?qagclM#FkrjiY#;x;3dt{*GXwgk^7BTmvt&*nto6&tF{T+ zOJyykk@7>CT#ZU}Su(6I*2Z|Bzz4slG5q{h5UufX3?EIFH`m>R#M zjdpU4od%07|M0khczVH`JY`c4KgYPWM90*3T+?p^bDZ?`a6c60la~P)k^A4Qh;n5e zd;p*z!t6vrRwYhfzqzfGj;g%cS41LgYg(Fei&T#9q?;yytwa_N`r%2!YoqXSU8jy+`iY5!$BQ|6R5kE4H7uzL+x5kalH@T@HFhdC=ZDQ=3p_zCc5S{DAUN=Zqb|4;{?rI# zz8!d&r*nPMFcR;sFNmkEiKH_d|JKLZfDTm_EdZ+=>6TJcWe7}Use5%cP?KG$85zJi zUmxKFldqE9#BUn56k~mw^D8IY6)sx34{dIOn1n0^PA$eg6A{~VoB;B^^%j2GycM8hS4_Lj3))CEHS_PLYAn?0VG%1ur|BLZ?Po zn(9*H%qc~?9y+X>qgotctkm2YUkQMDuy>hEu(E}W&)HV*nslplU$ULG;h`vzD&T2&$*+q zdztoy{n28_hpg#4aD2u&dh526GV#Ioo<~R~8nxmoGdODP%rzznHt`uDm*EoUIYbWb zm0InoOk8%zKFXj1aoXyKOhNVso_)G;gwSr@TmhNLv=Z?xDWYe! z5EKep&J4!`LI@sP_6P>b1wMcaN@L9ptW-#2yVd^qw{lepYgiqD)o}1ILA&5=X%f+r zayQb{+zB=sE?K$WlPk0~d8IAY+~1+)?2|G)>$RQhj~l;ZwI;L7`~pQ*SFkT>qo-%Q z&s-%fC2*a&V$(cvquy$%bDl{?Xij?XoVsd1w07wwcbdSgU8i(|t|SY<8jwZDKqyJo zxs+(tLiHO;eEjZjT&%A(VvT9gD>N@2(K^gHGm-{jWtmcO{Ud)$dNvUzX?h2`Sej)v zzfQ_>A?VUfu7eDQfwz?4BL2Afd--Jzr2+7f@t&`Afcz3^yPYyDso@2NhoqG8zSuV^ zSr_Y0UF1@;AG|thnF|@9&EgX7rn&Jb?scm&Ctxm<>dS9s@kXtO|0G2ml1(s-ru|p> zVB)}T1frUC!PL7FP*?_Xh=Tmd?#}HEhWl9OP2gn`T5zg92f1=s~S8-T3ZJau{F46 z84!Yd5zvn91w!76gd|47FYYxZOp^_aB{4f*X**mp4A}cd40wF z4TtDu6W}N_unjs}pT8`l?5@|)a+a-rDXN%F)Y^s2;D^(i2Z zuj3=z56~+8lJy)S8z9_}Gsmi90@1H*cL?_9*gxdIzJGbgsC@>hCPbWJq`wTYVu{d;cP!}ioEIFD z%3lG9rllRz1oXtNVjip(XHQIdUVhb7PApkIDO^UJsv8#?bbA0B!L8j2~IYO|V#cgv)&%P_Y-pR%IS{&Zp~bhPdju|nhi8Q>l34Z$ZCfv;nhQ}ng~$3P&_ z8za?J!_Tvv&_Zygq~mZ_l=S^p61QpC`yD$z`NNOx(k-NDibR{z3h5jLiii8w8k5fc zO^YK~i%jdIh}rX&g#~_M$|t~_?CT%ofsyrALDX(!WRC%om-90=`u3Xm@P6=hEQ0cQ z@!kP(!vJZ6ePHP2f;0a-0TNYbabtPOuT=&r zE%At(4bFTs&Ycg$!+yHuoe^gFcL#wvKVXN$Eul3trwFWw5!N<+@0*(NY6lO)`4pjb z)jm;ZV?JsQC7fOJd89iHUB*horyu(U!&c(@s0pAn$(G_B6RgC)YHM*fXjJWywr7!` zmy^UzrtsCyHd=t=f$W^&ZOD}@7?)`>h)xjT2HEq&ho${< zMc`QqD$?!%OJX%_^M)T{0VK?KLe61qU*ZCQjX<)$5_dmAe92SxQ=omc;Ku|(oP|Q| z0dCi!p3EDMolFRxuq1!vh>4T_V7%&$m6!;MmTX8MN0)1-#rJM|`KlYfB&b3f^@h-m z^Pj1YbYnh5=}c5J7-O#4#cn=mg&0S-o@%bZoW9v08WK0u&&XueFnt2CKMkl5BCOj1 z!?vBbIK{h@8z#vN4#rZIg#Mr6KbTm`l8dx9*TGO?sDCn;k8zgJTaSUCQ!2f<_ggC! z_~_foY{jI}wPx+@9aO^COrq6V@dIUVn(jr_9dkY{oop;vnw`?wyT`6|dd?>wA?kBf zVR?r3ndpU~H!YbO@lteX6+1g!8*BYGz>1KRE<0NSYNZipLOd-}a@LqobKAM;2=yEE zaWCe9IJ$keWN{Bw|C+f#B%>#h);7#yB=HX2Q)CjcA^uCW`BlC|Xjh8UA`|))U5F)6 z^*A1(Rt*m|QDKpiA0@%PVFal~_f%4yNK8Ka`&rK-BXho*{y^g;lYNrG4%NLNz&=@c z+x;HlG@iYMo;vLCvvDW>{p?6o^$uzivLRbXfEa;bB&zp#u6atm><0qApf-gr?hD2= zv>xMWB2lKsxpy1oq0Xjf=AM^C?oW8{PFOzg(XHyvXMFuRxN0^vXDqkj*~Te~$;cNU0KReQcdl#~oOA31f+OirI9|}Z(An(g?EyU{ECcU6 zwvMfK6!U@$X0*HJza^;6o={+AndAG;IDB@+A;AY1y^+8DPZZLaUl*Z zuRxZSMhNaCyW$SRRN1D3p$BUtx?;G~m5t)B`#2jFenp8gghT5+|HCd`_q%OhD zbo}GFw1T;;vihVtWy>2;iW$djl zkOMON{WKUqgOR7Y8w)+t-vhqDO`uYMg0>cvnLz7U# zuQAN2P#X`ruAxL*lODiK(1SNt#Vy=S2B>_b)SLgViVzdnZ(mU$@{=y{Mo&=_by z_lW1)_wTAaC4RmqaycUJKLWVyQIP*c)JH|HM)Ok|ly0Z0$JGSLorf~?WK2gkn{uzG zJbOy%_r!fyXs16zAq7f5kfiL`g+#TaFIE}zr}_xTb{Y}juRaU42NAQy3X7upi+|BO zih-}2QX~9+w}rGMdP)w$Psl<(aFyrd>R%@=JSEkMa6uz%lP zi#e}nCJvKl%vzS3i`_S^-{bOSL}pawz^<%%CZhWc(Z?GAMej4&JGrcVrmy}2-F{E6 zl}y-Ed=-h<7ZF*}&wfGTOpoK9!L45U-aiVj70d1VCECf|jF?JMi$s+8@xToDLa5jo zoxeeMP>Xw|!MQ$ww!S0x*@;kSwzf8WS-ocb3HFzw(j%|ps(S_M3&gL_P7ahWQPh>n z_O$*n8pPIhnSHhrk*gad>yZprZQVuhxP(~&U2sHEyfgZk+vr;vKcVE?I_K-lU z6q>|LmCF(1Bu36H>7Ue6J1A+rV-&pQpVt9=bAMv4+Fxe8Lw~-t$nPHLEmKN6q*l9~ z!)Z8t92Qert2iqsh;^8}O^zyYtn8>>{Z3fyGC9WmPUS}jU-p;kSnAVqKLNkw&Y_hd z9*CR{K%!z^B&py%MX^8PgcZiYodt>#;bFlifcz}9#_=3@d4Z$g(peT8btT>T=C9dt z(-(9`{K3qbUkSjh`<)8@5ft}g2O$~3CF^T=$8pQ!gMP(z)>EdI4--b#{s%Pff-r4o z7klcwE@_N&%TiZQHI&^$z)#`cBL{ z!!omutKBkMVxO-wi3eVwZ@B9^BaV8OHb(uKAK$O?wj@8>6?SGl?@Kr9w%@&XIQ{j1 zhkyTG?X71xMR*2z#hU;%nwbGd1_WBT{^rc1b@H&vOaWAfRJ(Nya+4IxV6@4Ty}@80 zVSb9agWxO%AQQi-2bP$P!uv|yGY^Hzg)+~GPqUD+7dHw3|J(PS*E!07d#D^2bN5BF zFzC+F_WjXEp?$xcTW9xQUS}trU_9Z%5>tUtm^sm8A49AuoHY83F^m8f7nz;{)!S++ z>iqo7vzs$5nnBnXiJt8h+w62g_!5Lz`HK-+*5|x>Y8Ur-zTnl8=b#Yjk<-T`DjeJN zbRBpS_*i6jpF9DAfezuf+#&tV!Mn{i=Y)FbBWLg*&pzMzLoO5?e6!)a1J}pq6UK-m zju<$i^RF;0;dIE*j~eet9}l zu}Gh)KNNy7bQ~QndYtAJOlEyBXEWbG_hxb^l&omw70ke6ukXk8+TKJ-u-SK!TpwH> z*X(#Ym+2`U?%CxRf|1S5WVK+#p+zp8Z?WFL+S2>NBIRp8o4g5#PWJ*|>#(vxI4&zN zpKl1mXy}#0P+XE!>`Y^YZkwQmjnSqR^PD)Rf_K4=SykK42n=Plk(|h!aVger%b0t+ zFCa>zp81)?u!-K1;X;wf{5`M#%pPTqVlMplN>PTBcGcL+7?=Mtsn7iABy*d+9m!A4oMHcjJ6yiX}BMU~|swZcv$Dp=CC zd=WY3!oHKhN((;44$(rbAcgjF(*WN;MZ*hQ$1S*BTA?eOc@bWh9x)bkRDKvGU2E(K zjy<&`#aW+Xomn8~&EDdsxQe6e3RZ`{*2Ir{<0;NQdd@F^L$$SvQ>;Cm5<(gDvC#S` ziII6v8I3sY^k`Oc9qf62c1`b5Z5B3tbnZubdg(j=#e9Iz^TZYM^AlBmiE1G%b!@I+Z#Z|J8gx++Ns1t|jfwfQ|d9w4spI<*cNOUvb9jtf4y~H_kT3ljH z9F^io3msemIQgtFo!R^0)Z_#9;O`*1t&pV7+0nj;Ov?xgkHjuaMnPZ_d-7X)3ct1H zi4KA%TD;@S965{%G(;l)2E$9u(H@ZFqHTEx<^S0Tu2U7IEoWnN@kV><+~!HL&tVBA zqgBgEtmo|92P$keofqY3klJLoIk{fTzbN7>+c$P>0CRmjr$9&v=My-$m#`fxzh@qW z37-9yLToG(k_GE$Bgo=V;q9hKemo)Y#IMnqG@g%)#Er!$ZZ5U#vcgp ztF-6qOlWt|3X}*@a7W5K<$CDsZ9MU5k!)H%$k;=<948DPs;@G%L104eIE!bjOSp9%arW)~eO1LN4B~|Jq3y6=OlV8Z54-*<7 zmoe$I@@C;Y3)wx6`UKgoGCw@ECn(qJO8lymRJt(L`XJfg# zKH%Pm=)4!Yv7CsYBv2{}WyghAJTxH&3^$#p0^DJd@^|uboEQK8 zARLI-5to~D36?8Q3Y*MdO{JMjF^`g_FLM4?6r%^D{Pf)#3OPnOt>js5u?6O*z>Dv6 z?ldj2GZ@yGPe}aK^U6|L4*|+&YgB8#C-L{Mc%^fy<-Ou$4+lk zK-8&3NwEgg>Ak}y>Iu7(GEEHc;gM`t*^b+E3VngiPBMT9d_yn*_fD3WDl$+liL)as zOGUPXwwb&^u_rf@6?2D<>Z8wrx|3ud0A24HKkFA|w%9GOVJmtIXu4zdKtAb>_o@6P zI_1zX5V4egk&~AY%{T_5M>HDtg0W#ei6!vuK!aH50ngkH9|20x#F$0=8Qp2t2QmEm z^G#37!J*lA(&r2=j@r`pZ@Yc;#WKvq=$VhZT#qoD-;h$U1i5tGG0y1SY_n2-=KtT@m zat?GPZDmoEjBlVEdrWxfFoR3t05Ullgb)**-dJNOTNrx2$cy2^$23Mt8!+zBwA3-} zQ4ool_JJqNR`pHB8Jvm~i~7h0Qar9ER?lmjNX-0W-?fr-@mtrGs+NaLv2`${s7q%g z!+Hbq&rI|$JbX@Fd%hLbZDaFWr8*&XwJ8tXoW_vl>~gQ?F_AN)a?@0Z13YG)Z@|_n z@s(Z(+vX=(*Cufji#Ev1e4su66e7FfWf$;GM`>@WMDEenvXkux2)?0V6ZTv4!ih`4 z6xyKDcue(CeNP?noHwgeVnYa)0N9-t%gb8QguW-K3mO>@2L$$kjyodS~|7BhlzE_*x@ru!Ni6YQr zT%Y$6gEmGw$3}%34y}pz`&#{meOSATG+6ID_nkXk8wwlp8Bi*NX&6JgA~zBK znkE2I=W*+;I^iKe!dNz-k1^d}KpI)~(!JBarLyq*6^(xH9K-&#a}3%({yX7-J{h}N z*_tvso0*tdIl3}AIy*R;IlEe!xzNio(v6Q!{G=aKkY%jnoMPvgWPbzNg@b{$d2CGv z>5_nfcB4Vx!QWtjVI<^YN`Q1p{wFC&sEaVlC`vN_h5CCw(}_JKB?ir>=szR? z3>-TvlZma7i_8BOxZrHsfehNSe+N2(&+&>I4D%P4^j`%Y!R^^Lf~3si2*JQeUy*j< z{vyF5y($lQK1d2GVF~9ymw`WV{(bkf-i1BwATQ+zM3Bqht9*xW{}5MjN&Z!tteYW7 zZ_pitg7SaeWb-5-5)0ra#TDZJ9t7F{K9s zBY8y%;r@#R^FPg|GV;3)7jl0t6Urj~E6=~;8eU)dH;vbUGC=zg99_L@gR}r*c z5sQ@nBI5k>j$cJBd4&hl{)1=MBm`EELj9BTUwQxkeKbrT{&3DmiT{cJTT>m>NHnj? zfH(XL4+B&kLkD$6pvBnlmH}7+KUz@!=aK#Hhht;#M8B!)R{z&U|LTV(wpRb?i@@tY zR3vNQTTAwTwaY7+(N}dyvjq`wf2)rEr##@-@!yqr?*w%6A^^UO6a20i!Ni|O<_r{> zVEO0Gz0v@Dm9dKJAHJS5BJkV9s|NgA{RxDB-5`11APzYYc@puTWxUd3dR0b@4+t*^ z1Wdll|CN%=D?B#eqg<|&eY*6Hul`kS{A%*>tu diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e0b3fb8d70b..6b3851a8ad2 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-4.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cccdd3d517f..af6708ff229 100755 --- a/gradlew +++ b/gradlew @@ -28,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index e95643d6a2c..0f8d5937c4a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/settings.gradle b/settings.gradle index 31f651b27a1..cf064976db5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1 @@ rootProject.name = "gradle-avro-plugin" - -enableFeaturePreview("STABLE_PUBLISHING") diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index e8d9c005daf..1f0612e7d66 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -15,15 +15,26 @@ */ package com.commercehub.gradle.plugin.avro; +import java.util.concurrent.Callable; import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.internal.ConventionMapping; import org.gradle.api.internal.IConventionAware; -import java.util.concurrent.Callable; - -import static com.commercehub.gradle.plugin.avro.Constants.*; +import static com.commercehub.gradle.plugin.avro.Constants.AVRO_EXTENSION_NAME; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_DATE_TIME_LOGICAL_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_CREATE_SETTERS; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_DATE_TIME_LOGICAL_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_ENABLE_DECIMAL_LOGICAL_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_FIELD_VISIBILITY; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_OUTPUT_CHARACTER_ENCODING; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_TEMPLATE_DIRECTORY; public class AvroBasePlugin implements Plugin { @Override diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index f299ef3cba8..843b9d191fa 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -15,6 +15,9 @@ */ package com.commercehub.gradle.plugin.avro; +import java.io.File; +import java.io.FileFilter; +import java.util.concurrent.Callable; import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; @@ -33,11 +36,12 @@ import org.gradle.plugins.ide.idea.IdeaPlugin; import org.gradle.plugins.ide.idea.model.IdeaModule; -import java.io.File; -import java.io.FileFilter; -import java.util.concurrent.Callable; - -import static com.commercehub.gradle.plugin.avro.Constants.*; +import static com.commercehub.gradle.plugin.avro.Constants.GROUP_SOURCE_GENERATION; +import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; +import static com.commercehub.gradle.plugin.avro.Constants.JAVA_EXTENSION; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_OUTPUT_CHARACTER_ENCODING; +import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; +import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; public class AvroPlugin implements Plugin { @Override diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 0ac837b3851..fd6808b94ef 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -15,11 +15,10 @@ */ package com.commercehub.gradle.plugin.avro; +import java.nio.charset.Charset; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.generic.GenericData; -import java.nio.charset.Charset; - public class DefaultAvroExtension implements AvroExtension { private String outputCharacterEncoding; private String stringType; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java index b3056893343..72599e350c2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java @@ -15,13 +15,12 @@ */ package com.commercehub.gradle.plugin.avro; -import org.gradle.api.specs.Spec; - import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Set; +import org.gradle.api.specs.Spec; class FileExtensionSpec implements Spec { private final Set extensions; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index cea8f94843c..077409edf69 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -15,6 +15,13 @@ */ package com.commercehub.gradle.plugin.avro; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.apache.avro.SchemaParseException; @@ -25,17 +32,21 @@ import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; -import org.gradle.api.tasks.*; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static com.commercehub.gradle.plugin.avro.Constants.*; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.TaskAction; + +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_DATE_TIME_LOGICAL_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_DATE_TIME_LOGICAL_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_FIELD_VISIBILITY; +import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; +import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; /** @@ -274,12 +285,12 @@ private void compile(Schema schema, File sourceFile) throws IOException { } private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { - String templateDirectory = getTemplateDirectory(); + String configuredTemplateDirectory = getTemplateDirectory(); compiler.setOutputCharacterEncoding(getOutputCharacterEncoding()); compiler.setStringType(parsedStringType); compiler.setFieldVisibility(parsedFieldVisibility); - if (templateDirectory != null) { - compiler.setTemplateDir(templateDirectory); + if (configuredTemplateDirectory != null) { + compiler.setTemplateDir(configuredTemplateDirectory); } compiler.setCreateSetters(isCreateSetters()); compiler.setEnableDecimalLogicalType(isEnableDecimalLogicalType()); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 80365ab8b28..136c13a7497 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -15,6 +15,13 @@ */ package com.commercehub.gradle.plugin.avro; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.LinkedList; +import java.util.List; import org.apache.avro.compiler.idl.Idl; import org.apache.avro.compiler.idl.ParseException; import org.gradle.api.GradleException; @@ -27,14 +34,6 @@ import org.gradle.api.tasks.TaskAction; import org.gradle.util.GradleVersion; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.LinkedList; -import java.util.List; - import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java index 95e831ceb76..66ace4fc168 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java @@ -15,6 +15,9 @@ */ package com.commercehub.gradle.plugin.avro; +import java.io.File; +import java.io.IOException; +import java.util.regex.Pattern; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.gradle.api.GradleException; @@ -23,10 +26,6 @@ import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.TaskAction; -import java.io.File; -import java.io.IOException; -import java.util.regex.Pattern; - import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java index fc440d2baac..13ab11542e7 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java @@ -15,6 +15,7 @@ */ package com.commercehub.gradle.plugin.avro; +import java.io.File; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTree; import org.gradle.api.specs.Spec; @@ -22,8 +23,6 @@ import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.SourceTask; -import java.io.File; - import static org.gradle.api.tasks.PathSensitivity.RELATIVE; class OutputDirTask extends SourceTask { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java index 4cfb2b4edec..ddfe0e65066 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -15,17 +15,21 @@ */ package com.commercehub.gradle.plugin.avro; +import java.io.File; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Set; import org.apache.avro.Schema; import org.gradle.api.Project; -import java.io.File; -import java.util.*; - class ProcessingState { private final Map typeStates = new HashMap<>(); private final Set delayedFiles = new LinkedHashSet<>(); private final Queue filesToProcess = new LinkedList<>(); - private int processedTotal = 0; + private int processedTotal; ProcessingState(Set files, Project project) { for (File file : files) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java index fe90e67544f..8ac16006b0d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java @@ -15,11 +15,10 @@ */ package com.commercehub.gradle.plugin.avro; -import org.apache.avro.Schema; -import org.gradle.api.GradleException; - import java.util.Set; import java.util.TreeSet; +import org.apache.avro.Schema; +import org.gradle.api.GradleException; class TypeState { private final String name; @@ -30,11 +29,11 @@ class TypeState { this.name = name; } - void processTypeDefinition(String path, Schema schema) { + void processTypeDefinition(String path, Schema schemaToProcess) { locations.add(path); if (this.schema == null) { - this.schema = schema; - } else if (!this.schema.equals(schema)) { + this.schema = schemaToProcess; + } else if (!this.schema.equals(schemaToProcess)) { throw new GradleException(String.format("Found conflicting definition of type %s in %s", name, locations)); } // Otherwise duplicate declaration of identical schema; nothing to do } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 739ace96890..2b369d1debf 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -120,6 +120,7 @@ abstract class FunctionalSpec extends Specification { return gradleVersion >= GradleVersion.version("4.0") } + @SuppressWarnings("UnnecessaryGetter") protected String buildOutputClassPath(String suffix) { return isMultipleClassDirectoriesUsed() ? "build/classes/java/main/${suffix}" : "build/classes/main/${suffix}" } From b1685452a25079b7328808484077c5722d6632ab Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 22 Aug 2019 13:39:56 -0400 Subject: [PATCH 245/479] Use new Lazy Configuration approach rather than internal conventions API Now supports Gradle 5.6 Minimum Gradle version is now 4.4 * Eliminate usage of internal conventions API, using new Lazy Configuration approach instead; requires Gradle 4.4+ * Technically, the APIs needed are available in Gradle 4.3, but there is a bug related to un-set `Property` instances in 4.3 and 4.3.1; see https://github.com/gradle/gradle/issues/3879 * Cleaned up compatibility code for older versions of Gradle * Built using Gradle 5.6 * Change source compatibility to 8 * Modernized for Java 8 --- CHANGES.md | 7 +- README.md | 12 +- build.gradle | 24 +-- config/checkstyle/import-control.xml | 3 +- gradle/wrapper/gradle-wrapper.jar | Bin 55190 -> 55616 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 22 ++- gradlew.bat | 18 +- .../gradle/plugin/avro/AvroBasePlugin.java | 116 ++----------- .../gradle/plugin/avro/AvroExtension.java | 18 +- .../gradle/plugin/avro/AvroPlugin.java | 159 ++++++------------ .../gradle/plugin/avro/Constants.java | 15 -- .../plugin/avro/DefaultAvroExtension.java | 65 ++++--- .../gradle/plugin/avro/FileExtensionSpec.java | 4 +- .../gradle/plugin/avro/FileState.java | 2 +- .../plugin/avro/GenerateAvroJavaTask.java | 129 ++++++++------ .../plugin/avro/GenerateAvroProtocolTask.java | 18 +- .../plugin/avro/GenerateAvroSchemaTask.java | 4 +- .../plugin/avro/GradleCompatibility.java | 59 +++++++ .../gradle/plugin/avro/GradleFeatures.java | 42 +++++ .../gradle/plugin/avro/GradleVersions.java | 25 +++ .../gradle/plugin/avro/OutputDirTask.java | 14 +- .../gradle/plugin/avro/AvroPluginSpec.groovy | 10 +- 23 files changed, 402 insertions(+), 366 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java diff --git a/CHANGES.md b/CHANGES.md index 6eafa412452..a739a8de0de 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,10 +2,15 @@ ## Unreleased * Use reproducible file order for plugin archives -* Built using Gradle 5.1 +* Eliminate usage of internal conventions API, using new Lazy Configuration approach instead; requires Gradle 4.4+ + * Technically, the APIs needed are available in Gradle 4.3, but there is a bug related to un-set `Property` instances in 4.3 and 4.3.1; see https://github.com/gradle/gradle/issues/3879 +* Cleaned up compatibility code for older versions of Gradle +* Built using Gradle 5.6 * Upgrade Spock from 1.2 to 1.3 * Upgrade Checkstyle from 6.1.1 to 8.23 and adjust rules used * Upgrade Codenarc from 1.0 to 1.4 and adjust rules used +* Change source compatibility to 8 +* Modernized for Java 8 ## 0.17.0 * Built using Avro 1.9.0 diff --git a/README.md b/README.md index 6ec8d01b5d2..f3fa9d9e4e8 100644 --- a/README.md +++ b/README.md @@ -10,24 +10,20 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Java 8-12 * Java 11 support requires Gradle 4.8 or higher - * Java 9 support requires Gradle 4.2.1 or higher * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Gradle 5.1 - * Currently tested against Gradle 3.0-3.5.1, 4.0-4.10.3, and 5.0-5.1 - * Gradle 5.2+ is *mostly* supported; there is an incompatibility with setting `outputDir` that has not yet been addressed. +* Currently built against Gradle 5.6 + * Currently tested against Gradle 4.4-4.10.3 and 5.0-5.6 + * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) - * Other versions may be compatible, but Gradle 1.x versions are unlikely to work * Currently built against Avro 1.9.0 - * Currently tested against Avro 1.9.0; other versions may be compatible + * Currently tested against Avro 1.9.0 * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) * Versions of Avro prior to 1.7.x are unlikely to work * Incubating: support for Kotlin * Currently tested against Kotlin 1.2.31 - * Kotlin 1.1.2 and higher requires Java 8+ - * Doesn't work with Gradle 3.2-3.2.1 * Incubating: support for Gradle Kotlin DSL * No test coverage yet; will attempt to address incompatibilities as they are discovered diff --git a/build.gradle b/build.gradle index 9df4dd2c95b..be74bae3229 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,6 @@ tasks.withType(AbstractCompile) { tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -sourceCompatibility = 1.7 version = "0.17.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" @@ -177,23 +176,18 @@ test { ] } +// Java 8+ is required due to Avro 1.9.0 requirements +// Java 8+ is also required by Gradle 5.x +sourceCompatibility = 8 + def avroVersions = ["1.9.0"] def gradleVersions = [] -if (org.gradle.api.JavaVersion.current().isJava8Compatible()) { - // Support for running Gradle on Java 7 is deprecated and will be removed in Gradle 5, as per https://docs.gradle.org/4.2.1/release-notes.html - gradleVersions.addAll("5.0", "5.1", "5.1.1") - // Gradle 5.2 appears to introduce an incompatibility with the previous approach used for task property re-configuration. - // "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6" -} -if (org.gradle.api.JavaVersion.current().isJava7Compatible()) { - gradleVersions.addAll("4.8", "4.8.1", "4.9", "4.10", "4.10.1", "4.10.2", "4.10.3") - if (!org.gradle.api.JavaVersion.current().isJava9Compatible()) { // Gradle 4.2.1 is the first version that supports modern Java 9, as per https://discuss.gradle.org/t/could-not-determine-java-version-from-9-0-1/24457 - gradleVersions.addAll("3.0", "3.1", "3.2", "3.2.1", "3.3", "3.4", "3.4.1", "3.5", "3.5.1", "4.0", "4.0.1", "4.0.2", "4.1", "4.2") - } - if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 appears to be the first version that supports Java 11, as per https://github.com/gradle/gradle/pull/4759 and testing - gradleVersions.addAll("4.2.1", "4.3", "4.3.1", "4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") - } +if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 appears to be the first version that supports Java 11, as per https://github.com/gradle/gradle/pull/4759 and testing + gradleVersions.addAll("4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") } +gradleVersions.addAll("4.8", "4.8.1", "4.9", "4.10", "4.10.1", "4.10.2", "4.10.3") +gradleVersions.addAll("5.0", "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6") + avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 8ceb0caed49..328a947c8c8 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -10,6 +10,7 @@ + @@ -19,6 +20,4 @@ - - diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 87b738cbd051603d91cc39de6cb000dd98fe6b02..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch delta 3320 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 { @Override @@ -43,93 +29,15 @@ public void apply(final Project project) { } private static void configureExtension(final Project project) { - final AvroExtension avroExtension = project.getExtensions().create(AVRO_EXTENSION_NAME, DefaultAvroExtension.class); - ConventionMapping extensionMapping = conventionMapping(avroExtension); - extensionMapping.map(OPTION_STRING_TYPE, new Callable() { - @Override - public String call() throws Exception { - return DEFAULT_STRING_TYPE; - } + final AvroExtension avroExtension = createExtensionWithObjectFactory(project, AVRO_EXTENSION_NAME, DefaultAvroExtension.class); + project.getTasks().withType(GenerateAvroJavaTask.class).all(task -> { + configurePropertyConvention(task.getOutputCharacterEncoding(), avroExtension.getOutputCharacterEncoding()); + configurePropertyConvention(task.getStringType(), avroExtension.getStringType()); + configurePropertyConvention(task.getFieldVisibility(), avroExtension.getFieldVisibility()); + configurePropertyConvention(task.getTemplateDirectory(), avroExtension.getTemplateDirectory()); + configurePropertyConvention(task.isCreateSetters(), avroExtension.isCreateSetters()); + configurePropertyConvention(task.isEnableDecimalLogicalType(), avroExtension.isEnableDecimalLogicalType()); + configurePropertyConvention(task.getDateTimeLogicalType(), avroExtension.getDateTimeLogicalType()); }); - extensionMapping.map(OPTION_FIELD_VISIBILITY, new Callable() { - @Override - public String call() throws Exception { - return DEFAULT_FIELD_VISIBILITY; - } - }); - extensionMapping.map(OPTION_CREATE_SETTERS, new Callable() { - @Override - public Boolean call() throws Exception { - return DEFAULT_CREATE_SETTERS; - } - }); - extensionMapping.map(OPTION_ENABLE_DECIMAL_LOGICAL_TYPE, new Callable() { - @Override - public Boolean call() throws Exception { - return DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; - } - }); - extensionMapping.map(OPTION_DATE_TIME_LOGICAL_TYPE, new Callable() { - @Override - public String call() throws Exception { - return DEFAULT_DATE_TIME_LOGICAL_TYPE; - } - }); - project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { - @Override - public void execute(GenerateAvroJavaTask task) { - ConventionMapping taskMapping = conventionMapping(task); - taskMapping.map(OPTION_OUTPUT_CHARACTER_ENCODING, new Callable() { - @Override - public String call() throws Exception { - return avroExtension.getOutputCharacterEncoding(); - } - }); - taskMapping.map(OPTION_STRING_TYPE, new Callable() { - @Override - public String call() throws Exception { - return avroExtension.getStringType(); - } - }); - taskMapping.map(OPTION_FIELD_VISIBILITY, new Callable() { - @Override - public String call() throws Exception { - return avroExtension.getFieldVisibility(); - } - }); - taskMapping.map(OPTION_TEMPLATE_DIRECTORY, new Callable() { - @Override - public String call() throws Exception { - return avroExtension.getTemplateDirectory(); - } - }); - taskMapping.map(OPTION_CREATE_SETTERS, new Callable() { - @Override - public Boolean call() throws Exception { - return avroExtension.isCreateSetters(); - } - }); - taskMapping.map(OPTION_ENABLE_DECIMAL_LOGICAL_TYPE, new Callable() { - @Override - public Boolean call() throws Exception { - return avroExtension.isEnableDecimalLogicalType(); - } - }); - taskMapping.map(OPTION_DATE_TIME_LOGICAL_TYPE, new Callable() { - @Override - public String call() throws Exception { - return avroExtension.getDateTimeLogicalType(); - } - }); - } - }); - } - - private static ConventionMapping conventionMapping(Object conventionAware) { - // TODO: try other alternatives to convention mapping - // Convention mapping is an internal API. - // Other options here: - // http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api - return ((IConventionAware) conventionAware).getConventionMapping(); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index bb235a7bf54..c381a0bd632 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -1,5 +1,5 @@ /** - * Copyright © 2013-2015 Commerce Technologies, LLC. + * Copyright © 2013-2019 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,12 +15,14 @@ */ package com.commercehub.gradle.plugin.avro; +import org.gradle.api.provider.Property; + public interface AvroExtension { - String getOutputCharacterEncoding(); - String getStringType(); - String getFieldVisibility(); - String getTemplateDirectory(); - boolean isCreateSetters(); - boolean isEnableDecimalLogicalType(); - String getDateTimeLogicalType(); + Property getOutputCharacterEncoding(); + Property getStringType(); + Property getFieldVisibility(); + Property getTemplateDirectory(); + Property isCreateSetters(); + Property isEnableDecimalLogicalType(); + Property getDateTimeLogicalType(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 843b9d191fa..949e051e325 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -1,5 +1,5 @@ /** - * Copyright © 2013-2015 Commerce Technologies, LLC. + * Copyright © 2013-2019 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,17 +17,12 @@ import java.io.File; import java.io.FileFilter; -import java.util.concurrent.Callable; -import org.gradle.api.Action; import org.gradle.api.Plugin; import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.internal.ConventionMapping; -import org.gradle.api.internal.IConventionAware; -import org.gradle.api.plugins.AppliedPlugin; +import org.gradle.api.file.Directory; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; -import org.gradle.api.specs.Spec; +import org.gradle.api.provider.Provider; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.SourceTask; @@ -39,9 +34,9 @@ import static com.commercehub.gradle.plugin.avro.Constants.GROUP_SOURCE_GENERATION; import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.JAVA_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.OPTION_OUTPUT_CHARACTER_ENCODING; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; public class AvroPlugin implements Plugin { @Override @@ -53,56 +48,38 @@ public void apply(final Project project) { } private static void configureTasks(final Project project) { - getSourceSets(project).all(new Action() { - public void execute(SourceSet sourceSet) { - GenerateAvroProtocolTask protoTask = configureProtocolGenerationTask(project, sourceSet); - GenerateAvroJavaTask javaTask = configureJavaGenerationTask(project, sourceSet, protoTask); - configureTaskDependencies(project, sourceSet, javaTask); - } + getSourceSets(project).all(sourceSet -> { + GenerateAvroProtocolTask protoTask = configureProtocolGenerationTask(project, sourceSet); + GenerateAvroJavaTask javaTask = configureJavaGenerationTask(project, sourceSet, protoTask); + configureTaskDependencies(project, sourceSet, javaTask); }); } private static void configureIntelliJ(final Project project) { - project.getPlugins().withType(IdeaPlugin.class).all(new Action() { - @Override - public void execute(IdeaPlugin ideaPlugin) { - SourceSet mainSourceSet = getMainSourceSet(project); - SourceSet testSourceSet = getTestSourceSet(project); - project.getTasks().withType(GenerateIdeaModule.class).all(new Action() { - @Override - public void execute(final GenerateIdeaModule generateIdeaModule) { - project.getTasks().withType(GenerateAvroJavaTask.class).all(new Action() { - @Override - public void execute(final GenerateAvroJavaTask generateAvroJavaTask) { - generateIdeaModule.doFirst(new Action() { - @Override - public void execute(Task task) { - project.mkdir(generateAvroJavaTask.getOutputDir()); - } - }); - } - }); - } - }); - IdeaModule module = ideaPlugin.getModel().getModule(); - module.setSourceDirs(new SetBuilder() - .addAll(module.getSourceDirs()) - .add(getAvroSourceDir(project, mainSourceSet)) - .build()); - module.setTestSourceDirs(new SetBuilder() - .addAll(module.getTestSourceDirs()) - .add(getAvroSourceDir(project, testSourceSet)) - .build()); - // IntelliJ doesn't allow source directories beneath an excluded directory. - // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. - SetBuilder excludeDirs = new SetBuilder<>(); - excludeDirs.addAll(module.getExcludeDirs()).remove(project.getBuildDir()); - File buildDir = project.getBuildDir(); - if (buildDir.isDirectory()) { - excludeDirs.addAll(project.getBuildDir().listFiles(new NonGeneratedDirectoryFileFilter())); - } - module.setExcludeDirs(excludeDirs.build()); + project.getPlugins().withType(IdeaPlugin.class).all(ideaPlugin -> { + SourceSet mainSourceSet = getMainSourceSet(project); + SourceSet testSourceSet = getTestSourceSet(project); + project.getTasks().withType(GenerateIdeaModule.class).all(generateIdeaModule -> + project.getTasks().withType(GenerateAvroJavaTask.class).all(generateAvroJavaTask -> + generateIdeaModule.doFirst(task -> project.mkdir(generateAvroJavaTask.getOutputDir())))); + IdeaModule module = ideaPlugin.getModel().getModule(); + module.setSourceDirs(new SetBuilder() + .addAll(module.getSourceDirs()) + .add(getAvroSourceDir(project, mainSourceSet)) + .build()); + module.setTestSourceDirs(new SetBuilder() + .addAll(module.getTestSourceDirs()) + .add(getAvroSourceDir(project, testSourceSet)) + .build()); + // IntelliJ doesn't allow source directories beneath an excluded directory. + // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. + SetBuilder excludeDirs = new SetBuilder<>(); + excludeDirs.addAll(module.getExcludeDirs()).remove(project.getBuildDir()); + File buildDir = project.getBuildDir(); + if (buildDir.isDirectory()) { + excludeDirs.addAll(project.getBuildDir().listFiles(new NonGeneratedDirectoryFileFilter())); } + module.setExcludeDirs(excludeDirs.build()); }); } @@ -114,12 +91,7 @@ private static GenerateAvroProtocolTask configureProtocolGenerationTask(final Pr task.setGroup(GROUP_SOURCE_GENERATION); task.source(getAvroSourceDir(project, sourceSet)); task.include("**/*." + IDL_EXTENSION); - task.getConventionMapping().map("outputDir", new Callable() { - @Override - public File call() throws Exception { - return getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION); - } - }); + configurePropertyConvention(task.getOutputDir(), getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION)); return task; } @@ -134,12 +106,7 @@ private static GenerateAvroJavaTask configureJavaGenerationTask(final Project pr task.source(protoTask.getOutputDir()); task.source(protoTask.getOutputs()); task.include("**/*." + SCHEMA_EXTENSION, "**/*." + PROTOCOL_EXTENSION); - task.getConventionMapping().map("outputDir", new Callable() { - @Override - public File call() throws Exception { - return getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION); - } - }); + configurePropertyConvention(task.getOutputDir(), getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION)); sourceSet.getJava().srcDir(task.getOutputDir()); @@ -148,49 +115,37 @@ public File call() throws Exception { compileJavaTask.source(task.getOutputs()); final AvroExtension avroExtension = project.getExtensions().findByType(AvroExtension.class); - ConventionMapping taskMapping = conventionMapping(task); - taskMapping.map(OPTION_OUTPUT_CHARACTER_ENCODING, new Callable() { - @Override - public String call() throws Exception { - String compilationEncoding = compileJavaTask.getOptions().getEncoding(); - String extensionEncoding = avroExtension.getOutputCharacterEncoding(); - return compilationEncoding != null ? compilationEncoding : extensionEncoding; - } - }); + + configurePropertyConvention(task.getOutputCharacterEncoding(), project.provider(() -> { + String compilationEncoding = compileJavaTask.getOptions().getEncoding(); + String extensionEncoding = avroExtension.getOutputCharacterEncoding().getOrNull(); + return compilationEncoding != null ? compilationEncoding : extensionEncoding; + })); return task; } private static void configureTaskDependencies(final Project project, final SourceSet sourceSet, final GenerateAvroJavaTask javaTask) { - project.getPluginManager().withPlugin("org.jetbrains.kotlin.jvm", new Action() { - @Override - public void execute(AppliedPlugin appliedPlugin) { - project.getTasks().matching(new Spec() { - @Override - public boolean isSatisfiedBy(Task task) { - String compilationTaskName = sourceSet.getCompileTaskName("kotlin"); - return compilationTaskName.equals(task.getName()); + project.getPluginManager().withPlugin("org.jetbrains.kotlin.jvm", appliedPlugin -> + project.getTasks().matching(task -> { + String compilationTaskName = sourceSet.getCompileTaskName("kotlin"); + return compilationTaskName.equals(task.getName()); + }) + .all(task -> { + if (task instanceof SourceTask) { + ((SourceTask) task).source(javaTask.getOutputs()); + } else { + task.dependsOn(javaTask); } - }) - .all(new Action() { - @Override - public void execute(Task task) { - if (task instanceof SourceTask) { - ((SourceTask) task).source(javaTask.getOutputs()); - } else { - task.dependsOn(javaTask); - } - } - }); - } - }); + })); } private static File getAvroSourceDir(Project project, SourceSet sourceSet) { return project.file(String.format("src/%s/avro", sourceSet.getName())); } - private static File getGeneratedOutputDir(Project project, SourceSet sourceSet, String extension) { - return new File(project.getBuildDir(), String.format("generated-%s-avro-%s", sourceSet.getName(), extension)); + private static Provider getGeneratedOutputDir(Project project, SourceSet sourceSet, String extension) { + String generatedOutputDirName = String.format("generated-%s-avro-%s", sourceSet.getName(), extension); + return project.getLayout().getBuildDirectory().dir(generatedOutputDirName); } private static JavaCompile getCompileJavaTask(Project project, SourceSet sourceSet) { @@ -209,14 +164,6 @@ private static SourceSet getTestSourceSet(Project project) { return getSourceSets(project).getByName(SourceSet.TEST_SOURCE_SET_NAME); } - private static ConventionMapping conventionMapping(Object conventionAware) { - // TODO: try other alternatives to convention mapping - // Convention mapping is an internal API. - // Other options here: - // http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api - return ((IConventionAware) conventionAware).getConventionMapping(); - } - private static class NonGeneratedDirectoryFileFilter implements FileFilter { @Override public boolean accept(File file) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index d2d0bd66114..4b7582cff3f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -18,7 +18,6 @@ import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; import org.apache.avro.generic.GenericData.StringType; -import org.gradle.api.plugins.JavaPlugin; /** * Various constants needed by the plugin. @@ -44,21 +43,7 @@ class Constants { static final String AVRO_EXTENSION_NAME = "avro"; - static final String OPTION_ENABLE_DECIMAL_LOGICAL_TYPE = "enableDecimalLogicalType"; - static final String OPTION_CREATE_SETTERS = "createSetters"; - static final String OPTION_TEMPLATE_DIRECTORY = "templateDirectory"; static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; - static final String OPTION_OUTPUT_CHARACTER_ENCODING = "outputCharacterEncoding"; static final String OPTION_DATE_TIME_LOGICAL_TYPE = "dateTimeLogicalType"; - - /** - * When our minimum supported version is 3.5+, we can remove this - */ - @SuppressWarnings("deprecation") - static final String RUNTIME_CONFIGURATION_NAME = JavaPlugin.RUNTIME_CONFIGURATION_NAME; - /** - * When our minimum supported version is 3.5+, we can use JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME - */ - static final String RUNTIME_CLASSPATH_CONFIGURATION_NAME = "runtimeClasspath"; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index fd6808b94ef..eeb951788a9 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -1,5 +1,5 @@ /** - * Copyright © 2013-2015 Commerce Technologies, LLC. + * Copyright © 2013-2019 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,25 +16,46 @@ package com.commercehub.gradle.plugin.avro; import java.nio.charset.Charset; +import javax.inject.Inject; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.generic.GenericData; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; + +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_DATE_TIME_LOGICAL_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; public class DefaultAvroExtension implements AvroExtension { - private String outputCharacterEncoding; - private String stringType; - private String fieldVisibility; - private String templateDirectory; - private boolean createSetters; - private boolean enableDecimalLogicalType; - private String dateTimeLogicalType; + private final Property outputCharacterEncoding; + private final Property stringType; + private final Property fieldVisibility; + private final Property templateDirectory; + private final Property createSetters; + private final Property enableDecimalLogicalType; + private final Property dateTimeLogicalType; + + @Inject + public DefaultAvroExtension(ObjectFactory objects) { + this.outputCharacterEncoding = objects.property(String.class); + this.stringType = configurePropertyConvention(objects.property(String.class), DEFAULT_STRING_TYPE); + this.fieldVisibility = configurePropertyConvention(objects.property(String.class), DEFAULT_FIELD_VISIBILITY); + this.templateDirectory = objects.property(String.class); + this.createSetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_SETTERS); + this.enableDecimalLogicalType = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); + this.dateTimeLogicalType = configurePropertyConvention(objects.property(String.class), DEFAULT_DATE_TIME_LOGICAL_TYPE); + } @Override - public String getOutputCharacterEncoding() { + public Property getOutputCharacterEncoding() { return outputCharacterEncoding; } public void setOutputCharacterEncoding(String outputCharacterEncoding) { - this.outputCharacterEncoding = outputCharacterEncoding; + this.outputCharacterEncoding.set(outputCharacterEncoding); } public void setOutputCharacterEncoding(Charset outputCharacterEncoding) { @@ -42,12 +63,12 @@ public void setOutputCharacterEncoding(Charset outputCharacterEncoding) { } @Override - public String getStringType() { + public Property getStringType() { return stringType; } public void setStringType(String stringType) { - this.stringType = stringType; + this.stringType.set(stringType); } public void setStringType(GenericData.StringType stringType) { @@ -55,12 +76,12 @@ public void setStringType(GenericData.StringType stringType) { } @Override - public String getFieldVisibility() { + public Property getFieldVisibility() { return fieldVisibility; } public void setFieldVisibility(String fieldVisibility) { - this.fieldVisibility = fieldVisibility; + this.fieldVisibility.set(fieldVisibility); } public void setFieldVisibility(SpecificCompiler.FieldVisibility fieldVisibility) { @@ -68,16 +89,16 @@ public void setFieldVisibility(SpecificCompiler.FieldVisibility fieldVisibility) } @Override - public String getTemplateDirectory() { + public Property getTemplateDirectory() { return templateDirectory; } public void setTemplateDirectory(String templateDirectory) { - this.templateDirectory = templateDirectory; + this.templateDirectory.set(templateDirectory); } @Override - public boolean isCreateSetters() { + public Property isCreateSetters() { return createSetters; } @@ -86,11 +107,11 @@ public void setCreateSetters(String createSetters) { } public void setCreateSetters(boolean createSetters) { - this.createSetters = createSetters; + this.createSetters.set(createSetters); } @Override - public boolean isEnableDecimalLogicalType() { + public Property isEnableDecimalLogicalType() { return enableDecimalLogicalType; } @@ -99,16 +120,16 @@ public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { } public void setEnableDecimalLogicalType(boolean enableDecimalLogicalType) { - this.enableDecimalLogicalType = enableDecimalLogicalType; + this.enableDecimalLogicalType.set(enableDecimalLogicalType); } @Override - public String getDateTimeLogicalType() { + public Property getDateTimeLogicalType() { return dateTimeLogicalType; } public void setDateTimeLogicalType(String dateTimeLogicalType) { - this.dateTimeLogicalType = dateTimeLogicalType; + this.dateTimeLogicalType.set(dateTimeLogicalType); } public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplementation dateTimeLogicalType) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java index 72599e350c2..5842861efae 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java @@ -26,11 +26,11 @@ class FileExtensionSpec implements Spec { private final Set extensions; FileExtensionSpec(String... extensions) { - this.extensions = new HashSet(Arrays.asList(extensions)); + this.extensions = new HashSet<>(Arrays.asList(extensions)); } FileExtensionSpec(Collection extensions) { - this.extensions = new HashSet(extensions); + this.extensions = new HashSet<>(extensions); } @Override diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java index c571b45669c..dc4b1ce647e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java @@ -23,7 +23,7 @@ class FileState implements Comparable { private final File file; private final String path; private String errorMessage; - private Set duplicateTypeNames = new TreeSet(); + private Set duplicateTypeNames = new TreeSet<>(); FileState(File file, String path) { this.file = file; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 077409edf69..d24e42b4981 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -1,5 +1,5 @@ /** - * Copyright © 2013-2015 Commerce Technologies, LLC. + * Copyright © 2013-2019 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.inject.Inject; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.apache.avro.SchemaParseException; @@ -31,6 +32,9 @@ import org.apache.avro.generic.GenericData.StringType; import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.Input; @@ -47,6 +51,7 @@ import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; /** @@ -59,26 +64,45 @@ public class GenerateAvroJavaTask extends OutputDirTask { private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); private static Set SUPPORTED_EXTENSIONS = new SetBuilder().add(PROTOCOL_EXTENSION).add(SCHEMA_EXTENSION).build(); - private String outputCharacterEncoding; - private String stringType = DEFAULT_STRING_TYPE; - private String fieldVisibility = DEFAULT_FIELD_VISIBILITY; - private String templateDirectory; - private boolean createSetters = DEFAULT_CREATE_SETTERS; - private boolean enableDecimalLogicalType = DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; - private String dateTimeLogicalType = DEFAULT_DATE_TIME_LOGICAL_TYPE; - - private transient StringType parsedStringType; - private transient FieldVisibility parsedFieldVisibility; - private transient SpecificCompiler.DateTimeLogicalTypeImplementation parsedDateTimeLogicalTypeImplementation; + private final Property outputCharacterEncoding; + private final Property stringType; + private final Property fieldVisibility; + private final Property templateDirectory; + private final Property createSetters; + private final Property enableDecimalLogicalType; + private final Property dateTimeLogicalType; + + private final Provider stringTypeProvider; + private final Provider fieldVisibilityProvider; + private final Provider dateTimeLogicalTypeImplementationProvider; + + @Inject + public GenerateAvroJavaTask(ObjectFactory objects) { + super(); + this.outputCharacterEncoding = objects.property(String.class); + this.stringType = configurePropertyConvention(objects.property(String.class), DEFAULT_STRING_TYPE); + this.fieldVisibility = configurePropertyConvention(objects.property(String.class), DEFAULT_FIELD_VISIBILITY); + this.templateDirectory = objects.property(String.class); + this.createSetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_SETTERS); + this.enableDecimalLogicalType = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); + this.dateTimeLogicalType = configurePropertyConvention(objects.property(String.class), DEFAULT_DATE_TIME_LOGICAL_TYPE); + this.stringTypeProvider = getStringType() + .map(input -> Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), input)); + this.fieldVisibilityProvider = getFieldVisibility() + .map(input -> Enums.parseCaseInsensitive(OPTION_FIELD_VISIBILITY, FieldVisibility.values(), input)); + this.dateTimeLogicalTypeImplementationProvider = getDateTimeLogicalType() + .map(input -> Enums.parseCaseInsensitive(OPTION_DATE_TIME_LOGICAL_TYPE, + SpecificCompiler.DateTimeLogicalTypeImplementation.values(), input)); + } @Optional @Input - public String getOutputCharacterEncoding() { + public Property getOutputCharacterEncoding() { return outputCharacterEncoding; } public void setOutputCharacterEncoding(String outputCharacterEncoding) { - this.outputCharacterEncoding = outputCharacterEncoding; + this.outputCharacterEncoding.set(outputCharacterEncoding); } public void setOutputCharacterEncoding(Charset outputCharacterEncoding) { @@ -86,7 +110,7 @@ public void setOutputCharacterEncoding(Charset outputCharacterEncoding) { } @Input - public String getStringType() { + public Property getStringType() { return stringType; } @@ -95,16 +119,16 @@ public void setStringType(GenericData.StringType stringType) { } public void setStringType(String stringType) { - this.stringType = stringType; + this.stringType.set(stringType); } @Input - public String getFieldVisibility() { + public Property getFieldVisibility() { return fieldVisibility; } public void setFieldVisibility(String fieldVisibility) { - this.fieldVisibility = fieldVisibility; + this.fieldVisibility.set(fieldVisibility); } public void setFieldVisibility(SpecificCompiler.FieldVisibility fieldVisibility) { @@ -113,40 +137,48 @@ public void setFieldVisibility(SpecificCompiler.FieldVisibility fieldVisibility) @Optional @Input - public String getTemplateDirectory() { + public Property getTemplateDirectory() { return templateDirectory; } public void setTemplateDirectory(String templateDirectory) { - this.templateDirectory = templateDirectory; + this.templateDirectory.set(templateDirectory); + } + + public Property isCreateSetters() { + return createSetters; } @Input - public boolean isCreateSetters() { + public Property getCreateSetters() { return createSetters; } public void setCreateSetters(String createSetters) { - this.createSetters = Boolean.parseBoolean(createSetters); + this.createSetters.set(Boolean.parseBoolean(createSetters)); + } + + public Property isEnableDecimalLogicalType() { + return enableDecimalLogicalType; } @Input - public boolean isEnableDecimalLogicalType() { + public Property getEnableDecimalLogicalType() { return enableDecimalLogicalType; } public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { - this.enableDecimalLogicalType = Boolean.parseBoolean(enableDecimalLogicalType); + this.enableDecimalLogicalType.set(Boolean.parseBoolean(enableDecimalLogicalType)); } @Optional @Input - public String getDateTimeLogicalType() { + public Property getDateTimeLogicalType() { return dateTimeLogicalType; } public void setDateTimeLogicalType(String dateTimeLogicalType) { - this.dateTimeLogicalType = dateTimeLogicalType; + this.dateTimeLogicalType.set(dateTimeLogicalType); } public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplementation dateTimeLogicalType) { @@ -155,28 +187,20 @@ public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplement @TaskAction protected void process() { - parsedStringType = Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), getStringType()); - parsedFieldVisibility = - Enums.parseCaseInsensitive(OPTION_FIELD_VISIBILITY, FieldVisibility.values(), getFieldVisibility()); - parsedDateTimeLogicalTypeImplementation = Enums.parseCaseInsensitive( - OPTION_DATE_TIME_LOGICAL_TYPE, - SpecificCompiler.DateTimeLogicalTypeImplementation.values(), getDateTimeLogicalType() - ); - - getLogger().debug("Using outputCharacterEncoding {}", getOutputCharacterEncoding()); - getLogger().debug("Using stringType {}", parsedStringType.name()); - getLogger().debug("Using fieldVisibility {}", parsedFieldVisibility.name()); - getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory()); - getLogger().debug("Using createSetters {}", isCreateSetters()); - getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType()); - getLogger().debug("Using dateTimeLogicalType {}", parsedDateTimeLogicalTypeImplementation.name()); + getLogger().debug("Using outputCharacterEncoding {}", getOutputCharacterEncoding().getOrNull()); + getLogger().debug("Using stringType {}", stringTypeProvider.get().name()); + getLogger().debug("Using fieldVisibility {}", fieldVisibilityProvider.get().name()); + getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory().getOrNull()); + getLogger().debug("Using createSetters {}", isCreateSetters().get()); + getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType().get()); + getLogger().debug("Using dateTimeLogicalType {}", dateTimeLogicalTypeImplementationProvider.get().name()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); processFiles(); } private void failOnUnsupportedFiles() { - FileCollection unsupportedFiles = filterSources(new NotSpec(new FileExtensionSpec(SUPPORTED_EXTENSIONS))); + FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(SUPPORTED_EXTENSIONS))); if (!unsupportedFiles.isEmpty()) { throw new GradleException( String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); @@ -277,24 +301,23 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt } private void compile(Protocol protocol, File sourceFile) throws IOException { - compile(new SpecificCompiler(protocol, parsedDateTimeLogicalTypeImplementation), sourceFile); + compile(new SpecificCompiler(protocol, dateTimeLogicalTypeImplementationProvider.get()), sourceFile); } private void compile(Schema schema, File sourceFile) throws IOException { - compile(new SpecificCompiler(schema, parsedDateTimeLogicalTypeImplementation), sourceFile); + compile(new SpecificCompiler(schema, dateTimeLogicalTypeImplementationProvider.get()), sourceFile); } private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { - String configuredTemplateDirectory = getTemplateDirectory(); - compiler.setOutputCharacterEncoding(getOutputCharacterEncoding()); - compiler.setStringType(parsedStringType); - compiler.setFieldVisibility(parsedFieldVisibility); - if (configuredTemplateDirectory != null) { - compiler.setTemplateDir(configuredTemplateDirectory); + compiler.setOutputCharacterEncoding(getOutputCharacterEncoding().getOrNull()); + compiler.setStringType(stringTypeProvider.get()); + compiler.setFieldVisibility(fieldVisibilityProvider.get()); + if (getTemplateDirectory().isPresent()) { + compiler.setTemplateDir(getTemplateDirectory().get()); } - compiler.setCreateSetters(isCreateSetters()); - compiler.setEnableDecimalLogicalType(isEnableDecimalLogicalType()); + compiler.setCreateSetters(isCreateSetters().get()); + compiler.setEnableDecimalLogicalType(isEnableDecimalLogicalType().get()); - compiler.compileToDestination(sourceFile, getOutputDir()); + compiler.compileToDestination(sourceFile, getOutputDir().get().getAsFile()); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 136c13a7497..3c2a0f144ad 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -1,5 +1,5 @@ /** - * Copyright © 2013-2015 Commerce Technologies, LLC. + * Copyright © 2013-2019 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,10 +29,10 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.UnknownConfigurationException; import org.gradle.api.file.FileCollection; +import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.TaskAction; -import org.gradle.util.GradleVersion; import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; @@ -69,7 +69,7 @@ private void processFiles() { private void processIDLFile(File idlFile, ClassLoader loader) { getLogger().info("Processing {}", idlFile); - File protoFile = new File(getOutputDir(), + File protoFile = new File(getOutputDir().get().getAsFile(), FilenameUtils.getBaseName(idlFile.getName()) + "." + PROTOCOL_EXTENSION); Idl idl = null; try { @@ -92,7 +92,7 @@ private void processIDLFile(File idlFile, ClassLoader loader) { private ClassLoader getRuntimeClassLoader(Project project) { List urls = new LinkedList<>(); - String configurationName = getRuntimeConfigurationName(); + String configurationName = JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME; try { Configuration configuration = project.getConfigurations().getByName(configurationName); for (File file : configuration) { @@ -106,14 +106,6 @@ private ClassLoader getRuntimeClassLoader(Project project) { getLogger().debug("No configuration found with name {}; defaulting to system classloader", configurationName); } return urls.isEmpty() ? ClassLoader.getSystemClassLoader() - : new URLClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader()); - } - - /** - * Backwards-compatible logic to return the appropriate configuration name for resolving the runtime classpath - */ - private static String getRuntimeConfigurationName() { - return GradleVersion.current().compareTo(GradleVersion.version("3.5")) >= 0 - ? Constants.RUNTIME_CLASSPATH_CONFIGURATION_NAME : Constants.RUNTIME_CONFIGURATION_NAME; + : new URLClassLoader(urls.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java index 66ace4fc168..931f1dbcaef 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Commerce Technologies, LLC. + * Copyright © 2018-2019 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ private void processProtoFile(File sourceFile) { Protocol protocol = Protocol.parse(sourceFile); for (Schema schema : protocol.getTypes()) { String path = schema.getNamespace().replaceAll(Pattern.quote("."), "/"); - File schemaFile = new File(getOutputDir(), path + "/" + schema.getName() + "." + SCHEMA_EXTENSION); + File schemaFile = new File(getOutputDir().get().getAsFile(), path + "/" + schema.getName() + "." + SCHEMA_EXTENSION); String schemaJson = schema.toString(true); FileUtils.writeJsonFile(schemaFile, schemaJson); getLogger().debug("Wrote {}", schemaFile.getPath()); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java new file mode 100644 index 00000000000..7fab730b8e3 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java @@ -0,0 +1,59 @@ +/* + * Copyright © 2019 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; + +import org.gradle.api.Project; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; + +class GradleCompatibility { + static T createExtensionWithObjectFactory(Project project, String extensionName, Class extensionType) { + if (GradleFeatures.extensionInjection.isSupported()) { + return project.getExtensions().create(extensionName, extensionType); + } else { + return project.getExtensions().create(extensionName, extensionType, project.getObjects()); + } + } + + @SuppressWarnings("deprecation") + static DirectoryProperty createDirectoryProperty(Project project) { + if (GradleFeatures.objectFactoryDirectoryProperty.isSupported()) { + return project.getObjects().directoryProperty(); + } else { + return project.getLayout().directoryProperty(); + } + } + + static Property configurePropertyConvention(Property property, Provider valueProvider) { + if (GradleFeatures.propertyConventions.isSupported()) { + property.convention(valueProvider); + } else { + property.set(valueProvider); + } + return property; + } + + static Property configurePropertyConvention(Property property, T value) { + if (GradleFeatures.propertyConventions.isSupported()) { + property.convention(value); + } else { + property.set(value); + } + return property; + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java new file mode 100644 index 00000000000..18f875e7f41 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java @@ -0,0 +1,42 @@ +/* + * Copyright © 2019 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; + +import org.gradle.util.GradleVersion; + +enum GradleFeatures { + extensionInjection() { + @Override + boolean isSupported() { + return GradleVersion.current().compareTo(GradleVersions.v5_2) >= 0; + } + }, + propertyConventions() { + @Override + boolean isSupported() { + return GradleVersion.current().compareTo(GradleVersions.v5_1) >= 0; + } + }, + objectFactoryDirectoryProperty() { + @Override + boolean isSupported() { + return GradleVersion.current().compareTo(GradleVersions.v5_0) >= 0; + } + }; + + abstract boolean isSupported(); +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java new file mode 100644 index 00000000000..cb44c1791f7 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java @@ -0,0 +1,25 @@ +/* + * Copyright © 2019 Commerce Technologies, LLC. + * + * 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 com.commercehub.gradle.plugin.avro; + +import org.gradle.util.GradleVersion; + +class GradleVersions { + static final GradleVersion v5_0 = GradleVersion.version("5.0"); + static final GradleVersion v5_1 = GradleVersion.version("5.1"); + static final GradleVersion v5_2 = GradleVersion.version("5.2"); +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java index 13ab11542e7..6140775fb7f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java @@ -1,5 +1,5 @@ /** - * Copyright © 2013 Commerce Technologies, LLC. + * Copyright © 2013-2019 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package com.commercehub.gradle.plugin.avro; import java.io.File; +import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTree; import org.gradle.api.specs.Spec; @@ -23,13 +24,18 @@ import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.SourceTask; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.createDirectoryProperty; import static org.gradle.api.tasks.PathSensitivity.RELATIVE; class OutputDirTask extends SourceTask { - private File outputDir; + private final DirectoryProperty outputDir; + + protected OutputDirTask() { + this.outputDir = createDirectoryProperty(getProject()); + } public void setOutputDir(File outputDir) { - this.outputDir = outputDir; + this.outputDir.set(outputDir); getOutputs().dir(outputDir); } @@ -39,7 +45,7 @@ public FileTree getSource() { } @OutputDirectory - protected File getOutputDir() { + protected DirectoryProperty getOutputDir() { return outputDir; } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy index ac8478269c1..531fc568dcb 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright © 2013-2015 Commerce Technologies, LLC. + * Copyright © 2013-2019 Commerce Technologies, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,8 +33,8 @@ class AvroPluginSpec extends Specification { mainGenerateAvroProtoTask.group == Constants.GROUP_SOURCE_GENERATION testGenerateAvroProtoTask.group == Constants.GROUP_SOURCE_GENERATION // Can't easily test the sources - mainGenerateAvroProtoTask.outputDir == project.file("build/generated-main-avro-avpr") - testGenerateAvroProtoTask.outputDir == project.file("build/generated-test-avro-avpr") + mainGenerateAvroProtoTask.outputDir.get().asFile == project.file("build/generated-main-avro-avpr") + testGenerateAvroProtoTask.outputDir.get().asFile == project.file("build/generated-test-avro-avpr") } def "avro java generation tasks are registered"() { @@ -48,8 +48,8 @@ class AvroPluginSpec extends Specification { mainGenerateAvroJavaTask.group == Constants.GROUP_SOURCE_GENERATION testGenerateAvroJavaTask.group == Constants.GROUP_SOURCE_GENERATION // Can't easily test the sources - mainGenerateAvroJavaTask.outputDir == project.file("build/generated-main-avro-java") - testGenerateAvroJavaTask.outputDir == project.file("build/generated-test-avro-java") + mainGenerateAvroJavaTask.outputDir.get().asFile == project.file("build/generated-main-avro-java") + testGenerateAvroJavaTask.outputDir.get().asFile == project.file("build/generated-test-avro-java") } OutputDirTask getTask(String name) { From 475622792483a1ce07b7795cef2671dd8ad0408d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 5 Sep 2019 09:45:33 -0400 Subject: [PATCH 246/479] Remove .gitlab-ci.yml It was inaccurate (still had a java 7 job even though it isn't supported) and not really used. --- .gitlab-ci.yml | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 303ce2d7e80..00000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,50 +0,0 @@ -.job_template: &job_definition - variables: - GRADLE_OPTS: "-Xmx386m -Xms386m" - script: - - echo PATH = ${PATH} - - echo JAVA_HOME = ${JAVA_HOME} - - java -Xmx32m -version - - ./gradlew build testRecentVersionCompatibility --info - -openjdk7: - <<: *job_definition - image: openjdk:7-jdk - before_script: # Workaround for https://github.com/travis-ci/travis-ci/issues/8503 - - sed -i 's/security.provider.9/#security.provider.9/g' $JAVA_HOME/jre/lib/security/java.security - variables: - GRADLE_OPTS: "-Xmx386m -Xms386m -XX:MaxPermSize=128m" # Java 7 still uses separate permgen - -openjdk8: - <<: *job_definition - image: openjdk:8-jdk - -openjdk9: - <<: *job_definition - image: openjdk:9-jdk - -openjdk10: - <<: *job_definition - image: openjdk:10-jdk - -openjdk11: - <<: *job_definition - image: openjdk:11-jdk - - -code_quality: - image: docker:stable - variables: - DOCKER_DRIVER: overlay2 - allow_failure: true - services: - - docker:stable-dind - script: - - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') - - docker run - --env SOURCE_CODE="$PWD" - --volume "$PWD":/code - --volume /var/run/docker.sock:/var/run/docker.sock - "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code - artifacts: - paths: [gl-code-quality-report.json] From fc237bd562dd1155d8b300590b5bf3a2e2fa8043 Mon Sep 17 00:00:00 2001 From: Raman Gupta Date: Sun, 15 Sep 2019 00:58:53 -0400 Subject: [PATCH 247/479] Avro 1.9.0 -> 1.9.1 Fixes #84 --- CHANGES.md | 1 + README.md | 8 ++++---- build.gradle | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a739a8de0de..883b75c7a2b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ * Upgrade Codenarc from 1.0 to 1.4 and adjust rules used * Change source compatibility to 8 * Modernized for Java 8 +* Avro 1.9.0 -> 1.9.1 ## 0.17.0 * Built using Avro 1.9.0 diff --git a/README.md b/README.md index f3fa9d9e4e8..52ffc60dd0f 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Gradle 4.4-4.10.3 and 5.0-5.6 * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Avro 1.9.0 - * Currently tested against Avro 1.9.0 +* Currently built against Avro 1.9.1 + * Currently tested against Avro 1.9.1 * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) @@ -50,7 +50,7 @@ repositories { jcenter() } dependencies { - compile "org.apache.avro:avro:1.9.0" + compile "org.apache.avro:avro:1.9.1" } ``` @@ -217,7 +217,7 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - compile "org.apache.avro:avro:1.9.0" + compile "org.apache.avro:avro:1.9.1" } task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { diff --git a/build.gradle b/build.gradle index be74bae3229..ad7c2461043 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ repositories { jcenter() } -def compileAvroVersion = "1.9.0" +def compileAvroVersion = "1.9.1" dependencies { compile localGroovy() @@ -176,11 +176,11 @@ test { ] } -// Java 8+ is required due to Avro 1.9.0 requirements +// Java 8+ is required due to Avro 1.9+ requirements // Java 8+ is also required by Gradle 5.x sourceCompatibility = 8 -def avroVersions = ["1.9.0"] +def avroVersions = ["1.9.1"] def gradleVersions = [] if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 appears to be the first version that supports Java 11, as per https://github.com/gradle/gradle/pull/4759 and testing gradleVersions.addAll("4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") From be010df7829d10deaadd1ec49384b35afaf9e569 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 16 Sep 2019 14:17:59 -0400 Subject: [PATCH 248/479] Restore Avro 1.9.0 compatibility testing --- CHANGES.md | 2 +- README.md | 2 +- build.gradle | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 883b75c7a2b..7d3da186a61 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ * Upgrade Codenarc from 1.0 to 1.4 and adjust rules used * Change source compatibility to 8 * Modernized for Java 8 -* Avro 1.9.0 -> 1.9.1 +* Built using Avro 1.9.1 ## 0.17.0 * Built using Avro 1.9.0 diff --git a/README.md b/README.md index 52ffc60dd0f..ed3d8fb6c48 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Avro 1.9.1 - * Currently tested against Avro 1.9.1 + * Currently tested against Avro 1.9.0-1.9.1 * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) diff --git a/build.gradle b/build.gradle index ad7c2461043..e0bf7b3d74a 100644 --- a/build.gradle +++ b/build.gradle @@ -176,11 +176,11 @@ test { ] } -// Java 8+ is required due to Avro 1.9+ requirements +// Java 8+ is required due to requirements introduced in Avro 1.9.0 // Java 8+ is also required by Gradle 5.x sourceCompatibility = 8 -def avroVersions = ["1.9.1"] +def avroVersions = ["1.9.0", "1.9.1"] def gradleVersions = [] if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 appears to be the first version that supports Java 11, as per https://github.com/gradle/gradle/pull/4759 and testing gradleVersions.addAll("4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") From 8a1d05b65c337d4e3e791445c631c5a8816e3892 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 13 Oct 2019 23:53:51 -0400 Subject: [PATCH 249/479] Adjust GenerateAvroProtocolTask to properly declare classpath inputs Fixes #86 Also introduces new configurable property `classpath` to the task --- CHANGES.md | 2 + .../gradle/plugin/avro/AvroPlugin.java | 2 + .../plugin/avro/GenerateAvroProtocolTask.java | 60 +++++++------- .../plugin/avro/GradleCompatibility.java | 12 +++ .../gradle/plugin/avro/GradleFeatures.java | 12 +++ .../gradle/plugin/avro/GradleVersions.java | 2 + ...erateAvroProtocolTaskFunctionalSpec.groovy | 78 +++++++++++++++++++ .../gradle/plugin/avro/dependent.avdl | 26 +++++++ .../gradle/plugin/avro/shared.avdl | 23 ++++++ 9 files changed, 189 insertions(+), 28 deletions(-) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/dependent.avdl create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/shared.avdl diff --git a/CHANGES.md b/CHANGES.md index 7d3da186a61..e70b1fe7f08 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,8 @@ * Change source compatibility to 8 * Modernized for Java 8 * Built using Avro 1.9.1 +* GenerateAvroProtocolTask now has a `classpath` property; defaults to the runtime configuration when the Avro plugin is applied +* GenerateAvroProtocolTask now properly declares the `classpath` as an input; fixes #86; thanks to [RichSteele](https://github.com/RichSteele) for the bug report ## 0.17.0 * Built using Avro 1.9.0 diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 949e051e325..47c19a55110 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -37,6 +37,7 @@ import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; +import static org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME; public class AvroPlugin implements Plugin { @Override @@ -91,6 +92,7 @@ private static GenerateAvroProtocolTask configureProtocolGenerationTask(final Pr task.setGroup(GROUP_SOURCE_GENERATION); task.source(getAvroSourceDir(project, sourceSet)); task.include("**/*." + IDL_EXTENSION); + task.setClasspath(project.getConfigurations().getByName(RUNTIME_CLASSPATH_CONFIGURATION_NAME)); configurePropertyConvention(task.getOutputDir(), getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION)); return task; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 3c2a0f144ad..1c7e9c812f9 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -25,13 +25,10 @@ import org.apache.avro.compiler.idl.Idl; import org.apache.avro.compiler.idl.ParseException; import org.gradle.api.GradleException; -import org.gradle.api.Project; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.UnknownConfigurationException; import org.gradle.api.file.FileCollection; -import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.TaskAction; import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; @@ -42,6 +39,26 @@ */ @CacheableTask public class GenerateAvroProtocolTask extends OutputDirTask { + @InputFiles + private FileCollection classpath; + + public GenerateAvroProtocolTask() { + super(); + this.classpath = GradleCompatibility.createConfigurableFileCollection(getProject()); + } + + public void setClasspath(FileCollection classpath) { + this.classpath = classpath; + } + + public void classpath(Object... paths) { + this.classpath.plus(getProject().files(paths)); + } + + public FileCollection getClasspath() { + return this.classpath; + } + @TaskAction protected void process() { getLogger().info("Found {} files", getSource().getFiles().size()); @@ -59,7 +76,7 @@ private void failOnUnsupportedFiles() { private void processFiles() { int processedFileCount = 0; - ClassLoader loader = getRuntimeClassLoader(getProject()); + ClassLoader loader = assembleClassLoader(); for (File sourceFile : filterSources(new FileExtensionSpec(IDL_EXTENSION))) { processIDLFile(sourceFile, loader); processedFileCount++; @@ -71,39 +88,26 @@ private void processIDLFile(File idlFile, ClassLoader loader) { getLogger().info("Processing {}", idlFile); File protoFile = new File(getOutputDir().get().getAsFile(), FilenameUtils.getBaseName(idlFile.getName()) + "." + PROTOCOL_EXTENSION); - Idl idl = null; - try { - idl = new Idl(idlFile, loader); + try (Idl idl = new Idl(idlFile, loader)) { String protoJson = idl.CompilationUnit().toString(true); FileUtils.writeJsonFile(protoFile, protoJson); getLogger().debug("Wrote {}", protoFile.getPath()); } catch (IOException | ParseException ex) { throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); - } finally { - if (idl != null) { - try { - idl.close(); - } catch (IOException ioe) { - // ignore - } - } } } - private ClassLoader getRuntimeClassLoader(Project project) { + private ClassLoader assembleClassLoader() { List urls = new LinkedList<>(); - String configurationName = JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME; - try { - Configuration configuration = project.getConfigurations().getByName(configurationName); - for (File file : configuration) { - try { - urls.add(file.toURI().toURL()); - } catch (MalformedURLException e) { - getLogger().debug(e.getMessage()); - } + for (File file : classpath) { + try { + urls.add(file.toURI().toURL()); + } catch (MalformedURLException e) { + getLogger().debug(e.getMessage()); } - } catch (UnknownConfigurationException ex) { - getLogger().debug("No configuration found with name {}; defaulting to system classloader", configurationName); + } + if (urls.isEmpty()) { + getLogger().debug("No classpath configured; defaulting to system classloader"); } return urls.isEmpty() ? ClassLoader.getSystemClassLoader() : new URLClassLoader(urls.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java index 7fab730b8e3..3a019c86e59 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java @@ -17,6 +17,7 @@ package com.commercehub.gradle.plugin.avro; import org.gradle.api.Project; +import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -39,6 +40,17 @@ static DirectoryProperty createDirectoryProperty(Project project) { } } + @SuppressWarnings("deprecation") + static ConfigurableFileCollection createConfigurableFileCollection(Project project) { + if (GradleFeatures.objectFactoryFileCollection.isSupported()) { + return project.getObjects().fileCollection(); + } else if (GradleFeatures.projectLayoutConfigurableFiles.isSupported()) { + return project.getLayout().configurableFiles(); + } else { + return project.files(); + } + } + static Property configurePropertyConvention(Property property, Provider valueProvider) { if (GradleFeatures.propertyConventions.isSupported()) { property.convention(valueProvider); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java index 18f875e7f41..ea096ca605d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java @@ -36,6 +36,18 @@ boolean isSupported() { boolean isSupported() { return GradleVersion.current().compareTo(GradleVersions.v5_0) >= 0; } + }, + projectLayoutConfigurableFiles() { + @Override + boolean isSupported() { + return GradleVersion.current().compareTo(GradleVersions.v4_8) >= 0; + } + }, + objectFactoryFileCollection() { + @Override + boolean isSupported() { + return GradleVersion.current().compareTo(GradleVersions.v5_3) >= 0; + } }; abstract boolean isSupported(); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java index cb44c1791f7..fb962241234 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java @@ -19,7 +19,9 @@ import org.gradle.util.GradleVersion; class GradleVersions { + static final GradleVersion v4_8 = GradleVersion.version("4.8"); static final GradleVersion v5_0 = GradleVersion.version("5.0"); static final GradleVersion v5_1 = GradleVersion.version("5.1"); static final GradleVersion v5_2 = GradleVersion.version("5.2"); + static final GradleVersion v5_3 = GradleVersion.version("5.3"); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy new file mode 100644 index 00000000000..527a8616485 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy @@ -0,0 +1,78 @@ +/* + * Copyright © 2019 David M. Carr + * + * 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 com.commercehub.gradle.plugin.avro + +import spock.lang.Subject + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +@Subject(GenerateAvroProtocolTask) +class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { + def "With base plugin, declares input on classpath"() { + given: "a build that declares another task's output in the classpath" + applyAvroBasePlugin() + buildFile << """ + apply plugin: "java" // Jar task appears to only work with the java plugin applied + configurations.create("shared") + task sharedIdlJar(type: Jar) { + from "src/shared" + } + dependencies { + shared sharedIdlJar.outputs.files + } + task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + classpath = configurations.shared + source file("src/dependent") + outputDir = file("build/protocol") + } + """ + + copyResource("shared.avdl", testProjectDir.newFolder("src", "shared")) + copyResource("dependent.avdl", testProjectDir.newFolder("src", "dependent")) + + when: "running the task" + def result = run("generateProtocol") + + then: "running the generate protocol task occurs after running the producing task" + result.tasks*.path == [":sharedIdlJar", ":generateProtocol"] + taskInfoAbsent || result.task(":generateProtocol").outcome == SUCCESS + projectFile("build/protocol/dependent.avpr").file + } + + def "With avro plugin, declares input on classpath (runtime configuration by default)"() { + given: "a build that declares another task's output in the classpath" + applyAvroPlugin() + buildFile << """ + task sharedIdlJar(type: Jar) { + from "src/shared" + } + dependencies { + runtime sharedIdlJar.outputs.files + } + """ + + copyResource("shared.avdl", testProjectDir.newFolder("src", "shared")) + copyResource("dependent.avdl", avroDir) + + when: "running the task" + def result = run("generateAvroProtocol") + + then: "running the generate protocol task occurs after running the producing task" + result.tasks*.path == [":sharedIdlJar", ":generateAvroProtocol"] + taskInfoAbsent || result.task(":generateAvroProtocol").outcome == SUCCESS + projectFile("build/generated-main-avro-avpr/dependent.avpr").file + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/dependent.avdl b/src/test/resources/com/commercehub/gradle/plugin/avro/dependent.avdl new file mode 100644 index 00000000000..c2ef56b1464 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/dependent.avdl @@ -0,0 +1,26 @@ +/** + * Copyright 2019 Paychex, Inc. + * Licensed pursuant to the terms of the Apache License, Version 2.0 (the "License"); + * your use of the Work is subject to the terms and conditions of the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor + * provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, + * without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible + * for determining the appropriateness of using or redistributing the Work and assume + * any risks associated with your exercise of permissions under this License. + */ + +@namespace("com.example.dependent") +protocol DependentProtocol { + + import idl "shared.avdl"; + + record ThisDependsOnTemporal { + com.example.shared.SomethingShared a; + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/shared.avdl b/src/test/resources/com/commercehub/gradle/plugin/avro/shared.avdl new file mode 100644 index 00000000000..b1c4f4dfb7b --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/shared.avdl @@ -0,0 +1,23 @@ +/** + * Copyright 2019 Paychex, Inc. + * Licensed pursuant to the terms of the Apache License, Version 2.0 (the "License"); + * your use of the Work is subject to the terms and conditions of the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor + * provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, + * without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible + * for determining the appropriateness of using or redistributing the Work and assume + * any risks associated with your exercise of permissions under this License. + */ + +@namespace("com.example.shared") +protocol SharedProtocol { + record SomethingShared { + string greeting; + } +} From 1debd40d049436ec3dbd34a6182bee46809e23ef Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 00:17:15 -0400 Subject: [PATCH 250/479] Update gradle to 5.6.2 --- CHANGES.md | 2 +- README.md | 4 ++-- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e70b1fe7f08..4361f05b3d4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ * Eliminate usage of internal conventions API, using new Lazy Configuration approach instead; requires Gradle 4.4+ * Technically, the APIs needed are available in Gradle 4.3, but there is a bug related to un-set `Property` instances in 4.3 and 4.3.1; see https://github.com/gradle/gradle/issues/3879 * Cleaned up compatibility code for older versions of Gradle -* Built using Gradle 5.6 +* Built using Gradle 5.6.2 * Upgrade Spock from 1.2 to 1.3 * Upgrade Checkstyle from 6.1.1 to 8.23 and adjust rules used * Upgrade Codenarc from 1.0 to 1.4 and adjust rules used diff --git a/README.md b/README.md index ed3d8fb6c48..d8080bcdf97 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 11 support requires Gradle 4.8 or higher * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Gradle 5.6 - * Currently tested against Gradle 4.4-4.10.3 and 5.0-5.6 +* Currently built against Gradle 5.6.2 + * Currently tested against Gradle 4.4-4.10.3 and 5.0-5.6.2 * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Avro 1.9.1 diff --git a/build.gradle b/build.gradle index e0bf7b3d74a..a44ab9edcab 100644 --- a/build.gradle +++ b/build.gradle @@ -186,7 +186,7 @@ if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 gradleVersions.addAll("4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") } gradleVersions.addAll("4.8", "4.8.1", "4.9", "4.10", "4.10.1", "4.10.2", "4.10.3") -gradleVersions.addAll("5.0", "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6") +gradleVersions.addAll("5.0", "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2") avroVersions.each { def avroVersion -> diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ef9a9e05e4c..7c4388a9216 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-5.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From ef581e64936d32d82ba353152185d30aeff03847 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 21:47:32 -0400 Subject: [PATCH 251/479] Try a simple github actions CI job --- .github/workflows/ci.yml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..92088ebfb86 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,39 @@ +name: CI build +on: [push] +jobs: + build: + name: Baseline build (Java 8 on ubuntu-18.04) + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v1 + - name: Set up Java 8 + uses: actions/setup-java@v1 + with: + java-version: 8.0.222 + architecture: x64 + - name: Java version + run: java -version + - name: Gradle version + run: ./gradlew --version + - name: Build with Gradle + run: ./gradlew build --info + # compatibility-tests: + # name: Compatibility tests (Java ${{ matrix.java }} on ${{ matrix.os }}) + # runs-on: ${{ matrix.os }} + # strategy: + # matrix: + # os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] + # java: [8.0.222, 11.0.4, 13.0.0] + # steps: + # - uses: actions/checkout@v1 + # - name: Set up JDK + # uses: actions/setup-java@v1 + # with: + # java-version: ${{ matrix.java }} + # architecture: x64 + # - name: Java version + # run: java -version + # - name: Gradle version + # run: ./gradlew --version + # - name: Run version compatibility tests + # run: ./gradlew testRecentVersionCompatibility --info From daefa67f955b27cb1229718147fc9a7c51caa262 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 21:58:16 -0400 Subject: [PATCH 252/479] Try again with github actions --- .github/workflows/ci.yml | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92088ebfb86..2bb191c1d97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,39 +1,44 @@ name: CI build -on: [push] +on: [push, pull_request] jobs: build: name: Baseline build (Java 8 on ubuntu-18.04) runs-on: ubuntu-18.04 steps: - - uses: actions/checkout@v1 + - name: Check out repository + uses: actions/checkout@v1 - name: Set up Java 8 uses: actions/setup-java@v1 with: java-version: 8.0.222 architecture: x64 - - name: Java version + - name: Output Java version run: java -version - - name: Gradle version + - name: Output Gradle version run: ./gradlew --version - name: Build with Gradle run: ./gradlew build --info - # compatibility-tests: - # name: Compatibility tests (Java ${{ matrix.java }} on ${{ matrix.os }}) + #compatibility-tests: + # name: Compatibility tests (Java ${{ matrix.java }} on ${{ matrix.os }}) + # needs: [build] # runs-on: ${{ matrix.os }} # strategy: # matrix: # os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] # java: [8.0.222, 11.0.4, 13.0.0] + # fail-fast: true + # max-parallel: 5 # steps: - # - uses: actions/checkout@v1 - # - name: Set up JDK + # - name: Check out repository + # uses: actions/checkout@v1 + # - name: Set up Java ${{ matrix.java }} # uses: actions/setup-java@v1 # with: # java-version: ${{ matrix.java }} # architecture: x64 - # - name: Java version + # - name: Output Java version # run: java -version - # - name: Gradle version + # - name: Output Gradle version # run: ./gradlew --version # - name: Run version compatibility tests # run: ./gradlew testRecentVersionCompatibility --info From 86b304f3ef5344572eadb8bbaf9dba1a453797e0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 22:03:16 -0400 Subject: [PATCH 253/479] Adjust CI output --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bb191c1d97..51a24a419c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,9 +15,9 @@ jobs: - name: Output Java version run: java -version - name: Output Gradle version - run: ./gradlew --version + run: ./gradlew --quiet --version - name: Build with Gradle - run: ./gradlew build --info + run: ./gradlew build #compatibility-tests: # name: Compatibility tests (Java ${{ matrix.java }} on ${{ matrix.os }}) # needs: [build] @@ -39,6 +39,6 @@ jobs: # - name: Output Java version # run: java -version # - name: Output Gradle version - # run: ./gradlew --version + # run: ./gradlew --quiet --version # - name: Run version compatibility tests - # run: ./gradlew testRecentVersionCompatibility --info + # run: ./gradlew testRecentVersionCompatibility From 482f4574c7dbd948ab4d3e662bcc22c54b5ff577 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 22:05:59 -0400 Subject: [PATCH 254/479] Try again to avoid gradle welcome banner in CI --- .github/workflows/ci.yml | 4 ++-- gradle.properties | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51a24a419c9..3763374620b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: - name: Output Java version run: java -version - name: Output Gradle version - run: ./gradlew --quiet --version + run: ./gradlew --version - name: Build with Gradle run: ./gradlew build #compatibility-tests: @@ -39,6 +39,6 @@ jobs: # - name: Output Java version # run: java -version # - name: Output Gradle version - # run: ./gradlew --quiet --version + # run: ./gradlew --version # - name: Run version compatibility tests # run: ./gradlew testRecentVersionCompatibility diff --git a/gradle.properties b/gradle.properties index 55a902b413b..f5b0e963282 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ org.gradle.warning.mode=all +systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false From a89d14d128c0dca2365cf2d916a99983aca8be42 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 22:13:05 -0400 Subject: [PATCH 255/479] ci: try turning on github actions compatibility tests --- .github/workflows/ci.yml | 48 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3763374620b..88227130efb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,27 +18,27 @@ jobs: run: ./gradlew --version - name: Build with Gradle run: ./gradlew build - #compatibility-tests: - # name: Compatibility tests (Java ${{ matrix.java }} on ${{ matrix.os }}) - # needs: [build] - # runs-on: ${{ matrix.os }} - # strategy: - # matrix: - # os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] - # java: [8.0.222, 11.0.4, 13.0.0] - # fail-fast: true - # max-parallel: 5 - # steps: - # - name: Check out repository - # uses: actions/checkout@v1 - # - name: Set up Java ${{ matrix.java }} - # uses: actions/setup-java@v1 - # with: - # java-version: ${{ matrix.java }} - # architecture: x64 - # - name: Output Java version - # run: java -version - # - name: Output Gradle version - # run: ./gradlew --version - # - name: Run version compatibility tests - # run: ./gradlew testRecentVersionCompatibility + compatibility-tests: + name: Compatibility tests (Java ${{ matrix.java }} on ${{ matrix.os }}) + needs: [build] + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] + java: [8.0.222, 11.0.4] # TODO: 13.0.0 + fail-fast: true + max-parallel: 5 + steps: + - name: Check out repository + uses: actions/checkout@v1 + - name: Set up Java ${{ matrix.java }} + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + architecture: x64 + - name: Output Java version + run: java -version + - name: Output Gradle version + run: ./gradlew --version + - name: Run version compatibility tests + run: ./gradlew testRecentVersionCompatibility From bc0e04721f8a0c04a9859a290be9519db12eb53e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 22:13:39 -0400 Subject: [PATCH 256/479] fix ci syntax --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88227130efb..71299f38e60 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,8 +19,8 @@ jobs: - name: Build with Gradle run: ./gradlew build compatibility-tests: - name: Compatibility tests (Java ${{ matrix.java }} on ${{ matrix.os }}) - needs: [build] + name: Compatibility tests (Java ${{ matrix.java }} on ${{ matrix.os }}) + needs: [build] runs-on: ${{ matrix.os }} strategy: matrix: From 16f12131b35350be3bb5f479700614230d6b6856 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 22:14:41 -0400 Subject: [PATCH 257/479] ci: fix yaml indentation --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71299f38e60..b09692bafad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,8 +29,8 @@ jobs: fail-fast: true max-parallel: 5 steps: - - name: Check out repository - uses: actions/checkout@v1 + - name: Check out repository + uses: actions/checkout@v1 - name: Set up Java ${{ matrix.java }} uses: actions/setup-java@v1 with: From 60240138be98bde108dddce9516a31af88f2dcd9 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 22:16:05 -0400 Subject: [PATCH 258/479] ci: comment out fail fast --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b09692bafad..71c14a9882f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: matrix: os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] java: [8.0.222, 11.0.4] # TODO: 13.0.0 - fail-fast: true + # fail-fast: true max-parallel: 5 steps: - name: Check out repository From f6addc81178cb335590042896669a1db2785a200 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 22:17:01 -0400 Subject: [PATCH 259/479] ci: fix matrix structure --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71c14a9882f..eedf2bb0d49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,8 +26,8 @@ jobs: matrix: os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] java: [8.0.222, 11.0.4] # TODO: 13.0.0 - # fail-fast: true - max-parallel: 5 + fail-fast: true + max-parallel: 5 steps: - name: Check out repository uses: actions/checkout@v1 From 4e7e41cd7263ca87427176512b21da13c70eec70 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 22:49:47 -0400 Subject: [PATCH 260/479] CI: try matrix with allowed failures --- .github/workflows/ci.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eedf2bb0d49..2c91bb78be3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,8 @@ -name: CI build +name: CI Build on: [push, pull_request] jobs: build: - name: Baseline build (Java 8 on ubuntu-18.04) + name: Baseline build runs-on: ubuntu-18.04 steps: - name: Check out repository @@ -19,13 +19,13 @@ jobs: - name: Build with Gradle run: ./gradlew build compatibility-tests: - name: Compatibility tests (Java ${{ matrix.java }} on ${{ matrix.os }}) + name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility needs: [build] runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] - java: [8.0.222, 11.0.4] # TODO: 13.0.0 + os: [ubuntu-16.04] #, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14 + java: [11.0.4, 13.0.0] # 8.0.222, fail-fast: true max-parallel: 5 steps: @@ -41,4 +41,9 @@ jobs: - name: Output Gradle version run: ./gradlew --version - name: Run version compatibility tests + id: tests run: ./gradlew testRecentVersionCompatibility + continue-on-error: true + - name: Check if failure allowed + run: exit 1 + if: (job.steps.tests.outputs.status == 'failure' && job.matrix.java != '13.0.0') From 986a35c7c68cbdb2e869555231ad5cf2efbf2432 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 23:03:11 -0400 Subject: [PATCH 261/479] CI: give up on conditional failures allowed for now; exclude java 13 --- .github/workflows/ci.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c91bb78be3..ccfaf91f7e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,8 +24,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-16.04] #, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14 - java: [11.0.4, 13.0.0] # 8.0.222, + os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] + java: [8.0.222, 11.0.4] fail-fast: true max-parallel: 5 steps: @@ -43,7 +43,3 @@ jobs: - name: Run version compatibility tests id: tests run: ./gradlew testRecentVersionCompatibility - continue-on-error: true - - name: Check if failure allowed - run: exit 1 - if: (job.steps.tests.outputs.status == 'failure' && job.matrix.java != '13.0.0') From e06261f4b0e37702237118f5b0dd8f23a8a79b3d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Oct 2019 23:19:27 -0400 Subject: [PATCH 262/479] CI: info output for builds --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccfaf91f7e9..92aeec01f8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: - name: Output Gradle version run: ./gradlew --version - name: Build with Gradle - run: ./gradlew build + run: ./gradlew build --info compatibility-tests: name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility needs: [build] @@ -42,4 +42,4 @@ jobs: run: ./gradlew --version - name: Run version compatibility tests id: tests - run: ./gradlew testRecentVersionCompatibility + run: ./gradlew testRecentVersionCompatibility --info From ada51238f06380ad21ecdd1ae343b9a2473680a7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 15 Oct 2019 02:21:31 -0400 Subject: [PATCH 263/479] Try to resolve the test failures on windows regarding default encoding handling --- .github/workflows/ci.yml | 5 ++++- .../gradle/plugin/avro/EncodingFunctionalSpec.groovy | 2 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 10 ++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92aeec01f8f..4b3f41a3e96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,10 @@ on: [push, pull_request] jobs: build: name: Baseline build - runs-on: ubuntu-18.04 + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] steps: - name: Check out repository uses: actions/checkout@v1 diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy index 38cdc11fac1..88db1847037 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -34,7 +34,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { def "default encoding matches default compilation behavior"() { given: - copyResource("idioma.avsc", avroDir) + copyResource("idioma.avsc", avroDir, Charset.defaultCharset()) when: def result = run() diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 2b369d1debf..fde71ad7e94 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -23,6 +23,8 @@ import org.junit.Rule import org.junit.rules.TemporaryFolder import spock.lang.Specification +import java.nio.charset.Charset + @SuppressWarnings(["Println"]) abstract class FunctionalSpec extends Specification { @SuppressWarnings(["FieldName"]) @@ -90,10 +92,14 @@ abstract class FunctionalSpec extends Specification { addDependency("org.apache.avro:avro-ipc:${avroVersion}") } - protected void copyResource(String name, File targetFolder) { + protected void copyResource(String name, File targetFolder, Charset charset = null) { def file = new File(targetFolder, name) file.parentFile.mkdirs() - file << getClass().getResourceAsStream(name) + if (charset) { + file << getClass().getResourceAsStream(name).getText("UTF-8").getBytes(charset) + } else { + file << getClass().getResourceAsStream(name) + } } protected File projectFile(String path) { From 9c376d5eb5412f3f49243353db2195cfb18a3a35 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 15 Oct 2019 11:16:59 -0400 Subject: [PATCH 264/479] Fix encoding support on windows, for real this time --- CHANGES.md | 1 + README.md | 2 +- .../gradle/plugin/avro/AvroPlugin.java | 10 ++-- .../avro/AvroBasePluginFunctionalSpec.groovy | 20 +++++++ .../plugin/avro/EncodingFunctionalSpec.groovy | 52 +++++++++++-------- .../gradle/plugin/avro/FunctionalSpec.groovy | 8 +-- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4361f05b3d4..396fc829273 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,7 @@ * Built using Avro 1.9.1 * GenerateAvroProtocolTask now has a `classpath` property; defaults to the runtime configuration when the Avro plugin is applied * GenerateAvroProtocolTask now properly declares the `classpath` as an input; fixes #86; thanks to [RichSteele](https://github.com/RichSteele) for the bug report +* Fix handling of default `outputCharacterEncoding` (use of system default character set to match Java compiler) ## 0.17.0 * Built using Avro 1.9.0 diff --git a/README.md b/README.md index d8080bcdf97..fec582639b6 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ avro { Valid values: any [Charset](http://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html) or equivalent `String` name Controls the character encoding of generated Java files. -If the associated `JavaCompile` task has a configured encoding, it will be used automatically. +If using the plugin's conventions (i.e., not just the base plugin), the associated `JavaCompile` task's encoding will be used automatically. Otherwise, it will use the value configured in the `avro` block, defaulting to `"UTF-8"`. Examples: diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 47c19a55110..0cd6321c21e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -17,6 +17,8 @@ import java.io.File; import java.io.FileFilter; +import java.nio.charset.Charset; +import java.util.Optional; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.file.Directory; @@ -116,13 +118,9 @@ private static GenerateAvroJavaTask configureJavaGenerationTask(final Project pr compileJavaTask.source(task.getOutputDir()); compileJavaTask.source(task.getOutputs()); - final AvroExtension avroExtension = project.getExtensions().findByType(AvroExtension.class); + configurePropertyConvention(task.getOutputCharacterEncoding(), project.provider(() -> + Optional.ofNullable(compileJavaTask.getOptions().getEncoding()).orElse(Charset.defaultCharset().name()))); - configurePropertyConvention(task.getOutputCharacterEncoding(), project.provider(() -> { - String compilationEncoding = compileJavaTask.getOptions().getEncoding(); - String extensionEncoding = avroExtension.getOutputCharacterEncoding().getOrNull(); - return compilationEncoding != null ? compilationEncoding : extensionEncoding; - })); return task; } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy index caf22d6e028..c9a2920f782 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy @@ -22,6 +22,26 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { applyAvroBasePlugin() } + def "can generate java files from json schema"() { + given: + buildFile << """ + task("generateAvroJava", type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { + source file("src/main/avro") + include("**/*.avsc") + outputDir = file("build/generated-main-avro-java") + } + """ + + copyResource("user.avsc", avroDir) + + when: + def result = run("generateAvroJava") + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + projectFile("build/generated-main-avro-java/example/avro/User.java").file + } + def "can generate json schema files from json protocol"() { given: buildFile << """ diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy index 88db1847037..50d33b652ce 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -26,15 +26,13 @@ class EncodingFunctionalSpec extends FunctionalSpec { /* Not all encodings have the characters needed for the test file, and not all encoding may be supported by any given JRE */ private static final List AVAILABLE_ENCODINGS = ["UTF-8", "UTF-16", "UTF-32", "windows-1252", "X-MacRoman"].findAll { Charset.isSupported(it) } + private static final String SYSTEM_ENCODING = Charset.defaultCharset().name() - def "setup"() { + def "with convention plugin, default encoding matches default compilation behavior"() { + given: applyAvroPlugin() addAvroDependency() - } - - def "default encoding matches default compilation behavior"() { - given: - copyResource("idioma.avsc", avroDir, Charset.defaultCharset()) + copyResource("idioma.avsc", avroDir) when: def result = run() @@ -44,59 +42,67 @@ class EncodingFunctionalSpec extends FunctionalSpec { taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS and: "the system default encoding is used" - def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").text + def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(SYSTEM_ENCODING) LANGUAGES.collect { content.contains(it) }.every { it } } @Unroll - def "supports configuring outputCharacterEncoding to #outputCharacterEncoding"() { + def "with convention plugin, configuring Java compilation task with encoding=#encoding will use it for outputCharacterEncoding"() { given: + applyAvroPlugin() + addAvroDependency() copyResource("idioma.avsc", avroDir) buildFile << """ - |avro { - | outputCharacterEncoding = ${outputCharacterEncoding} + |compileJava { + | options.encoding = '${encoding}' |} |""".stripMargin() when: - def result = run("generateAvroJava") + def result = run() then: "compilation succeeds" taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS and: "the specified encoding is used" - def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(expectedEncoding) + def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(encoding) LANGUAGES.collect { content.contains(it) }.every { it } where: - outputCharacterEncoding | expectedEncoding - "'UTF-16'" | "UTF-16" - "'utf-8'" | "UTF-8" - "java.nio.charset.Charset.forName('UTF-16')" | "UTF-16" + encoding << AVAILABLE_ENCODINGS } @Unroll - def "uses configured encoding #encoding from java compilation task"() { + def "with base plugin, configuring outputCharacterEncoding=#outputCharacterEncoding is supported"() { given: + applyAvroBasePlugin() copyResource("idioma.avsc", avroDir) buildFile << """ - |compileJava { - | options.encoding = '${encoding}' + |avro { + | outputCharacterEncoding = ${outputCharacterEncoding} + |} + |task("generateAvroJava", type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { + | source file("src/main/avro") + | include("**/*.avsc") + | outputDir = file("build/generated-main-avro-java") |} |""".stripMargin() when: - def result = run() + def result = run("generateAvroJava") then: "compilation succeeds" taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS and: "the specified encoding is used" - def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(encoding) + def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(expectedEncoding) LANGUAGES.collect { content.contains(it) }.every { it } where: - encoding << AVAILABLE_ENCODINGS + outputCharacterEncoding | expectedEncoding + "'UTF-16'" | "UTF-16" + "'utf-8'" | "UTF-8" + "java.nio.charset.Charset.forName('UTF-16')" | "UTF-16" } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index fde71ad7e94..37958e88c62 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -23,8 +23,6 @@ import org.junit.Rule import org.junit.rules.TemporaryFolder import spock.lang.Specification -import java.nio.charset.Charset - @SuppressWarnings(["Println"]) abstract class FunctionalSpec extends Specification { @SuppressWarnings(["FieldName"]) @@ -92,15 +90,11 @@ abstract class FunctionalSpec extends Specification { addDependency("org.apache.avro:avro-ipc:${avroVersion}") } - protected void copyResource(String name, File targetFolder, Charset charset = null) { + protected void copyResource(String name, File targetFolder) { def file = new File(targetFolder, name) file.parentFile.mkdirs() - if (charset) { - file << getClass().getResourceAsStream(name).getText("UTF-8").getBytes(charset) - } else { file << getClass().getResourceAsStream(name) } - } protected File projectFile(String path) { return new File(testProjectDir.root, path) From 7bf9337fad8253345235072c09208f358cf5640f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 15 Oct 2019 13:51:20 -0400 Subject: [PATCH 265/479] CI: add unsupported-java-versions job --- .github/workflows/ci.yml | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b3f41a3e96..e6b10c562f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,5 +44,29 @@ jobs: - name: Output Gradle version run: ./gradlew --version - name: Run version compatibility tests - id: tests - run: ./gradlew testRecentVersionCompatibility --info + run: ./gradlew testVersionCompatibility --info + unsupported-java-versions: + name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility + needs: [build] + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-18.04] + java: [13.0.0] + fail-fast: false + max-parallel: 5 + steps: + - name: Check out repository + uses: actions/checkout@v1 + - name: Set up Java ${{ matrix.java }} + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + architecture: x64 + - name: Output Java version + run: java -version + - name: Output Gradle version + run: ./gradlew --version + - name: Run tests + continue-on-error: true + run: ./gradlew build testVersionCompatibility --info From 7d9b9be3e211667ed25d50953282d5c44a58fab5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 15 Oct 2019 14:15:44 -0400 Subject: [PATCH 266/479] CI: run the unsupported java versions job on all the OS versions After all, they'll all fail almost immediately anyway --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6b10c562f1..b0fcef4bfc8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-18.04] + os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] java: [13.0.0] fail-fast: false max-parallel: 5 From 29103e08426e2c4fb7731a919785220bb76a37b0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Oct 2019 19:03:04 -0400 Subject: [PATCH 267/479] README: Update badge to use github actions rather than travis --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fec582639b6..1f4ca4271e2 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Java code generation for [Apache Avro](http://avro.apache.org/). It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files. -[![Build Status](https://travis-ci.org/commercehub-oss/gradle-avro-plugin.svg?branch=master)](https://travis-ci.org/commercehub-oss/gradle-avro-plugin) +[![Build Status](https://github.com/davidmc24/gradle-avro-plugin/workflows/ci.yml/badge.svg](https://github.com/davidmc24/gradle-avro-plugin/actions) > See [our security policy](SECURITY.md) for handling of security-related matters. From 2c8725e797b3b7eef6fa2ee2bb9243f442123fa6 Mon Sep 17 00:00:00 2001 From: Ben Speakmon Date: Wed, 16 Oct 2019 16:04:41 -0700 Subject: [PATCH 268/479] add support for generating optional getters --- .../gradle/plugin/avro/AvroBasePlugin.java | 2 + .../gradle/plugin/avro/AvroExtension.java | 2 + .../gradle/plugin/avro/Constants.java | 2 + .../plugin/avro/DefaultAvroExtension.java | 32 +++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 36 ++++++++++ .../plugin/avro/OptionsFunctionalSpec.groovy | 66 +++++++++++++++++++ 6 files changed, 140 insertions(+) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 95ff8ceaa97..32e657521f1 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -36,6 +36,8 @@ private static void configureExtension(final Project project) { configurePropertyConvention(task.getFieldVisibility(), avroExtension.getFieldVisibility()); configurePropertyConvention(task.getTemplateDirectory(), avroExtension.getTemplateDirectory()); configurePropertyConvention(task.isCreateSetters(), avroExtension.isCreateSetters()); + configurePropertyConvention(task.isCreateOptionalGetters(), avroExtension.isCreateOptionalGetters()); + configurePropertyConvention(task.isGettersReturnOptional(), avroExtension.isGettersReturnOptional()); configurePropertyConvention(task.isEnableDecimalLogicalType(), avroExtension.isEnableDecimalLogicalType()); configurePropertyConvention(task.getDateTimeLogicalType(), avroExtension.getDateTimeLogicalType()); }); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index c381a0bd632..aa085fff441 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -23,6 +23,8 @@ public interface AvroExtension { Property getFieldVisibility(); Property getTemplateDirectory(); Property isCreateSetters(); + Property isCreateOptionalGetters(); + Property isGettersReturnOptional(); Property isEnableDecimalLogicalType(); Property getDateTimeLogicalType(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 4b7582cff3f..bd5f4891b6e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -31,6 +31,8 @@ class Constants { static final String DEFAULT_STRING_TYPE = StringType.String.name(); static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); static final boolean DEFAULT_CREATE_SETTERS = true; + static final boolean DEFAULT_CREATE_OPTIONAL_GETTERS = false; + static final boolean DEFAULT_GETTERS_RETURN_OPTIONAL = false; static final boolean DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE = true; static final String DEFAULT_DATE_TIME_LOGICAL_TYPE = SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT.name(); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index eeb951788a9..9e46ffadf0b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -22,10 +22,12 @@ import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.Property; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_OPTIONAL_GETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_DATE_TIME_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; @@ -35,6 +37,8 @@ public class DefaultAvroExtension implements AvroExtension { private final Property fieldVisibility; private final Property templateDirectory; private final Property createSetters; + private final Property createOptionalGetters; + private final Property gettersReturnOptional; private final Property enableDecimalLogicalType; private final Property dateTimeLogicalType; @@ -45,6 +49,8 @@ public DefaultAvroExtension(ObjectFactory objects) { this.fieldVisibility = configurePropertyConvention(objects.property(String.class), DEFAULT_FIELD_VISIBILITY); this.templateDirectory = objects.property(String.class); this.createSetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_SETTERS); + this.createOptionalGetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_OPTIONAL_GETTERS); + this.gettersReturnOptional = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_GETTERS_RETURN_OPTIONAL); this.enableDecimalLogicalType = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); this.dateTimeLogicalType = configurePropertyConvention(objects.property(String.class), DEFAULT_DATE_TIME_LOGICAL_TYPE); } @@ -110,6 +116,32 @@ public void setCreateSetters(boolean createSetters) { this.createSetters.set(createSetters); } + @Override + public Property isCreateOptionalGetters() { + return createOptionalGetters; + } + + public void setCreateOptionalGetters(String createOptionalGetters) { + setCreateOptionalGetters(Boolean.parseBoolean(createOptionalGetters)); + } + + public void setCreateOptionalGetters(boolean createOptionalGetters) { + this.createOptionalGetters.set(createOptionalGetters); + } + + @Override + public Property isGettersReturnOptional() { + return gettersReturnOptional; + } + + public void setGettersReturnOptional(String gettersReturnOptional) { + setGettersReturnOptional(Boolean.parseBoolean(gettersReturnOptional)); + } + + public void setGettersReturnOptional(boolean gettersReturnOptional) { + this.gettersReturnOptional.set(gettersReturnOptional); + } + @Override public Property isEnableDecimalLogicalType() { return enableDecimalLogicalType; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index d24e42b4981..7cacfccf27a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -41,10 +41,12 @@ import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.TaskAction; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_OPTIONAL_GETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_DATE_TIME_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.OPTION_DATE_TIME_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.OPTION_FIELD_VISIBILITY; @@ -68,6 +70,8 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Property stringType; private final Property fieldVisibility; private final Property templateDirectory; + private final Property createOptionalGetters; + private final Property gettersReturnOptional; private final Property createSetters; private final Property enableDecimalLogicalType; private final Property dateTimeLogicalType; @@ -83,6 +87,8 @@ public GenerateAvroJavaTask(ObjectFactory objects) { this.stringType = configurePropertyConvention(objects.property(String.class), DEFAULT_STRING_TYPE); this.fieldVisibility = configurePropertyConvention(objects.property(String.class), DEFAULT_FIELD_VISIBILITY); this.templateDirectory = objects.property(String.class); + this.createOptionalGetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_OPTIONAL_GETTERS); + this.gettersReturnOptional = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_GETTERS_RETURN_OPTIONAL); this.createSetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_SETTERS); this.enableDecimalLogicalType = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); this.dateTimeLogicalType = configurePropertyConvention(objects.property(String.class), DEFAULT_DATE_TIME_LOGICAL_TYPE); @@ -158,6 +164,32 @@ public void setCreateSetters(String createSetters) { this.createSetters.set(Boolean.parseBoolean(createSetters)); } + public Property isCreateOptionalGetters() { + return createOptionalGetters; + } + + @Input + public Property getCreateOptionalGetters() { + return createOptionalGetters; + } + + public void setCreateOptionalGetters(String createOptionalGetters) { + this.createOptionalGetters.set(Boolean.parseBoolean(createOptionalGetters)); + } + + public Property isGettersReturnOptional() { + return gettersReturnOptional; + } + + @Input + public Property getGettersReturnOptional() { + return gettersReturnOptional; + } + + public void setGettersReturnOptional(String gettersReturnOptional) { + this.gettersReturnOptional.set(Boolean.parseBoolean(gettersReturnOptional)); + } + public Property isEnableDecimalLogicalType() { return enableDecimalLogicalType; } @@ -192,6 +224,8 @@ protected void process() { getLogger().debug("Using fieldVisibility {}", fieldVisibilityProvider.get().name()); getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory().getOrNull()); getLogger().debug("Using createSetters {}", isCreateSetters().get()); + getLogger().debug("Using createOptionalGetters {}", isCreateOptionalGetters().get()); + getLogger().debug("Using gettersReturnOptional {}", isGettersReturnOptional().get()); getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType().get()); getLogger().debug("Using dateTimeLogicalType {}", dateTimeLogicalTypeImplementationProvider.get().name()); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); @@ -315,6 +349,8 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept if (getTemplateDirectory().isPresent()) { compiler.setTemplateDir(getTemplateDirectory().get()); } + compiler.setCreateOptionalGetters(createOptionalGetters.get()); + compiler.setGettersReturnOptional(gettersReturnOptional.get()); compiler.setCreateSetters(isCreateSetters().get()); compiler.setEnableDecimalLogicalType(isEnableDecimalLogicalType().get()); diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 670839ae99c..3e860a94ec5 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -58,6 +58,12 @@ class OptionsFunctionalSpec extends FunctionalSpec { and: "createSetters is enabled" content.contains("public void setName(java.lang.String value)") + and: "createOptionalGetters is disabled" + !content.contains("Optional") + + and: "gettersReturnOptional is disabled" + !content.contains("Optional") + and: "enableDecimalLogicalType is enabled" content.contains("public void setSalary(${BigDecimal.name} value)") @@ -153,6 +159,66 @@ class OptionsFunctionalSpec extends FunctionalSpec { "'false'" | false } + @Unroll + def "supports configuring createOptionalGetters to #createOptionalGetters"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | createOptionalGetters = ${createOptionalGetters} + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "the task succeeds" + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + + and: "the specified createOptionalGetters is used" + content.contains("public Optional getOptionalFavoriteColor()") == expectedPresent + + where: + createOptionalGetters | expectedPresent + "Boolean.TRUE" | true + "Boolean.FALSE" | false + "true" | true + "false" | false + "'true'" | true + "'false'" | false + } + + @Unroll + def "supports configuring gettersReturnOptional to #gettersReturnOptional"() { + given: + copyResource("user.avsc", avroDir) + buildFile << """ + |avro { + | gettersReturnOptional = ${gettersReturnOptional} + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "the task succeeds" + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + + and: "the specified createOptionalGetters is used" + content.contains("public Optional getFavoriteColor()") == expectedPresent + + where: + gettersReturnOptional | expectedPresent + "Boolean.TRUE" | true + "Boolean.FALSE" | false + "true" | true + "false" | false + "'true'" | true + "'false'" | false + } + def "supports configuring templateDirectory"() { given: def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") From e375c753f614170422fe92d1de5eec0378440244 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Oct 2019 19:05:36 -0400 Subject: [PATCH 269/479] README: fix CI badge syntax --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f4ca4271e2..238915cf6d7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Java code generation for [Apache Avro](http://avro.apache.org/). It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files. -[![Build Status](https://github.com/davidmc24/gradle-avro-plugin/workflows/ci.yml/badge.svg](https://github.com/davidmc24/gradle-avro-plugin/actions) +[![Build Status](https://github.com/davidmc24/gradle-avro-plugin/workflows/ci.yml/badge.svg)](https://github.com/davidmc24/gradle-avro-plugin/actions) > See [our security policy](SECURITY.md) for handling of security-related matters. From a2e1725d310a1031bc938fa5c410ad04a59b8b5c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Oct 2019 19:07:23 -0400 Subject: [PATCH 270/479] README: fix CI badge image --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 238915cf6d7..af6097f8bdb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Java code generation for [Apache Avro](http://avro.apache.org/). It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files. -[![Build Status](https://github.com/davidmc24/gradle-avro-plugin/workflows/ci.yml/badge.svg)](https://github.com/davidmc24/gradle-avro-plugin/actions) +[![Build Status](https://github.com/davidmc24/gradle-avro-plugin/workflows/CI%20Build/badge.svg)](https://github.com/davidmc24/gradle-avro-plugin/actions) > See [our security policy](SECURITY.md) for handling of security-related matters. From cbcce719f1c570086ee43fe0eb39e3e396928c19 Mon Sep 17 00:00:00 2001 From: Ben Speakmon Date: Wed, 16 Oct 2019 16:24:59 -0700 Subject: [PATCH 271/479] add doc for optional getter field generation --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index d8080bcdf97..092cd45be72 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ There are a number of configuration options supported in the `avro` block. | option | default | description | | --------------------------| --------------------- | ------------------------------------------------- | | createSetters | `true` | `createSetters` passed to Avro compiler | +| createOptionalGetters | `false` | `createOptionalGetters` passed to Avro compiler | +| gettersReturnOptional | `false` | `gettersReturnOptional` passed to Avro compiler | fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | | outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | | stringType | `"String"` | `stringType` passed to Avro compiler | @@ -108,6 +110,40 @@ avro { } ``` +## createOptionalGetters + +Valid values: `false` (default), `true`; supports equivalent `String` values + +Set to `true` to create additional getter methods that return their fields wrapped in an +[Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html). For a field with +name `abc` and type `string`, this setting will create a method +`Optional getOptionalAbc()`. + +Example: + +```groovy +avro { + createOptionalGetters = false +} +``` + +## gettersReturnOptional + +Valid values: `false` (default), `true`; supports equivalent `String` values + +Set to `true` to cause getter methods to return +[Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) wrappers of the +underlying type. Where [`createOptionalGetters`](#createoptionalgetters) generates an additional +method, this one replaces the existing getter. + +Example: + +```groovy +avro { + gettersReturnOptional = false +} +``` + ## fieldVisibility Valid values: any [FieldVisibility](http://avro.apache.org/docs/1.8.1/api/java/org/apache/avro/compiler/specific/SpecificCompiler.FieldVisibility.html) or equivalent `String` name (matched case-insensitively); default `"PUBLIC_DEPRECATED"` (default) From 7aa5f6fb3778ffac2b20e2252ac82f5558d67c12 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Oct 2019 20:55:53 -0400 Subject: [PATCH 272/479] Update changelog to note the recent merged pull request --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 396fc829273..84ec8eb97df 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,7 +4,7 @@ * Use reproducible file order for plugin archives * Eliminate usage of internal conventions API, using new Lazy Configuration approach instead; requires Gradle 4.4+ * Technically, the APIs needed are available in Gradle 4.3, but there is a bug related to un-set `Property` instances in 4.3 and 4.3.1; see https://github.com/gradle/gradle/issues/3879 -* Cleaned up compatibility code for older versions of Gradle +* Cleaned up compatibility code for older versions of Gradle * Built using Gradle 5.6.2 * Upgrade Spock from 1.2 to 1.3 * Upgrade Checkstyle from 6.1.1 to 8.23 and adjust rules used @@ -15,6 +15,7 @@ * GenerateAvroProtocolTask now has a `classpath` property; defaults to the runtime configuration when the Avro plugin is applied * GenerateAvroProtocolTask now properly declares the `classpath` as an input; fixes #86; thanks to [RichSteele](https://github.com/RichSteele) for the bug report * Fix handling of default `outputCharacterEncoding` (use of system default character set to match Java compiler) +* Add support for generating getters that return Optional (#90); contribution from [bspeakmon](https://github.com/bspeakmon) ## 0.17.0 * Built using Avro 1.9.0 From e4b09a4203f126f42d13c634482a24b1f6f537fa Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Oct 2019 20:59:04 -0400 Subject: [PATCH 273/479] CI: disable the gradle daemon to try to eliminate the sporadic clean failure on windows --- .github/workflows/ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0fcef4bfc8..656062ae983 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,8 +19,12 @@ jobs: run: java -version - name: Output Gradle version run: ./gradlew --version + env: + GRADLE_OPTS: -Dorg.gradle.daemon=false - name: Build with Gradle run: ./gradlew build --info + env: + GRADLE_OPTS: -Dorg.gradle.daemon=false compatibility-tests: name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility needs: [build] @@ -43,8 +47,12 @@ jobs: run: java -version - name: Output Gradle version run: ./gradlew --version + env: + GRADLE_OPTS: -Dorg.gradle.daemon=false - name: Run version compatibility tests run: ./gradlew testVersionCompatibility --info + env: + GRADLE_OPTS: -Dorg.gradle.daemon=false unsupported-java-versions: name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility needs: [build] @@ -67,6 +75,10 @@ jobs: run: java -version - name: Output Gradle version run: ./gradlew --version + env: + GRADLE_OPTS: -Dorg.gradle.daemon=false - name: Run tests continue-on-error: true run: ./gradlew build testVersionCompatibility --info + env: + GRADLE_OPTS: -Dorg.gradle.daemon=false From 7da5f43ce943a1d1f1da588a635c911b2f6968ee Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Oct 2019 21:01:12 -0400 Subject: [PATCH 274/479] Remove security policy; not a CommerceHub OSS project any more --- README.md | 2 -- SECURITY.md | 6 ------ 2 files changed, 8 deletions(-) delete mode 100644 SECURITY.md diff --git a/README.md b/README.md index 5c848b0e71e..28f5a3a0ab8 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav [![Build Status](https://github.com/davidmc24/gradle-avro-plugin/workflows/CI%20Build/badge.svg)](https://github.com/davidmc24/gradle-avro-plugin/actions) -> See [our security policy](SECURITY.md) for handling of security-related matters. - # Compatibility * Currently tested against Java 8-12 diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index d223e0d95ac..00000000000 --- a/SECURITY.md +++ /dev/null @@ -1,6 +0,0 @@ -# How to report a security vulnerability? - -If you believe you’ve found a security vulnerability in this project, please send it to us by emailing . Please include the following details with your report: - -* Description of the location and potential impact of the vulnerability; -* A detailed description of the steps required to reproduce the vulnerability (POC scripts, screenshots, and compressed screen captures are all helpful to us) From 95f992d41e794dd7099e614187ce51053a8a828d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Oct 2019 21:49:53 -0400 Subject: [PATCH 275/479] Update various files for commercehub-oss -> davidmc24 github move --- CODE_OF_CONDUCT.md | 2 +- CONTRIBUTING.md | 9 +++++---- README.md | 4 ++-- RELEASING.md | 2 +- build.gradle | 8 ++++---- design-docs/external-schemata-and-protocols.md | 2 +- design-docs/run-avro-as-an-external-process.md | 2 +- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index bb0c27088f3..a4157ac46eb 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at oss-conduct@commercehub.com. +reported by contacting the project team at david@carrclan.us. We will endeavor to review submitted complaints and respond in a manner that CommerceHub (in its sole discretion) deems necessary and appropriate to the circumstances. In enforcing this Code of Conduct, Project maintainers may diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 337dd324b8e..ca5fceac861 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,12 +1,13 @@ # Contributing -> Before contributing, please read our [code of conduct](https://github.com/commercehub-oss/gradle-avro-plugin/blob/master/CODE_OF_CONDUCT.md). +> Before contributing, please read our [code of conduct](https://github.com/davidmc24/gradle-avro-plugin/blob/master/CODE_OF_CONDUCT.md). -> See [our security policy](SECURITY.md) for handling of security-related matters. - -Before starting work on an enhancement, it's highly recommended to open an [issue](https://github.com/commercehub-oss/gradle-avro-plugin/issues) to describe the intended change. +Before starting work on an enhancement, it's highly recommended to open an [issue](https://github.com/davidmc24/gradle-avro-plugin/issues) to describe the intended change. This allows for the project maintainers to provide feedback before you've done work that may not fit the project's vision. +Note that this plugin is primarily focussed on exposing functionality from the [Apache Avro Java API](https://avro.apache.org/docs/current/api/java/index.html) in the ways most commonly used in Gradle builds. +If the capability that you are looking for doesn't currently exist in said upstream API, you're likely better off requesting the feature from the [Apache Avro project](https://avro.apache.org/) than requesting it here. + Some possible enhancements may have already been considered and documented. Check the design-docs folder for the design specification for such features. To run the project's build, run: diff --git a/README.md b/README.md index 28f5a3a0ab8..e05916c2b21 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Usage -Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](https://github.com/commercehub-oss/gradle-avro-plugin/blob/master/CHANGES.md). +Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](https://github.com/davidmc24/gradle-avro-plugin/blob/master/CHANGES.md). ```groovy buildscript { @@ -338,7 +338,7 @@ In `gradle.build.kts` add: ```kotlin plugins { - // Find latest release here: https://github.com/commercehub-oss/gradle-avro-plugin/releases + // Find latest release here: https://github.com/davidmc24/gradle-avro-plugin/releases id("com.commercehub.gradle.plugin.avro") version "0.17.0" } ``` diff --git a/RELEASING.md b/RELEASING.md index 347dda44f70..54b58fe0471 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -11,4 +11,4 @@ 1. Push 1. If there was a issue requesting the release, close it. 1. Close the milestone. -1. Go to the [GitHub Releases page](https://github.com/commercehub-oss/gradle-avro-plugin/releases), click "Draft a new release", select the tag version, use the version number as the title, copy the relevant segment from `CHANGES.md` into the description, and click "Publish release". +1. Go to the [GitHub Releases page](https://github.com/davidmc24/gradle-avro-plugin/releases), click "Draft a new release", select the tag version, use the version number as the title, copy the relevant segment from `CHANGES.md` into the description, and click "Publish release". diff --git a/build.gradle b/build.gradle index a44ab9edcab..d1ca4551dfe 100644 --- a/build.gradle +++ b/build.gradle @@ -71,11 +71,11 @@ bintray { userOrg = "commercehub-oss" licenses = ["Apache-2.0"] desc = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." - websiteUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" - issueTrackerUrl = 'https://github.com/commercehub-oss/gradle-avro-plugin/issues' - vcsUrl = "https://github.com/commercehub-oss/gradle-avro-plugin" + websiteUrl = "https://github.com/davidmc24/gradle-avro-plugin" + issueTrackerUrl = 'https://github.com/davidmc24/gradle-avro-plugin/issues' + vcsUrl = "https://github.com/davidmc24/gradle-avro-plugin" labels = ["serialization", "avro"] - githubRepo = "commercehub-oss/gradle-avro-plugin" + githubRepo = "davidmc24/gradle-avro-plugin" version { name = project.version vcsTag = project.version diff --git a/design-docs/external-schemata-and-protocols.md b/design-docs/external-schemata-and-protocols.md index 5cb0ac4271a..50861b7d423 100644 --- a/design-docs/external-schemata-and-protocols.md +++ b/design-docs/external-schemata-and-protocols.md @@ -1,4 +1,4 @@ -Originally requested as [#4](https://github.com/commercehub-oss/gradle-avro-plugin/issues/4). +Originally requested as [#4](https://github.com/davidmc24/gradle-avro-plugin/issues/4). Some users would like the ability to have JAR files that contain Avro schema/protocol files, and have a way to declare a dependency on these, such that the plugin's generation capability can use them without needing to manual extract the archives. Intended approach: diff --git a/design-docs/run-avro-as-an-external-process.md b/design-docs/run-avro-as-an-external-process.md index b0c0683c869..85c7816793d 100644 --- a/design-docs/run-avro-as-an-external-process.md +++ b/design-docs/run-avro-as-an-external-process.md @@ -1,4 +1,4 @@ -Originally reported as [#27](https://github.com/commercehub-oss/gradle-avro-plugin/issues/27). +Originally reported as [#27](https://github.com/davidmc24/gradle-avro-plugin/issues/27). Currently, Avro generation takes by running the avro-compiler library as part of the Gradle plugin process. This is simple and works, but has a few drawbacks: From 5fa162d5d7af352acc6306e2cd4fb603f82c87bc Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 15 Nov 2019 10:17:08 -0500 Subject: [PATCH 276/479] Working version of custom conversions against modern gradle; still need to adjust for earlier versions --- CHANGES.md | 1 + build.gradle | 3 + .../gradle/plugin/avro/AvroBasePlugin.java | 4 + .../gradle/plugin/avro/AvroExtension.java | 6 + .../gradle/plugin/avro/Constants.java | 7 + .../plugin/avro/DefaultAvroExtension.java | 47 +++++++ .../plugin/avro/GenerateAvroJavaTask.java | 80 +++++++++++ .../plugin/avro/GenerateAvroProtocolTask.java | 3 + .../plugin/avro/GradleCompatibility.java | 41 ++++++ .../CustomConversionFunctionalSpec.groovy | 129 ++++++++++++++++++ .../gradle/plugin/avro/FunctionalSpec.groovy | 11 +- .../avro/test/custom/TimeZoneConversion.java | 51 +++++++ .../avro/test/custom/TimeZoneLogicalType.java | 35 +++++ .../custom/TimeZoneLogicalTypeFactory.java | 27 ++++ .../gradle/plugin/avro/customConversion.avpr | 13 ++ .../gradle/plugin/avro/customConversion.avsc | 9 ++ 16 files changed, 465 insertions(+), 2 deletions(-) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy create mode 100644 src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java create mode 100644 src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java create mode 100644 src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avpr create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avsc diff --git a/CHANGES.md b/CHANGES.md index 84ec8eb97df..97839f9b640 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ * GenerateAvroProtocolTask now properly declares the `classpath` as an input; fixes #86; thanks to [RichSteele](https://github.com/RichSteele) for the bug report * Fix handling of default `outputCharacterEncoding` (use of system default character set to match Java compiler) * Add support for generating getters that return Optional (#90); contribution from [bspeakmon](https://github.com/bspeakmon) +* Add support for `logicalTypeFactories` and `customConversions`; fixes #92 ## 0.17.0 * Built using Avro 1.9.0 diff --git a/build.gradle b/build.gradle index d1ca4551dfe..679d010d50e 100644 --- a/build.gradle +++ b/build.gradle @@ -149,6 +149,9 @@ checkstyle { checkstyleMain { configProperties = ['basedir': "$rootDir/config/checkstyle"] } +checkstyleTest { + configProperties = ['basedir': "$rootDir/config/checkstyle"] +} codenarc { config = project.resources.text.fromFile("config/codenarc/codenarc.groovy") diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 32e657521f1..221c601f60c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -19,6 +19,8 @@ import org.gradle.api.Project; import static com.commercehub.gradle.plugin.avro.Constants.AVRO_EXTENSION_NAME; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureListPropertyConvention; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureMapPropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.createExtensionWithObjectFactory; @@ -40,6 +42,8 @@ private static void configureExtension(final Project project) { configurePropertyConvention(task.isGettersReturnOptional(), avroExtension.isGettersReturnOptional()); configurePropertyConvention(task.isEnableDecimalLogicalType(), avroExtension.isEnableDecimalLogicalType()); configurePropertyConvention(task.getDateTimeLogicalType(), avroExtension.getDateTimeLogicalType()); + configureMapPropertyConvention(task.getLogicalTypeFactories(), avroExtension.getLogicalTypeFactories()); + configureListPropertyConvention(task.getCustomConversions(), avroExtension.getCustomConversions()); }); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index aa085fff441..376c6672ced 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -15,6 +15,8 @@ */ package com.commercehub.gradle.plugin.avro; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; public interface AvroExtension { @@ -27,4 +29,8 @@ public interface AvroExtension { Property isGettersReturnOptional(); Property isEnableDecimalLogicalType(); Property getDateTimeLogicalType(); + @SuppressWarnings("rawtypes") + MapProperty getLogicalTypeFactories(); + @SuppressWarnings("rawtypes") + ListProperty getCustomConversions(); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index bd5f4891b6e..db3db00893e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -15,6 +15,9 @@ */ package com.commercehub.gradle.plugin.avro; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; import org.apache.avro.generic.GenericData.StringType; @@ -35,6 +38,10 @@ class Constants { static final boolean DEFAULT_GETTERS_RETURN_OPTIONAL = false; static final boolean DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE = true; static final String DEFAULT_DATE_TIME_LOGICAL_TYPE = SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT.name(); + @SuppressWarnings("rawtypes") + static final Map DEFAULT_LOGICAL_TYPE_FACTORIES = Collections.emptyMap(); + @SuppressWarnings("rawtypes") + static final List DEFAULT_CUSTOM_CONVERSIONS = Collections.emptyList(); static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 9e46ffadf0b..25aa31ada10 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -16,19 +16,27 @@ package com.commercehub.gradle.plugin.avro; import java.nio.charset.Charset; +import java.util.Map; import javax.inject.Inject; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.generic.GenericData; import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_OPTIONAL_GETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CUSTOM_CONVERSIONS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_DATE_TIME_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_LOGICAL_TYPE_FACTORIES; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureListPropertyConvention; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureMapPropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; public class DefaultAvroExtension implements AvroExtension { @@ -41,6 +49,10 @@ public class DefaultAvroExtension implements AvroExtension { private final Property gettersReturnOptional; private final Property enableDecimalLogicalType; private final Property dateTimeLogicalType; + @SuppressWarnings("rawtypes") + private final MapProperty logicalTypeFactories; + @SuppressWarnings("rawtypes") + private final ListProperty customConversions; @Inject public DefaultAvroExtension(ObjectFactory objects) { @@ -53,6 +65,9 @@ public DefaultAvroExtension(ObjectFactory objects) { this.gettersReturnOptional = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_GETTERS_RETURN_OPTIONAL); this.enableDecimalLogicalType = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); this.dateTimeLogicalType = configurePropertyConvention(objects.property(String.class), DEFAULT_DATE_TIME_LOGICAL_TYPE); + this.logicalTypeFactories = configureMapPropertyConvention( + objects.mapProperty(String.class, Class.class), DEFAULT_LOGICAL_TYPE_FACTORIES); + this.customConversions = configureListPropertyConvention(objects.listProperty(Class.class), DEFAULT_CUSTOM_CONVERSIONS); } @Override @@ -167,4 +182,36 @@ public void setDateTimeLogicalType(String dateTimeLogicalType) { public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplementation dateTimeLogicalType) { setDateTimeLogicalType(dateTimeLogicalType.name()); } + + @Override + @SuppressWarnings("rawtypes") + public MapProperty getLogicalTypeFactories() { + return logicalTypeFactories; + } + + @SuppressWarnings("rawtypes") + public void setLogicalTypeFactories(Provider> provider) { + this.logicalTypeFactories.set(provider); + } + + @SuppressWarnings("rawtypes") + public void setLogicalTypeFactories(Map logicalTypeFactories) { + this.logicalTypeFactories.set(logicalTypeFactories); + } + + @Override + @SuppressWarnings("rawtypes") + public ListProperty getCustomConversions() { + return customConversions; + } + + @SuppressWarnings("rawtypes") + public void setCustomConversions(Provider> provider) { + this.customConversions.set(provider); + } + + @SuppressWarnings("rawtypes") + public void setCustomConversions(Iterable customConversions) { + this.customConversions.set(customConversions); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 7cacfccf27a..9ab7f0d3819 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -22,7 +22,9 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.inject.Inject; +import org.apache.avro.LogicalTypes; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.apache.avro.SchemaParseException; @@ -33,6 +35,8 @@ import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.specs.NotSpec; @@ -43,16 +47,20 @@ import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_OPTIONAL_GETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CUSTOM_CONVERSIONS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_DATE_TIME_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_LOGICAL_TYPE_FACTORIES; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.OPTION_DATE_TIME_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.OPTION_FIELD_VISIBILITY; import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureListPropertyConvention; +import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureMapPropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; @@ -75,6 +83,10 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Property createSetters; private final Property enableDecimalLogicalType; private final Property dateTimeLogicalType; + @SuppressWarnings("rawtypes") + private final MapProperty logicalTypeFactories; + @SuppressWarnings("rawtypes") + private final ListProperty customConversions; private final Provider stringTypeProvider; private final Provider fieldVisibilityProvider; @@ -99,6 +111,9 @@ public GenerateAvroJavaTask(ObjectFactory objects) { this.dateTimeLogicalTypeImplementationProvider = getDateTimeLogicalType() .map(input -> Enums.parseCaseInsensitive(OPTION_DATE_TIME_LOGICAL_TYPE, SpecificCompiler.DateTimeLogicalTypeImplementation.values(), input)); + this.logicalTypeFactories = + configureMapPropertyConvention(objects.mapProperty(String.class, Class.class), DEFAULT_LOGICAL_TYPE_FACTORIES); + this.customConversions = configureListPropertyConvention(objects.listProperty(Class.class), DEFAULT_CUSTOM_CONVERSIONS); } @Optional @@ -217,7 +232,42 @@ public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplement setDateTimeLogicalType(dateTimeLogicalType.name()); } + @Optional + @Input + @SuppressWarnings("rawtypes") + public MapProperty getLogicalTypeFactories() { + return logicalTypeFactories; + } + + @SuppressWarnings("rawtypes") + public void setLogicalTypeFactories(Provider> provider) { + this.logicalTypeFactories.set(provider); + } + + @SuppressWarnings("rawtypes") + public void setLogicalTypeFactories(Map logicalTypeFactories) { + this.logicalTypeFactories.set(logicalTypeFactories); + } + + @Optional + @Input + @SuppressWarnings("rawtypes") + public ListProperty getCustomConversions() { + return customConversions; + } + + @SuppressWarnings("rawtypes") + public void setCustomConversions(Provider> provider) { + this.customConversions.set(provider); + } + + @SuppressWarnings("rawtypes") + public void setCustomConversions(Iterable customConversions) { + this.customConversions.set(customConversions); + } + @TaskAction + @SuppressWarnings("rawtypes") protected void process() { getLogger().debug("Using outputCharacterEncoding {}", getOutputCharacterEncoding().getOrNull()); getLogger().debug("Using stringType {}", stringTypeProvider.get().name()); @@ -228,6 +278,9 @@ protected void process() { getLogger().debug("Using gettersReturnOptional {}", isGettersReturnOptional().get()); getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType().get()); getLogger().debug("Using dateTimeLogicalType {}", dateTimeLogicalTypeImplementationProvider.get().name()); + getLogger().debug("Using logicalTypeFactories {}", + logicalTypeFactories.get().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getName()))); + getLogger().debug("Using customConversions {}", customConversions.get().stream().map(Class::getName).collect(Collectors.toList())); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); processFiles(); @@ -242,6 +295,7 @@ private void failOnUnsupportedFiles() { } private void processFiles() { + registerLogicalTypes(); int processedFileCount = 0; processedFileCount += processProtoFiles(); processedFileCount += processSchemaFiles(); @@ -342,6 +396,7 @@ private void compile(Schema schema, File sourceFile) throws IOException { compile(new SpecificCompiler(schema, dateTimeLogicalTypeImplementationProvider.get()), sourceFile); } + @SuppressWarnings("rawtypes") private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { compiler.setOutputCharacterEncoding(getOutputCharacterEncoding().getOrNull()); compiler.setStringType(stringTypeProvider.get()); @@ -353,7 +408,32 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept compiler.setGettersReturnOptional(gettersReturnOptional.get()); compiler.setCreateSetters(isCreateSetters().get()); compiler.setEnableDecimalLogicalType(isEnableDecimalLogicalType().get()); + registerCustomConversions(compiler); compiler.compileToDestination(sourceFile, getOutputDir().get().getAsFile()); } + + /** + * Registers the logical types to be used in this run. + * This must be called before the Schemas are parsed, or they will not be applied correctly. + * Since {@link LogicalTypes} is a static registry, this may result in side-effects. + */ + @SuppressWarnings("rawtypes") + private void registerLogicalTypes() { + for (Map.Entry entry : logicalTypeFactories.get().entrySet()) { + String logicalTypeName = entry.getKey(); + Class logicalTypeFactoryClass = entry.getValue(); + try { + LogicalTypes.LogicalTypeFactory logicalTypeFactory = + (LogicalTypes.LogicalTypeFactory) logicalTypeFactoryClass.newInstance(); + LogicalTypes.register(logicalTypeName, logicalTypeFactory); + } catch (InstantiationException | IllegalAccessException ex) { + getLogger().error("Could not instantiate logicalTypeFactory class \"" + logicalTypeFactoryClass.getName() + "\""); + } + } + } + + private void registerCustomConversions(SpecificCompiler compiler) { + customConversions.get().forEach(compiler::addCustomConversion); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index 1c7e9c812f9..f1ea6f70c6e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -29,10 +29,12 @@ import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.TaskAction; import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; +import static org.gradle.api.tasks.PathSensitivity.RELATIVE; /** * Task to convert Avro IDL files into Avro protocol files using {@link Idl}. @@ -40,6 +42,7 @@ @CacheableTask public class GenerateAvroProtocolTask extends OutputDirTask { @InputFiles + @PathSensitive(value = RELATIVE) private FileCollection classpath; public GenerateAvroProtocolTask() { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java index 3a019c86e59..55f2273611f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java @@ -16,9 +16,12 @@ package com.commercehub.gradle.plugin.avro; +import java.util.Map; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -68,4 +71,42 @@ static Property configurePropertyConvention(Property property, T value } return property; } + + static ListProperty configureListPropertyConvention(ListProperty property, + Provider> provider) { + if (GradleFeatures.propertyConventions.isSupported()) { + property.convention(provider); + } else { + property.set(provider); + } + return property; + } + + static ListProperty configureListPropertyConvention(ListProperty property, Iterable elements) { + if (GradleFeatures.propertyConventions.isSupported()) { + property.convention(elements); + } else { + property.set(elements); + } + return property; + } + + static MapProperty configureMapPropertyConvention(MapProperty property, + Provider> valueProvider) { + if (GradleFeatures.propertyConventions.isSupported()) { + property.convention(valueProvider); + } else { + property.set(valueProvider); + } + return property; + } + + static MapProperty configureMapPropertyConvention(MapProperty property, Map value) { + if (GradleFeatures.propertyConventions.isSupported()) { + property.convention(value); + } else { + property.set(value); + } + return property; + } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy new file mode 100644 index 00000000000..1409598cb6c --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -0,0 +1,129 @@ +/* + * Copyright © 2019 David M. Carr + * + * 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 com.commercehub.gradle.plugin.avro + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class CustomConversionFunctionalSpec extends FunctionalSpec { + def "setup"() { + applyAvroPlugin() + addAvroDependency() + } + + private void copyCustomConversion(String destDir) { + copyFile("src/test/java", destDir, + "com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java") + copyFile("src/test/java", destDir, + "com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java") + copyFile("src/test/java", destDir, + "com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java") + } + + def "can use a custom conversion when generating java from a schema"() { + // As of Avro 1.9.1, custom conversions have an undesirable interaction with stringType=String. + // See https://issues.apache.org/jira/browse/AVRO-2548 + given: + copyResource("customConversion.avsc", avroDir) + buildFile << """ + import com.commercehub.gradle.plugin.avro.test.custom.* + avro { + stringType = "CharSequence" + logicalTypeFactories.put("timezone", TimeZoneLogicalTypeFactory) + customConversions.add(TimeZoneConversion) + } + """ + testProjectDir.newFolder("buildSrc") + testProjectDir.newFile("buildSrc/build.gradle") << """ + repositories { + jcenter() + } + dependencies { + compile "org.apache.avro:avro:${avroVersion}" + } + """ + copyCustomConversion("buildSrc/src/main/java") + copyCustomConversion("src/main/java") + + when: + def result = run() + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + projectFile(buildOutputClassPath("test/Event.class")).file + def javaSource = projectFile("build/generated-main-avro-java/test/Event.java").text + javaSource.contains("java.time.Instant start;") + javaSource.contains("java.util.TimeZone timezone;") + } + + def "can use a custom conversion when generating java from a protocol"() { + // As of Avro 1.9.1, custom conversions have an undesirable interaction with stringType=String. + // See https://issues.apache.org/jira/browse/AVRO-2548 + given: + copyResource("customConversion.avpr", avroDir) + buildFile << """ + import com.commercehub.gradle.plugin.avro.test.custom.* + avro { + stringType = "CharSequence" + logicalTypeFactories.put("timezone", TimeZoneLogicalTypeFactory) + customConversions.add(TimeZoneConversion) + } + """ + testProjectDir.newFolder("buildSrc") + testProjectDir.newFile("buildSrc/build.gradle") << """ + repositories { + jcenter() + } + dependencies { + compile "org.apache.avro:avro:${avroVersion}" + } + """ + copyCustomConversion("buildSrc/src/main/java") + copyCustomConversion("src/main/java") + + when: + def result = run() + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + projectFile(buildOutputClassPath("test/Event.class")).file + def javaSource = projectFile("build/generated-main-avro-java/test/Event.java").text + javaSource.contains("java.time.Instant start;") + javaSource.contains("java.util.TimeZone timezone;") + } + + def "can use a custom logical type while generating a schema from a protocol"() { + given: + copyResource("customConversion.avpr", avroDir) + buildFile << """ + task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + source file("src/main/avro") + include("**/*.avpr") + outputDir = file("build/generated-main-avro-avsc") + } + """ + + when: + def result = run("generateSchema") + + then: + taskInfoAbsent || result.task(":generateSchema").outcome == SUCCESS + def schemaFile = projectFile("build/generated-main-avro-avsc/test/Event.avsc").text + schemaFile.contains('"logicalType" : "timestamp-millis"') + schemaFile.contains('"logicalType" : "timezone"') + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 37958e88c62..aac7aaf7cee 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -93,8 +93,15 @@ abstract class FunctionalSpec extends Specification { protected void copyResource(String name, File targetFolder) { def file = new File(targetFolder, name) file.parentFile.mkdirs() - file << getClass().getResourceAsStream(name) - } + file << getClass().getResourceAsStream(name) + } + + protected void copyFile(String srcDir, String destDir, String path) { + def destFile = new File(projectFile(destDir), path) + def srcFile = new File(srcDir, path) + destFile.parentFile.mkdirs() + destFile << srcFile.bytes + } protected File projectFile(String path) { return new File(testProjectDir.root, path) diff --git a/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java b/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java new file mode 100644 index 00000000000..a9e2a4cdf64 --- /dev/null +++ b/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java @@ -0,0 +1,51 @@ +/* + * Copyright © 2019 David M. Carr + * + * 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 com.commercehub.gradle.plugin.avro.test.custom; + +import java.util.TimeZone; +import org.apache.avro.Conversion; +import org.apache.avro.LogicalType; +import org.apache.avro.Schema; + +@SuppressWarnings("unused") +public class TimeZoneConversion extends Conversion { + public static final String LOGICAL_TYPE_NAME = "timezone"; + + @Override + public Class getConvertedType() { + return TimeZone.class; + } + + @Override + public String getLogicalTypeName() { + return LOGICAL_TYPE_NAME; + } + + @Override + public TimeZone fromCharSequence(CharSequence value, Schema schema, LogicalType type) { + return TimeZone.getTimeZone(value.toString()); + } + + @Override + public CharSequence toCharSequence(TimeZone value, Schema schema, LogicalType type) { + return value.getID(); + } + + @Override + public Schema getRecommendedSchema() { + return TimeZoneLogicalType.INSTANCE.addToSchema(Schema.create(Schema.Type.STRING)); + } +} diff --git a/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java b/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java new file mode 100644 index 00000000000..bb146854b10 --- /dev/null +++ b/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2019 David M. Carr + * + * 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 com.commercehub.gradle.plugin.avro.test.custom; + +import org.apache.avro.LogicalType; +import org.apache.avro.Schema; + +public class TimeZoneLogicalType extends LogicalType { + static final TimeZoneLogicalType INSTANCE = new TimeZoneLogicalType(); + + private TimeZoneLogicalType() { + super(TimeZoneConversion.LOGICAL_TYPE_NAME); + } + + @Override + public void validate(Schema schema) { + super.validate(schema); + if (schema.getType() != Schema.Type.STRING) { + throw new IllegalArgumentException("Timezone can only be used with an underlying string type"); + } + } +} diff --git a/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java b/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java new file mode 100644 index 00000000000..32d57922847 --- /dev/null +++ b/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright © 2019 David M. Carr + * + * 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 com.commercehub.gradle.plugin.avro.test.custom; + +import org.apache.avro.LogicalType; +import org.apache.avro.LogicalTypes; +import org.apache.avro.Schema; + +public class TimeZoneLogicalTypeFactory implements LogicalTypes.LogicalTypeFactory { + @Override + public LogicalType fromSchema(Schema schema) { + return TimeZoneLogicalType.INSTANCE; + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avpr b/src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avpr new file mode 100644 index 00000000000..1b32e8fae7c --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avpr @@ -0,0 +1,13 @@ +{"namespace": "test", + "protocol": "CustomConversion", + "types": [ + {"name": "Event", "type": "record", + "fields": [ + {"name": "name", "type": "string"}, + {"name": "start", "type": {"type": "long", "logicalType": "timestamp-millis"} }, + {"name": "timezone", "type": {"type": "string", "logicalType": "timezone"} } + ] + } + ], + "messages": { } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avsc new file mode 100644 index 00000000000..7f345f2e666 --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avsc @@ -0,0 +1,9 @@ +{"namespace": "test", + "type": "record", + "name": "Event", + "fields": [ + {"name": "name", "type": "string"}, + {"name": "start", "type": {"type": "long", "logicalType": "timestamp-millis"} }, + {"name": "timezone", "type": {"type": "string", "logicalType": "timezone"} } + ] +} From bb62c99d7f858b5eef6feb3553a3be9f7e445a04 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 15 Nov 2019 10:17:46 -0500 Subject: [PATCH 277/479] Don't use MapProperty yet; it wasn't introduced until Gradle 5.1 --- .../gradle/plugin/avro/AvroBasePlugin.java | 3 +- .../gradle/plugin/avro/AvroExtension.java | 9 ++++-- .../plugin/avro/DefaultAvroExtension.java | 28 +++++++++++++++---- .../plugin/avro/GenerateAvroJavaTask.java | 24 +++++++++------- .../plugin/avro/GradleCompatibility.java | 21 -------------- .../CustomConversionFunctionalSpec.groovy | 8 +++--- 6 files changed, 48 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 221c601f60c..187a293661e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -20,7 +20,6 @@ import static com.commercehub.gradle.plugin.avro.Constants.AVRO_EXTENSION_NAME; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureListPropertyConvention; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureMapPropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.createExtensionWithObjectFactory; @@ -42,7 +41,7 @@ private static void configureExtension(final Project project) { configurePropertyConvention(task.isGettersReturnOptional(), avroExtension.isGettersReturnOptional()); configurePropertyConvention(task.isEnableDecimalLogicalType(), avroExtension.isEnableDecimalLogicalType()); configurePropertyConvention(task.getDateTimeLogicalType(), avroExtension.getDateTimeLogicalType()); - configureMapPropertyConvention(task.getLogicalTypeFactories(), avroExtension.getLogicalTypeFactories()); + configurePropertyConvention(task.getLogicalTypeFactories(), avroExtension.getLogicalTypeFactories()); configureListPropertyConvention(task.getCustomConversions(), avroExtension.getCustomConversions()); }); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 376c6672ced..2f1b6ac85f1 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -15,8 +15,10 @@ */ package com.commercehub.gradle.plugin.avro; +import java.util.Map; +import org.apache.avro.Conversion; +import org.apache.avro.LogicalTypes; import org.gradle.api.provider.ListProperty; -import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; public interface AvroExtension { @@ -29,8 +31,11 @@ public interface AvroExtension { Property isGettersReturnOptional(); Property isEnableDecimalLogicalType(); Property getDateTimeLogicalType(); + // When we require Gradle 5.1+, we could use MapProperty here. @SuppressWarnings("rawtypes") - MapProperty getLogicalTypeFactories(); + Property getLogicalTypeFactories(); @SuppressWarnings("rawtypes") ListProperty getCustomConversions(); + AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass); + AvroExtension customConversion(Class> conversionClass); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 25aa31ada10..dfa3e36c5c8 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -16,13 +16,15 @@ package com.commercehub.gradle.plugin.avro; import java.nio.charset.Charset; +import java.util.LinkedHashMap; import java.util.Map; import javax.inject.Inject; +import org.apache.avro.Conversion; +import org.apache.avro.LogicalTypes; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.generic.GenericData; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; -import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -36,7 +38,6 @@ import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_LOGICAL_TYPE_FACTORIES; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureListPropertyConvention; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureMapPropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; public class DefaultAvroExtension implements AvroExtension { @@ -49,8 +50,9 @@ public class DefaultAvroExtension implements AvroExtension { private final Property gettersReturnOptional; private final Property enableDecimalLogicalType; private final Property dateTimeLogicalType; + // When we require Gradle 5.1+, we could use MapProperty here. @SuppressWarnings("rawtypes") - private final MapProperty logicalTypeFactories; + private final Property logicalTypeFactories; @SuppressWarnings("rawtypes") private final ListProperty customConversions; @@ -65,8 +67,7 @@ public DefaultAvroExtension(ObjectFactory objects) { this.gettersReturnOptional = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_GETTERS_RETURN_OPTIONAL); this.enableDecimalLogicalType = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); this.dateTimeLogicalType = configurePropertyConvention(objects.property(String.class), DEFAULT_DATE_TIME_LOGICAL_TYPE); - this.logicalTypeFactories = configureMapPropertyConvention( - objects.mapProperty(String.class, Class.class), DEFAULT_LOGICAL_TYPE_FACTORIES); + this.logicalTypeFactories = configurePropertyConvention(objects.property(Map.class), DEFAULT_LOGICAL_TYPE_FACTORIES); this.customConversions = configureListPropertyConvention(objects.listProperty(Class.class), DEFAULT_CUSTOM_CONVERSIONS); } @@ -185,7 +186,7 @@ public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplement @Override @SuppressWarnings("rawtypes") - public MapProperty getLogicalTypeFactories() { + public Property getLogicalTypeFactories() { return logicalTypeFactories; } @@ -214,4 +215,19 @@ public void setCustomConversions(Provider> provider) { public void setCustomConversions(Iterable customConversions) { this.customConversions.set(customConversions); } + + @SuppressWarnings("unchecked") + @Override + public AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass) { + Map> newValue = new LinkedHashMap<>(logicalTypeFactories.get()); + newValue.put(typeName, typeFactoryClass); + logicalTypeFactories.set(newValue); + return this; + } + + @Override + public AvroExtension customConversion(Class> conversionClass) { + customConversions.add(conversionClass); + return this; + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 9ab7f0d3819..6c3e23b4faa 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -36,7 +36,6 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; -import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.specs.NotSpec; @@ -60,7 +59,6 @@ import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureListPropertyConvention; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureMapPropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; @@ -83,8 +81,9 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Property createSetters; private final Property enableDecimalLogicalType; private final Property dateTimeLogicalType; + // When we require Gradle 5.1+, we could use MapProperty here. @SuppressWarnings("rawtypes") - private final MapProperty logicalTypeFactories; + private final Property logicalTypeFactories; @SuppressWarnings("rawtypes") private final ListProperty customConversions; @@ -112,7 +111,7 @@ public GenerateAvroJavaTask(ObjectFactory objects) { .map(input -> Enums.parseCaseInsensitive(OPTION_DATE_TIME_LOGICAL_TYPE, SpecificCompiler.DateTimeLogicalTypeImplementation.values(), input)); this.logicalTypeFactories = - configureMapPropertyConvention(objects.mapProperty(String.class, Class.class), DEFAULT_LOGICAL_TYPE_FACTORIES); + configurePropertyConvention(objects.property(Map.class), DEFAULT_LOGICAL_TYPE_FACTORIES); this.customConversions = configureListPropertyConvention(objects.listProperty(Class.class), DEFAULT_CUSTOM_CONVERSIONS); } @@ -235,7 +234,7 @@ public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplement @Optional @Input @SuppressWarnings("rawtypes") - public MapProperty getLogicalTypeFactories() { + public Property getLogicalTypeFactories() { return logicalTypeFactories; } @@ -267,7 +266,7 @@ public void setCustomConversions(Iterable customConversions) { } @TaskAction - @SuppressWarnings("rawtypes") + @SuppressWarnings({"rawtypes", "unchecked"}) protected void process() { getLogger().debug("Using outputCharacterEncoding {}", getOutputCharacterEncoding().getOrNull()); getLogger().debug("Using stringType {}", stringTypeProvider.get().name()); @@ -279,7 +278,10 @@ protected void process() { getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType().get()); getLogger().debug("Using dateTimeLogicalType {}", dateTimeLogicalTypeImplementationProvider.get().name()); getLogger().debug("Using logicalTypeFactories {}", - logicalTypeFactories.get().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getName()))); + logicalTypeFactories.get().entrySet().stream().collect(Collectors.toMap( + (Map.Entry e) -> (String) e.getKey(), + (Map.Entry e) -> ((Class) e.getValue()).getName() + ))); getLogger().debug("Using customConversions {}", customConversions.get().stream().map(Class::getName).collect(Collectors.toList())); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); @@ -420,9 +422,11 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept */ @SuppressWarnings("rawtypes") private void registerLogicalTypes() { - for (Map.Entry entry : logicalTypeFactories.get().entrySet()) { - String logicalTypeName = entry.getKey(); - Class logicalTypeFactoryClass = entry.getValue(); + Map logicalTypeFactoryMap = logicalTypeFactories.get(); + Set> logicalTypeFactoryEntries = logicalTypeFactoryMap.entrySet(); + for (Map.Entry entry : logicalTypeFactoryEntries) { + String logicalTypeName = (String) entry.getKey(); + Class logicalTypeFactoryClass = (Class) entry.getValue(); try { LogicalTypes.LogicalTypeFactory logicalTypeFactory = (LogicalTypes.LogicalTypeFactory) logicalTypeFactoryClass.newInstance(); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java index 55f2273611f..2e93d92ed93 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java @@ -16,12 +16,10 @@ package com.commercehub.gradle.plugin.avro; -import java.util.Map; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.provider.ListProperty; -import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -90,23 +88,4 @@ static ListProperty configureListPropertyConvention(ListProperty prope } return property; } - - static MapProperty configureMapPropertyConvention(MapProperty property, - Provider> valueProvider) { - if (GradleFeatures.propertyConventions.isSupported()) { - property.convention(valueProvider); - } else { - property.set(valueProvider); - } - return property; - } - - static MapProperty configureMapPropertyConvention(MapProperty property, Map value) { - if (GradleFeatures.propertyConventions.isSupported()) { - property.convention(value); - } else { - property.set(value); - } - return property; - } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index 1409598cb6c..b5851019b9d 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -41,8 +41,8 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { import com.commercehub.gradle.plugin.avro.test.custom.* avro { stringType = "CharSequence" - logicalTypeFactories.put("timezone", TimeZoneLogicalTypeFactory) - customConversions.add(TimeZoneConversion) + logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) + customConversion(TimeZoneConversion) } """ testProjectDir.newFolder("buildSrc") @@ -78,8 +78,8 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { import com.commercehub.gradle.plugin.avro.test.custom.* avro { stringType = "CharSequence" - logicalTypeFactories.put("timezone", TimeZoneLogicalTypeFactory) - customConversions.add(TimeZoneConversion) + logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) + customConversion(TimeZoneConversion) } """ testProjectDir.newFolder("buildSrc") From a861cf236d54208829b3ab2713c78b8131e68a38 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 15 Nov 2019 11:39:51 -0500 Subject: [PATCH 278/479] Don't use ListProperty It changed incompatibly between Gradle 4.4 and Gralde 4.5 --- .../gradle/plugin/avro/AvroBasePlugin.java | 3 +- .../gradle/plugin/avro/AvroExtension.java | 5 +-- .../plugin/avro/DefaultAvroExtension.java | 32 ++++++++++++------- .../plugin/avro/GenerateAvroJavaTask.java | 30 +++++++++-------- .../plugin/avro/GradleCompatibility.java | 20 ------------ 5 files changed, 41 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 187a293661e..6c8dc28265e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -19,7 +19,6 @@ import org.gradle.api.Project; import static com.commercehub.gradle.plugin.avro.Constants.AVRO_EXTENSION_NAME; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureListPropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.createExtensionWithObjectFactory; @@ -42,7 +41,7 @@ private static void configureExtension(final Project project) { configurePropertyConvention(task.isEnableDecimalLogicalType(), avroExtension.isEnableDecimalLogicalType()); configurePropertyConvention(task.getDateTimeLogicalType(), avroExtension.getDateTimeLogicalType()); configurePropertyConvention(task.getLogicalTypeFactories(), avroExtension.getLogicalTypeFactories()); - configureListPropertyConvention(task.getCustomConversions(), avroExtension.getCustomConversions()); + configurePropertyConvention(task.getCustomConversions(), avroExtension.getCustomConversions()); }); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 2f1b6ac85f1..1e127b8a2a1 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -15,10 +15,10 @@ */ package com.commercehub.gradle.plugin.avro; +import java.util.List; import java.util.Map; import org.apache.avro.Conversion; import org.apache.avro.LogicalTypes; -import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; public interface AvroExtension { @@ -34,8 +34,9 @@ public interface AvroExtension { // When we require Gradle 5.1+, we could use MapProperty here. @SuppressWarnings("rawtypes") Property getLogicalTypeFactories(); + // When we require Gradle 4.5+, we could use ListProperty here. @SuppressWarnings("rawtypes") - ListProperty getCustomConversions(); + Property getCustomConversions(); AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass); AvroExtension customConversion(Class> conversionClass); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index dfa3e36c5c8..86f2f98220b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -16,7 +16,9 @@ package com.commercehub.gradle.plugin.avro; import java.nio.charset.Charset; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.avro.Conversion; @@ -24,7 +26,6 @@ import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.generic.GenericData; import org.gradle.api.model.ObjectFactory; -import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -37,7 +38,6 @@ import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_LOGICAL_TYPE_FACTORIES; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureListPropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; public class DefaultAvroExtension implements AvroExtension { @@ -53,8 +53,9 @@ public class DefaultAvroExtension implements AvroExtension { // When we require Gradle 5.1+, we could use MapProperty here. @SuppressWarnings("rawtypes") private final Property logicalTypeFactories; + // When we require Gradle 4.5+, we could use ListProperty here. @SuppressWarnings("rawtypes") - private final ListProperty customConversions; + private final Property customConversions; @Inject public DefaultAvroExtension(ObjectFactory objects) { @@ -68,7 +69,7 @@ public DefaultAvroExtension(ObjectFactory objects) { this.enableDecimalLogicalType = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); this.dateTimeLogicalType = configurePropertyConvention(objects.property(String.class), DEFAULT_DATE_TIME_LOGICAL_TYPE); this.logicalTypeFactories = configurePropertyConvention(objects.property(Map.class), DEFAULT_LOGICAL_TYPE_FACTORIES); - this.customConversions = configureListPropertyConvention(objects.listProperty(Class.class), DEFAULT_CUSTOM_CONVERSIONS); + this.customConversions = configurePropertyConvention(objects.property(List.class), DEFAULT_CUSTOM_CONVERSIONS); } @Override @@ -190,44 +191,51 @@ public Property getLogicalTypeFactories() { return logicalTypeFactories; } - @SuppressWarnings("rawtypes") - public void setLogicalTypeFactories(Provider> provider) { + public void setLogicalTypeFactories(Provider>> provider) { this.logicalTypeFactories.set(provider); } - @SuppressWarnings("rawtypes") - public void setLogicalTypeFactories(Map logicalTypeFactories) { + public void setLogicalTypeFactories(Map> logicalTypeFactories) { this.logicalTypeFactories.set(logicalTypeFactories); } @Override @SuppressWarnings("rawtypes") - public ListProperty getCustomConversions() { + public Property getCustomConversions() { return customConversions; } @SuppressWarnings("rawtypes") - public void setCustomConversions(Provider> provider) { + public void setCustomConversions(Provider>> provider) { + // If we were using ListProperty, this method could take Iterables rather than Lists this.customConversions.set(provider); } @SuppressWarnings("rawtypes") - public void setCustomConversions(Iterable customConversions) { + public void setCustomConversions(List> customConversions) { + // If we were using ListProperty, this method could take Iterables rather than Lists this.customConversions.set(customConversions); } @SuppressWarnings("unchecked") @Override public AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass) { + // If we were using MapProperty, we could use the put method here Map> newValue = new LinkedHashMap<>(logicalTypeFactories.get()); newValue.put(typeName, typeFactoryClass); logicalTypeFactories.set(newValue); return this; } + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public AvroExtension customConversion(Class> conversionClass) { - customConversions.add(conversionClass); + // If we were using ListProperty, we could use the add method here + List> newValue = new ArrayList<>(customConversions.get()); + newValue.add(conversionClass); + customConversions.set(newValue); return this; } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 6c3e23b4faa..06526ac78ab 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -18,12 +18,14 @@ import java.io.File; import java.io.IOException; import java.nio.charset.Charset; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.inject.Inject; +import org.apache.avro.Conversion; import org.apache.avro.LogicalTypes; import org.apache.avro.Protocol; import org.apache.avro.Schema; @@ -35,7 +37,6 @@ import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.model.ObjectFactory; -import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.specs.NotSpec; @@ -58,7 +59,6 @@ import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configureListPropertyConvention; import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; @@ -85,7 +85,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { @SuppressWarnings("rawtypes") private final Property logicalTypeFactories; @SuppressWarnings("rawtypes") - private final ListProperty customConversions; + private final Property customConversions; private final Provider stringTypeProvider; private final Provider fieldVisibilityProvider; @@ -112,7 +112,7 @@ public GenerateAvroJavaTask(ObjectFactory objects) { SpecificCompiler.DateTimeLogicalTypeImplementation.values(), input)); this.logicalTypeFactories = configurePropertyConvention(objects.property(Map.class), DEFAULT_LOGICAL_TYPE_FACTORIES); - this.customConversions = configureListPropertyConvention(objects.listProperty(Class.class), DEFAULT_CUSTOM_CONVERSIONS); + this.customConversions = configurePropertyConvention(objects.property(List.class), DEFAULT_CUSTOM_CONVERSIONS); } @Optional @@ -239,29 +239,31 @@ public Property getLogicalTypeFactories() { } @SuppressWarnings("rawtypes") - public void setLogicalTypeFactories(Provider> provider) { + public void setLogicalTypeFactories(Provider>> provider) { this.logicalTypeFactories.set(provider); } @SuppressWarnings("rawtypes") - public void setLogicalTypeFactories(Map logicalTypeFactories) { + public void setLogicalTypeFactories(Map> logicalTypeFactories) { this.logicalTypeFactories.set(logicalTypeFactories); } @Optional @Input @SuppressWarnings("rawtypes") - public ListProperty getCustomConversions() { + public Property getCustomConversions() { return customConversions; } - @SuppressWarnings("rawtypes") - public void setCustomConversions(Provider> provider) { + public void setCustomConversions(Provider>>> provider) { + // If we were using ListProperty, this method could take Iterables rather than Lists this.customConversions.set(provider); } - @SuppressWarnings("rawtypes") - public void setCustomConversions(Iterable customConversions) { + public void setCustomConversions(List>> customConversions) { + // If we were using ListProperty, this method could take Iterables rather than Lists this.customConversions.set(customConversions); } @@ -282,7 +284,8 @@ protected void process() { (Map.Entry e) -> (String) e.getKey(), (Map.Entry e) -> ((Class) e.getValue()).getName() ))); - getLogger().debug("Using customConversions {}", customConversions.get().stream().map(Class::getName).collect(Collectors.toList())); + getLogger().debug("Using customConversions {}", + customConversions.get().stream().map(v -> ((Class) v).getName()).collect(Collectors.toList())); getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); failOnUnsupportedFiles(); processFiles(); @@ -437,7 +440,8 @@ private void registerLogicalTypes() { } } + @SuppressWarnings("unchecked") private void registerCustomConversions(SpecificCompiler compiler) { - customConversions.get().forEach(compiler::addCustomConversion); + customConversions.get().forEach(v -> compiler.addCustomConversion((Class) v)); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java index 2e93d92ed93..3a019c86e59 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java @@ -19,7 +19,6 @@ import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -69,23 +68,4 @@ static Property configurePropertyConvention(Property property, T value } return property; } - - static ListProperty configureListPropertyConvention(ListProperty property, - Provider> provider) { - if (GradleFeatures.propertyConventions.isSupported()) { - property.convention(provider); - } else { - property.set(provider); - } - return property; - } - - static ListProperty configureListPropertyConvention(ListProperty property, Iterable elements) { - if (GradleFeatures.propertyConventions.isSupported()) { - property.convention(elements); - } else { - property.set(elements); - } - return property; - } } From f0b1206ba88353ec419b8de69be48eb08db7b02f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 15 Nov 2019 12:49:53 -0500 Subject: [PATCH 279/479] Don't use Class.newInstance(), as it was deprecated in Java 11 --- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 06526ac78ab..45c6b803564 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -423,7 +423,7 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept * This must be called before the Schemas are parsed, or they will not be applied correctly. * Since {@link LogicalTypes} is a static registry, this may result in side-effects. */ - @SuppressWarnings("rawtypes") + @SuppressWarnings({"rawtypes", "unchecked"}) private void registerLogicalTypes() { Map logicalTypeFactoryMap = logicalTypeFactories.get(); Set> logicalTypeFactoryEntries = logicalTypeFactoryMap.entrySet(); @@ -432,9 +432,9 @@ private void registerLogicalTypes() { Class logicalTypeFactoryClass = (Class) entry.getValue(); try { LogicalTypes.LogicalTypeFactory logicalTypeFactory = - (LogicalTypes.LogicalTypeFactory) logicalTypeFactoryClass.newInstance(); + (LogicalTypes.LogicalTypeFactory) logicalTypeFactoryClass.getDeclaredConstructor().newInstance(); LogicalTypes.register(logicalTypeName, logicalTypeFactory); - } catch (InstantiationException | IllegalAccessException ex) { + } catch (ReflectiveOperationException ex) { getLogger().error("Could not instantiate logicalTypeFactory class \"" + logicalTypeFactoryClass.getName() + "\""); } } From 5070f7ea4104612b34b53a05cc8656e3cb17ca97 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 19 Nov 2019 11:47:49 -0500 Subject: [PATCH 280/479] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 30 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000000..958456c9cab --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Project set up like this... +2. Source files like this... +3. Ran this task... +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Environment (please complete the following information):** + - Gradle Version [e.g. 5.6.1] + - Apache Avro Version [e.g. 1.8.2] + - Gradle-Avro Plugin Version [e.g. 0.17.0] + - OS: [e.g. Mac OS X Mojave, Windows 10, Ubuntu 16.04] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000000..5efb987e381 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context about the feature request here. From 6483614a286b139c633eb4292ad923cbd71922c0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 19 Nov 2019 12:02:50 -0500 Subject: [PATCH 281/479] Update bug_report.md to add a checklist --- .github/ISSUE_TEMPLATE/bug_report.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 958456c9cab..5e6bd27549a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,17 +7,33 @@ assignees: '' --- +**Prerequisites** + +* [ ] Are you running the latest version of the plugin? (Check [releases](https://github.com/davidmc24/gradle-avro-plugin/releases)) +* [ ] Are you running a supported version of Gradle? (Check the [README](https://github.com/davidmc24/gradle-avro-plugin/blob/master/README.md)) +* [ ] Are you running a supported version of Apache Avro? (Check the [README](https://github.com/davidmc24/gradle-avro-plugin/blob/master/README.md)) +* [ ] Are you running a supported version of Java? (Check the [README](https://github.com/davidmc24/gradle-avro-plugin/blob/master/README.md)) +* [ ] Did you check to see if an [issue](https://github.com/davidmc24/gradle-avro-plugin/issues) has already been submitted? +* [ ] Are you reporting to the correct repository? +* [ ] Did you perform a cursory search? + +For more information, see the [CONTRIBUTING](https://github.com/davidmc24/gradle-avro-plugin/blob/master/CONTRIBUTING.md) guide. + **Describe the bug** + A clear and concise description of what the bug is. **To Reproduce** + Steps to reproduce the behavior: + 1. Project set up like this... 2. Source files like this... 3. Ran this task... 4. See error **Expected behavior** + A clear and concise description of what you expected to happen. **Environment (please complete the following information):** @@ -27,4 +43,5 @@ A clear and concise description of what you expected to happen. - OS: [e.g. Mac OS X Mojave, Windows 10, Ubuntu 16.04] **Additional context** + Add any other context about the problem here. From aafbe2a52785b1382482595794e78c183b08224a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 19 Nov 2019 12:07:14 -0500 Subject: [PATCH 282/479] Update feature_request.md to include a checklist --- .github/ISSUE_TEMPLATE/feature_request.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 5efb987e381..556f72716b5 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,14 +7,27 @@ assignees: '' --- +**Prerequisites** + +* [ ] Have you checked if the feature exists in the latest version of the plugin? (See [releases](https://github.com/davidmc24/gradle-avro-plugin/releases)) +* [ ] Did you check to see if an [issue](https://github.com/davidmc24/gradle-avro-plugin/issues) has already been submitted? +* [ ] Are you reporting to the correct repository? Requests for functionality not currently provided by the [Avro Java library](https://avro.apache.org/docs/current/gettingstartedjava.html) are better submitted to the [Apache Avro project](https://avro.apache.org/issue_tracking.html). +* [ ] Did you perform a cursory search? + +For more information, see the [CONTRIBUTING](https://github.com/davidmc24/gradle-avro-plugin/blob/master/CONTRIBUTING.md) guide. + **Is your feature request related to a problem? Please describe.** + A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** + A clear and concise description of what you want to happen. **Describe alternatives you've considered** + A clear and concise description of any alternative solutions or features you've considered. **Additional context** + Add any other context about the feature request here. From 852d7190aeeada589027419571d1e4fa11dd3c99 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 10 Feb 2020 09:38:28 -0500 Subject: [PATCH 283/479] CI: don't bother doing maintenance builds on old OS versions; only use latest --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 656062ae983..d2a283aa315 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] + os: [ubuntu-latest, windows-latest, macOS-latest] java: [8.0.222, 11.0.4] fail-fast: true max-parallel: 5 From cc7a52164b97c7fba590353cac28ee06951d20f2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 10 Feb 2020 09:38:52 -0500 Subject: [PATCH 284/479] CI: update another place with os versions that I missed --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2a283aa315..0997bdc4432 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-16.04, ubuntu-18.04, windows-2016, windows-2019, macOS-10.14] + os: [ubuntu-latest, windows-latest, macOS-latest] java: [13.0.0] fail-fast: false max-parallel: 5 From 84e1392443af7a69940c32c91ef2f141017901b8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 10 Feb 2020 11:32:28 -0500 Subject: [PATCH 285/479] version: 0.18.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 97839f9b640..08cbc45560d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.18.0 * Use reproducible file order for plugin archives * Eliminate usage of internal conventions API, using new Lazy Configuration approach instead; requires Gradle 4.4+ * Technically, the APIs needed are available in Gradle 4.3, but there is a bug related to un-set `Property` instances in 4.3 and 4.3.1; see https://github.com/gradle/gradle/issues/3879 diff --git a/build.gradle b/build.gradle index 679d010d50e..9beb848d802 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.17.1-SNAPSHOT" +version = "0.18.0" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From 740f352ce2dd149bec362846dc1791b2c073b951 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 10 Feb 2020 11:35:49 -0500 Subject: [PATCH 286/479] version: 0.18.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9beb848d802..05f1295f309 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.18.0" +version = "0.18.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From 302f8953dff286e5fc30fc162aacf9111b62413c Mon Sep 17 00:00:00 2001 From: Markus Helbig Date: Sun, 23 Feb 2020 08:30:35 +0100 Subject: [PATCH 287/479] update to Avro 1.9.2 since https://issues.apache.org/jira/browse/AVRO-2548 has been fixed there --- build.gradle | 4 +- .../CustomConversionFunctionalSpec.groovy | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 05f1295f309..1907d19a93e 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ repositories { jcenter() } -def compileAvroVersion = "1.9.1" +def compileAvroVersion = "1.9.2" dependencies { compile localGroovy() @@ -183,7 +183,7 @@ test { // Java 8+ is also required by Gradle 5.x sourceCompatibility = 8 -def avroVersions = ["1.9.0", "1.9.1"] +def avroVersions = ["1.9.0", "1.9.1", "1.9.2"] def gradleVersions = [] if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 appears to be the first version that supports Java 11, as per https://github.com/gradle/gradle/pull/4759 and testing gradleVersions.addAll("4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index b5851019b9d..46c8905ce98 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -15,7 +15,10 @@ */ package com.commercehub.gradle.plugin.avro +import spock.lang.Requires + import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +import static org.gradle.util.GradleVersion.version class CustomConversionFunctionalSpec extends FunctionalSpec { def "setup"() { @@ -32,6 +35,43 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { "com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java") } + @Requires({ version(avroVersion).compareTo(version("1.9.2")) >= 0 }) + def "can use a custom conversion when generating java from a schema with stringType = \"String\""() { + // since Avro 1.9.2 https://issues.apache.org/jira/browse/AVRO-2548 is fixed + given: + copyResource("customConversion.avsc", avroDir) + buildFile << """ + import com.commercehub.gradle.plugin.avro.test.custom.* + avro { + stringType = "String" + logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) + customConversion(TimeZoneConversion) + } + """ + testProjectDir.newFolder("buildSrc") + testProjectDir.newFile("buildSrc/build.gradle") << """ + repositories { + jcenter() + } + dependencies { + compile "org.apache.avro:avro:${avroVersion}" + } + """ + copyCustomConversion("buildSrc/src/main/java") + copyCustomConversion("src/main/java") + + when: + def result = run() + + then: + taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + projectFile(buildOutputClassPath("test/Event.class")).file + def javaSource = projectFile("build/generated-main-avro-java/test/Event.java").text + javaSource.contains("java.time.Instant start;") + javaSource.contains("java.util.TimeZone timezone;") + } + def "can use a custom conversion when generating java from a schema"() { // As of Avro 1.9.1, custom conversions have an undesirable interaction with stringType=String. // See https://issues.apache.org/jira/browse/AVRO-2548 From 97e29996b64fd570fe16742e0dec399fc9273ae5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 24 Feb 2020 12:52:12 -0500 Subject: [PATCH 288/479] Add support for Gradle 6.0-6.2, drop support for gradle <5.1 (#101) --- CHANGES.md | 3 + README.md | 7 +- build.gradle | 8 +- config/checkstyle/import-control.xml | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 58695 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 29 +++----- gradlew.bat | 3 + .../gradle/plugin/avro/AvroBasePlugin.java | 23 +++--- .../gradle/plugin/avro/AvroExtension.java | 13 ++-- .../gradle/plugin/avro/AvroPlugin.java | 7 +- .../gradle/plugin/avro/Constants.java | 15 +++- .../plugin/avro/DefaultAvroExtension.java | 60 ++++++--------- .../gradle/plugin/avro/FileUtils.java | 15 +--- .../plugin/avro/GenerateAvroJavaTask.java | 70 ++++++++---------- .../plugin/avro/GradleCompatibility.java | 34 +-------- .../gradle/plugin/avro/GradleFeatures.java | 18 ----- .../gradle/plugin/avro/GradleVersions.java | 3 - .../gradle/plugin/avro/OutputDirTask.java | 9 ++- .../gradle/plugin/avro/ProcessingState.java | 2 +- .../gradle/plugin/avro/SetBuilder.java | 1 + .../KotlinCompatibilityFunctionalSpec.groovy | 16 +--- 22 files changed, 118 insertions(+), 221 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 08cbc45560d..709052c3097 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,9 @@ # Change Log ## Unreleased +* Add support for Gradle 6.0-6.2 (#101) +* Drop support for Gradle versions prior to 5.1 +* Update version of kotlin plugin in tests/example ## 0.18.0 * Use reproducible file order for plugin archives diff --git a/README.md b/README.md index e05916c2b21..164bd4be29c 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,9 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 11 support requires Gradle 4.8 or higher * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Gradle 5.6.2 - * Currently tested against Gradle 4.4-4.10.3 and 5.0-5.6.2 +* Currently built against Gradle 6.2 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.2 + * If you need support for Gradle 4.4-5.0, version 0.18.0 was the last version tested for compatibility * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Avro 1.9.1 @@ -21,7 +22,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) * Versions of Avro prior to 1.7.x are unlikely to work * Incubating: support for Kotlin - * Currently tested against Kotlin 1.2.31 + * Currently tested against Kotlin plugin version 1.3.61 * Incubating: support for Gradle Kotlin DSL * No test coverage yet; will attempt to address incompatibilities as they are discovered diff --git a/build.gradle b/build.gradle index 05f1295f309..a0f4a03c0e3 100644 --- a/build.gradle +++ b/build.gradle @@ -185,12 +185,8 @@ sourceCompatibility = 8 def avroVersions = ["1.9.0", "1.9.1"] def gradleVersions = [] -if (!org.gradle.api.JavaVersion.current().isJava11Compatible()) { // Gradle 4.8 appears to be the first version that supports Java 11, as per https://github.com/gradle/gradle/pull/4759 and testing - gradleVersions.addAll("4.4", "4.4.1", "4.5", "4.5.1", "4.6", "4.7") -} -gradleVersions.addAll("4.8", "4.8.1", "4.9", "4.10", "4.10.1", "4.10.2", "4.10.3") -gradleVersions.addAll("5.0", "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2") - +gradleVersions.addAll("5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4") +gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2") avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 328a947c8c8..8f3f535fcaa 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -10,6 +10,7 @@ + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..f3d88b1c2faf2fc91d853cd5d4242b5547257070 100644 GIT binary patch delta 22808 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 delta 20005 zcmV)NK)1ig$^*c%1F$Or3aZ&=*aHOs0O|>o?>!llP5~5?9@GYZjaFM%6IT@ej+ta& z90g-QgNlPU5-y3g)>g2zO1&TfEdgvq+YZSgj810K$;3T}Lh^P8=451Lj40^Byo?0}XR#>b#!kfWj*MIfZVGox zV!0)j+Z}jU!FzaLhTef?vCS(ugn|st5IJX9hC9I!N+cHty)Km8Rina?%-BvbU3Bz<$Y0>ZqLf+3lDh1@ zi(FJZz(dMg@JxtXs8aDEK4R$J6kl7uL$s^-7@ttZ0`!xnUEzX96`$g0kZ+w9>Uq;x z7P)<<;&XhV;!Au*X#J!{gQP}NL$`<$%Kwpyukj7ldo%1@)pCsz-zX5n#Ywwr7BtIt zHIpiT?{dvu<(dyn3w&x<&(CRw6^IK4)xcP;3J==g@ycLI#kcrQr1m|-;Qzc`4Ewk1 zL%KnmM-9n#EwwgE*tHktrij`^vhjLMjW-v2s;-&YqM0Gho|bY2?Gh_;H~X;S@>26f z3_P@2c(<6l*L8%L=5YmeV4lWY@;v#UNrfti;`PK zRMfn{r_Cz;Rk5o^U@- z(5m_h7({}e)U6mIEiz^Uq$iV%4~?v0$Lte?a?&4=a-q>0!Zk#)>yT^cSVQNSv<@XM z)vz-zMb#R1jfLak=x);P%7voc*&6nLj78!RMuKQAG)(V%Z^Wg)5PK}lenSs~NKW#S zJAqDG`zZJU!f_D8^wB?!eq6#~EI`9;!djpck^B`u!FuvyH;fSv5XUG|1SCSg8`883 zk;Mg^#7h+AG_9xbGJzI8PvaHRI#Z{@KYNwVUL#3A*mDXd%NUT+Eu+`_56S3%lIiyg zFy>{=Fiw%^n^R}~XUZx<&*>-V%?(HQtzmx+@tKjQ6QMIwk96oq93JVBP6?7~=!+hx z;oxIL;^AK&N$jWR|2)B=T(m#nY8{8yp#ABUR?yQ+sR@!a0zFEwPtyJj!4`CAq@$r5 z69iajO>Yo0?a{$JP`eR&hM0^EHyAtcFX_=W_B!MIf0K;}@dd}_?x`D-8xBH$PZL2D zJ+m!rUA9yn2;J0lWIs%62sHbPTDogPBWca`j1S|L|=qx;t%jg z8Sj*W4KzjfVQ1#vbIv_?ZsynT?>_hmdy5+gJs-y zkbrMv#l{_m@n>Ni>gNmzKflF)kSxoZV7OQbWAVDZyCc*az7tWztH>&kwzvw-xgSjG zM%bds_d zvjQcCsk+b`MDIvd8_0z+W?1y|mG}Gu4`QK%;h>U@y9^8d$ik~7)3vpKS7eww2gu-T z%C@SC_0aU5K28;k4;N`nlEyin7$zH9Hw#VE@7tD8HtxA7AfQY9n>gk&z$A+{R$ZFz z15@OojYkZH|GP|v?1`~ciJ6g2Gh}+ih{yF{v)j^Qmtn%pMM*;HF2k~48GvXN#`RME zY>45>5a2&jGpA!@Ld$Z0gR3>AIGITL`Ry`8Zb*skvYGJoh&C}#uf~P>60po5K`($# z0j)FxjIA8N`brxM8Tya+f*)}SW@3IG5I2mk;8K>#(jJe$A{005jF001EXlcCfdlaJK~ zf1Ozgd|by_|9{f%zNgjG;q|$`vQF$+)@eJA9m|OmOTJ{wlB|{F%68&BNl((+t6k;o zTiZ%XLrM*$C4{3i&C#Sl+dwJcwDro3+9m|*K!I{opyen~&QR_aXj=C_vxj!2tw`%% zG;ijcZ|1xIGqd^Jw_f@TfSvNzAlBp8e}d@2XRFw|p_NlOUGkPlE{I&w_X!UsTgyQq7;6 z_=_OkkH1vSUm5ta`u=qg&*5)^_*;BMHGfw{X@76xAA!v-(9$sW7F|5ML1c@mW*+{7QfQ#Qg6yK z15X$d3d(X>VaiIi>ncN58?wfff3PWQ4OwT(`XGj6gDD$Lxkc?8p(e7)lv_=?&6Lfi zY%%3_Q?{DYpf=cMNTVT50;?;LaNN$gok}?=L8#A7UY^a`k zd#dN$(4qclS8os5y3gAe?Y6j`m}rZ7ZY(jePf*jDOr$(J;SJgGv|~!Mf1tLnzxPQ0 zp=k76=TUAVkgiJQYe99#;NioE`p-qXP9LfS8b}JnlM@pT<*n;Zx)W^^u00la+Ag{F z^t9u)b?ZrrF*xqAryTm1y&=a<#gYj@{j{5$aGg}DJC^dCgxaU2+&%}BmlE-$J=V8? zojV8ajwNE=enCgW5*jQve|<4!+mOK5nH-~%b=|Rq)03VWaohoWBtx@5)JuCEE_i;*OSJ*kfZ#HKt1`E3;(GNqMnEe@<3y=~^bhq06Jr zw3_7N`n=4pgy*;kJ5J@&ZhXP6-CS0iPC4#@2`87S4E#uXd|YKr#hDK3lSohXJ4*K& z+D>nI-A-b{n`A8WIo6p>DwUQnM`|vRRwc; z)82I2qthLGiqjP_e=c8HnC(i;Pa4uo+PG>*ePfCu0x4YT>-Z@l*z1e z08&5Uc-ckn3CEjE(wA$C_*`c^PHAn~Ir3YMX3p~(*`Zqse^0$5=ebBlUD59Bbr0EY zJf^r-7I764DbKj4h%ule%g*Ye6&fdD3d%G zO{U#ZN0k_Je>OF3u)C{#3c*gkH_e~Nza>ZomOC>G&kf< zOLpTUg4QMAY4hT9hjL_(A$M7_SK2MvCwE(NkLKcCP)&y=opR8^hwxzwFJX=@P>Q!`f1g`&NDfjf8bZqOIb256M`$J4)phQ^&E)|rkH4vqXPqd5sey=QrL(jFFJ0-PEgyFGs>eP zGLH-qFB!=rbA*c`N3;VYV?2o5*hpIOv_|^k4lzS5OT}1Gk#s>|w3S(?#3kL>!#R*z zy|4y4(y_R%&_Gr_<()|jKaY=C5>r;5mkXA}e}(x_uhzCwY`nEY!;~cnVW|e^!G}P< zpw2CsmWOh=RJ?X`VMT2gdrI=A;=Kdl9aHD{euICTbS2rxmd!NU%I>uE(s!v zdb#!TRJ?U0mKbY2XnVFdGwl$R>3w|~Et}>BURJdZ9-HnA5p;gDejZw}DW_=9`}4V` zf4p5LFsaC;m^ZmZ;A5#sBI!j^>FMbtbr_3~HbeY~92+{J^Ys#uEL$?Ixsp+}#RI66 z*q6gS6}Zcm%&02VK-PLO2WwVtl!L3f>~LzHVkA?oSriSjS3RR%!JVGofQ{i0)3wN0fOCi_}e^%!9eBI^nhKOD6jHmhKkJVyKNEERb7jt(> zf(%T$$xGQw*Sg}0kIp1K`*KmJSC&1xO7m}qcSB06W+@PlX`MHt&#)!U)>nafdltMM zf+@#4=#1OxI1_(e(Q#P9r}wB)Vr`eitn2FYhu!>zFEDjsEas;4wevI!$xCW~e-t?9 z?|91^7GE^O4driKYOa>%CW-^GcEO${7q}3u>USPW^L9G#sI6u0Ipy!vwY0P(zN?E& zExzt$??j!Yw@}*N#apJUuc-cpGaYJJUy>5J+iTiY-pr3nFArI&dbY(i}uOWx4%3bo5&%fhye}&Oh!vsZcFJ9a^X}eM7+r+3-a$!24xmB)Ho2KvL ztwZhdClKE$UOGh)i3w%v@&)&^W5<-v{!4DmV*(oVZC96~RPt#``e;0vQr9NNBsx0j zD6BEqKblN=*o#yDrSmI*x0z<#Ij33XGac#NBh;mrRjHiBbSyj$L z^$u-ZI!6k~pM9n`bS@Puf0cdn&yv7+(w(xs1tyg7R2dU;T-b#5=z+k2fiPk?&;A7f z6^LUkrjRI%lN?VMjUPfty&l*PsRxAqrgL9DBlr!H_cCVKKFrY|{P6Kx)z~D>Ewhjp z^)`=a#tOEZVB%K1mA%F+BfbxB(?9D~X+ffUN>qjJDPfgb#G^S8fA8ds`XO**<18u~ zo35d?kjbYz4_#2zAA;1Y^UhYO34Q!^gE!^*R)M6`Epn;Cqh7Ht0>9Q-kV?mdV z1zk33Gb?n@)4Hgh(#l6FA5l52dbO6oija97RX0#Ohv2ZxqWU^4rAwvOrB<(Rp$}TI z9NV>QE4wZy`|X-nf0mQ@19%5TWW8Fc7uGdrP?JIJsm7+}S=7zjnBDgd?z@ZqJN3Si z?2>{_b-02b)UxXEL)wc!%)XD5DEsfq3#;6Ofd1L9h7Y55f75l;XRxe2Fo)3a9F`AL z@QPWi>-pYzq5kv6?Pl({6-)p>Wv9U~Sl!!Mb+;f3gOA%4|2)Xv6Mc)t>6A zJvCu}*vw$#@b0RL=P`91w`34`3M)T`O`%&exNQ!bheKOtar?`wYF1WVvG>%hs@C7? zRn;r7b*kz;&!MUD6Q~Sr%b@X;COUhnNeSFQNPU`C2CuBD`6QYGXbGE@E2}bSe&Oc3 z^_rFpTEqSue=x)T4BA?5pplgAFW|QJy7Kdenh)2#{Gv{}&*OEv>~(xqf3qQdFVhOx z%lUoexQFiF&jh)b)ceqk1K5cU&UCUph%OvPACA!BM=`|F7>=>}jx(LQnch7NOD~=v z$J028527C*CFjR6fLC#fvQOg+ID;?YEWV5f@D-e+e-@|lb<*CzSrI%Sew>pk*kWNs zr@)U=n_9ercjHGG)SY-1k27%%O1{FmCzvh|veti$e^r$FHvBkyLCSmtKY^b_HFdm< z_pnz(YhJ@o(N>>IjC@M5mrE)3vME&|)p!!`L#3#+&aUu_iKl3jUnlpgsJh9GYYeP6 zu*1MJe+Hg4@O}f&8F=16zkw4FALZO+jV{F{n(G_rxJgX|ix~+~H)&1D3=~}qeBdSv zu71%>{vR3G+@w8a_bn_NX`%8!#NSZn1k2-e~nGE*xS?c8hkH?+M6gVgMClK(n)+b zlejr_&m8s-&*I+DeHk2RBoue>n?Wb5a~_Yf*qEdq({$BCbYu#viE|O6-aW*)n09NCW-7+^XHcj4zWHojeBcEua0W{g%8jMz*jzVEY8DRBx7aOQEk<6s7dPBe!O ze`jzcbhPr*=*r+&Pjl$F8h86R9!U_`2DI5^imzdk zx6-V=#LJT`t9};LBunX07Sm%aB;~KOfAqi_a{L0zx02kqF=`*B8}^d=OZa6*aFRaG z(jH^fui{1a`Uw&rV^3lB;{{(ouKmg@2<3kqpP-J)!%e8TN%56BH(3hTR7yv0@?7y1 zNF-<~mt-)TJEWfGNCk68Xqbo8iO^}bJE{f6iVl zWXvjkQofe~e3H7qk7e`}VeXltOxaP;euvIwUSX*5b$y~+1d>k{GNl^wO*CtL`#Jd% z=5l&|kwR2r-XFT38g_>s(Au6;+J+uv+wKe5>f;ZMs81j?T5swAGyi?jVIM#K=rGeH zIvfbIXM_XMVY4YZTpws=W3)uCU1My%3bR%4JoWql)UTBxmUNi9M_7GZS$)d3qgjP= zwgm{tpVE=B7>G}6+d>3@&uH7ig!-5D4I#oRdWAhd_t}kKVJ|?=SGD9{#e}{_RbX8I zUriJ0|3ywB_-(VTAEFfsa6sYpV+Q~L2@sQSG#Zo8Kn9bb*9d=|SNVS&WgULr>@m~L zgrc` z%9W4Gm5-_TxK#N>4EN!aa^+La_%uEv1@4#A&o<*QKG%$Kd|ozRQ1L~%{G}MajIYFS zr*xLVS7q~ng0HFgx{3!?d_%=IW9Y=U)i}b>YKJ~9WG7_v<1#A z-Oi9-4>Zdp=pr)itsZh`v~O9?K#ghsQ%6WM)EKez*_1iYhTY8~jaC+?$Ct16Z zhYr&cqtu${tPgI?o6c85AIi!I3yxM+<@yioJDGnm^5w9^rgeA9a0Brc+c2_)KIepO zIeM0g7?dl?YwO@dVlz9{NaTkHvwBV@5_oST=0tY~3rmbhmf0 zKn;HY@;Xy=UBmWLy}VfIt^uCduv2t1MsQbJIUL&^k9dEo!F&e557-ZwXQV$0Q~}2*OTkkqG@FfSHlnSBMndC zG{f8NOlf#p&iCNQ8h(PGYIsIAKa*=e$FqM5&S-cJ&kIDl^SbM4_=Vg)i&=WD1e(S> zq{Whga~kGwUc(Expx~DpeuWn`yo8rE{2IT}@Ctsb;dj!)tGJuo=rb(Clj`Iduhel* z(a`Vl2L*rB@EZQ4;dT63!(Z@M3O67inbYeOt!#(wcpXLiUNhf8=5%-tJJBtm4jF%X z!LfU2^$mHVH}N+Of0zDmlXtXwsVt%G`j88(Su*C8NR%r9tKdS8GKc3E`aOenz;P=l z^ZnGE?3#;%Bb73)p?iK_32bjzxEhw6Md=<&$ePoVGrWVkJWD`Mh4Vpu+Ne*B`Qj>V z+f4DUM1v}}XsOISDyp6nED2nnXjFei>&s!YS?H^f!-vb75;Y3}&gI0pccS1}Mb9{> zdy~8vJ(DpCtos{S`O}wO(Hk6N{;pOvFg9Q86j|s-T$9x|vG76YtbYrmS;>229_>bn zws9CMXdAwjX(yNSuXRBf%JpffFvKrvjCX7~jLynNfgPQPyh%dddHIn0D>r|(<0APt zf1_%)I=rs#N*9Jk;!??8GWL+ePmMZaNy=1UZ~ot~>y#HiO{!T<-S$N7ekG+TqfF|B zLE|K|Gi>`^1;EV`K-c8}Ao_KenBPH0)V{VgZ~Q#}Dp`Q-?MJ}kBgT@KDgbsfBZic|kh_<%M2Nqzzt=#jO^?Saw ze$U6&@A(?@FF}aEJ=ja_TR9p>6BPD0CfCnGByXBUQ?hFop=3Nfi*Pa?nMEWSkIo{R zJO|}DN;aXFZIt@J2K2FQ=Nc_wA3gy1Bk75+n0%?YM?Xz(BO?8Xw=RD`J)As?rV^H2 zKw&L$WDY5s-7pr9oPiL%Vn~ee?^)PqhmBSKpU-~;S-PDpO_Q5P$jdA_ zIZ0MNNKQUPR-PqOUL{xFAV>Z|&3Diz)?lAlhy5an+e9yJ7ehEm%V{x&0r3C^#j`jd zp2v`Q1;gTX91?G0)Mw!lETi39@Ihuln3mS#c8;RdyNmt@$Um~L%+Z8+27}xcI3iBs z01lF+S&_#bL>qr1l7C_d!wA#I3LK(b1S8baC?D*N(!&^6Zh-m@(hAg;J>p$>LcyKy zVx@w^3daA1-eU?n-zKoTC>oZ|TK6&~?haA{DL+NP{3>DNnTDCA1p;N%RWocq@3IG5I2mk;8K>!U@s4Rai6aWBpD*yl>ldx$P zlg~g6f1Ozgd{oudKPR)i$?(_$Aq?w?1hR)635bLwNHhsZSd0|mW#%OrnI+D=Aqll= zEmmu_ty?Wx*Q#ixRZtQjifh$c+^VhGO{=!ns-L#~7X6B*|MT9=WReU5@+0@Xcb9X| z@;}SH^V}B)4-wHE{>V++dAKwqq!}sAC}~D#f1}BfW{iA}byFedDm>0c{OV(Fa&w-H zjhDvb<_SDenn`Y+%v0QS15cI4tMEx~8q3pU{>chYcX7U(9^e@Y&verSE^yNxE|i`k zX^Istann@Jb#p0~xv7%N<#U!av!$6cj1KZ#h3C0=zQPM+#zHsEL zd7dvkMHP;@sZ|u(%EmDInB&rHQ@F!TL9UgiQzmvPyj|h1yXkzH+s+rrf^Uet7rN;a zzDPbVlDCV+G#4rSO(wNA9M+>%K`j>3V@#gvniZAn>egShK zT)UDfr|vv$n^qpw!mZ_vMl=v^UCcDRDiV$vTG&{x1>?GlFJW>9Bdx7^lxbpJB-&cu z8rA$ky}To;wYTfh@;Y-6D_#CbM>rVK{7h3aO{}d>jLRtT)6%&3bgLhC#7F#HR(k*3oWAuBITkJF@-OEoT>1*NkJk%f3}YXn&a}l zE*fMSVUZ8(M)|rmwV0BdKBciun=^kwV?4w(Iw+!7rwuCnEp*on?q-^IOf63zvI;vZ zvU7DHnqsP7X4TyMoItyLLzlpb-Y&~x3h#hfFzAa1q24rxrxgsOQkcnmY;Afc69@2D z3rn_`iOJUVnC^>5e*;EWc|EWQAXW!j^_U?mTg2$OsXc1L?QsKibuENZh8mpB z@s<{Wde+9}@V4eISYIoH$6&~Dk%?hiyEf9EJ`1;&HrbpcZW z;|BUdS9{VQyo2U08Mxch#R^}B<=ZUw6P{Vsru(+W#BTEohBACif#9@C$g&XhtNDz$ z7Bo?i9gD=HKHbFnFuk)~_Zhn19B~CLxIsE^W~lT_tMKI@)fi|EYeqb(57qJD6+>i( zrDM8L(+M~kqNde)e>4<`#RS4|qQTT4PL{xHe5&6PA# zvN+qX2XzUa(G1GML?sqClLc7Dm&?}%*`hk&J7!}>uLr0VdW*>s4{r}Z{HYmTCfytk zJ#0j~QWi0_jiu#?Ni{MeK?>$b#Q^b-B#~8V{SxPdR6vq_UK+8Qa6F`^0=3O#%kI}D zTPWL;fiG|9f9@uS3SXh{cNM-8A>J2h?@9|sOl1WbgH&erEa*XVHWOU7plH#pncAH` zYt}5Lx{SFindnY9^kj9;l4iCvbNaWMEn8(ylgX_zCcad4lO!}p2rW5rLh02{lGfZ~ z(>g{V>8CYMXqBD_t#kSp&zHq#9mnDm4We0{bNhE$e;~UoK4EjGyG@eR!V{KO7B`x) z+k(EDm{%s#RC=18QRy9eSEXKhSf$_7A5?mro>1u$`j$!;(>GOmkRDR$a=r>1pHQhO zi@vAQx9KvKb`Y}e_f`G@U#;>re67OQ$;b67|B!D``A2*M((%!Snm${I?Ns?jz6m0v zO9;1ae_UBvifTpWAM?%d?ex(!M+F7Q%D3>XD&NMpt9%Fl1kojP*`V;9D&NI-tGtWv zQTbl}sWkVgyqm98`DgS7azX#fHSw?!2J>Z?0ADij*NA#FC95K8o zKMgGq_G;lSOp79+MkJb*d215c)oVn&EePaZf4vilIN0T#otoEGhEk$`|5eTBpb3$5|w@urodz*DV>@~DdyQFPzN5E(+%MY6cc{JoT+B5@= zf9{=`vD}{NZI4E<(CG3)(_ONc1+dZtz{(Qi5Zfz7t2YpXa-t$54C9w2UM&jN58!<%g5e&?{A+3|ZYNjr$VyTZL&T zknvWUMc9x5m3zdE_N#n=4=UWN^21{Ie@FNbvUPv7tc*srE(w_`KT2f}*NOJm@!_7_}&zBUy}k+xx3gZ%ZUv;gzWI8-;(X@@xD6 z67lMwuEhjSUODWF>%q2gtU!wiwGJ(8h||R}M_`t4jCHl}cO?=l3!{ot`E`Cn;oqtJ zd;WvUf8;-5tivk!RDP4+Qu)vPe>Muvj3tgr@AEq7Vp3l|SICRQ`}}NANs)tVfBP>=B_4sxsqA$wUj1GvJA1mr-5?<^%`>E?ul_ z4*`ckKvROS4-(GKaNaLGf5zpD9oX{=zBVo|tOa-RcE4swNresza!!B3H|zz4a{V%T zU<@^{Acq-|mHjs{xdpWuvE#%MsMTmQF)e$E&g1|)v7l<`{M6-5$XFj>heq;KF5?4af>k_}HGw*$t zoDgP)+#X2~s!v|1rI`{j-gLd;30F^k4-C9k?_#;rNfs>T@$a}?B6%<6IqLCV?j<6v zRv=lOD3qCI92fn?NpY;iC~;bD$<{TdeqTu&SZoG~x=072e82TYJ2bLQi`7S>dQDId!3F^Su&~}~Bt8clBjwEs)MeeL zIYV2mdtFaIjD}nTm8Z)(;I8Xvcy;)K5z&&P15sP2lW02?5|M*EbOC*Xm@dRu7F|R+ zaze*@jvUv`ei+ai3lrwBJJ=;U-J{n$B zypNQkl6~YXD&0pT_Lw_-7wrUcqMe47UK&d$gNNxfh4S$>gRaC#kwufPqVExzZ^9Fs zZ^BiU`6hhX(EEM*0eXa+{p2PE&!xrPG_oGesD`44e`o|=MpxK9_HN3laL8j!g%kb5 zJvm#lc&CyCNvfI(8LDY0{iGu^suYKk!#Pol_r&X9Njc&fj!rLOW!9Y9)~R# zLQdY*_ijlyO{svCQ=59oTcOw%xN=<{=b<}j)@bVUICEWdFWgTjRb+dzyJ?#JHX7zp zM$PJ`lQ(!2>6*S_hl_Xhz2H&0DPPoLGu5(!e@3I-1h&tmk+d1m*a8!3G?kiZCi$Q! zKb=CYP)C4Hr}JnHZN-crzCv_9MW_pX7g5wyVG9J5)we@Q*>ncYr#t8;1 zgp%MISalcO4dslaZM2K-0Y5nuqkFN!4jMuFDcuLPF2%09@#e&HDgBIo4l~^kI;G_3 zf5SAVLfaL}Q|JMO_OL>GiKcu(qw%89R6as86sr7;h7YjGgY-}WW4{71L1#k|OyOuK zJwP)UW*y&4Gn;Y>?2k}kldYt2Kfxi2AH`@1!pW_P;nKmwwgXg_MG4H=(=gY8wi9A@ z0q0)_;x3>ncxb7*q;Bega`vNFH5Dg42hbyG$fm3#G+m*C zQwE6GOAjYRdArQnNSY%u!59iW{5k=$PBsIKHrzqOVAQdQC?3R=8Svk^c%A~^Sq8tUe}#XCtY@i-6Ak}TS= z!vXhrv!vg8Q%r(80pJ^9y_={2e_YMN_KWa-8bF@3U;$j{PSf+TeM*|jge_f|FBZ&7 zS`p}t+S5yU zO~pA&d+4-!Zs?_DP0mNCvdNaS90tv)f;nN;>c$?bvEt?m#7!9V^qsV#f0tG^^-^t< ze4o)nXZBE?M3{Ogu%SW`4XtXba6L_V9wleBg?Epuv764?fOsTsx<3g_$aYf&;=yu6gbh&S7TSZzv=>q3A*}BOrEX}e2XO2K zwfzX(2VjnaFx$hR_6Tru2=4!wX~cE_aswRmS^6b(y9LSXIWsi0(PTOd__?s#8hV~y zfUzs+OnTAusw*(}W%@Pxu7_D)rdLcjA5H<_Ffb_q7=xXEW5PKXfBgJ51?L)ax%#lL zD`|QBuT*H6La!;bQlWaHBQynleUg{cClM`IsPPPi)(tNN+1KffLYLJXBg(C;CCE)D6`ANPnLG#Z>><14wHwJ{+r7gk z-iE2O`&pW1<_gjLVQl<7g31f9#fxyVmym~^r#aA`us9Ffn|2TZhLi1c8llkJJoz&a$&#No68ZUMe{3#pbxkj|N@i}eU>%UG zaGqp^0A98-AQQA4D72IEM7R?92t&MXioh>k>7{l!)%i^W#(F5)Lot*p9=miI9%m25 z#lg1iqT!aSZSyFP?&`ZvHtmp3m-*&#J-P=%ZbF)kg1aag=F<(JO9giss<+Eh3Tyz_ z2$pd}HKU*ke-D%~o!*A>-l0<==`wl`l->ue50JV)1f>sK4^!D|pqJ@%HvNVE3XN?-VelUP4Hh4Ty!Jl*9Xms3DP>;+idF`@26P4VSL4f? z=Y~^$ME?b8#1tASpVKIXK31sp2$d@o?4#MFq~Tmff6%Rf8D#ceXzPCH3c87 z=1?Cj=NPmSTO>0@BiQ&S{VS0vZbqNLHGi}nWmiLSDax&;1@@b0L`kVxY<2GH`v}17 zLa5r-pYg0*{@-Z-5Aps}RD1tM#f#)ipQk_xqA5+}W9~hsCi3ZjpfSniQ_Z5r2FT{o z|C)u)fBmM9A%`RW?>$1f+|TqV7k2tI!E_B)iKdmJV&rgFe_87^x0qt3 zWnOIsBxg!0rzI8WWU(z19sBMRq+@4CLd~n8RUHY7E~puY2-}{Fl&rGNm7?SVC9808 zLC;p<;$o*6>C-gM3cE6zGb{5pUvAEu(##30a5lR$DT6c9K8i9Zi-*a4R#B-+j>tj~ zw*K9~lj%pq{{gdrRk{KVZ*Cb8wgCVDU;_XEIFqnx7L!0)4U_EH7=M*gTT2^36#mX; zv#aS= zCG!2Gbf`4J%e!i@`G1zM-pF((?r70YWPG7Tzb|$CMdaQ3U?9($iPVhqKB!dX9|`r^ z?DlEW>1gYO;2vacNmy*CR2~n{no@rg3?zh&tR<2Yp_PdzN!JJ^EZN#2%h#$o%vF{W zf=_8G^+6(-np@t@l(zZL5PnJ-aJQ07cD z#$t&NtYa3Riz=Je$;ZbTDq1j3zvN5bWLuUp@eK z@XXrhtQ)M5xbm9cM1KHKO9KQ7000OG0000%03Ax$;uZ%009y_K049^LX%>?}S`~k3 zV;ff$J!4B6SsurZVkfm@7sWBHEZG(bG(g-2yfsm4*}+?J($*bY6L}JOq>e_34P_~i zmVGHuD3r28*B*CUi}$dH#|Lxm;V1z8kTJRN^Q1UcEUMJk2i$Xt#<#ZB41CBvqQtq6|c6A^q; z{)^+8Fg_K*r}3ExbbMB%XH|So=FdlP5?_$vwu9X34S5)v|wM7Ayr? z+OiCLBCnT9MoGbmi*sX>(^D&p^HXyxmu53lEAtC;>6wcPqSM#)n|dm*Te;Lc4OqER z1#J@rtK{gGv!v(ChJquP=Vl+7npmivI+C;XY~ENb8TO^ZhG=+Z%tGp6GjGsD=t0vm zoeK(@$>jg1(wJ1YgK6>9#3re>32$n`GTTU9fX04=Q!b z){8~MPF>cW^)Y(2K~0-LN8|gU1+6`2IQ!$V5^rSdF>j`~*UVhm)us+WuzT>=@-(yS-8+Jyq$u)UQke{khXSInY<+4z53v-d9iY>;`i zZ09fOrFBY-p(owf0HxvKwhg0H(sRb7nKMd`f<8~FWUQ5K)7eU8_Wn)%;Odqm)!B4) zT!BI#yY^U}+FUb=etbeD7lH`$j=pvyqZj=`X}67y!cAjp(=n`)8}@+ZMoVFIlr&@L zSArMAe%}+za8iqN=|g`)AmLrK^R=Sh)u!>K7s)Ip)Fn zLfKw3WRu0eudGJogoaT(sNusnui}RqCh)R`$MJ-Qk7HIt8q>Vndo64D5nj=-iZ$Ny zgDl3&Wqxc)kRVw3rjMW!2OR=(b!z$b&-;TO7v#ZyQ zHD}+}ykFw?zr*{>!|}m`1$yj2;~RHtt~1`S&<`q$|0FL^R#w6AJG%CMiAfW43cEg> zKG2gJ7+Uh~5Zjo?(O-BR#u|3({hhxN!rnJP+Z!4MC;xv>EArYz+I{lY$mPu8o*&xF z!qO1Db{2>aN<#~ki&@>FxnTV2xG)N3eY8+K?d^2M(+x9|Xw=v1I}7V};g&Q&*U?r! z@+6-%HfOJi$p+l%e@m&ny4yvM$J32*rRV!qU_4#c^Q8m!ys{k~yt2P?w@Qw&;RW%s zU0|x5twVo^Ea4QtlFssrtQp;S0Oz3KgIqOXkn0caStt2p6QmsG9(y9khq!t_XN7Yx zQHAoFt9pTBgfq~G0Pe*{C~2M&K8i8UVqn}i@Gvz+HzEcS$vbGOTRB2n;CEGkG+WT` zS~~7&`<6r!T0&w1lfKRW5=rHJJCUrQxr#t0F;ss=a3(RFtRi$iumg2j{t8#ovV+KS z6|G!p6|_ZIiSA%`sEW?*nmauRag5WI zL9`=*6O8HvhOmiY*R@L?>6&Y|F~#t(R`3iiG8aueb(31>7?u;T`1+htJN#btbq_^pi39OilUH01>> zy55Y`*pFbzW&arE5R_GwI8E}T`>e0?q?BG~GJ3j#froluMliXZZ0@b#z1!|>5l&Ip zvqzb=X`*Bp{aKew%sX2{>%_8)rc&byt`f<|{TJH!wI$yZKJK$TDK>i;r~5KPlA3>k z3w;D1+8*i)JXOK{b@b!(81ykn|1^5oL7$@Zp`NXt8iO7@i4|f5(S@hnO44|_giEu_ zr3K2r5mliJ9e%s`bY7qt3EX5dI#@yCC4>{NqiH)CO}eWNxf{`;yBMxwWLvW5msK>y za&l|yeY=<9%$o;@KTgmmNa9JRYK0<2r0==ilQrU#$kq}?E=Rifzu^|?HKtt3l<{)lOUxelWK({e_J?ZTcA`yydzeGw$KYAAcz)} zixdh$N$}sYtaYL6lIb?SYQhw@y|JPX6Afz*_qk% z^Uv3B0MeM3(11i8ElCNDNJvN_9Y8PcarANA7m@)99D^JWIEEzzFd{+1BaX)$8HQTx zwN{KIe;L}dhM7;~O?joDCX|Af7&F$_Wql>9>FS(p7FBbIw1+iavql&uI^EU()v(zs zWqLzhiwwRoV?||X6pY!;^<~w3E-x2|6V4inTv(J%O`JSN?69Evlb9B3Yqf11ij80rmu!IDiYw_$09&N0T&vJL%gy zIwC-_qO8rx8}_H*c*3xDE>++jYs#(^&)cL}QesInM5?*RAT1c1rlO8(qI_B^bb3Ut ze}V|(LJ%P|aXbxT91|RqK}_KpLz`P_7zSM(d7-cA#+H6WJ+vMt3gRlR3CCurkX;Q- z9|PZVoS?hP0&@z8TC4mh+?o|jj-l^NJyuOjj>XKDY^sN2I!=&2ebZ3wyI0YPMc^n= zoym%#7K@RABvol|6^+s5wCSd$6%y1{f1<+RSzJ~493tEyt{-7RNv%+cIB z6xzF^X3aUYWBJgjwt1(kntRov{W`a`fbu_lFnY*gVES0c%rfR4!j@e>_IcF4MN5yP{Sq>U{h!zUJJ=cAD3_if3PW< zOvGcjPSzaM_wd6y!Qhv(JbD0}Z6d z$KU}3005f{002CbAf+Uejour7#a8Q5+eQ@r))uTIi^RB?gtnv(H359V+>&6MBn6sV zad28Ev?jgDLU9#rIU~zWUZIcBw@7E&At}?O|2osR=-<9WJ3T8oU}A$zCNuq`-97v1 zoNqs!Jvx8>`|Aq;b9f+Q2#Y7^k&zL>B1cY!ge4hSTn^$2u5x@N7RwxeD+2bh3>nur zt_N^~W6owHmsWBlMDC8uk^28sva*DPdS|*2=ndS1nh`63*8( zwYs5NhFG_ZlAy~FS#Fvgb+G-=qSCb zp(8~Qj-Y^2gisZO(g~3&Maoj73J1Z^q)9K*5fH%=N+KeS5Q?s2zee_hA?({;06fkFE zOviFf>)qNmI9=U}bRy7Na9+LbOt5o83 zPBoU@ziZ`(0^NjBNf)F%!?<4Hd-V`DcAakr9PbI=7Qj_0i|*s>r^3ia(Sah_oKIK> znQOFX2hK=^S??TwWO`t;$%oQ{hqWf&FzHA`q&bPq2Y*7EPUt`^0+jSs60NfO;FnS9 zj)wOfOW*kq6hFl-aFR-DTmex3^7AtEJ3VM#yqJlukx3zUS@|t{~h1)*b#ye>wlA;qQw#$z%_gz$ukQ+XvE|LNt&mkIA zQ;Pv+h7XF&bd(uw54e!7kDayK4df;W9KLk}XM7l#aCBVUhUUig!JHd77vlXpbgB?l zIAXJ>R?Ck;RmtC7mAQ*_$@lZFl@|?;H^a-5-ka09$Tp?1Iu2X%{`+^!4~zKu_2*yw z(jBM!h4xooY(=bZ-FiCSzDt#h8roHe&3Hd_yUpliRol#7 zAS5FMLFd=XRym~iW~EM6kv*|eR5vlr&eX@~mNN5oXtM|Ev=|+cg`}BSXf9w2N_AZ` zSdP@JXnKUynGt;H8~0*l=SOt0rc@%`)R@-XmsPML4ZVe3pB*6Qi_AX$+;T9c1Gyj4 z;P=5IyE{8MW*Ej7(_5(U<->qRgXbCH3D?2l%cJ+ja}jej_U(jylU^Ic=l64w=j95v zbQQbjIPr7N_g!N>2>EC~X`eF@e}46SrrcJo?`5Zi#D(%>`Up>^ZI~U}AgeZ0eGc|}$J zkUqY+<$Io#Oqnl1x}_ml%`m$oW9n^h`E{@H63ckS(6bH&`3 z@+GvNuOYPg-F*556nCIJ=&mO7kI^%Vg0J^jrx%2pPkeOP)O_;l{B<=+{|gN~eF5A? zI(Vsy;)h(F$wU{`mw{`iiw2(6&yxjIucHPzkUZ0GeIIL!+oGaNbbl#Yh)OR80?n|1;0J!B3|psn6Pf!>R++GI)x*Mv zhGXk4_@oQ!a*H~A>q|*Vrx)-^>>I^Nr*De4?O2-_Jqmdq-;{Z3>=m!AJQ=PqO{)GYurw&9HxsH{d=NrD?pV2KaUx&rA1jyGuet%MKJj&bACJKtSH@gL? zx@>p3B&(ph-pQ!JX6Omp6!zE)7u)MQu`co^-&3yCj=l0trP@l4W~kUVNCJaZp|f@7 zb(gx0hwkF}A{Q?zjK#IqaH1+Vx3$-vAaeOLl`Yyp6O62q6?)IKtuyBHR-5O_?1iiA zKt482>mKY=_e~Yv*FNoj`-5zs26Z5lnS39EwKWc{HTY2MIyWzAS_%#?ZTDV~@uK=TWCAwO zO5t9KeSUYReglVutdPz$&;lhnE~9*c>mYTj$6zj>&pm6aZW(Xh6!&!AK?kv{7}f5G zF87Q`;708b?d5>zf!yR%$&2D&pWBrrcnVtDk@I7(f_GbJw_V^2_ z{hsv);Z-YPKgj&o(~N!9-ytn~Jl2NESC}47{hH9kd+t#PDdY@6~^V_ej~8 z7saZK7hSpvoRfDU2)F-=#bA={M(#m{I0zb&WY>#zUzor0To3e&K^ccU+a_v$9MwO2 zg*0R4W6EclP=Du6mvGNGL&_EW^5vhqJU>_I5bimjH0n>(h>Zqek2Mxf5;#(@tA-(t z=8Gp_(=hdd+da7f=O^E>kFYwz!{wA(atMEN+(_(x)S^Oss~OX#G`}~+b>XyL+VHE{ z)H3h*`m_4Ppm%wPQ22;uBk0HG&n(k_ZDhz&s^Y<-)uzT^KkU2BA>)buZ1ocdG3Uth z+o-S@Y=X?=r@hNyvlJxIDnHR5dsjQ~>4Wl%VM4bTZTH~&5xiAp&)X6NIB#Du$cbh= zNFi3HIxdv4oS0jR8~v-+7@2wlbI#kmsLTyP-s?#1T*<8+D;X6pNP2Mo7YhvW9b!Bf z)n%{vbBA7hNu)Uv9s*BkSvkO0ItvjUvNNpHl1q3*-Wtx6X!jUL)Fbq{d1y-ikp zk>Y{X*p->aMtyE*@9lve|2Nna4UHUl_q94D*3?PBn}HG;LlE?P14B}StN=7LW|YCY zG9`q@KgUCy1tS%bCrI)ijjHhvLPPTq*A5m@DoP=o1lr(W55W*_m~$R3?y!0N!|jtQZM!ZW#%c z`iG~a4{^$9&<7&}vXi8Na5Shz(gLc`;Pu;l;64TcR#Lob-V{@ZBB7x8TLkdoIw(?# z1RdU<1tR>ZGM^*_5-B-zH>qaR5)zc3MF8T#6jKbuMl*uLuc62zpFfVYfIWl?dc`2X z*;#3zDV%Du-Q@&z=b*?V^SLAC$|I>@@|*!c7ekd>b1KOH4e2;&XmpP7jd4`Sd)^S> zPNB-lc>{neog$?`^#We7n+yeg77zeDlj_nbf`Z6-D9Bs#|BqPmJ~h+4goDbfEg}Gk zT#8Etj9-)nL<%TU0W`z^U6huL0H8$_ml&u}`F84c zrDskYX>wsH1r!C@mQDiO&ET<7QP71V>ANXXp0c7G3c_Cef7_(`z_lfJV80*yHLgYN nvEpR}Ffj;rE}sKLhd|1%F5dI!=ox-rLy2 { @@ -31,17 +30,17 @@ public void apply(final Project project) { private static void configureExtension(final Project project) { final AvroExtension avroExtension = createExtensionWithObjectFactory(project, AVRO_EXTENSION_NAME, DefaultAvroExtension.class); project.getTasks().withType(GenerateAvroJavaTask.class).all(task -> { - configurePropertyConvention(task.getOutputCharacterEncoding(), avroExtension.getOutputCharacterEncoding()); - configurePropertyConvention(task.getStringType(), avroExtension.getStringType()); - configurePropertyConvention(task.getFieldVisibility(), avroExtension.getFieldVisibility()); - configurePropertyConvention(task.getTemplateDirectory(), avroExtension.getTemplateDirectory()); - configurePropertyConvention(task.isCreateSetters(), avroExtension.isCreateSetters()); - configurePropertyConvention(task.isCreateOptionalGetters(), avroExtension.isCreateOptionalGetters()); - configurePropertyConvention(task.isGettersReturnOptional(), avroExtension.isGettersReturnOptional()); - configurePropertyConvention(task.isEnableDecimalLogicalType(), avroExtension.isEnableDecimalLogicalType()); - configurePropertyConvention(task.getDateTimeLogicalType(), avroExtension.getDateTimeLogicalType()); - configurePropertyConvention(task.getLogicalTypeFactories(), avroExtension.getLogicalTypeFactories()); - configurePropertyConvention(task.getCustomConversions(), avroExtension.getCustomConversions()); + task.getOutputCharacterEncoding().convention(avroExtension.getOutputCharacterEncoding()); + task.getStringType().convention(avroExtension.getStringType()); + task.getFieldVisibility().convention(avroExtension.getFieldVisibility()); + task.getTemplateDirectory().convention(avroExtension.getTemplateDirectory()); + task.isCreateSetters().convention(avroExtension.isCreateSetters()); + task.isCreateOptionalGetters().convention(avroExtension.isCreateOptionalGetters()); + task.isGettersReturnOptional().convention(avroExtension.isGettersReturnOptional()); + task.isEnableDecimalLogicalType().convention(avroExtension.isEnableDecimalLogicalType()); + task.getDateTimeLogicalType().convention(avroExtension.getDateTimeLogicalType()); + task.getLogicalTypeFactories().convention(avroExtension.getLogicalTypeFactories()); + task.getCustomConversions().convention(avroExtension.getCustomConversions()); }); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 1e127b8a2a1..81025afa224 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -15,12 +15,13 @@ */ package com.commercehub.gradle.plugin.avro; -import java.util.List; -import java.util.Map; import org.apache.avro.Conversion; import org.apache.avro.LogicalTypes; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; +@SuppressWarnings("unused") public interface AvroExtension { Property getOutputCharacterEncoding(); Property getStringType(); @@ -31,12 +32,8 @@ public interface AvroExtension { Property isGettersReturnOptional(); Property isEnableDecimalLogicalType(); Property getDateTimeLogicalType(); - // When we require Gradle 5.1+, we could use MapProperty here. - @SuppressWarnings("rawtypes") - Property getLogicalTypeFactories(); - // When we require Gradle 4.5+, we could use ListProperty here. - @SuppressWarnings("rawtypes") - Property getCustomConversions(); + MapProperty> getLogicalTypeFactories(); + ListProperty>> getCustomConversions(); AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass); AvroExtension customConversion(Class> conversionClass); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 0cd6321c21e..62bdf5a2c53 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -38,7 +38,6 @@ import static com.commercehub.gradle.plugin.avro.Constants.JAVA_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; import static org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME; public class AvroPlugin implements Plugin { @@ -95,7 +94,7 @@ private static GenerateAvroProtocolTask configureProtocolGenerationTask(final Pr task.source(getAvroSourceDir(project, sourceSet)); task.include("**/*." + IDL_EXTENSION); task.setClasspath(project.getConfigurations().getByName(RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - configurePropertyConvention(task.getOutputDir(), getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION)); + task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION)); return task; } @@ -110,7 +109,7 @@ private static GenerateAvroJavaTask configureJavaGenerationTask(final Project pr task.source(protoTask.getOutputDir()); task.source(protoTask.getOutputs()); task.include("**/*." + SCHEMA_EXTENSION, "**/*." + PROTOCOL_EXTENSION); - configurePropertyConvention(task.getOutputDir(), getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION)); + task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION)); sourceSet.getJava().srcDir(task.getOutputDir()); @@ -118,7 +117,7 @@ private static GenerateAvroJavaTask configureJavaGenerationTask(final Project pr compileJavaTask.source(task.getOutputDir()); compileJavaTask.source(task.getOutputs()); - configurePropertyConvention(task.getOutputCharacterEncoding(), project.provider(() -> + task.getOutputCharacterEncoding().convention(project.provider(() -> Optional.ofNullable(compileJavaTask.getOptions().getEncoding()).orElse(Charset.defaultCharset().name()))); return task; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index db3db00893e..0b10f9b780b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -18,9 +18,12 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import org.apache.avro.Conversion; +import org.apache.avro.LogicalTypes; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; import org.apache.avro.generic.GenericData.StringType; +import org.gradle.api.reflect.TypeOf; /** * Various constants needed by the plugin. @@ -38,10 +41,8 @@ class Constants { static final boolean DEFAULT_GETTERS_RETURN_OPTIONAL = false; static final boolean DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE = true; static final String DEFAULT_DATE_TIME_LOGICAL_TYPE = SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT.name(); - @SuppressWarnings("rawtypes") - static final Map DEFAULT_LOGICAL_TYPE_FACTORIES = Collections.emptyMap(); - @SuppressWarnings("rawtypes") - static final List DEFAULT_CUSTOM_CONVERSIONS = Collections.emptyList(); + static final Map> DEFAULT_LOGICAL_TYPE_FACTORIES = Collections.emptyMap(); + static final List>> DEFAULT_CUSTOM_CONVERSIONS = Collections.emptyList(); static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; @@ -55,4 +56,10 @@ class Constants { static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; static final String OPTION_DATE_TIME_LOGICAL_TYPE = "dateTimeLogicalType"; + + static final TypeOf> LOGICAL_TYPE_FACTORY_TYPE = + new TypeOf>() { }; + + static final TypeOf>> CONVERSION_TYPE = + new TypeOf>>() { }; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 86f2f98220b..256fc608849 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -16,9 +16,6 @@ package com.commercehub.gradle.plugin.avro; import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.avro.Conversion; @@ -26,6 +23,8 @@ import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.generic.GenericData; import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -38,8 +37,8 @@ import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_LOGICAL_TYPE_FACTORIES; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; +@SuppressWarnings({"unused", "WeakerAccess"}) public class DefaultAvroExtension implements AvroExtension { private final Property outputCharacterEncoding; private final Property stringType; @@ -50,26 +49,23 @@ public class DefaultAvroExtension implements AvroExtension { private final Property gettersReturnOptional; private final Property enableDecimalLogicalType; private final Property dateTimeLogicalType; - // When we require Gradle 5.1+, we could use MapProperty here. - @SuppressWarnings("rawtypes") - private final Property logicalTypeFactories; - // When we require Gradle 4.5+, we could use ListProperty here. - @SuppressWarnings("rawtypes") - private final Property customConversions; + private final MapProperty> logicalTypeFactories; + private final ListProperty>> customConversions; @Inject public DefaultAvroExtension(ObjectFactory objects) { this.outputCharacterEncoding = objects.property(String.class); - this.stringType = configurePropertyConvention(objects.property(String.class), DEFAULT_STRING_TYPE); - this.fieldVisibility = configurePropertyConvention(objects.property(String.class), DEFAULT_FIELD_VISIBILITY); + this.stringType = objects.property(String.class).convention(DEFAULT_STRING_TYPE); + this.fieldVisibility = objects.property(String.class).convention(DEFAULT_FIELD_VISIBILITY); this.templateDirectory = objects.property(String.class); - this.createSetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_SETTERS); - this.createOptionalGetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_OPTIONAL_GETTERS); - this.gettersReturnOptional = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_GETTERS_RETURN_OPTIONAL); - this.enableDecimalLogicalType = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); - this.dateTimeLogicalType = configurePropertyConvention(objects.property(String.class), DEFAULT_DATE_TIME_LOGICAL_TYPE); - this.logicalTypeFactories = configurePropertyConvention(objects.property(Map.class), DEFAULT_LOGICAL_TYPE_FACTORIES); - this.customConversions = configurePropertyConvention(objects.property(List.class), DEFAULT_CUSTOM_CONVERSIONS); + this.createSetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_SETTERS); + this.createOptionalGetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_OPTIONAL_GETTERS); + this.gettersReturnOptional = objects.property(Boolean.class).convention(DEFAULT_GETTERS_RETURN_OPTIONAL); + this.enableDecimalLogicalType = objects.property(Boolean.class).convention(DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); + this.dateTimeLogicalType = objects.property(String.class).convention(DEFAULT_DATE_TIME_LOGICAL_TYPE); + this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) + .convention(DEFAULT_LOGICAL_TYPE_FACTORIES); + this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(DEFAULT_CUSTOM_CONVERSIONS); } @Override @@ -186,8 +182,7 @@ public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplement } @Override - @SuppressWarnings("rawtypes") - public Property getLogicalTypeFactories() { + public MapProperty> getLogicalTypeFactories() { return logicalTypeFactories; } @@ -202,40 +197,27 @@ public void setLogicalTypeFactories(Map getCustomConversions() { + public ListProperty>> getCustomConversions() { return customConversions; } - @SuppressWarnings("rawtypes") - public void setCustomConversions(Provider>> provider) { - // If we were using ListProperty, this method could take Iterables rather than Lists + public void setCustomConversions(Provider>>> provider) { this.customConversions.set(provider); } - @SuppressWarnings("rawtypes") - public void setCustomConversions(List> customConversions) { - // If we were using ListProperty, this method could take Iterables rather than Lists + public void setCustomConversions(Iterable>> customConversions) { this.customConversions.set(customConversions); } - @SuppressWarnings("unchecked") @Override public AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass) { - // If we were using MapProperty, we could use the put method here - Map> newValue = new LinkedHashMap<>(logicalTypeFactories.get()); - newValue.put(typeName, typeFactoryClass); - logicalTypeFactories.set(newValue); + logicalTypeFactories.put(typeName, typeFactoryClass); return this; } - @SuppressWarnings({"unchecked", "rawtypes"}) @Override public AvroExtension customConversion(Class> conversionClass) { - // If we were using ListProperty, we could use the add method here - List> newValue = new ArrayList<>(customConversions.get()); - newValue.add(conversionClass); - customConversions.set(newValue); + customConversions.add(conversionClass); return this; } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java index 1533066ea69..cdf3905196d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java @@ -111,24 +111,15 @@ private static FileOutputStream openOutputStream(File file) throws IOException { * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM */ - static void writeStringToFile(File file, String data, String encoding) throws IOException { + @SuppressWarnings("SameParameterValue") + private static void writeStringToFile(File file, String data, String encoding) throws IOException { if (encoding == null) { throw new IllegalArgumentException("Must specify encoding"); } - OutputStream out = null; - try { - out = openOutputStream(file); + try (OutputStream out = openOutputStream(file)) { if (data != null) { out.write(data.getBytes(encoding)); } - } finally { - try { - if (out != null) { - out.close(); - } - } catch (IOException ioe) { - // ignore - } } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 45c6b803564..1d50da2a28c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -18,7 +18,6 @@ import java.io.File; import java.io.IOException; import java.nio.charset.Charset; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; @@ -37,6 +36,8 @@ import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.specs.NotSpec; @@ -59,13 +60,13 @@ import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.configurePropertyConvention; import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; /** * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and * {@link SpecificCompiler}. */ +@SuppressWarnings("WeakerAccess") @CacheableTask public class GenerateAvroJavaTask extends OutputDirTask { private static Pattern ERROR_UNKNOWN_TYPE = Pattern.compile("(?i).*(undefined name|not a defined name).*"); @@ -81,11 +82,8 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Property createSetters; private final Property enableDecimalLogicalType; private final Property dateTimeLogicalType; - // When we require Gradle 5.1+, we could use MapProperty here. - @SuppressWarnings("rawtypes") - private final Property logicalTypeFactories; - @SuppressWarnings("rawtypes") - private final Property customConversions; + private final MapProperty> logicalTypeFactories; + private final ListProperty>> customConversions; private final Provider stringTypeProvider; private final Provider fieldVisibilityProvider; @@ -95,14 +93,14 @@ public class GenerateAvroJavaTask extends OutputDirTask { public GenerateAvroJavaTask(ObjectFactory objects) { super(); this.outputCharacterEncoding = objects.property(String.class); - this.stringType = configurePropertyConvention(objects.property(String.class), DEFAULT_STRING_TYPE); - this.fieldVisibility = configurePropertyConvention(objects.property(String.class), DEFAULT_FIELD_VISIBILITY); + this.stringType = objects.property(String.class).convention(DEFAULT_STRING_TYPE); + this.fieldVisibility = objects.property(String.class).convention(DEFAULT_FIELD_VISIBILITY); this.templateDirectory = objects.property(String.class); - this.createOptionalGetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_OPTIONAL_GETTERS); - this.gettersReturnOptional = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_GETTERS_RETURN_OPTIONAL); - this.createSetters = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_CREATE_SETTERS); - this.enableDecimalLogicalType = configurePropertyConvention(objects.property(Boolean.class), DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); - this.dateTimeLogicalType = configurePropertyConvention(objects.property(String.class), DEFAULT_DATE_TIME_LOGICAL_TYPE); + this.createOptionalGetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_OPTIONAL_GETTERS); + this.gettersReturnOptional = objects.property(Boolean.class).convention(DEFAULT_GETTERS_RETURN_OPTIONAL); + this.createSetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_SETTERS); + this.enableDecimalLogicalType = objects.property(Boolean.class).convention(DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); + this.dateTimeLogicalType = objects.property(String.class).convention(DEFAULT_DATE_TIME_LOGICAL_TYPE); this.stringTypeProvider = getStringType() .map(input -> Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), input)); this.fieldVisibilityProvider = getFieldVisibility() @@ -110,9 +108,9 @@ public GenerateAvroJavaTask(ObjectFactory objects) { this.dateTimeLogicalTypeImplementationProvider = getDateTimeLogicalType() .map(input -> Enums.parseCaseInsensitive(OPTION_DATE_TIME_LOGICAL_TYPE, SpecificCompiler.DateTimeLogicalTypeImplementation.values(), input)); - this.logicalTypeFactories = - configurePropertyConvention(objects.property(Map.class), DEFAULT_LOGICAL_TYPE_FACTORIES); - this.customConversions = configurePropertyConvention(objects.property(List.class), DEFAULT_CUSTOM_CONVERSIONS); + this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) + .convention(DEFAULT_LOGICAL_TYPE_FACTORIES); + this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(DEFAULT_CUSTOM_CONVERSIONS); } @Optional @@ -233,18 +231,15 @@ public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplement @Optional @Input - @SuppressWarnings("rawtypes") - public Property getLogicalTypeFactories() { + public MapProperty> getLogicalTypeFactories() { return logicalTypeFactories; } - @SuppressWarnings("rawtypes") public void setLogicalTypeFactories(Provider>> provider) { this.logicalTypeFactories.set(provider); } - @SuppressWarnings("rawtypes") public void setLogicalTypeFactories(Map> logicalTypeFactories) { this.logicalTypeFactories.set(logicalTypeFactories); @@ -252,23 +247,19 @@ public void setLogicalTypeFactories(Map getCustomConversions() { + public ListProperty>> getCustomConversions() { return customConversions; } - public void setCustomConversions(Provider>>> provider) { - // If we were using ListProperty, this method could take Iterables rather than Lists + public void setCustomConversions(Provider>>> provider) { this.customConversions.set(provider); } - public void setCustomConversions(List>> customConversions) { - // If we were using ListProperty, this method could take Iterables rather than Lists + public void setCustomConversions(Iterable>> customConversions) { this.customConversions.set(customConversions); } @TaskAction - @SuppressWarnings({"rawtypes", "unchecked"}) protected void process() { getLogger().debug("Using outputCharacterEncoding {}", getOutputCharacterEncoding().getOrNull()); getLogger().debug("Using stringType {}", stringTypeProvider.get().name()); @@ -281,8 +272,8 @@ protected void process() { getLogger().debug("Using dateTimeLogicalType {}", dateTimeLogicalTypeImplementationProvider.get().name()); getLogger().debug("Using logicalTypeFactories {}", logicalTypeFactories.get().entrySet().stream().collect(Collectors.toMap( - (Map.Entry e) -> (String) e.getKey(), - (Map.Entry e) -> ((Class) e.getValue()).getName() + Map.Entry::getKey, + (Map.Entry> e) -> e.getValue().getName() ))); getLogger().debug("Using customConversions {}", customConversions.get().stream().map(v -> ((Class) v).getName()).collect(Collectors.toList())); @@ -401,7 +392,6 @@ private void compile(Schema schema, File sourceFile) throws IOException { compile(new SpecificCompiler(schema, dateTimeLogicalTypeImplementationProvider.get()), sourceFile); } - @SuppressWarnings("rawtypes") private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { compiler.setOutputCharacterEncoding(getOutputCharacterEncoding().getOrNull()); compiler.setStringType(stringTypeProvider.get()); @@ -423,16 +413,15 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept * This must be called before the Schemas are parsed, or they will not be applied correctly. * Since {@link LogicalTypes} is a static registry, this may result in side-effects. */ - @SuppressWarnings({"rawtypes", "unchecked"}) private void registerLogicalTypes() { - Map logicalTypeFactoryMap = logicalTypeFactories.get(); - Set> logicalTypeFactoryEntries = logicalTypeFactoryMap.entrySet(); - for (Map.Entry entry : logicalTypeFactoryEntries) { - String logicalTypeName = (String) entry.getKey(); - Class logicalTypeFactoryClass = (Class) entry.getValue(); + Map> logicalTypeFactoryMap = logicalTypeFactories.get(); + Set>> logicalTypeFactoryEntries = + logicalTypeFactoryMap.entrySet(); + for (Map.Entry> entry : logicalTypeFactoryEntries) { + String logicalTypeName = entry.getKey(); + Class logicalTypeFactoryClass = entry.getValue(); try { - LogicalTypes.LogicalTypeFactory logicalTypeFactory = - (LogicalTypes.LogicalTypeFactory) logicalTypeFactoryClass.getDeclaredConstructor().newInstance(); + LogicalTypes.LogicalTypeFactory logicalTypeFactory = logicalTypeFactoryClass.getDeclaredConstructor().newInstance(); LogicalTypes.register(logicalTypeName, logicalTypeFactory); } catch (ReflectiveOperationException ex) { getLogger().error("Could not instantiate logicalTypeFactory class \"" + logicalTypeFactoryClass.getName() + "\""); @@ -440,8 +429,7 @@ private void registerLogicalTypes() { } } - @SuppressWarnings("unchecked") private void registerCustomConversions(SpecificCompiler compiler) { - customConversions.get().forEach(v -> compiler.addCustomConversion((Class) v)); + customConversions.get().forEach(compiler::addCustomConversion); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java index 3a019c86e59..df2d7b08e17 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java @@ -18,9 +18,6 @@ import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.provider.Provider; class GradleCompatibility { static T createExtensionWithObjectFactory(Project project, String extensionName, Class extensionType) { @@ -31,41 +28,12 @@ static T createExtensionWithObjectFactory(Project project, String extensionN } } - @SuppressWarnings("deprecation") - static DirectoryProperty createDirectoryProperty(Project project) { - if (GradleFeatures.objectFactoryDirectoryProperty.isSupported()) { - return project.getObjects().directoryProperty(); - } else { - return project.getLayout().directoryProperty(); - } - } - @SuppressWarnings("deprecation") static ConfigurableFileCollection createConfigurableFileCollection(Project project) { if (GradleFeatures.objectFactoryFileCollection.isSupported()) { return project.getObjects().fileCollection(); - } else if (GradleFeatures.projectLayoutConfigurableFiles.isSupported()) { - return project.getLayout().configurableFiles(); } else { - return project.files(); - } - } - - static Property configurePropertyConvention(Property property, Provider valueProvider) { - if (GradleFeatures.propertyConventions.isSupported()) { - property.convention(valueProvider); - } else { - property.set(valueProvider); - } - return property; - } - - static Property configurePropertyConvention(Property property, T value) { - if (GradleFeatures.propertyConventions.isSupported()) { - property.convention(value); - } else { - property.set(value); + return project.getLayout().configurableFiles(); } - return property; } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java index ea096ca605d..aa54b538775 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java @@ -25,24 +25,6 @@ boolean isSupported() { return GradleVersion.current().compareTo(GradleVersions.v5_2) >= 0; } }, - propertyConventions() { - @Override - boolean isSupported() { - return GradleVersion.current().compareTo(GradleVersions.v5_1) >= 0; - } - }, - objectFactoryDirectoryProperty() { - @Override - boolean isSupported() { - return GradleVersion.current().compareTo(GradleVersions.v5_0) >= 0; - } - }, - projectLayoutConfigurableFiles() { - @Override - boolean isSupported() { - return GradleVersion.current().compareTo(GradleVersions.v4_8) >= 0; - } - }, objectFactoryFileCollection() { @Override boolean isSupported() { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java index fb962241234..3adab2c39e5 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java @@ -19,9 +19,6 @@ import org.gradle.util.GradleVersion; class GradleVersions { - static final GradleVersion v4_8 = GradleVersion.version("4.8"); - static final GradleVersion v5_0 = GradleVersion.version("5.0"); - static final GradleVersion v5_1 = GradleVersion.version("5.1"); static final GradleVersion v5_2 = GradleVersion.version("5.2"); static final GradleVersion v5_3 = GradleVersion.version("5.3"); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java index 6140775fb7f..7eefeed4693 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java @@ -16,6 +16,7 @@ package com.commercehub.gradle.plugin.avro; import java.io.File; +import javax.annotation.Nonnull; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTree; @@ -24,14 +25,13 @@ import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.SourceTask; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.createDirectoryProperty; import static org.gradle.api.tasks.PathSensitivity.RELATIVE; class OutputDirTask extends SourceTask { private final DirectoryProperty outputDir; - protected OutputDirTask() { - this.outputDir = createDirectoryProperty(getProject()); + OutputDirTask() { + this.outputDir = getProject().getObjects().directoryProperty(); } public void setOutputDir(File outputDir) { @@ -39,6 +39,7 @@ public void setOutputDir(File outputDir) { getOutputs().dir(outputDir); } + @Nonnull @PathSensitive(value = RELATIVE) public FileTree getSource() { return super.getSource(); @@ -49,7 +50,7 @@ protected DirectoryProperty getOutputDir() { return outputDir; } - protected FileCollection filterSources(Spec spec) { + FileCollection filterSources(Spec spec) { return getSource().filter(spec); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java index ddfe0e65066..0131247c16f 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -65,7 +65,7 @@ Set getFailedFiles() { return delayedFiles; } - TypeState getTypeState(String typeName) { + private TypeState getTypeState(String typeName) { TypeState typeState = typeStates.get(typeName); if (typeState == null) { typeState = new TypeState(typeName); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java index e14d3d9321b..34b18c4543a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java @@ -20,6 +20,7 @@ import java.util.HashSet; import java.util.Set; +@SuppressWarnings("UnusedReturnValue") class SetBuilder { private Set set = new HashSet(); diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy index f24c020c753..b57eb28883a 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy @@ -15,26 +15,12 @@ */ package com.commercehub.gradle.plugin.avro -import org.gradle.util.GradleVersion -import spock.lang.IgnoreIf - class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { def "setup"() { applyAvroPlugin() addAvroDependency() } - /** - * Since Kotlin 1.1.2, the Kotlin compiler requires Java 8+ - * https://blog.jetbrains.com/kotlin/2017/04/kotlin-1-1-2-is-out/ - * - * Kotlin support appears broken on Gradle 3.2-3.2.1 - * https://discuss.kotlinlang.org/t/1-1-50-js-compiler-requires-kotlin-reflect/4699 - */ - @IgnoreIf({ - javaVersion < 1.8 || - (gradleVersion >= GradleVersion.version("3.2") && gradleVersion <= GradleVersion.version("3.2.1")) - }) def "works with kotlin-gradle-plugin"() { given: File kotlinDir = testProjectDir.newFolder("src", "main", "kotlin") @@ -44,7 +30,7 @@ class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { jcenter() } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.31" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61" } } apply plugin: "kotlin" From 6fe19a594e2d8c73b5ce0cc9d899c2d39b69a8d3 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 24 Feb 2020 13:13:19 -0500 Subject: [PATCH 289/479] Update changelog for #104 --- CHANGES.md | 1 + README.md | 8 ++++---- .../plugin/avro/CustomConversionFunctionalSpec.groovy | 6 ++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 709052c3097..79180a6c64c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ * Add support for Gradle 6.0-6.2 (#101) * Drop support for Gradle versions prior to 5.1 * Update version of kotlin plugin in tests/example +* Built using Avro 1.9.2 (#104) ## 0.18.0 * Use reproducible file order for plugin archives diff --git a/README.md b/README.md index 164bd4be29c..6746a33bda0 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * If you need support for Gradle 4.4-5.0, version 0.18.0 was the last version tested for compatibility * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Avro 1.9.1 - * Currently tested against Avro 1.9.0-1.9.1 +* Currently built against Avro 1.9.2 + * Currently tested against Avro 1.9.0-1.9.2 * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) @@ -49,7 +49,7 @@ repositories { jcenter() } dependencies { - compile "org.apache.avro:avro:1.9.1" + compile "org.apache.avro:avro:1.9.2" } ``` @@ -252,7 +252,7 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - compile "org.apache.avro:avro:1.9.1" + compile "org.apache.avro:avro:1.9.2" } task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index 46c8905ce98..e6320623ec2 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -15,10 +15,7 @@ */ package com.commercehub.gradle.plugin.avro -import spock.lang.Requires - import static org.gradle.testkit.runner.TaskOutcome.SUCCESS -import static org.gradle.util.GradleVersion.version class CustomConversionFunctionalSpec extends FunctionalSpec { def "setup"() { @@ -35,9 +32,10 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { "com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java") } - @Requires({ version(avroVersion).compareTo(version("1.9.2")) >= 0 }) def "can use a custom conversion when generating java from a schema with stringType = \"String\""() { // since Avro 1.9.2 https://issues.apache.org/jira/browse/AVRO-2548 is fixed + // This is a behavior of the buildscript version of avro rather than the compile-time one, + // so our version compatibility tests won't cover the difference given: copyResource("customConversion.avsc", avroDir) buildFile << """ From 6b1f1df744e4665759d0b79f120194f5468edf64 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 24 Feb 2020 22:24:48 -0500 Subject: [PATCH 290/479] Add support for Java 13 --- .github/workflows/ci.yml | 4 ++-- .travis.yml | 26 -------------------------- CHANGES.md | 1 + README.md | 3 ++- build.gradle | 5 ++++- 5 files changed, 9 insertions(+), 30 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0997bdc4432..c9f2e009236 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - java: [8.0.222, 11.0.4] + java: [8, 11, 13] fail-fast: true max-parallel: 5 steps: @@ -60,7 +60,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - java: [13.0.0] + java: [14-ea, 15-ea] fail-fast: false max-parallel: 5 steps: diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 51343af2734..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: true -dist: trusty -language: java - -install: true - -matrix: - include: - - jdk: openjdk8 - - jdk: openjdk9 - - jdk: openjdk10 - - jdk: openjdk11 - - jdk: openjdk12 - - jdk: openjdk-ea - allow_failures: - - jdk: openjdk-ea - -env: - global: - - GRADLE_OPTS="-Xmx386m -Xms386m" - -script: - - echo PATH = ${PATH} - - echo JAVA_HOME = ${JAVA_HOME} - - java -Xmx32m -version - - ./gradlew build testRecentVersionCompatibility --info diff --git a/CHANGES.md b/CHANGES.md index 79180a6c64c..f59d8ee0a95 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ * Drop support for Gradle versions prior to 5.1 * Update version of kotlin plugin in tests/example * Built using Avro 1.9.2 (#104) +* Add support for Java 13 ## 0.18.0 * Use reproducible file order for plugin archives diff --git a/README.md b/README.md index 6746a33bda0..be60a10c0ef 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Java 8-12 +* Currently tested against Java 8-13 + * Java 13 support requires Gradle 6.0 or higher * Java 11 support requires Gradle 4.8 or higher * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) diff --git a/build.gradle b/build.gradle index 72615b40605..cc79b786acc 100644 --- a/build.gradle +++ b/build.gradle @@ -185,7 +185,10 @@ sourceCompatibility = 8 def avroVersions = ["1.9.0", "1.9.1", "1.9.2"] def gradleVersions = [] -gradleVersions.addAll("5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4") +if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { + // Java 13 support was added in Gradle 6.0 + gradleVersions.addAll("5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4") +} gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2") avroVersions.each { def avroVersion -> From 5dfc8b807a8e262c76a9104f5efcd6eb881ef8d2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Mar 2020 14:13:28 -0500 Subject: [PATCH 291/479] Add support for testing multiple kotlin versions --- CHANGES.md | 1 + README.md | 6 +- build.gradle | 114 ++++++++++++++++-- .../KotlinCompatibilityFunctionalSpec.groovy | 7 +- 4 files changed, 115 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f59d8ee0a95..d2361c42f07 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ * Update version of kotlin plugin in tests/example * Built using Avro 1.9.2 (#104) * Add support for Java 13 +* Add support for testing multiple Kotlin versions ## 0.18.0 * Use reproducible file order for plugin archives diff --git a/README.md b/README.md index be60a10c0ef..dd9c70d4949 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,10 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) * Versions of Avro prior to 1.7.x are unlikely to work -* Incubating: support for Kotlin - * Currently tested against Kotlin plugin version 1.3.61 +* Support for Kotlin + * Currently tested against Kotlin plugin versions 1.3.20-1.3.61 using the latest supported version of Gradle + * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 + * Version of the Kotlin plugin prior to 1.2.20 are unlikely to work * Incubating: support for Gradle Kotlin DSL * No test coverage yet; will attempt to address incompatibilities as they are discovered diff --git a/build.gradle b/build.gradle index cc79b786acc..16550f4572e 100644 --- a/build.gradle +++ b/build.gradle @@ -162,21 +162,29 @@ codenarc { toolVersion = "1.4" } -tasks.create("testVersionCompatibility") { - description = "Tests cross-compatibility of the plugin with different versions of Avro and Gradle." +tasks.create("testAvroCompatibility") { + description = "Tests cross-compatibility of the plugin with different versions of Avro." group = "Verification" } -tasks.create("testRecentVersionCompatibility") { - description = "Tests cross-compatibility of the plugin with recent versions of Avro and Gradle." +tasks.create("testGradleCompatibility") { + description = "Tests cross-compatibility of the plugin with different versions of Gradle." group = "Verification" } -test { - systemProperties = [ - avroVersion: compileAvroVersion, - gradleVersion: gradle.gradleVersion, - ] +tasks.create("testKotlinCompatibility") { + description = "Tests cross-compatibility of the plugin with different versions of Kotlin." + group = "Verification" +} + +tasks.create("testVersionCompatibility") { + description = "Tests cross-compatibility of the plugin with different versions of Avro, Gradle, and Kotlin." + group = "Verification" +} + +tasks.create("testRecentVersionCompatibility") { + description = "Tests cross-compatibility of the plugin with recent versions of Avro, Gradle, and Kotlin." + group = "Verification" } // Java 8+ is required due to requirements introduced in Avro 1.9.0 @@ -184,20 +192,52 @@ test { sourceCompatibility = 8 def avroVersions = ["1.9.0", "1.9.1", "1.9.2"] +def keyAvroVersions = avroVersions.last() +def gradle5KotlinVersions = [ + "1.2.20", "1.2.21", "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", + "1.3.0", "1.3.10", "1.3.11", +] +def latestGradleKotlinVersions = [ + "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", +] +def kotlinVersions = gradle5KotlinVersions + latestGradleKotlinVersions +def keyKotlinVersions = [ // First and last version for each supported line + "1.2.20", "1.2.71", + "1.3.0", "1.3.61", +] +def keyGradleVersions = [] // First and last version for each supported line +def firstSupportedGradleVersion = null def gradleVersions = [] if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { // Java 13 support was added in Gradle 6.0 gradleVersions.addAll("5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4") + keyGradleVersions.addAll("5.1", "5.6.4") // First and last for the 5.x line + firstSupportedGradleVersion = gradleVersions.first() } gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2") +keyGradleVersions.addAll("6.0", "6.2") // First and last for the 6.x line + +def latestAvroVersion = avroVersions.last() +def latestGradleVersion = gradleVersions.last() +def latestKotlinVersion = kotlinVersions.last() + +test { + systemProperties = [ + avroVersion: compileAvroVersion, + gradleVersion: gradle.gradleVersion, + kotlinVersion: latestKotlinVersion, + ] +} avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> + def kotlinVersion = latestKotlinVersion def newTask = tasks.create(name: "testAvro${avroVersion}Gradle${gradleVersion}", type: Test) { description = "Test cross-compatibility of the plugin with Avro ${avroVersion} and Gradle ${gradleVersion}" systemProperties = [ avroVersion: avroVersion, gradleVersion: gradleVersion, + kotlinVersion: kotlinVersion, ] reports { html.destination = file("$buildDir/reports/tests-${avroVersion}-${gradleVersion}") @@ -205,12 +245,66 @@ avroVersions.each { def avroVersion -> } } testVersionCompatibility.dependsOn newTask - if (gradleVersions.indexOf(gradleVersion) >= gradleVersions.size() - 5) { + if (avroVersion == latestAvroVersion) { + testGradleCompatibility.dependsOn newTask + } + if (gradleVersion == latestGradleVersion) { + testAvroCompatibility.dependsOn newTask + } + if (gradleVersion in keyGradleVersions && avroVersion in keyAvroVersions) { testRecentVersionCompatibility.dependsOn newTask } } } +gradle5KotlinVersions.each { def kotlinVersion -> + def avroVersion = latestAvroVersion + def gradleVersion = firstSupportedGradleVersion + if (gradleVersion) { + def newTask = tasks.create(name: "testKotlin${kotlinVersion}", type: Test) { + description = "Test cross-compatibility of the plugin with Kotlin ${kotlinVersion}" + systemProperties = [ + avroVersion : avroVersion, + gradleVersion: gradleVersion, + kotlinVersion: kotlinVersion, + ] + include("**/KotlinCompatibilityFunctionalSpec.class") + reports { + html.destination = file("$buildDir/reports/tests-${kotlinVersion}") + junitXml.destination = file("$buildDir/reports/tests-${kotlinVersion}") + } + } + testVersionCompatibility.dependsOn newTask + testKotlinCompatibility.dependsOn newTask + if (kotlinVersion in keyKotlinVersions) { + testRecentVersionCompatibility.dependsOn newTask + } + } +} + +latestGradleKotlinVersions.each { def kotlinVersion -> + def avroVersion = latestAvroVersion + def gradleVersion = latestGradleVersion + def newTask = tasks.create(name: "testKotlin${kotlinVersion}", type: Test) { + description = "Test cross-compatibility of the plugin with Kotlin ${kotlinVersion}" + systemProperties = [ + avroVersion : avroVersion, + gradleVersion: gradleVersion, + kotlinVersion: kotlinVersion, + ] + include("**/KotlinCompatibilityFunctionalSpec.class") + reports { + html.destination = file("$buildDir/reports/tests-${kotlinVersion}") + junitXml.destination = file("$buildDir/reports/tests-${kotlinVersion}") + } + } + testVersionCompatibility.dependsOn newTask + testKotlinCompatibility.dependsOn newTask + if (kotlinVersion in keyKotlinVersions) { + testRecentVersionCompatibility.dependsOn newTask + } +} + tasks.withType(Test) { jvmArgs "-Xss320k" minHeapSize "120m" diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy index b57eb28883a..843b0f66964 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy @@ -15,8 +15,13 @@ */ package com.commercehub.gradle.plugin.avro +@SuppressWarnings(["Println"]) class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { + @SuppressWarnings(["FieldName"]) + protected static final String kotlinVersion = System.getProperty("kotlinVersion", "undefined") + def "setup"() { + println "Testing using Kotlin version ${kotlinVersion}." applyAvroPlugin() addAvroDependency() } @@ -30,7 +35,7 @@ class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { jcenter() } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" } } apply plugin: "kotlin" From 87063742cc7912f6eedc7bad359cd5288a1f35fc Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Mar 2020 14:14:58 -0500 Subject: [PATCH 292/479] Update plugin's own build to address some deprecation warnings of APIs being removed in Gradle 7 --- CHANGES.md | 1 + build.gradle | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d2361c42f07..34251d010ac 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ * Built using Avro 1.9.2 (#104) * Add support for Java 13 * Add support for testing multiple Kotlin versions +* Update plugin's own build to address some deprecation warnings of APIs being removed in Gradle 7 ## 0.18.0 * Use reproducible file order for plugin archives diff --git a/build.gradle b/build.gradle index 16550f4572e..01a94e24245 100644 --- a/build.gradle +++ b/build.gradle @@ -16,10 +16,10 @@ repositories { def compileAvroVersion = "1.9.2" dependencies { - compile localGroovy() - compile "org.apache.avro:avro-compiler:${compileAvroVersion}" - testCompile "org.spockframework:spock-core:1.3-groovy-2.5" - testCompile gradleTestKit() + implementation localGroovy() + implementation "org.apache.avro:avro-compiler:${compileAvroVersion}" + testImplementation "org.spockframework:spock-core:1.3-groovy-2.5" + testImplementation gradleTestKit() } tasks.withType(AbstractCompile) { @@ -40,13 +40,13 @@ tasks.withType(AbstractArchiveTask) { task sourcesJar(type: Jar, dependsOn: classes) { from sourceSets.main.allSource classifier "sources" - extension "jar" + archiveExtension.set("jar") } task javadocJar(type: Jar, dependsOn: javadoc) { from javadoc.destinationDir classifier "javadoc" - extension "jar" + archiveExtension.set("jar") } publishing { @@ -135,7 +135,7 @@ task createClasspathManifest { // Add the classpath file to the test runtime classpath dependencies { - testRuntime files(createClasspathManifest) + testRuntimeOnly files(createClasspathManifest) } checkstyle { From d0d1bafae49f5ee796295e7a38595df96370b18a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Mar 2020 14:27:05 -0500 Subject: [PATCH 293/479] BuildCacheSupportFunctionalSpec no longer needs an @IgnoreIf, as we only support versions where the Build Cache is supported. --- .../plugin/avro/BuildCacheSupportFunctionalSpec.groovy | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy index 48a52cb0ec2..c59339355f0 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy @@ -15,17 +15,11 @@ */ package com.commercehub.gradle.plugin.avro -import org.gradle.util.GradleVersion -import spock.lang.IgnoreIf - import static org.gradle.testkit.runner.TaskOutcome.FROM_CACHE /** * Testing for Build Cache feature support. - * - * Only run if on a version of Gradle after Build Cache support was introduced. */ -@IgnoreIf({ gradleVersion < GradleVersion.version("3.5") }) class BuildCacheSupportFunctionalSpec extends FunctionalSpec { def "setup"() { applyAvroPlugin() From b5a655dbcebf734a77fe8c31db7b317646cf0340 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Mar 2020 14:32:09 -0500 Subject: [PATCH 294/479] Remove license plugin It was resulting in deprecation warnings about Gradle 7, a new version wasn't available, and I don't think it was providing real value. --- build.gradle | 10 ---------- gradle/DEFAULT_LICENSE_NOTICE | 13 ------------- 2 files changed, 23 deletions(-) delete mode 100644 gradle/DEFAULT_LICENSE_NOTICE diff --git a/build.gradle b/build.gradle index 01a94e24245..bc60d7d1582 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,6 @@ plugins { id "maven-publish" id "java-gradle-plugin" id "com.jfrog.bintray" version "1.8.1" - id "com.github.hierynomus.license" version "0.14.0" } repositories { @@ -310,12 +309,3 @@ tasks.withType(Test) { minHeapSize "120m" maxHeapSize "280m" } - -license { - header = file("gradle/DEFAULT_LICENSE_NOTICE") - skipExistingHeaders = true - mapping("avdl", "JAVADOC_STYLE") - excludes(["**/*.avsc", "**/*.avpr"]) // JSON doesn't allow comments - exclude("**/record.vm") // Existing header in different style - // dryRun = true -} diff --git a/gradle/DEFAULT_LICENSE_NOTICE b/gradle/DEFAULT_LICENSE_NOTICE deleted file mode 100644 index 9104ff09113..00000000000 --- a/gradle/DEFAULT_LICENSE_NOTICE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright © 2016 Commerce Technologies, LLC. - -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. From 923956d47b41852379b55c70af49b6e79aeac117 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Mar 2020 16:54:57 -0500 Subject: [PATCH 295/479] Lots of test updates * Remove taskInfoAbsent, as it isn't needed any more with the versions of Gradle we support * Remove isMultipleClassDirectoriesUsed, as all versions of Gradle we support now use it * Leverage GradleRunner's withPluginClasspath feature when able to use plugin DSL to apply the test plugin * Add addDefaultRepository utility method * Add applyPlugin override that takes a version * Rename addDependency to addImplementationDependency; add addRuntimeDependency and addDependency that takes a configuration argument * Use stripMargin more consistently --- .../avro/AvroBasePluginFunctionalSpec.groovy | 82 +++++----- .../avro/AvroPluginFunctionalSpec.groovy | 31 ++-- .../BuildCacheSupportFunctionalSpec.groovy | 13 +- .../CustomConversionFunctionalSpec.groovy | 146 +++++++++++------- .../DuplicateHandlingFunctionalSpec.groovy | 15 +- .../plugin/avro/EncodingFunctionalSpec.groovy | 12 +- .../avro/EnumHandlingFunctionalSpec.groovy | 17 +- .../plugin/avro/ExamplesFunctionalSpec.groovy | 9 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 58 ++++--- ...erateAvroProtocolTaskFunctionalSpec.groovy | 46 +++--- .../plugin/avro/IntellijFunctionalSpec.groovy | 18 +-- .../KotlinCompatibilityFunctionalSpec.groovy | 30 +--- .../plugin/avro/OptionsFunctionalSpec.groovy | 43 ++++-- 13 files changed, 272 insertions(+), 248 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy index c9a2920f782..04edde1f976 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy @@ -25,12 +25,12 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "can generate java files from json schema"() { given: buildFile << """ - task("generateAvroJava", type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { - source file("src/main/avro") - include("**/*.avsc") - outputDir = file("build/generated-main-avro-java") - } - """ + |task("generateAvroJava", type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { + | source file("src/main/avro") + | include("**/*.avsc") + | outputDir = file("build/generated-main-avro-java") + |} + |""".stripMargin() copyResource("user.avsc", avroDir) @@ -38,19 +38,19 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS projectFile("build/generated-main-avro-java/example/avro/User.java").file } def "can generate json schema files from json protocol"() { given: buildFile << """ - task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { - source file("src/main/avro") - include("**/*.avpr") - outputDir = file("build/generated-main-avro-avsc") - } - """ + |task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + | source file("src/main/avro") + | include("**/*.avpr") + | outputDir = file("build/generated-main-avro-avsc") + |} + |""".stripMargin() copyResource("mail.avpr", avroDir) @@ -58,7 +58,7 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def result = run("generateSchema") then: - taskInfoAbsent || result.task(":generateSchema").outcome == SUCCESS + result.task(":generateSchema").outcome == SUCCESS def expectedFileContents = getClass().getResource("Message.avsc").text.trim() def generateFileContents = new File(testProjectDir.root, "build/generated-main-avro-avsc/org/apache/avro/test/Message.avsc").text.trim() @@ -68,18 +68,17 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "can generate json schema files from IDL"() { given: buildFile << """ - task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { - source file("src/main/avro") - outputDir = file("build/generated-avro-main-avpr") - } - - task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { - dependsOn generateProtocol - source file("build/generated-avro-main-avpr") - include("**/*.avpr") - outputDir = file("build/generated-main-avro-avsc") - } - """ + |task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + | source file("src/main/avro") + | outputDir = file("build/generated-avro-main-avpr") + |} + |task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + | dependsOn generateProtocol + | source file("build/generated-avro-main-avpr") + | include("**/*.avpr") + | outputDir = file("build/generated-main-avro-avsc") + |} + |""".stripMargin() copyResource("interop.avdl", avroDir) @@ -87,7 +86,7 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def result = run("generateSchema") then: - taskInfoAbsent || result.task(":generateSchema").outcome == SUCCESS + result.task(":generateSchema").outcome == SUCCESS projectFile("build/generated-main-avro-avsc/org/apache/avro/Foo.avsc").file projectFile("build/generated-main-avro-avsc/org/apache/avro/Kind.avsc").file projectFile("build/generated-main-avro-avsc/org/apache/avro/MD5.avsc").file @@ -98,20 +97,19 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "example of converting both IDL and json protocol simultaneously"() { given: buildFile << """ - task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { - source file("src/main/avro") - include("**/*.avdl") - outputDir = file("build/generated-avro-main-avpr") - } - - task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { - dependsOn generateProtocol - source file("src/main/avro") - source file("build/generated-avro-main-avpr") - include("**/*.avpr") - outputDir = file("build/generated-main-avro-avsc") - } - """ + |task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + | source file("src/main/avro") + | include("**/*.avdl") + | outputDir = file("build/generated-avro-main-avpr") + |} + |task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + | dependsOn generateProtocol + | source file("src/main/avro") + | source file("build/generated-avro-main-avpr") + | include("**/*.avpr") + | outputDir = file("build/generated-main-avro-avsc") + |} + |""".stripMargin() copyResource("mail.avpr", avroDir) copyResource("interop.avdl", avroDir) @@ -120,7 +118,7 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def result = run("generateSchema") then: - taskInfoAbsent || result.task(":generateSchema").outcome == SUCCESS + result.task(":generateSchema").outcome == SUCCESS projectFile("build/generated-main-avro-avsc/org/apache/avro/test/Message.avsc").file projectFile("build/generated-main-avro-avsc/org/apache/avro/Foo.avsc").file projectFile("build/generated-main-avro-avsc/org/apache/avro/Kind.avsc").file diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index a7c4a1622e6..c3977e52a15 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -21,6 +21,7 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class AvroPluginFunctionalSpec extends FunctionalSpec { def "setup"() { applyAvroPlugin() + addDefaultRepository() addAvroDependency() } @@ -32,8 +33,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/avro/User.class")).file } @@ -46,8 +47,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("org/apache/avro/test/Mail.class")).file projectFile(buildOutputClassPath("org/apache/avro/test/Message.class")).file } @@ -60,9 +61,9 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroProtocol").outcome == SUCCESS - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroProtocol").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("org/apache/avro/Foo.class")).file projectFile(buildOutputClassPath("org/apache/avro/Interop.class")).file projectFile(buildOutputClassPath("org/apache/avro/Kind.class")).file @@ -78,8 +79,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/avro/User.class")).file } @@ -92,8 +93,8 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("org/apache/avro/test/Mail.class")).file projectFile(buildOutputClassPath("org/apache/avro/test/Message.class")).file } @@ -106,9 +107,9 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroProtocol").outcome == SUCCESS - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroProtocol").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("org/apache/avro/Foo.class")).file projectFile(buildOutputClassPath("org/apache/avro/Interop.class")).file projectFile(buildOutputClassPath("org/apache/avro/Kind.class")).file @@ -125,7 +126,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def result = runAndFail() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.task(":generateAvroJava").outcome == FAILED result.output.contains("> Could not compile schema definition files:") result.output.contains("* $errorFilePath: \"enum\" is not a defined name. The type of the \"gender\" " + "field must be a defined name or a {\"type\": ...} expression.") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy index c59339355f0..85301eb60d5 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy @@ -23,6 +23,7 @@ import static org.gradle.testkit.runner.TaskOutcome.FROM_CACHE class BuildCacheSupportFunctionalSpec extends FunctionalSpec { def "setup"() { applyAvroPlugin() + addDefaultRepository() addAvroDependency() } @@ -40,8 +41,8 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { def result = run("build", "--build-cache") then: "the expected outputs were produced from the build cache" - taskInfoAbsent || result.task(":generateAvroJava").outcome == FROM_CACHE - taskInfoAbsent || result.task(":compileJava").outcome == FROM_CACHE + result.task(":generateAvroJava").outcome == FROM_CACHE + result.task(":compileJava").outcome == FROM_CACHE projectFile("build/generated-main-avro-java/example/avro/User.java").file projectFile("build/generated-main-avro-java/org/apache/avro/test/Mail.java").file projectFile(buildOutputClassPath("example/avro/User.class")).file @@ -60,9 +61,9 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { def result = run("build", "--build-cache") then: "the expected outputs were produced from the build cache" - taskInfoAbsent || result.task(":generateAvroProtocol").outcome == FROM_CACHE - taskInfoAbsent || result.task(":generateAvroJava").outcome == FROM_CACHE - taskInfoAbsent || result.task(":compileJava").outcome == FROM_CACHE + result.task(":generateAvroProtocol").outcome == FROM_CACHE + result.task(":generateAvroJava").outcome == FROM_CACHE + result.task(":compileJava").outcome == FROM_CACHE projectFile("build/generated-main-avro-avpr/interop.avpr").file projectFile("build/generated-main-avro-java/org/apache/avro/Interop.java").file projectFile(buildOutputClassPath("org/apache/avro/Interop.class")).file @@ -87,7 +88,7 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { def result = run("generateSchema", "--build-cache") then: "the expected outputs were produced from the build cache" - taskInfoAbsent || result.task(":generateSchema").outcome == FROM_CACHE + result.task(":generateSchema").outcome == FROM_CACHE projectFile("build/generated-main-avro-avsc/org/apache/avro/test/Message.avsc").file } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index e6320623ec2..fcf895e0447 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -18,11 +18,6 @@ package com.commercehub.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class CustomConversionFunctionalSpec extends FunctionalSpec { - def "setup"() { - applyAvroPlugin() - addAvroDependency() - } - private void copyCustomConversion(String destDir) { copyFile("src/test/java", destDir, "com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java") @@ -38,23 +33,33 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { // so our version compatibility tests won't cover the difference given: copyResource("customConversion.avsc", avroDir) + // This functionality doesn't work with the plugins DSL syntax. + // To load files from the buildSrc classpath you need to load the plugin from the buildscript classpath. buildFile << """ - import com.commercehub.gradle.plugin.avro.test.custom.* - avro { - stringType = "String" - logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) - customConversion(TimeZoneConversion) - } - """ + |buildscript { + | dependencies { + | classpath files(${readPluginClasspath()}) + | } + |} + |apply plugin: "com.commercehub.gradle.plugin.avro" + |import com.commercehub.gradle.plugin.avro.test.custom.* + |avro { + | stringType = "String" + | logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) + | customConversion(TimeZoneConversion) + |} + |""".stripMargin() + addDefaultRepository() + addAvroDependency() testProjectDir.newFolder("buildSrc") testProjectDir.newFile("buildSrc/build.gradle") << """ - repositories { - jcenter() - } - dependencies { - compile "org.apache.avro:avro:${avroVersion}" - } - """ + |repositories { + | jcenter() + |} + |dependencies { + | implementation "org.apache.avro:avro:${avroVersion}" + |} + |""".stripMargin() copyCustomConversion("buildSrc/src/main/java") copyCustomConversion("src/main/java") @@ -62,8 +67,8 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("test/Event.class")).file def javaSource = projectFile("build/generated-main-avro-java/test/Event.java").text javaSource.contains("java.time.Instant start;") @@ -75,23 +80,33 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { // See https://issues.apache.org/jira/browse/AVRO-2548 given: copyResource("customConversion.avsc", avroDir) + // This functionality doesn't work with the plugins DSL syntax. + // To load files from the buildSrc classpath you need to load the plugin from the buildscript classpath. buildFile << """ - import com.commercehub.gradle.plugin.avro.test.custom.* - avro { - stringType = "CharSequence" - logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) - customConversion(TimeZoneConversion) - } - """ + |buildscript { + | dependencies { + | classpath files(${readPluginClasspath()}) + | } + |} + |apply plugin: "com.commercehub.gradle.plugin.avro" + |import com.commercehub.gradle.plugin.avro.test.custom.* + |avro { + | stringType = "CharSequence" + | logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) + | customConversion(TimeZoneConversion) + |} + |""".stripMargin() + addDefaultRepository() + addAvroDependency() testProjectDir.newFolder("buildSrc") testProjectDir.newFile("buildSrc/build.gradle") << """ - repositories { - jcenter() - } - dependencies { - compile "org.apache.avro:avro:${avroVersion}" - } - """ + |repositories { + | jcenter() + |} + |dependencies { + | implementation "org.apache.avro:avro:${avroVersion}" + |} + |""".stripMargin() copyCustomConversion("buildSrc/src/main/java") copyCustomConversion("src/main/java") @@ -99,8 +114,8 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("test/Event.class")).file def javaSource = projectFile("build/generated-main-avro-java/test/Event.java").text javaSource.contains("java.time.Instant start;") @@ -112,23 +127,33 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { // See https://issues.apache.org/jira/browse/AVRO-2548 given: copyResource("customConversion.avpr", avroDir) + // This functionality doesn't work with the plugins DSL syntax. + // To load files from the buildSrc classpath you need to load the plugin from the buildscript classpath. buildFile << """ - import com.commercehub.gradle.plugin.avro.test.custom.* - avro { - stringType = "CharSequence" - logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) - customConversion(TimeZoneConversion) - } - """ + |buildscript { + | dependencies { + | classpath files(${readPluginClasspath()}) + | } + |} + |apply plugin: "com.commercehub.gradle.plugin.avro" + |import com.commercehub.gradle.plugin.avro.test.custom.* + |avro { + | stringType = "CharSequence" + | logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) + | customConversion(TimeZoneConversion) + |} + |""".stripMargin() + addDefaultRepository() + addAvroDependency() testProjectDir.newFolder("buildSrc") testProjectDir.newFile("buildSrc/build.gradle") << """ - repositories { - jcenter() - } - dependencies { - compile "org.apache.avro:avro:${avroVersion}" - } - """ + |repositories { + | jcenter() + |} + |dependencies { + | implementation "org.apache.avro:avro:${avroVersion}" + |} + |""".stripMargin() copyCustomConversion("buildSrc/src/main/java") copyCustomConversion("src/main/java") @@ -136,8 +161,8 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("test/Event.class")).file def javaSource = projectFile("build/generated-main-avro-java/test/Event.java").text javaSource.contains("java.time.Instant start;") @@ -147,19 +172,20 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { def "can use a custom logical type while generating a schema from a protocol"() { given: copyResource("customConversion.avpr", avroDir) + applyAvroPlugin() buildFile << """ - task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { - source file("src/main/avro") - include("**/*.avpr") - outputDir = file("build/generated-main-avro-avsc") - } - """ + |task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + | source file("src/main/avro") + | include("**/*.avpr") + | outputDir = file("build/generated-main-avro-avsc") + |} + |""".stripMargin() when: def result = run("generateSchema") then: - taskInfoAbsent || result.task(":generateSchema").outcome == SUCCESS + result.task(":generateSchema").outcome == SUCCESS def schemaFile = projectFile("build/generated-main-avro-avsc/test/Event.avsc").text schemaFile.contains('"logicalType" : "timestamp-millis"') schemaFile.contains('"logicalType" : "timezone"') diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index 1fd9dccdcc4..ac54adffc02 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -27,6 +27,7 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def "setup"() { applyAvroPlugin() + addDefaultRepository() addAvroDependency() } @@ -38,8 +39,8 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/Person.class")).file projectFile(buildOutputClassPath("example/Cat.class")).file projectFile(buildOutputClassPath("example/Gender.class")).file @@ -53,8 +54,8 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/Person.class")).file projectFile(buildOutputClassPath("example/Fish.class")).file projectFile(buildOutputClassPath("example/Gender.class")).file @@ -70,7 +71,7 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def result = runAndFail() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.task(":generateAvroJava").outcome == FAILED result.output.contains("Found conflicting definition of type example.Gender in " + "[$errorFilePath1, $errorFilePath2]") } @@ -84,7 +85,7 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def result = runAndFail() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.task(":generateAvroJava").outcome == FAILED result.output.contains("Found conflicting definition of type example.Person in " + "[$errorFilePath1, $errorFilePath2]") } @@ -98,7 +99,7 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { def result = runAndFail() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.task(":generateAvroJava").outcome == FAILED result.output.contains("Failed to compile schema definition file $errorFilePath; " + "contains duplicate type definition example.avro.date") } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy index 50d33b652ce..967e9a95879 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -31,6 +31,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { def "with convention plugin, default encoding matches default compilation behavior"() { given: applyAvroPlugin() + addDefaultRepository() addAvroDependency() copyResource("idioma.avsc", avroDir) @@ -38,8 +39,8 @@ class EncodingFunctionalSpec extends FunctionalSpec { def result = run() then: "compilation succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS and: "the system default encoding is used" def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(SYSTEM_ENCODING) @@ -50,6 +51,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { def "with convention plugin, configuring Java compilation task with encoding=#encoding will use it for outputCharacterEncoding"() { given: applyAvroPlugin() + addDefaultRepository() addAvroDependency() copyResource("idioma.avsc", avroDir) buildFile << """ @@ -62,8 +64,8 @@ class EncodingFunctionalSpec extends FunctionalSpec { def result = run() then: "compilation succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS and: "the specified encoding is used" def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(encoding) @@ -93,7 +95,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "compilation succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS and: "the specified encoding is used" def content = projectFile("build/generated-main-avro-java/example/avro/Idioma.java").getText(expectedEncoding) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index aa90af21665..f0732cf9918 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -23,6 +23,7 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class EnumHandlingFunctionalSpec extends FunctionalSpec { def "setup"() { applyAvroPlugin() + addDefaultRepository() addAvroDependency() } @@ -34,8 +35,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/avro/MyEnum.class")).file } @@ -47,8 +48,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/avro/Test.class")).file projectFile(buildOutputClassPath("example/avro/Gender.class")).file } @@ -61,8 +62,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/avro/Test.class")).file projectFile(buildOutputClassPath("example/avro/Kind.class")).file } @@ -76,8 +77,8 @@ class EnumHandlingFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/avro/User.class")).file projectFile(buildOutputClassPath("example/avro/MyEnum.class")).file } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy index 4b87b4df482..3172527490b 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy @@ -20,6 +20,7 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class ExamplesFunctionalSpec extends FunctionalSpec { def "setup"() { applyAvroPlugin() + addDefaultRepository() addAvroDependency() } @@ -31,8 +32,8 @@ class ExamplesFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/Cat.class")).file projectFile(buildOutputClassPath("example/Breed.class")).file } @@ -46,8 +47,8 @@ class ExamplesFunctionalSpec extends FunctionalSpec { def result = run() then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS - taskInfoAbsent || result.task(":compileJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS projectFile(buildOutputClassPath("example/Cat.class")).file projectFile(buildOutputClassPath("example/Breed.class")).file } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index aac7aaf7cee..62bc41dbfc2 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -17,7 +17,6 @@ package com.commercehub.gradle.plugin.avro import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner -import org.gradle.testkit.runner.internal.feature.TestKitFeature import org.gradle.util.GradleVersion import org.junit.Rule import org.junit.rules.TemporaryFolder @@ -44,26 +43,16 @@ abstract class FunctionalSpec extends Specification { buildFile = testProjectDir.newFile("build.gradle") avroDir = testProjectDir.newFolder("src", "main", "avro") avroSubDir = testProjectDir.newFolder("src", "main", "avro", "foo") + } + protected String readPluginClasspath() { def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") if (pluginClasspathResource == null) { throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") } - // escape backslashes in Windows paths and assemble - def pluginClasspath = pluginClasspathResource.readLines()*.replace('\\', '\\\\').collect { "'$it'" }.join(", ") - - // Add the logic under test to the test build - buildFile << """ - buildscript { - dependencies { - classpath files($pluginClasspath) - } - } - repositories { - jcenter() - } - """ + // escape backslashes in Windows paths and assemble + return pluginClasspathResource.readLines()*.replace('\\', '\\\\').collect { "\"$it\"" }.join(", ") } protected void applyAvroPlugin() { @@ -75,19 +64,35 @@ abstract class FunctionalSpec extends Specification { } protected void applyPlugin(String pluginId) { - buildFile << "apply plugin: \"${pluginId}\"\n" + buildFile << "plugins { id \"${pluginId}\" }\n" + } + + protected void applyPlugin(String pluginId, String version) { + buildFile << "plugins { id \"${pluginId}\" version \"${version}\" }\n" + } + + protected void addDefaultRepository() { + buildFile << "repositories { jcenter() }\n" + } + + protected void addImplementationDependency(String dependencySpec) { + addDependency("implementation", dependencySpec) + } + + protected void addRuntimeDependency(String dependencySpec) { + addDependency("runtimeOnly", dependencySpec) } - protected void addDependency(String dependencySpec) { - buildFile << "dependencies { compile \"${dependencySpec}\" }\n" + protected void addDependency(String configuration, String dependencySpec) { + buildFile << "dependencies { ${configuration} \"${dependencySpec}\" }\n" } protected void addAvroDependency() { - addDependency("org.apache.avro:avro:${avroVersion}") + addImplementationDependency("org.apache.avro:avro:${avroVersion}") } protected void addAvroIpcDependency() { - addDependency("org.apache.avro:avro-ipc:${avroVersion}") + addImplementationDependency("org.apache.avro:avro-ipc:${avroVersion}") } protected void copyResource(String name, File targetFolder) { @@ -108,7 +113,7 @@ abstract class FunctionalSpec extends Specification { } protected GradleRunner createGradleRunner() { - return GradleRunner.create().withProjectDir(testProjectDir.root).withGradleVersion(gradleVersion.version) + return GradleRunner.create().withProjectDir(testProjectDir.root).withGradleVersion(gradleVersion.version).withPluginClasspath() } protected BuildResult run(String... args = ["build"]) { @@ -119,16 +124,7 @@ abstract class FunctionalSpec extends Specification { return createGradleRunner().withArguments(Arrays.asList(args) + "--stacktrace").buildAndFail() } - protected boolean isTaskInfoAbsent() { - return gradleVersion < TestKitFeature.CAPTURE_BUILD_RESULT_TASKS.since - } - - protected isMultipleClassDirectoriesUsed() { - return gradleVersion >= GradleVersion.version("4.0") - } - - @SuppressWarnings("UnnecessaryGetter") protected String buildOutputClassPath(String suffix) { - return isMultipleClassDirectoriesUsed() ? "build/classes/java/main/${suffix}" : "build/classes/main/${suffix}" + return "build/classes/java/main/${suffix}" } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy index 527a8616485..47560ed40cd 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy @@ -24,21 +24,21 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { def "With base plugin, declares input on classpath"() { given: "a build that declares another task's output in the classpath" applyAvroBasePlugin() + applyPlugin("java") // Jar task appears to only work with the java plugin applied buildFile << """ - apply plugin: "java" // Jar task appears to only work with the java plugin applied - configurations.create("shared") - task sharedIdlJar(type: Jar) { - from "src/shared" - } - dependencies { - shared sharedIdlJar.outputs.files - } - task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { - classpath = configurations.shared - source file("src/dependent") - outputDir = file("build/protocol") - } - """ + |configurations.create("shared") + |task sharedIdlJar(type: Jar) { + | from "src/shared" + |} + |dependencies { + | shared sharedIdlJar.outputs.files + |} + |task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + | classpath = configurations.shared + | source file("src/dependent") + | outputDir = file("build/protocol") + |} + |""".stripMargin() copyResource("shared.avdl", testProjectDir.newFolder("src", "shared")) copyResource("dependent.avdl", testProjectDir.newFolder("src", "dependent")) @@ -48,7 +48,7 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { then: "running the generate protocol task occurs after running the producing task" result.tasks*.path == [":sharedIdlJar", ":generateProtocol"] - taskInfoAbsent || result.task(":generateProtocol").outcome == SUCCESS + result.task(":generateProtocol").outcome == SUCCESS projectFile("build/protocol/dependent.avpr").file } @@ -56,13 +56,13 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { given: "a build that declares another task's output in the classpath" applyAvroPlugin() buildFile << """ - task sharedIdlJar(type: Jar) { - from "src/shared" - } - dependencies { - runtime sharedIdlJar.outputs.files - } - """ + |task sharedIdlJar(type: Jar) { + | from "src/shared" + |} + |dependencies { + | runtimeOnly sharedIdlJar.outputs.files + |} + |""".stripMargin() copyResource("shared.avdl", testProjectDir.newFolder("src", "shared")) copyResource("dependent.avdl", avroDir) @@ -72,7 +72,7 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { then: "running the generate protocol task occurs after running the producing task" result.tasks*.path == [":sharedIdlJar", ":generateAvroProtocol"] - taskInfoAbsent || result.task(":generateAvroProtocol").outcome == SUCCESS + result.task(":generateAvroProtocol").outcome == SUCCESS projectFile("build/generated-main-avro-avpr/dependent.avpr").file } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy index 70dab02e77a..ba2b459cd91 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy @@ -51,7 +51,7 @@ class IntellijFunctionalSpec extends FunctionalSpec { def result = run("idea") then: - taskInfoAbsent || result.task(":idea").outcome == SUCCESS + result.task(":idea").outcome == SUCCESS projectFile("build/generated-main-avro-java").directory projectFile("build/generated-test-avro-java").directory } @@ -59,19 +59,19 @@ class IntellijFunctionalSpec extends FunctionalSpec { def "overriding task's outputDir doesn't result in default directory still being created"() { given: buildFile << """ - generateAvroJava { - outputDir = file("build/generatedMainAvro") - } - generateTestAvroJava { - outputDir = file("build/generatedTestAvro") - } - """ + |generateAvroJava { + | outputDir = file("build/generatedMainAvro") + |} + |generateTestAvroJava { + | outputDir = file("build/generatedTestAvro") + |} + |""".stripMargin() when: def result = run("idea") then: - taskInfoAbsent || result.task(":idea").outcome == SUCCESS + result.task(":idea").outcome == SUCCESS !projectFile("build/generated-main-avro-java").directory !projectFile("build/generated-test-avro-java").directory projectFile("build/generatedMainAvro").directory diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy index 843b0f66964..e1ff6672622 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy @@ -22,33 +22,19 @@ class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { def "setup"() { println "Testing using Kotlin version ${kotlinVersion}." - applyAvroPlugin() - addAvroDependency() } def "works with kotlin-gradle-plugin"() { given: File kotlinDir = testProjectDir.newFolder("src", "main", "kotlin") - buildFile << """ - buildscript { - repositories { - jcenter() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" - } - } - apply plugin: "kotlin" - apply plugin: "application" - repositories { - jcenter() - } - dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib" - runtime "joda-time:joda-time:2.9.9" - } - mainClassName = "demo.HelloWorldKt" - """ + applyAvroPlugin() + applyPlugin("org.jetbrains.kotlin.jvm", kotlinVersion) + applyPlugin("application") + addDefaultRepository() + addAvroDependency() + addImplementationDependency("org.jetbrains.kotlin:kotlin-stdlib") + addRuntimeDependency("joda-time:joda-time:2.9.9") + buildFile << 'mainClassName = "demo.HelloWorldKt"' copyResource("user.avsc", avroDir) copyResource("helloWorld.kt", kotlinDir) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 3e860a94ec5..632db7bc2dd 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -31,19 +31,16 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class OptionsFunctionalSpec extends FunctionalSpec { static actualDateTimeImplementationDefault = DEFAULT == JSR310 ? "java.time.LocalDate" : "org.joda.time.LocalDate" - def "setup"() { - applyAvroPlugin() - } - def "works with default options"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() when: def result = run("generateAvroJava") then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the stringType is string" @@ -75,6 +72,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "supports configuring stringType to #stringType"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | stringType = ${stringType} @@ -85,7 +83,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified stringType is used" @@ -105,6 +103,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "supports configuring fieldVisibility to #fieldVisibility"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | fieldVisibility = "${fieldVisibility}" @@ -115,7 +114,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified fieldVisibility is used" @@ -133,6 +132,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "supports configuring createSetters to #createSetters"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | createSetters = ${createSetters} @@ -143,7 +143,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified createSetters is used" @@ -163,6 +163,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "supports configuring createOptionalGetters to #createOptionalGetters"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | createOptionalGetters = ${createOptionalGetters} @@ -173,7 +174,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified createOptionalGetters is used" @@ -193,6 +194,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "supports configuring gettersReturnOptional to #gettersReturnOptional"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | gettersReturnOptional = ${gettersReturnOptional} @@ -203,7 +205,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified createOptionalGetters is used" @@ -224,12 +226,16 @@ class OptionsFunctionalSpec extends FunctionalSpec { def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") copyResource("user.avsc", avroDir) copyResource("record.vm", templatesDir) + // This functionality doesn't work with the plugins DSL syntax. + // To load files from the buildscript classpath you need to load the plugin from it as well. buildFile << """ |buildscript { | dependencies { + | classpath files(${readPluginClasspath()}) | classpath files(["${templatesDir.parentFile.toURI()}"]) | } |} + |apply plugin: "com.commercehub.gradle.plugin.avro" |avro { | templateDirectory = "/alternateTemplates/" |} @@ -239,7 +245,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified templates are used" @@ -249,6 +255,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "rejects unsupported stringType values"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | stringType = "badValue" @@ -259,13 +266,14 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = runAndFail("generateAvroJava") then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.task(":generateAvroJava").outcome == FAILED result.output.contains("Invalid stringType 'badValue'. Value values are: [CharSequence, String, Utf8]") } def "rejects unsupported fieldVisibility values"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | fieldVisibility = "badValue" @@ -276,7 +284,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = runAndFail("generateAvroJava") then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.task(":generateAvroJava").outcome == FAILED result.output.contains("Invalid fieldVisibility 'badValue'. Value values are: [PUBLIC, PUBLIC_DEPRECATED, PRIVATE]") } @@ -284,6 +292,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "supports configuring enableDecimalLogicalType to #enableDecimalLogicalType"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | enableDecimalLogicalType = $enableDecimalLogicalType @@ -294,7 +303,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified enableDecimalLogicalType is used" @@ -314,6 +323,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "supports configuration of dateTimeLogicalType to #dateTimeLogicalType"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | dateTimeLogicalType = "${dateTimeLogicalType}" @@ -324,7 +334,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = run("generateAvroJava") then: "the task succeeds" - taskInfoAbsent || result.task(":generateAvroJava").outcome == SUCCESS + result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified dateTimeLogicalType is used" @@ -340,6 +350,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "rejects unsupported dateTimeLogicalType values"() { given: copyResource("user.avsc", avroDir) + applyAvroPlugin() buildFile << """ |avro { | dateTimeLogicalType = "badValue" @@ -350,7 +361,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def result = runAndFail("generateAvroJava") then: - taskInfoAbsent || result.task(":generateAvroJava").outcome == FAILED + result.task(":generateAvroJava").outcome == FAILED result.output.contains("Invalid dateTimeLogicalType 'badValue'. Value values are: [JODA, JSR310]") } } From 271fef01ea1779cde30000eb2c9d08d0673e2dda Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 3 Mar 2020 17:00:33 -0500 Subject: [PATCH 296/479] Add tests for Kotlin DSL usage (#61) --- CHANGES.md | 1 + README.md | 23 +++++-- ...otlinDSLCompatibilityFunctionalSpec.groovy | 63 +++++++++++++++++++ 3 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy diff --git a/CHANGES.md b/CHANGES.md index 34251d010ac..a8cef454881 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ * Add support for Java 13 * Add support for testing multiple Kotlin versions * Update plugin's own build to address some deprecation warnings of APIs being removed in Gradle 7 +* Add tests for Kotlin DSL usage (#61) ## 0.18.0 * Use reproducible file order for plugin archives diff --git a/README.md b/README.md index dd9c70d4949..c6ccffe8810 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Kotlin plugin versions 1.3.20-1.3.61 using the latest supported version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 * Version of the Kotlin plugin prior to 1.2.20 are unlikely to work -* Incubating: support for Gradle Kotlin DSL - * No test coverage yet; will attempt to address incompatibilities as they are discovered +* Support for Gradle Kotlin DSL # Usage @@ -334,7 +333,7 @@ This support does *not* support producing the Avro generated classes as Kotlin c Special notes relevant to using this plugin via the Gradle Kotlin DSL: * Apply the plugin declaratively using the `plugins {}` block. Otherwise, various features may not work as intended. See [Configuring Plugins in the Gradle Kotlin DSL](https://github.com/gradle/kotlin-dsl/blob/master/doc/getting-started/Configuring-Plugins.md) for more details. -* Most configuration in the `avro {}` block can be used identically to the Groovy DSL. Boolean settings are an exception, as they require an "is" prefix. For example, instead of `createSetters = false`, one would use `isCreateSetters = false`. See [Getters and Setters](https://kotlinlang.org/docs/reference/java-interop.html#getters-and-setters) for more details. +* Configuration in the `avro {}` block must be applied differently than in the Groovy DSL. See the example below for details. ### Example Kotlin DSL Setup: @@ -343,7 +342,7 @@ In `gradle.build.kts` add: ```kotlin plugins { // Find latest release here: https://github.com/davidmc24/gradle-avro-plugin/releases - id("com.commercehub.gradle.plugin.avro") version "0.17.0" + id("com.commercehub.gradle.plugin.avro") version "VERSION" } ``` @@ -359,6 +358,22 @@ pluginManagement { } ``` +The syntax for configuring the extension looks like this: + +```kotlin +avro { + isCreateSetters.set(true) + isCreateOptionalGetters.set(false) + isGettersReturnOptional.set(false) + fieldVisibility.set("PUBLIC_DEPRECATED") + outputCharacterEncoding.set("UTF-8") + stringType.set("String") + templateDirectory.set(null as String?) + isEnableDecimalLogicalType.set(true) + dateTimeLogicalType.set("JSR310") +} +``` + # Generating schema files If desired, you can generate JSON schema files. diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy new file mode 100644 index 00000000000..7de7e2a9dbc --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy @@ -0,0 +1,63 @@ +package com.commercehub.gradle.plugin.avro + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class KotlinDSLCompatibilityFunctionalSpec extends FunctionalSpec { + File kotlinBuildFile + + def "setup"() { + buildFile.delete() // Don't use the Groovy build file created by the superclass + kotlinBuildFile = testProjectDir.newFile("build.gradle.kts") + kotlinBuildFile << """ + |plugins { + | java + | id("com.commercehub.gradle.plugin.avro") + |} + |repositories { + | jcenter() + |} + |dependencies { + | implementation("org.apache.avro:avro:${avroVersion}") + |} + |""".stripMargin() + } + + def "works with kotlin DSL"() { + given: + copyResource("user.avsc", avroDir) + + when: + def result = run() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + projectFile(buildOutputClassPath("example/avro/User.class")).file + } + + def "extension supports configuring all supported properties"() { + given: + copyResource("user.avsc", avroDir) + kotlinBuildFile << """ + |avro { + | isCreateSetters.set(true) + | isCreateOptionalGetters.set(false) + | isGettersReturnOptional.set(false) + | fieldVisibility.set("PUBLIC_DEPRECATED") + | outputCharacterEncoding.set("UTF-8") + | stringType.set("String") + | templateDirectory.set(null as String?) + | isEnableDecimalLogicalType.set(true) + | dateTimeLogicalType.set("JSR310") + |} + |""".stripMargin() + + when: + def result = run() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + projectFile(buildOutputClassPath("example/avro/User.class")).file + } +} From c7b01729a01034ca7097e6f1ac3b3e97f457bb3f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 4 Mar 2020 10:01:17 -0500 Subject: [PATCH 297/479] Handle a test that appears to fail on Windows due to weird file locking behaviors --- .../plugin/avro/BuildCacheSupportFunctionalSpec.groovy | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy index 85301eb60d5..ead6ef88e6a 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy @@ -15,6 +15,9 @@ */ package com.commercehub.gradle.plugin.avro +import spock.lang.IgnoreIf +import spock.util.environment.OperatingSystem + import static org.gradle.testkit.runner.TaskOutcome.FROM_CACHE /** @@ -49,6 +52,10 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { projectFile(buildOutputClassPath("org/apache/avro/test/Mail.class")).file } + /** + * This test appears to fail on Windows due to clean being unable to delete interop.avpr. + */ + @IgnoreIf({ OperatingSystem.current.windows }) def "supports build cache for IDL to protocol conversion"() { given: "a project is built once with build cache enabled" copyResource("interop.avdl", avroDir) From 4debab9b173102296f1254a8fcda996869eb96b6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 4 Mar 2020 12:44:45 -0500 Subject: [PATCH 298/479] Update to note a Kotlin-Java version incompatibility --- README.md | 1 + build.gradle | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c6ccffe8810..78b9b896032 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Support for Kotlin * Currently tested against Kotlin plugin versions 1.3.20-1.3.61 using the latest supported version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 + * Kotlin plugin versions prior to 1.2.30 do not support Java 10+ * Version of the Kotlin plugin prior to 1.2.20 are unlikely to work * Support for Gradle Kotlin DSL diff --git a/build.gradle b/build.gradle index bc60d7d1582..65ac8ddc9c0 100644 --- a/build.gradle +++ b/build.gradle @@ -192,18 +192,32 @@ sourceCompatibility = 8 def avroVersions = ["1.9.0", "1.9.1", "1.9.2"] def keyAvroVersions = avroVersions.last() -def gradle5KotlinVersions = [ - "1.2.20", "1.2.21", "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", +def gradle5KotlinVersions =[] +if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_10)) { + // Java 10 support was added in Kotlin 1.2.30 + gradle5KotlinVersions.addAll([ + "1.2.20", "1.2.21", + ]) +} +gradle5KotlinVersions.addAll([ + "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", "1.3.0", "1.3.10", "1.3.11", -] +]) def latestGradleKotlinVersions = [ "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", ] def kotlinVersions = gradle5KotlinVersions + latestGradleKotlinVersions -def keyKotlinVersions = [ // First and last version for each supported line - "1.2.20", "1.2.71", +def keyKotlinVersions = [] // First and last version for each supported line +if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_10)) { + // Java 10 support was added in Kotlin 1.2.30 + keyKotlinVersions.add("1.2.20") +} else { + keyKotlinVersions.add("1.2.30") +} +keyKotlinVersions.addAll([ + "1.2.71", "1.3.0", "1.3.61", -] +]) def keyGradleVersions = [] // First and last version for each supported line def firstSupportedGradleVersion = null def gradleVersions = [] From 28f166c33fdd46e6a38de83f6b1a6b43b067a5c7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 4 Mar 2020 15:14:37 -0500 Subject: [PATCH 299/479] Update to gradle 6.2.2 --- CHANGES.md | 2 +- README.md | 4 ++-- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a8cef454881..523c9e8488b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,7 @@ # Change Log ## Unreleased -* Add support for Gradle 6.0-6.2 (#101) +* Add support for Gradle 6.0-6.2.2 (#101) * Drop support for Gradle versions prior to 5.1 * Update version of kotlin plugin in tests/example * Built using Avro 1.9.2 (#104) diff --git a/README.md b/README.md index 78b9b896032..653a22bbe75 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 11 support requires Gradle 4.8 or higher * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Gradle 6.2 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.2 +* Currently built against Gradle 6.2.2 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.2.2 * If you need support for Gradle 4.4-5.0, version 0.18.0 was the last version tested for compatibility * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) diff --git a/build.gradle b/build.gradle index 65ac8ddc9c0..08130ba5415 100644 --- a/build.gradle +++ b/build.gradle @@ -227,8 +227,8 @@ if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { keyGradleVersions.addAll("5.1", "5.6.4") // First and last for the 5.x line firstSupportedGradleVersion = gradleVersions.first() } -gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2") -keyGradleVersions.addAll("6.0", "6.2") // First and last for the 6.x line +gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2") +keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line def latestAvroVersion = avroVersions.last() def latestGradleVersion = gradleVersions.last() diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b7c8c5dbf58..a2bf1313b8a 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-6.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 2bfbcb3c48afbf2c6a2206daa6367cef702f880a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 4 Mar 2020 15:15:10 -0500 Subject: [PATCH 300/479] Official Gradle Wrapper Validation Action See: https://github.com/gradle/wrapper-validation-action Added as a dedicated Workflow --- .github/workflows/gradle-wrapper-validation.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/gradle-wrapper-validation.yml diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml new file mode 100644 index 00000000000..09d2a7fd1e6 --- /dev/null +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -0,0 +1,11 @@ +# See https://github.com/marketplace/actions/gradle-wrapper-validation +name: "Validate Gradle Wrapper" +on: [push, pull_request] + +jobs: + validation: + name: "Validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: gradle/wrapper-validation-action@v1 From 33b182ceb7de4353525ab14b49efd4f47ac44a2a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 5 Mar 2020 12:26:49 -0500 Subject: [PATCH 301/479] Support Task Configuration Avoidance (#97) https://docs.gradle.org/current/userguide/task_configuration_avoidance.html Thanks to [dcabasson](https://github.com/dcabasson) for the collaboration --- CHANGES.md | 1 + README.md | 14 ++- .../gradle/plugin/avro/AvroBasePlugin.java | 2 +- .../gradle/plugin/avro/AvroPlugin.java | 109 +++++++++--------- .../avro/AvroBasePluginFunctionalSpec.groovy | 12 +- .../avro/AvroPluginFunctionalSpec.groovy | 22 ++++ .../BuildCacheSupportFunctionalSpec.groovy | 12 +- .../CustomConversionFunctionalSpec.groovy | 2 +- .../plugin/avro/EncodingFunctionalSpec.groovy | 4 +- ...erateAvroProtocolTaskFunctionalSpec.groovy | 6 +- .../plugin/avro/IntellijFunctionalSpec.groovy | 4 +- 11 files changed, 105 insertions(+), 83 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 523c9e8488b..475789f1b03 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ * Add support for testing multiple Kotlin versions * Update plugin's own build to address some deprecation warnings of APIs being removed in Gradle 7 * Add tests for Kotlin DSL usage (#61) +* Support [Task Configuration Avoidance](https://docs.gradle.org/current/userguide/task_configuration_avoidance.html) (#97); thanks to [dcabasson](https://github.com/dcabasson) for the collaboration ## 0.18.0 * Use reproducible file order for plugin archives diff --git a/README.md b/README.md index 653a22bbe75..1e608ae73e6 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ Examples: ```groovy // Option 1: configure compilation task (avro plugin will automatically match) -tasks.withType(JavaCompile) { +tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' } // Option 2: just configure avro plugin @@ -255,15 +255,17 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - compile "org.apache.avro:avro:1.9.2" + implementation "org.apache.avro:avro:1.9.2" } -task generateAvro(type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { +def generateAvro = tasks.register("generateAvro", com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { source("src/avro") outputDir = file("dest/avro") } -compileJava.source(generateAvro.outputs) +tasks.named("compileJava").configure { + source(generateAvro) +} ``` # File Processing @@ -387,13 +389,13 @@ Example using base plugin with support for both IDL and JSON protocol files in ` ```groovy apply plugin: "com.commercehub.gradle.plugin.avro-base" -task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { +def generateProtocol = tasks.register("generateProtocol", com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { source file("src/main/avro") include("**/*.avdl") outputDir = file("build/generated-avro-main-avpr") } -task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { +tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { dependsOn generateProtocol source file("src/main/avro") source file("build/generated-avro-main-avpr") diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index 01b482882b1..e50c4264f8c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -29,7 +29,7 @@ public void apply(final Project project) { private static void configureExtension(final Project project) { final AvroExtension avroExtension = createExtensionWithObjectFactory(project, AVRO_EXTENSION_NAME, DefaultAvroExtension.class); - project.getTasks().withType(GenerateAvroJavaTask.class).all(task -> { + project.getTasks().withType(GenerateAvroJavaTask.class).configureEach(task -> { task.getOutputCharacterEncoding().convention(avroExtension.getOutputCharacterEncoding()); task.getStringType().convention(avroExtension.getStringType()); task.getFieldVisibility().convention(avroExtension.getFieldVisibility()); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 62bdf5a2c53..7056fb67bcd 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -28,6 +28,7 @@ import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.SourceTask; +import org.gradle.api.tasks.TaskProvider; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.plugins.ide.idea.GenerateIdeaModule; import org.gradle.plugins.ide.idea.IdeaPlugin; @@ -50,28 +51,27 @@ public void apply(final Project project) { } private static void configureTasks(final Project project) { - getSourceSets(project).all(sourceSet -> { - GenerateAvroProtocolTask protoTask = configureProtocolGenerationTask(project, sourceSet); - GenerateAvroJavaTask javaTask = configureJavaGenerationTask(project, sourceSet, protoTask); - configureTaskDependencies(project, sourceSet, javaTask); + getSourceSets(project).configureEach(sourceSet -> { + TaskProvider protoTaskProvider = configureProtocolGenerationTask(project, sourceSet); + TaskProvider javaTaskProvider = configureJavaGenerationTask(project, sourceSet, protoTaskProvider); + configureTaskDependencies(project, sourceSet, javaTaskProvider); }); } private static void configureIntelliJ(final Project project) { - project.getPlugins().withType(IdeaPlugin.class).all(ideaPlugin -> { + project.getPlugins().withType(IdeaPlugin.class).configureEach(ideaPlugin -> { SourceSet mainSourceSet = getMainSourceSet(project); SourceSet testSourceSet = getTestSourceSet(project); - project.getTasks().withType(GenerateIdeaModule.class).all(generateIdeaModule -> - project.getTasks().withType(GenerateAvroJavaTask.class).all(generateAvroJavaTask -> - generateIdeaModule.doFirst(task -> project.mkdir(generateAvroJavaTask.getOutputDir())))); IdeaModule module = ideaPlugin.getModel().getModule(); module.setSourceDirs(new SetBuilder() .addAll(module.getSourceDirs()) .add(getAvroSourceDir(project, mainSourceSet)) + .add(getGeneratedOutputDir(project, mainSourceSet, JAVA_EXTENSION).map(Directory::getAsFile).get()) .build()); module.setTestSourceDirs(new SetBuilder() .addAll(module.getTestSourceDirs()) .add(getAvroSourceDir(project, testSourceSet)) + .add(getGeneratedOutputDir(project, testSourceSet, JAVA_EXTENSION).map(Directory::getAsFile).get()) .build()); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. @@ -83,59 +83,60 @@ private static void configureIntelliJ(final Project project) { } module.setExcludeDirs(excludeDirs.build()); }); + project.getTasks().withType(GenerateIdeaModule.class).configureEach(generateIdeaModule -> + generateIdeaModule.doFirst(task -> + project.getTasks().withType(GenerateAvroJavaTask.class, generateAvroJavaTask -> + project.mkdir(generateAvroJavaTask.getOutputDir().get())))); } - private static GenerateAvroProtocolTask configureProtocolGenerationTask(final Project project, final SourceSet sourceSet) { + private static TaskProvider configureProtocolGenerationTask(final Project project, + final SourceSet sourceSet) { String taskName = sourceSet.getTaskName("generate", "avroProtocol"); - GenerateAvroProtocolTask task = project.getTasks().create(taskName, GenerateAvroProtocolTask.class); - task.setDescription( - String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); - task.setGroup(GROUP_SOURCE_GENERATION); - task.source(getAvroSourceDir(project, sourceSet)); - task.include("**/*." + IDL_EXTENSION); - task.setClasspath(project.getConfigurations().getByName(RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION)); - return task; + return project.getTasks().register(taskName, GenerateAvroProtocolTask.class, task -> { + task.setDescription( + String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); + task.setGroup(GROUP_SOURCE_GENERATION); + task.source(getAvroSourceDir(project, sourceSet)); + task.include("**/*." + IDL_EXTENSION); + task.setClasspath(project.getConfigurations().getByName(RUNTIME_CLASSPATH_CONFIGURATION_NAME)); + task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION)); + }); } - private static GenerateAvroJavaTask configureJavaGenerationTask(final Project project, final SourceSet sourceSet, - GenerateAvroProtocolTask protoTask) { + private static TaskProvider configureJavaGenerationTask(final Project project, final SourceSet sourceSet, + TaskProvider protoTaskProvider) { String taskName = sourceSet.getTaskName("generate", "avroJava"); - GenerateAvroJavaTask task = project.getTasks().create(taskName, GenerateAvroJavaTask.class); - task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.", - sourceSet.getName())); - task.setGroup(GROUP_SOURCE_GENERATION); - task.source(getAvroSourceDir(project, sourceSet)); - task.source(protoTask.getOutputDir()); - task.source(protoTask.getOutputs()); - task.include("**/*." + SCHEMA_EXTENSION, "**/*." + PROTOCOL_EXTENSION); - task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION)); - - sourceSet.getJava().srcDir(task.getOutputDir()); - - final JavaCompile compileJavaTask = getCompileJavaTask(project, sourceSet); - compileJavaTask.source(task.getOutputDir()); - compileJavaTask.source(task.getOutputs()); - - task.getOutputCharacterEncoding().convention(project.provider(() -> - Optional.ofNullable(compileJavaTask.getOptions().getEncoding()).orElse(Charset.defaultCharset().name()))); - - return task; + TaskProvider javaTaskProvider = project.getTasks().register(taskName, GenerateAvroJavaTask.class, task -> { + task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.", + sourceSet.getName())); + task.setGroup(GROUP_SOURCE_GENERATION); + task.source(getAvroSourceDir(project, sourceSet)); + task.source(protoTaskProvider); + task.include("**/*." + SCHEMA_EXTENSION, "**/*." + PROTOCOL_EXTENSION); + task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION)); + + sourceSet.getJava().srcDir(task.getOutputDir()); + + JavaCompile compileJavaTask = project.getTasks().named(sourceSet.getCompileJavaTaskName(), JavaCompile.class).get(); + task.getOutputCharacterEncoding().convention(project.provider(() -> + Optional.ofNullable(compileJavaTask.getOptions().getEncoding()).orElse(Charset.defaultCharset().name()))); + }); + project.getTasks().named(sourceSet.getCompileJavaTaskName(), JavaCompile.class, compileJavaTask -> { + compileJavaTask.source(javaTaskProvider); + }); + return javaTaskProvider; } - private static void configureTaskDependencies(final Project project, final SourceSet sourceSet, final GenerateAvroJavaTask javaTask) { + private static void configureTaskDependencies(final Project project, final SourceSet sourceSet, + final TaskProvider javaTaskProvider) { project.getPluginManager().withPlugin("org.jetbrains.kotlin.jvm", appliedPlugin -> - project.getTasks().matching(task -> { - String compilationTaskName = sourceSet.getCompileTaskName("kotlin"); - return compilationTaskName.equals(task.getName()); - }) - .all(task -> { - if (task instanceof SourceTask) { - ((SourceTask) task).source(javaTask.getOutputs()); - } else { - task.dependsOn(javaTask); - } - })); + project.getTasks() + .matching(task -> sourceSet.getCompileTaskName("kotlin").equals(task.getName())) + .withType(SourceTask.class) + .configureEach(task -> + task.source(javaTaskProvider.get().getOutputs()) + ) + ); } private static File getAvroSourceDir(Project project, SourceSet sourceSet) { @@ -147,10 +148,6 @@ private static Provider getGeneratedOutputDir(Project project, Source return project.getLayout().getBuildDirectory().dir(generatedOutputDirName); } - private static JavaCompile getCompileJavaTask(Project project, SourceSet sourceSet) { - return (JavaCompile) project.getTasks().getByName(sourceSet.getCompileJavaTaskName()); - } - private static SourceSetContainer getSourceSets(Project project) { return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets(); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy index 04edde1f976..882177801ef 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy @@ -25,7 +25,7 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "can generate java files from json schema"() { given: buildFile << """ - |task("generateAvroJava", type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { + |tasks.register("generateAvroJava", com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { | source file("src/main/avro") | include("**/*.avsc") | outputDir = file("build/generated-main-avro-java") @@ -45,7 +45,7 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "can generate json schema files from json protocol"() { given: buildFile << """ - |task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { | source file("src/main/avro") | include("**/*.avpr") | outputDir = file("build/generated-main-avro-avsc") @@ -68,11 +68,11 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "can generate json schema files from IDL"() { given: buildFile << """ - |task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + |tasks.register("generateProtocol", com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { | source file("src/main/avro") | outputDir = file("build/generated-avro-main-avpr") |} - |task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { | dependsOn generateProtocol | source file("build/generated-avro-main-avpr") | include("**/*.avpr") @@ -97,12 +97,12 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "example of converting both IDL and json protocol simultaneously"() { given: buildFile << """ - |task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + |tasks.register("generateProtocol", com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { | source file("src/main/avro") | include("**/*.avdl") | outputDir = file("build/generated-avro-main-avpr") |} - |task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { | dependsOn generateProtocol | source file("src/main/avro") | source file("build/generated-avro-main-avpr") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index c3977e52a15..c8211630b25 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -131,4 +131,26 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { result.output.contains("* $errorFilePath: \"enum\" is not a defined name. The type of the \"gender\" " + "field must be a defined name or a {\"type\": ...} expression.") } + + @SuppressWarnings(["GStringExpressionWithinString"]) + def "avro plugin correctly uses task configuration avoidance"() { + given: + buildFile << """ + |def configuredTasks = [] + |tasks.configureEach { + | configuredTasks << it + |} + |gradle.buildFinished { + | println "Configured tasks: \${configuredTasks*.path}" + |} + |""".stripMargin() + when: + def result = run("help") + + then: + def taskMatcher = result.output =~ /(?m)^Configured tasks: (.*)$/ + taskMatcher.find() + def configuredTasks = taskMatcher.group(1) + configuredTasks == "[:help]" + } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy index ead6ef88e6a..c97a3e4eb48 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy @@ -80,12 +80,12 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { given: "a project is built once with build cache enabled" copyResource("mail.avpr", avroDir) buildFile << """ - task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { - source file("src/main/avro") - include("**/*.avpr") - outputDir = file("build/generated-main-avro-avsc") - } - """ + |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + | source file("src/main/avro") + | include("**/*.avpr") + | outputDir = file("build/generated-main-avro-avsc") + |} + |""".stripMargin() run("generateSchema", "--build-cache") and: "the project is cleaned" diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index fcf895e0447..f5cd3f962fd 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -174,7 +174,7 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { copyResource("customConversion.avpr", avroDir) applyAvroPlugin() buildFile << """ - |task("generateSchema", type: com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { | source file("src/main/avro") | include("**/*.avpr") | outputDir = file("build/generated-main-avro-avsc") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy index 967e9a95879..14a10ff0256 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -55,7 +55,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { addAvroDependency() copyResource("idioma.avsc", avroDir) buildFile << """ - |compileJava { + |tasks.named("compileJava").configure { | options.encoding = '${encoding}' |} |""".stripMargin() @@ -84,7 +84,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { |avro { | outputCharacterEncoding = ${outputCharacterEncoding} |} - |task("generateAvroJava", type: com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { + |tasks.register("generateAvroJava", com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { | source file("src/main/avro") | include("**/*.avsc") | outputDir = file("build/generated-main-avro-java") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy index 47560ed40cd..81c4b0781fe 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy @@ -27,13 +27,13 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { applyPlugin("java") // Jar task appears to only work with the java plugin applied buildFile << """ |configurations.create("shared") - |task sharedIdlJar(type: Jar) { + |tasks.register("sharedIdlJar", Jar) { | from "src/shared" |} |dependencies { | shared sharedIdlJar.outputs.files |} - |task("generateProtocol", type: com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + |tasks.register("generateProtocol", com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { | classpath = configurations.shared | source file("src/dependent") | outputDir = file("build/protocol") @@ -56,7 +56,7 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { given: "a build that declares another task's output in the classpath" applyAvroPlugin() buildFile << """ - |task sharedIdlJar(type: Jar) { + |tasks.register("sharedIdlJar", Jar) { | from "src/shared" |} |dependencies { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy index ba2b459cd91..9082c765e37 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy @@ -59,10 +59,10 @@ class IntellijFunctionalSpec extends FunctionalSpec { def "overriding task's outputDir doesn't result in default directory still being created"() { given: buildFile << """ - |generateAvroJava { + |tasks.named("generateAvroJava").configure { | outputDir = file("build/generatedMainAvro") |} - |generateTestAvroJava { + |tasks.named("generateTestAvroJava").configure { | outputDir = file("build/generatedTestAvro") |} |""".stripMargin() From a89f26f4461733918e8f3a0ca10f2207c7eec0ee Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 5 Mar 2020 13:48:17 -0500 Subject: [PATCH 302/479] Update test result directory names --- build.gradle | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 08130ba5415..d58ac8aba7f 100644 --- a/build.gradle +++ b/build.gradle @@ -253,8 +253,8 @@ avroVersions.each { def avroVersion -> kotlinVersion: kotlinVersion, ] reports { - html.destination = file("$buildDir/reports/tests-${avroVersion}-${gradleVersion}") - junitXml.destination = file("$buildDir/reports/tests-${avroVersion}-${gradleVersion}") + html.destination = file("$buildDir/reports/tests-avro${avroVersion}-gradle${gradleVersion}") + junitXml.destination = file("$buildDir/reports/tests-avro${avroVersion}-gradle${gradleVersion}") } } testVersionCompatibility.dependsOn newTask @@ -283,8 +283,8 @@ gradle5KotlinVersions.each { def kotlinVersion -> ] include("**/KotlinCompatibilityFunctionalSpec.class") reports { - html.destination = file("$buildDir/reports/tests-${kotlinVersion}") - junitXml.destination = file("$buildDir/reports/tests-${kotlinVersion}") + html.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") + junitXml.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") } } testVersionCompatibility.dependsOn newTask @@ -307,8 +307,8 @@ latestGradleKotlinVersions.each { def kotlinVersion -> ] include("**/KotlinCompatibilityFunctionalSpec.class") reports { - html.destination = file("$buildDir/reports/tests-${kotlinVersion}") - junitXml.destination = file("$buildDir/reports/tests-${kotlinVersion}") + html.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") + junitXml.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") } } testVersionCompatibility.dependsOn newTask From 8c51d8ea1ef61357b6a8eada8ee5459201fc6ea1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 5 Mar 2020 13:49:48 -0500 Subject: [PATCH 303/479] Work around a bug showing in Gradle 5.1 It appears that in Gradle 5.1, TaskContainer's `withType` overwrites the results of `matching`, causing java compilation tasks to be returned. This results in a circular task dependency. Changing the order to filter by type first fixes it. --- .../java/com/commercehub/gradle/plugin/avro/AvroPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java index 7056fb67bcd..45a2e4058b7 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java @@ -131,8 +131,8 @@ private static void configureTaskDependencies(final Project project, final Sourc final TaskProvider javaTaskProvider) { project.getPluginManager().withPlugin("org.jetbrains.kotlin.jvm", appliedPlugin -> project.getTasks() - .matching(task -> sourceSet.getCompileTaskName("kotlin").equals(task.getName())) .withType(SourceTask.class) + .matching(task -> sourceSet.getCompileTaskName("kotlin").equals(task.getName())) .configureEach(task -> task.source(javaTaskProvider.get().getOutputs()) ) From a365cda295db45c98c0a3b8005659b546e34b9ea Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 9 Mar 2020 13:48:59 -0400 Subject: [PATCH 304/479] See if we can get Java 14 support working with a Gradle 6.3 nightly build --- build.gradle | 28 +++++++++++++++--------- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index d58ac8aba7f..a1f11983d0d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,6 @@ plugins { id "groovy" id "checkstyle" - id "codenarc" id "idea" id "maven-publish" id "java-gradle-plugin" @@ -152,13 +151,17 @@ checkstyleTest { configProperties = ['basedir': "$rootDir/config/checkstyle"] } -codenarc { - config = project.resources.text.fromFile("config/codenarc/codenarc.groovy") - ignoreFailures = false - maxPriority1Violations = 0 - maxPriority2Violations = 0 - maxPriority3Violations = 0 - toolVersion = "1.4" +if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) { + // CodeNarc is not yet compatible with Java 14 due to usage of Groovy less than 2.5.10 + apply plugin: "codenarc" + codenarc { + config = project.resources.text.fromFile("config/codenarc/codenarc.groovy") + ignoreFailures = false + maxPriority1Violations = 0 + maxPriority2Violations = 0 + maxPriority3Violations = 0 + toolVersion = "1.4" + } } tasks.create("testAvroCompatibility") { @@ -227,8 +230,13 @@ if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { keyGradleVersions.addAll("5.1", "5.6.4") // First and last for the 5.x line firstSupportedGradleVersion = gradleVersions.first() } -gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2") -keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line +if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) { + // Java 14 support will be added in Gradle 6.3 + gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2") + keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line +} +gradleVersions.addAll("6.3-20200309143235+0000") +keyGradleVersions.addAll("6.3-20200309143235+0000") def latestAvroVersion = avroVersions.last() def latestGradleVersion = gradleVersions.last() diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a2bf1313b8a..8f229351dbb 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-6.2.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-6.3-20200309143235+0000-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 597214db3c21bcd321f3e39a26b54f91309fe41a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 9 Mar 2020 15:24:20 -0400 Subject: [PATCH 305/479] Update codenarc support so it works in Java 14+; update compatibility notes --- CHANGES.md | 2 ++ README.md | 2 ++ build.gradle | 69 ++++++++++++++++++++++++++++++---------------------- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 475789f1b03..912c82bc607 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ * Update plugin's own build to address some deprecation warnings of APIs being removed in Gradle 7 * Add tests for Kotlin DSL usage (#61) * Support [Task Configuration Avoidance](https://docs.gradle.org/current/userguide/task_configuration_avoidance.html) (#97); thanks to [dcabasson](https://github.com/dcabasson) for the collaboration +* Upgrade Codenarc from 1.4 to 1.5 +* Preliminary Java 14 support ## 0.18.0 * Use reproducible file order for plugin archives diff --git a/README.md b/README.md index 1e608ae73e6..ae4f27a8e6b 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,10 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility * Currently tested against Java 8-13 + * Java 14 support is expected to require Gradle 6.3 or higher (currently tested against pre-release versions) * Java 13 support requires Gradle 6.0 or higher * Java 11 support requires Gradle 4.8 or higher + * Though not supported yet, tests are also run against early-access builds of Java 14 and Java 15 to provide early notification of potential incompatibilities * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Gradle 6.2.2 diff --git a/build.gradle b/build.gradle index a1f11983d0d..8e3d8dcc263 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ plugins { id "groovy" id "checkstyle" + id "codenarc" id "idea" id "maven-publish" id "java-gradle-plugin" @@ -12,12 +13,44 @@ repositories { } def compileAvroVersion = "1.9.2" +def codenarcVersion = "1.5" +def codenarcGroovyVersion = "2.5.10" // Newer version than included in 1.5 required for Java 14 support + +// Write the plugin's classpath to a file to share with the tests +task createClasspathManifest { + def outputDir = file("$buildDir/$name") + + inputs.files sourceSets.main.runtimeClasspath + outputs.dir outputDir + + doLast { + outputDir.mkdirs() + file("$outputDir/plugin-classpath.txt").text = sourceSets.main.runtimeClasspath.join("\n") + } +} dependencies { implementation localGroovy() implementation "org.apache.avro:avro-compiler:${compileAvroVersion}" testImplementation "org.spockframework:spock-core:1.3-groovy-2.5" testImplementation gradleTestKit() + testRuntimeOnly files(createClasspathManifest) // Add the classpath file to the test runtime classpath +} + +configurations { + codenarc { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if (details.requested.group == "org.codehaus.groovy") { + if (details.requested.name == "groovy" && details.requested.version != codenarcGroovyVersion) { + // Template support appears to have moved between modules in between versions + details.useTarget("${details.requested.group}:groovy-all:${codenarcGroovyVersion}") + } else { + details.useVersion codenarcGroovyVersion + } + details.because "Required for Java 14+ support" + } + } + } } tasks.withType(AbstractCompile) { @@ -118,24 +151,6 @@ idea { } } -// Write the plugin's classpath to a file to share with the tests -task createClasspathManifest { - def outputDir = file("$buildDir/$name") - - inputs.files sourceSets.main.runtimeClasspath - outputs.dir outputDir - - doLast { - outputDir.mkdirs() - file("$outputDir/plugin-classpath.txt").text = sourceSets.main.runtimeClasspath.join("\n") - } -} - -// Add the classpath file to the test runtime classpath -dependencies { - testRuntimeOnly files(createClasspathManifest) -} - checkstyle { ignoreFailures = false maxErrors = 0 @@ -151,17 +166,13 @@ checkstyleTest { configProperties = ['basedir': "$rootDir/config/checkstyle"] } -if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) { - // CodeNarc is not yet compatible with Java 14 due to usage of Groovy less than 2.5.10 - apply plugin: "codenarc" - codenarc { - config = project.resources.text.fromFile("config/codenarc/codenarc.groovy") - ignoreFailures = false - maxPriority1Violations = 0 - maxPriority2Violations = 0 - maxPriority3Violations = 0 - toolVersion = "1.4" - } +codenarc { + config = project.resources.text.fromFile("config/codenarc/codenarc.groovy") + ignoreFailures = false + maxPriority1Violations = 0 + maxPriority2Violations = 0 + maxPriority3Violations = 0 + toolVersion = codenarcVersion } tasks.create("testAvroCompatibility") { From 68c00768960c971c5d1db58f95b4d71a82fb9806 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 16 Mar 2020 15:31:18 -0400 Subject: [PATCH 306/479] version: 0.19.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 912c82bc607..27187b00975 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.19.0 * Add support for Gradle 6.0-6.2.2 (#101) * Drop support for Gradle versions prior to 5.1 * Update version of kotlin plugin in tests/example diff --git a/build.gradle b/build.gradle index 8e3d8dcc263..62ceeb17b4f 100644 --- a/build.gradle +++ b/build.gradle @@ -60,7 +60,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.18.1-SNAPSHOT" +version = "0.19.0" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From 02c43f085f979e556bad90ba49bb4e56b90b77b1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 16 Mar 2020 15:35:15 -0400 Subject: [PATCH 307/479] version: 0.19.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 62ceeb17b4f..d946637b422 100644 --- a/build.gradle +++ b/build.gradle @@ -60,7 +60,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.19.0" +version = "0.19.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From 4a67920eb1bec7371a6a5408d6693e2fbeb1544f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 20 Mar 2020 08:53:05 -0400 Subject: [PATCH 308/479] Create FUNDING.yml --- .github/FUNDING.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..f200f5f9ba8 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: davidmc24 From 9eddf0092d0ec031bdbd8d22f78f857e32b98438 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 23 Mar 2020 21:23:43 -0400 Subject: [PATCH 309/479] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5e6bd27549a..385d14d4417 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -40,6 +40,7 @@ A clear and concise description of what you expected to happen. - Gradle Version [e.g. 5.6.1] - Apache Avro Version [e.g. 1.8.2] - Gradle-Avro Plugin Version [e.g. 0.17.0] + - Java Version [e.g. 13.0.2] - OS: [e.g. Mac OS X Mojave, Windows 10, Ubuntu 16.04] **Additional context** From f277616f58c20e4da88124eac89a685795736cc8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 28 Mar 2020 00:20:22 -0400 Subject: [PATCH 310/479] Fix schema dependency resolution when types are referenced with a `{ "type": NAME }` block rather than just `NAME` (#107) --- CHANGES.md | 1 + .../plugin/avro/GenerateAvroJavaTask.java | 79 ++----- .../gradle/plugin/avro/ProcessingState.java | 7 +- .../gradle/plugin/avro/SchemaResolver.java | 94 ++++++++ .../gradle/plugin/avro/TypeState.java | 4 + .../DuplicateHandlingFunctionalSpec.groovy | 74 +++++-- .../plugin/avro/SchemaResolverSpec.groovy | 200 ++++++++++++++++++ .../plugin/avro/duplicate/ContainsFixed1.avsc | 8 + .../plugin/avro/duplicate/ContainsFixed2.avsc | 8 + .../plugin/avro/duplicate/ContainsFixed3.avsc | 8 + src/test/resources/resolver/SimpleEnum.avsc | 6 + src/test/resources/resolver/SimpleFixed.avsc | 6 + src/test/resources/resolver/SimpleRecord.avsc | 8 + src/test/resources/resolver/UseArray.avsc | 10 + .../resources/resolver/UseArrayWithType.avsc | 10 + src/test/resources/resolver/UseEnum.avsc | 8 + .../resources/resolver/UseEnumWithType.avsc | 8 + src/test/resources/resolver/UseFixed.avsc | 8 + .../resources/resolver/UseFixedWithType.avsc | 8 + src/test/resources/resolver/UseMap.avsc | 10 + .../resources/resolver/UseMapWithType.avsc | 10 + src/test/resources/resolver/UseRecord.avsc | 8 + .../resources/resolver/UseRecordWithType.avsc | 8 + 23 files changed, 506 insertions(+), 85 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed1.avsc create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed2.avsc create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed3.avsc create mode 100644 src/test/resources/resolver/SimpleEnum.avsc create mode 100644 src/test/resources/resolver/SimpleFixed.avsc create mode 100644 src/test/resources/resolver/SimpleRecord.avsc create mode 100644 src/test/resources/resolver/UseArray.avsc create mode 100644 src/test/resources/resolver/UseArrayWithType.avsc create mode 100644 src/test/resources/resolver/UseEnum.avsc create mode 100644 src/test/resources/resolver/UseEnumWithType.avsc create mode 100644 src/test/resources/resolver/UseFixed.avsc create mode 100644 src/test/resources/resolver/UseFixedWithType.avsc create mode 100644 src/test/resources/resolver/UseMap.avsc create mode 100644 src/test/resources/resolver/UseMapWithType.avsc create mode 100644 src/test/resources/resolver/UseRecord.avsc create mode 100644 src/test/resources/resolver/UseRecordWithType.avsc diff --git a/CHANGES.md b/CHANGES.md index 27187b00975..9b848dd3cb1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Fix schema dependency resolution when types are referenced with a `{ "type": NAME }` block rather than just `NAME` (#107) ## 0.19.0 * Add support for Gradle 6.0-6.2.2 (#101) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 1d50da2a28c..aa62d9ca803 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -20,15 +20,12 @@ import java.nio.charset.Charset; import java.util.Map; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.inject.Inject; import org.apache.avro.Conversion; import org.apache.avro.LogicalTypes; import org.apache.avro.Protocol; import org.apache.avro.Schema; -import org.apache.avro.SchemaParseException; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; import org.apache.avro.generic.GenericData; @@ -60,7 +57,6 @@ import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; -import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; /** * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and @@ -69,8 +65,6 @@ @SuppressWarnings("WeakerAccess") @CacheableTask public class GenerateAvroJavaTask extends OutputDirTask { - private static Pattern ERROR_UNKNOWN_TYPE = Pattern.compile("(?i).*(undefined name|not a defined name).*"); - private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); private static Set SUPPORTED_EXTENSIONS = new SetBuilder().add(PROTOCOL_EXTENSION).add(SCHEMA_EXTENSION).build(); private final Property outputCharacterEncoding; @@ -89,6 +83,8 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Provider fieldVisibilityProvider; private final Provider dateTimeLogicalTypeImplementationProvider; + private final SchemaResolver resolver; + @Inject public GenerateAvroJavaTask(ObjectFactory objects) { super(); @@ -111,6 +107,7 @@ public GenerateAvroJavaTask(ObjectFactory objects) { this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) .convention(DEFAULT_LOGICAL_TYPE_FACTORIES); this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(DEFAULT_CUSTOM_CONVERSIONS); + this.resolver = new SchemaResolver(getProject(), getLogger()); } @Optional @@ -318,70 +315,18 @@ private void processProtoFile(File sourceFile) { private int processSchemaFiles() { Set files = filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles(); - ProcessingState processingState = new ProcessingState(files, getProject()); - while (processingState.isWorkRemaining()) { - processSchemaFile(processingState, processingState.nextFileState()); - } - Set failedFiles = processingState.getFailedFiles(); - if (!failedFiles.isEmpty()) { - StringBuilder errorMessage = new StringBuilder("Could not compile schema definition files:"); - for (FileState fileState : failedFiles) { - String path = fileState.getPath(); - String fileErrorMessage = fileState.getErrorMessage(); - errorMessage.append(System.lineSeparator()).append("* ").append(path).append(": ").append(fileErrorMessage); - } - throw new GradleException(errorMessage.toString()); - } - return processingState.getProcessedTotal(); - } - - private void processSchemaFile(ProcessingState processingState, FileState fileState) { - String path = fileState.getPath(); - getLogger().debug("Processing {}, excluding types {}", path, fileState.getDuplicateTypeNames()); - File sourceFile = fileState.getFile(); - Map parserTypes = processingState.determineParserTypes(fileState); - try { - Schema.Parser parser = new Schema.Parser(); - parser.addTypes(parserTypes); - - compile(parser.parse(sourceFile), sourceFile); - Map typesDefinedInFile = asymmetricDifference(parser.getTypes(), parserTypes); - processingState.processTypeDefinitions(fileState, typesDefinedInFile); - if (getLogger().isDebugEnabled()) { - getLogger().debug("Processed {}; contained types {}", path, typesDefinedInFile.keySet()); - } else { - getLogger().info("Processed {}", path); - } - } catch (SchemaParseException ex) { - String errorMessage = ex.getMessage(); - Matcher unknownTypeMatcher = ERROR_UNKNOWN_TYPE.matcher(errorMessage); - Matcher duplicateTypeMatcher = ERROR_DUPLICATE_TYPE.matcher(errorMessage); - if (unknownTypeMatcher.matches()) { - fileState.setError(ex); - processingState.queueForDelayedProcessing(fileState); - getLogger().debug("Found undefined name in {} ({}); will try again", path, errorMessage); - } else if (duplicateTypeMatcher.matches()) { - String typeName = duplicateTypeMatcher.group(1); - if (fileState.containsDuplicateTypeName(typeName)) { - throw new GradleException( - String.format("Failed to compile schema definition file %s; contains duplicate type definition %s", path, typeName), - ex); - } else { - fileState.setError(ex); - fileState.addDuplicateTypeName(typeName); - processingState.queueForProcessing(fileState); - getLogger().debug("Identified duplicate type {} in {}; will re-process excluding it", typeName, path); + ProcessingState processingState = resolver.resolve(files); + for (File file : files) { + String path = getProject().relativePath(file); + for (Schema schema : processingState.getSchemasForLocation(path)) { + try { + compile(schema, file); + } catch (IOException ex) { + throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } - } else { - throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } - } catch (NullPointerException ex) { - fileState.setError(ex); - processingState.queueForDelayedProcessing(fileState); - getLogger().debug("Encountered null reference while parsing {} (possibly due to unresolved dependency); will try again", path); - } catch (IOException ex) { - throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } + return processingState.getProcessedTotal(); } private void compile(Protocol protocol, File sourceFile) throws IOException { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java index 0131247c16f..d0e29d72ae7 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Queue; import java.util.Set; +import java.util.stream.Collectors; import org.apache.avro.Schema; import org.gradle.api.Project; @@ -31,7 +32,7 @@ class ProcessingState { private final Queue filesToProcess = new LinkedList<>(); private int processedTotal; - ProcessingState(Set files, Project project) { + ProcessingState(Iterable files, Project project) { for (File file : files) { filesToProcess.add(new FileState(file, project.relativePath(file))); } @@ -98,4 +99,8 @@ boolean isWorkRemaining() { int getProcessedTotal() { return processedTotal; } + + Iterable getSchemasForLocation(String path) { + return typeStates.values().stream().filter(it -> it.hasLocation(path)).map(TypeState::getSchema).collect(Collectors.toList()); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java b/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java new file mode 100644 index 00000000000..7e1c548c7e9 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java @@ -0,0 +1,94 @@ +package com.commercehub.gradle.plugin.avro; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.avro.Schema; +import org.apache.avro.SchemaParseException; +import org.gradle.api.GradleException; +import org.gradle.api.Project; +import org.gradle.api.logging.Logger; + +import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; + +class SchemaResolver { + private static Pattern ERROR_UNKNOWN_TYPE = Pattern.compile("(?i).*(undefined name|not a defined name|type not supported).*"); + private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); + + private final Project project; + private final Logger logger; + + SchemaResolver(Project project, Logger logger) { + this.project = project; + this.logger = logger; + } + + ProcessingState resolve(Iterable files) { + ProcessingState processingState = new ProcessingState(files, project); + while (processingState.isWorkRemaining()) { + processSchemaFile(processingState, processingState.nextFileState()); + } + Set failedFiles = processingState.getFailedFiles(); + if (!failedFiles.isEmpty()) { + StringBuilder errorMessage = new StringBuilder("Could not compile schema definition files:"); + for (FileState fileState : failedFiles) { + String path = fileState.getPath(); + String fileErrorMessage = fileState.getErrorMessage(); + errorMessage.append(System.lineSeparator()).append("* ").append(path).append(": ").append(fileErrorMessage); + } + throw new GradleException(errorMessage.toString()); + } + return processingState; + } + + private void processSchemaFile(ProcessingState processingState, FileState fileState) { + String path = fileState.getPath(); + logger.debug("Processing {}, excluding types {}", path, fileState.getDuplicateTypeNames()); + File sourceFile = fileState.getFile(); + Map parserTypes = processingState.determineParserTypes(fileState); + try { + Schema.Parser parser = new Schema.Parser(); + parser.addTypes(parserTypes); + parser.parse(sourceFile); + Map typesDefinedInFile = asymmetricDifference(parser.getTypes(), parserTypes); + processingState.processTypeDefinitions(fileState, typesDefinedInFile); + if (logger.isDebugEnabled()) { + logger.debug("Processed {}; contained types {}", path, typesDefinedInFile.keySet()); + } else { + logger.info("Processed {}", path); + } + } catch (SchemaParseException ex) { + String errorMessage = ex.getMessage(); + Matcher unknownTypeMatcher = ERROR_UNKNOWN_TYPE.matcher(errorMessage); + Matcher duplicateTypeMatcher = ERROR_DUPLICATE_TYPE.matcher(errorMessage); + if (unknownTypeMatcher.matches()) { + fileState.setError(ex); + processingState.queueForDelayedProcessing(fileState); + logger.debug("Found undefined name in {} ({}); will try again", path, errorMessage); + } else if (duplicateTypeMatcher.matches()) { + String typeName = duplicateTypeMatcher.group(1); + if (fileState.containsDuplicateTypeName(typeName)) { + throw new GradleException( + String.format("Failed to compile schema definition file %s; contains duplicate type definition %s", path, typeName), + ex); + } else { + fileState.setError(ex); + fileState.addDuplicateTypeName(typeName); + processingState.queueForProcessing(fileState); + logger.debug("Identified duplicate type {} in {}; will re-process excluding it", typeName, path); + } + } else { + throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); + } + } catch (NullPointerException ex) { + fileState.setError(ex); + processingState.queueForDelayedProcessing(fileState); + logger.debug("Encountered null reference while parsing {} (possibly due to unresolved dependency); will try again", path); + } catch (IOException ex) { + throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); + } + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java index 8ac16006b0d..a0e50f28861 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java @@ -45,4 +45,8 @@ String getName() { Schema getSchema() { return schema; } + + boolean hasLocation(String location) { + return locations.contains(location); + } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index ac54adffc02..8cd0c04f5af 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -31,6 +31,21 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { addAvroDependency() } + def "Duplicate record definition succeeds if definition identical"() { + given: + copyIdenticalRecord() + + when: + def result = run() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + projectFile(buildOutputClassPath("example/Person.class")).file + projectFile(buildOutputClassPath("example/Fish.class")).file + projectFile(buildOutputClassPath("example/Gender.class")).file + } + def "Duplicate enum definition succeeds if definition identical"() { given: copyIdenticalEnum() @@ -46,9 +61,9 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { projectFile(buildOutputClassPath("example/Gender.class")).file } - def "Duplicate record definition succeeds if definition identical"() { + def "Duplicate fixed definition succeeds if definition identical"() { given: - copyIdenticalRecord() + copyIdenticalFixed() when: def result = run() @@ -56,9 +71,23 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS - projectFile(buildOutputClassPath("example/Person.class")).file - projectFile(buildOutputClassPath("example/Fish.class")).file - projectFile(buildOutputClassPath("example/Gender.class")).file + projectFile(buildOutputClassPath("example/ContainsFixed1.class")).file + projectFile(buildOutputClassPath("example/ContainsFixed2.class")).file + projectFile(buildOutputClassPath("example/Picture.class")).file + } + + def "Duplicate record definition fails if definition differs"() { + given: + copyDifferentRecord() + def errorFilePath1 = new File("src/main/avro/duplicate/Person.avsc").path + def errorFilePath2 = new File("src/main/avro/duplicate/Spider.avsc").path + when: + def result = runAndFail() + + then: + result.task(":generateAvroJava").outcome == FAILED + result.output.contains("Found conflicting definition of type example.Person in " + + "[$errorFilePath1, $errorFilePath2]") } def "Duplicate enum definition fails if definition differs"() { @@ -76,17 +105,18 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { + "[$errorFilePath1, $errorFilePath2]") } - def "Duplicate record definition fails if definition differs"() { + def "Duplicate fixed definition fails if definition differs"() { given: - copyDifferentRecord() - def errorFilePath1 = new File("src/main/avro/duplicate/Person.avsc").path - def errorFilePath2 = new File("src/main/avro/duplicate/Spider.avsc").path + copyDifferentFixed() + def errorFilePath1 = new File("src/main/avro/duplicate/ContainsFixed1.avsc").path + def errorFilePath2 = new File("src/main/avro/duplicate/ContainsFixed3.avsc").path + when: def result = runAndFail() then: result.task(":generateAvroJava").outcome == FAILED - result.output.contains("Found conflicting definition of type example.Person in " + result.output.contains("Found conflicting definition of type example.Picture in " + "[$errorFilePath1, $errorFilePath2]") } @@ -104,23 +134,33 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { "contains duplicate type definition example.avro.date") } - private void copyIdenticalEnum() { + private void copyIdenticalRecord() { copyResource("duplicate/Person.avsc", avroDir) - copyResource("duplicate/Cat.avsc", avroDir) + copyResource("duplicate/Fish.avsc", avroDir) } - private void copyDifferentEnum() { + private void copyIdenticalEnum() { copyResource("duplicate/Person.avsc", avroDir) - copyResource("duplicate/Dog.avsc", avroDir) + copyResource("duplicate/Cat.avsc", avroDir) } - private void copyIdenticalRecord() { - copyResource("duplicate/Person.avsc", avroDir) - copyResource("duplicate/Fish.avsc", avroDir) + private void copyIdenticalFixed() { + copyResource("duplicate/ContainsFixed1.avsc", avroDir) + copyResource("duplicate/ContainsFixed2.avsc", avroDir) } private void copyDifferentRecord() { copyResource("duplicate/Person.avsc", avroDir) copyResource("duplicate/Spider.avsc", avroDir) } + + private void copyDifferentEnum() { + copyResource("duplicate/Person.avsc", avroDir) + copyResource("duplicate/Dog.avsc", avroDir) + } + + private void copyDifferentFixed() { + copyResource("duplicate/ContainsFixed1.avsc", avroDir) + copyResource("duplicate/ContainsFixed3.avsc", avroDir) + } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy new file mode 100644 index 00000000000..7ee925557d7 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy @@ -0,0 +1,200 @@ +package com.commercehub.gradle.plugin.avro + +import org.gradle.api.GradleException +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import spock.lang.Specification +import spock.lang.Unroll + +class SchemaResolverSpec extends Specification { + private Project project + private SchemaResolver resolver + + def setup() { + project = ProjectBuilder.builder().build() + resolver = new SchemaResolver(project, project.logger) + } + + @Unroll + def "Can resolve records that use a separate record type (#resourceNames)"(List resourceNames) { + when: + def files = resourceNames.collect { new File("src/test/resources/resolver/${it}") } + def processingState = resolver.resolve(files) + + then: + noExceptionThrown() + processingState.failedFiles.empty + processingState.processedTotal == resourceNames.size() + + where: + resourceNames << ( + ["SimpleRecord.avsc", "UseRecord.avsc"].permutations() + + ["SimpleRecord.avsc", "UseRecordWithType.avsc"].permutations() + ) + } + + @Unroll + def "Can resolve records that use a separate enum type (#resourceNames)"(List resourceNames) { + when: + def files = resourceNames.collect { new File("src/test/resources/resolver/${it}") } + def processingState = resolver.resolve(files) + + then: + noExceptionThrown() + processingState.failedFiles.empty + processingState.processedTotal == resourceNames.size() + + where: + resourceNames << ( + ["SimpleEnum.avsc", "UseEnum.avsc"].permutations() + + ["SimpleEnum.avsc", "UseEnumWithType.avsc"].permutations() + ) + } + + @Unroll + def "Can resolve records that use a separate fixed type (#resourceNames)"(List resourceNames) { + when: + def files = resourceNames.collect { new File("src/test/resources/resolver/${it}") } + def processingState = resolver.resolve(files) + + then: + noExceptionThrown() + processingState.failedFiles.empty + processingState.processedTotal == resourceNames.size() + + where: + resourceNames << ( + ["SimpleFixed.avsc", "UseFixed.avsc"].permutations() + + ["SimpleFixed.avsc", "UseFixedWithType.avsc"].permutations() + ) + } + + @Unroll + def "Can resolve records that use a separate type in an array (#resourceNames)"(List resourceNames) { + when: + def files = resourceNames.collect { new File("src/test/resources/resolver/${it}") } + def processingState = resolver.resolve(files) + + then: + noExceptionThrown() + processingState.failedFiles.empty + processingState.processedTotal == resourceNames.size() + + where: + resourceNames << ( + ["SimpleEnum.avsc", "SimpleRecord.avsc", "SimpleFixed.avsc", "UseArray.avsc"].permutations() + + ["SimpleEnum.avsc", "SimpleRecord.avsc", "SimpleFixed.avsc", "UseArrayWithType.avsc"].permutations() + ) + } + + @Unroll + def "Can resolve records that use a separate type in an map value (#resourceNames)"(List resourceNames) { + when: + def files = resourceNames.collect { new File("src/test/resources/resolver/${it}") } + def processingState = resolver.resolve(files) + + then: + noExceptionThrown() + processingState.failedFiles.empty + processingState.processedTotal == resourceNames.size() + + where: + resourceNames << ( + ["SimpleEnum.avsc", "SimpleRecord.avsc", "SimpleFixed.avsc", "UseMap.avsc"].permutations() + + ["SimpleEnum.avsc", "SimpleRecord.avsc", "SimpleFixed.avsc", "UseMapWithType.avsc"].permutations() + ) + } + + def "Duplicate record definition succeeds if definition identical"() { + given: + def resourceNames = ["Person.avsc", "Fish.avsc"] + def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + + when: + def processingState = resolver.resolve(files) + + then: + noExceptionThrown() + processingState.failedFiles.empty + processingState.processedTotal == files.size() + } + + def "Duplicate enum definition succeeds if definition identical"() { + given: + def resourceNames = ["Person.avsc", "Cat.avsc"] + def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + + when: + def processingState = resolver.resolve(files) + + then: + noExceptionThrown() + processingState.failedFiles.empty + processingState.processedTotal == files.size() + } + + def "Duplicate fixed definition succeeds if definition identical"() { + given: + def resourceNames = ["ContainsFixed1.avsc", "ContainsFixed2.avsc"] + def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + + when: + def processingState = resolver.resolve(files) + + then: + noExceptionThrown() + processingState.failedFiles.empty + processingState.processedTotal == files.size() + } + + def "Duplicate record definition fails if definition differs"() { + given: + def resourceNames = ["Person.avsc", "Spider.avsc"] + def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + + when: + resolver.resolve(files) + + then: + def ex = thrown(GradleException) + ex.message == "Found conflicting definition of type example.Person in [${files[0].path}, ${files[1].path}]" + } + + def "Duplicate enum definition fails if definition differs"() { + given: + def resourceNames = ["Dog.avsc", "Person.avsc"] + def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + + when: + resolver.resolve(files) + + then: + def ex = thrown(GradleException) + ex.message == "Found conflicting definition of type example.Gender in [${files[0].path}, ${files[1].path}]" + } + + def "Duplicate fixed definition fails if definition differs"() { + given: + def resourceNames = ["ContainsFixed1.avsc", "ContainsFixed3.avsc"] + def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + + when: + resolver.resolve(files) + + then: + def ex = thrown(GradleException) + ex.message == "Found conflicting definition of type example.Picture in [${files[0].path}, ${files[1].path}]" + } + + def "Duplicate record definition in single file fails with clear error"() { + given: + def file = new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc") + + when: + resolver.resolve([file]) + + then: + def ex = thrown(GradleException) + ex.message == "Failed to compile schema definition file ${file.path}; contains duplicate type definition example.avro.date" + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed1.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed1.avsc new file mode 100644 index 00000000000..137ea4eca6a --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed1.avsc @@ -0,0 +1,8 @@ +{ + "name": "ContainsFixed1", + "namespace": "example", + "type": "record", + "fields": [ + { "name": "picture", "type": { "type": "fixed", "name": "Picture", "size": 16 } } + ] +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed2.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed2.avsc new file mode 100644 index 00000000000..6f55e12703b --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed2.avsc @@ -0,0 +1,8 @@ +{ + "name": "ContainsFixed2", + "namespace": "example", + "type": "record", + "fields": [ + { "name": "picture", "type": { "type": "fixed", "name": "Picture", "size": 16 } } + ] +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed3.avsc b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed3.avsc new file mode 100644 index 00000000000..9b8f65aaf2b --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed3.avsc @@ -0,0 +1,8 @@ +{ + "name": "ContainsFixed3", + "namespace": "example", + "type": "record", + "fields": [ + { "name": "picture", "type": { "type": "fixed", "name": "Picture", "size": 12 } } + ] +} diff --git a/src/test/resources/resolver/SimpleEnum.avsc b/src/test/resources/resolver/SimpleEnum.avsc new file mode 100644 index 00000000000..e4f869dee90 --- /dev/null +++ b/src/test/resources/resolver/SimpleEnum.avsc @@ -0,0 +1,6 @@ +{ + "name": "SimpleEnum", + "namespace": "resolver", + "type": "enum", + "symbols" : ["val1", "val2", "val3"] +} diff --git a/src/test/resources/resolver/SimpleFixed.avsc b/src/test/resources/resolver/SimpleFixed.avsc new file mode 100644 index 00000000000..b2b3c56137d --- /dev/null +++ b/src/test/resources/resolver/SimpleFixed.avsc @@ -0,0 +1,6 @@ +{ + "name": "SimpleFixed", + "type": "fixed", + "namespace": "resolver", + "size": 16 +} diff --git a/src/test/resources/resolver/SimpleRecord.avsc b/src/test/resources/resolver/SimpleRecord.avsc new file mode 100644 index 00000000000..2db062f3303 --- /dev/null +++ b/src/test/resources/resolver/SimpleRecord.avsc @@ -0,0 +1,8 @@ +{ + "name": "SimpleRecord", + "type": "record", + "namespace": "resolver", + "fields": [ + { "name": "field1", "type": "string" } + ] +} diff --git a/src/test/resources/resolver/UseArray.avsc b/src/test/resources/resolver/UseArray.avsc new file mode 100644 index 00000000000..1b39cd9a055 --- /dev/null +++ b/src/test/resources/resolver/UseArray.avsc @@ -0,0 +1,10 @@ +{ + "name": "UseRecord", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": {"type": "array", "items": "SimpleRecord"} }, + {"name": "field2", "type": {"type": "array", "items": "SimpleEnum"} }, + {"name": "field3", "type": {"type": "array", "items": "SimpleFixed"} } + ] +} diff --git a/src/test/resources/resolver/UseArrayWithType.avsc b/src/test/resources/resolver/UseArrayWithType.avsc new file mode 100644 index 00000000000..58407ee1fd1 --- /dev/null +++ b/src/test/resources/resolver/UseArrayWithType.avsc @@ -0,0 +1,10 @@ +{ + "name": "UseRecord", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": {"type": "array", "items": {"type": "SimpleRecord"} } }, + {"name": "field2", "type": {"type": "array", "items": {"type": "SimpleEnum"} } }, + {"name": "field3", "type": {"type": "array", "items": {"type": "SimpleFixed"} } } + ] +} diff --git a/src/test/resources/resolver/UseEnum.avsc b/src/test/resources/resolver/UseEnum.avsc new file mode 100644 index 00000000000..d8c97fd2e90 --- /dev/null +++ b/src/test/resources/resolver/UseEnum.avsc @@ -0,0 +1,8 @@ +{ + "name": "UseEnum", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": "SimpleEnum"} + ] +} diff --git a/src/test/resources/resolver/UseEnumWithType.avsc b/src/test/resources/resolver/UseEnumWithType.avsc new file mode 100644 index 00000000000..fc2893f7ef4 --- /dev/null +++ b/src/test/resources/resolver/UseEnumWithType.avsc @@ -0,0 +1,8 @@ +{ + "name": "UseEnum", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": {"type": "SimpleEnum"} } + ] +} diff --git a/src/test/resources/resolver/UseFixed.avsc b/src/test/resources/resolver/UseFixed.avsc new file mode 100644 index 00000000000..22017e7ddc5 --- /dev/null +++ b/src/test/resources/resolver/UseFixed.avsc @@ -0,0 +1,8 @@ +{ + "name": "UseEnum", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": "SimpleFixed"} + ] +} diff --git a/src/test/resources/resolver/UseFixedWithType.avsc b/src/test/resources/resolver/UseFixedWithType.avsc new file mode 100644 index 00000000000..f5253e23316 --- /dev/null +++ b/src/test/resources/resolver/UseFixedWithType.avsc @@ -0,0 +1,8 @@ +{ + "name": "UseEnum", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": {"type": "SimpleFixed"} } + ] +} diff --git a/src/test/resources/resolver/UseMap.avsc b/src/test/resources/resolver/UseMap.avsc new file mode 100644 index 00000000000..5f0689414ef --- /dev/null +++ b/src/test/resources/resolver/UseMap.avsc @@ -0,0 +1,10 @@ +{ + "name": "UseRecord", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": {"type": "map", "values": "SimpleRecord"} }, + {"name": "field2", "type": {"type": "map", "values": "SimpleEnum"} }, + {"name": "field3", "type": {"type": "map", "values": "SimpleFixed"} } + ] +} diff --git a/src/test/resources/resolver/UseMapWithType.avsc b/src/test/resources/resolver/UseMapWithType.avsc new file mode 100644 index 00000000000..b927f9ec301 --- /dev/null +++ b/src/test/resources/resolver/UseMapWithType.avsc @@ -0,0 +1,10 @@ +{ + "name": "UseRecord", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": {"type": "map", "values": {"type": "SimpleRecord"} } }, + {"name": "field2", "type": {"type": "map", "values": {"type": "SimpleEnum"} } }, + {"name": "field3", "type": {"type": "map", "values": {"type": "SimpleFixed"} } } + ] +} diff --git a/src/test/resources/resolver/UseRecord.avsc b/src/test/resources/resolver/UseRecord.avsc new file mode 100644 index 00000000000..6d9fb0431fb --- /dev/null +++ b/src/test/resources/resolver/UseRecord.avsc @@ -0,0 +1,8 @@ +{ + "name": "UseRecord", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": "SimpleRecord"} + ] +} diff --git a/src/test/resources/resolver/UseRecordWithType.avsc b/src/test/resources/resolver/UseRecordWithType.avsc new file mode 100644 index 00000000000..522448c22bd --- /dev/null +++ b/src/test/resources/resolver/UseRecordWithType.avsc @@ -0,0 +1,8 @@ +{ + "name": "UseRecord", + "namespace": "resolver", + "type": "record", + "fields" : [ + {"name": "field1", "type": {"type": "SimpleRecord"} } + ] +} From 9c633b7d21024a0520b8c148a1165cbf48833104 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 28 Mar 2020 00:44:10 -0400 Subject: [PATCH 311/479] Eliminate `NullPointerException` handling in schema dependency resolution, as it no longer appears to be needed. --- CHANGES.md | 1 + .../com/commercehub/gradle/plugin/avro/SchemaResolver.java | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9b848dd3cb1..000130a0fff 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## Unreleased * Fix schema dependency resolution when types are referenced with a `{ "type": NAME }` block rather than just `NAME` (#107) +* Eliminate `NullPointerException` handling in schema dependency resolution, as it no longer appears to be needed. ## 0.19.0 * Add support for Gradle 6.0-6.2.2 (#101) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java b/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java index 7e1c548c7e9..061fb4aaf6b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java @@ -83,10 +83,6 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt } else { throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } - } catch (NullPointerException ex) { - fileState.setError(ex); - processingState.queueForDelayedProcessing(fileState); - logger.debug("Encountered null reference while parsing {} (possibly due to unresolved dependency); will try again", path); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } From e54847a149bfb59ee5d9ab4f3759138f1fc29bb7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 30 Mar 2020 10:47:45 -0400 Subject: [PATCH 312/479] version: 0.19.1 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 000130a0fff..ca3e42a3486 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.19.1 * Fix schema dependency resolution when types are referenced with a `{ "type": NAME }` block rather than just `NAME` (#107) * Eliminate `NullPointerException` handling in schema dependency resolution, as it no longer appears to be needed. diff --git a/build.gradle b/build.gradle index d946637b422..f7a9c575b20 100644 --- a/build.gradle +++ b/build.gradle @@ -60,7 +60,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.19.1-SNAPSHOT" +version = "0.19.1" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From ff699b8f9c385c033313b62d8a573651016b6622 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 30 Mar 2020 10:50:25 -0400 Subject: [PATCH 313/479] version: 0.19.2-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f7a9c575b20..7ec23972fce 100644 --- a/build.gradle +++ b/build.gradle @@ -60,7 +60,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.19.1" +version = "0.19.2-SNAPSHOT" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From 644a7447f3f040000ca246f6d7c9abb7dad160f2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 12 Jun 2020 17:27:57 -0400 Subject: [PATCH 314/479] Add (#115) --- CHANGES.md | 1 + README.md | 17 +++++- build.gradle | 1 + .../gradle/plugin/avro/ProcessingState.java | 4 ++ .../avro/ResolveAvroDependenciesTask.java | 60 +++++++++++++++++++ .../gradle/plugin/avro/SchemaResolver.java | 8 +-- .../avro/AvroPluginFunctionalSpec.groovy | 2 +- .../DuplicateHandlingFunctionalSpec.groovy | 2 +- ...eAvroDependenciesTaskFunctionalSpec.groovy | 39 ++++++++++++ .../plugin/avro/SchemaResolverSpec.groovy | 2 +- 10 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy diff --git a/CHANGES.md b/CHANGES.md index ca3e42a3486..b39cd14b508 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Add `ResolveAvroDependenciesTask` (#115) ## 0.19.1 * Fix schema dependency resolution when types are referenced with a `{ "type": NAME }` block rather than just `NAME` (#107) diff --git a/README.md b/README.md index ae4f27a8e6b..11dda73ce8e 100644 --- a/README.md +++ b/README.md @@ -379,7 +379,22 @@ avro { } ``` -# Generating schema files +# Resolving schema dependencies + +If desired, you can generate JSON schema with dependencies resolved. + +Example build: + +```groovy +apply plugin: "com.commercehub.gradle.plugin.avro-base" + +tasks.register("resolveAvroDependencies", com.commercehub.gradle.plugin.avro.ResolveAvroDependenciesTask) { + source file("src/avro/normalized") + outputDir = file("build/avro/resolved") +} +``` + +# Generating schema files from protocol/IDL If desired, you can generate JSON schema files. To do this, apply the plugin (either `avro` or `avro-base`), and define custom tasks as needed for the schema generation. diff --git a/build.gradle b/build.gradle index 7ec23972fce..1498b1a2a22 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,7 @@ dependencies { implementation "org.apache.avro:avro-compiler:${compileAvroVersion}" testImplementation "org.spockframework:spock-core:1.3-groovy-2.5" testImplementation gradleTestKit() + testImplementation "uk.co.datumedge:hamcrest-json:0.2" testRuntimeOnly files(createClasspathManifest) // Add the classpath file to the test runtime classpath } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java index d0e29d72ae7..9dfef361fe8 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -103,4 +103,8 @@ int getProcessedTotal() { Iterable getSchemasForLocation(String path) { return typeStates.values().stream().filter(it -> it.hasLocation(path)).map(TypeState::getSchema).collect(Collectors.toList()); } + + Iterable getSchemas() { + return typeStates.values().stream().map(TypeState::getSchema).collect(Collectors.toSet()); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java new file mode 100644 index 00000000000..43be00c8dd2 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java @@ -0,0 +1,60 @@ +package com.commercehub.gradle.plugin.avro; + +import java.io.File; +import java.io.IOException; +import java.util.Set; +import java.util.regex.Pattern; +import org.apache.avro.Schema; +import org.gradle.api.GradleException; +import org.gradle.api.file.FileCollection; +import org.gradle.api.specs.NotSpec; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.TaskAction; + +import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; + +/** + * Task to read Avro schema files, resolve their dependencies, and write out dependency-free Avro schema files. + */ +@CacheableTask +public class ResolveAvroDependenciesTask extends OutputDirTask { + private final SchemaResolver resolver = new SchemaResolver(getProject(), getLogger()); + + @TaskAction + protected void process() { + getLogger().info("Found {} files", getInputs().getSourceFiles().getFiles().size()); + failOnUnsupportedFiles(); + processFiles(); + } + + private void failOnUnsupportedFiles() { + FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(SCHEMA_EXTENSION))); + if (!unsupportedFiles.isEmpty()) { + throw new GradleException( + String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); + } + } + + private void processFiles() { + int processedFileCount = processSchemaFiles(); + setDidWork(processedFileCount > 0); + } + + private int processSchemaFiles() { + Set inputFiles = filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles(); + ProcessingState processingState = resolver.resolve(inputFiles); + for (Schema schema : processingState.getSchemas()) { + try { + String outputPath = schema.getNamespace().replaceAll(Pattern.quote("."), "/") + + "/" + schema.getName() + "." + SCHEMA_EXTENSION; + File outputFile = new File(getOutputDir().get().getAsFile(), outputPath); + String schemaJson = schema.toString(true); + FileUtils.writeJsonFile(outputFile, schemaJson); + getLogger().debug("Wrote {}", outputFile.getPath()); + } catch (IOException ex) { + throw new GradleException(String.format("Failed to write resolved schema definition for %s", schema.getFullName()), ex); + } + } + return processingState.getProcessedTotal(); + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java b/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java index 061fb4aaf6b..9c3253208db 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java @@ -33,7 +33,7 @@ ProcessingState resolve(Iterable files) { } Set failedFiles = processingState.getFailedFiles(); if (!failedFiles.isEmpty()) { - StringBuilder errorMessage = new StringBuilder("Could not compile schema definition files:"); + StringBuilder errorMessage = new StringBuilder("Could not resolve schema definition files:"); for (FileState fileState : failedFiles) { String path = fileState.getPath(); String fileErrorMessage = fileState.getErrorMessage(); @@ -72,7 +72,7 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt String typeName = duplicateTypeMatcher.group(1); if (fileState.containsDuplicateTypeName(typeName)) { throw new GradleException( - String.format("Failed to compile schema definition file %s; contains duplicate type definition %s", path, typeName), + String.format("Failed to resolve schema definition file %s; contains duplicate type definition %s", path, typeName), ex); } else { fileState.setError(ex); @@ -81,10 +81,10 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt logger.debug("Identified duplicate type {} in {}; will re-process excluding it", typeName, path); } } else { - throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); + throw new GradleException(String.format("Failed to resolve schema definition file %s", path), ex); } } catch (IOException ex) { - throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); + throw new GradleException(String.format("Failed to resolve schema definition file %s", path), ex); } } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index c8211630b25..21b2e3f720d 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -127,7 +127,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == FAILED - result.output.contains("> Could not compile schema definition files:") + result.output.contains("> Could not resolve schema definition files:") result.output.contains("* $errorFilePath: \"enum\" is not a defined name. The type of the \"gender\" " + "field must be a defined name or a {\"type\": ...} expression.") } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index 8cd0c04f5af..ee68afafc44 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -130,7 +130,7 @@ class DuplicateHandlingFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == FAILED - result.output.contains("Failed to compile schema definition file $errorFilePath; " + + result.output.contains("Failed to resolve schema definition file $errorFilePath; " + "contains duplicate type definition example.avro.date") } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy new file mode 100644 index 00000000000..23edcb9d8c0 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy @@ -0,0 +1,39 @@ +package com.commercehub.gradle.plugin.avro + +import org.hamcrest.MatcherAssert +import spock.lang.Subject +import uk.co.datumedge.hamcrest.json.SameJSONAs + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +@Subject(ResolveAvroDependenciesTask) +class ResolveAvroDependenciesTaskFunctionalSpec extends FunctionalSpec { + def "resolves dependencies"() { + def srcDir = testProjectDir.newFolder("src", "avro", "normalized") + + given: "a build with the task declared" + applyAvroBasePlugin() + buildFile << """ + |tasks.register("resolveAvroDependencies", com.commercehub.gradle.plugin.avro.ResolveAvroDependenciesTask) { + | source file("src/avro/normalized") + | outputDir = file("build/avro/resolved") + |} + |""".stripMargin() + + and: "some normalized schema files" + copyResource("/examples/separate/Breed.avsc", srcDir) + copyResource("/examples/separate/Cat.avsc", srcDir) + + when: "running the task" + def result = run("resolveAvroDependencies") + + then: "the resolved schema files are generated" + result.task(":resolveAvroDependencies").outcome == SUCCESS + MatcherAssert.assertThat( + projectFile("build/avro/resolved/example/Cat.avsc").text, + SameJSONAs.sameJSONAs(getClass().getResourceAsStream("/examples/inline/Cat.avsc").text)) + MatcherAssert.assertThat( + projectFile("build/avro/resolved/example/Breed.avsc").text, + SameJSONAs.sameJSONAs(getClass().getResourceAsStream("/examples/separate/Breed.avsc").text)) + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy index 7ee925557d7..38d418c04ba 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy @@ -195,6 +195,6 @@ class SchemaResolverSpec extends Specification { then: def ex = thrown(GradleException) - ex.message == "Failed to compile schema definition file ${file.path}; contains duplicate type definition example.avro.date" + ex.message == "Failed to resolve schema definition file ${file.path}; contains duplicate type definition example.avro.date" } } From 7c82319612f89be4e5e01f91f90a61a83803141c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 15 Jun 2020 09:38:59 -0400 Subject: [PATCH 315/479] Update version compatibility support * Built using Gradle 6.5 * Updated compatibility testing to include Java 14 * Updated compatibility testing through Gradle 6.5 --- .github/workflows/ci.yml | 4 ++-- CHANGES.md | 3 +++ README.md | 9 +++++---- build.gradle | 8 ++++---- gradle/wrapper/gradle-wrapper.jar | Bin 58695 -> 58910 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 ++ gradlew.bat | 1 + 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9f2e009236..8d08a7ddd87 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - java: [8, 11, 13] + java: [8, 11, 13, 14] fail-fast: true max-parallel: 5 steps: @@ -60,7 +60,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - java: [14-ea, 15-ea] + java: [15-ea] fail-fast: false max-parallel: 5 steps: diff --git a/CHANGES.md b/CHANGES.md index b39cd14b508..9a78667ca39 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,9 @@ # Change Log ## Unreleased +* Built using Gradle 6.5 +* Updated compatibility testing to include Java 14 +* Updated compatibility testing through Gradle 6.5 * Add `ResolveAvroDependenciesTask` (#115) ## 0.19.1 diff --git a/README.md b/README.md index 11dda73ce8e..63a347258b7 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,16 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Java 8-13 - * Java 14 support is expected to require Gradle 6.3 or higher (currently tested against pre-release versions) +* Currently tested against Java 8-14 + * Java 15 support appears to require Gradle 6.3 or higher (currently tested against pre-release versions) + * Java 14 support requires Gradle 6.3 or higher * Java 13 support requires Gradle 6.0 or higher * Java 11 support requires Gradle 4.8 or higher * Though not supported yet, tests are also run against early-access builds of Java 14 and Java 15 to provide early notification of potential incompatibilities * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Gradle 6.2.2 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.2.2 +* Currently built against Gradle 6.5 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.5 * If you need support for Gradle 4.4-5.0, version 0.18.0 was the last version tested for compatibility * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) diff --git a/build.gradle b/build.gradle index 1498b1a2a22..99f86e0c594 100644 --- a/build.gradle +++ b/build.gradle @@ -243,12 +243,12 @@ if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { firstSupportedGradleVersion = gradleVersions.first() } if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) { - // Java 14 support will be added in Gradle 6.3 + // Java 14 support was added in Gradle 6.3 gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2") - keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line + keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line before Java 14 support } -gradleVersions.addAll("6.3-20200309143235+0000") -keyGradleVersions.addAll("6.3-20200309143235+0000") +gradleVersions.addAll("6.3", "6.4", "6.4.1", "6.5") +keyGradleVersions.addAll("6.3", "6.5") // First and last for the 6.x line after Java 14 support def latestAvroVersion = avroVersions.last() def latestGradleVersion = gradleVersions.last() diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f3d88b1c2faf2fc91d853cd5d4242b5547257070..62d4c053550b91381bbd28b1afc82d634bf73a8a 100644 GIT binary patch delta 12524 zcmY*pqN z|ERss*;ReIR@Lg&r_R7IT-GRDbpR4NMKNcwFgy&*A|eco1PnBHRth?SBneiw6$UT&^LVJ0?Naa`KfV(>F!Ez}~S z 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 delta 12163 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8f229351dbb..622ab64a3cb 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-snapshots/gradle-6.3-20200309143235+0000-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 2fe81a7d95e..fbd7c515832 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index 9109989e3cb..a9f778a7a96 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -84,6 +84,7 @@ set CMD_LINE_ARGS=%* set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% From 5bad604c638ff94eee419801844c004e285215f6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 17 Jun 2020 10:49:58 -0400 Subject: [PATCH 316/479] version: 0.20.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 9a78667ca39..372af70f9fa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.20.0 * Built using Gradle 6.5 * Updated compatibility testing to include Java 14 * Updated compatibility testing through Gradle 6.5 diff --git a/build.gradle b/build.gradle index 99f86e0c594..5c5c1fe9ba2 100644 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.19.2-SNAPSHOT" +version = "0.20.0" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From 0dd326fa18c4d3e2585adeb17ea0d85bb8244a47 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 17 Jun 2020 10:52:49 -0400 Subject: [PATCH 317/479] version: 0.20.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5c5c1fe9ba2..106b8ef1de3 100644 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.20.0" +version = "0.20.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From a5ad2f5f510afcbf8a53a9d053843a2468e4b554 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 17 Jun 2020 23:20:45 -0400 Subject: [PATCH 318/479] ci: Tweak how the jobs are run to reduce execution time and unreliability Mac OS X jobs have been failing with messages that they were cancelled. My theory is that either Mac OS X jobs are flakey right now, or I'm hitting an execution timeout of some kind. Either way, this reduces how long jobs run for and how many are run on Mac OS X. Hopefully it will complete faster (providing faster feedback) and be more reliable. --- .github/workflows/ci.yml | 60 ++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d08a7ddd87..d8317bd8bc9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,18 +2,19 @@ name: CI Build on: [push, pull_request] jobs: build: - name: Baseline build + name: Java ${{ matrix.java }}/${{ matrix.os }} baseline build runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] + os: [ubuntu-latest, windows-latest, macOS-latest] # All supported OS + java: [8] # Minimum supported major version steps: - name: Check out repository uses: actions/checkout@v1 - name: Set up Java 8 uses: actions/setup-java@v1 with: - java-version: 8.0.222 + java-version: ${{ matrix.java }} architecture: x64 - name: Output Java version run: java -version @@ -25,16 +26,17 @@ jobs: run: ./gradlew build --info env: GRADLE_OPTS: -Dorg.gradle.daemon=false - compatibility-tests: - name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility + recent-compatibility-tests: + name: Java ${{ matrix.java }}/${{ matrix.os }} recent version compatibility needs: [build] runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] - java: [8, 11, 13, 14] + # Exclude mac as it's unreliable at the moment + # See https://github.com/actions/virtual-environments/issues/736 + os: [ubuntu-latest, windows-latest] + java: [8, 11, 13, 14] # All supported major versions fail-fast: true - max-parallel: 5 steps: - name: Check out repository uses: actions/checkout@v1 @@ -49,7 +51,34 @@ jobs: run: ./gradlew --version env: GRADLE_OPTS: -Dorg.gradle.daemon=false - - name: Run version compatibility tests + - name: Run recent version compatibility tests + run: ./gradlew testRecentVersionCompatibility --info + env: + GRADLE_OPTS: -Dorg.gradle.daemon=false + full-compatibility-tests: + name: Java ${{ matrix.java }}/${{ matrix.os }} full compatibility + needs: [build] + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] # Only a single OS to cut down on execution time + java: [8, 11] # LTS versions only; 17 will be the next one + fail-fast: true + steps: + - name: Check out repository + uses: actions/checkout@v1 + - name: Set up Java ${{ matrix.java }} + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + architecture: x64 + - name: Output Java version + run: java -version + - name: Output Gradle version + run: ./gradlew --version + env: + GRADLE_OPTS: -Dorg.gradle.daemon=false + - name: Run full version compatibility tests run: ./gradlew testVersionCompatibility --info env: GRADLE_OPTS: -Dorg.gradle.daemon=false @@ -59,10 +88,11 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] - java: [15-ea] + # Exclude mac as it's unreliable at the moment + # See https://github.com/actions/virtual-environments/issues/736 + os: [ubuntu-latest, windows-latest] + java: [15-ea] # EA builds of all current pre-release major versions fail-fast: false - max-parallel: 5 steps: - name: Check out repository uses: actions/checkout@v1 @@ -77,8 +107,10 @@ jobs: run: ./gradlew --version env: GRADLE_OPTS: -Dorg.gradle.daemon=false - - name: Run tests + - name: Build with Gradle continue-on-error: true - run: ./gradlew build testVersionCompatibility --info + # Most Java version compatibility failures will manifest directly in the + # test suite with any Avro version + run: ./gradlew build --info env: GRADLE_OPTS: -Dorg.gradle.daemon=false From dd0a7a828fcf8d6aa2e6b3989d560d1e65bc6440 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 18 Jun 2020 10:34:14 -0400 Subject: [PATCH 319/479] CI: try using eskatos/gradle-command-action to improve build speed This enables use of the daemon and easy caching of wrapper Might enable depenendcy caching latter (isn't on by default yet) --- .github/workflows/ci.yml | 80 +++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8317bd8bc9..7bb8db0d777 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,9 @@ name: CI Build on: [push, pull_request] jobs: + # Run the main project first to get rapid feedback about anything broken + # on the most important supported versions (latest supported Avro/Gradle, + # earliest supported Java major version) build: name: Java ${{ matrix.java }}/${{ matrix.os }} baseline build runs-on: ${{ matrix.os }} @@ -19,13 +22,19 @@ jobs: - name: Output Java version run: java -version - name: Output Gradle version - run: ./gradlew --version - env: - GRADLE_OPTS: -Dorg.gradle.daemon=false + uses: eskatos/gradle-command-action@v1 + with: + arguments: --version - name: Build with Gradle - run: ./gradlew build --info - env: - GRADLE_OPTS: -Dorg.gradle.daemon=false + uses: eskatos/gradle-command-action@v1 + with: + arguments: --info build + - name: Stop Gradle Daemon + uses: eskatos/gradle-command-action@v1 + with: + arguments: --stop + # Run further compatibility tests to ensure that key versions of Gradle/Avro + # work on a variety of OS/Java version combinations recent-compatibility-tests: name: Java ${{ matrix.java }}/${{ matrix.os }} recent version compatibility needs: [build] @@ -48,13 +57,19 @@ jobs: - name: Output Java version run: java -version - name: Output Gradle version - run: ./gradlew --version - env: - GRADLE_OPTS: -Dorg.gradle.daemon=false + uses: eskatos/gradle-command-action@v1 + with: + arguments: --version - name: Run recent version compatibility tests - run: ./gradlew testRecentVersionCompatibility --info - env: - GRADLE_OPTS: -Dorg.gradle.daemon=false + uses: eskatos/gradle-command-action@v1 + with: + arguments: --info testRecentVersionCompatibility + - name: Stop Gradle Daemon + uses: eskatos/gradle-command-action@v1 + with: + arguments: --stop + # Run exhaustive compatibility testing of further Gradle/Avro versions on a + # smaller set of OS/Java versions full-compatibility-tests: name: Java ${{ matrix.java }}/${{ matrix.os }} full compatibility needs: [build] @@ -75,14 +90,22 @@ jobs: - name: Output Java version run: java -version - name: Output Gradle version - run: ./gradlew --version - env: - GRADLE_OPTS: -Dorg.gradle.daemon=false + uses: eskatos/gradle-command-action@v1 + with: + arguments: --version - name: Run full version compatibility tests - run: ./gradlew testVersionCompatibility --info - env: - GRADLE_OPTS: -Dorg.gradle.daemon=false + uses: eskatos/gradle-command-action@v1 + with: + arguments: --info testVersionCompatibility + - name: Stop Gradle Daemon + uses: eskatos/gradle-command-action@v1 + with: + arguments: --stop + # Early visibility to whether the project works on upcoming Java versions unsupported-java-versions: + # Most Java version compatibility failures will manifest directly in the + # test suite with any Avro version; no need to run compatibity test + # target. name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility needs: [build] runs-on: ${{ matrix.os }} @@ -104,13 +127,18 @@ jobs: - name: Output Java version run: java -version - name: Output Gradle version - run: ./gradlew --version - env: - GRADLE_OPTS: -Dorg.gradle.daemon=false + uses: eskatos/gradle-command-action@v1 + with: + arguments: --version - name: Build with Gradle continue-on-error: true - # Most Java version compatibility failures will manifest directly in the - # test suite with any Avro version - run: ./gradlew build --info - env: - GRADLE_OPTS: -Dorg.gradle.daemon=false + uses: eskatos/gradle-command-action@v1 + with: + arguments: --info build + - name: Build with Gradle + continue-on-error: true + run: ./gradlew --no-daemon --info build + - name: Stop Gradle Daemon + uses: eskatos/gradle-command-action@v1 + with: + arguments: --stop From d0d48feb3e53060fc6ebb0f61811c70f691c013d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 18 Jun 2020 16:13:04 -0400 Subject: [PATCH 320/479] CI: try turning on build scans --- build.gradle | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/build.gradle b/build.gradle index 106b8ef1de3..d267283da97 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,22 @@ plugins { id "maven-publish" id "java-gradle-plugin" id "com.jfrog.bintray" version "1.8.1" + id "org.nosphere.gradle.github.actions" version "1.2.0" + id "com.gradle.enterprise" version "3.3.4" +} + +gradleEnterprise { + buildScan { + if (System.getenv("CI")) { + termsOfServiceUrl = "https://gradle.com/terms-of-service" + termsOfServiceAgree = "yes" + publishAlways() + uploadInBackground = false + tag "CI" + } else { + tag "Local" + } + } } repositories { From ea06bcc82666fe3bf929ef5cd934394a64c3ef8e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 18 Jun 2020 16:35:16 -0400 Subject: [PATCH 321/479] CI: fix the build It looks like there may be an incompatibility between gradle-entrprise and gradle-github-actions; try just gradle-enterprise for now. Also, gralde-enterprise needs to be applied in the settings file with the latest version. --- build.gradle | 18 ++---------------- settings.gradle | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/build.gradle b/build.gradle index d267283da97..db3cf32fab2 100644 --- a/build.gradle +++ b/build.gradle @@ -6,22 +6,8 @@ plugins { id "maven-publish" id "java-gradle-plugin" id "com.jfrog.bintray" version "1.8.1" - id "org.nosphere.gradle.github.actions" version "1.2.0" - id "com.gradle.enterprise" version "3.3.4" -} - -gradleEnterprise { - buildScan { - if (System.getenv("CI")) { - termsOfServiceUrl = "https://gradle.com/terms-of-service" - termsOfServiceAgree = "yes" - publishAlways() - uploadInBackground = false - tag "CI" - } else { - tag "Local" - } - } + // TODO: try to get this working + //id "org.nosphere.gradle.github.actions" version "1.2.0" } repositories { diff --git a/settings.gradle b/settings.gradle index cf064976db5..b3d572ee837 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,19 @@ +plugins { + id "com.gradle.enterprise" version "3.3.4" +} + rootProject.name = "gradle-avro-plugin" + +gradleEnterprise { + buildScan { + if (System.getenv("CI")) { + termsOfServiceUrl = "https://gradle.com/terms-of-service" + termsOfServiceAgree = "yes" + publishAlways() + uploadInBackground = false + tag "CI" + } else { + tag "Local" + } + } +} From 46956aa9de3937cdb992f6ca1720c16a3cc15d20 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 18 Jun 2020 16:57:19 -0400 Subject: [PATCH 322/479] CI: some build tweaks for performance Enable github actions plugin to capture metadata in build scans Enable parallel builds Enable dependency caching --- .github/workflows/ci.yml | 4 ++++ build.gradle | 2 +- gradle.properties | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7bb8db0d777..4a994b654b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,7 @@ jobs: uses: eskatos/gradle-command-action@v1 with: arguments: --info build + dependencies-cache-enabled: true - name: Stop Gradle Daemon uses: eskatos/gradle-command-action@v1 with: @@ -64,6 +65,7 @@ jobs: uses: eskatos/gradle-command-action@v1 with: arguments: --info testRecentVersionCompatibility + dependencies-cache-enabled: true - name: Stop Gradle Daemon uses: eskatos/gradle-command-action@v1 with: @@ -97,6 +99,7 @@ jobs: uses: eskatos/gradle-command-action@v1 with: arguments: --info testVersionCompatibility + dependencies-cache-enabled: true - name: Stop Gradle Daemon uses: eskatos/gradle-command-action@v1 with: @@ -135,6 +138,7 @@ jobs: uses: eskatos/gradle-command-action@v1 with: arguments: --info build + dependencies-cache-enabled: true - name: Build with Gradle continue-on-error: true run: ./gradlew --no-daemon --info build diff --git a/build.gradle b/build.gradle index db3cf32fab2..cfe00923948 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { id "java-gradle-plugin" id "com.jfrog.bintray" version "1.8.1" // TODO: try to get this working - //id "org.nosphere.gradle.github.actions" version "1.2.0" + id "org.nosphere.gradle.github.actions" version "1.2.0" } repositories { diff --git a/gradle.properties b/gradle.properties index f5b0e963282..3f5b52c4be6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,3 @@ org.gradle.warning.mode=all +org.gradle.parallel=true systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false From 109e700ae5084d8ebe9f04952dfd77a3f0dc0973 Mon Sep 17 00:00:00 2001 From: Denis Cabasson Date: Fri, 26 Jun 2020 13:35:06 -0400 Subject: [PATCH 323/479] Correcting cache annotation for classpath --- .../gradle/plugin/avro/GenerateAvroProtocolTask.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index f1ea6f70c6e..e7682283996 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -28,21 +28,18 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.specs.NotSpec; import org.gradle.api.tasks.CacheableTask; -import org.gradle.api.tasks.InputFiles; -import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.TaskAction; import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; -import static org.gradle.api.tasks.PathSensitivity.RELATIVE; /** * Task to convert Avro IDL files into Avro protocol files using {@link Idl}. */ @CacheableTask public class GenerateAvroProtocolTask extends OutputDirTask { - @InputFiles - @PathSensitive(value = RELATIVE) + private FileCollection classpath; public GenerateAvroProtocolTask() { @@ -58,6 +55,7 @@ public void classpath(Object... paths) { this.classpath.plus(getProject().files(paths)); } + @Classpath public FileCollection getClasspath() { return this.classpath; } From 8424b7c89d65ed8cdbd8dd18337bce469e5c7639 Mon Sep 17 00:00:00 2001 From: Denis Cabasson Date: Fri, 26 Jun 2020 18:20:18 -0400 Subject: [PATCH 324/479] Correcting cache annotation for classpath - add items to unreleased changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 372af70f9fa..4a92f923a34 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Apply @Classpath annotation to classpath on `GenerateAvroProtocolTask` ## 0.20.0 * Built using Gradle 6.5 From 71a4507e39e0bc5b4639181f386621aba04ae687 Mon Sep 17 00:00:00 2001 From: mcwhitak Date: Sat, 27 Jun 2020 12:06:52 -0500 Subject: [PATCH 325/479] Update to Avro 1.10.0 --- README.md | 66 ++++++------- build.gradle | 7 +- .../gradle/plugin/avro/AvroBasePlugin.java | 2 +- .../gradle/plugin/avro/AvroExtension.java | 2 +- .../gradle/plugin/avro/Constants.java | 4 +- .../plugin/avro/DefaultAvroExtension.java | 31 ++++--- .../plugin/avro/GenerateAvroJavaTask.java | 46 +++++----- .../CustomConversionFunctionalSpec.groovy | 9 ++ .../gradle/plugin/avro/FunctionalSpec.groovy | 2 +- ...otlinDSLCompatibilityFunctionalSpec.groovy | 3 +- .../plugin/avro/OptionsFunctionalSpec.groovy | 92 ++++++++----------- .../commercehub/gradle/plugin/avro/record.vm | 2 +- 12 files changed, 133 insertions(+), 133 deletions(-) diff --git a/README.md b/README.md index 63a347258b7..0a28ca37027 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,9 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * If you need support for Gradle 4.4-5.0, version 0.18.0 was the last version tested for compatibility * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Avro 1.9.2 - * Currently tested against Avro 1.9.0-1.9.2 +* Currently built against Avro 1.10.0 + * Currently tested against Avro 1.10.0 + * If you need support for Avro 1.9.0-1.9.2 try plugin version 0.20.0 * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) @@ -55,7 +56,7 @@ repositories { jcenter() } dependencies { - compile "org.apache.avro:avro:1.9.2" + compile "org.apache.avro:avro:1.10.0" } ``` @@ -89,17 +90,17 @@ plugins { There are a number of configuration options supported in the `avro` block. -| option | default | description | -| --------------------------| --------------------- | ------------------------------------------------- | -| createSetters | `true` | `createSetters` passed to Avro compiler | -| createOptionalGetters | `false` | `createOptionalGetters` passed to Avro compiler | -| gettersReturnOptional | `false` | `gettersReturnOptional` passed to Avro compiler -| fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | -| outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | -| stringType | `"String"` | `stringType` passed to Avro compiler | -| templateDirectory | see below | `templateDir` passed to Avro compiler | -| enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | -| dateTimeLogicalType | see below | `dateTimeLogicalType` passed to Avro compiler | +| option | default | description | +| -------------------------------------| --------------------- | ---------------------------------------------------------------| +| createSetters | `true` | `createSetters` passed to Avro compiler | +| createOptionalGetters | `false` | `createOptionalGetters` passed to Avro compiler | +| gettersReturnOptional | `false` | `gettersReturnOptional` passed to Avro compiler | +| optionalGettersForNullableFieldsOnly | `false` | `optionalGettersForNullableFieldsOnly` passed to Avro compiler | +| fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | +| outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | +| stringType | `"String"` | `stringType` passed to Avro compiler | +| templateDirectory | see below | `templateDir` passed to Avro compiler | +| enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | ## createSetters @@ -149,6 +150,24 @@ avro { } ``` +## optionalGettersForNullableFieldsOnly + +Valid values: `false` (default), `true`; supports equivalent `String` values + +Set to `true` in conjuction with `gettersReturnOptional` to `true` to return +[Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) wrappers of the +underlying type. Where [`gettersReturnOptional`](#gettersReturnOptional) alone changes all getters to +return `Optional`, this one only returns Optional for nullable (null union) field definitions. +Setting this to `true` without setting `gettersReturnOptional` to `true` will result in this flag having no effect. + +Example: +```groovy +avro { + gettersReturnOptional = true + optionalGettersForNullableFieldsOnly = true +} +``` + ## fieldVisibility Valid values: any [FieldVisibility](http://avro.apache.org/docs/1.8.1/api/java/org/apache/avro/compiler/specific/SpecificCompiler.FieldVisibility.html) or equivalent `String` name (matched case-insensitively); default `"PUBLIC_DEPRECATED"` (default) @@ -225,21 +244,6 @@ avro { } ``` -## dateTimeLogicalType - -Valid values: `JSR310`, `JODA` - -By default, generated Java files will use the upstream Avro default date/time types. At time of writing this is JSR310. -See `DateTimeLogicalTypeImplementation.DEFAULT` in the upstream code. - -Example: - -```groovy -avro { - dateTimeLogicalType = 'JSR310' -} -``` - # IntelliJ Integration The plugin attempts to make IntelliJ play more smoothly with generated sources when using Gradle-generated project files. @@ -258,7 +262,7 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - implementation "org.apache.avro:avro:1.9.2" + implementation "org.apache.avro:avro:1.10.0" } def generateAvro = tasks.register("generateAvro", com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { @@ -371,12 +375,12 @@ avro { isCreateSetters.set(true) isCreateOptionalGetters.set(false) isGettersReturnOptional.set(false) + isOptionalGettersForNullableFieldsOnly(false) fieldVisibility.set("PUBLIC_DEPRECATED") outputCharacterEncoding.set("UTF-8") stringType.set("String") templateDirectory.set(null as String?) isEnableDecimalLogicalType.set(true) - dateTimeLogicalType.set("JSR310") } ``` diff --git a/build.gradle b/build.gradle index 106b8ef1de3..d2f0a5b5994 100644 --- a/build.gradle +++ b/build.gradle @@ -10,9 +10,12 @@ plugins { repositories { jcenter() + maven { + url 'https://repository.apache.org/content/repositories/staging/' + } } -def compileAvroVersion = "1.9.2" +def compileAvroVersion = "1.10.0" def codenarcVersion = "1.5" def codenarcGroovyVersion = "2.5.10" // Newer version than included in 1.5 required for Java 14 support @@ -205,7 +208,7 @@ tasks.create("testRecentVersionCompatibility") { // Java 8+ is also required by Gradle 5.x sourceCompatibility = 8 -def avroVersions = ["1.9.0", "1.9.1", "1.9.2"] +def avroVersions = ["1.10.0"] def keyAvroVersions = avroVersions.last() def gradle5KotlinVersions =[] if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_10)) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java index e50c4264f8c..b9b9932c61c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java @@ -37,8 +37,8 @@ private static void configureExtension(final Project project) { task.isCreateSetters().convention(avroExtension.isCreateSetters()); task.isCreateOptionalGetters().convention(avroExtension.isCreateOptionalGetters()); task.isGettersReturnOptional().convention(avroExtension.isGettersReturnOptional()); + task.isOptionalGettersForNullableFieldsOnly().convention(avroExtension.isOptionalGettersForNullableFieldsOnly()); task.isEnableDecimalLogicalType().convention(avroExtension.isEnableDecimalLogicalType()); - task.getDateTimeLogicalType().convention(avroExtension.getDateTimeLogicalType()); task.getLogicalTypeFactories().convention(avroExtension.getLogicalTypeFactories()); task.getCustomConversions().convention(avroExtension.getCustomConversions()); }); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java index 81025afa224..543cb568c00 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java @@ -30,8 +30,8 @@ public interface AvroExtension { Property isCreateSetters(); Property isCreateOptionalGetters(); Property isGettersReturnOptional(); + Property isOptionalGettersForNullableFieldsOnly(); Property isEnableDecimalLogicalType(); - Property getDateTimeLogicalType(); MapProperty> getLogicalTypeFactories(); ListProperty>> getCustomConversions(); AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java index 0b10f9b780b..12287665f67 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java @@ -20,7 +20,6 @@ import java.util.Map; import org.apache.avro.Conversion; import org.apache.avro.LogicalTypes; -import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility; import org.apache.avro.generic.GenericData.StringType; import org.gradle.api.reflect.TypeOf; @@ -39,8 +38,8 @@ class Constants { static final boolean DEFAULT_CREATE_SETTERS = true; static final boolean DEFAULT_CREATE_OPTIONAL_GETTERS = false; static final boolean DEFAULT_GETTERS_RETURN_OPTIONAL = false; + static final boolean DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY = false; static final boolean DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE = true; - static final String DEFAULT_DATE_TIME_LOGICAL_TYPE = SpecificCompiler.DateTimeLogicalTypeImplementation.DEFAULT.name(); static final Map> DEFAULT_LOGICAL_TYPE_FACTORIES = Collections.emptyMap(); static final List>> DEFAULT_CUSTOM_CONVERSIONS = Collections.emptyList(); @@ -55,7 +54,6 @@ class Constants { static final String OPTION_FIELD_VISIBILITY = "fieldVisibility"; static final String OPTION_STRING_TYPE = "stringType"; - static final String OPTION_DATE_TIME_LOGICAL_TYPE = "dateTimeLogicalType"; static final TypeOf> LOGICAL_TYPE_FACTORY_TYPE = new TypeOf>() { }; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java index 256fc608849..43f31cc1a32 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java @@ -31,11 +31,11 @@ import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_OPTIONAL_GETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CUSTOM_CONVERSIONS; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_DATE_TIME_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_LOGICAL_TYPE_FACTORIES; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; @SuppressWarnings({"unused", "WeakerAccess"}) @@ -47,8 +47,8 @@ public class DefaultAvroExtension implements AvroExtension { private final Property createSetters; private final Property createOptionalGetters; private final Property gettersReturnOptional; + private final Property optionalGettersForNullableFieldsOnly; private final Property enableDecimalLogicalType; - private final Property dateTimeLogicalType; private final MapProperty> logicalTypeFactories; private final ListProperty>> customConversions; @@ -61,8 +61,9 @@ public DefaultAvroExtension(ObjectFactory objects) { this.createSetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_SETTERS); this.createOptionalGetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_OPTIONAL_GETTERS); this.gettersReturnOptional = objects.property(Boolean.class).convention(DEFAULT_GETTERS_RETURN_OPTIONAL); + this.optionalGettersForNullableFieldsOnly = objects.property(Boolean.class) + .convention(DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY); this.enableDecimalLogicalType = objects.property(Boolean.class).convention(DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); - this.dateTimeLogicalType = objects.property(String.class).convention(DEFAULT_DATE_TIME_LOGICAL_TYPE); this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) .convention(DEFAULT_LOGICAL_TYPE_FACTORIES); this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(DEFAULT_CUSTOM_CONVERSIONS); @@ -156,29 +157,29 @@ public void setGettersReturnOptional(boolean gettersReturnOptional) { } @Override - public Property isEnableDecimalLogicalType() { - return enableDecimalLogicalType; + public Property isOptionalGettersForNullableFieldsOnly() { + return optionalGettersForNullableFieldsOnly; } - public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { - setEnableDecimalLogicalType(Boolean.parseBoolean(enableDecimalLogicalType)); + public void setOptionalGettersForNullableFieldsOnly(String optionalGettersForNullableFieldsOnly) { + setOptionalGettersForNullableFieldsOnly(Boolean.parseBoolean(optionalGettersForNullableFieldsOnly)); } - public void setEnableDecimalLogicalType(boolean enableDecimalLogicalType) { - this.enableDecimalLogicalType.set(enableDecimalLogicalType); + public void setOptionalGettersForNullableFieldsOnly(boolean optionalGettersForNullableFieldsOnly) { + this.optionalGettersForNullableFieldsOnly.set(optionalGettersForNullableFieldsOnly); } @Override - public Property getDateTimeLogicalType() { - return dateTimeLogicalType; + public Property isEnableDecimalLogicalType() { + return enableDecimalLogicalType; } - public void setDateTimeLogicalType(String dateTimeLogicalType) { - this.dateTimeLogicalType.set(dateTimeLogicalType); + public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { + setEnableDecimalLogicalType(Boolean.parseBoolean(enableDecimalLogicalType)); } - public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplementation dateTimeLogicalType) { - setDateTimeLogicalType(dateTimeLogicalType.name()); + public void setEnableDecimalLogicalType(boolean enableDecimalLogicalType) { + this.enableDecimalLogicalType.set(enableDecimalLogicalType); } @Override diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index aa62d9ca803..1247f6a240a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -46,13 +46,12 @@ import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_OPTIONAL_GETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CUSTOM_CONVERSIONS; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_DATE_TIME_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_LOGICAL_TYPE_FACTORIES; +import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY; import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; -import static com.commercehub.gradle.plugin.avro.Constants.OPTION_DATE_TIME_LOGICAL_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.OPTION_FIELD_VISIBILITY; import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; @@ -73,15 +72,14 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Property templateDirectory; private final Property createOptionalGetters; private final Property gettersReturnOptional; + private final Property optionalGettersForNullableFieldsOnly; private final Property createSetters; private final Property enableDecimalLogicalType; - private final Property dateTimeLogicalType; private final MapProperty> logicalTypeFactories; private final ListProperty>> customConversions; private final Provider stringTypeProvider; private final Provider fieldVisibilityProvider; - private final Provider dateTimeLogicalTypeImplementationProvider; private final SchemaResolver resolver; @@ -94,16 +92,14 @@ public GenerateAvroJavaTask(ObjectFactory objects) { this.templateDirectory = objects.property(String.class); this.createOptionalGetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_OPTIONAL_GETTERS); this.gettersReturnOptional = objects.property(Boolean.class).convention(DEFAULT_GETTERS_RETURN_OPTIONAL); + this.optionalGettersForNullableFieldsOnly = objects.property(Boolean.class) + .convention(DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY); this.createSetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_SETTERS); this.enableDecimalLogicalType = objects.property(Boolean.class).convention(DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); - this.dateTimeLogicalType = objects.property(String.class).convention(DEFAULT_DATE_TIME_LOGICAL_TYPE); this.stringTypeProvider = getStringType() .map(input -> Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), input)); this.fieldVisibilityProvider = getFieldVisibility() .map(input -> Enums.parseCaseInsensitive(OPTION_FIELD_VISIBILITY, FieldVisibility.values(), input)); - this.dateTimeLogicalTypeImplementationProvider = getDateTimeLogicalType() - .map(input -> Enums.parseCaseInsensitive(OPTION_DATE_TIME_LOGICAL_TYPE, - SpecificCompiler.DateTimeLogicalTypeImplementation.values(), input)); this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) .convention(DEFAULT_LOGICAL_TYPE_FACTORIES); this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(DEFAULT_CUSTOM_CONVERSIONS); @@ -199,31 +195,30 @@ public void setGettersReturnOptional(String gettersReturnOptional) { this.gettersReturnOptional.set(Boolean.parseBoolean(gettersReturnOptional)); } - public Property isEnableDecimalLogicalType() { - return enableDecimalLogicalType; + public Property isOptionalGettersForNullableFieldsOnly() { + return optionalGettersForNullableFieldsOnly; } @Input - public Property getEnableDecimalLogicalType() { - return enableDecimalLogicalType; + public Property getOptionalGettersForNullableFieldsOnly() { + return optionalGettersForNullableFieldsOnly; } - public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { - this.enableDecimalLogicalType.set(Boolean.parseBoolean(enableDecimalLogicalType)); + public void setOptionalGettersForNullableFieldsOnly(String optionalGettersForNullableFieldsOnly) { + this.optionalGettersForNullableFieldsOnly.set(Boolean.parseBoolean(optionalGettersForNullableFieldsOnly)); } - @Optional - @Input - public Property getDateTimeLogicalType() { - return dateTimeLogicalType; + public Property isEnableDecimalLogicalType() { + return enableDecimalLogicalType; } - public void setDateTimeLogicalType(String dateTimeLogicalType) { - this.dateTimeLogicalType.set(dateTimeLogicalType); + @Input + public Property getEnableDecimalLogicalType() { + return enableDecimalLogicalType; } - public void setDateTimeLogicalType(SpecificCompiler.DateTimeLogicalTypeImplementation dateTimeLogicalType) { - setDateTimeLogicalType(dateTimeLogicalType.name()); + public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { + this.enableDecimalLogicalType.set(Boolean.parseBoolean(enableDecimalLogicalType)); } @Optional @@ -265,8 +260,8 @@ protected void process() { getLogger().debug("Using createSetters {}", isCreateSetters().get()); getLogger().debug("Using createOptionalGetters {}", isCreateOptionalGetters().get()); getLogger().debug("Using gettersReturnOptional {}", isGettersReturnOptional().get()); + getLogger().debug("Using optionalGettersForNullableFieldsOnly {}", isOptionalGettersForNullableFieldsOnly().get()); getLogger().debug("Using enableDecimalLogicalType {}", isEnableDecimalLogicalType().get()); - getLogger().debug("Using dateTimeLogicalType {}", dateTimeLogicalTypeImplementationProvider.get().name()); getLogger().debug("Using logicalTypeFactories {}", logicalTypeFactories.get().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, @@ -330,11 +325,11 @@ private int processSchemaFiles() { } private void compile(Protocol protocol, File sourceFile) throws IOException { - compile(new SpecificCompiler(protocol, dateTimeLogicalTypeImplementationProvider.get()), sourceFile); + compile(new SpecificCompiler(protocol), sourceFile); } private void compile(Schema schema, File sourceFile) throws IOException { - compile(new SpecificCompiler(schema, dateTimeLogicalTypeImplementationProvider.get()), sourceFile); + compile(new SpecificCompiler(schema), sourceFile); } private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { @@ -346,6 +341,7 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept } compiler.setCreateOptionalGetters(createOptionalGetters.get()); compiler.setGettersReturnOptional(gettersReturnOptional.get()); + compiler.setOptionalGettersForNullableFieldsOnly(optionalGettersForNullableFieldsOnly.get()); compiler.setCreateSetters(isCreateSetters().get()); compiler.setEnableDecimalLogicalType(isEnableDecimalLogicalType().get()); registerCustomConversions(compiler); diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index f5cd3f962fd..00dc73efdba 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -55,6 +55,9 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { testProjectDir.newFile("buildSrc/build.gradle") << """ |repositories { | jcenter() + | maven { + | url "https://repository.apache.org/content/repositories/staging/" + | } |} |dependencies { | implementation "org.apache.avro:avro:${avroVersion}" @@ -102,6 +105,9 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { testProjectDir.newFile("buildSrc/build.gradle") << """ |repositories { | jcenter() + | maven { + | url "https://repository.apache.org/content/repositories/staging/" + | } |} |dependencies { | implementation "org.apache.avro:avro:${avroVersion}" @@ -149,6 +155,9 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { testProjectDir.newFile("buildSrc/build.gradle") << """ |repositories { | jcenter() + | maven { + | url "https://repository.apache.org/content/repositories/staging/" + | } |} |dependencies { | implementation "org.apache.avro:avro:${avroVersion}" diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 62bc41dbfc2..63866d6b7e3 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -72,7 +72,7 @@ abstract class FunctionalSpec extends Specification { } protected void addDefaultRepository() { - buildFile << "repositories { jcenter() }\n" + buildFile << "repositories { jcenter()\n maven {\nurl 'https://repository.apache.org/content/repositories/staging/'}\n}\n" } protected void addImplementationDependency(String dependencySpec) { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy index 7de7e2a9dbc..bd62816d56f 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy @@ -15,6 +15,7 @@ class KotlinDSLCompatibilityFunctionalSpec extends FunctionalSpec { |} |repositories { | jcenter() + | maven("https://repository.apache.org/content/repositories/staging/") |} |dependencies { | implementation("org.apache.avro:avro:${avroVersion}") @@ -43,12 +44,12 @@ class KotlinDSLCompatibilityFunctionalSpec extends FunctionalSpec { | isCreateSetters.set(true) | isCreateOptionalGetters.set(false) | isGettersReturnOptional.set(false) + | isOptionalGettersForNullableFieldsOnly.set(false) | fieldVisibility.set("PUBLIC_DEPRECATED") | outputCharacterEncoding.set("UTF-8") | stringType.set("String") | templateDirectory.set(null as String?) | isEnableDecimalLogicalType.set(true) - | dateTimeLogicalType.set("JSR310") |} |""".stripMargin() diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 632db7bc2dd..95ec20e21dd 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -21,15 +21,13 @@ import spock.lang.Unroll import java.nio.ByteBuffer -import static org.apache.avro.compiler.specific.SpecificCompiler.DateTimeLogicalTypeImplementation.* import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS /** - * Functional tests for most functions. Encoding tests have been pulled out into {@link EncodingFunctionalSpec}. + * Functional tests for most functions. Encoding tests have been pulled out into {@link EncodingFunctionalSpec} */ class OptionsFunctionalSpec extends FunctionalSpec { - static actualDateTimeImplementationDefault = DEFAULT == JSR310 ? "java.time.LocalDate" : "org.joda.time.LocalDate" def "works with default options"() { given: @@ -63,9 +61,6 @@ class OptionsFunctionalSpec extends FunctionalSpec { and: "enableDecimalLogicalType is enabled" content.contains("public void setSalary(${BigDecimal.name} value)") - - and: "getDateTimeLogicalType is ?" - content.contains("public void setBirthDate(${actualDateTimeImplementationDefault} value)") } @Unroll @@ -221,6 +216,45 @@ class OptionsFunctionalSpec extends FunctionalSpec { "'false'" | false } + @Unroll + def "supports configuring optionalGettersForNullableFieldsOnly to #optionalGettersForNullableFieldsOnly"() { + given: + copyResource("user.avsc", avroDir) + applyAvroPlugin() + buildFile << """ + |avro { + | gettersReturnOptional = ${gettersReturnOptional} + | optionalGettersForNullableFieldsOnly = ${optionalGettersForNullableFieldsOnly} + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "the task succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + + and: "the specified optionalGettersForNullableFieldsOnly is used" + content.contains("public Optional getFavoriteColor()") == expectedNullableOptionalGetter + content.contains("public Optional getName()") == expectedRequiredOptionalGetter + + where: + gettersReturnOptional | optionalGettersForNullableFieldsOnly | expectedNullableOptionalGetter | expectedRequiredOptionalGetter + "Boolean.TRUE" | "Boolean.TRUE" | true | false + "Boolean.TRUE" | "Boolean.FALSE" | true | true + "Boolean.FALSE" | "Boolean.TRUE" | false | false + "Boolean.FALSE" | "Boolean.FALSE" | false | false + "true" | "true" | true | false + "true" | "false" | true | true + "false" | "true" | false | false + "false" | "false" | false | false + "'true'" | "'true'" | true | false + "'true'" | "'false'" | true | true + "'false'" | "'true'" | false | false + "'false'" | "'false'" | false | false + } + def "supports configuring templateDirectory"() { given: def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") @@ -318,50 +352,4 @@ class OptionsFunctionalSpec extends FunctionalSpec { "'true'" | BigDecimal "'false'" | ByteBuffer } - - @Unroll - def "supports configuration of dateTimeLogicalType to #dateTimeLogicalType"() { - given: - copyResource("user.avsc", avroDir) - applyAvroPlugin() - buildFile << """ - |avro { - | dateTimeLogicalType = "${dateTimeLogicalType}" - |} - |""".stripMargin() - - when: - def result = run("generateAvroJava") - - then: "the task succeeds" - result.task(":generateAvroJava").outcome == SUCCESS - def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text - - and: "the specified dateTimeLogicalType is used" - content.contains("public void setBirthDate(${fieldClz} value)") - - where: - dateTimeLogicalType | fieldClz - JODA.name() | "org.joda.time.LocalDate" - JODA.name().toLowerCase() | "org.joda.time.LocalDate" - JSR310.name() | "java.time.LocalDate" - } - - def "rejects unsupported dateTimeLogicalType values"() { - given: - copyResource("user.avsc", avroDir) - applyAvroPlugin() - buildFile << """ - |avro { - | dateTimeLogicalType = "badValue" - |} - |""".stripMargin() - - when: - def result = runAndFail("generateAvroJava") - - then: - result.task(":generateAvroJava").outcome == FAILED - result.output.contains("Invalid dateTimeLogicalType 'badValue'. Value values are: [JODA, JSR310]") - } } diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm b/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm index 1d6aeac6b8a..2ef2a3017fa 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm @@ -210,7 +210,7 @@ static { } #foreach ($field in $schema.getFields()) -#if (${this.gettersReturnOptional}) +#if (${this.gettersReturnOptional} && (!${this.optionalGettersForNullableFieldsOnly} || ${field.schema().isNullable()})) /** * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. #if ($field.doc()) * $field.doc() From 0fc1ba3d1716781dd56ece7e6cf97721c7af5743 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 28 Jun 2020 11:38:18 -0400 Subject: [PATCH 326/479] Add a test project to aid in reproducing problems --- .gitattributes | 6 + .github/ISSUE_TEMPLATE/bug_report.md | 5 +- test-project/build.gradle | 33 ++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58910 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + test-project/gradlew | 185 ++++++++++++++++++ test-project/gradlew.bat | 104 ++++++++++ test-project/settings.gradle | 12 ++ test-project/src/main/avro/BuggyRecord.avsc | 26 +++ .../src/main/avro/BuggyRecordWorkaround.avsc | 26 +++ test-project/src/main/avro/Messages.avsc | 26 +++ .../test/java/project/CLIComparisonTest.java | 56 ++++++ .../src/test/java/project/CLIUtil.java | 19 ++ .../test/java/project/RandomRecordTest.java | 46 +++++ .../src/test/java/project/RecordTest.java | 50 +++++ .../src/test/java/project/SystemUtil.java | 38 ++++ 16 files changed, 636 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 test-project/build.gradle create mode 100644 test-project/gradle/wrapper/gradle-wrapper.jar create mode 100644 test-project/gradle/wrapper/gradle-wrapper.properties create mode 100755 test-project/gradlew create mode 100644 test-project/gradlew.bat create mode 100644 test-project/settings.gradle create mode 100644 test-project/src/main/avro/BuggyRecord.avsc create mode 100644 test-project/src/main/avro/BuggyRecordWorkaround.avsc create mode 100644 test-project/src/main/avro/Messages.avsc create mode 100644 test-project/src/test/java/project/CLIComparisonTest.java create mode 100644 test-project/src/test/java/project/CLIUtil.java create mode 100644 test-project/src/test/java/project/RandomRecordTest.java create mode 100644 test-project/src/test/java/project/RecordTest.java create mode 100644 test-project/src/test/java/project/SystemUtil.java diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 385d14d4417..655407d8bcc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -14,7 +14,7 @@ assignees: '' * [ ] Are you running a supported version of Apache Avro? (Check the [README](https://github.com/davidmc24/gradle-avro-plugin/blob/master/README.md)) * [ ] Are you running a supported version of Java? (Check the [README](https://github.com/davidmc24/gradle-avro-plugin/blob/master/README.md)) * [ ] Did you check to see if an [issue](https://github.com/davidmc24/gradle-avro-plugin/issues) has already been submitted? -* [ ] Are you reporting to the correct repository? +* [ ] Are you reporting to the correct repository? If your schema doesn't work with the Apache Avro CLI tool either, it's not a problem with this plugin. Running your file through the `CLIComparisonTest` in the sample project under the `test-project` directory can help diagnose this. * [ ] Did you perform a cursory search? For more information, see the [CONTRIBUTING](https://github.com/davidmc24/gradle-avro-plugin/blob/master/CONTRIBUTING.md) guide. @@ -32,6 +32,9 @@ Steps to reproduce the behavior: 3. Ran this task... 4. See error +Please provide complete input files that reproduce the problem, not fragments. +When possible, please express this using `test-project`. + **Expected behavior** A clear and concise description of what you expected to happen. diff --git a/test-project/build.gradle b/test-project/build.gradle new file mode 100644 index 00000000000..a61b541104b --- /dev/null +++ b/test-project/build.gradle @@ -0,0 +1,33 @@ +plugins { + id "application" + id "idea" + id "com.commercehub.gradle.plugin.avro" version "0.20.0" +} + +repositories { + jcenter() +} + +ext { + avroVersion = "1.9.2" +} + +dependencies { + implementation "org.apache.avro:avro:${avroVersion}" + implementation "org.apache.avro:avro-tools:${avroVersion}" + implementation "joda-time:joda-time:2.10.6" + testImplementation "org.junit.jupiter:junit-jupiter:5.6.2" +} + +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } +} + +avro { + stringType = "CharSequence" + fieldVisibility = "private" + dateTimeLogicalType = "JODA" +} diff --git a/test-project/gradle/wrapper/gradle-wrapper.jar b/test-project/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..62d4c053550b91381bbd28b1afc82d634bf73a8a GIT binary patch literal 58910 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 literal 0 HcmV?d00001 diff --git a/test-project/gradle/wrapper/gradle-wrapper.properties b/test-project/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..622ab64a3cb --- /dev/null +++ b/test-project/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/test-project/gradlew b/test-project/gradlew new file mode 100755 index 00000000000..fbd7c515832 --- /dev/null +++ b/test-project/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/test-project/gradlew.bat b/test-project/gradlew.bat new file mode 100644 index 00000000000..5093609d512 --- /dev/null +++ b/test-project/gradlew.bat @@ -0,0 +1,104 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/test-project/settings.gradle b/test-project/settings.gradle new file mode 100644 index 00000000000..ee4b9ef53d0 --- /dev/null +++ b/test-project/settings.gradle @@ -0,0 +1,12 @@ +pluginManagement { + repositories { + gradlePluginPortal() + jcenter() + maven { + name "JCenter Gradle Plugins" + url "https://dl.bintray.com/gradle/gradle-plugins" + } + } +} + +rootProject.name = "test-project" diff --git a/test-project/src/main/avro/BuggyRecord.avsc b/test-project/src/main/avro/BuggyRecord.avsc new file mode 100644 index 00000000000..57f422504aa --- /dev/null +++ b/test-project/src/main/avro/BuggyRecord.avsc @@ -0,0 +1,26 @@ +{ + "namespace":"com.example", + "type":"record", + "name":"BuggyRecord", + "fields":[ + { + "name":"my_mandatory_date", + "type":{ + "type":"long", + "logicalType":"timestamp-millis" + }, + "default":1502250227187 + }, + { + "name":"my_optional_date", + "type":[ + { + "type":"long", + "logicalType":"timestamp-millis" + }, + "null" + ], + "default":1502250227187 + } + ] +} diff --git a/test-project/src/main/avro/BuggyRecordWorkaround.avsc b/test-project/src/main/avro/BuggyRecordWorkaround.avsc new file mode 100644 index 00000000000..e397d55a025 --- /dev/null +++ b/test-project/src/main/avro/BuggyRecordWorkaround.avsc @@ -0,0 +1,26 @@ +{ + "namespace":"com.example", + "type":"record", + "name":"BuggyRecordWorkaround", + "fields":[ + { + "name":"my_mandatory_date", + "type":{ + "type":"long", + "logicalType":"timestamp-millis" + }, + "default":1502250227187 + }, + { + "name":"my_optional_date", + "type":[ + "null", + { + "type":"long", + "logicalType":"timestamp-millis" + } + ], + "default":null + } + ] +} diff --git a/test-project/src/main/avro/Messages.avsc b/test-project/src/main/avro/Messages.avsc new file mode 100644 index 00000000000..1dc457940ff --- /dev/null +++ b/test-project/src/main/avro/Messages.avsc @@ -0,0 +1,26 @@ +{ + "type": "record", + "name": "Messages", + "namespace": "com.somedomain", + "fields": [ + { + "name": "start", + "type": { + "type": "long", + "logicalType": "timestamp-millis" + } + }, + { + "name": "end", + "type": [ + "null", + { + "type": "long", + "logicalType": "timestamp-millis" + } + ], + "default": null + } + ] + } +} diff --git a/test-project/src/test/java/project/CLIComparisonTest.java b/test-project/src/test/java/project/CLIComparisonTest.java new file mode 100644 index 00000000000..c248f26458e --- /dev/null +++ b/test-project/src/test/java/project/CLIComparisonTest.java @@ -0,0 +1,56 @@ +package project; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import static project.CLIUtil.runCLITool; + +public class CLIComparisonTest { + @TempDir + Path cliGeneratedDir; + Path schemaDir = Paths.get("src/main/avro"); + Path pluginGeneratedDir = Paths.get("build/generated-main-avro-java"); + + @SuppressWarnings("unused") + private static Stream compareSpecificCompilerOutput() { + return Stream.of( + // From https://stackoverflow.com/questions/45581437/how-to-specify-converter-for-default-value-in-avro-union-logical-type-fields + Arguments.of("BuggyRecord.avsc", "com/example/BuggyRecord.java", "compile -dateTimeLogicalTypeImpl JODA schema".split(" ")), + // From https://github.com/davidmc24/gradle-avro-plugin/issues/120 + Arguments.of("Messages.avsc", "com/somedomain/Messages.java", "compile -dateTimeLogicalTypeImpl JODA schema".split(" ")) + ); + } + + @ParameterizedTest + @MethodSource + void compareSpecificCompilerOutput(String schemaPath, String generatedPath, String... toolArgs) throws Exception { + Path schemaFile = schemaDir.resolve(schemaPath); + Path pluginGeneratedFile = pluginGeneratedDir.resolve(generatedPath); + Path cliGeneratedFile = cliGeneratedDir.resolve(generatedPath); + + List args = new ArrayList<>(Arrays.asList(toolArgs)); + args.add(schemaFile.toString()); + args.add(cliGeneratedDir.toString()); + runCLITool(args.toArray(new String[0])); + + String pluginGeneratedContent = readFile(pluginGeneratedFile); + String cliGeneratedContent = readFile(cliGeneratedFile); + Assertions.assertEquals(cliGeneratedContent, pluginGeneratedContent); + } + + private static String readFile(Path file) throws Exception { + return new String(Files.readAllBytes(file), StandardCharsets.UTF_8); + } +} diff --git a/test-project/src/test/java/project/CLIUtil.java b/test-project/src/test/java/project/CLIUtil.java new file mode 100644 index 00000000000..326e33d2586 --- /dev/null +++ b/test-project/src/test/java/project/CLIUtil.java @@ -0,0 +1,19 @@ +package project; + +import org.apache.avro.tool.Main; +import org.junit.jupiter.api.Assertions; + +class CLIUtil { + private static final int STATUS_SUCCESS = 0; + + static void runCLITool(String... args) throws Exception { + SystemUtil.forbidSystemExitCall(); + try { + Main.main(args); + } catch (SystemUtil.ExitTrappedException ex) { + Assertions.assertEquals(STATUS_SUCCESS, ex.getStatus(), "CLI tool failed"); + } finally { + SystemUtil.allowSystemExitCall(); + } + } +} diff --git a/test-project/src/test/java/project/RandomRecordTest.java b/test-project/src/test/java/project/RandomRecordTest.java new file mode 100644 index 00000000000..47b4d306393 --- /dev/null +++ b/test-project/src/test/java/project/RandomRecordTest.java @@ -0,0 +1,46 @@ +package project; + +import org.apache.avro.specific.SpecificRecord; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import static project.CLIUtil.runCLITool; + +public class RandomRecordTest { + @TempDir + Path cliGeneratedDir; + Path schemaDir = Paths.get("src/main/avro"); + + @SuppressWarnings("unused") + private static Stream generateRandomRecords() { + return Stream.of( + // From https://stackoverflow.com/questions/45581437/how-to-specify-converter-for-default-value-in-avro-union-logical-type-fields + Arguments.of("BuggyRecord.avsc"), + // From https://github.com/davidmc24/gradle-avro-plugin/issues/120 + Arguments.of("Messages.avsc") + ); + } + + @ParameterizedTest + @MethodSource + void generateRandomRecords(String schemaPath) throws Exception { + Path schemaFile = schemaDir.resolve(schemaPath); + Path outputFile = cliGeneratedDir.resolve("random.avro"); + List args = new ArrayList<>(); + args.add("random"); + args.add("--count"); + args.add("1"); + args.add("--schema-file"); + args.add(schemaFile.toString()); + args.add(outputFile.toString()); + runCLITool(args.toArray(new String[0])); + } +} diff --git a/test-project/src/test/java/project/RecordTest.java b/test-project/src/test/java/project/RecordTest.java new file mode 100644 index 00000000000..58a96886cff --- /dev/null +++ b/test-project/src/test/java/project/RecordTest.java @@ -0,0 +1,50 @@ +package project; + +import com.example.BuggyRecord; +import com.example.BuggyRecordWorkaround; +import com.somedomain.Messages; +import org.apache.avro.Schema; +import org.apache.avro.io.Encoder; +import org.apache.avro.io.EncoderFactory; +import org.apache.avro.specific.SpecificDatumWriter; +import org.apache.avro.specific.SpecificRecord; +import org.joda.time.DateTime; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.util.stream.Stream; + +public class RecordTest { + private static final EncoderFactory encoderFactory = EncoderFactory.get(); + + @SuppressWarnings("unused") + private static Stream buildAndWriteRecord() { + return Stream.of( + // From https://stackoverflow.com/questions/45581437/how-to-specify-converter-for-default-value-in-avro-union-logical-type-fields + // Broken due to an Avro bug + Arguments.of(BuggyRecord.newBuilder().setMyMandatoryDate(DateTime.now()).build()), + // Broken due to an Avro bug + Arguments.of(BuggyRecordWorkaround.newBuilder().setMyMandatoryDate(DateTime.now()).build()), + // From https://github.com/davidmc24/gradle-avro-plugin/issues/120 + // Broken due to an Avro bug + Arguments.of(Messages.newBuilder().setStart(DateTime.now()).build()) + ); + } + + // Broken due to an Avro bug + @Disabled + @ParameterizedTest + @MethodSource + void buildAndWriteRecord(T record) throws Exception { + Schema schema = record.getSchema(); + SpecificDatumWriter writer = new SpecificDatumWriter<>(); + OutputStream outputStream = new ByteArrayOutputStream(); + Encoder jsonEncoder = encoderFactory.jsonEncoder(schema, outputStream, true); + Encoder validatingEncoder = encoderFactory.validatingEncoder(schema, jsonEncoder); + writer.write(record, validatingEncoder); + } +} diff --git a/test-project/src/test/java/project/SystemUtil.java b/test-project/src/test/java/project/SystemUtil.java new file mode 100644 index 00000000000..5a04d2b5c66 --- /dev/null +++ b/test-project/src/test/java/project/SystemUtil.java @@ -0,0 +1,38 @@ +package project; + +import java.security.Permission; + +class SystemUtil { + private static final String PERMISSION_PREFIX = "exitVM."; + + static class ExitTrappedException extends SecurityException { + private final int status; + + ExitTrappedException(int status) { + super("Trapped System.exit(" + status + ")"); + this.status = status; + } + + int getStatus() { + return status; + } + } + + static void forbidSystemExitCall() { + final SecurityManager securityManager = new SecurityManager() { + public void checkPermission(Permission permission) { + String permissionName = permission.getName(); + if (permissionName.startsWith(PERMISSION_PREFIX)) { + String suffix = permissionName.substring(PERMISSION_PREFIX.length()); + int status = Integer.parseInt(suffix); + throw new ExitTrappedException(status); + } + } + }; + System.setSecurityManager(securityManager); + } + + static void allowSystemExitCall() { + System.setSecurityManager(null); + } +} From 84dd60065d18b73ee19aa779e08e1800a29c58af Mon Sep 17 00:00:00 2001 From: mcwhitak Date: Sun, 28 Jun 2020 11:13:21 -0500 Subject: [PATCH 327/479] Test cleanup and CHANGES.md additions for Avro 1.10.0 support --- CHANGES.md | 4 +++ .../plugin/avro/GenerateAvroJavaTask.java | 14 +++----- .../plugin/avro/OptionsFunctionalSpec.groovy | 36 +++---------------- .../commercehub/gradle/plugin/avro/record.vm | 9 ++--- 4 files changed, 17 insertions(+), 46 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 372af70f9fa..4f51166bd83 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,10 @@ # Change Log ## Unreleased +* Built using Avro 1.10.0 +* Drop support for Avro 1.9.X +* Removed support for `dateTimeLogicalType`; The behavior is now as if it were always `JSR-310` due to an upstream change +* Add support for `optionalGettersForNullableFieldsOnly` ## 0.20.0 * Built using Gradle 6.5 diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 1247f6a240a..e60a85c3962 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -302,7 +302,8 @@ private int processProtoFiles() { private void processProtoFile(File sourceFile) { getLogger().info("Processing {}", sourceFile); try { - compile(Protocol.parse(sourceFile), sourceFile); + SpecificCompiler compiler = new SpecificCompiler(Protocol.parse(sourceFile)); + compile(compiler, sourceFile); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); } @@ -315,7 +316,8 @@ private int processSchemaFiles() { String path = getProject().relativePath(file); for (Schema schema : processingState.getSchemasForLocation(path)) { try { - compile(schema, file); + SpecificCompiler compiler = new SpecificCompiler(schema); + compile(compiler, file); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } @@ -324,14 +326,6 @@ private int processSchemaFiles() { return processingState.getProcessedTotal(); } - private void compile(Protocol protocol, File sourceFile) throws IOException { - compile(new SpecificCompiler(protocol), sourceFile); - } - - private void compile(Schema schema, File sourceFile) throws IOException { - compile(new SpecificCompiler(schema), sourceFile); - } - private void compile(SpecificCompiler compiler, File sourceFile) throws IOException { compiler.setOutputCharacterEncoding(getOutputCharacterEncoding().getOrNull()); compiler.setStringType(stringTypeProvider.get()); diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 95ec20e21dd..4837a9f7d20 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -186,38 +186,10 @@ class OptionsFunctionalSpec extends FunctionalSpec { } @Unroll - def "supports configuring gettersReturnOptional to #gettersReturnOptional"() { - given: - copyResource("user.avsc", avroDir) - applyAvroPlugin() - buildFile << """ - |avro { - | gettersReturnOptional = ${gettersReturnOptional} - |} - |""".stripMargin() - - when: - def result = run("generateAvroJava") - - then: "the task succeeds" - result.task(":generateAvroJava").outcome == SUCCESS - def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text - - and: "the specified createOptionalGetters is used" - content.contains("public Optional getFavoriteColor()") == expectedPresent - - where: - gettersReturnOptional | expectedPresent - "Boolean.TRUE" | true - "Boolean.FALSE" | false - "true" | true - "false" | false - "'true'" | true - "'false'" | false - } - - @Unroll - def "supports configuring optionalGettersForNullableFieldsOnly to #optionalGettersForNullableFieldsOnly"() { + def """ + supports configuring gettersReturnOptional to #gettersReturnOptional in conjunction with + setting optionalGettersForNullableFieldsOnly to #optionalGettersForNullableFieldsOnly + """() { given: copyResource("user.avsc", avroDir) applyAvroPlugin() diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm b/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm index 2ef2a3017fa..286aa9dbab4 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm @@ -7,7 +7,7 @@ ## "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 +## https://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, software ## distributed under the License is distributed on an "AS IS" BASIS, @@ -202,7 +202,7 @@ static { switch (field$) { #set ($i = 0) #foreach ($field in $schema.getFields()) - case $i: ${this.mangle($field.name(), $schema.isError())} = #if(${this.javaType($field.schema())} != "java.lang.Object")(${this.javaType($field.schema())})#{end}value$; break; + case $i: ${this.mangle($field.name(), $schema.isError())} = #if(${this.javaType($field.schema())} != "java.lang.Object" && ${this.javaType($field.schema())} != "java.lang.String")(${this.javaType($field.schema())})#{end}value$#if(${this.javaType($field.schema())} == "java.lang.String") != null ? value$.toString() : null#{end}; break; #set ($i = $i + 1) #end default: throw new org.apache.avro.AvroRuntimeException("Bad index"); @@ -294,6 +294,7 @@ static { /** * RecordBuilder for ${this.mangle($schema.getName())} instances. */ + @org.apache.avro.specific.AvroGenerated public static class Builder extends#if ($schema.isError()) org.apache.avro.specific.SpecificErrorBuilderBase<${this.mangle($schema.getName())}>#else org.apache.avro.specific.SpecificRecordBuilderBase<${this.mangle($schema.getName())}>#end implements#if ($schema.isError()) org.apache.avro.data.ErrorBuilder<${this.mangle($schema.getName())}>#else org.apache.avro.data.RecordBuilder<${this.mangle($schema.getName())}>#end { @@ -537,7 +538,7 @@ static { #if ($this.isCustomCodable($schema)) @Override protected boolean hasCustomCoders() { return true; } - @Override protected void customEncode(org.apache.avro.io.Encoder out) + @Override public void customEncode(org.apache.avro.io.Encoder out) throws java.io.IOException { #set ($nv = 0)## Counter to ensure unique var-names @@ -551,7 +552,7 @@ static { #end } - @Override protected void customDecode(org.apache.avro.io.ResolvingDecoder in) + @Override public void customDecode(org.apache.avro.io.ResolvingDecoder in) throws java.io.IOException { org.apache.avro.Schema.Field[] fieldOrder = in.readFieldOrderIfDiff(); From aa47f0bd16ccbdb66aaa2e88b42dd7ab358f03a4 Mon Sep 17 00:00:00 2001 From: mcwhitak Date: Sun, 28 Jun 2020 11:25:08 -0500 Subject: [PATCH 328/479] Fix test name for optionalGettersForNullableFieldsOnly --- .../gradle/plugin/avro/OptionsFunctionalSpec.groovy | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 4837a9f7d20..351d2751c53 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -186,10 +186,8 @@ class OptionsFunctionalSpec extends FunctionalSpec { } @Unroll - def """ - supports configuring gettersReturnOptional to #gettersReturnOptional in conjunction with - setting optionalGettersForNullableFieldsOnly to #optionalGettersForNullableFieldsOnly - """() { + def "supports configuring gettersReturnOptional to #gettersReturnOptional in conjunction with \ +setting optionalGettersForNullableFieldsOnly to #optionalGettersForNullableFieldsOnly"() { given: copyResource("user.avsc", avroDir) applyAvroPlugin() From 4c490257bc388dac56e918cc6f38a00e440b06e7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 28 Jun 2020 13:17:06 -0400 Subject: [PATCH 329/479] Confirm that the nullable getter is still generated when createOptionalGetters is enabled --- .../gradle/plugin/avro/OptionsFunctionalSpec.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 632db7bc2dd..11ae6dd3342 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -177,6 +177,9 @@ class OptionsFunctionalSpec extends FunctionalSpec { result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + and: "the nullable getter is generated" + content.contains("public java.lang.String getFavoriteColor()") + and: "the specified createOptionalGetters is used" content.contains("public Optional getOptionalFavoriteColor()") == expectedPresent From f02b712e86124a151ac70aaa7508e50f40074a09 Mon Sep 17 00:00:00 2001 From: mcwhitak Date: Sun, 28 Jun 2020 14:06:10 -0500 Subject: [PATCH 330/479] Formatting fixes and test simplification --- .../gradle/plugin/avro/GenerateAvroJavaTask.java | 6 ++---- .../gradle/plugin/avro/OptionsFunctionalSpec.groovy | 9 +++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index e60a85c3962..9e6d730d76c 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -302,8 +302,7 @@ private int processProtoFiles() { private void processProtoFile(File sourceFile) { getLogger().info("Processing {}", sourceFile); try { - SpecificCompiler compiler = new SpecificCompiler(Protocol.parse(sourceFile)); - compile(compiler, sourceFile); + compile(new SpecificCompiler(Protocol.parse(sourceFile)), sourceFile); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile protocol definition file %s", sourceFile), ex); } @@ -316,8 +315,7 @@ private int processSchemaFiles() { String path = getProject().relativePath(file); for (Schema schema : processingState.getSchemasForLocation(path)) { try { - SpecificCompiler compiler = new SpecificCompiler(schema); - compile(compiler, file); + compile(new SpecificCompiler(schema), file); } catch (IOException ex) { throw new GradleException(String.format("Failed to compile schema definition file %s", path), ex); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 351d2751c53..94111c3147c 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -185,9 +185,9 @@ class OptionsFunctionalSpec extends FunctionalSpec { "'false'" | false } + @SuppressWarnings("LineLength") @Unroll - def "supports configuring gettersReturnOptional to #gettersReturnOptional in conjunction with \ -setting optionalGettersForNullableFieldsOnly to #optionalGettersForNullableFieldsOnly"() { + def "supports configuring gettersReturnOptional to #gettersReturnOptional in conjunction with setting optionalGettersForNullableFieldsOnly to #optionalGettersForNullableFieldsOnly"() { given: copyResource("user.avsc", avroDir) applyAvroPlugin() @@ -206,8 +206,9 @@ setting optionalGettersForNullableFieldsOnly to #optionalGettersForNullableField def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified optionalGettersForNullableFieldsOnly is used" - content.contains("public Optional getFavoriteColor()") == expectedNullableOptionalGetter - content.contains("public Optional getName()") == expectedRequiredOptionalGetter + expectedNullableOptionalGetter ? content.contains("public Optional getFavoriteColor()") : content.contains("public java.lang.String getFavoriteColor()") + expectedRequiredOptionalGetter ? content.contains("public Optional getName()") : content.contains("public java.lang.String getName()") + where: gettersReturnOptional | optionalGettersForNullableFieldsOnly | expectedNullableOptionalGetter | expectedRequiredOptionalGetter From 27d921da8e6b7b8493dc7c3318d76575c5cb1cc7 Mon Sep 17 00:00:00 2001 From: mcwhitak Date: Sun, 28 Jun 2020 14:16:09 -0500 Subject: [PATCH 331/479] Fix optionalGettersForNullableFieldsOnly test naming and CHANGES formatting --- CHANGES.md | 2 +- .../gradle/plugin/avro/OptionsFunctionalSpec.groovy | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 81eadc85af4..44a48bef32f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,7 +3,7 @@ ## Unreleased * Built using Avro 1.10.0 * Drop support for Avro 1.9.X -* Removed support for `dateTimeLogicalType`; The behavior is now as if it were always `JSR-310` due to an upstream change +* Removed support for `dateTimeLogicalType`; The behavior is now as if it were always `JSR-310` due to an upstream change * Add support for `optionalGettersForNullableFieldsOnly` * Apply @Classpath annotation to classpath on `GenerateAvroProtocolTask` diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 94111c3147c..69080704d78 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -187,7 +187,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { @SuppressWarnings("LineLength") @Unroll - def "supports configuring gettersReturnOptional to #gettersReturnOptional in conjunction with setting optionalGettersForNullableFieldsOnly to #optionalGettersForNullableFieldsOnly"() { + def "supports configuring gettersReturnOptional/optionalGettersForNullableFieldsOnly to #gettersReturnOptional/#optionalGettersForNullableFieldsOnly"() { given: copyResource("user.avsc", avroDir) applyAvroPlugin() @@ -206,9 +206,8 @@ class OptionsFunctionalSpec extends FunctionalSpec { def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text and: "the specified optionalGettersForNullableFieldsOnly is used" - expectedNullableOptionalGetter ? content.contains("public Optional getFavoriteColor()") : content.contains("public java.lang.String getFavoriteColor()") - expectedRequiredOptionalGetter ? content.contains("public Optional getName()") : content.contains("public java.lang.String getName()") - + content.contains("public java.lang.String getFavoriteColor()") + content.contains("public java.lang.String getName()") where: gettersReturnOptional | optionalGettersForNullableFieldsOnly | expectedNullableOptionalGetter | expectedRequiredOptionalGetter From 2235eddb069bd425a5a19f28c0cee0e5ab764fe3 Mon Sep 17 00:00:00 2001 From: mcwhitak Date: Mon, 29 Jun 2020 08:21:47 -0500 Subject: [PATCH 332/479] Ensure option conditions are checked against relevant file portions --- .../plugin/avro/OptionsFunctionalSpec.groovy | 39 +++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 69080704d78..f3298d84a83 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -80,9 +80,10 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + def mainClassContent = getMainClassContent(content) and: "the specified stringType is used" - content.contains(expectedContent) + mainClassContent.contains(expectedContent) where: stringType | expectedContent @@ -111,9 +112,10 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + def mainClassContent = getMainClassContent(content) and: "the specified fieldVisibility is used" - content.contains(expectedContent) + mainClassContent.contains(expectedContent) where: fieldVisibility | expectedContent @@ -140,9 +142,10 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + def mainClassContent = getMainClassContent(content) and: "the specified createSetters is used" - content.contains("public void setName(java.lang.String value)") == expectedPresent + mainClassContent.contains("public void setName(java.lang.String value)") == expectedPresent where: createSetters | expectedPresent @@ -171,9 +174,11 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + def mainClassContent = getMainClassContent(content) and: "the specified createOptionalGetters is used" - content.contains("public Optional getOptionalFavoriteColor()") == expectedPresent + mainClassContent.contains("public Optional getOptionalFavoriteColor()") == expectedPresent + mainClassContent.contains("public java.lang.String getFavoriteColor()") where: createOptionalGetters | expectedPresent @@ -204,10 +209,14 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + def mainClassContent = getMainClassContent(content) and: "the specified optionalGettersForNullableFieldsOnly is used" - content.contains("public java.lang.String getFavoriteColor()") - content.contains("public java.lang.String getName()") + mainClassContent.contains("public Optional getFavoriteColor()") == expectedNullableOptionalGetter + mainClassContent.contains("public java.lang.String getFavoriteColor()") != expectedNullableOptionalGetter + mainClassContent.contains("public Optional getName()") == expectedRequiredOptionalGetter + mainClassContent.contains("public java.lang.String getName()") != expectedRequiredOptionalGetter + where: gettersReturnOptional | optionalGettersForNullableFieldsOnly | expectedNullableOptionalGetter | expectedRequiredOptionalGetter @@ -309,9 +318,10 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: "the task succeeds" result.task(":generateAvroJava").outcome == SUCCESS def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + def mainClassContent = getMainClassContent(content) and: "the specified enableDecimalLogicalType is used" - content.contains("public void setSalary(${fieldClz.name} value)") + mainClassContent.contains("public void setSalary(${fieldClz.name} value)") where: enableDecimalLogicalType | fieldClz @@ -322,4 +332,19 @@ class OptionsFunctionalSpec extends FunctionalSpec { "'true'" | BigDecimal "'false'" | ByteBuffer } + + /** + * Returns just the portion of a file that relates to the main class. + * This is used in order to allow assertions on the getters/setters/fields of the generated class itself, as opposed to a Builder. + * + * @param content the file content for which to get the main content + * @return the content of the class, from the start of the class body to the first inner class definition + */ + @SuppressWarnings("LineLength") + private static String getMainClassContent(String content) { + def className = "User" + def matcher = content =~ /(?s)public class ${className} extends org\.apache\.avro\.specific\.\SpecificRecordBase implements org\.apache\.avro\.specific\.SpecificRecord \{(?.*)public static class Builder/ + assert matcher.find() + return matcher.group("mainClassContent") + } } From 1c33e4f8ac7d047515543e65c124f299ab7d1d75 Mon Sep 17 00:00:00 2001 From: mcwhitak Date: Tue, 30 Jun 2020 07:40:40 -0500 Subject: [PATCH 333/479] Remove apache staging dependency and pull release from JCenter --- build.gradle | 3 --- .../plugin/avro/CustomConversionFunctionalSpec.groovy | 9 --------- .../commercehub/gradle/plugin/avro/FunctionalSpec.groovy | 2 +- .../avro/KotlinDSLCompatibilityFunctionalSpec.groovy | 1 - 4 files changed, 1 insertion(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index cafafcc2d4d..28f1e9c274f 100644 --- a/build.gradle +++ b/build.gradle @@ -12,9 +12,6 @@ plugins { repositories { jcenter() - maven { - url 'https://repository.apache.org/content/repositories/staging/' - } } def compileAvroVersion = "1.10.0" diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index 00dc73efdba..f5cd3f962fd 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -55,9 +55,6 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { testProjectDir.newFile("buildSrc/build.gradle") << """ |repositories { | jcenter() - | maven { - | url "https://repository.apache.org/content/repositories/staging/" - | } |} |dependencies { | implementation "org.apache.avro:avro:${avroVersion}" @@ -105,9 +102,6 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { testProjectDir.newFile("buildSrc/build.gradle") << """ |repositories { | jcenter() - | maven { - | url "https://repository.apache.org/content/repositories/staging/" - | } |} |dependencies { | implementation "org.apache.avro:avro:${avroVersion}" @@ -155,9 +149,6 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { testProjectDir.newFile("buildSrc/build.gradle") << """ |repositories { | jcenter() - | maven { - | url "https://repository.apache.org/content/repositories/staging/" - | } |} |dependencies { | implementation "org.apache.avro:avro:${avroVersion}" diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 63866d6b7e3..a17f023c056 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -72,7 +72,7 @@ abstract class FunctionalSpec extends Specification { } protected void addDefaultRepository() { - buildFile << "repositories { jcenter()\n maven {\nurl 'https://repository.apache.org/content/repositories/staging/'}\n}\n" + buildFile << "repositories { jcenter()\n}\n" } protected void addImplementationDependency(String dependencySpec) { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy index bd62816d56f..d17f336027e 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy @@ -15,7 +15,6 @@ class KotlinDSLCompatibilityFunctionalSpec extends FunctionalSpec { |} |repositories { | jcenter() - | maven("https://repository.apache.org/content/repositories/staging/") |} |dependencies { | implementation("org.apache.avro:avro:${avroVersion}") From 461b565a6d27a2a0fd9413c86979f67762b156ed Mon Sep 17 00:00:00 2001 From: mcwhitak Date: Tue, 30 Jun 2020 07:50:23 -0500 Subject: [PATCH 334/479] Ensure createOptionalGetters test checks correct mainClassContent --- .../gradle/plugin/avro/OptionsFunctionalSpec.groovy | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 8a9ac2ba3a8..087eb0deea1 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -177,11 +177,10 @@ class OptionsFunctionalSpec extends FunctionalSpec { def mainClassContent = getMainClassContent(content) and: "the nullable getter is generated" - content.contains("public java.lang.String getFavoriteColor()") - + mainClassContent.contains("public java.lang.String getFavoriteColor()") + and: "the specified createOptionalGetters is used" mainClassContent.contains("public Optional getOptionalFavoriteColor()") == expectedPresent - mainClassContent.contains("public java.lang.String getFavoriteColor()") where: createOptionalGetters | expectedPresent From f3d8b11c0e1c5bda409ff65907857f823847e335 Mon Sep 17 00:00:00 2001 From: mcwhitak Date: Tue, 30 Jun 2020 10:37:33 -0500 Subject: [PATCH 335/479] Remove extraneous newline from test repository definition --- .../com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index a17f023c056..62bc41dbfc2 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -72,7 +72,7 @@ abstract class FunctionalSpec extends Specification { } protected void addDefaultRepository() { - buildFile << "repositories { jcenter()\n}\n" + buildFile << "repositories { jcenter() }\n" } protected void addImplementationDependency(String dependencySpec) { From 8fd8f5f2effed4eef0585303ab69730f32a4f75d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 30 Jun 2020 22:27:54 -0400 Subject: [PATCH 336/479] version: 0.21.0 --- CHANGES.md | 2 ++ README.md | 2 +- build.gradle | 2 +- test-project/build.gradle | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 44a48bef32f..18782c06870 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.21.0 * Built using Avro 1.10.0 * Drop support for Avro 1.9.X * Removed support for `dateTimeLogicalType`; The behavior is now as if it were always `JSR-310` due to an upstream change diff --git a/README.md b/README.md index 0a28ca37027..edf158e3a79 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 14 support requires Gradle 6.3 or higher * Java 13 support requires Gradle 6.0 or higher * Java 11 support requires Gradle 4.8 or higher - * Though not supported yet, tests are also run against early-access builds of Java 14 and Java 15 to provide early notification of potential incompatibilities + * Though not supported yet, tests are also run against early-access builds of Java 15 to provide early notification of potential incompatibilities * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Gradle 6.5 diff --git a/build.gradle b/build.gradle index 28f1e9c274f..61a2b5a7202 100644 --- a/build.gradle +++ b/build.gradle @@ -63,7 +63,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.20.1-SNAPSHOT" +version = "0.21.0" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { diff --git a/test-project/build.gradle b/test-project/build.gradle index a61b541104b..13e9410111a 100644 --- a/test-project/build.gradle +++ b/test-project/build.gradle @@ -1,7 +1,7 @@ plugins { id "application" id "idea" - id "com.commercehub.gradle.plugin.avro" version "0.20.0" + id "com.commercehub.gradle.plugin.avro" version "0.21.0" } repositories { @@ -9,7 +9,7 @@ repositories { } ext { - avroVersion = "1.9.2" + avroVersion = "1.10.0" } dependencies { From 25eab8b42e1d05a54a9dd862ce2550d0ad313ee8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 30 Jun 2020 22:30:59 -0400 Subject: [PATCH 337/479] version: 0.21.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 61a2b5a7202..1277a2f7041 100644 --- a/build.gradle +++ b/build.gradle @@ -63,7 +63,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.21.0" +version = "0.21.1-SNAPSHOT" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From 3fd998827e77fd9dce54c684b7b76f0b2db0436d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 6 Aug 2020 09:16:15 -0400 Subject: [PATCH 338/479] build: add coverage reporting using JaCoCo and Codecov --- .github/workflows/ci.yml | 5 +++++ CHANGES.md | 1 + build.gradle | 10 +++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a994b654b8..5b59f23f11c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,11 @@ jobs: uses: eskatos/gradle-command-action@v1 with: arguments: --stop + - name: Upload coverage report to Codecov + uses: codecov/codecov-action@v1 + with: + file: ./build/reports/jacoco/test/jacocoTestReport.xml + fail_ci_if_error: true # Run further compatibility tests to ensure that key versions of Gradle/Avro # work on a variety of OS/Java version combinations recent-compatibility-tests: diff --git a/CHANGES.md b/CHANGES.md index 18782c06870..a82c95a3207 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Add coverage reporting via JaCoco/Codecov to the plugin's build pipeline ## 0.21.0 * Built using Avro 1.10.0 diff --git a/build.gradle b/build.gradle index 1277a2f7041..ebe730897c6 100644 --- a/build.gradle +++ b/build.gradle @@ -3,10 +3,10 @@ plugins { id "checkstyle" id "codenarc" id "idea" + id "jacoco" id "maven-publish" id "java-gradle-plugin" id "com.jfrog.bintray" version "1.8.1" - // TODO: try to get this working id "org.nosphere.gradle.github.actions" version "1.2.0" } @@ -262,6 +262,14 @@ test { gradleVersion: gradle.gradleVersion, kotlinVersion: latestKotlinVersion, ] + finalizedBy jacocoTestReport // report is always generated after tests run +} + +jacocoTestReport { + reports { + html.enabled true + xml.enabled true + } } avroVersions.each { def avroVersion -> From 4ed611b9db1ea5137b35a0a6d856c04e97a9a3c0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 6 Aug 2020 09:40:24 -0400 Subject: [PATCH 339/479] CI: flag codecov report by OS --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b59f23f11c..3790769f687 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,7 @@ jobs: uses: codecov/codecov-action@v1 with: file: ./build/reports/jacoco/test/jacocoTestReport.xml + flags: baseline,${{ matrix.os }} fail_ci_if_error: true # Run further compatibility tests to ensure that key versions of Gradle/Avro # work on a variety of OS/Java version combinations From bb8c50055e249f9e18e90788bc7de10c569f9f31 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 6 Aug 2020 13:20:01 -0400 Subject: [PATCH 340/479] Add support for multiple IDL files with the same name in different directories (#123) --- CHANGES.md | 2 + .../gradle/plugin/avro/AvroUtils.java | 56 +++++++++++++++++++ .../plugin/avro/GenerateAvroProtocolTask.java | 8 +-- .../plugin/avro/GenerateAvroSchemaTask.java | 5 +- .../avro/ResolveAvroDependenciesTask.java | 5 +- .../BuildCacheSupportFunctionalSpec.groovy | 2 +- ...erateAvroProtocolTaskFunctionalSpec.groovy | 22 +++++++- .../plugin/avro/namespaced-idl/v1/test.avdl | 6 ++ .../plugin/avro/namespaced-idl/v2/test.avdl | 7 +++ 9 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v1/test.avdl create mode 100644 src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v2/test.avdl diff --git a/CHANGES.md b/CHANGES.md index a82c95a3207..155e789be64 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased * Add coverage reporting via JaCoco/Codecov to the plugin's build pipeline +* Add support for multiple IDL files with the same name in different directories (#123) + * The `.avpr` file generated by `GenerateAvroProtocolTask` is now based on the namespace and name of the protocol, rather than the name of the `.avdl` file. ## 0.21.0 * Built using Avro 1.10.0 diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java new file mode 100644 index 00000000000..b31d16094df --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java @@ -0,0 +1,56 @@ +package com.commercehub.gradle.plugin.avro; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import org.apache.avro.Protocol; +import org.apache.avro.Schema; + +import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; +import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; + +class AvroUtils { + /** + * The namespace separator. + */ + private static final String NAMESPACE_SEPARATOR = "."; + + /** + * The extension separator. + */ + private static final String EXTENSION_SEPARATOR = "."; + + /** + * The Unix separator. + */ + private static final String UNIX_SEPARATOR = "/"; + + /** + * Assembles a file path based on the namespace and name of the provided {@link Schema}. + * + * @param schema the schema for which to assemble a path + * @return a file path + */ + static String assemblePath(Schema schema) { + return assemblePath(schema.getNamespace(), schema.getName(), SCHEMA_EXTENSION); + } + + /** + * Assembles a file path based on the namespace and name of the provided {@link Protocol}. + * + * @param protocol the protocol for which to assemble a path + * @return a file path + */ + static String assemblePath(Protocol protocol) { + return assemblePath(protocol.getNamespace(), protocol.getName(), PROTOCOL_EXTENSION); + } + + private static String assemblePath(String namespace, String name, String extension) { + List parts = new ArrayList<>(); + if (namespace != null && !namespace.isEmpty()) { + parts.add(namespace.replaceAll(Pattern.quote(NAMESPACE_SEPARATOR), UNIX_SEPARATOR)); + } + parts.add(name + EXTENSION_SEPARATOR + extension); + return String.join(UNIX_SEPARATOR, parts); + } +} diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java index e7682283996..f08a0625938 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -22,6 +22,7 @@ import java.net.URLClassLoader; import java.util.LinkedList; import java.util.List; +import org.apache.avro.Protocol; import org.apache.avro.compiler.idl.Idl; import org.apache.avro.compiler.idl.ParseException; import org.gradle.api.GradleException; @@ -32,7 +33,6 @@ import org.gradle.api.tasks.TaskAction; import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; /** * Task to convert Avro IDL files into Avro protocol files using {@link Idl}. @@ -87,10 +87,10 @@ private void processFiles() { private void processIDLFile(File idlFile, ClassLoader loader) { getLogger().info("Processing {}", idlFile); - File protoFile = new File(getOutputDir().get().getAsFile(), - FilenameUtils.getBaseName(idlFile.getName()) + "." + PROTOCOL_EXTENSION); try (Idl idl = new Idl(idlFile, loader)) { - String protoJson = idl.CompilationUnit().toString(true); + Protocol protocol = idl.CompilationUnit(); + File protoFile = new File(getOutputDir().get().getAsFile(), AvroUtils.assemblePath(protocol)); + String protoJson = protocol.toString(true); FileUtils.writeJsonFile(protoFile, protoJson); getLogger().debug("Wrote {}", protoFile.getPath()); } catch (IOException | ParseException ex) { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java index 931f1dbcaef..a5267ed55b9 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java @@ -17,7 +17,6 @@ import java.io.File; import java.io.IOException; -import java.util.regex.Pattern; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.gradle.api.GradleException; @@ -27,7 +26,6 @@ import org.gradle.api.tasks.TaskAction; import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; @CacheableTask public class GenerateAvroSchemaTask extends OutputDirTask { @@ -60,8 +58,7 @@ private void processProtoFile(File sourceFile) { try { Protocol protocol = Protocol.parse(sourceFile); for (Schema schema : protocol.getTypes()) { - String path = schema.getNamespace().replaceAll(Pattern.quote("."), "/"); - File schemaFile = new File(getOutputDir().get().getAsFile(), path + "/" + schema.getName() + "." + SCHEMA_EXTENSION); + File schemaFile = new File(getOutputDir().get().getAsFile(), AvroUtils.assemblePath(schema)); String schemaJson = schema.toString(true); FileUtils.writeJsonFile(schemaFile, schemaJson); getLogger().debug("Wrote {}", schemaFile.getPath()); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java index 43be00c8dd2..2af02741305 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java @@ -3,7 +3,6 @@ import java.io.File; import java.io.IOException; import java.util.Set; -import java.util.regex.Pattern; import org.apache.avro.Schema; import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; @@ -45,9 +44,7 @@ private int processSchemaFiles() { ProcessingState processingState = resolver.resolve(inputFiles); for (Schema schema : processingState.getSchemas()) { try { - String outputPath = schema.getNamespace().replaceAll(Pattern.quote("."), "/") - + "/" + schema.getName() + "." + SCHEMA_EXTENSION; - File outputFile = new File(getOutputDir().get().getAsFile(), outputPath); + File outputFile = new File(getOutputDir().get().getAsFile(), AvroUtils.assemblePath(schema)); String schemaJson = schema.toString(true); FileUtils.writeJsonFile(outputFile, schemaJson); getLogger().debug("Wrote {}", outputFile.getPath()); diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy index c97a3e4eb48..9bc3a269c1a 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy @@ -71,7 +71,7 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { result.task(":generateAvroProtocol").outcome == FROM_CACHE result.task(":generateAvroJava").outcome == FROM_CACHE result.task(":compileJava").outcome == FROM_CACHE - projectFile("build/generated-main-avro-avpr/interop.avpr").file + projectFile("build/generated-main-avro-avpr/org/apache/avro/InteropProtocol.avpr").file projectFile("build/generated-main-avro-java/org/apache/avro/Interop.java").file projectFile(buildOutputClassPath("org/apache/avro/Interop.class")).file } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy index 81c4b0781fe..52a133ae9e4 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy @@ -39,7 +39,7 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { | outputDir = file("build/protocol") |} |""".stripMargin() - + copyResource("shared.avdl", testProjectDir.newFolder("src", "shared")) copyResource("dependent.avdl", testProjectDir.newFolder("src", "dependent")) @@ -49,7 +49,7 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { then: "running the generate protocol task occurs after running the producing task" result.tasks*.path == [":sharedIdlJar", ":generateProtocol"] result.task(":generateProtocol").outcome == SUCCESS - projectFile("build/protocol/dependent.avpr").file + projectFile("build/protocol/com/example/dependent/DependentProtocol.avpr").file } def "With avro plugin, declares input on classpath (runtime configuration by default)"() { @@ -73,6 +73,22 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { then: "running the generate protocol task occurs after running the producing task" result.tasks*.path == [":sharedIdlJar", ":generateAvroProtocol"] result.task(":generateAvroProtocol").outcome == SUCCESS - projectFile("build/generated-main-avro-avpr/dependent.avpr").file + projectFile("build/generated-main-avro-avpr/com/example/dependent/DependentProtocol.avpr").file + } + + def "supports files with the same name in different directories"() { + given: "a project with two IDL files with the same name, but in different directories" + applyAvroPlugin() + + copyResource("namespaced-idl/v1/test.avdl", testProjectDir.newFolder("src", "main", "avro", "v1")) + copyResource("namespaced-idl/v2/test.avdl", testProjectDir.newFolder("src", "main", "avro", "v2")) + + when: "running the task" + def result = run("generateAvroProtocol") + + then: "avpr files are generated for each IDL file" + result.task(":generateAvroProtocol").outcome == SUCCESS + projectFile("build/generated-main-avro-avpr/org/example/v1/TestProtocol.avpr").file + projectFile("build/generated-main-avro-avpr/org/example/v1/TestProtocol.avpr").file } } diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v1/test.avdl b/src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v1/test.avdl new file mode 100644 index 00000000000..242cb42184a --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v1/test.avdl @@ -0,0 +1,6 @@ +@namespace("org.example.v1") +protocol TestProtocol { + record TestRecord { + string field1; + } +} diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v2/test.avdl b/src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v2/test.avdl new file mode 100644 index 00000000000..e6ec904bc2c --- /dev/null +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v2/test.avdl @@ -0,0 +1,7 @@ +@namespace("org.example.v2") +protocol TestProtocol { + record TestRecord { + string field1; + string field2; + } +} From ec6b119fb914a070195164cf41f5b3ef610d85b8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 6 Aug 2020 15:10:26 -0400 Subject: [PATCH 341/479] Update AvroUtils and Strings, with unit test coverage --- .../gradle/plugin/avro/AvroUtils.java | 19 ++++- .../gradle/plugin/avro/Strings.java | 48 +++++++++++++ .../gradle/plugin/avro/AvroUtilsSpec.groovy | 70 +++++++++++++++++++ .../gradle/plugin/avro/StringsSpec.groovy | 57 +++++++++++++++ 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/commercehub/gradle/plugin/avro/Strings.java create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy create mode 100644 src/test/groovy/com/commercehub/gradle/plugin/avro/StringsSpec.groovy diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java index b31d16094df..28431e8954b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java @@ -9,6 +9,9 @@ import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; +/** + * Utility method for working with Avro objects. + */ class AvroUtils { /** * The namespace separator. @@ -25,6 +28,11 @@ class AvroUtils { */ private static final String UNIX_SEPARATOR = "/"; + /** + * Not intended for instantiation. + */ + private AvroUtils() { } + /** * Assembles a file path based on the namespace and name of the provided {@link Schema}. * @@ -45,9 +53,18 @@ static String assemblePath(Protocol protocol) { return assemblePath(protocol.getNamespace(), protocol.getName(), PROTOCOL_EXTENSION); } + /** + * Assembles a file path based on the provided arguments. + * + * @param namespace the namespace for the path; may be null + * @param name the name for the path; will result in an exception if null or empty + * @param extension the extension for the path + * @return the assembled path + */ private static String assemblePath(String namespace, String name, String extension) { + Strings.requireNotEmpty(name, "Path cannot be assembled for nameless objects"); List parts = new ArrayList<>(); - if (namespace != null && !namespace.isEmpty()) { + if (Strings.isNotEmpty(namespace)) { parts.add(namespace.replaceAll(Pattern.quote(NAMESPACE_SEPARATOR), UNIX_SEPARATOR)); } parts.add(name + EXTENSION_SEPARATOR + extension); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Strings.java b/src/main/java/com/commercehub/gradle/plugin/avro/Strings.java new file mode 100644 index 00000000000..241eb9d5b77 --- /dev/null +++ b/src/main/java/com/commercehub/gradle/plugin/avro/Strings.java @@ -0,0 +1,48 @@ +package com.commercehub.gradle.plugin.avro; + +/** + * Utility methods for working with {@link String}s. + */ +class Strings { + /** + * Not intended for instantiation. + */ + private Strings() { } + + /** + * Checks if a {@link String} is empty ({@code ""}) or {@code null}. + * + * @param str the String to check, may be {@code null} + * @return true if the String is empty or {@code null} + */ + static boolean isEmpty(String str) { + return str == null || str.isEmpty(); + } + + /** + * Checks if a {@link String} is not empty ({@code ""}) and not {@code null}. + * + * @param str the String to check, may be {@code null} + * @return true if the String is not empty and not {@code null} + */ + static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * Requires that a {@link String} is not empty ({@code ""}) and not {@code null}. + * If the requirement is violated, an {@link IllegalArgumentException} will be thrown. + * + * @param str the String to check, may be {@code null} + * @param message the message to include in + * @return the String, if the requirement was not violated + * @throws IllegalArgumentException if the requirement was violated + */ + @SuppressWarnings({"UnusedReturnValue", "SameParameterValue"}) + static String requireNotEmpty(String str, String message) { + if (isEmpty(str)) { + throw new IllegalArgumentException(message); + } + return str; + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy new file mode 100644 index 00000000000..507341ce9f4 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy @@ -0,0 +1,70 @@ +package com.commercehub.gradle.plugin.avro + +import org.apache.avro.Protocol +import org.apache.avro.Schema +import spock.lang.Specification +import spock.lang.Subject +import spock.lang.Unroll + +import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION +import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION + +@Subject(AvroUtils) +class AvroUtilsSpec extends Specification { + private static final String EMPTY_STRING = "" + private static final String SINGLE_LEVEL_NAMESPACE = "avro" + private static final String MULTI_LEVEL_NAMESPACE = "org.example" + private static final String MULTI_LEVEL_NAMESPACE_PATH = "org/example" + private static final String SCHEMA_NAME = "SchemaName" + private static final String PROTOCOL_NAME = "ProtocolName" + + @Unroll + def "assemblePath rejects unnamed arguments (#arg)"(def arg, def _) { + when: + //noinspection GroovyAssignabilityCheck + AvroUtils.assemblePath(arg) + then: + def ex = thrown(IllegalArgumentException) + ex.message == "Path cannot be assembled for nameless objects" + where: + arg | _ + createSchema(null, null, true) | _ + createSchema(null, EMPTY_STRING, true) | _ + createProtocol(null, null) | _ + createProtocol(null, EMPTY_STRING) | _ + } + + @Unroll + def "assemblePath(#arg)"(def arg, String expectedPath) { + when: + //noinspection GroovyAssignabilityCheck + def actualPath = AvroUtils.assemblePath(arg) + then: + actualPath == expectedPath + where: + arg | expectedPath + createSchema(null, SCHEMA_NAME) | "${SCHEMA_NAME}.${SCHEMA_EXTENSION}" + createSchema(EMPTY_STRING, SCHEMA_NAME) | "${SCHEMA_NAME}.${SCHEMA_EXTENSION}" + createSchema(SINGLE_LEVEL_NAMESPACE, SCHEMA_NAME) | "${SINGLE_LEVEL_NAMESPACE}/${SCHEMA_NAME}.${SCHEMA_EXTENSION}" + createSchema(MULTI_LEVEL_NAMESPACE, SCHEMA_NAME) | "${MULTI_LEVEL_NAMESPACE_PATH}/${SCHEMA_NAME}.${SCHEMA_EXTENSION}" + createProtocol(null, PROTOCOL_NAME) | "${PROTOCOL_NAME}.${PROTOCOL_EXTENSION}" + createProtocol(EMPTY_STRING, PROTOCOL_NAME) | "${PROTOCOL_NAME}.${PROTOCOL_EXTENSION}" + createProtocol(SINGLE_LEVEL_NAMESPACE, PROTOCOL_NAME) | "${SINGLE_LEVEL_NAMESPACE}/${PROTOCOL_NAME}.${PROTOCOL_EXTENSION}" + createProtocol(MULTI_LEVEL_NAMESPACE, PROTOCOL_NAME) | "${MULTI_LEVEL_NAMESPACE_PATH}/${PROTOCOL_NAME}.${PROTOCOL_EXTENSION}" + } + + Schema createSchema(String namespace, String name, boolean disableNameValidation = false) { + if (disableNameValidation) { + Schema.validateNames.set(false) + } + def schema = Schema.createRecord(name, null, namespace, false, Collections.emptyList()) + if (disableNameValidation) { + Schema.validateNames.set(true) + } + return schema + } + + Protocol createProtocol(String namespace, String name) { + return new Protocol(name, null, namespace); + } +} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/StringsSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/StringsSpec.groovy new file mode 100644 index 00000000000..14eaa943c48 --- /dev/null +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/StringsSpec.groovy @@ -0,0 +1,57 @@ +package com.commercehub.gradle.plugin.avro + +import spock.lang.Specification +import spock.lang.Subject +import spock.lang.Unroll + +@Subject(Strings) +class StringsSpec extends Specification { + @Unroll + def "isEmpty(#str)"() { + when: + def actual = Strings.isEmpty(str) + then: + actual == expected + where: + str | expected + null | true + "" | true + " " | false + "abc" | false + } + + @Unroll + def "isNotEmpty(#str)"() { + when: + def actual = Strings.isNotEmpty(str) + then: + actual == expected + where: + str | expected + null | false + "" | false + " " | true + "abc" | true + } + + @Unroll + def "when not empty, requireNotEmpty returns argument (#str)"() { + def message = "testMessage" + expect: + Strings.requireNotEmpty(str, message) == str + where: + str << [" ", "abc"] + } + + @Unroll + def "when empty, requireNotEmpty throws exception (#str)"() { + def message = "testMessage" + when: + Strings.requireNotEmpty(str, message) + then: + def ex = thrown(IllegalArgumentException) + ex.message == message + where: + str << [null, ""] + } +} From 852e371630fe7c6cc3d14a46b721fc5d38e9f14a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 6 Aug 2020 16:37:22 -0400 Subject: [PATCH 342/479] Fix codenarc failures --- .../com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy index 507341ce9f4..d96a620cc74 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy @@ -18,6 +18,7 @@ class AvroUtilsSpec extends Specification { private static final String SCHEMA_NAME = "SchemaName" private static final String PROTOCOL_NAME = "ProtocolName" + @SuppressWarnings("ParameterName") @Unroll def "assemblePath rejects unnamed arguments (#arg)"(def arg, def _) { when: @@ -65,6 +66,6 @@ class AvroUtilsSpec extends Specification { } Protocol createProtocol(String namespace, String name) { - return new Protocol(name, null, namespace); + return new Protocol(name, null, namespace) } } From c82a1bec40da2584ebb36c727c57105832ae3aa5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 29 Sep 2020 22:14:44 -0400 Subject: [PATCH 343/479] Fix a test typo (Fixes #125) --- .../plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy index 52a133ae9e4..ace7a5374c2 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy @@ -89,6 +89,6 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { then: "avpr files are generated for each IDL file" result.task(":generateAvroProtocol").outcome == SUCCESS projectFile("build/generated-main-avro-avpr/org/example/v1/TestProtocol.avpr").file - projectFile("build/generated-main-avro-avpr/org/example/v1/TestProtocol.avpr").file + projectFile("build/generated-main-avro-avpr/org/example/v2/TestProtocol.avpr").file } } From 35ea37ecc91116fa0766d28710e6b90b75a05d45 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 30 Sep 2020 15:43:47 -0400 Subject: [PATCH 344/479] Update test-project to remove references to dataTimeLogicalType --- test-project/build.gradle | 3 --- test-project/src/test/java/project/CLIComparisonTest.java | 4 ++-- test-project/src/test/java/project/RecordTest.java | 8 ++++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/test-project/build.gradle b/test-project/build.gradle index 13e9410111a..2e0eb07f14d 100644 --- a/test-project/build.gradle +++ b/test-project/build.gradle @@ -1,5 +1,4 @@ plugins { - id "application" id "idea" id "com.commercehub.gradle.plugin.avro" version "0.21.0" } @@ -15,7 +14,6 @@ ext { dependencies { implementation "org.apache.avro:avro:${avroVersion}" implementation "org.apache.avro:avro-tools:${avroVersion}" - implementation "joda-time:joda-time:2.10.6" testImplementation "org.junit.jupiter:junit-jupiter:5.6.2" } @@ -29,5 +27,4 @@ test { avro { stringType = "CharSequence" fieldVisibility = "private" - dateTimeLogicalType = "JODA" } diff --git a/test-project/src/test/java/project/CLIComparisonTest.java b/test-project/src/test/java/project/CLIComparisonTest.java index c248f26458e..9990da98e10 100644 --- a/test-project/src/test/java/project/CLIComparisonTest.java +++ b/test-project/src/test/java/project/CLIComparisonTest.java @@ -27,9 +27,9 @@ public class CLIComparisonTest { private static Stream compareSpecificCompilerOutput() { return Stream.of( // From https://stackoverflow.com/questions/45581437/how-to-specify-converter-for-default-value-in-avro-union-logical-type-fields - Arguments.of("BuggyRecord.avsc", "com/example/BuggyRecord.java", "compile -dateTimeLogicalTypeImpl JODA schema".split(" ")), + Arguments.of("BuggyRecord.avsc", "com/example/BuggyRecord.java", "compile schema".split(" ")), // From https://github.com/davidmc24/gradle-avro-plugin/issues/120 - Arguments.of("Messages.avsc", "com/somedomain/Messages.java", "compile -dateTimeLogicalTypeImpl JODA schema".split(" ")) + Arguments.of("Messages.avsc", "com/somedomain/Messages.java", "compile schema".split(" ")) ); } diff --git a/test-project/src/test/java/project/RecordTest.java b/test-project/src/test/java/project/RecordTest.java index 58a96886cff..8f979a6a7a5 100644 --- a/test-project/src/test/java/project/RecordTest.java +++ b/test-project/src/test/java/project/RecordTest.java @@ -8,7 +8,6 @@ import org.apache.avro.io.EncoderFactory; import org.apache.avro.specific.SpecificDatumWriter; import org.apache.avro.specific.SpecificRecord; -import org.joda.time.DateTime; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -16,6 +15,7 @@ import java.io.ByteArrayOutputStream; import java.io.OutputStream; +import java.time.Instant; import java.util.stream.Stream; public class RecordTest { @@ -26,12 +26,12 @@ private static Stream buildAndWriteRecord() { return Stream.of( // From https://stackoverflow.com/questions/45581437/how-to-specify-converter-for-default-value-in-avro-union-logical-type-fields // Broken due to an Avro bug - Arguments.of(BuggyRecord.newBuilder().setMyMandatoryDate(DateTime.now()).build()), + Arguments.of(BuggyRecord.newBuilder().setMyMandatoryDate(Instant.now()).build()), // Broken due to an Avro bug - Arguments.of(BuggyRecordWorkaround.newBuilder().setMyMandatoryDate(DateTime.now()).build()), + Arguments.of(BuggyRecordWorkaround.newBuilder().setMyMandatoryDate(Instant.now()).build()), // From https://github.com/davidmc24/gradle-avro-plugin/issues/120 // Broken due to an Avro bug - Arguments.of(Messages.newBuilder().setStart(DateTime.now()).build()) + Arguments.of(Messages.newBuilder().setStart(Instant.now()).build()) ); } From 1d0a257db9546326823c222a8693835e5da00734 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 2 Dec 2020 09:42:27 -0500 Subject: [PATCH 345/479] Plugin DSL is no longer incubating, and is now recommended. --- README.md | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index edf158e3a79..8979cf57233 100644 --- a/README.md +++ b/README.md @@ -35,35 +35,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Usage -Add the following to your `build.gradle` file. Substitute the desired version based on [CHANGES.md](https://github.com/davidmc24/gradle-avro-plugin/blob/master/CHANGES.md). - -```groovy -buildscript { - repositories { - jcenter() - } - dependencies { - classpath "com.commercehub.gradle.plugin:gradle-avro-plugin:VERSION" - } -} -apply plugin: "com.commercehub.gradle.plugin.avro" -``` - -Additionally, ensure that you have a compile dependency on Avro, such as: - -```groovy -repositories { - jcenter() -} -dependencies { - compile "org.apache.avro:avro:1.10.0" -} -``` - -If you now run `gradle build`, Java classes will be compiled from Avro files in `src/main/avro`. -Actually, it will attempt to process an "avro" directory in every `SourceSet` (main, test, etc.) - -Alternatively, if you prefer to use the incubating plugins DSL, see the following example: +Add the following to your build files. Substitute the desired version based on [CHANGES.md](https://github.com/davidmc24/gradle-avro-plugin/blob/master/CHANGES.md). `settings.gradle`: ```groovy @@ -86,6 +58,20 @@ plugins { } ``` +Additionally, ensure that you have a compile dependency on Avro, such as: + +```groovy +repositories { + jcenter() +} +dependencies { + compile "org.apache.avro:avro:1.10.0" +} +``` + +If you now run `gradle build`, Java classes will be compiled from Avro files in `src/main/avro`. +Actually, it will attempt to process an "avro" directory in every `SourceSet` (main, test, etc.) + # Configuration There are a number of configuration options supported in the `avro` block. From 443a410b82771a37b5ce0ebce0992f14e552b509 Mon Sep 17 00:00:00 2001 From: Vladimir Kralik Date: Fri, 11 Dec 2020 15:00:56 +0100 Subject: [PATCH 346/479] Upgrade to Avro 0.10.1 because of https://issues.apache.org/jira/browse/AVRO-2924 --- CHANGES.md | 3 +++ README.md | 9 +++++---- build.gradle | 2 +- .../gradle/plugin/avro/AvroPluginFunctionalSpec.groovy | 8 ++++++++ .../com/commercehub/gradle/plugin/avro/interop.avdl | 5 +++++ 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 155e789be64..9850fdabd72 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,9 @@ * Add support for multiple IDL files with the same name in different directories (#123) * The `.avpr` file generated by `GenerateAvroProtocolTask` is now based on the namespace and name of the protocol, rather than the name of the `.avdl` file. +## 0.21.1 +* Built using Avro 1.10.1 + ## 0.21.0 * Built using Avro 1.10.0 * Drop support for Avro 1.9.X diff --git a/README.md b/README.md index 8979cf57233..b662c354f98 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,9 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * If you need support for Gradle 4.4-5.0, version 0.18.0 was the last version tested for compatibility * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Avro 1.10.0 - * Currently tested against Avro 1.10.0 +* Currently built against Avro 1.10.1 + * Currently tested against Avro 1.10.1 + * If you need support for Avro 1.10.0 try plugin version 0.20.0 * If you need support for Avro 1.9.0-1.9.2 try plugin version 0.20.0 * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 @@ -65,7 +66,7 @@ repositories { jcenter() } dependencies { - compile "org.apache.avro:avro:1.10.0" + compile "org.apache.avro:avro:1.10.1" } ``` @@ -248,7 +249,7 @@ apply plugin: "java" apply plugin: "com.commercehub.gradle.plugin.avro-base" dependencies { - implementation "org.apache.avro:avro:1.10.0" + implementation "org.apache.avro:avro:1.10.1" } def generateAvro = tasks.register("generateAvro", com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { diff --git a/build.gradle b/build.gradle index ebe730897c6..3d32fb7af2d 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ repositories { jcenter() } -def compileAvroVersion = "1.10.0" +def compileAvroVersion = "1.10.1" def codenarcVersion = "1.5" def codenarcGroovyVersion = "2.5.10" // Newer version than included in 1.5 required for Java 14 support diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 21b2e3f720d..d326e1dc076 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -59,16 +59,24 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { when: def result = run() + def interopJavaContent = projectFile("build/generated-main-avro-java/org/apache/avro/Interop.java").text then: result.task(":generateAvroProtocol").outcome == SUCCESS result.task(":generateAvroJava").outcome == SUCCESS result.task(":compileJava").outcome == SUCCESS + projectFile("build/generated-main-avro-java/org/apache/avro/Interop.java").file projectFile(buildOutputClassPath("org/apache/avro/Foo.class")).file projectFile(buildOutputClassPath("org/apache/avro/Interop.class")).file projectFile(buildOutputClassPath("org/apache/avro/Kind.class")).file projectFile(buildOutputClassPath("org/apache/avro/MD5.class")).file projectFile(buildOutputClassPath("org/apache/avro/Node.class")).file + interopJavaContent + interopJavaContent.contains("BigDecimal decimalField") + interopJavaContent.contains("LocalDate dateField") + interopJavaContent.contains("LocalTime timeField") + interopJavaContent.contains("Instant timeStampField") + interopJavaContent.contains("LocalDateTime localTimeStampField") } def "supports json schema files in subdirectories"() { diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl b/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl index 7e056665165..d711890cec5 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl @@ -45,6 +45,11 @@ protocol InteropProtocol { Kind enumField; MD5 fixedField; Node recordField; + decimal(10,2) decimalField; + date dateField; + time_ms timeField; + timestamp_ms timeStampField; + local_timestamp_ms localTimeStampField; } } From 470db3dcc71247bf6528794527b57a4d1274540e Mon Sep 17 00:00:00 2001 From: Vladimir Kralik Date: Sun, 13 Dec 2020 11:05:37 +0100 Subject: [PATCH 347/479] Added compatibility testing against 1.10.0 and 1.10.1 --- README.md | 3 +-- build.gradle | 8 ++++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b662c354f98..a40a033ab28 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Avro 1.10.1 - * Currently tested against Avro 1.10.1 - * If you need support for Avro 1.10.0 try plugin version 0.20.0 + * Currently tested against Avro 1.10.0-1.10.1 * If you need support for Avro 1.9.0-1.9.2 try plugin version 0.20.0 * If you need support for Avro 1.8.2, try plugin version 0.16.0 * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 diff --git a/build.gradle b/build.gradle index 3d32fb7af2d..7d2f838fc26 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,9 @@ repositories { jcenter() } -def compileAvroVersion = "1.10.1" +def compileAvroVersionMinor = "1.10" +def compileAvroVersionPatch = 1 // 1.10.1 +def compileAvroVersion = "${compileAvroVersionMinor}.${compileAvroVersionPatch}" def codenarcVersion = "1.5" def codenarcGroovyVersion = "2.5.10" // Newer version than included in 1.5 required for Java 14 support @@ -207,7 +209,9 @@ tasks.create("testRecentVersionCompatibility") { // Java 8+ is also required by Gradle 5.x sourceCompatibility = 8 -def avroVersions = ["1.10.0"] +def avroVersions = (0..compileAvroVersionPatch).collect { "${compileAvroVersionMinor}.${it}" } +// println "Checked avroVersions = ${avroVersions}" + def keyAvroVersions = avroVersions.last() def gradle5KotlinVersions =[] if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_10)) { From 1fe0eb4aebc15c2165665d62f9811ff76447e956 Mon Sep 17 00:00:00 2001 From: Vladimir Kralik Date: Sun, 13 Dec 2020 13:10:13 +0100 Subject: [PATCH 348/479] More spock assert about generated Java Code was added. Type uuid is not compilable with Avro 1.10.1 --- config/codenarc/codenarc.groovy | 2 +- .../plugin/avro/AvroPluginFunctionalSpec.groovy | 16 ++++++++++++++++ .../commercehub/gradle/plugin/avro/interop.avdl | 3 ++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/config/codenarc/codenarc.groovy b/config/codenarc/codenarc.groovy index 3b4ffd2de42..73b495d739a 100644 --- a/config/codenarc/codenarc.groovy +++ b/config/codenarc/codenarc.groovy @@ -306,7 +306,7 @@ ruleset { UnnecessaryModOne UnnecessaryNullCheck UnnecessaryNullCheckBeforeInstanceOf - UnnecessaryObjectReferences + // UnnecessaryObjectReferences // <= this has problem with Spock asserts UnnecessaryOverridingMethod UnnecessaryPackageReference UnnecessaryParenthesesForMethodCallWithClosure diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index d326e1dc076..f456821ff6d 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -71,12 +71,28 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { projectFile(buildOutputClassPath("org/apache/avro/Kind.class")).file projectFile(buildOutputClassPath("org/apache/avro/MD5.class")).file projectFile(buildOutputClassPath("org/apache/avro/Node.class")).file + /* codenarc-disable */ // <= this doesn't help, so I have to switch the rule off interopJavaContent + interopJavaContent.contains("int intField") + interopJavaContent.contains("long longField") + interopJavaContent.contains("String stringField") + interopJavaContent.contains("boolean boolField") + interopJavaContent.contains("float floatField") + interopJavaContent.contains("double doubleField") + interopJavaContent.contains("java.lang.Void nullField") + interopJavaContent.contains("java.util.List arrayField") + interopJavaContent =~ /Map mapField/ + interopJavaContent.contains("Object unionField") + interopJavaContent.contains("Kind enumField") + interopJavaContent.contains("MD5 fixedField") + interopJavaContent.contains("Node recordField") interopJavaContent.contains("BigDecimal decimalField") interopJavaContent.contains("LocalDate dateField") interopJavaContent.contains("LocalTime timeField") interopJavaContent.contains("Instant timeStampField") interopJavaContent.contains("LocalDateTime localTimeStampField") + // interopJavaContent.contains("CharSequence uuidField") // not compilable with Avro 1.10.1 yet + /* codenarc-enable */ } def "supports json schema files in subdirectories"() { diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl b/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl index d711890cec5..f0aee4439fb 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl @@ -41,7 +41,7 @@ protocol InteropProtocol { null nullField; array arrayField = []; map mapField; - union { boolean, double, array } unionFIeld; + union { boolean, double, array } unionField; Kind enumField; MD5 fixedField; Node recordField; @@ -50,6 +50,7 @@ protocol InteropProtocol { time_ms timeField; timestamp_ms timeStampField; local_timestamp_ms localTimeStampField; + // uuid uuidField; // not compilable with Avro 1.10.1 } } From fa7d7a9049ca4ca5e5e0987de72ec5f7c222a377 Mon Sep 17 00:00:00 2001 From: Vladimir Kralik Date: Sun, 13 Dec 2020 13:14:14 +0100 Subject: [PATCH 349/479] Avro 1.10.1 was set also in test-project/build.gradle --- test-project/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-project/build.gradle b/test-project/build.gradle index 2e0eb07f14d..03fe6470c32 100644 --- a/test-project/build.gradle +++ b/test-project/build.gradle @@ -8,7 +8,7 @@ repositories { } ext { - avroVersion = "1.10.0" + avroVersion = "1.10.1" } dependencies { From 1ef60521b9606249dc2e84ce2af1ad032d2bc065 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Dec 2020 00:06:51 -0500 Subject: [PATCH 350/479] Minor post pull-request-merge tweaks --- CHANGES.md | 2 -- build.gradle | 7 ++----- config/codenarc/codenarc.groovy | 3 ++- .../gradle/plugin/avro/AvroPluginFunctionalSpec.groovy | 3 --- .../com/commercehub/gradle/plugin/avro/interop.avdl | 2 -- 5 files changed, 4 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9850fdabd72..3c687435f0e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,8 +4,6 @@ * Add coverage reporting via JaCoco/Codecov to the plugin's build pipeline * Add support for multiple IDL files with the same name in different directories (#123) * The `.avpr` file generated by `GenerateAvroProtocolTask` is now based on the namespace and name of the protocol, rather than the name of the `.avdl` file. - -## 0.21.1 * Built using Avro 1.10.1 ## 0.21.0 diff --git a/build.gradle b/build.gradle index 7d2f838fc26..2e66c3c91b2 100644 --- a/build.gradle +++ b/build.gradle @@ -14,9 +14,7 @@ repositories { jcenter() } -def compileAvroVersionMinor = "1.10" -def compileAvroVersionPatch = 1 // 1.10.1 -def compileAvroVersion = "${compileAvroVersionMinor}.${compileAvroVersionPatch}" +def compileAvroVersion = "1.10.1" def codenarcVersion = "1.5" def codenarcGroovyVersion = "2.5.10" // Newer version than included in 1.5 required for Java 14 support @@ -209,8 +207,7 @@ tasks.create("testRecentVersionCompatibility") { // Java 8+ is also required by Gradle 5.x sourceCompatibility = 8 -def avroVersions = (0..compileAvroVersionPatch).collect { "${compileAvroVersionMinor}.${it}" } -// println "Checked avroVersions = ${avroVersions}" +def avroVersions = ["1.10.0", "1.10.1"] def keyAvroVersions = avroVersions.last() def gradle5KotlinVersions =[] diff --git a/config/codenarc/codenarc.groovy b/config/codenarc/codenarc.groovy index 73b495d739a..9265e6a8fe5 100644 --- a/config/codenarc/codenarc.groovy +++ b/config/codenarc/codenarc.groovy @@ -306,7 +306,8 @@ ruleset { UnnecessaryModOne UnnecessaryNullCheck UnnecessaryNullCheckBeforeInstanceOf - // UnnecessaryObjectReferences // <= this has problem with Spock asserts + // Unnecessarily complicates Spock assertions + // UnnecessaryObjectReferences UnnecessaryOverridingMethod UnnecessaryPackageReference UnnecessaryParenthesesForMethodCallWithClosure diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index f456821ff6d..b411a79d398 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -71,7 +71,6 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { projectFile(buildOutputClassPath("org/apache/avro/Kind.class")).file projectFile(buildOutputClassPath("org/apache/avro/MD5.class")).file projectFile(buildOutputClassPath("org/apache/avro/Node.class")).file - /* codenarc-disable */ // <= this doesn't help, so I have to switch the rule off interopJavaContent interopJavaContent.contains("int intField") interopJavaContent.contains("long longField") @@ -91,8 +90,6 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { interopJavaContent.contains("LocalTime timeField") interopJavaContent.contains("Instant timeStampField") interopJavaContent.contains("LocalDateTime localTimeStampField") - // interopJavaContent.contains("CharSequence uuidField") // not compilable with Avro 1.10.1 yet - /* codenarc-enable */ } def "supports json schema files in subdirectories"() { diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl b/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl index f0aee4439fb..a290af330db 100644 --- a/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl +++ b/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl @@ -50,7 +50,5 @@ protocol InteropProtocol { time_ms timeField; timestamp_ms timeStampField; local_timestamp_ms localTimeStampField; - // uuid uuidField; // not compilable with Avro 1.10.1 } - } From fe564af5f769e5c60befc5480fec747dbdaa281c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Dec 2020 00:40:04 -0500 Subject: [PATCH 351/479] Update compatibility with Java/Gradle, tweak build spead --- .github/workflows/ci.yml | 4 +- CHANGES.md | 5 +- README.md | 14 +- build.gradle | 5 +- gradle.properties | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 58910 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- gradlew.bat | 193 +++++++++++------------ 9 files changed, 108 insertions(+), 118 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3790769f687..0fd96866def 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: # Exclude mac as it's unreliable at the moment # See https://github.com/actions/virtual-environments/issues/736 os: [ubuntu-latest, windows-latest] - java: [8, 11, 13, 14] # All supported major versions + java: [8, 11, 13, 14, 15] # All supported major versions fail-fast: true steps: - name: Check out repository @@ -123,7 +123,7 @@ jobs: # Exclude mac as it's unreliable at the moment # See https://github.com/actions/virtual-environments/issues/736 os: [ubuntu-latest, windows-latest] - java: [15-ea] # EA builds of all current pre-release major versions + java: [16-ea] # EA builds of all current pre-release major versions fail-fast: false steps: - name: Check out repository diff --git a/CHANGES.md b/CHANGES.md index 3c687435f0e..db25278b88d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,8 +3,11 @@ ## Unreleased * Add coverage reporting via JaCoco/Codecov to the plugin's build pipeline * Add support for multiple IDL files with the same name in different directories (#123) - * The `.avpr` file generated by `GenerateAvroProtocolTask` is now based on the namespace and name of the protocol, rather than the name of the `.avdl` file. + * The `.avpr` file generated by `GenerateAvroProtocolTask` is now based on the namespace and name of the protocol, rather than the name of the `.avdl` file. * Built using Avro 1.10.1 +* Built using Gradle 6.7.1 +* Updated compatibility testing to include Java 15 +* Updated compatibility testing through Gradle 6.7.1 ## 0.21.0 * Built using Avro 1.10.0 diff --git a/README.md b/README.md index a40a033ab28..24a167c738a 100644 --- a/README.md +++ b/README.md @@ -6,16 +6,16 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -* Currently tested against Java 8-14 - * Java 15 support appears to require Gradle 6.3 or higher (currently tested against pre-release versions) - * Java 14 support requires Gradle 6.3 or higher +* Currently tested against Java 8-15 + * Java 15 support requires Gradle 6.7 or higher (as per Gradle's release notes) + * Java 14 support requires Gradle 6.3 or higher (as per Gradle's release notes) * Java 13 support requires Gradle 6.0 or higher - * Java 11 support requires Gradle 4.8 or higher - * Though not supported yet, tests are also run against early-access builds of Java 15 to provide early notification of potential incompatibilities + * Java 11 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) + * Though not supported yet, tests are also run against early-access builds of Java 16 to provide early notification of potential incompatibilities * If you need support for Java 7, version 0.16.0 was the last supported version * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) -* Currently built against Gradle 6.5 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.5 +* Currently built against Gradle 6.7.1 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.7.1 * If you need support for Gradle 4.4-5.0, version 0.18.0 was the last version tested for compatibility * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) diff --git a/build.gradle b/build.gradle index 2e66c3c91b2..3d06827367a 100644 --- a/build.gradle +++ b/build.gradle @@ -250,8 +250,8 @@ if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) { gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2") keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line before Java 14 support } -gradleVersions.addAll("6.3", "6.4", "6.4.1", "6.5") -keyGradleVersions.addAll("6.3", "6.5") // First and last for the 6.x line after Java 14 support +gradleVersions.addAll("6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", "6.7", "6.7.1") +keyGradleVersions.addAll("6.3", "6.7.1") // First and last for the 6.x line after Java 14 support def latestAvroVersion = avroVersions.last() def latestGradleVersion = gradleVersions.last() @@ -353,4 +353,5 @@ tasks.withType(Test) { jvmArgs "-Xss320k" minHeapSize "120m" maxHeapSize "280m" + maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1 } diff --git a/gradle.properties b/gradle.properties index 3f5b52c4be6..e51e97e1bc5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,4 @@ org.gradle.warning.mode=all org.gradle.parallel=true +org.gradle.vfs.watch=true systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 62d4c053550b91381bbd28b1afc82d634bf73a8a..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 6656 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 Yte!%o?r4GTrVtxD61Ym!|5fq-1K$0e!T1w z1SC8j)_dObefzK9b=~*c&wBRW>;B{VGKiBofK!FMN5oJBE0V;;!kWUz!jc1W?5KdY zyZ3mCBHprpchz-9{ASiJJh&&h1|4rdw6wxD2+9= z#6#}Uq8&^1F3wgvGFoNDo?bIeEQXpcuAR0-+w$JWoK-@yUal1M&~W_O)r+Rx;{@hWH5n^oQWR36GMYBDDZyPK4L@WVjRrF+XlSzi4X4!_!U%Uujl6LHQ#|l(sUU%{ zefYd8jnVYP91K}Qn-OmmSLYFK1h~_}RPS~>+Xdz%dpvpJ{ll!IKX=JN99qowqslbO zV3DmqPZ}6>KB!9>jEObpi$u5oGPfO3O5!o3N2Mn`ozpje<}1I1H)m2rJDcB7AwXc6 z6j)tnPiql7#)r+b+p9?MVahp&=qJ^$oG+a^C*);FoJ!+V*^W+|2Olx5{*&$bXth)U zejc7mU6cBp?^Rj|dd{GL-0eHRTBi6_yJ&GLP5kIncv^z{?=0AVy^5{S8_n=rtua!J zFGY=A(yV^ZhB}1J_y(F`3QTu+zkHlw;1GiFeP&pw0N1k%NShHlO(4W+(!wy5phcg4 zA-|}(lE_1@@e6y`veg;v7m;q%(PFG&K3#}eRhJioXUU0jg_8{kn$;KVwf;zpL2X_( zC*_R#5*PaBaY73(x*oZ}oE#HPLJQRQ7brNK=v!lsu==lSG1(&q>F)`adBT~d*lMS| z%!%7(p~<7kWNmpZ5-N31*e=8`kih|g5lVrI%2wnLF-2D+G4k6@FrYsJ_80AJ}KMRi>) z-kIeHp{maorNWkF81v0FKgB==_6blyaF$5GaW)B!i4v*jNk6r)vU6?G$0pV8(Y+UK z5lgRVt%;N_gWp)^osv=h+^07UY6+$4^#t=M3>0i0`{`aEkFLL#a)93uXhYO+aKTtu zckg2T9S&GKNtZmdAS^8PzvDva-%-K&g9eqPXQ4$dM^inr@6Zl z{!Cq&C_+V;g*{>!0cZP}?ogDb$#ZS=n@NHE{>k@84lOkl&$Bt2NF)W%GClViJq14_ zQIfa^q+0aq){}CO8j%g%R9|;G0uJuND*HO$2i&U_uW_a5xJ33~(Vy?;%6_(2_Cuq1 zLhThN@xH7-BaNtkKTn^taQHrs$<<)euc6z(dhps>SM;^Wx=7;O&IfNVJq3wk4<1VS z-`*7W4DR_i^W4=dRh>AXi~J$K>`UqP>CKVVH&+T(ODhRJZO7DScU$F7D)di-%^8?O z6)Ux`zdrVOe1GNkPo0FgrrxSu1AGQkJe@pqu}8LkBDm+V!N_1l}`tjLW8${rgDLv3m@E*#zappt-Mm zSC<$o+6UO~w0C=(0$&*y**@nKe_Q{|eAuD!(0YL0_a{z%+sdfSyP={Nyd$re6Rzbp zvsgTY7~VflX0^Vf7qqomYZ_$ryrFVV2$sFyzw2r%Q8*uYDA+)iQdfKms_5(>!s#!( z!P5S(N0i9CKQKaqg(U%Gk#V3*?)lO6dLv`8KB~F<-%VhbtL8Rl>mEz+PN=qx&t*|= zQHV=qG)YKlPk4iCyWIUGjC?kpeA>hIBK*A?B0)rB=RqAal#D%1C9yVQwBcz${#Jb5 zR{TRmMrOrJsLc&6x9qDo@FJ^=do_Y?3oU0G^nV5_EU&+DS+VA7Tp{^TAF>yZbyM3c zf*1CqHY9T|aL_lyY7c)i!_MtGPA!sdy3|mrsKVj1mi&>dms@-ozSa}OZ?2I*tAndg z@S7er$t^d^-;!wLQbG60nWd@1pQVD7tw-G_B#OscoYyremiZ_hj8*sXqQdchuD^!R zpXGuSj5psk+jR>3rWu3^`17>j&*^9^rWbszP=Mf@5KIEj%b=z98v=Ymp%$FYt>%Ld zm8})EDbNOJu9n)gwhz_RS``#Ag)fr)3<*?(!9O~mTQWeh;8c;0@o=iBLQNqx3d_2#W7S9#FXzr6VXfs>4 z;QXw}-STvK9_-7H=uqgal2{GkbjVLN+=D5ddd)4^WvX;(NYA*X*(JxTdiUzqVJopd zQg#~psX4o<)cF>r=rxP`(Xsf<+HG-pf&7aFPL8z|-&B*P?Vmsu5d>Nlg^2$WRY!S@#`g2{81;(1w#o5HsvN}5pFZi});>|VK^kL{Zkx~wgn ztlZp;HW`H8(GdRfIwc~?#N6}o#h158ohI*GIsK%56I_9sf2k_K@4vD!l{(dX9E7PJ;w>$|Y;-VBJSO4@){07bo-89^LZ9g<<%;dOl zyIq{s8`8Ltp*GDwu(l_Z$6sA2nam$BM$Q~6TpZg)w2TtW?G5whV(lRwaf$6EU86is zBP9Rs&vS_~sk?Nn_b}^HkM8LiO@>J}=g(T4hLmvH@5Jj#2aHa~K)lD9VB0k>$V2BP zgh;(=y9Op(KQ=H5vj+%qs>?s4tYN~-Q|fyQePA)s?HrF~;l!+@t8VMzqUpqMLudFT z)=o~s!MM4XkgbetIsODwtQ=FF$IcIp&!pjh6Q6{tL+l*7GQ%8Wsg(tC#qU3oW$~n) zL=>XIxI}Hi7HS0F_mmi+(c%1HDuKiWm>|6Xa}nW7ei55ggru9)xjBvC#JcEIN*#cp zv*ACvr=HTC?dX9NNo9Yhulu_gX5Z~}QQ2&QZ&C77{(>Y3_ z6j5Z1Uc5FtPEpS_31HsgmSLHZijGb_p$WlRJ1p^_1!ZLP8kr6OtCEK7Qh267o$H>e zf<4cNGQRk{g5h$XfvTFQ@`qm@iju83-~}ebAYpZryARHVR$AEt3229U{y@Fp4 z-8FBBtGG&(hTyUdx5ZOfiz`c=<0F%+w|Fl=rWk{K7>70k04SN?RU(^mrKSeKDqA!K^Hsv8C?#ioj4@WUL zC*?{hTai6q0%_oBTqDHygp_Kl;({sAScYQIwMDM1U>{x0ww zve?_}E;DG?+|zsUrsph5X_G7l#Y~vqkq3@NNDabbw7|`eJBmn`Qrlr%?`va=mm$Mc{+FBbQbogAZ6{MuzT|P%QZZotd21eb1hfj|;GYAX&>bx#D5EB+=XMj2XJkpnyMUykaVo) zj3ZLqEl1&)Rturc8m@+uUuD^vaNaSxGwP4dq0-OSb~62lPv8E_K4usLvG{Qg zdR%z8dd2H!{JaT|X_bfm{##*W$YM;_J8Y8&Z)*ImOAf4+| zEyi)qK%Ld1bHuqD+}-WiCnjszDeC-%8g+8JRpG1bOc!xUGB?@?6f~FTrI%U#5R~YF z%t5(S2Q>?0`(XNHa8xKdTEZ~Z4SJOheit#ldfdg63}#W6j8kO;SjQD`vftxS+#x1B zYu|5szEvkyz|}|B3x|DNlyi$;+n+cW$Hu+?)=X1!sa%{H-^;oBO9XACZJ}wkQ!sTa zQ#J3h|HX{{&WwIG3h7d6aWktuJaO)ie6&=KJBoX@w(rBWfin`*a6OmCC5M0HzL(gv zY<*e4hmW>SWVhxk-`UGOAbD%Hk+uu<^7zJ_ytVXamfqCd0$g+W08>?QAB}Cv{b}eM z@X}ILg+uT%>-6`A25p@uhS3%;u>ccSq}8|H_^o&`nBT5S0y z;2H0I^(4MO*S+(4l$gULc4KSeKvidto5Nl0P|%9CqQ*ikY!w_GUlo}sb9HYB=L^oFpJ zfTQskXW!LFVnUo4(OHPDaZSf3zB|3{RGu1>ueE$(+dr?tT zp!SGlqDU8vu{5xLWSvj+j$arHglg54#Lx&TvuO3LIIU>hF9Uoj&=-b*Q?uYr`#V?xz?2 zhirZrv^eA{k%{hFh%9LYVXEYWd5#PuUd1QqaqB*J!CMXEM>fEB$@#1>mtB`Bfil}t zhhTIObqh5HRvT+4q_Do$Q*Jika?qV=Np-DtPkU z(KoXyWLfPwr@UY1)hBAvR3nCBZgd|CevTG?H~HqDF}dzy%2sd2`f{^CBbTk*^K~RO zN~O0+2EjAJlywF%SjgYz810l&G5AqzI<=Ber{912^PpSPRJl3dm8W@dKHL}7_@k3)Y!SXYkyxQy>Q4I2o zr`ev7fLF$1t96h|sH<-#*YzGD-b^3$_!#wsh(Yw;)b@udLz9mm`mFYh z1Zz24KIQJ(*_-E0(3&1InqG;U?wF)GYd>DFo(em`#|UaaYmkA9;GTX7b?0@C@QkTVpGD#mf$dQoRNV=n{^Zi_W*ps;3?^$s`0;ER7;==~OmQ~9 zS5P=FjxE5%|;xq6h4@!_h?@|aK&FYI2IT(OHXv2%1 zWEo-v!L7x^YT(xLVHlpJttcwaF@1Y;-S*q3CRa!g7xdzl|Jan>2#dI0`LKl!T1GMk zRKe4|bQO&ET}Z^Aiym*HII>cSxIzl|F~JEUGxz;+DB=8fxXhnBI4R12q6ews$lA`Jfi}r@A@-)6TOAUMNYFYJ zZ-Zd?lxFTyjN3mXnL!%#>Z%$0gJ4*9g;e;@zSmQ{eGGDaRRNM3s@6!;hYuVc=c+3B z=qzNNS~n^EsJU4aOGE|mdy={C^lPKEfPL-IJAsTpQsDgZ@~s+eHZYmp9yb=YW_4r?lqQaYZQ`nau){W`LY#P)>i zq^wHEuOYs#FlPZeMuT@Etb@~A6feCebq`miJE3w+gAL%bVF_s*5e*@)?xmKSo%I3? zLELHVdWia$}~s6 zr!^LfxSSB4Td&9iTXrzQpl5ZDo#SdmNr;23QsPHQ!x!UT9xtb!Ycz^JF8x)%cFOXK z^EXw%dRz_VD}7?RU^4{)1+xFO=z!EI8IUa3U*rag=1BpHX$Xi<__kSbS{y_xa*MJv z_`thq0Z^sPzjAk48ssDQj}!$N8Q$XC84(bU$t_Bm69Jf+C!h_}ep zwzpQj9sRA94<{x3{~z&ix-DwX;RAzka)4-#6ZHJqKh|SVuO|>Yrv+m30+!|sK<-|E z=)5E->#y<_1V|T1f%Af!ZYqXg}`O zI$qKOWdnclF`%_Z`WGOe{`A`l-#a?s=Q1a#@BOWmExH2;Wl`OB!B-%lq3nO{4=WO& z#k_x|N&(qzm*6S{G*|GCegF2N2ulC+(58z2DG~yUs}i8zvRf&$CJCaexJ6Xu!`qz( z)*v8*kAE#D0KCo*s{8^Rbg=`*E2MzeIt0|x55%n-gO&yX#$l=3W7-_~&(G8j1E(XB hw}tl`5K!1C(72%nnjQrp<7@!WCh47rWB+@R{{wClNUHz< diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 622ab64a3cb..4d9ca164914 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-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index fbd7c515832..4f906e0c811 100755 --- a/gradlew +++ b/gradlew @@ -130,7 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index a9f778a7a96..107acd32c4e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,104 +1,89 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 099719ff18255ef22994fbe5a12dd1103ad2509f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Dec 2020 01:07:41 -0500 Subject: [PATCH 352/479] Improve Java version support Use a Java 15-compatible version of Jacoco (currently requires a snapshot build) Use a new Java 9+ option in Gradle 6.6 that use cross-compilation to ensure that APIs not available in previous versions aren't used improperly --- build.gradle | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 3d06827367a..fa180ee5a9d 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,11 @@ plugins { repositories { jcenter() + maven { + // Used for snapshot builds for some libraries + name 'Sonatype OSS' + url 'https://oss.sonatype.org/content/repositories/snapshots' + } } def compileAvroVersion = "1.10.1" @@ -205,13 +210,19 @@ tasks.create("testRecentVersionCompatibility") { // Java 8+ is required due to requirements introduced in Avro 1.9.0 // Java 8+ is also required by Gradle 5.x -sourceCompatibility = 8 +if (JavaVersion.current().java9Compatible) { + compileJava { + options.release = 8 + } +} else { + sourceCompatibility = 8 +} def avroVersions = ["1.10.0", "1.10.1"] def keyAvroVersions = avroVersions.last() def gradle5KotlinVersions =[] -if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_10)) { +if (!JavaVersion.current().java10Compatible) { // Java 10 support was added in Kotlin 1.2.30 gradle5KotlinVersions.addAll([ "1.2.20", "1.2.21", @@ -226,7 +237,7 @@ def latestGradleKotlinVersions = [ ] def kotlinVersions = gradle5KotlinVersions + latestGradleKotlinVersions def keyKotlinVersions = [] // First and last version for each supported line -if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_10)) { +if (!JavaVersion.current().java10Compatible) { // Java 10 support was added in Kotlin 1.2.30 keyKotlinVersions.add("1.2.20") } else { @@ -266,6 +277,12 @@ test { finalizedBy jacocoTestReport // report is always generated after tests run } +jacoco { + // 0.8.7+ needed for Java 15 support + // See https://www.jacoco.org/jacoco/trunk/doc/changes.html + toolVersion = "0.8.7-SNAPSHOT" +} + jacocoTestReport { reports { html.enabled true From 842c3287a549275f6d11841ace31461c95e4b587 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 14 Dec 2020 01:14:32 -0500 Subject: [PATCH 353/479] Correct Java 15 Gradle version compatibility --- build.gradle | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index fa180ee5a9d..923162cf26e 100644 --- a/build.gradle +++ b/build.gradle @@ -261,8 +261,13 @@ if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) { gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2") keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line before Java 14 support } -gradleVersions.addAll("6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", "6.7", "6.7.1") -keyGradleVersions.addAll("6.3", "6.7.1") // First and last for the 6.x line after Java 14 support +if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_15)) { + // Java 15 support was added in Gradle 6.7 + gradleVersions.addAll("6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1") + keyGradleVersions.addAll("6.3", "6.6.1") // First and last for the 6.x line before Java 15 support +} +gradleVersions.addAll("6.7", "6.7.1") +keyGradleVersions.addAll("6.7", "6.7.1") // First and last for the 6.x line after Java 15 support def latestAvroVersion = avroVersions.last() def latestGradleVersion = gradleVersions.last() From 5ba8e2904088c609865dcb74478443bb4d4e9082 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Dec 2020 18:05:09 -0500 Subject: [PATCH 354/479] Add support for configuration cache and update kotlin testing Closes #129 --- CHANGES.md | 2 ++ README.md | 3 ++- build.gradle | 14 +++++++++---- config/checkstyle/import-control.xml | 1 + .../gradle/plugin/avro/FileUtils.java | 17 +++++++++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 7 +++++-- .../gradle/plugin/avro/GradleFeatures.java | 19 ++++++++++++----- .../gradle/plugin/avro/GradleVersions.java | 1 + .../gradle/plugin/avro/ProcessingState.java | 6 +++--- .../avro/ResolveAvroDependenciesTask.java | 2 +- .../gradle/plugin/avro/SchemaResolver.java | 10 ++++----- .../avro/AvroPluginFunctionalSpec.groovy | 21 ++++++++++++------- .../gradle/plugin/avro/FunctionalSpec.groovy | 13 ++++++++++-- .../plugin/avro/IntellijFunctionalSpec.groovy | 18 +++++++++++++--- .../plugin/avro/SchemaResolverSpec.groovy | 2 +- 15 files changed, 101 insertions(+), 35 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index db25278b88d..96d729a1c0e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Add [Configuration Cache](https://docs.gradle.org/6.6/userguide/configuration_cache.html) support (#129; thanks to [dcabasson](https://github.com/dcabasson) and [eskatos](https://github.com/eskatos)) * Add coverage reporting via JaCoco/Codecov to the plugin's build pipeline * Add support for multiple IDL files with the same name in different directories (#123) * The `.avpr` file generated by `GenerateAvroProtocolTask` is now based on the namespace and name of the protocol, rather than the name of the `.avdl` file. @@ -8,6 +9,7 @@ * Built using Gradle 6.7.1 * Updated compatibility testing to include Java 15 * Updated compatibility testing through Gradle 6.7.1 +* Updated compatibility testing through Kotlin 1.4.20 ## 0.21.0 * Built using Avro 1.10.0 diff --git a/README.md b/README.md index 24a167c738a..393714aec32 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,9 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) * Versions of Avro prior to 1.7.x are unlikely to work * Support for Kotlin - * Currently tested against Kotlin plugin versions 1.3.20-1.3.61 using the latest supported version of Gradle + * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.20 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 + * Kotlin plugin versions starting with 1.4.0 require Gradle 5.3+ * Kotlin plugin versions prior to 1.2.30 do not support Java 10+ * Version of the Kotlin plugin prior to 1.2.20 are unlikely to work * Support for Gradle Kotlin DSL diff --git a/build.gradle b/build.gradle index 923162cf26e..c28d1c5ae12 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,5 @@ +import org.gradle.util.GradleVersion + plugins { id "groovy" id "checkstyle" @@ -221,7 +223,7 @@ if (JavaVersion.current().java9Compatible) { def avroVersions = ["1.10.0", "1.10.1"] def keyAvroVersions = avroVersions.last() -def gradle5KotlinVersions =[] +def gradle5KotlinVersions = [] if (!JavaVersion.current().java10Compatible) { // Java 10 support was added in Kotlin 1.2.30 gradle5KotlinVersions.addAll([ @@ -233,10 +235,12 @@ gradle5KotlinVersions.addAll([ "1.3.0", "1.3.10", "1.3.11", ]) def latestGradleKotlinVersions = [ - "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", + "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", + "1.4.0", "1.4.10", "1.4.20", "1.4.21" ] def kotlinVersions = gradle5KotlinVersions + latestGradleKotlinVersions def keyKotlinVersions = [] // First and last version for each supported line +// Determine first supported version if (!JavaVersion.current().java10Compatible) { // Java 10 support was added in Kotlin 1.2.30 keyKotlinVersions.add("1.2.20") @@ -245,8 +249,10 @@ if (!JavaVersion.current().java10Compatible) { } keyKotlinVersions.addAll([ "1.2.71", - "1.3.0", "1.3.61", + "1.3.0", "1.3.72", // First and last version for 1.3.x line + "1.4.0", "1.4.21", // First and last version for 1.4.x line ]) +def pre5_3KotlinVersion = "1.3.72" // Kotlin plugin 1.4.x appears to require Gradle 5.3+ def keyGradleVersions = [] // First and last version for each supported line def firstSupportedGradleVersion = null def gradleVersions = [] @@ -297,7 +303,7 @@ jacocoTestReport { avroVersions.each { def avroVersion -> gradleVersions.each { def gradleVersion -> - def kotlinVersion = latestKotlinVersion + def kotlinVersion = GradleVersion.version(gradleVersion) < GradleVersion.version("5.3") ? pre5_3KotlinVersion : latestKotlinVersion def newTask = tasks.create(name: "testAvro${avroVersion}Gradle${gradleVersion}", type: Test) { description = "Test cross-compatibility of the plugin with Avro ${avroVersion} and Gradle ${gradleVersion}" systemProperties = [ diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 8f3f535fcaa..f5be6beb488 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -8,6 +8,7 @@ + diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java index cdf3905196d..11e0bded3c5 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java @@ -20,6 +20,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.nio.file.Path; +import org.gradle.api.file.ProjectLayout; /** * General file manipulation utilities. @@ -132,4 +134,19 @@ private static void writeStringToFile(File file, String data, String encoding) t static void writeJsonFile(File file, String data) throws IOException { writeStringToFile(file, data, Constants.UTF8_ENCODING); } + + /** + * Acts as a replacement for {@link org.gradle.api.Project#relativePath(Object)}, as Configuration Cache support doesn't allow + * maintaining references to the {@link org.gradle.api.Project}. + */ + static String projectRelativePath(ProjectLayout projectLayout, File file) { + Path path = file.toPath(); + if (path.isAbsolute()) { + Path projectDirectoryPath = projectLayout.getProjectDirectory().getAsFile().toPath(); + path = projectDirectoryPath.relativize(path); + } else { + path = file.toPath(); + } + return path.toString(); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java index 9e6d730d76c..789a13ea2f7 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -32,6 +32,7 @@ import org.apache.avro.generic.GenericData.StringType; import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; +import org.gradle.api.file.ProjectLayout; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.MapProperty; @@ -81,6 +82,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Provider stringTypeProvider; private final Provider fieldVisibilityProvider; + private final ProjectLayout projectLayout; private final SchemaResolver resolver; @Inject @@ -103,7 +105,8 @@ public GenerateAvroJavaTask(ObjectFactory objects) { this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) .convention(DEFAULT_LOGICAL_TYPE_FACTORIES); this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(DEFAULT_CUSTOM_CONVERSIONS); - this.resolver = new SchemaResolver(getProject(), getLogger()); + this.projectLayout = getProject().getLayout(); + this.resolver = new SchemaResolver(projectLayout, getLogger()); } @Optional @@ -312,7 +315,7 @@ private int processSchemaFiles() { Set files = filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles(); ProcessingState processingState = resolver.resolve(files); for (File file : files) { - String path = getProject().relativePath(file); + String path = FileUtils.projectRelativePath(projectLayout, file); for (Schema schema : processingState.getSchemasForLocation(path)) { try { compile(new SpecificCompiler(schema), file); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java index aa54b538775..d75f104b4d6 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java @@ -21,16 +21,25 @@ enum GradleFeatures { extensionInjection() { @Override - boolean isSupported() { - return GradleVersion.current().compareTo(GradleVersions.v5_2) >= 0; + boolean isSupportedBy(GradleVersion version) { + return version.compareTo(GradleVersions.v5_2) >= 0; } }, objectFactoryFileCollection() { @Override - boolean isSupported() { - return GradleVersion.current().compareTo(GradleVersions.v5_3) >= 0; + boolean isSupportedBy(GradleVersion version) { + return version.compareTo(GradleVersions.v5_3) >= 0; + } + }, + configCache() { + @Override + boolean isSupportedBy(GradleVersion version) { + return version.compareTo(GradleVersions.v6_6) >= 0; } }; - abstract boolean isSupported(); + abstract boolean isSupportedBy(GradleVersion version); + boolean isSupported() { + return isSupportedBy(GradleVersion.current()); + } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java b/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java index 3adab2c39e5..25a6638c089 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java @@ -21,4 +21,5 @@ class GradleVersions { static final GradleVersion v5_2 = GradleVersion.version("5.2"); static final GradleVersion v5_3 = GradleVersion.version("5.3"); + static final GradleVersion v6_6 = GradleVersion.version("6.6"); } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java index 9dfef361fe8..45206c3c412 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java @@ -24,7 +24,7 @@ import java.util.Set; import java.util.stream.Collectors; import org.apache.avro.Schema; -import org.gradle.api.Project; +import org.gradle.api.file.ProjectLayout; class ProcessingState { private final Map typeStates = new HashMap<>(); @@ -32,9 +32,9 @@ class ProcessingState { private final Queue filesToProcess = new LinkedList<>(); private int processedTotal; - ProcessingState(Iterable files, Project project) { + ProcessingState(Iterable files, ProjectLayout projectLayout) { for (File file : files) { - filesToProcess.add(new FileState(file, project.relativePath(file))); + filesToProcess.add(new FileState(file, FileUtils.projectRelativePath(projectLayout, file))); } } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java b/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java index 2af02741305..f1560c35d55 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java @@ -17,7 +17,7 @@ */ @CacheableTask public class ResolveAvroDependenciesTask extends OutputDirTask { - private final SchemaResolver resolver = new SchemaResolver(getProject(), getLogger()); + private final SchemaResolver resolver = new SchemaResolver(getProject().getLayout(), getLogger()); @TaskAction protected void process() { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java b/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java index 9c3253208db..933a053607a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java +++ b/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java @@ -9,7 +9,7 @@ import org.apache.avro.Schema; import org.apache.avro.SchemaParseException; import org.gradle.api.GradleException; -import org.gradle.api.Project; +import org.gradle.api.file.ProjectLayout; import org.gradle.api.logging.Logger; import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; @@ -18,16 +18,16 @@ class SchemaResolver { private static Pattern ERROR_UNKNOWN_TYPE = Pattern.compile("(?i).*(undefined name|not a defined name|type not supported).*"); private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); - private final Project project; + private final ProjectLayout projectLayout; private final Logger logger; - SchemaResolver(Project project, Logger logger) { - this.project = project; + SchemaResolver(ProjectLayout projectLayout, Logger logger) { + this.projectLayout = projectLayout; this.logger = logger; } ProcessingState resolve(Iterable files) { - ProcessingState processingState = new ProcessingState(files, project); + ProcessingState processingState = new ProcessingState(files, projectLayout); while (processingState.isWorkRemaining()) { processSchemaFile(processingState, processingState.nextFileState()); } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index b411a79d398..635770e2353 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -159,19 +159,24 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { buildFile << """ |def configuredTasks = [] |tasks.configureEach { - | configuredTasks << it - |} - |gradle.buildFinished { - | println "Configured tasks: \${configuredTasks*.path}" + | println "Configured task: \${it.path}" |} |""".stripMargin() + when: def result = run("help") then: - def taskMatcher = result.output =~ /(?m)^Configured tasks: (.*)$/ - taskMatcher.find() - def configuredTasks = taskMatcher.group(1) - configuredTasks == "[:help]" + def expectedConfiguredTasks = [":help"] + if (GradleFeatures.configCache.isSupportedBy(gradleVersion)) { + // Not sure why, but when configuration caching was introduced, the base plugin started configuring the + // clean task even if it wasn't called. + expectedConfiguredTasks << ":clean" + } + def actualConfiguredTasks = [] + result.output.findAll(/(?m)^Configured task: (.*)$/) { match, taskPath -> + actualConfiguredTasks << taskPath + } + actualConfiguredTasks == expectedConfiguredTasks } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy index 62bc41dbfc2..621e0b960b6 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy @@ -117,14 +117,23 @@ abstract class FunctionalSpec extends Specification { } protected BuildResult run(String... args = ["build"]) { - return createGradleRunner().withArguments(Arrays.asList(args) + "--stacktrace").build() + return createGradleRunner().withArguments(determineGradleArguments(args)).build() } protected BuildResult runAndFail(String... args = ["build"]) { - return createGradleRunner().withArguments(Arrays.asList(args) + "--stacktrace").buildAndFail() + return createGradleRunner().withArguments(determineGradleArguments(args)).buildAndFail() } protected String buildOutputClassPath(String suffix) { return "build/classes/java/main/${suffix}" } + + private List determineGradleArguments(String... args) { + def arguments = ["--stacktrace"] + arguments.addAll(Arrays.asList(args)) + if (GradleFeatures.configCache.isSupportedBy(gradleVersion) && !arguments.contains("--no-configuration-cache")) { + arguments << "--configuration-cache" + } + return arguments + } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy index 9082c765e37..e8934f5a115 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy @@ -15,6 +15,8 @@ */ package com.commercehub.gradle.plugin.avro +import org.gradle.testkit.runner.BuildResult + import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class IntellijFunctionalSpec extends FunctionalSpec { @@ -31,7 +33,7 @@ class IntellijFunctionalSpec extends FunctionalSpec { testProjectDir.newFolder("src", "test", "avro") when: - run("idea") + runIdea() then: def moduleFile = new File(testProjectDir.root, "${testProjectDir.root.name}.iml") @@ -48,7 +50,7 @@ class IntellijFunctionalSpec extends FunctionalSpec { def "generated output directories are created by default"() { when: - def result = run("idea") + def result = runIdea() then: result.task(":idea").outcome == SUCCESS @@ -68,7 +70,7 @@ class IntellijFunctionalSpec extends FunctionalSpec { |""".stripMargin() when: - def result = run("idea") + def result = runIdea() then: result.task(":idea").outcome == SUCCESS @@ -77,4 +79,14 @@ class IntellijFunctionalSpec extends FunctionalSpec { projectFile("build/generatedMainAvro").directory projectFile("build/generatedTestAvro").directory } + + private BuildResult runIdea() { + def args = ["idea"] + if (GradleFeatures.configCache.isSupportedBy(gradleVersion)) { + // As of Gradle 6.7.1, idea plugin doesn't support configuration cache yet. + // Thus, don't try to use it in this spec. + args << "--no-configuration-cache" + } + return run(args as String[]) + } } diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy index 38d418c04ba..3a603c0bfac 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy @@ -12,7 +12,7 @@ class SchemaResolverSpec extends Specification { def setup() { project = ProjectBuilder.builder().build() - resolver = new SchemaResolver(project, project.logger) + resolver = new SchemaResolver(project.layout, project.logger) } @Unroll From ee13037914a0ea85e7917f28a29f4c2785c3783b Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Dec 2020 18:56:57 -0500 Subject: [PATCH 355/479] Make codenarc happy Fix ClosureStatementOnOpeningLineOfMultipleLineClosure violation --- .../gradle/plugin/avro/AvroPluginFunctionalSpec.groovy | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 635770e2353..10089971b45 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -174,9 +174,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { expectedConfiguredTasks << ":clean" } def actualConfiguredTasks = [] - result.output.findAll(/(?m)^Configured task: (.*)$/) { match, taskPath -> - actualConfiguredTasks << taskPath - } + result.output.findAll(/(?m)^Configured task: (.*)$/) { match, taskPath -> actualConfiguredTasks << taskPath } actualConfiguredTasks == expectedConfiguredTasks } } From 0b45c899d07298094c42244434732d98e5033c37 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 16 Dec 2020 21:01:44 -0500 Subject: [PATCH 356/479] Address not all versions of kotlin plugin supporting config cache --- .../KotlinCompatibilityFunctionalSpec.groovy | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy index e1ff6672622..1fffa8072aa 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy @@ -15,6 +15,9 @@ */ package com.commercehub.gradle.plugin.avro +import org.gradle.testkit.runner.BuildResult +import org.gradle.util.GradleVersion + @SuppressWarnings(["Println"]) class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { @SuppressWarnings(["FieldName"]) @@ -39,9 +42,22 @@ class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { copyResource("helloWorld.kt", kotlinDir) when: - def result = run("run") + def result = runBuild() then: result.output.contains("Hello, David") } + + private BuildResult runBuild() { + def args = ["run"] + if (GradleFeatures.configCache.isSupportedBy(gradleVersion)) { + // The kotlin plugin prior to 1.4.20 doesn't support the configuration cache, so we need to disable it. + // This is a bit of a mis-use of the GradleVersion class, but it's way easier than writing our own + // version comparison logic. + if (GradleVersion.version(kotlinVersion) < GradleVersion.version("1.4.20")) { + args << "--no-configuration-cache" + } + } + return run(args as String[]) + } } From 58ecb42941de21a521920f0268b9da7f1391abc8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 18 Dec 2020 10:54:49 -0500 Subject: [PATCH 357/479] version: 0.22.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 96d729a1c0e..93a2c1e967d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 0.22.0 * Add [Configuration Cache](https://docs.gradle.org/6.6/userguide/configuration_cache.html) support (#129; thanks to [dcabasson](https://github.com/dcabasson) and [eskatos](https://github.com/eskatos)) * Add coverage reporting via JaCoco/Codecov to the plugin's build pipeline * Add support for multiple IDL files with the same name in different directories (#123) diff --git a/build.gradle b/build.gradle index c28d1c5ae12..19b04f886c0 100644 --- a/build.gradle +++ b/build.gradle @@ -70,7 +70,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.21.1-SNAPSHOT" +version = "0.22.0" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From a9ae91cd1a5b0da9371e27b39909a199071521ac Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 18 Dec 2020 10:57:35 -0500 Subject: [PATCH 358/479] version: 0.23.0-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 19b04f886c0..5d9136d01eb 100644 --- a/build.gradle +++ b/build.gradle @@ -70,7 +70,7 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.22.0" +version = "0.23.0-SNAPSHOT" group = "com.commercehub.gradle.plugin" tasks.withType(AbstractArchiveTask) { From 946cf474013d4f93becaed26a3f1afc6edf88439 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 7 Feb 2021 22:43:04 -0500 Subject: [PATCH 359/479] Add link to discussions for Q&A --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..ab8e82a50a4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Discussions: Q&A + url: https://github.com/davidmc24/gradle-avro-plugin/discussions/categories/q-a + about: Please ask and answer questions here. From 37a023c3a677b8355000aa52f3f92fbe8e246e39 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 7 Feb 2021 22:47:07 -0500 Subject: [PATCH 360/479] Revert "Add link to discussions for Q&A" This reverts commit 946cf474013d4f93becaed26a3f1afc6edf88439. --- .github/ISSUE_TEMPLATE/config.yml | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index ab8e82a50a4..00000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Discussions: Q&A - url: https://github.com/davidmc24/gradle-avro-plugin/discussions/categories/q-a - about: Please ask and answer questions here. From ef5a83d359fe5b398e66b99bb4964d66e5d06600 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 7 Feb 2021 22:49:23 -0500 Subject: [PATCH 361/479] Add link to discussions for Q&A --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..ab8e82a50a4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Discussions: Q&A + url: https://github.com/davidmc24/gradle-avro-plugin/discussions/categories/q-a + about: Please ask and answer questions here. From 31ce146aa0284291dc0fcdd3a41ccf6068f66ee2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 7 Feb 2021 22:58:10 -0500 Subject: [PATCH 362/479] Add feature requests to template chooser --- .github/ISSUE_TEMPLATE/config.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index ab8e82a50a4..d7c064ecafe 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: false contact_links: - - name: Discussions: Q&A + - name: Feature requests and ideas + url: https://github.com/davidmc24/gradle-avro-plugin/discussions/categories/ideas + about: Suggest an idea for this project. + - name: Questions url: https://github.com/davidmc24/gradle-avro-plugin/discussions/categories/q-a about: Please ask and answer questions here. From c28094dabbd2adc4fab77b1973dd8e2f448815ca Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 7 Feb 2021 23:02:39 -0500 Subject: [PATCH 363/479] Try moving feature requests to discussions --- .github/ISSUE_TEMPLATE/config.yml | 4 +-- .github/ISSUE_TEMPLATE/feature_request.md | 33 ----------------------- 2 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d7c064ecafe..ffca0ecaa45 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,7 +2,7 @@ blank_issues_enabled: false contact_links: - name: Feature requests and ideas url: https://github.com/davidmc24/gradle-avro-plugin/discussions/categories/ideas - about: Suggest an idea for this project. + about: Suggest an idea for this project - name: Questions url: https://github.com/davidmc24/gradle-avro-plugin/discussions/categories/q-a - about: Please ask and answer questions here. + about: Please ask and answer questions here diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 556f72716b5..00000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- - -**Prerequisites** - -* [ ] Have you checked if the feature exists in the latest version of the plugin? (See [releases](https://github.com/davidmc24/gradle-avro-plugin/releases)) -* [ ] Did you check to see if an [issue](https://github.com/davidmc24/gradle-avro-plugin/issues) has already been submitted? -* [ ] Are you reporting to the correct repository? Requests for functionality not currently provided by the [Avro Java library](https://avro.apache.org/docs/current/gettingstartedjava.html) are better submitted to the [Apache Avro project](https://avro.apache.org/issue_tracking.html). -* [ ] Did you perform a cursory search? - -For more information, see the [CONTRIBUTING](https://github.com/davidmc24/gradle-avro-plugin/blob/master/CONTRIBUTING.md) guide. - -**Is your feature request related to a problem? Please describe.** - -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** - -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** - -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** - -Add any other context about the feature request here. From 15f1b33728009c537278f1aca5b04af73c84f2e4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 8 Feb 2021 02:48:40 -0500 Subject: [PATCH 364/479] Update README to reflect changes in historical version handling --- README.md | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 393714aec32..8d0bad1282c 100644 --- a/README.md +++ b/README.md @@ -6,26 +6,19 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility +**NOTE**: Historical versions used a different publishing process. The artifacts are still available in [GitHub Releases](https://github.com/davidmc24/gradle-avro-plugin/releases), but may use different coordinates or may no longer be available in a repository that can be directly referenced from Gradle. +Please upgrade to a modern version or self-host historical artifacts using a Maven repository such as [JFrog Artifactory](https://jfrog.com/artifactory/) or [Sonatype Nexus](https://www.sonatype.com/nexus/repository-oss). + * Currently tested against Java 8-15 * Java 15 support requires Gradle 6.7 or higher (as per Gradle's release notes) * Java 14 support requires Gradle 6.3 or higher (as per Gradle's release notes) * Java 13 support requires Gradle 6.0 or higher * Java 11 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) * Though not supported yet, tests are also run against early-access builds of Java 16 to provide early notification of potential incompatibilities - * If you need support for Java 7, version 0.16.0 was the last supported version - * If you need support for Java 6, version 0.9.1 was the last supported version; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Gradle 6.7.1 * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.7.1 - * If you need support for Gradle 4.4-5.0, version 0.18.0 was the last version tested for compatibility - * If you need support for Gradle 3.0-3.5.1 or 4.0-4.3, version 0.17.0 was the last version tested for compatibility - * If you need support for Gradle 2.0-2.14.1, version 0.9.1 was the last version tested for compatibility; please see [the Gradle plugin portal](https://plugins.gradle.org/plugin/com.commercehub.gradle.plugin.avro) * Currently built against Avro 1.10.1 * Currently tested against Avro 1.10.0-1.10.1 - * If you need support for Avro 1.9.0-1.9.2 try plugin version 0.20.0 - * If you need support for Avro 1.8.2, try plugin version 0.16.0 - * If you need support for Avro 1.8.0-1.8.1, try plugin version 0.10.0 - * If you need support for Avro 1.7.7, try plugin version 0.8.1 (updated for Gradle 5.6) - * Versions of Avro prior to 1.7.x are unlikely to work * Support for Kotlin * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.20 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 From a21c0a710e24bea3006043b0bf8a2fa45467d3ea Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 8 Feb 2021 23:06:07 -0500 Subject: [PATCH 365/479] Update notes about pre-1.0 versions --- CHANGES.md | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 3 +- 2 files changed, 152 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 93a2c1e967d..8919ce40685 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,13 @@ ## Unreleased +# Pre-1.0 Versions + +These versions used a different publishing process. They use different coordinates/packages and may no longer be available in a traditional Maven repository. It is strongly recommended to upgrade to a newer version. + +If you still need to use them, the artifacts can be downloaded from [GitHub Releases](https://github.com/davidmc24/gradle-avro-plugin/releases) or accessed via [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin). +The plugin IDs are `com.commercehub.gradle.plugin.avro` and `com.commercehub.gradle.plugin.avro-base`, with all tasks in the package `com.commercehub.gradle.plugin.avro`. + ## 0.22.0 * Add [Configuration Cache](https://docs.gradle.org/6.6/userguide/configuration_cache.html) support (#129; thanks to [dcabasson](https://github.com/dcabasson) and [eskatos](https://github.com/eskatos)) * Add coverage reporting via JaCoco/Codecov to the plugin's build pipeline @@ -13,6 +20,10 @@ * Updated compatibility testing through Gradle 6.7.1 * Updated compatibility testing through Kotlin 1.4.20 +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.22.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.22.0) + ## 0.21.0 * Built using Avro 1.10.0 * Drop support for Avro 1.9.X @@ -20,16 +31,28 @@ * Add support for `optionalGettersForNullableFieldsOnly` * Apply @Classpath annotation to classpath on `GenerateAvroProtocolTask` +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.21.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.21.0) + ## 0.20.0 * Built using Gradle 6.5 * Updated compatibility testing to include Java 14 * Updated compatibility testing through Gradle 6.5 * Add `ResolveAvroDependenciesTask` (#115) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.20.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.20.0) + ## 0.19.1 * Fix schema dependency resolution when types are referenced with a `{ "type": NAME }` block rather than just `NAME` (#107) * Eliminate `NullPointerException` handling in schema dependency resolution, as it no longer appears to be needed. +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.19.1) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.19.1) + ## 0.19.0 * Add support for Gradle 6.0-6.2.2 (#101) * Drop support for Gradle versions prior to 5.1 @@ -43,6 +66,10 @@ * Upgrade Codenarc from 1.4 to 1.5 * Preliminary Java 14 support +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.19.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.19.0) + ## 0.18.0 * Use reproducible file order for plugin archives * Eliminate usage of internal conventions API, using new Lazy Configuration approach instead; requires Gradle 4.4+ @@ -61,12 +88,20 @@ * Add support for generating getters that return Optional (#90); contribution from [bspeakmon](https://github.com/bspeakmon) * Add support for `logicalTypeFactories` and `customConversions`; fixes #92 +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.18.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.18.0) + ## 0.17.0 * Built using Avro 1.9.0 * Removed configuration setting `validateDefaults`; defaults are now always validated due to an upstream change * Java 7 is no longer supported, as Avro 1.9.0 is now Java 8+ * Began testing using Java 12 +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.17.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.17.0) + ## 0.16.0 * Built using Gradle 4.10.2 * Updated compatibility testing through Gradle 4.10.2 @@ -74,9 +109,17 @@ * Upgrade Spock from 1.0 to 1.2 * Update plugin publishing mode to address Gradle 5.0 deprecation warning +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.16.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.16.0) + ## 0.15.1 * Fix "Boolean configuration cannot be set with boolean values from Kotlin DSL" (#60) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.15.1) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.15.1) + ## 0.15.0 * Built using Gradle 4.9 * Updated compatibility testing through Gradle 4.9 @@ -84,9 +127,17 @@ * Add support for generating schema files (#56) * Fix bug where `GenerateAvroProtocolTask` can't be used without a runtime configuration +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.15.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.15.0) + ## 0.14.2 * Stop creating default generated output directories when `outputDir` is customized and IntelliJ integration is used (#52) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.14.2) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.14.2) + ## 0.14.1 * Built using Gradle 4.6 * Updated compatibility testing through Gradle 4.6 @@ -94,17 +145,33 @@ * Began testing using Kotlin 1.2.31 * Fixed infinite loop when a schema file contains multiple definitions of the same type (#47) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.14.1) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.14.1) + ## 0.14.0 * Built using Gradle 4.5 * Updated compatibility testing through Gradle 4.5 * Support for validation of default values in schema (#42) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.14.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.14.0) + ## 0.13.0 * Remove pre-cleaning behavior from `GenerateAvroJavaTask` (#41) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.13.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.13.0) + ## 0.12.0 * Improve support for Kotlin (#36) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.12.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.12.0) + ## 0.11.0 * Built using Gradle 4.2.1 * Began testing using Java 9 @@ -113,6 +180,10 @@ * Add new configuration option "enableDecimalLogicalType" to generate `BigDecimal` for fields annotated with `logicalType` equals to `decimal` * Breaking backward compatibility caused by "enableDecimalLogicalType" default value set `true`. `BigDecimal` will be used instead of old usage of `ByteBuffer` +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.11.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.11.0) + ## 0.10.0 * Drop support for Gradle 2.x * As Gradle 3.0+ has a minimum Java version requiremenet of Java 7, drop support for Java 6 @@ -122,21 +193,41 @@ * Published to [Bintray](https://bintray.com/commercehub-oss/main/gradle-avro-plugin) * MapUtils class is no longer public +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.10.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.10.0) + ## 0.9.1 * Built using Gradle 4.1 * Updated versions for cross-compatibility testing +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.9.1) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.9.1) + ## 0.9.0 * Built using Avro 1.8.1 (#23) * Built using Gradle 2.13 * Added version cross-compatibility testing +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.9.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.9.0) + ## 0.8.1 * Compatible at runtime with Gradle 5; no functional changes. Compiled with Gradle 5.6. +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.8.1) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.8.1) + ## 0.8.0 * Add support for Java 6 (#21) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.8.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.8.0) + ## 0.7.0 * Remove usage of Apache Commons IO (#19) * Add ability to retry processing of duplicate type definitions (#13) @@ -148,10 +239,18 @@ * Automatically use encoding from `JavaCompile` task as "outputCharacterEncoding", if set * Change default "outputCharacterEncoding" to system default to match `JavaCompile` task behavior (#20) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.7.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.7.0) + ## 0.6.1 * Add Checkstyle ImportControl to prevent accidentally adding dependencies on libraries that Gradle makes available for build but not runtime. * Remove usage of Guava (#18) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.6.1) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.6.1) + ## 0.6.0 * Add new configuration option "templateDirectory" to set source directory for the Avro compiler's Velocity templates. * Add new configuration option "createSetters" to allow suppressing the Avro compiler's creation of setters in created domain objects. @@ -161,10 +260,18 @@ * Added Checkstyle and Codenarc to build * Known Bug: doesn't work properly unless you manually add a dependency on guava; please upgrade to 0.6.1 +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.6.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.6.0) + ## 0.5.0 * Add support for schemas/protocols/IDL in subdirectories of `src/main/avro`, etc. (#11) * Expose original error messages from `avro-compiler` when compilation fails +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.5.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.5.0) + ## 0.4.0 * Add ability to specify fieldVisibility for generated Java source; contribution from [wooder79](https://github.com/wooder79) * Removed support for unqualified plugin ID (just "avro") @@ -172,40 +279,80 @@ * Stopped publishing to previous location on Bintray * Built against Gradle 2.6; uses [test kit](https://docs.gradle.org/current/userguide/test_kit.html) for functional testing +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.4.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.4.0) + ## 0.3.4 * Fix registration of generated sources for compilation (#8) * Change classloader handling to better support import of external dependencies (#9) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.3.4) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.3.4) + ## 0.3.3 * Fix generation of Java files from .avdl files; contribution from [viacoban](https://github.com/viacoban) +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.3.3) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.3.3) + ## 0.3.2 * Improve handling when custom buildDir is used +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.3.2) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.3.2) + ## 0.3.1 * Fix extension support for configuring encoding * Make default encoding UTF-8 +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.3.1) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.3.1) + ## 0.3.0 * IntelliJ: register generated source directories even if they don't already exist. * Add avro-base plugin, which exposes tasks and the extension without creating tasks, defaults, etc. * Add support for configuring encoding +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.3.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.3.0) + ## 0.2.0 * Build against Gradle 1.12 * Compile using Avro 1.7.6 * Support for qualified plugin ID * Deprecate unqualified plugin ID +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.2.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.2.0) + ## 0.1.3 * Always regenerate all Java classes when any schema file changes to avoid some classes having outdated schema information. +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.1.3) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.1.3) + ## 0.1.2 * Eliminate dependency on guava, make dependency on commons-io explicit +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.1.2) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.1.2) + ## 0.1.1 * Fixed NullPointerException when performing clean builds +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.1.1) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.1.1) + ## 0.1.0 * Add support for converting IDL files to JSON protocol declaration files * Add support for generating Java classes from JSON protocol declaration files @@ -213,3 +360,7 @@ * Add support for inter-dependent JSON schema declaration files * Add support for tweaking source/exclude directories in IntelliJ * Add support for specifying the string type to use in generated classes + +Links: +* [Release](https://github.com/davidmc24/gradle-avro-plugin/releases/tag/0.1.0) +* [JitPack](https://jitpack.io/#davidmc24/gradle-avro-plugin/0.1.0) diff --git a/README.md b/README.md index 8d0bad1282c..ba688404c9e 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav # Compatibility -**NOTE**: Historical versions used a different publishing process. The artifacts are still available in [GitHub Releases](https://github.com/davidmc24/gradle-avro-plugin/releases), but may use different coordinates or may no longer be available in a repository that can be directly referenced from Gradle. -Please upgrade to a modern version or self-host historical artifacts using a Maven repository such as [JFrog Artifactory](https://jfrog.com/artifactory/) or [Sonatype Nexus](https://www.sonatype.com/nexus/repository-oss). +**NOTE**: Pre-1.0 versions used a different publishing process/namespace. It is strongly recommended to upgrade to a newer version. Further details can be found in the [change log](CHANGES.md). * Currently tested against Java 8-15 * Java 15 support requires Gradle 6.7 or higher (as per Gradle's release notes) From 8c2d2e612b1f887b0aad1b37af8945d7ca0e0311 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 9 Feb 2021 00:27:36 -0500 Subject: [PATCH 366/479] Work towards a 1.0 release --- .github/workflows/publish.yml | 18 +++++ CHANGES.md | 3 + README.md | 27 ++++--- RELEASING.md | 6 +- build.gradle | 81 ++++++++++--------- config/checkstyle/import-control.xml | 4 +- .../gradle/plugin/avro/AvroBasePlugin.java | 8 +- .../gradle/plugin/avro/AvroExtension.java | 2 +- .../gradle/plugin/avro/AvroPlugin.java | 23 +++--- .../gradle/plugin/avro/AvroUtils.java | 9 +-- .../gradle/plugin/avro/Constants.java | 2 +- .../plugin/avro/DefaultAvroExtension.java | 31 +++---- .../davidmc24}/gradle/plugin/avro/Enums.java | 2 +- .../gradle/plugin/avro/FileExtensionSpec.java | 2 +- .../gradle/plugin/avro/FileState.java | 2 +- .../gradle/plugin/avro/FileUtils.java | 2 +- .../gradle/plugin/avro/FilenameUtils.java | 2 +- .../plugin/avro/GenerateAvroJavaTask.java | 46 ++++------- .../plugin/avro/GenerateAvroProtocolTask.java | 4 +- .../plugin/avro/GenerateAvroSchemaTask.java | 8 +- .../plugin/avro/GradleCompatibility.java | 2 +- .../gradle/plugin/avro/GradleFeatures.java | 2 +- .../gradle/plugin/avro/GradleVersions.java | 2 +- .../gradle/plugin/avro/MapUtils.java | 2 +- .../gradle/plugin/avro/OutputDirTask.java | 2 +- .../gradle/plugin/avro/ProcessingState.java | 2 +- .../avro/ResolveAvroDependenciesTask.java | 8 +- .../gradle/plugin/avro/SchemaResolver.java | 6 +- .../gradle/plugin/avro/SetBuilder.java | 2 +- .../gradle/plugin/avro/Strings.java | 2 +- .../gradle/plugin/avro/TypeState.java | 2 +- .../avro/AvroBasePluginFunctionalSpec.groovy | 14 ++-- .../avro/AvroPluginFunctionalSpec.groovy | 2 +- .../gradle/plugin/avro/AvroPluginSpec.groovy | 2 +- .../gradle/plugin/avro/AvroUtilsSpec.groovy | 6 +- .../BuildCacheSupportFunctionalSpec.groovy | 4 +- .../CustomConversionFunctionalSpec.groovy | 22 ++--- .../DuplicateHandlingFunctionalSpec.groovy | 2 +- .../plugin/avro/EncodingFunctionalSpec.groovy | 4 +- .../avro/EnumHandlingFunctionalSpec.groovy | 2 +- .../plugin/avro/ExamplesFunctionalSpec.groovy | 2 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 6 +- ...erateAvroProtocolTaskFunctionalSpec.groovy | 4 +- .../plugin/avro/IntellijFunctionalSpec.groovy | 2 +- .../KotlinCompatibilityFunctionalSpec.groovy | 2 +- ...otlinDSLCompatibilityFunctionalSpec.groovy | 4 +- .../plugin/avro/OptionsFunctionalSpec.groovy | 4 +- ...eAvroDependenciesTaskFunctionalSpec.groovy | 4 +- .../plugin/avro/SchemaResolverSpec.groovy | 16 ++-- .../gradle/plugin/avro/StringsSpec.groovy | 2 +- .../avro/test/custom/TimeZoneConversion.java | 2 +- .../avro/test/custom/TimeZoneLogicalType.java | 2 +- .../custom/TimeZoneLogicalTypeFactory.java | 2 +- .../gradle/plugin/avro/Message.avsc | 0 .../gradle/plugin/avro/customConversion.avpr | 0 .../gradle/plugin/avro/customConversion.avsc | 0 .../gradle/plugin/avro/dependent.avdl | 0 .../gradle/plugin/avro/duplicate/Cat.avsc | 0 .../plugin/avro/duplicate/ContainsFixed1.avsc | 0 .../plugin/avro/duplicate/ContainsFixed2.avsc | 0 .../plugin/avro/duplicate/ContainsFixed3.avsc | 0 .../gradle/plugin/avro/duplicate/Dog.avsc | 0 .../gradle/plugin/avro/duplicate/Fish.avsc | 0 .../gradle/plugin/avro/duplicate/Person.avsc | 0 .../gradle/plugin/avro/duplicate/Spider.avsc | 0 .../avro/duplicate/duplicateInSingleFile.avsc | 0 .../gradle/plugin/avro/enumField.avsc | 0 .../gradle/plugin/avro/enumMalformed.avsc | 0 .../gradle/plugin/avro/enumSimple.avsc | 0 .../gradle/plugin/avro/enumUnion.avsc | 0 .../gradle/plugin/avro/enumUseSimple.avsc | 0 .../gradle/plugin/avro/helloWorld.kt | 0 .../davidmc24}/gradle/plugin/avro/idioma.avsc | 0 .../gradle/plugin/avro/interop.avdl | 0 .../davidmc24}/gradle/plugin/avro/mail.avpr | 0 .../plugin/avro/namespaced-idl/v1/test.avdl | 0 .../plugin/avro/namespaced-idl/v2/test.avdl | 0 .../davidmc24}/gradle/plugin/avro/record.vm | 0 .../davidmc24}/gradle/plugin/avro/shared.avdl | 0 .../davidmc24}/gradle/plugin/avro/user.avsc | 0 test-project/build.gradle | 2 +- 81 files changed, 211 insertions(+), 215 deletions(-) create mode 100644 .github/workflows/publish.yml rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/AvroBasePlugin.java (84%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/AvroExtension.java (97%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/AvroPlugin.java (90%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/AvroUtils.java (89%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/Constants.java (98%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/DefaultAvroExtension.java (84%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/Enums.java (95%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/FileExtensionSpec.java (96%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/FileState.java (97%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/FileUtils.java (99%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/FilenameUtils.java (99%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/GenerateAvroJavaTask.java (86%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/GenerateAvroProtocolTask.java (96%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/GenerateAvroSchemaTask.java (92%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/GradleCompatibility.java (96%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/GradleFeatures.java (96%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/GradleVersions.java (94%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/MapUtils.java (95%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/OutputDirTask.java (97%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/ProcessingState.java (98%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/ResolveAvroDependenciesTask.java (91%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/SchemaResolver.java (94%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/SetBuilder.java (96%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/Strings.java (96%) rename src/main/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/TypeState.java (96%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy (86%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy (99%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/AvroPluginSpec.groovy (98%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/AvroUtilsSpec.groovy (93%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy (96%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy (89%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy (99%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/EncodingFunctionalSpec.groovy (96%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy (98%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/ExamplesFunctionalSpec.groovy (97%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/FunctionalSpec.groovy (96%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy (95%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/IntellijFunctionalSpec.groovy (98%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy (98%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy (94%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/OptionsFunctionalSpec.groovy (99%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy (89%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/SchemaResolverSpec.groovy (91%) rename src/test/groovy/com/{commercehub => github/davidmc24}/gradle/plugin/avro/StringsSpec.groovy (96%) rename src/test/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/test/custom/TimeZoneConversion.java (96%) rename src/test/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java (95%) rename src/test/java/com/{commercehub => github/davidmc24}/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java (93%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/Message.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/customConversion.avpr (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/customConversion.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/dependent.avdl (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/duplicate/Cat.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/duplicate/ContainsFixed1.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/duplicate/ContainsFixed2.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/duplicate/ContainsFixed3.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/duplicate/Dog.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/duplicate/Fish.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/duplicate/Person.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/duplicate/Spider.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/enumField.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/enumMalformed.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/enumSimple.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/enumUnion.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/enumUseSimple.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/helloWorld.kt (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/idioma.avsc (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/interop.avdl (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/mail.avpr (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/namespaced-idl/v1/test.avdl (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/namespaced-idl/v2/test.avdl (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/record.vm (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/shared.avdl (100%) rename src/test/resources/com/{commercehub => github/davidmc24}/gradle/plugin/avro/user.avsc (100%) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000000..aae2a0b7fc1 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,18 @@ +name: Publish package to the Maven Central Repository +on: + release: + types: [created] +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Java + uses: actions/setup-java@v1 + with: + java-version: 8 + - name: Publish package + run: ./gradlew publish + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} diff --git a/CHANGES.md b/CHANGES.md index 8919ce40685..5df446b2f73 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,9 @@ # Change Log ## Unreleased +* Published to Maven Central (no longer published to JCenter) +* New plugin IDs: `com.github.davidmc24.gradle.plugin.avro` and `com.github.davidmc24.gradle.plugin.avro-base` +* New package for tasks: `com.github.davidmc24.gradle.plugin.avro` # Pre-1.0 Versions diff --git a/README.md b/README.md index ba688404c9e..04d1cec25a3 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ pluginManagement { `build.gradle`: ```groovy plugins { - id "com.commercehub.gradle.plugin.avro" version "VERSION" + id "com.github.davidmc24.gradle.plugin.avro" version "VERSION" } ``` @@ -232,19 +232,21 @@ If you do it in the other order, IntelliJ may not properly exclude some director # Alternate Usage If the defaults used by the plugin don't work for you, you can still use the tasks by themselves. -In this case, use the `com.commercehub.gradle.plugin.avro-base` plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. +In this case, use the `com.github.davidmc24.gradle.plugin.avro-base` plugin instead, and create tasks of type `GenerateAvroJavaTask` and/or `GenerateAvroProtocolTask`. Here's a short example of what this might look like: ```groovy +import com.github.davidmc24.gradle.plugin.avro.GenerateAvroJavaTask + apply plugin: "java" -apply plugin: "com.commercehub.gradle.plugin.avro-base" +apply plugin: "com.github.davidmc24.gradle.plugin.avro-base" dependencies { implementation "org.apache.avro:avro:1.10.1" } -def generateAvro = tasks.register("generateAvro", com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { +def generateAvro = tasks.register("generateAvro", GenerateAvroJavaTask) { source("src/avro") outputDir = file("dest/avro") } @@ -331,7 +333,7 @@ In `gradle.build.kts` add: ```kotlin plugins { // Find latest release here: https://github.com/davidmc24/gradle-avro-plugin/releases - id("com.commercehub.gradle.plugin.avro") version "VERSION" + id("com.github.davidmc24.gradle.plugin.avro") version "VERSION" } ``` @@ -370,9 +372,11 @@ If desired, you can generate JSON schema with dependencies resolved. Example build: ```groovy -apply plugin: "com.commercehub.gradle.plugin.avro-base" +import com.github.davidmc24.gradle.plugin.avro.ResolveAvroDependenciesTask + +apply plugin: "com.github.davidmc24.gradle.plugin.avro-base" -tasks.register("resolveAvroDependencies", com.commercehub.gradle.plugin.avro.ResolveAvroDependenciesTask) { +tasks.register("resolveAvroDependencies", ResolveAvroDependenciesTask) { source file("src/avro/normalized") outputDir = file("build/avro/resolved") } @@ -388,15 +392,18 @@ From IDL files, first use `GenerateAvroProtocolTask` to convert the IDL files to Example using base plugin with support for both IDL and JSON protocol files in `src/main/avro`: ```groovy -apply plugin: "com.commercehub.gradle.plugin.avro-base" +import com.github.davidmc24.gradle.plugin.avro.GenerateAvroProtocolTask +import com.github.davidmc24.gradle.plugin.avro.GenerateAvroSchemaTask + +apply plugin: "com.github.davidmc24.gradle.plugin.avro-base" -def generateProtocol = tasks.register("generateProtocol", com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { +def generateProtocol = tasks.register("generateProtocol", GenerateAvroProtocolTask) { source file("src/main/avro") include("**/*.avdl") outputDir = file("build/generated-avro-main-avpr") } -tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { +tasks.register("generateSchema", GenerateAvroSchemaTask) { dependsOn generateProtocol source file("src/main/avro") source file("build/generated-avro-main-avpr") diff --git a/RELEASING.md b/RELEASING.md index 54b58fe0471..f0a540cdea1 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,14 +1,12 @@ # Release Process -1. Acquire permissions to publish the package to Bintray and set the keys "bintrayUserName" and "bintrayApiKey" in `~/.gradle/gradle.properties`. 1. Update `CHANGES.md` 1. Ensure that there is a milestone for the version, and that appropriate issues are associated with the milestone. 1. Update the plugin version in `build.gradle` under "version" 1. Commit and tag with the version number (don't push yet) -1. Run `./gradlew clean bintrayUpload` -1. Go to the [Bintray page](https://bintray.com/commercehub-oss/main/gradle-avro-plugin), verify the files, and click "Publish". +1. Run `./gradlew clean build` to make sure it looks good. 1. Update the version in `build.gradle` to the next SNAPSHOT and commit. 1. Push 1. If there was a issue requesting the release, close it. 1. Close the milestone. -1. Go to the [GitHub Releases page](https://github.com/davidmc24/gradle-avro-plugin/releases), click "Draft a new release", select the tag version, use the version number as the title, copy the relevant segment from `CHANGES.md` into the description, and click "Publish release". +1. Go to the [GitHub Releases page](https://github.com/davidmc24/gradle-avro-plugin/releases), click "Draft a new release", select the tag version, use the version number as the title, copy the relevant segment from `CHANGES.md` into the description, and click "Publish release". This will trigger the CI job that does the actual publishing. diff --git a/build.gradle b/build.gradle index 5d9136d01eb..9bd4238c26f 100644 --- a/build.gradle +++ b/build.gradle @@ -8,12 +8,11 @@ plugins { id "jacoco" id "maven-publish" id "java-gradle-plugin" - id "com.jfrog.bintray" version "1.8.1" id "org.nosphere.gradle.github.actions" version "1.2.0" } repositories { - jcenter() + mavenCentral() maven { // Used for snapshot builds for some libraries name 'Sonatype OSS' @@ -70,8 +69,9 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -version = "0.23.0-SNAPSHOT" -group = "com.commercehub.gradle.plugin" +group = "com.github.davidmc24.gradle.plugin" +version = "1.0.0-SNAPSHOT" +def isSnapshot = version.endsWith('-SNAPSHOT') tasks.withType(AbstractArchiveTask) { preserveFileTimestamps = false @@ -91,50 +91,57 @@ task javadocJar(type: Jar, dependsOn: javadoc) { } publishing { - publications { - mainMaven(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar + publications.withType(MavenPublication) { +// from components.java + artifact sourcesJar + artifact javadocJar + pom { + name = "gradle-avro-plugin" + description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." + url = "https://github.com/davidmc24/gradle-avro-plugin" + licenses { + license { + name = "The Apache License, Version 2.0" + url = "http://www.apache.org/licenses/LICENSE-2.0.txt" + } + } + developers { + developer { + id = 'davidmc24' + name = 'David M. Carr' + email = 'david@carrclan.us' + } + } + scm { + connection = 'scm:git:https://github.com/davidmc24/gradle-avro-plugin.git' + developerConnection = 'scm:git:ssh://github.com/davidmc24/gradle-avro-plugin.git' + url = 'https://github.com/davidmc24/gradle-avro-plugin' + } } } -} - -bintray { - // dryRun = true - // publish = true - user = project.hasProperty("bintrayUserName") ? bintrayUserName : null - key = project.hasProperty("bintrayApiKey") ? bintrayApiKey : null - publications = ["mainMaven", "avroBasePluginMarkerMaven", "avroPluginMarkerMaven"] - pkg { - repo = "main" - name = project.name - userOrg = "commercehub-oss" - licenses = ["Apache-2.0"] - desc = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." - websiteUrl = "https://github.com/davidmc24/gradle-avro-plugin" - issueTrackerUrl = 'https://github.com/davidmc24/gradle-avro-plugin/issues' - vcsUrl = "https://github.com/davidmc24/gradle-avro-plugin" - labels = ["serialization", "avro"] - githubRepo = "davidmc24/gradle-avro-plugin" - version { - name = project.version - vcsTag = project.version + repositories { + maven { + def snapshotUrl = "https://oss.sonatype.org/content/repositories/snapshots/" + def releaseUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + name = "OSSRH" + url = isSnapshot ? snapshotUrl : releaseUrl + credentials { + username = System.getenv("MAVEN_USERNAME") + password = System.getenv("MAVEN_PASSWORD") + } } } } -bintrayUpload.dependsOn build, { generatePomFileForAvroBasePluginMarkerMavenPublication }, { generatePomFileForAvroPluginMarkerMavenPublication } - gradlePlugin { plugins { avro { - id = "com.commercehub.gradle.plugin.avro" - implementationClass = "com.commercehub.gradle.plugin.avro.AvroPlugin" + id = "com.github.davidmc24.gradle.plugin.avro" + implementationClass = "com.github.davidmc24.gradle.plugin.avro.AvroPlugin" } avroBase { - id = "com.commercehub.gradle.plugin.avro-base" - implementationClass = "com.commercehub.gradle.plugin.avro.AvroBasePlugin" + id = "com.github.davidmc24.gradle.plugin.avro-base" + implementationClass = "com.github.davidmc24.gradle.plugin.avro.AvroBasePlugin" } } } diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index f5be6beb488..920e5ea3e29 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -1,8 +1,8 @@ - - + + diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java similarity index 84% rename from src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java index b9b9932c61c..6fe6f7cfc8e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java @@ -13,14 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import org.gradle.api.Plugin; import org.gradle.api.Project; -import static com.commercehub.gradle.plugin.avro.Constants.AVRO_EXTENSION_NAME; -import static com.commercehub.gradle.plugin.avro.GradleCompatibility.createExtensionWithObjectFactory; - public class AvroBasePlugin implements Plugin { @Override public void apply(final Project project) { @@ -28,7 +25,8 @@ public void apply(final Project project) { } private static void configureExtension(final Project project) { - final AvroExtension avroExtension = createExtensionWithObjectFactory(project, AVRO_EXTENSION_NAME, DefaultAvroExtension.class); + final AvroExtension avroExtension = + GradleCompatibility.createExtensionWithObjectFactory(project, Constants.AVRO_EXTENSION_NAME, DefaultAvroExtension.class); project.getTasks().withType(GenerateAvroJavaTask.class).configureEach(task -> { task.getOutputCharacterEncoding().convention(avroExtension.getOutputCharacterEncoding()); task.getStringType().convention(avroExtension.getStringType()); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java similarity index 97% rename from src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java index 543cb568c00..bd5b817cb06 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import org.apache.avro.Conversion; import org.apache.avro.LogicalTypes; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java similarity index 90% rename from src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java index 45a2e4058b7..313f44d45a5 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.io.FileFilter; @@ -34,11 +34,6 @@ import org.gradle.plugins.ide.idea.IdeaPlugin; import org.gradle.plugins.ide.idea.model.IdeaModule; -import static com.commercehub.gradle.plugin.avro.Constants.GROUP_SOURCE_GENERATION; -import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.JAVA_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; import static org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME; public class AvroPlugin implements Plugin { @@ -66,12 +61,12 @@ private static void configureIntelliJ(final Project project) { module.setSourceDirs(new SetBuilder() .addAll(module.getSourceDirs()) .add(getAvroSourceDir(project, mainSourceSet)) - .add(getGeneratedOutputDir(project, mainSourceSet, JAVA_EXTENSION).map(Directory::getAsFile).get()) + .add(getGeneratedOutputDir(project, mainSourceSet, Constants.JAVA_EXTENSION).map(Directory::getAsFile).get()) .build()); module.setTestSourceDirs(new SetBuilder() .addAll(module.getTestSourceDirs()) .add(getAvroSourceDir(project, testSourceSet)) - .add(getGeneratedOutputDir(project, testSourceSet, JAVA_EXTENSION).map(Directory::getAsFile).get()) + .add(getGeneratedOutputDir(project, testSourceSet, Constants.JAVA_EXTENSION).map(Directory::getAsFile).get()) .build()); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. @@ -95,11 +90,11 @@ private static TaskProvider configureProtocolGeneratio return project.getTasks().register(taskName, GenerateAvroProtocolTask.class, task -> { task.setDescription( String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName())); - task.setGroup(GROUP_SOURCE_GENERATION); + task.setGroup(Constants.GROUP_SOURCE_GENERATION); task.source(getAvroSourceDir(project, sourceSet)); - task.include("**/*." + IDL_EXTENSION); + task.include("**/*." + Constants.IDL_EXTENSION); task.setClasspath(project.getConfigurations().getByName(RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION)); + task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, Constants.PROTOCOL_EXTENSION)); }); } @@ -109,11 +104,11 @@ private static TaskProvider configureJavaGenerationTask(fi TaskProvider javaTaskProvider = project.getTasks().register(taskName, GenerateAvroJavaTask.class, task -> { task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.", sourceSet.getName())); - task.setGroup(GROUP_SOURCE_GENERATION); + task.setGroup(Constants.GROUP_SOURCE_GENERATION); task.source(getAvroSourceDir(project, sourceSet)); task.source(protoTaskProvider); - task.include("**/*." + SCHEMA_EXTENSION, "**/*." + PROTOCOL_EXTENSION); - task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION)); + task.include("**/*." + Constants.SCHEMA_EXTENSION, "**/*." + Constants.PROTOCOL_EXTENSION); + task.getOutputDir().convention(getGeneratedOutputDir(project, sourceSet, Constants.JAVA_EXTENSION)); sourceSet.getJava().srcDir(task.getOutputDir()); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroUtils.java similarity index 89% rename from src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroUtils.java index 28431e8954b..a753ffc7ab2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/AvroUtils.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroUtils.java @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.util.ArrayList; import java.util.List; @@ -6,9 +6,6 @@ import org.apache.avro.Protocol; import org.apache.avro.Schema; -import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; - /** * Utility method for working with Avro objects. */ @@ -40,7 +37,7 @@ private AvroUtils() { } * @return a file path */ static String assemblePath(Schema schema) { - return assemblePath(schema.getNamespace(), schema.getName(), SCHEMA_EXTENSION); + return assemblePath(schema.getNamespace(), schema.getName(), Constants.SCHEMA_EXTENSION); } /** @@ -50,7 +47,7 @@ static String assemblePath(Schema schema) { * @return a file path */ static String assemblePath(Protocol protocol) { - return assemblePath(protocol.getNamespace(), protocol.getName(), PROTOCOL_EXTENSION); + return assemblePath(protocol.getNamespace(), protocol.getName(), Constants.PROTOCOL_EXTENSION); } /** diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java similarity index 98% rename from src/main/java/com/commercehub/gradle/plugin/avro/Constants.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java index 12287665f67..3ac50152c6e 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.util.Collections; import java.util.List; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java similarity index 84% rename from src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java index 43f31cc1a32..9b78c3dd31b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.nio.charset.Charset; import java.util.Map; @@ -28,16 +28,6 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_OPTIONAL_GETTERS; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CUSTOM_CONVERSIONS; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_LOGICAL_TYPE_FACTORIES; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; - @SuppressWarnings({"unused", "WeakerAccess"}) public class DefaultAvroExtension implements AvroExtension { private final Property outputCharacterEncoding; @@ -55,18 +45,19 @@ public class DefaultAvroExtension implements AvroExtension { @Inject public DefaultAvroExtension(ObjectFactory objects) { this.outputCharacterEncoding = objects.property(String.class); - this.stringType = objects.property(String.class).convention(DEFAULT_STRING_TYPE); - this.fieldVisibility = objects.property(String.class).convention(DEFAULT_FIELD_VISIBILITY); + this.stringType = objects.property(String.class).convention(Constants.DEFAULT_STRING_TYPE); + this.fieldVisibility = objects.property(String.class).convention(Constants.DEFAULT_FIELD_VISIBILITY); this.templateDirectory = objects.property(String.class); - this.createSetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_SETTERS); - this.createOptionalGetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_OPTIONAL_GETTERS); - this.gettersReturnOptional = objects.property(Boolean.class).convention(DEFAULT_GETTERS_RETURN_OPTIONAL); + this.createSetters = objects.property(Boolean.class).convention(Constants.DEFAULT_CREATE_SETTERS); + this.createOptionalGetters = objects.property(Boolean.class).convention(Constants.DEFAULT_CREATE_OPTIONAL_GETTERS); + this.gettersReturnOptional = objects.property(Boolean.class).convention(Constants.DEFAULT_GETTERS_RETURN_OPTIONAL); this.optionalGettersForNullableFieldsOnly = objects.property(Boolean.class) - .convention(DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY); - this.enableDecimalLogicalType = objects.property(Boolean.class).convention(DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); + .convention(Constants.DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY); + this.enableDecimalLogicalType = objects.property(Boolean.class).convention(Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) - .convention(DEFAULT_LOGICAL_TYPE_FACTORIES); - this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(DEFAULT_CUSTOM_CONVERSIONS); + .convention(Constants.DEFAULT_LOGICAL_TYPE_FACTORIES); + this.customConversions = + objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(Constants.DEFAULT_CUSTOM_CONVERSIONS); } @Override diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Enums.java similarity index 95% rename from src/main/java/com/commercehub/gradle/plugin/avro/Enums.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/Enums.java index 9d6c77fe56f..252e7f3f6ad 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Enums.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Enums.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.util.Arrays; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileExtensionSpec.java similarity index 96% rename from src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/FileExtensionSpec.java index 5842861efae..a9545a86d85 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileExtensionSpec.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileExtensionSpec.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.util.Arrays; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileState.java similarity index 97% rename from src/main/java/com/commercehub/gradle/plugin/avro/FileState.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/FileState.java index dc4b1ce647e..e65243ff889 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileState.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileState.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.util.Set; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileUtils.java similarity index 99% rename from src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/FileUtils.java index 11e0bded3c5..a7266ead0bc 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FileUtils.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileUtils.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.io.FileOutputStream; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/FilenameUtils.java similarity index 99% rename from src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/FilenameUtils.java index 875f54a99ac..dae1e0c38b6 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/FilenameUtils.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/FilenameUtils.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; /** * General filename and filepath manipulation utilities. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java similarity index 86% rename from src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java index 789a13ea2f7..366a3c56f29 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.io.IOException; @@ -44,20 +44,6 @@ import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.TaskAction; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_OPTIONAL_GETTERS; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CREATE_SETTERS; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_CUSTOM_CONVERSIONS; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_FIELD_VISIBILITY; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_GETTERS_RETURN_OPTIONAL; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_LOGICAL_TYPE_FACTORIES; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY; -import static com.commercehub.gradle.plugin.avro.Constants.DEFAULT_STRING_TYPE; -import static com.commercehub.gradle.plugin.avro.Constants.OPTION_FIELD_VISIBILITY; -import static com.commercehub.gradle.plugin.avro.Constants.OPTION_STRING_TYPE; -import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; -import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; - /** * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and * {@link SpecificCompiler}. @@ -65,7 +51,8 @@ @SuppressWarnings("WeakerAccess") @CacheableTask public class GenerateAvroJavaTask extends OutputDirTask { - private static Set SUPPORTED_EXTENSIONS = new SetBuilder().add(PROTOCOL_EXTENSION).add(SCHEMA_EXTENSION).build(); + private static Set SUPPORTED_EXTENSIONS = + new SetBuilder().add(Constants.PROTOCOL_EXTENSION).add(Constants.SCHEMA_EXTENSION).build(); private final Property outputCharacterEncoding; private final Property stringType; @@ -89,22 +76,23 @@ public class GenerateAvroJavaTask extends OutputDirTask { public GenerateAvroJavaTask(ObjectFactory objects) { super(); this.outputCharacterEncoding = objects.property(String.class); - this.stringType = objects.property(String.class).convention(DEFAULT_STRING_TYPE); - this.fieldVisibility = objects.property(String.class).convention(DEFAULT_FIELD_VISIBILITY); + this.stringType = objects.property(String.class).convention(Constants.DEFAULT_STRING_TYPE); + this.fieldVisibility = objects.property(String.class).convention(Constants.DEFAULT_FIELD_VISIBILITY); this.templateDirectory = objects.property(String.class); - this.createOptionalGetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_OPTIONAL_GETTERS); - this.gettersReturnOptional = objects.property(Boolean.class).convention(DEFAULT_GETTERS_RETURN_OPTIONAL); + this.createOptionalGetters = objects.property(Boolean.class).convention(Constants.DEFAULT_CREATE_OPTIONAL_GETTERS); + this.gettersReturnOptional = objects.property(Boolean.class).convention(Constants.DEFAULT_GETTERS_RETURN_OPTIONAL); this.optionalGettersForNullableFieldsOnly = objects.property(Boolean.class) - .convention(DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY); - this.createSetters = objects.property(Boolean.class).convention(DEFAULT_CREATE_SETTERS); - this.enableDecimalLogicalType = objects.property(Boolean.class).convention(DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); + .convention(Constants.DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY); + this.createSetters = objects.property(Boolean.class).convention(Constants.DEFAULT_CREATE_SETTERS); + this.enableDecimalLogicalType = objects.property(Boolean.class).convention(Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); this.stringTypeProvider = getStringType() - .map(input -> Enums.parseCaseInsensitive(OPTION_STRING_TYPE, StringType.values(), input)); + .map(input -> Enums.parseCaseInsensitive(Constants.OPTION_STRING_TYPE, StringType.values(), input)); this.fieldVisibilityProvider = getFieldVisibility() - .map(input -> Enums.parseCaseInsensitive(OPTION_FIELD_VISIBILITY, FieldVisibility.values(), input)); + .map(input -> Enums.parseCaseInsensitive(Constants.OPTION_FIELD_VISIBILITY, FieldVisibility.values(), input)); this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) - .convention(DEFAULT_LOGICAL_TYPE_FACTORIES); - this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(DEFAULT_CUSTOM_CONVERSIONS); + .convention(Constants.DEFAULT_LOGICAL_TYPE_FACTORIES); + this.customConversions = + objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(Constants.DEFAULT_CUSTOM_CONVERSIONS); this.projectLayout = getProject().getLayout(); this.resolver = new SchemaResolver(projectLayout, getLogger()); } @@ -295,7 +283,7 @@ private void processFiles() { private int processProtoFiles() { int processedFileCount = 0; - for (File sourceFile : filterSources(new FileExtensionSpec(PROTOCOL_EXTENSION))) { + for (File sourceFile : filterSources(new FileExtensionSpec(Constants.PROTOCOL_EXTENSION))) { processProtoFile(sourceFile); processedFileCount++; } @@ -312,7 +300,7 @@ private void processProtoFile(File sourceFile) { } private int processSchemaFiles() { - Set files = filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles(); + Set files = filterSources(new FileExtensionSpec(Constants.SCHEMA_EXTENSION)).getFiles(); ProcessingState processingState = resolver.resolve(files); for (File file : files) { String path = FileUtils.projectRelativePath(projectLayout, file); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java similarity index 96% rename from src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java index f08a0625938..9ae839e25b2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.io.IOException; @@ -32,7 +32,7 @@ import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.TaskAction; -import static com.commercehub.gradle.plugin.avro.Constants.IDL_EXTENSION; +import static com.github.davidmc24.gradle.plugin.avro.Constants.IDL_EXTENSION; /** * Task to convert Avro IDL files into Avro protocol files using {@link Idl}. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroSchemaTask.java similarity index 92% rename from src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroSchemaTask.java index a5267ed55b9..fe51733788b 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GenerateAvroSchemaTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroSchemaTask.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.io.IOException; @@ -25,8 +25,6 @@ import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.TaskAction; -import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION; - @CacheableTask public class GenerateAvroSchemaTask extends OutputDirTask { @TaskAction @@ -37,7 +35,7 @@ protected void process() { } private void failOnUnsupportedFiles() { - FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(PROTOCOL_EXTENSION))); + FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(Constants.PROTOCOL_EXTENSION))); if (!unsupportedFiles.isEmpty()) { throw new GradleException( String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); @@ -46,7 +44,7 @@ private void failOnUnsupportedFiles() { private void processFiles() { int processedFileCount = 0; - for (File sourceFile : filterSources(new FileExtensionSpec(PROTOCOL_EXTENSION))) { + for (File sourceFile : filterSources(new FileExtensionSpec(Constants.PROTOCOL_EXTENSION))) { processProtoFile(sourceFile); processedFileCount++; } diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java similarity index 96% rename from src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java index df2d7b08e17..5d0bc9bfea9 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java similarity index 96% rename from src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java index d75f104b4d6..09e851c74ab 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleFeatures.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import org.gradle.util.GradleVersion; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java similarity index 94% rename from src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java index 25a6638c089..bca78419f67 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/GradleVersions.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import org.gradle.util.GradleVersion; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/MapUtils.java similarity index 95% rename from src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/MapUtils.java index e784770a043..70e75dc0eb8 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/MapUtils.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/MapUtils.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/OutputDirTask.java similarity index 97% rename from src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/OutputDirTask.java index 7eefeed4693..6eab997caca 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/OutputDirTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/OutputDirTask.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import javax.annotation.Nonnull; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/ProcessingState.java similarity index 98% rename from src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/ProcessingState.java index 45206c3c412..9d9f905243d 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ProcessingState.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/ProcessingState.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.util.HashMap; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTask.java similarity index 91% rename from src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTask.java index f1560c35d55..9edd68d2644 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTask.java @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.io.IOException; @@ -10,8 +10,6 @@ import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.TaskAction; -import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION; - /** * Task to read Avro schema files, resolve their dependencies, and write out dependency-free Avro schema files. */ @@ -27,7 +25,7 @@ protected void process() { } private void failOnUnsupportedFiles() { - FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(SCHEMA_EXTENSION))); + FileCollection unsupportedFiles = filterSources(new NotSpec<>(new FileExtensionSpec(Constants.SCHEMA_EXTENSION))); if (!unsupportedFiles.isEmpty()) { throw new GradleException( String.format("Unsupported file extension for the following files: %s", unsupportedFiles)); @@ -40,7 +38,7 @@ private void processFiles() { } private int processSchemaFiles() { - Set inputFiles = filterSources(new FileExtensionSpec(SCHEMA_EXTENSION)).getFiles(); + Set inputFiles = filterSources(new FileExtensionSpec(Constants.SCHEMA_EXTENSION)).getFiles(); ProcessingState processingState = resolver.resolve(inputFiles); for (Schema schema : processingState.getSchemas()) { try { diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/SchemaResolver.java similarity index 94% rename from src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/SchemaResolver.java index 933a053607a..59f60def7ea 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SchemaResolver.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/SchemaResolver.java @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.io.File; import java.io.IOException; @@ -12,8 +12,6 @@ import org.gradle.api.file.ProjectLayout; import org.gradle.api.logging.Logger; -import static com.commercehub.gradle.plugin.avro.MapUtils.asymmetricDifference; - class SchemaResolver { private static Pattern ERROR_UNKNOWN_TYPE = Pattern.compile("(?i).*(undefined name|not a defined name|type not supported).*"); private static Pattern ERROR_DUPLICATE_TYPE = Pattern.compile("Can't redefine: (.*)"); @@ -53,7 +51,7 @@ private void processSchemaFile(ProcessingState processingState, FileState fileSt Schema.Parser parser = new Schema.Parser(); parser.addTypes(parserTypes); parser.parse(sourceFile); - Map typesDefinedInFile = asymmetricDifference(parser.getTypes(), parserTypes); + Map typesDefinedInFile = MapUtils.asymmetricDifference(parser.getTypes(), parserTypes); processingState.processTypeDefinitions(fileState, typesDefinedInFile); if (logger.isDebugEnabled()) { logger.debug("Processed {}; contained types {}", path, typesDefinedInFile.keySet()); diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/SetBuilder.java similarity index 96% rename from src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/SetBuilder.java index 34b18c4543a..1d3202e9e5a 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/SetBuilder.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/SetBuilder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.util.Collection; import java.util.Collections; diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/Strings.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Strings.java similarity index 96% rename from src/main/java/com/commercehub/gradle/plugin/avro/Strings.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/Strings.java index 241eb9d5b77..605c2944c49 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/Strings.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Strings.java @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; /** * Utility methods for working with {@link String}s. diff --git a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/TypeState.java similarity index 96% rename from src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java rename to src/main/java/com/github/davidmc24/gradle/plugin/avro/TypeState.java index a0e50f28861..9094029b2a2 100644 --- a/src/main/java/com/commercehub/gradle/plugin/avro/TypeState.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/TypeState.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro; +package com.github.davidmc24.gradle.plugin.avro; import java.util.Set; import java.util.TreeSet; diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy similarity index 86% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy index 882177801ef..22c342d590d 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -25,7 +25,7 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "can generate java files from json schema"() { given: buildFile << """ - |tasks.register("generateAvroJava", com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { + |tasks.register("generateAvroJava", com.github.davidmc24.gradle.plugin.avro.GenerateAvroJavaTask) { | source file("src/main/avro") | include("**/*.avsc") | outputDir = file("build/generated-main-avro-java") @@ -45,7 +45,7 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "can generate json schema files from json protocol"() { given: buildFile << """ - |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + |tasks.register("generateSchema", com.github.davidmc24.gradle.plugin.avro.GenerateAvroSchemaTask) { | source file("src/main/avro") | include("**/*.avpr") | outputDir = file("build/generated-main-avro-avsc") @@ -68,11 +68,11 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "can generate json schema files from IDL"() { given: buildFile << """ - |tasks.register("generateProtocol", com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + |tasks.register("generateProtocol", com.github.davidmc24.gradle.plugin.avro.GenerateAvroProtocolTask) { | source file("src/main/avro") | outputDir = file("build/generated-avro-main-avpr") |} - |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + |tasks.register("generateSchema", com.github.davidmc24.gradle.plugin.avro.GenerateAvroSchemaTask) { | dependsOn generateProtocol | source file("build/generated-avro-main-avpr") | include("**/*.avpr") @@ -97,12 +97,12 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { def "example of converting both IDL and json protocol simultaneously"() { given: buildFile << """ - |tasks.register("generateProtocol", com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + |tasks.register("generateProtocol", com.github.davidmc24.gradle.plugin.avro.GenerateAvroProtocolTask) { | source file("src/main/avro") | include("**/*.avdl") | outputDir = file("build/generated-avro-main-avpr") |} - |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + |tasks.register("generateSchema", com.github.davidmc24.gradle.plugin.avro.GenerateAvroSchemaTask) { | dependsOn generateProtocol | source file("src/main/avro") | source file("build/generated-avro-main-avpr") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy similarity index 99% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 10089971b45..94054f48658 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginSpec.groovy similarity index 98% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginSpec.groovy index 531fc568dcb..28d3c515183 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroPluginSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroUtilsSpec.groovy similarity index 93% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroUtilsSpec.groovy index d96a620cc74..993f8a245fc 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/AvroUtilsSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroUtilsSpec.groovy @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import org.apache.avro.Protocol import org.apache.avro.Schema @@ -6,8 +6,8 @@ import spock.lang.Specification import spock.lang.Subject import spock.lang.Unroll -import static com.commercehub.gradle.plugin.avro.Constants.PROTOCOL_EXTENSION -import static com.commercehub.gradle.plugin.avro.Constants.SCHEMA_EXTENSION +import static Constants.PROTOCOL_EXTENSION +import static Constants.SCHEMA_EXTENSION @Subject(AvroUtils) class AvroUtilsSpec extends Specification { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy similarity index 96% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy index 9bc3a269c1a..8906f9e57b8 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import spock.lang.IgnoreIf import spock.util.environment.OperatingSystem @@ -80,7 +80,7 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { given: "a project is built once with build cache enabled" copyResource("mail.avpr", avroDir) buildFile << """ - |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + |tasks.register("generateSchema", com.github.davidmc24.gradle.plugin.avro.GenerateAvroSchemaTask) { | source file("src/main/avro") | include("**/*.avpr") | outputDir = file("build/generated-main-avro-avsc") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy similarity index 89% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index f5cd3f962fd..885a30eb35e 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class CustomConversionFunctionalSpec extends FunctionalSpec { private void copyCustomConversion(String destDir) { copyFile("src/test/java", destDir, - "com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java") + "com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneConversion.java") copyFile("src/test/java", destDir, - "com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java") + "com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java") copyFile("src/test/java", destDir, - "com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java") + "com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java") } def "can use a custom conversion when generating java from a schema with stringType = \"String\""() { @@ -41,8 +41,8 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { | classpath files(${readPluginClasspath()}) | } |} - |apply plugin: "com.commercehub.gradle.plugin.avro" - |import com.commercehub.gradle.plugin.avro.test.custom.* + |apply plugin: "com.github.davidmc24.gradle.plugin.avro" + |import com.github.davidmc24.gradle.plugin.avro.test.custom.* |avro { | stringType = "String" | logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) @@ -88,8 +88,8 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { | classpath files(${readPluginClasspath()}) | } |} - |apply plugin: "com.commercehub.gradle.plugin.avro" - |import com.commercehub.gradle.plugin.avro.test.custom.* + |apply plugin: "com.github.davidmc24.gradle.plugin.avro" + |import com.github.davidmc24.gradle.plugin.avro.test.custom.* |avro { | stringType = "CharSequence" | logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) @@ -135,8 +135,8 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { | classpath files(${readPluginClasspath()}) | } |} - |apply plugin: "com.commercehub.gradle.plugin.avro" - |import com.commercehub.gradle.plugin.avro.test.custom.* + |apply plugin: "com.github.davidmc24.gradle.plugin.avro" + |import com.github.davidmc24.gradle.plugin.avro.test.custom.* |avro { | stringType = "CharSequence" | logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory) @@ -174,7 +174,7 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { copyResource("customConversion.avpr", avroDir) applyAvroPlugin() buildFile << """ - |tasks.register("generateSchema", com.commercehub.gradle.plugin.avro.GenerateAvroSchemaTask) { + |tasks.register("generateSchema", com.github.davidmc24.gradle.plugin.avro.GenerateAvroSchemaTask) { | source file("src/main/avro") | include("**/*.avpr") | outputDir = file("build/generated-main-avro-avsc") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy similarity index 99% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy index ee68afafc44..03f396f0916 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.FAILED import static org.gradle.testkit.runner.TaskOutcome.SUCCESS diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EncodingFunctionalSpec.groovy similarity index 96% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EncodingFunctionalSpec.groovy index 14a10ff0256..1716cda1465 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EncodingFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EncodingFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import spock.lang.Unroll @@ -84,7 +84,7 @@ class EncodingFunctionalSpec extends FunctionalSpec { |avro { | outputCharacterEncoding = ${outputCharacterEncoding} |} - |tasks.register("generateAvroJava", com.commercehub.gradle.plugin.avro.GenerateAvroJavaTask) { + |tasks.register("generateAvroJava", com.github.davidmc24.gradle.plugin.avro.GenerateAvroJavaTask) { | source file("src/main/avro") | include("**/*.avsc") | outputDir = file("build/generated-main-avro-java") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy similarity index 98% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy index f0732cf9918..618d7f38a73 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.SUCCESS diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ExamplesFunctionalSpec.groovy similarity index 97% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ExamplesFunctionalSpec.groovy index 3172527490b..bc89ae18255 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/ExamplesFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ExamplesFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.SUCCESS diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy similarity index 96% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy index 621e0b960b6..79473a57741 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner @@ -56,11 +56,11 @@ abstract class FunctionalSpec extends Specification { } protected void applyAvroPlugin() { - applyPlugin("com.commercehub.gradle.plugin.avro") + applyPlugin("com.github.davidmc24.gradle.plugin.avro") } protected void applyAvroBasePlugin() { - applyPlugin("com.commercehub.gradle.plugin.avro-base") + applyPlugin("com.github.davidmc24.gradle.plugin.avro-base") } protected void applyPlugin(String pluginId) { diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy similarity index 95% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy index ace7a5374c2..7c0533d8800 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import spock.lang.Subject @@ -33,7 +33,7 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { |dependencies { | shared sharedIdlJar.outputs.files |} - |tasks.register("generateProtocol", com.commercehub.gradle.plugin.avro.GenerateAvroProtocolTask) { + |tasks.register("generateProtocol", com.github.davidmc24.gradle.plugin.avro.GenerateAvroProtocolTask) { | classpath = configurations.shared | source file("src/dependent") | outputDir = file("build/protocol") diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy similarity index 98% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy index e8934f5a115..7d7b7403bad 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/IntellijFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import org.gradle.testkit.runner.BuildResult diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy similarity index 98% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy index 1fffa8072aa..630252453cb 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import org.gradle.testkit.runner.BuildResult import org.gradle.util.GradleVersion diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy similarity index 94% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy index d17f336027e..3f624a5cbe2 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -11,7 +11,7 @@ class KotlinDSLCompatibilityFunctionalSpec extends FunctionalSpec { kotlinBuildFile << """ |plugins { | java - | id("com.commercehub.gradle.plugin.avro") + | id("com.github.davidmc24.gradle.plugin.avro") |} |repositories { | jcenter() diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy similarity index 99% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 087eb0deea1..d73502e0f61 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility import org.apache.avro.generic.GenericData.StringType @@ -250,7 +250,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { | classpath files(["${templatesDir.parentFile.toURI()}"]) | } |} - |apply plugin: "com.commercehub.gradle.plugin.avro" + |apply plugin: "com.github.davidmc24.gradle.plugin.avro" |avro { | templateDirectory = "/alternateTemplates/" |} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy similarity index 89% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy index 23edcb9d8c0..616f1978031 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import org.hamcrest.MatcherAssert import spock.lang.Subject @@ -14,7 +14,7 @@ class ResolveAvroDependenciesTaskFunctionalSpec extends FunctionalSpec { given: "a build with the task declared" applyAvroBasePlugin() buildFile << """ - |tasks.register("resolveAvroDependencies", com.commercehub.gradle.plugin.avro.ResolveAvroDependenciesTask) { + |tasks.register("resolveAvroDependencies", com.github.davidmc24.gradle.plugin.avro.ResolveAvroDependenciesTask) { | source file("src/avro/normalized") | outputDir = file("build/avro/resolved") |} diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/SchemaResolverSpec.groovy similarity index 91% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/SchemaResolverSpec.groovy index 3a603c0bfac..76b67152c66 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/SchemaResolverSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/SchemaResolverSpec.groovy @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import org.gradle.api.GradleException import org.gradle.api.Project @@ -108,7 +108,7 @@ class SchemaResolverSpec extends Specification { def "Duplicate record definition succeeds if definition identical"() { given: def resourceNames = ["Person.avsc", "Fish.avsc"] - def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + def files = resourceNames.collect { new File("src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/${it}") } when: def processingState = resolver.resolve(files) @@ -122,7 +122,7 @@ class SchemaResolverSpec extends Specification { def "Duplicate enum definition succeeds if definition identical"() { given: def resourceNames = ["Person.avsc", "Cat.avsc"] - def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + def files = resourceNames.collect { new File("src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/${it}") } when: def processingState = resolver.resolve(files) @@ -136,7 +136,7 @@ class SchemaResolverSpec extends Specification { def "Duplicate fixed definition succeeds if definition identical"() { given: def resourceNames = ["ContainsFixed1.avsc", "ContainsFixed2.avsc"] - def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + def files = resourceNames.collect { new File("src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/${it}") } when: def processingState = resolver.resolve(files) @@ -150,7 +150,7 @@ class SchemaResolverSpec extends Specification { def "Duplicate record definition fails if definition differs"() { given: def resourceNames = ["Person.avsc", "Spider.avsc"] - def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + def files = resourceNames.collect { new File("src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/${it}") } when: resolver.resolve(files) @@ -163,7 +163,7 @@ class SchemaResolverSpec extends Specification { def "Duplicate enum definition fails if definition differs"() { given: def resourceNames = ["Dog.avsc", "Person.avsc"] - def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + def files = resourceNames.collect { new File("src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/${it}") } when: resolver.resolve(files) @@ -176,7 +176,7 @@ class SchemaResolverSpec extends Specification { def "Duplicate fixed definition fails if definition differs"() { given: def resourceNames = ["ContainsFixed1.avsc", "ContainsFixed3.avsc"] - def files = resourceNames.collect { new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/${it}") } + def files = resourceNames.collect { new File("src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/${it}") } when: resolver.resolve(files) @@ -188,7 +188,7 @@ class SchemaResolverSpec extends Specification { def "Duplicate record definition in single file fails with clear error"() { given: - def file = new File("src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc") + def file = new File("src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc") when: resolver.resolve([file]) diff --git a/src/test/groovy/com/commercehub/gradle/plugin/avro/StringsSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/StringsSpec.groovy similarity index 96% rename from src/test/groovy/com/commercehub/gradle/plugin/avro/StringsSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/StringsSpec.groovy index 14eaa943c48..a2e98f773ef 100644 --- a/src/test/groovy/com/commercehub/gradle/plugin/avro/StringsSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/StringsSpec.groovy @@ -1,4 +1,4 @@ -package com.commercehub.gradle.plugin.avro +package com.github.davidmc24.gradle.plugin.avro import spock.lang.Specification import spock.lang.Subject diff --git a/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneConversion.java similarity index 96% rename from src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java rename to src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneConversion.java index a9e2a4cdf64..c80922294a0 100644 --- a/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneConversion.java +++ b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneConversion.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro.test.custom; +package com.github.davidmc24.gradle.plugin.avro.test.custom; import java.util.TimeZone; import org.apache.avro.Conversion; diff --git a/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java similarity index 95% rename from src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java rename to src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java index bb146854b10..72ba6e54419 100644 --- a/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java +++ b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro.test.custom; +package com.github.davidmc24.gradle.plugin.avro.test.custom; import org.apache.avro.LogicalType; import org.apache.avro.Schema; diff --git a/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java similarity index 93% rename from src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java rename to src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java index 32d57922847..5e35dac20a8 100644 --- a/src/test/java/com/commercehub/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java +++ b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.commercehub.gradle.plugin.avro.test.custom; +package com.github.davidmc24.gradle.plugin.avro.test.custom; import org.apache.avro.LogicalType; import org.apache.avro.LogicalTypes; diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/Message.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/Message.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/Message.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/Message.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avpr b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avpr similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avpr rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avpr diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/customConversion.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/dependent.avdl b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/dependent.avdl similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/dependent.avdl rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/dependent.avdl diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Cat.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Cat.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Cat.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Cat.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed1.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed1.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed1.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed1.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed2.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed2.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed2.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed2.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed3.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed3.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/ContainsFixed3.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed3.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Dog.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Dog.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Dog.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Dog.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Fish.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Fish.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Fish.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Fish.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Person.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Person.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Person.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Person.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Spider.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Spider.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/Spider.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Spider.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/enumField.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumField.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/enumField.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumField.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/enumMalformed.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumMalformed.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/enumMalformed.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumMalformed.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/enumSimple.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumSimple.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/enumSimple.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumSimple.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/enumUnion.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUnion.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/enumUnion.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUnion.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/enumUseSimple.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUseSimple.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/enumUseSimple.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUseSimple.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/helloWorld.kt similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/helloWorld.kt rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/helloWorld.kt diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/idioma.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/idioma.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/idioma.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/idioma.avsc diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop.avdl similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/interop.avdl rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop.avdl diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/mail.avpr b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/mail.avpr similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/mail.avpr rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/mail.avpr diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v1/test.avdl b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test.avdl similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v1/test.avdl rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test.avdl diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v2/test.avdl b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v2/test.avdl similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/namespaced-idl/v2/test.avdl rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v2/test.avdl diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/record.vm b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/record.vm rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/shared.avdl b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/shared.avdl similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/shared.avdl rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/shared.avdl diff --git a/src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/user.avsc similarity index 100% rename from src/test/resources/com/commercehub/gradle/plugin/avro/user.avsc rename to src/test/resources/com/github/davidmc24/gradle/plugin/avro/user.avsc diff --git a/test-project/build.gradle b/test-project/build.gradle index 03fe6470c32..b8922b129d6 100644 --- a/test-project/build.gradle +++ b/test-project/build.gradle @@ -1,6 +1,6 @@ plugins { id "idea" - id "com.commercehub.gradle.plugin.avro" version "0.21.0" + id "com.github.davidmc24.gradle.plugin.avro" version "1.0.0-SNAPSHOT" } repositories { From 4301939b9eab0670a1167f7f5dd77759d1eef492 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 9 Feb 2021 01:04:53 -0500 Subject: [PATCH 367/479] Fix up POMs, add signing; to satisfy Maven Central requirements --- build.gradle | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 9bd4238c26f..7b46d8c80c8 100644 --- a/build.gradle +++ b/build.gradle @@ -7,10 +7,17 @@ plugins { id "idea" id "jacoco" id "maven-publish" + id "signing" id "java-gradle-plugin" id "org.nosphere.gradle.github.actions" version "1.2.0" } +group = "com.github.davidmc24.gradle.plugin" +version = "1.0.0" + +def isCI = System.getenv("CI") == "true" +def isSnapshot = version.endsWith('-SNAPSHOT') + repositories { mavenCentral() maven { @@ -69,32 +76,24 @@ tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:all" << "-Xlint:-options" << "-Werror" } -group = "com.github.davidmc24.gradle.plugin" -version = "1.0.0-SNAPSHOT" -def isSnapshot = version.endsWith('-SNAPSHOT') - tasks.withType(AbstractArchiveTask) { preserveFileTimestamps = false reproducibleFileOrder = true } -task sourcesJar(type: Jar, dependsOn: classes) { - from sourceSets.main.allSource - classifier "sources" - archiveExtension.set("jar") +java { + withJavadocJar() + withSourcesJar() } -task javadocJar(type: Jar, dependsOn: javadoc) { - from javadoc.destinationDir - classifier "javadoc" - archiveExtension.set("jar") +javadoc { + if(JavaVersion.current().isJava9Compatible()) { + options.addBooleanOption('html5', true) + } } publishing { publications.withType(MavenPublication) { -// from components.java - artifact sourcesJar - artifact javadocJar pom { name = "gradle-avro-plugin" description = "A Gradle plugin to allow easily performing Java code generation for Apache Avro. It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files." @@ -133,15 +132,31 @@ publishing { } } +signing { + if (isCI) { + def signingKeyId = System.getenv("SIGNING_KEY_ID") + def signingKey = System.getenv("SIGNING_KEY") + def signingPassword = System.getenv("SIGNING_PASSWORD") + useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword) + } + publishing.publications.all { publication -> + sign publication + } +} + gradlePlugin { plugins { avro { id = "com.github.davidmc24.gradle.plugin.avro" implementationClass = "com.github.davidmc24.gradle.plugin.avro.AvroPlugin" + displayName = "avro" + description = "Conventions plugin for gradle-avro-plugin" } avroBase { id = "com.github.davidmc24.gradle.plugin.avro-base" implementationClass = "com.github.davidmc24.gradle.plugin.avro.AvroBasePlugin" + displayName = "avro-base" + description = "Capabilities plugin for gradle-avro-plugin" } } } From 9d2bf1b2f31deb1338fc5f87c35d15e3f26afbd7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 9 Feb 2021 01:08:56 -0500 Subject: [PATCH 368/479] version: 1.0.0 --- CHANGES.md | 2 ++ test-project/build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 5df446b2f73..9fd3c97f2d6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 1.0.0 * Published to Maven Central (no longer published to JCenter) * New plugin IDs: `com.github.davidmc24.gradle.plugin.avro` and `com.github.davidmc24.gradle.plugin.avro-base` * New package for tasks: `com.github.davidmc24.gradle.plugin.avro` diff --git a/test-project/build.gradle b/test-project/build.gradle index b8922b129d6..e7165957108 100644 --- a/test-project/build.gradle +++ b/test-project/build.gradle @@ -1,6 +1,6 @@ plugins { id "idea" - id "com.github.davidmc24.gradle.plugin.avro" version "1.0.0-SNAPSHOT" + id "com.github.davidmc24.gradle.plugin.avro" version "1.0.0" } repositories { From 80429949a7d92950ae99d5d7b6e08739544d53a6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 9 Feb 2021 01:11:09 -0500 Subject: [PATCH 369/479] version: 1.0.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7b46d8c80c8..977dd7ea358 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ plugins { } group = "com.github.davidmc24.gradle.plugin" -version = "1.0.0" +version = "1.0.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" def isSnapshot = version.endsWith('-SNAPSHOT') From d46e15478942a8bc4f014fd461b95bc9a82b762a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 9 Feb 2021 09:35:56 -0500 Subject: [PATCH 370/479] version: 1.0.0 (take 2) --- .github/workflows/publish.yml | 3 +++ build.gradle | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index aae2a0b7fc1..996f8746685 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -16,3 +16,6 @@ jobs: env: MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} diff --git a/build.gradle b/build.gradle index 977dd7ea358..7b46d8c80c8 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ plugins { } group = "com.github.davidmc24.gradle.plugin" -version = "1.0.1-SNAPSHOT" +version = "1.0.0" def isCI = System.getenv("CI") == "true" def isSnapshot = version.endsWith('-SNAPSHOT') From 5c0020d071b3d8cd79999e685a6d89a344cb9703 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 9 Feb 2021 09:53:35 -0500 Subject: [PATCH 371/479] version: 1.0.0 (take 3) --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index 7b46d8c80c8..4fa14433cf4 100644 --- a/build.gradle +++ b/build.gradle @@ -137,6 +137,10 @@ signing { def signingKeyId = System.getenv("SIGNING_KEY_ID") def signingKey = System.getenv("SIGNING_KEY") def signingPassword = System.getenv("SIGNING_PASSWORD") + // TODO: remove once I get publishing working + logger.warn("signingKeyId: ${signingKeyId}") + logger.warn("signingKey: ${signingKey != null ? 'present' : 'absent'}") + logger.warn("signingPassword: ${signingPassword != null ? 'present' : 'absent'}") useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword) } publishing.publications.all { publication -> From 6c8b2295f9275b6ced8612182316dffa7a493c0d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 9 Feb 2021 11:12:10 -0500 Subject: [PATCH 372/479] version: 1.0.1-SNAPSHOT --- build.gradle | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 4fa14433cf4..977dd7ea358 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ plugins { } group = "com.github.davidmc24.gradle.plugin" -version = "1.0.0" +version = "1.0.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" def isSnapshot = version.endsWith('-SNAPSHOT') @@ -137,10 +137,6 @@ signing { def signingKeyId = System.getenv("SIGNING_KEY_ID") def signingKey = System.getenv("SIGNING_KEY") def signingPassword = System.getenv("SIGNING_PASSWORD") - // TODO: remove once I get publishing working - logger.warn("signingKeyId: ${signingKeyId}") - logger.warn("signingKey: ${signingKey != null ? 'present' : 'absent'}") - logger.warn("signingPassword: ${signingPassword != null ? 'present' : 'absent'}") useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword) } publishing.publications.all { publication -> From d0889bb73f692a2fab920e8e5bcaea7ad4ccc807 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 9 Feb 2021 22:06:22 -0500 Subject: [PATCH 373/479] Remove remaining references to jcenter --- README.md | 21 +++++++------------ .../run-avro-as-an-external-process.md | 2 +- .../CustomConversionFunctionalSpec.groovy | 6 +++--- .../gradle/plugin/avro/FunctionalSpec.groovy | 2 +- ...otlinDSLCompatibilityFunctionalSpec.groovy | 2 +- test-project/build.gradle | 2 +- test-project/settings.gradle | 6 +----- 7 files changed, 16 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 04d1cec25a3..587cd3d9992 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,7 @@ Add the following to your build files. Substitute the desired version based on pluginManagement { repositories { gradlePluginPortal() - jcenter() - maven { - name "JCenter Gradle Plugins" - url "https://dl.bintray.com/gradle/gradle-plugins" - } + mavenCentral() } } ``` @@ -55,7 +51,7 @@ Additionally, ensure that you have a compile dependency on Avro, such as: ```groovy repositories { - jcenter() + mavenCentral() } dependencies { compile "org.apache.avro:avro:1.10.1" @@ -332,8 +328,8 @@ In `gradle.build.kts` add: ```kotlin plugins { - // Find latest release here: https://github.com/davidmc24/gradle-avro-plugin/releases - id("com.github.davidmc24.gradle.plugin.avro") version "VERSION" + // Find latest release here: https://github.com/davidmc24/gradle-avro-plugin/releases + id("com.github.davidmc24.gradle.plugin.avro") version "VERSION" } ``` @@ -341,11 +337,10 @@ And then in your `settings.gradle.kts` add: ```kotlin pluginManagement { - repositories { - gradlePluginPortal() - jcenter() - maven (url="https://dl.bintray.com/gradle/gradle-plugins") - } + repositories { + gradlePluginPortal() + mavenCentral() + } } ``` diff --git a/design-docs/run-avro-as-an-external-process.md b/design-docs/run-avro-as-an-external-process.md index 85c7816793d..eff15f70342 100644 --- a/design-docs/run-avro-as-an-external-process.md +++ b/design-docs/run-avro-as-an-external-process.md @@ -8,7 +8,7 @@ This is simple and works, but has a few drawbacks: Instead, here is an alternative view of how it could work. * There is an enhanced-avro-compiler library that externalizes most of the logic currently present in GenerateAvroJavaTask/GenerateAvroProtocolTask, and makes those calls accessible as JVM entry points (via `main` methods). - * This library would be published on JCenter and/or Maven Central, and potentially have multiple versions as needed for compatibility with multiple versions of Avro + * This library would be published on Maven Central, and potentially have multiple versions as needed for compatibility with multiple versions of Avro * It's possible we might be able to get this logic pushed upstream into avro-compiler, in which case the need for this library would be eliminated. * For a source-set, the plugin would take a single declaration of the desired Avro version, which is then used for both generation and compilation * The plugin would use a configuration per source-set to resolve the appropriate version of enhanced-avro-compiler diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index 885a30eb35e..2941fff9f95 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -54,7 +54,7 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { testProjectDir.newFolder("buildSrc") testProjectDir.newFile("buildSrc/build.gradle") << """ |repositories { - | jcenter() + | mavenCentral() |} |dependencies { | implementation "org.apache.avro:avro:${avroVersion}" @@ -101,7 +101,7 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { testProjectDir.newFolder("buildSrc") testProjectDir.newFile("buildSrc/build.gradle") << """ |repositories { - | jcenter() + | mavenCentral() |} |dependencies { | implementation "org.apache.avro:avro:${avroVersion}" @@ -148,7 +148,7 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { testProjectDir.newFolder("buildSrc") testProjectDir.newFile("buildSrc/build.gradle") << """ |repositories { - | jcenter() + | mavenCentral() |} |dependencies { | implementation "org.apache.avro:avro:${avroVersion}" diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy index 79473a57741..3fb45f7e015 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy @@ -72,7 +72,7 @@ abstract class FunctionalSpec extends Specification { } protected void addDefaultRepository() { - buildFile << "repositories { jcenter() }\n" + buildFile << "repositories { mavenCentral() }\n" } protected void addImplementationDependency(String dependencySpec) { diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy index 3f624a5cbe2..87f5fe7b819 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy @@ -14,7 +14,7 @@ class KotlinDSLCompatibilityFunctionalSpec extends FunctionalSpec { | id("com.github.davidmc24.gradle.plugin.avro") |} |repositories { - | jcenter() + | mavenCentral() |} |dependencies { | implementation("org.apache.avro:avro:${avroVersion}") diff --git a/test-project/build.gradle b/test-project/build.gradle index e7165957108..5d3188abe34 100644 --- a/test-project/build.gradle +++ b/test-project/build.gradle @@ -4,7 +4,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } ext { diff --git a/test-project/settings.gradle b/test-project/settings.gradle index ee4b9ef53d0..c9800b4942d 100644 --- a/test-project/settings.gradle +++ b/test-project/settings.gradle @@ -1,11 +1,7 @@ pluginManagement { repositories { gradlePluginPortal() - jcenter() - maven { - name "JCenter Gradle Plugins" - url "https://dl.bintray.com/gradle/gradle-plugins" - } + mavenCentral() } } From 1e0491cf3274bfd22d401ff5c4b4c434c65b6ecf Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 30 Mar 2021 21:41:34 -0400 Subject: [PATCH 374/479] Build using Avro 1.10.2 --- CHANGES.md | 1 + README.md | 4 ++-- build.gradle | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9fd3c97f2d6..d2de43d090f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Built using Avro 1.10.2 ## 1.0.0 * Published to Maven Central (no longer published to JCenter) diff --git a/README.md b/README.md index 587cd3d9992..a96637268de 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Though not supported yet, tests are also run against early-access builds of Java 16 to provide early notification of potential incompatibilities * Currently built against Gradle 6.7.1 * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.7.1 -* Currently built against Avro 1.10.1 - * Currently tested against Avro 1.10.0-1.10.1 +* Currently built against Avro 1.10.2 + * Currently tested against Avro 1.10.0-1.10.2 * Support for Kotlin * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.20 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 diff --git a/build.gradle b/build.gradle index 977dd7ea358..f08efa61472 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ repositories { } } -def compileAvroVersion = "1.10.1" +def compileAvroVersion = "1.10.2" def codenarcVersion = "1.5" def codenarcGroovyVersion = "2.5.10" // Newer version than included in 1.5 required for Java 14 support @@ -242,7 +242,7 @@ if (JavaVersion.current().java9Compatible) { sourceCompatibility = 8 } -def avroVersions = ["1.10.0", "1.10.1"] +def avroVersions = ["1.10.0", "1.10.1", "1.10.2"] def keyAvroVersions = avroVersions.last() def gradle5KotlinVersions = [] From 5f22915e323cf31b26f477f5366b5d12ad90b86a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 30 Mar 2021 21:57:54 -0400 Subject: [PATCH 375/479] Build using Gradle 6.8.3 --- CHANGES.md | 2 ++ README.md | 4 ++-- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d2de43d090f..5c0c05ec24b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased * Built using Avro 1.10.2 +* Built using Gradle 6.8.3 +* Updated compatibility testing through Gradle 6.8.3 ## 1.0.0 * Published to Maven Central (no longer published to JCenter) diff --git a/README.md b/README.md index a96637268de..871003ed912 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 13 support requires Gradle 6.0 or higher * Java 11 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) * Though not supported yet, tests are also run against early-access builds of Java 16 to provide early notification of potential incompatibilities -* Currently built against Gradle 6.7.1 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.7.1 +* Currently built against Gradle 6.8.3 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.8.3 * Currently built against Avro 1.10.2 * Currently tested against Avro 1.10.0-1.10.2 * Support for Kotlin diff --git a/build.gradle b/build.gradle index f08efa61472..97cc6477ed2 100644 --- a/build.gradle +++ b/build.gradle @@ -294,8 +294,8 @@ if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_15)) { gradleVersions.addAll("6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1") keyGradleVersions.addAll("6.3", "6.6.1") // First and last for the 6.x line before Java 15 support } -gradleVersions.addAll("6.7", "6.7.1") -keyGradleVersions.addAll("6.7", "6.7.1") // First and last for the 6.x line after Java 15 support +gradleVersions.addAll("6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3") +keyGradleVersions.addAll("6.7", "6.8.3") // First and last for the 6.x line after Java 15 support def latestAvroVersion = avroVersions.last() def latestGradleVersion = gradleVersions.last() diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4d9ca164914..442d9132ea3 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-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 5d6b03ca8c5fd482d14dd575c01c3375a85bbcbb Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 31 Mar 2021 09:21:26 -0400 Subject: [PATCH 376/479] Try running compatibility tests from github actions rather than gradle --- .github/workflows/ci.yml | 77 ++++----- build.gradle | 331 ++++++++++++++++++++------------------- 2 files changed, 202 insertions(+), 206 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fd96866def..3c9da573e25 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,8 +9,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] # All supported OS java: [8] # Minimum supported major version + os: [ubuntu-latest, windows-latest, macOS-latest] # All supported OS steps: - name: Check out repository uses: actions/checkout@v1 @@ -40,18 +40,34 @@ jobs: file: ./build/reports/jacoco/test/jacocoTestReport.xml flags: baseline,${{ matrix.os }} fail_ci_if_error: true - # Run further compatibility tests to ensure that key versions of Gradle/Avro - # work on a variety of OS/Java version combinations - recent-compatibility-tests: - name: Java ${{ matrix.java }}/${{ matrix.os }} recent version compatibility + compatibility-tests: + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}/os ${{ matrix.os }}" needs: [build] runs-on: ${{ matrix.os }} strategy: matrix: + avro: ["1.10.0", "1.10.1", "1.10.2"] + gradle: [ + "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", + "1.4.0", "1.4.10", "1.4.20", "1.4.21", + "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", + "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", + "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", + "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3" + ] + java: ["8", "11", "13", "14", "15"] # All supported major versions +# java: [ "8", "11" ] # LTS versions only; 17 will be the next one + kotlin: [ + "1.2.20", "1.2.21", + "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", + "1.3.0", "1.3.10", "1.3.11", + "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", + "1.4.0", "1.4.10", "1.4.20", "1.4.21" + ] # Exclude mac as it's unreliable at the moment # See https://github.com/actions/virtual-environments/issues/736 - os: [ubuntu-latest, windows-latest] - java: [8, 11, 13, 14, 15] # All supported major versions + os: ["ubuntu-latest", "windows-latest"] +# os: [ "ubuntu-latest" ] # Only a single OS to cut down on execution time fail-fast: true steps: - name: Check out repository @@ -61,6 +77,8 @@ jobs: with: java-version: ${{ matrix.java }} architecture: x64 + - name: Output Avro version + run: echo "Avro ${{ matrix.avro }}" - name: Output Java version run: java -version - name: Output Gradle version @@ -70,41 +88,7 @@ jobs: - name: Run recent version compatibility tests uses: eskatos/gradle-command-action@v1 with: - arguments: --info testRecentVersionCompatibility - dependencies-cache-enabled: true - - name: Stop Gradle Daemon - uses: eskatos/gradle-command-action@v1 - with: - arguments: --stop - # Run exhaustive compatibility testing of further Gradle/Avro versions on a - # smaller set of OS/Java versions - full-compatibility-tests: - name: Java ${{ matrix.java }}/${{ matrix.os }} full compatibility - needs: [build] - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] # Only a single OS to cut down on execution time - java: [8, 11] # LTS versions only; 17 will be the next one - fail-fast: true - steps: - - name: Check out repository - uses: actions/checkout@v1 - - name: Set up Java ${{ matrix.java }} - uses: actions/setup-java@v1 - with: - java-version: ${{ matrix.java }} - architecture: x64 - - name: Output Java version - run: java -version - - name: Output Gradle version - uses: eskatos/gradle-command-action@v1 - with: - arguments: --version - - name: Run full version compatibility tests - uses: eskatos/gradle-command-action@v1 - with: - arguments: --info testVersionCompatibility + arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinVersion=${{ matrix.kotlin }} dependencies-cache-enabled: true - name: Stop Gradle Daemon uses: eskatos/gradle-command-action@v1 @@ -113,16 +97,14 @@ jobs: # Early visibility to whether the project works on upcoming Java versions unsupported-java-versions: # Most Java version compatibility failures will manifest directly in the - # test suite with any Avro version; no need to run compatibity test + # test suite with any Avro version; no need to run compatibility test # target. name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility needs: [build] runs-on: ${{ matrix.os }} strategy: matrix: - # Exclude mac as it's unreliable at the moment - # See https://github.com/actions/virtual-environments/issues/736 - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest] # Only a single OS to cut down on execution time java: [16-ea] # EA builds of all current pre-release major versions fail-fast: false steps: @@ -145,9 +127,6 @@ jobs: with: arguments: --info build dependencies-cache-enabled: true - - name: Build with Gradle - continue-on-error: true - run: ./gradlew --no-daemon --info build - name: Stop Gradle Daemon uses: eskatos/gradle-command-action@v1 with: diff --git a/build.gradle b/build.gradle index 97cc6477ed2..bf40c86b41c 100644 --- a/build.gradle +++ b/build.gradle @@ -207,30 +207,30 @@ codenarc { toolVersion = codenarcVersion } -tasks.create("testAvroCompatibility") { - description = "Tests cross-compatibility of the plugin with different versions of Avro." - group = "Verification" -} - -tasks.create("testGradleCompatibility") { - description = "Tests cross-compatibility of the plugin with different versions of Gradle." - group = "Verification" -} - -tasks.create("testKotlinCompatibility") { - description = "Tests cross-compatibility of the plugin with different versions of Kotlin." - group = "Verification" -} - -tasks.create("testVersionCompatibility") { - description = "Tests cross-compatibility of the plugin with different versions of Avro, Gradle, and Kotlin." - group = "Verification" -} - -tasks.create("testRecentVersionCompatibility") { - description = "Tests cross-compatibility of the plugin with recent versions of Avro, Gradle, and Kotlin." - group = "Verification" -} +//tasks.create("testAvroCompatibility") { +// description = "Tests cross-compatibility of the plugin with different versions of Avro." +// group = "Verification" +//} +// +//tasks.create("testGradleCompatibility") { +// description = "Tests cross-compatibility of the plugin with different versions of Gradle." +// group = "Verification" +//} +// +//tasks.create("testKotlinCompatibility") { +// description = "Tests cross-compatibility of the plugin with different versions of Kotlin." +// group = "Verification" +//} +// +//tasks.create("testVersionCompatibility") { +// description = "Tests cross-compatibility of the plugin with different versions of Avro, Gradle, and Kotlin." +// group = "Verification" +//} +// +//tasks.create("testRecentVersionCompatibility") { +// description = "Tests cross-compatibility of the plugin with recent versions of Avro, Gradle, and Kotlin." +// group = "Verification" +//} // Java 8+ is required due to requirements introduced in Avro 1.9.0 // Java 8+ is also required by Gradle 5.x @@ -242,64 +242,65 @@ if (JavaVersion.current().java9Compatible) { sourceCompatibility = 8 } -def avroVersions = ["1.10.0", "1.10.1", "1.10.2"] - -def keyAvroVersions = avroVersions.last() -def gradle5KotlinVersions = [] -if (!JavaVersion.current().java10Compatible) { - // Java 10 support was added in Kotlin 1.2.30 - gradle5KotlinVersions.addAll([ - "1.2.20", "1.2.21", - ]) -} -gradle5KotlinVersions.addAll([ - "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", - "1.3.0", "1.3.10", "1.3.11", -]) -def latestGradleKotlinVersions = [ - "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", - "1.4.0", "1.4.10", "1.4.20", "1.4.21" -] -def kotlinVersions = gradle5KotlinVersions + latestGradleKotlinVersions -def keyKotlinVersions = [] // First and last version for each supported line -// Determine first supported version -if (!JavaVersion.current().java10Compatible) { - // Java 10 support was added in Kotlin 1.2.30 - keyKotlinVersions.add("1.2.20") -} else { - keyKotlinVersions.add("1.2.30") -} -keyKotlinVersions.addAll([ - "1.2.71", - "1.3.0", "1.3.72", // First and last version for 1.3.x line - "1.4.0", "1.4.21", // First and last version for 1.4.x line -]) -def pre5_3KotlinVersion = "1.3.72" // Kotlin plugin 1.4.x appears to require Gradle 5.3+ -def keyGradleVersions = [] // First and last version for each supported line -def firstSupportedGradleVersion = null -def gradleVersions = [] -if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { - // Java 13 support was added in Gradle 6.0 - gradleVersions.addAll("5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4") - keyGradleVersions.addAll("5.1", "5.6.4") // First and last for the 5.x line - firstSupportedGradleVersion = gradleVersions.first() -} -if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) { - // Java 14 support was added in Gradle 6.3 - gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2") - keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line before Java 14 support -} -if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_15)) { - // Java 15 support was added in Gradle 6.7 - gradleVersions.addAll("6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1") - keyGradleVersions.addAll("6.3", "6.6.1") // First and last for the 6.x line before Java 15 support -} -gradleVersions.addAll("6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3") -keyGradleVersions.addAll("6.7", "6.8.3") // First and last for the 6.x line after Java 15 support - -def latestAvroVersion = avroVersions.last() -def latestGradleVersion = gradleVersions.last() -def latestKotlinVersion = kotlinVersions.last() +//def avroVersions = ["1.10.0", "1.10.1", "1.10.2"] +// +//def keyAvroVersions = avroVersions.last() +//def gradle5KotlinVersions = [] +//if (!JavaVersion.current().java10Compatible) { +// // Java 10 support was added in Kotlin 1.2.30 +// gradle5KotlinVersions.addAll([ +// "1.2.20", "1.2.21", +// ]) +//} +//gradle5KotlinVersions.addAll([ +// "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", +// "1.3.0", "1.3.10", "1.3.11", +//]) +//def latestGradleKotlinVersions = [ +// "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", +// "1.4.0", "1.4.10", "1.4.20", "1.4.21" +//] +//def kotlinVersions = gradle5KotlinVersions + latestGradleKotlinVersions +//def keyKotlinVersions = [] // First and last version for each supported line +//// Determine first supported version +//if (!JavaVersion.current().java10Compatible) { +// // Java 10 support was added in Kotlin 1.2.30 +// keyKotlinVersions.add("1.2.20") +//} else { +// keyKotlinVersions.add("1.2.30") +//} +//keyKotlinVersions.addAll([ +// "1.2.71", +// "1.3.0", "1.3.72", // First and last version for 1.3.x line +// "1.4.0", "1.4.21", // First and last version for 1.4.x line +//]) +//def pre5_3KotlinVersion = "1.3.72" // Kotlin plugin 1.4.x appears to require Gradle 5.3+ +//def keyGradleVersions = [] // First and last version for each supported line +//def firstSupportedGradleVersion = null +//def gradleVersions = [] +//if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { +// // Java 13 support was added in Gradle 6.0 +// gradleVersions.addAll("5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4") +// keyGradleVersions.addAll("5.1", "5.6.4") // First and last for the 5.x line +// firstSupportedGradleVersion = gradleVersions.first() +//} +//if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) { +// // Java 14 support was added in Gradle 6.3 +// gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2") +// keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line before Java 14 support +//} +//if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_15)) { +// // Java 15 support was added in Gradle 6.7 +// gradleVersions.addAll("6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1") +// keyGradleVersions.addAll("6.3", "6.6.1") // First and last for the 6.x line before Java 15 support +//} +//gradleVersions.addAll("6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3") +//keyGradleVersions.addAll("6.7", "6.8.3") // First and last for the 6.x line after Java 15 support +// +//def latestAvroVersion = avroVersions.last() +//def latestGradleVersion = gradleVersions.last() +//def latestKotlinVersion = kotlinVersions.last() +def latestKotlinVersion = "1.4.21" test { systemProperties = [ @@ -310,6 +311,22 @@ test { finalizedBy jacocoTestReport // report is always generated after tests run } +tasks.create(name: "testCompatibility", type: Test) { + def compatAvroVersion = findProperty("avroVersion") ?: "unspecified" + def compatGradleVersion = findProperty("gradleVersion") ?: "unspecified" + def compatKotlinVersion = findProperty("kotlinVersion") ?: "unspecified" + description = "Test cross-compatibility of the plugin with Avro ${compatAvroVersion}, Gradle ${compatGradleVersion}, and Kotlin ${compatKotlinVersion}" + systemProperties = [ + avroVersion: compatAvroVersion, + gradleVersion: compatGradleVersion, + kotlinVersion: compatKotlinVersion, + ] + reports { + html.destination = file("$buildDir/reports/tests-avro${compatAvroVersion}-gradle${compatGradleVersion}-kotlin${compatKotlinVersion}") + junitXml.destination = file("$buildDir/reports/tests-avro${compatAvroVersion}-gradle${compatGradleVersion}-kotlin${compatKotlinVersion}") + } +} + jacoco { // 0.8.7+ needed for Java 15 support // See https://www.jacoco.org/jacoco/trunk/doc/changes.html @@ -323,81 +340,81 @@ jacocoTestReport { } } -avroVersions.each { def avroVersion -> - gradleVersions.each { def gradleVersion -> - def kotlinVersion = GradleVersion.version(gradleVersion) < GradleVersion.version("5.3") ? pre5_3KotlinVersion : latestKotlinVersion - def newTask = tasks.create(name: "testAvro${avroVersion}Gradle${gradleVersion}", type: Test) { - description = "Test cross-compatibility of the plugin with Avro ${avroVersion} and Gradle ${gradleVersion}" - systemProperties = [ - avroVersion: avroVersion, - gradleVersion: gradleVersion, - kotlinVersion: kotlinVersion, - ] - reports { - html.destination = file("$buildDir/reports/tests-avro${avroVersion}-gradle${gradleVersion}") - junitXml.destination = file("$buildDir/reports/tests-avro${avroVersion}-gradle${gradleVersion}") - } - } - testVersionCompatibility.dependsOn newTask - if (avroVersion == latestAvroVersion) { - testGradleCompatibility.dependsOn newTask - } - if (gradleVersion == latestGradleVersion) { - testAvroCompatibility.dependsOn newTask - } - if (gradleVersion in keyGradleVersions && avroVersion in keyAvroVersions) { - testRecentVersionCompatibility.dependsOn newTask - } - } -} - -gradle5KotlinVersions.each { def kotlinVersion -> - def avroVersion = latestAvroVersion - def gradleVersion = firstSupportedGradleVersion - if (gradleVersion) { - def newTask = tasks.create(name: "testKotlin${kotlinVersion}", type: Test) { - description = "Test cross-compatibility of the plugin with Kotlin ${kotlinVersion}" - systemProperties = [ - avroVersion : avroVersion, - gradleVersion: gradleVersion, - kotlinVersion: kotlinVersion, - ] - include("**/KotlinCompatibilityFunctionalSpec.class") - reports { - html.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") - junitXml.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") - } - } - testVersionCompatibility.dependsOn newTask - testKotlinCompatibility.dependsOn newTask - if (kotlinVersion in keyKotlinVersions) { - testRecentVersionCompatibility.dependsOn newTask - } - } -} - -latestGradleKotlinVersions.each { def kotlinVersion -> - def avroVersion = latestAvroVersion - def gradleVersion = latestGradleVersion - def newTask = tasks.create(name: "testKotlin${kotlinVersion}", type: Test) { - description = "Test cross-compatibility of the plugin with Kotlin ${kotlinVersion}" - systemProperties = [ - avroVersion : avroVersion, - gradleVersion: gradleVersion, - kotlinVersion: kotlinVersion, - ] - include("**/KotlinCompatibilityFunctionalSpec.class") - reports { - html.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") - junitXml.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") - } - } - testVersionCompatibility.dependsOn newTask - testKotlinCompatibility.dependsOn newTask - if (kotlinVersion in keyKotlinVersions) { - testRecentVersionCompatibility.dependsOn newTask - } -} +//avroVersions.each { def avroVersion -> +// gradleVersions.each { def gradleVersion -> +// def kotlinVersion = GradleVersion.version(gradleVersion) < GradleVersion.version("5.3") ? pre5_3KotlinVersion : latestKotlinVersion +// def newTask = tasks.create(name: "testAvro${avroVersion}Gradle${gradleVersion}", type: Test) { +// description = "Test cross-compatibility of the plugin with Avro ${avroVersion} and Gradle ${gradleVersion}" +// systemProperties = [ +// avroVersion: avroVersion, +// gradleVersion: gradleVersion, +// kotlinVersion: kotlinVersion, +// ] +// reports { +// html.destination = file("$buildDir/reports/tests-avro${avroVersion}-gradle${gradleVersion}") +// junitXml.destination = file("$buildDir/reports/tests-avro${avroVersion}-gradle${gradleVersion}") +// } +// } +// testVersionCompatibility.dependsOn newTask +// if (avroVersion == latestAvroVersion) { +// testGradleCompatibility.dependsOn newTask +// } +// if (gradleVersion == latestGradleVersion) { +// testAvroCompatibility.dependsOn newTask +// } +// if (gradleVersion in keyGradleVersions && avroVersion in keyAvroVersions) { +// testRecentVersionCompatibility.dependsOn newTask +// } +// } +//} + +//gradle5KotlinVersions.each { def kotlinVersion -> +// def avroVersion = latestAvroVersion +// def gradleVersion = firstSupportedGradleVersion +// if (gradleVersion) { +// def newTask = tasks.create(name: "testKotlin${kotlinVersion}", type: Test) { +// description = "Test cross-compatibility of the plugin with Kotlin ${kotlinVersion}" +// systemProperties = [ +// avroVersion : avroVersion, +// gradleVersion: gradleVersion, +// kotlinVersion: kotlinVersion, +// ] +// include("**/KotlinCompatibilityFunctionalSpec.class") +// reports { +// html.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") +// junitXml.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") +// } +// } +// testVersionCompatibility.dependsOn newTask +// testKotlinCompatibility.dependsOn newTask +// if (kotlinVersion in keyKotlinVersions) { +// testRecentVersionCompatibility.dependsOn newTask +// } +// } +//} + +//latestGradleKotlinVersions.each { def kotlinVersion -> +// def avroVersion = latestAvroVersion +// def gradleVersion = latestGradleVersion +// def newTask = tasks.create(name: "testKotlin${kotlinVersion}", type: Test) { +// description = "Test cross-compatibility of the plugin with Kotlin ${kotlinVersion}" +// systemProperties = [ +// avroVersion : avroVersion, +// gradleVersion: gradleVersion, +// kotlinVersion: kotlinVersion, +// ] +// include("**/KotlinCompatibilityFunctionalSpec.class") +// reports { +// html.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") +// junitXml.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") +// } +// } +// testVersionCompatibility.dependsOn newTask +// testKotlinCompatibility.dependsOn newTask +// if (kotlinVersion in keyKotlinVersions) { +// testRecentVersionCompatibility.dependsOn newTask +// } +//} tasks.withType(Test) { jvmArgs "-Xss320k" From 361e517c314e8b0977a22dfdb35be8034d39670f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 31 Mar 2021 23:27:29 -0400 Subject: [PATCH 377/479] Try extracting kotlin plugin compatibility testing to its own workflow --- .github/actions/run-tests/action.yml | 29 +++ .github/workflows/ci.yml | 208 ++++++++---------- .../workflows/kotlin-plugin-compatibility.yml | 115 ++++++++++ .github/workflows/publish.yml | 10 +- build.gradle | 29 ++- ...nPluginCompatibilityFunctionalSpec.groovy} | 10 +- 6 files changed, 275 insertions(+), 126 deletions(-) create mode 100644 .github/actions/run-tests/action.yml create mode 100644 .github/workflows/kotlin-plugin-compatibility.yml rename src/test/groovy/com/github/davidmc24/gradle/plugin/avro/{KotlinCompatibilityFunctionalSpec.groovy => KotlinPluginCompatibilityFunctionalSpec.groovy} (82%) diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml new file mode 100644 index 00000000000..f80bce73df6 --- /dev/null +++ b/.github/actions/run-tests/action.yml @@ -0,0 +1,29 @@ +inputs: + task-name: + description: The Gradle task to run + required: true + avro-version: + description: The Avro version to use when running the tests + required: true + gradle-version: + description: The Gradle version to use when running the tests + required: true + java-version: + description: The Java version to use when running the tests + required: true + kotlin-plugin-version: + description: The Kotlin plugin version to use when running the tests + required: false + default: undefined +runs: + using: composite + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ inputs.java-version }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: ${{ inputs.task-name }} -PavroVersion=${{ inputs.avro-version }} -PgradleVersion=${{ inputs.gradle-version }} -PkotlinPluginVersion=${{ inputs.kotlin-plugin-version }} + dependencies-cache-enabled: true + configuration-cache-enabled: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c9da573e25..b3f3f5544c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,122 +12,108 @@ jobs: java: [8] # Minimum supported major version os: [ubuntu-latest, windows-latest, macOS-latest] # All supported OS steps: - - name: Check out repository - uses: actions/checkout@v1 - - name: Set up Java 8 - uses: actions/setup-java@v1 + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 with: java-version: ${{ matrix.java }} - architecture: x64 - - name: Output Java version - run: java -version - - name: Output Gradle version - uses: eskatos/gradle-command-action@v1 + - uses: eskatos/gradle-command-action@v1 with: - arguments: --version - - name: Build with Gradle - uses: eskatos/gradle-command-action@v1 - with: - arguments: --info build + arguments: build dependencies-cache-enabled: true - - name: Stop Gradle Daemon - uses: eskatos/gradle-command-action@v1 - with: - arguments: --stop - - name: Upload coverage report to Codecov - uses: codecov/codecov-action@v1 + configuration-cache-enabled: true + - uses: codecov/codecov-action@v1 with: file: ./build/reports/jacoco/test/jacocoTestReport.xml flags: baseline,${{ matrix.os }} fail_ci_if_error: true - compatibility-tests: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}/os ${{ matrix.os }}" - needs: [build] - runs-on: ${{ matrix.os }} - strategy: - matrix: - avro: ["1.10.0", "1.10.1", "1.10.2"] - gradle: [ - "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", - "1.4.0", "1.4.10", "1.4.20", "1.4.21", - "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", - "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", - "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", - "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3" - ] - java: ["8", "11", "13", "14", "15"] # All supported major versions -# java: [ "8", "11" ] # LTS versions only; 17 will be the next one - kotlin: [ - "1.2.20", "1.2.21", - "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", - "1.3.0", "1.3.10", "1.3.11", - "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", - "1.4.0", "1.4.10", "1.4.20", "1.4.21" - ] - # Exclude mac as it's unreliable at the moment - # See https://github.com/actions/virtual-environments/issues/736 - os: ["ubuntu-latest", "windows-latest"] -# os: [ "ubuntu-latest" ] # Only a single OS to cut down on execution time - fail-fast: true - steps: - - name: Check out repository - uses: actions/checkout@v1 - - name: Set up Java ${{ matrix.java }} - uses: actions/setup-java@v1 - with: - java-version: ${{ matrix.java }} - architecture: x64 - - name: Output Avro version - run: echo "Avro ${{ matrix.avro }}" - - name: Output Java version - run: java -version - - name: Output Gradle version - uses: eskatos/gradle-command-action@v1 - with: - arguments: --version - - name: Run recent version compatibility tests - uses: eskatos/gradle-command-action@v1 - with: - arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinVersion=${{ matrix.kotlin }} - dependencies-cache-enabled: true - - name: Stop Gradle Daemon - uses: eskatos/gradle-command-action@v1 - with: - arguments: --stop - # Early visibility to whether the project works on upcoming Java versions - unsupported-java-versions: - # Most Java version compatibility failures will manifest directly in the - # test suite with any Avro version; no need to run compatibility test - # target. - name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility - needs: [build] - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] # Only a single OS to cut down on execution time - java: [16-ea] # EA builds of all current pre-release major versions - fail-fast: false - steps: - - name: Check out repository - uses: actions/checkout@v1 - - name: Set up Java ${{ matrix.java }} - uses: actions/setup-java@v1 - with: - java-version: ${{ matrix.java }} - architecture: x64 - - name: Output Java version - run: java -version - - name: Output Gradle version - uses: eskatos/gradle-command-action@v1 - with: - arguments: --version - - name: Build with Gradle - continue-on-error: true - uses: eskatos/gradle-command-action@v1 - with: - arguments: --info build - dependencies-cache-enabled: true - - name: Stop Gradle Daemon - uses: eskatos/gradle-command-action@v1 - with: - arguments: --stop +# compatibility-tests: +# name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}/os ${{ matrix.os }}" +# needs: [build] +# runs-on: ${{ matrix.os }} +# strategy: +# matrix: +# avro: ["1.10.0", "1.10.1", "1.10.2"] +# gradle: [ +# "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", +# "1.4.0", "1.4.10", "1.4.20", "1.4.21", +# "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", +# "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", +# "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", +# "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3" +# ] +# java: ["8", "11", "13", "14", "15"] # All supported major versions +## java: [ "8", "11" ] # LTS versions only; 17 will be the next one +# kotlin: [ +# "1.2.20", "1.2.21", +# "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", +# "1.3.0", "1.3.10", "1.3.11", +# "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", +# "1.4.0", "1.4.10", "1.4.20", "1.4.21" +# ] +# # Exclude mac as it's unreliable at the moment +# # See https://github.com/actions/virtual-environments/issues/736 +# os: ["ubuntu-latest", "windows-latest"] +## os: [ "ubuntu-latest" ] # Only a single OS to cut down on execution time +# fail-fast: true +# steps: +# - name: Check out repository +# uses: actions/checkout@v2 +# - name: Set up Java ${{ matrix.java }} +# uses: actions/setup-java@v1 +# with: +# java-version: ${{ matrix.java }} +# architecture: x64 +# - name: Output Avro version +# run: echo "Avro ${{ matrix.avro }}" +# - name: Output Java version +# run: java -version +# - name: Output Gradle version +# uses: eskatos/gradle-command-action@v1 +# with: +# arguments: --version +# - name: Run recent version compatibility tests +# uses: eskatos/gradle-command-action@v1 +# with: +# arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinVersion=${{ matrix.kotlin }} +# dependencies-cache-enabled: true +# - name: Stop Gradle Daemon +# uses: eskatos/gradle-command-action@v1 +# with: +# arguments: --stop +# # Early visibility to whether the project works on upcoming Java versions +# unsupported-java-versions: +# # Most Java version compatibility failures will manifest directly in the +# # test suite with any Avro version; no need to run compatibility test +# # target. +# name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility +# needs: [build] +# runs-on: ${{ matrix.os }} +# strategy: +# matrix: +# os: [ubuntu-latest] # Only a single OS to cut down on execution time +# java: [16-ea] # EA builds of all current pre-release major versions +# fail-fast: false +# steps: +# - name: Check out repository +# uses: actions/checkout@v2 +# - name: Set up Java ${{ matrix.java }} +# uses: actions/setup-java@v1 +# with: +# java-version: ${{ matrix.java }} +# architecture: x64 +# - name: Output Java version +# run: java -version +# - name: Output Gradle version +# uses: eskatos/gradle-command-action@v1 +# with: +# arguments: --version +# - name: Build with Gradle +# continue-on-error: true +# uses: eskatos/gradle-command-action@v1 +# with: +# arguments: --info build +# dependencies-cache-enabled: true +# - name: Stop Gradle Daemon +# uses: eskatos/gradle-command-action@v1 +# with: +# arguments: --stop diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml new file mode 100644 index 00000000000..98c9b910b75 --- /dev/null +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -0,0 +1,115 @@ +name: Kotlin Plugin Compatibility Tests +on: [push, pull_request] +jobs: + check-compat: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] + gradle: ["5.1", "6.8.3"] + java: ["8", "11"] + kotlin: [ + "1.2.20", "1.2.21", + "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", + "1.3.0", "1.3.10", "1.3.11", + "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", + "1.4.0", "1.4.10", "1.4.20", "1.4.21" + ] + steps: + - uses: ./.github/actions/run-tests + with: + task-name: testKotlinPluginCompatibility + avro-version: ${{ matrix.avro }} + gradle-version: ${{ matrix.gradle }} + java-version: ${{ matrix.java }} + kotlin-plugin-version: ${{ matrix.kotlin }} +# java-11: +# name: "Compatibility: java ${{ matrix.java }}/kotlin ${{ matrix.kotlin }}" +# runs-on: "ubuntu-latest" +# compatibility-tests: +# name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}/os ${{ matrix.os }}" +# needs: [build] +# runs-on: ${{ matrix.os }} +# strategy: +# matrix: +# avro: ["1.10.0", "1.10.1", "1.10.2"] +# gradle: [ +# "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", +# "1.4.0", "1.4.10", "1.4.20", "1.4.21", +# "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", +# "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", +# "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", +# "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3" +# ] +# java: ["8", "11", "13", "14", "15"] # All supported major versions +## java: [ "8", "11" ] # LTS versions only; 17 will be the next one +# kotlin: [ +# "1.2.20", "1.2.21", +# "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", +# "1.3.0", "1.3.10", "1.3.11", +# "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", +# "1.4.0", "1.4.10", "1.4.20", "1.4.21" +# ] +# # Exclude mac as it's unreliable at the moment +# # See https://github.com/actions/virtual-environments/issues/736 +# os: ["ubuntu-latest", "windows-latest"] +## os: [ "ubuntu-latest" ] # Only a single OS to cut down on execution time +# fail-fast: true +# steps: +# - name: Check out repository +# uses: actions/checkout@v1 +# - name: Set up Java ${{ matrix.java }} +# uses: actions/setup-java@v1 +# with: +# java-version: ${{ matrix.java }} +# architecture: x64 +# - name: Output Avro version +# run: echo "Avro ${{ matrix.avro }}" +# - name: Output Java version +# run: java -version +# - name: Output Gradle version +# uses: eskatos/gradle-command-action@v1 +# with: +# arguments: --version +# - name: Run recent version compatibility tests +# uses: eskatos/gradle-command-action@v1 +# with: +# arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinVersion=${{ matrix.kotlin }} +# dependencies-cache-enabled: true +# - name: Stop Gradle Daemon +# uses: eskatos/gradle-command-action@v1 +# with: +# arguments: --stop +# +# +#//def gradle5KotlinVersions = [] +# //if (!JavaVersion.current().java10Compatible) { +# // // Java 10 support was added in Kotlin 1.2.30 +# // gradle5KotlinVersions.addAll([ +# // "1.2.20", "1.2.21", +# // ]) +# //} +# //gradle5KotlinVersions.addAll([ +# // "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", +# // "1.3.0", "1.3.10", "1.3.11", +# //]) +# //def latestGradleKotlinVersions = [ +# // "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", +# // "1.4.0", "1.4.10", "1.4.20", "1.4.21" +# //] +# //def kotlinVersions = gradle5KotlinVersions + latestGradleKotlinVersions +# //def keyKotlinVersions = [] // First and last version for each supported line +# //// Determine first supported version +# //if (!JavaVersion.current().java10Compatible) { +# // // Java 10 support was added in Kotlin 1.2.30 +# // keyKotlinVersions.add("1.2.20") +# //} else { +# // keyKotlinVersions.add("1.2.30") +# //} +# //keyKotlinVersions.addAll([ +# // "1.2.71", +# // "1.3.0", "1.3.72", // First and last version for 1.3.x line +# // "1.4.0", "1.4.21", // First and last version for 1.4.x line +# //]) +# //def pre5_3KotlinVersion = "1.3.72" // Kotlin plugin 1.4.x appears to require Gradle 5.3+ diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 996f8746685..93521691513 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,12 +7,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up Java - uses: actions/setup-java@v1 + - uses: actions/setup-java@v1 with: java-version: 8 - - name: Publish package - run: ./gradlew publish + - uses: eskatos/gradle-command-action@v1 + with: + arguments: publish + dependencies-cache-enabled: true + configuration-cache-enabled: true env: MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} diff --git a/build.gradle b/build.gradle index bf40c86b41c..816c415eb9d 100644 --- a/build.gradle +++ b/build.gradle @@ -306,7 +306,7 @@ test { systemProperties = [ avroVersion: compileAvroVersion, gradleVersion: gradle.gradleVersion, - kotlinVersion: latestKotlinVersion, + kotlinPluginVersion: latestKotlinVersion, ] finalizedBy jacocoTestReport // report is always generated after tests run } @@ -314,16 +314,33 @@ test { tasks.create(name: "testCompatibility", type: Test) { def compatAvroVersion = findProperty("avroVersion") ?: "unspecified" def compatGradleVersion = findProperty("gradleVersion") ?: "unspecified" - def compatKotlinVersion = findProperty("kotlinVersion") ?: "unspecified" - description = "Test cross-compatibility of the plugin with Avro ${compatAvroVersion}, Gradle ${compatGradleVersion}, and Kotlin ${compatKotlinVersion}" + def compatKotlinPluginVersion = findProperty("kotlinPluginVersion") ?: "unspecified" + description = "Test cross-compatibility of the plugin with Avro ${compatAvroVersion}, Gradle ${compatGradleVersion}, and Kotlin ${compatKotlinPluginVersion}" systemProperties = [ avroVersion: compatAvroVersion, gradleVersion: compatGradleVersion, - kotlinVersion: compatKotlinVersion, + kotlinPluginVersion: compatKotlinPluginVersion, ] reports { - html.destination = file("$buildDir/reports/tests-avro${compatAvroVersion}-gradle${compatGradleVersion}-kotlin${compatKotlinVersion}") - junitXml.destination = file("$buildDir/reports/tests-avro${compatAvroVersion}-gradle${compatGradleVersion}-kotlin${compatKotlinVersion}") + html.destination = file("$buildDir/reports/tests-avro${compatAvroVersion}-gradle${compatGradleVersion}-kotlin${compatKotlinPluginVersion}") + junitXml.destination = file("$buildDir/reports/tests-avro${compatAvroVersion}-gradle${compatGradleVersion}-kotlin${compatKotlinPluginVersion}") + } +} + +tasks.create(name: "testKotlinPluginCompatibility", type: Test) { + def compatAvroVersion = findProperty("avroVersion") ?: "unspecified" + def compatGradleVersion = findProperty("gradleVersion") ?: "unspecified" + def compatKotlinPluginVersion = findProperty("kotlinPluginVersion") ?: "unspecified" + description = "Test cross-compatibility of the plugin with Kotlin ${compatKotlinPluginVersion}" + systemProperties = [ + avroVersion: compatAvroVersion, + gradleVersion: compatGradleVersion, + kotlinPluginVersion: compatKotlinPluginVersion, + ] + include '**/KotlinPlugin*Spec' + reports { + html.destination = file("$buildDir/reports/tests-kotlinPlugin${compatKotlinPluginVersion}") + junitXml.destination = file("$buildDir/reports/tests-kotlinPlugin${compatKotlinPluginVersion}") } } diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy similarity index 82% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy rename to src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy index 630252453cb..bf14102dd92 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy @@ -19,19 +19,19 @@ import org.gradle.testkit.runner.BuildResult import org.gradle.util.GradleVersion @SuppressWarnings(["Println"]) -class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { +class KotlinPluginCompatibilityFunctionalSpec extends FunctionalSpec { @SuppressWarnings(["FieldName"]) - protected static final String kotlinVersion = System.getProperty("kotlinVersion", "undefined") + protected static final String kotlinPluginVersion = System.getProperty("kotlinPluginVersion", "undefined") def "setup"() { - println "Testing using Kotlin version ${kotlinVersion}." + println "Testing using Kotlin plugin version ${kotlinPluginVersion}." } def "works with kotlin-gradle-plugin"() { given: File kotlinDir = testProjectDir.newFolder("src", "main", "kotlin") applyAvroPlugin() - applyPlugin("org.jetbrains.kotlin.jvm", kotlinVersion) + applyPlugin("org.jetbrains.kotlin.jvm", kotlinPluginVersion) applyPlugin("application") addDefaultRepository() addAvroDependency() @@ -54,7 +54,7 @@ class KotlinCompatibilityFunctionalSpec extends FunctionalSpec { // The kotlin plugin prior to 1.4.20 doesn't support the configuration cache, so we need to disable it. // This is a bit of a mis-use of the GradleVersion class, but it's way easier than writing our own // version comparison logic. - if (GradleVersion.version(kotlinVersion) < GradleVersion.version("1.4.20")) { + if (GradleVersion.version(kotlinPluginVersion) < GradleVersion.version("1.4.20")) { args << "--no-configuration-cache" } } From 8c3108e75df4caa88f6b746cb959ce2d7a425798 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 31 Mar 2021 23:29:51 -0400 Subject: [PATCH 378/479] Try to fix CI job --- .github/actions/run-tests/action.yml | 1 - .github/workflows/kotlin-plugin-compatibility.yml | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml index f80bce73df6..fb8bfa33606 100644 --- a/.github/actions/run-tests/action.yml +++ b/.github/actions/run-tests/action.yml @@ -18,7 +18,6 @@ inputs: runs: using: composite steps: - - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: java-version: ${{ inputs.java-version }} diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index 98c9b910b75..8f61400beaf 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -16,7 +16,9 @@ jobs: "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", "1.4.0", "1.4.10", "1.4.20", "1.4.21" ] + fail-fast: false # TODO: remove after testing steps: + - uses: actions/checkout@v2 - uses: ./.github/actions/run-tests with: task-name: testKotlinPluginCompatibility From 2fcae9081c2a8d8ca016de3b888adad848a3996d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 31 Mar 2021 23:34:26 -0400 Subject: [PATCH 379/479] Try to fix CI job --- .github/actions/run-tests/action.yml | 28 ------------------- .../workflows/kotlin-plugin-compatibility.yml | 11 ++++---- 2 files changed, 6 insertions(+), 33 deletions(-) delete mode 100644 .github/actions/run-tests/action.yml diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml deleted file mode 100644 index fb8bfa33606..00000000000 --- a/.github/actions/run-tests/action.yml +++ /dev/null @@ -1,28 +0,0 @@ -inputs: - task-name: - description: The Gradle task to run - required: true - avro-version: - description: The Avro version to use when running the tests - required: true - gradle-version: - description: The Gradle version to use when running the tests - required: true - java-version: - description: The Java version to use when running the tests - required: true - kotlin-plugin-version: - description: The Kotlin plugin version to use when running the tests - required: false - default: undefined -runs: - using: composite - steps: - - uses: actions/setup-java@v1 - with: - java-version: ${{ inputs.java-version }} - - uses: eskatos/gradle-command-action@v1 - with: - arguments: ${{ inputs.task-name }} -PavroVersion=${{ inputs.avro-version }} -PgradleVersion=${{ inputs.gradle-version }} -PkotlinPluginVersion=${{ inputs.kotlin-plugin-version }} - dependencies-cache-enabled: true - configuration-cache-enabled: true diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index 8f61400beaf..4f8daa5e409 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -19,13 +19,14 @@ jobs: fail-fast: false # TODO: remove after testing steps: - uses: actions/checkout@v2 - - uses: ./.github/actions/run-tests + - uses: actions/setup-java@v1 with: - task-name: testKotlinPluginCompatibility - avro-version: ${{ matrix.avro }} - gradle-version: ${{ matrix.gradle }} java-version: ${{ matrix.java }} - kotlin-plugin-version: ${{ matrix.kotlin }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + dependencies-cache-enabled: true + configuration-cache-enabled: true # java-11: # name: "Compatibility: java ${{ matrix.java }}/kotlin ${{ matrix.kotlin }}" # runs-on: "ubuntu-latest" From d0b980dbee4422e67bd66878038cda3afc8fff9c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 31 Mar 2021 23:50:12 -0400 Subject: [PATCH 380/479] Fix testKotlinPluginCompatibility --- build.gradle | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 816c415eb9d..d93298d4ef3 100644 --- a/build.gradle +++ b/build.gradle @@ -328,19 +328,18 @@ tasks.create(name: "testCompatibility", type: Test) { } tasks.create(name: "testKotlinPluginCompatibility", type: Test) { - def compatAvroVersion = findProperty("avroVersion") ?: "unspecified" - def compatGradleVersion = findProperty("gradleVersion") ?: "unspecified" - def compatKotlinPluginVersion = findProperty("kotlinPluginVersion") ?: "unspecified" - description = "Test cross-compatibility of the plugin with Kotlin ${compatKotlinPluginVersion}" + description = "Test cross-compatibility of the plugin with the Kotlin plugin" systemProperties = [ - avroVersion: compatAvroVersion, - gradleVersion: compatGradleVersion, - kotlinPluginVersion: compatKotlinPluginVersion, + avroVersion: findProperty("avroVersion"), + gradleVersion: findProperty("gradleVersion"), + kotlinPluginVersion: findProperty("kotlinPluginVersion"), ] - include '**/KotlinPlugin*Spec' + filter { + includeTestsMatching "*KotlinPlugin*" + } reports { - html.destination = file("$buildDir/reports/tests-kotlinPlugin${compatKotlinPluginVersion}") - junitXml.destination = file("$buildDir/reports/tests-kotlinPlugin${compatKotlinPluginVersion}") + html.destination = file("$buildDir/reports/tests-kotlinPluginCompatibility") + junitXml.destination = file("$buildDir/reports/tests-kotlinPluginCompatibility") } } From 81d4b8f588ee76704577f6abe4ab398dccb3017b Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 00:09:09 -0400 Subject: [PATCH 381/479] Next try at kotlin compatibility --- .github/workflows/ci.yml | 2 +- .../workflows/kotlin-plugin-compatibility.yml | 147 +++++++----------- .github/workflows/publish.yml | 2 +- 3 files changed, 54 insertions(+), 97 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3f3f5544c2..3ad43823b89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: build + arguments: --info build dependencies-cache-enabled: true configuration-cache-enabled: true - uses: codecov/codecov-action@v1 diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index 4f8daa5e409..ec8354759a6 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -1,22 +1,68 @@ name: Kotlin Plugin Compatibility Tests on: [push, pull_request] jobs: - check-compat: + java8-gradle5_1: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] - gradle: ["5.1", "6.8.3"] - java: ["8", "11"] + avro: ["1.10.0"] # Minimum version that this plugin supports + gradle: ["5.1"] # Minimum version that this plugin supports + java: ["8"] # Minimum version that this plugin supports kotlin: [ "1.2.20", "1.2.21", "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", "1.3.0", "1.3.10", "1.3.11", + "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72" + # Later versions require Gradle 5.3+ + ] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --info testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + dependencies-cache-enabled: true + configuration-cache-enabled: true + java8-gradle5_3: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.0"] # Minimum version that this plugin supports + gradle: ["5.3"] # Minimum version supported by these versions of the Kotlin plugin + java: ["8"] # Minimum version that this plugin supports + kotlin: [ + # These versions require Gradle 5.3+ + "1.4.0", "1.4.10", "1.4.20", "1.4.21" + ] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --info testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + dependencies-cache-enabled: true + configuration-cache-enabled: true + modern: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] # Latest version that this plugin supports + gradle: ["6.8.3"] # Latest version that this plugin supports + java: ["11"] # Latest LTS version that this plugin supports + kotlin: [ + # Earlier versions don't support Java 10+ + "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", + "1.3.0", "1.3.10", "1.3.11", "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", "1.4.0", "1.4.10", "1.4.20", "1.4.21" ] - fail-fast: false # TODO: remove after testing steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v1 @@ -24,95 +70,6 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + arguments: --info testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} dependencies-cache-enabled: true configuration-cache-enabled: true -# java-11: -# name: "Compatibility: java ${{ matrix.java }}/kotlin ${{ matrix.kotlin }}" -# runs-on: "ubuntu-latest" -# compatibility-tests: -# name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}/os ${{ matrix.os }}" -# needs: [build] -# runs-on: ${{ matrix.os }} -# strategy: -# matrix: -# avro: ["1.10.0", "1.10.1", "1.10.2"] -# gradle: [ -# "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", -# "1.4.0", "1.4.10", "1.4.20", "1.4.21", -# "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", -# "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", -# "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", -# "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3" -# ] -# java: ["8", "11", "13", "14", "15"] # All supported major versions -## java: [ "8", "11" ] # LTS versions only; 17 will be the next one -# kotlin: [ -# "1.2.20", "1.2.21", -# "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", -# "1.3.0", "1.3.10", "1.3.11", -# "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", -# "1.4.0", "1.4.10", "1.4.20", "1.4.21" -# ] -# # Exclude mac as it's unreliable at the moment -# # See https://github.com/actions/virtual-environments/issues/736 -# os: ["ubuntu-latest", "windows-latest"] -## os: [ "ubuntu-latest" ] # Only a single OS to cut down on execution time -# fail-fast: true -# steps: -# - name: Check out repository -# uses: actions/checkout@v1 -# - name: Set up Java ${{ matrix.java }} -# uses: actions/setup-java@v1 -# with: -# java-version: ${{ matrix.java }} -# architecture: x64 -# - name: Output Avro version -# run: echo "Avro ${{ matrix.avro }}" -# - name: Output Java version -# run: java -version -# - name: Output Gradle version -# uses: eskatos/gradle-command-action@v1 -# with: -# arguments: --version -# - name: Run recent version compatibility tests -# uses: eskatos/gradle-command-action@v1 -# with: -# arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinVersion=${{ matrix.kotlin }} -# dependencies-cache-enabled: true -# - name: Stop Gradle Daemon -# uses: eskatos/gradle-command-action@v1 -# with: -# arguments: --stop -# -# -#//def gradle5KotlinVersions = [] -# //if (!JavaVersion.current().java10Compatible) { -# // // Java 10 support was added in Kotlin 1.2.30 -# // gradle5KotlinVersions.addAll([ -# // "1.2.20", "1.2.21", -# // ]) -# //} -# //gradle5KotlinVersions.addAll([ -# // "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", -# // "1.3.0", "1.3.10", "1.3.11", -# //]) -# //def latestGradleKotlinVersions = [ -# // "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", -# // "1.4.0", "1.4.10", "1.4.20", "1.4.21" -# //] -# //def kotlinVersions = gradle5KotlinVersions + latestGradleKotlinVersions -# //def keyKotlinVersions = [] // First and last version for each supported line -# //// Determine first supported version -# //if (!JavaVersion.current().java10Compatible) { -# // // Java 10 support was added in Kotlin 1.2.30 -# // keyKotlinVersions.add("1.2.20") -# //} else { -# // keyKotlinVersions.add("1.2.30") -# //} -# //keyKotlinVersions.addAll([ -# // "1.2.71", -# // "1.3.0", "1.3.72", // First and last version for 1.3.x line -# // "1.4.0", "1.4.21", // First and last version for 1.4.x line -# //]) -# //def pre5_3KotlinVersion = "1.3.72" // Kotlin plugin 1.4.x appears to require Gradle 5.3+ diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 93521691513..53fc9497449 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,7 +12,7 @@ jobs: java-version: 8 - uses: eskatos/gradle-command-action@v1 with: - arguments: publish + arguments: --info publish dependencies-cache-enabled: true configuration-cache-enabled: true env: From e3b76bd0e1cbe7294af0407c1aac1c428496f20f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 00:35:47 -0400 Subject: [PATCH 382/479] More matrix stuff --- .github/workflows/avro-compatibility.yml | 21 ++++++ .github/workflows/java-compatibility.yml | 95 ++++++++++++++++++++++++ README.md | 4 +- build.gradle | 17 ++--- 4 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/avro-compatibility.yml create mode 100644 .github/workflows/java-compatibility.yml diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml new file mode 100644 index 00000000000..aca16e9b89e --- /dev/null +++ b/.github/workflows/avro-compatibility.yml @@ -0,0 +1,21 @@ +name: Avro Compatibility Tests +on: [push, pull_request] +jobs: + test: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.0", "1.10.1", "1.10.2"] + gradle: ["5.1", "6.8.3"] + java: ["8"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + dependencies-cache-enabled: true + configuration-cache-enabled: true diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml new file mode 100644 index 00000000000..9b60a6e0ffd --- /dev/null +++ b/.github/workflows/java-compatibility.yml @@ -0,0 +1,95 @@ +name: Avro Compatibility Tests +on: [push, pull_request] +jobs: + java8-12: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] + gradle: ["5.1", "6.8.3"] + java: ["8", "9", "10", "11", "12"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + dependencies-cache-enabled: true + configuration-cache-enabled: true + java13: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] + gradle: ["6.0", "6.8.3"] + java: ["13"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + dependencies-cache-enabled: true + configuration-cache-enabled: true + java14: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] + gradle: ["6.3", "6.8.3"] + java: ["14"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + dependencies-cache-enabled: true + configuration-cache-enabled: true + java15: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] + gradle: ["6.7", "6.8.3"] + java: ["15"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + dependencies-cache-enabled: true + configuration-cache-enabled: true + java16-17: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] + gradle: ["6.8.3", "7.0-rc-1"] # See here for latest versions: https://services.gradle.org/versions/ + java: ["16", "17ea"] + fail-fast: false + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + continue-on-error: true + with: + arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + dependencies-cache-enabled: true + configuration-cache-enabled: true diff --git a/README.md b/README.md index 871003ed912..8c161b9072b 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 15 support requires Gradle 6.7 or higher (as per Gradle's release notes) * Java 14 support requires Gradle 6.3 or higher (as per Gradle's release notes) * Java 13 support requires Gradle 6.0 or higher - * Java 11 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) - * Though not supported yet, tests are also run against early-access builds of Java 16 to provide early notification of potential incompatibilities + * Java 8-12 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) + * Though not supported yet, tests are also run against Java 16/17 to provide early notification of potential incompatibilities. It is expected that Java 16+ support will require Gradle 7.0 or higher. * Currently built against Gradle 6.8.3 * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.8.3 * Currently built against Avro 1.10.2 diff --git a/build.gradle b/build.gradle index d93298d4ef3..4780ec9b8f2 100644 --- a/build.gradle +++ b/build.gradle @@ -312,18 +312,17 @@ test { } tasks.create(name: "testCompatibility", type: Test) { - def compatAvroVersion = findProperty("avroVersion") ?: "unspecified" - def compatGradleVersion = findProperty("gradleVersion") ?: "unspecified" - def compatKotlinPluginVersion = findProperty("kotlinPluginVersion") ?: "unspecified" - description = "Test cross-compatibility of the plugin with Avro ${compatAvroVersion}, Gradle ${compatGradleVersion}, and Kotlin ${compatKotlinPluginVersion}" + description = "Test cross-compatibility of the plugin with Avro/Gradle" systemProperties = [ - avroVersion: compatAvroVersion, - gradleVersion: compatGradleVersion, - kotlinPluginVersion: compatKotlinPluginVersion, + avroVersion: findProperty("avroVersion"), + gradleVersion: findProperty("gradleVersion"), ] + filter { + excludeTestsMatching "*KotlinPlugin*" + } reports { - html.destination = file("$buildDir/reports/tests-avro${compatAvroVersion}-gradle${compatGradleVersion}-kotlin${compatKotlinPluginVersion}") - junitXml.destination = file("$buildDir/reports/tests-avro${compatAvroVersion}-gradle${compatGradleVersion}-kotlin${compatKotlinPluginVersion}") + html.destination = file("$buildDir/reports/tests-compatibility") + junitXml.destination = file("$buildDir/reports/tests-compatibility") } } From a4422438c5559879be5b7ec0c59c478974701c9e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 01:19:34 -0400 Subject: [PATCH 383/479] More matrix compatibility tweaks --- .github/workflows/avro-compatibility.yml | 4 +- .github/workflows/ci.yml | 52 ++----------------- .github/workflows/java-compatibility.yml | 22 ++++---- .../workflows/kotlin-plugin-compatibility.yml | 43 +++++++++++---- .github/workflows/os-compatibility.yml | 20 +++++++ .github/workflows/publish.yml | 2 +- CHANGES.md | 1 + README.md | 3 +- 8 files changed, 73 insertions(+), 74 deletions(-) create mode 100644 .github/workflows/os-compatibility.yml diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index aca16e9b89e..396d63ed889 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -2,7 +2,7 @@ name: Avro Compatibility Tests on: [push, pull_request] jobs: test: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -16,6 +16,6 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} dependencies-cache-enabled: true configuration-cache-enabled: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ad43823b89..607f266d868 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,30 +1,21 @@ name: CI Build on: [push, pull_request] jobs: - # Run the main project first to get rapid feedback about anything broken - # on the most important supported versions (latest supported Avro/Gradle, - # earliest supported Java major version) build: - name: Java ${{ matrix.java }}/${{ matrix.os }} baseline build - runs-on: ${{ matrix.os }} - strategy: - matrix: - java: [8] # Minimum supported major version - os: [ubuntu-latest, windows-latest, macOS-latest] # All supported OS + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: - java-version: ${{ matrix.java }} + java-version: 8 - uses: eskatos/gradle-command-action@v1 with: - arguments: --info build + arguments: --no-daemon --info --stacktrace build dependencies-cache-enabled: true configuration-cache-enabled: true - uses: codecov/codecov-action@v1 with: file: ./build/reports/jacoco/test/jacocoTestReport.xml - flags: baseline,${{ matrix.os }} fail_ci_if_error: true # compatibility-tests: # name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}/os ${{ matrix.os }}" @@ -80,40 +71,3 @@ jobs: # uses: eskatos/gradle-command-action@v1 # with: # arguments: --stop -# # Early visibility to whether the project works on upcoming Java versions -# unsupported-java-versions: -# # Most Java version compatibility failures will manifest directly in the -# # test suite with any Avro version; no need to run compatibility test -# # target. -# name: Java ${{ matrix.java }}/${{ matrix.os }} compatibility -# needs: [build] -# runs-on: ${{ matrix.os }} -# strategy: -# matrix: -# os: [ubuntu-latest] # Only a single OS to cut down on execution time -# java: [16-ea] # EA builds of all current pre-release major versions -# fail-fast: false -# steps: -# - name: Check out repository -# uses: actions/checkout@v2 -# - name: Set up Java ${{ matrix.java }} -# uses: actions/setup-java@v1 -# with: -# java-version: ${{ matrix.java }} -# architecture: x64 -# - name: Output Java version -# run: java -version -# - name: Output Gradle version -# uses: eskatos/gradle-command-action@v1 -# with: -# arguments: --version -# - name: Build with Gradle -# continue-on-error: true -# uses: eskatos/gradle-command-action@v1 -# with: -# arguments: --info build -# dependencies-cache-enabled: true -# - name: Stop Gradle Daemon -# uses: eskatos/gradle-command-action@v1 -# with: -# arguments: --stop diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 9b60a6e0ffd..2fe56312477 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -1,8 +1,8 @@ -name: Avro Compatibility Tests +name: Java Compatibility Tests on: [push, pull_request] jobs: java8-12: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -16,11 +16,11 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} dependencies-cache-enabled: true configuration-cache-enabled: true java13: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -34,11 +34,11 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} dependencies-cache-enabled: true configuration-cache-enabled: true java14: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -52,11 +52,11 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} dependencies-cache-enabled: true configuration-cache-enabled: true java15: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -70,11 +70,11 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} dependencies-cache-enabled: true configuration-cache-enabled: true java16-17: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -90,6 +90,6 @@ jobs: - uses: eskatos/gradle-command-action@v1 continue-on-error: true with: - arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} dependencies-cache-enabled: true configuration-cache-enabled: true diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index ec8354759a6..9b0c367e2ab 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -2,7 +2,7 @@ name: Kotlin Plugin Compatibility Tests on: [push, pull_request] jobs: java8-gradle5_1: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}//kotlin ${{ matrix.kotlin }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -10,7 +10,7 @@ jobs: gradle: ["5.1"] # Minimum version that this plugin supports java: ["8"] # Minimum version that this plugin supports kotlin: [ - "1.2.20", "1.2.21", + "1.2.20", "1.2.21", # These don't support Java 10+ "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", "1.3.0", "1.3.10", "1.3.11", "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72" @@ -23,11 +23,11 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --info testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} dependencies-cache-enabled: true configuration-cache-enabled: true java8-gradle5_3: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}//kotlin ${{ matrix.kotlin }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -36,7 +36,7 @@ jobs: java: ["8"] # Minimum version that this plugin supports kotlin: [ # These versions require Gradle 5.3+ - "1.4.0", "1.4.10", "1.4.20", "1.4.21" + "1.4.0", "1.4.10", "1.4.20", "1.4.21", "1.4.30", "1.4.31", "1.4.32" ] steps: - uses: actions/checkout@v2 @@ -45,11 +45,11 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --info testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} dependencies-cache-enabled: true configuration-cache-enabled: true - modern: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}/kotlin ${{ matrix.kotlin }}" + java11-gradle5_6_4: + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}//kotlin ${{ matrix.kotlin }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -58,10 +58,33 @@ jobs: java: ["11"] # Latest LTS version that this plugin supports kotlin: [ # Earlier versions don't support Java 10+ + # These versions don't support Gradle 6+ "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", "1.3.0", "1.3.10", "1.3.11", + ] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + dependencies-cache-enabled: true + configuration-cache-enabled: true + + modern: + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}//kotlin ${{ matrix.kotlin }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] # Latest version that this plugin supports + gradle: ["6.8.3"] # Latest version that this plugin supports + java: ["11"] # Latest LTS version that this plugin supports + kotlin: [ + # Earlier versions lack support for either Java 10+ or Gradle 6+ "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", - "1.4.0", "1.4.10", "1.4.20", "1.4.21" + "1.4.0", "1.4.10", "1.4.20", "1.4.21", "1.4.30", "1.4.31", "1.4.32" ] steps: - uses: actions/checkout@v2 @@ -70,6 +93,6 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --info testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} dependencies-cache-enabled: true configuration-cache-enabled: true diff --git a/.github/workflows/os-compatibility.yml b/.github/workflows/os-compatibility.yml new file mode 100644 index 00000000000..90d8137b3f2 --- /dev/null +++ b/.github/workflows/os-compatibility.yml @@ -0,0 +1,20 @@ +name: OS Compatibility +on: [push, pull_request] +jobs: + build: + name: "Compatibility: ${{ matrix.os }}" + runs-on: ${{ matrix.os }} + strategy: + matrix: + java: [8] # Minimum supported major version + os: [ubuntu-latest, windows-latest, macOS-latest] # All supported OS + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --no-daemon --info --stacktrace build + dependencies-cache-enabled: true + configuration-cache-enabled: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 53fc9497449..c59e7ff6aa9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,7 +12,7 @@ jobs: java-version: 8 - uses: eskatos/gradle-command-action@v1 with: - arguments: --info publish + arguments: --no-daemon --info --stacktrace publish dependencies-cache-enabled: true configuration-cache-enabled: true env: diff --git a/CHANGES.md b/CHANGES.md index 5c0c05ec24b..5e841c215aa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ * Built using Avro 1.10.2 * Built using Gradle 6.8.3 * Updated compatibility testing through Gradle 6.8.3 +* Updated compatibility testing through Kotlin 1.4.32 ## 1.0.0 * Published to Maven Central (no longer published to JCenter) diff --git a/README.md b/README.md index 8c161b9072b..1ead50a0b51 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,10 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently built against Avro 1.10.2 * Currently tested against Avro 1.10.0-1.10.2 * Support for Kotlin - * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.20 using the latest compatible version of Gradle + * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 * Kotlin plugin versions starting with 1.4.0 require Gradle 5.3+ + * Kotlin plugin versions prior to 1.3.20 do not support Gradle 6.0+ * Kotlin plugin versions prior to 1.2.30 do not support Java 10+ * Version of the Kotlin plugin prior to 1.2.20 are unlikely to work * Support for Gradle Kotlin DSL From ffba98d482086fa087bc63399f50bbab58c389c4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 01:21:25 -0400 Subject: [PATCH 384/479] More matrix compatibility tweaks --- .github/workflows/java-compatibility.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 2fe56312477..953bc15c11a 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -80,7 +80,7 @@ jobs: matrix: avro: ["1.10.2"] gradle: ["6.8.3", "7.0-rc-1"] # See here for latest versions: https://services.gradle.org/versions/ - java: ["16", "17ea"] + java: ["16", "17-ea"] fail-fast: false steps: - uses: actions/checkout@v2 From ec08b3ed48b6cc0bde09d3e2f763d6cf68e01e4d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 01:25:44 -0400 Subject: [PATCH 385/479] More matrix compatibility tweaks --- .github/workflows/avro-compatibility.yml | 2 +- .github/workflows/java-compatibility.yml | 10 +++++----- .github/workflows/kotlin-plugin-compatibility.yml | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index 396d63ed889..9263523f4e8 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -2,7 +2,7 @@ name: Avro Compatibility Tests on: [push, pull_request] jobs: test: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" + name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 953bc15c11a..353d9127a5b 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -2,7 +2,7 @@ name: Java Compatibility Tests on: [push, pull_request] jobs: java8-12: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -20,7 +20,7 @@ jobs: dependencies-cache-enabled: true configuration-cache-enabled: true java13: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -38,7 +38,7 @@ jobs: dependencies-cache-enabled: true configuration-cache-enabled: true java14: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -56,7 +56,7 @@ jobs: dependencies-cache-enabled: true configuration-cache-enabled: true java15: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -74,7 +74,7 @@ jobs: dependencies-cache-enabled: true configuration-cache-enabled: true java16-17: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index 9b0c367e2ab..618e5a7770b 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -2,7 +2,7 @@ name: Kotlin Plugin Compatibility Tests on: [push, pull_request] jobs: java8-gradle5_1: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}//kotlin ${{ matrix.kotlin }}" + name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -27,7 +27,7 @@ jobs: dependencies-cache-enabled: true configuration-cache-enabled: true java8-gradle5_3: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}//kotlin ${{ matrix.kotlin }}" + name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -49,7 +49,7 @@ jobs: dependencies-cache-enabled: true configuration-cache-enabled: true java11-gradle5_6_4: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}//kotlin ${{ matrix.kotlin }}" + name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: @@ -74,7 +74,7 @@ jobs: configuration-cache-enabled: true modern: - name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}//kotlin ${{ matrix.kotlin }}" + name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: matrix: From 45dca864393fa7e99c0d8fccc81655c05b637157 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 02:13:18 -0400 Subject: [PATCH 386/479] More matrix compatibility tweaks --- .github/workflows/kotlin-plugin-compatibility.yml | 2 +- build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index 618e5a7770b..7cc942db426 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -54,7 +54,7 @@ jobs: strategy: matrix: avro: ["1.10.2"] # Latest version that this plugin supports - gradle: ["6.8.3"] # Latest version that this plugin supports + gradle: ["5.6.4"] java: ["11"] # Latest LTS version that this plugin supports kotlin: [ # Earlier versions don't support Java 10+ diff --git a/build.gradle b/build.gradle index 4780ec9b8f2..239c53eeefd 100644 --- a/build.gradle +++ b/build.gradle @@ -234,7 +234,7 @@ codenarc { // Java 8+ is required due to requirements introduced in Avro 1.9.0 // Java 8+ is also required by Gradle 5.x -if (JavaVersion.current().java9Compatible) { +if (JavaVersion.current().java10Compatible) { compileJava { options.release = 8 } From 022745b3d715a1391b5c6287f01f7b60038bc4cc Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 09:10:20 -0400 Subject: [PATCH 387/479] Upgrade gradle used to build the project to 7.0-rc-1 in order to support the build running on Java 16 --- .github/workflows/ci.yml | 1 + CHANGES.md | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 607f266d868..6eb75dd4eb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,7 @@ name: CI Build on: [push, pull_request] jobs: build: + name: "Build" runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/CHANGES.md b/CHANGES.md index 5e841c215aa..52db4d2b3f4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ ## Unreleased * Built using Avro 1.10.2 -* Built using Gradle 6.8.3 +* Built using Gradle 7.0-rc-1 * Updated compatibility testing through Gradle 6.8.3 * Updated compatibility testing through Kotlin 1.4.32 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 442d9132ea3..e4bf89ebb80 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-6.8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-rc-1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 016c5a5645685bd72fbb00fea1aa7c25b6b24266 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 10:04:48 -0400 Subject: [PATCH 388/479] More changes for Gradle 7 compatibility --- build.gradle | 22 ++----------------- .../plugin/avro/GradleCompatibility.java | 14 +++++++++++- .../gradle/plugin/avro/FunctionalSpec.groovy | 13 +++++------ 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/build.gradle b/build.gradle index 239c53eeefd..68a99ee05c6 100644 --- a/build.gradle +++ b/build.gradle @@ -28,8 +28,6 @@ repositories { } def compileAvroVersion = "1.10.2" -def codenarcVersion = "1.5" -def codenarcGroovyVersion = "2.5.10" // Newer version than included in 1.5 required for Java 14 support // Write the plugin's classpath to a file to share with the tests task createClasspathManifest { @@ -47,28 +45,12 @@ task createClasspathManifest { dependencies { implementation localGroovy() implementation "org.apache.avro:avro-compiler:${compileAvroVersion}" - testImplementation "org.spockframework:spock-core:1.3-groovy-2.5" + testImplementation "org.spockframework:spock-core:2.0-M5-groovy-3.0" testImplementation gradleTestKit() testImplementation "uk.co.datumedge:hamcrest-json:0.2" testRuntimeOnly files(createClasspathManifest) // Add the classpath file to the test runtime classpath } -configurations { - codenarc { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - if (details.requested.group == "org.codehaus.groovy") { - if (details.requested.name == "groovy" && details.requested.version != codenarcGroovyVersion) { - // Template support appears to have moved between modules in between versions - details.useTarget("${details.requested.group}:groovy-all:${codenarcGroovyVersion}") - } else { - details.useVersion codenarcGroovyVersion - } - details.because "Required for Java 14+ support" - } - } - } -} - tasks.withType(AbstractCompile) { options.encoding = "UTF-8" } @@ -204,7 +186,7 @@ codenarc { maxPriority1Violations = 0 maxPriority2Violations = 0 maxPriority3Violations = 0 - toolVersion = codenarcVersion + toolVersion = "2.0.0" } //tasks.create("testAvroCompatibility") { diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java index 5d0bc9bfea9..707bad5c80a 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java @@ -16,6 +16,8 @@ package com.github.davidmc24.gradle.plugin.avro; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; @@ -33,7 +35,17 @@ static ConfigurableFileCollection createConfigurableFileCollection(Project proje if (GradleFeatures.objectFactoryFileCollection.isSupported()) { return project.getObjects().fileCollection(); } else { - return project.getLayout().configurableFiles(); + return invokeAccessorMethod(project.getLayout(), "configurableFiles"); + } + } + + @SuppressWarnings("unchecked") + private static T invokeAccessorMethod(Object object, String methodName) { + try { + Method method = object.getClass().getMethod(methodName); + return (T) method.invoke(object); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException("Failed to invoke method via reflection", ex); } } } diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy index 3fb45f7e015..48545dec117 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy @@ -18,9 +18,8 @@ package com.github.davidmc24.gradle.plugin.avro import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner import org.gradle.util.GradleVersion -import org.junit.Rule -import org.junit.rules.TemporaryFolder import spock.lang.Specification +import spock.lang.TempDir @SuppressWarnings(["Println"]) abstract class FunctionalSpec extends Specification { @@ -29,8 +28,8 @@ abstract class FunctionalSpec extends Specification { @SuppressWarnings(["FieldName"]) protected static final GradleVersion gradleVersion = GradleVersion.version(System.getProperty("gradleVersion", "undefined")) - @Rule - TemporaryFolder testProjectDir + @TempDir + File testProjectDir File buildFile File avroDir @@ -40,9 +39,9 @@ abstract class FunctionalSpec extends Specification { println "Testing using Avro version ${avroVersion}." println "Testing using Gradle version ${gradleVersion}." - buildFile = testProjectDir.newFile("build.gradle") - avroDir = testProjectDir.newFolder("src", "main", "avro") - avroSubDir = testProjectDir.newFolder("src", "main", "avro", "foo") + buildFile = new File(testProjectDir, "build.gradle") + avroDir = new File(testProjectDir, "src/main/avro") + avroSubDir = new File(testProjectDir, "src/main/avro/foo") } protected String readPluginClasspath() { From d19a36e76a5ad45a107202567578c77085719845 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 10:11:42 -0400 Subject: [PATCH 389/479] Add gradle compatibility tests --- .github/workflows/ci.yml | 54 ---------------------- .github/workflows/gradle-compatibility.yml | 27 +++++++++++ 2 files changed, 27 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/gradle-compatibility.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6eb75dd4eb4..7592f2042ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,57 +18,3 @@ jobs: with: file: ./build/reports/jacoco/test/jacocoTestReport.xml fail_ci_if_error: true -# compatibility-tests: -# name: "Compatibility: avro ${{ matrix.avro }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}/os ${{ matrix.os }}" -# needs: [build] -# runs-on: ${{ matrix.os }} -# strategy: -# matrix: -# avro: ["1.10.0", "1.10.1", "1.10.2"] -# gradle: [ -# "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", -# "1.4.0", "1.4.10", "1.4.20", "1.4.21", -# "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", -# "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", -# "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", -# "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3" -# ] -# java: ["8", "11", "13", "14", "15"] # All supported major versions -## java: [ "8", "11" ] # LTS versions only; 17 will be the next one -# kotlin: [ -# "1.2.20", "1.2.21", -# "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", -# "1.3.0", "1.3.10", "1.3.11", -# "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", -# "1.4.0", "1.4.10", "1.4.20", "1.4.21" -# ] -# # Exclude mac as it's unreliable at the moment -# # See https://github.com/actions/virtual-environments/issues/736 -# os: ["ubuntu-latest", "windows-latest"] -## os: [ "ubuntu-latest" ] # Only a single OS to cut down on execution time -# fail-fast: true -# steps: -# - name: Check out repository -# uses: actions/checkout@v2 -# - name: Set up Java ${{ matrix.java }} -# uses: actions/setup-java@v1 -# with: -# java-version: ${{ matrix.java }} -# architecture: x64 -# - name: Output Avro version -# run: echo "Avro ${{ matrix.avro }}" -# - name: Output Java version -# run: java -version -# - name: Output Gradle version -# uses: eskatos/gradle-command-action@v1 -# with: -# arguments: --version -# - name: Run recent version compatibility tests -# uses: eskatos/gradle-command-action@v1 -# with: -# arguments: --info testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinVersion=${{ matrix.kotlin }} -# dependencies-cache-enabled: true -# - name: Stop Gradle Daemon -# uses: eskatos/gradle-command-action@v1 -# with: -# arguments: --stop diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml new file mode 100644 index 00000000000..b5e1018a21b --- /dev/null +++ b/.github/workflows/gradle-compatibility.yml @@ -0,0 +1,27 @@ +name: Gradle Compatibility Tests +on: [push, pull_request] +jobs: + test: + name: "Compatibility: gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] + gradle: [ + "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", + "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", + "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", + "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3", + "7.0-rc-1" # See here for latest versions: https://services.gradle.org/versions/ + ] + java: ["8", "11"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + dependencies-cache-enabled: true + configuration-cache-enabled: true From 79a619d85b768cf398d016ed35879eb1a7206984 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 23:06:48 -0400 Subject: [PATCH 390/479] More spock 2.0 and Gradle 7 compatibility changes --- build.gradle | 164 +----------------- .../plugin/avro/GradleCompatibility.java | 10 +- .../avro/AvroBasePluginFunctionalSpec.groovy | 3 +- .../CustomConversionFunctionalSpec.groovy | 9 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 18 +- ...erateAvroProtocolTaskFunctionalSpec.groovy | 10 +- .../plugin/avro/IntellijFunctionalSpec.groovy | 8 +- ...otlinDSLCompatibilityFunctionalSpec.groovy | 2 +- ...inPluginCompatibilityFunctionalSpec.groovy | 2 +- .../plugin/avro/OptionsFunctionalSpec.groovy | 2 +- ...eAvroDependenciesTaskFunctionalSpec.groovy | 2 +- 11 files changed, 39 insertions(+), 191 deletions(-) diff --git a/build.gradle b/build.gradle index 68a99ee05c6..d6b28d7eddf 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,3 @@ -import org.gradle.util.GradleVersion - plugins { id "groovy" id "checkstyle" @@ -189,31 +187,6 @@ codenarc { toolVersion = "2.0.0" } -//tasks.create("testAvroCompatibility") { -// description = "Tests cross-compatibility of the plugin with different versions of Avro." -// group = "Verification" -//} -// -//tasks.create("testGradleCompatibility") { -// description = "Tests cross-compatibility of the plugin with different versions of Gradle." -// group = "Verification" -//} -// -//tasks.create("testKotlinCompatibility") { -// description = "Tests cross-compatibility of the plugin with different versions of Kotlin." -// group = "Verification" -//} -// -//tasks.create("testVersionCompatibility") { -// description = "Tests cross-compatibility of the plugin with different versions of Avro, Gradle, and Kotlin." -// group = "Verification" -//} -// -//tasks.create("testRecentVersionCompatibility") { -// description = "Tests cross-compatibility of the plugin with recent versions of Avro, Gradle, and Kotlin." -// group = "Verification" -//} - // Java 8+ is required due to requirements introduced in Avro 1.9.0 // Java 8+ is also required by Gradle 5.x if (JavaVersion.current().java10Compatible) { @@ -224,67 +197,10 @@ if (JavaVersion.current().java10Compatible) { sourceCompatibility = 8 } -//def avroVersions = ["1.10.0", "1.10.1", "1.10.2"] -// -//def keyAvroVersions = avroVersions.last() -//def gradle5KotlinVersions = [] -//if (!JavaVersion.current().java10Compatible) { -// // Java 10 support was added in Kotlin 1.2.30 -// gradle5KotlinVersions.addAll([ -// "1.2.20", "1.2.21", -// ]) -//} -//gradle5KotlinVersions.addAll([ -// "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", -// "1.3.0", "1.3.10", "1.3.11", -//]) -//def latestGradleKotlinVersions = [ -// "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", -// "1.4.0", "1.4.10", "1.4.20", "1.4.21" -//] -//def kotlinVersions = gradle5KotlinVersions + latestGradleKotlinVersions -//def keyKotlinVersions = [] // First and last version for each supported line -//// Determine first supported version -//if (!JavaVersion.current().java10Compatible) { -// // Java 10 support was added in Kotlin 1.2.30 -// keyKotlinVersions.add("1.2.20") -//} else { -// keyKotlinVersions.add("1.2.30") -//} -//keyKotlinVersions.addAll([ -// "1.2.71", -// "1.3.0", "1.3.72", // First and last version for 1.3.x line -// "1.4.0", "1.4.21", // First and last version for 1.4.x line -//]) -//def pre5_3KotlinVersion = "1.3.72" // Kotlin plugin 1.4.x appears to require Gradle 5.3+ -//def keyGradleVersions = [] // First and last version for each supported line -//def firstSupportedGradleVersion = null -//def gradleVersions = [] -//if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { -// // Java 13 support was added in Gradle 6.0 -// gradleVersions.addAll("5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4") -// keyGradleVersions.addAll("5.1", "5.6.4") // First and last for the 5.x line -// firstSupportedGradleVersion = gradleVersions.first() -//} -//if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) { -// // Java 14 support was added in Gradle 6.3 -// gradleVersions.addAll("6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2") -// keyGradleVersions.addAll("6.0", "6.2.2") // First and last for the 6.x line before Java 14 support -//} -//if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_15)) { -// // Java 15 support was added in Gradle 6.7 -// gradleVersions.addAll("6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1") -// keyGradleVersions.addAll("6.3", "6.6.1") // First and last for the 6.x line before Java 15 support -//} -//gradleVersions.addAll("6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3") -//keyGradleVersions.addAll("6.7", "6.8.3") // First and last for the 6.x line after Java 15 support -// -//def latestAvroVersion = avroVersions.last() -//def latestGradleVersion = gradleVersions.last() -//def latestKotlinVersion = kotlinVersions.last() def latestKotlinVersion = "1.4.21" test { + useJUnitPlatform() systemProperties = [ avroVersion: compileAvroVersion, gradleVersion: gradle.gradleVersion, @@ -295,6 +211,7 @@ test { tasks.create(name: "testCompatibility", type: Test) { description = "Test cross-compatibility of the plugin with Avro/Gradle" + useJUnitPlatform() systemProperties = [ avroVersion: findProperty("avroVersion"), gradleVersion: findProperty("gradleVersion"), @@ -310,6 +227,7 @@ tasks.create(name: "testCompatibility", type: Test) { tasks.create(name: "testKotlinPluginCompatibility", type: Test) { description = "Test cross-compatibility of the plugin with the Kotlin plugin" + useJUnitPlatform() systemProperties = [ avroVersion: findProperty("avroVersion"), gradleVersion: findProperty("gradleVersion"), @@ -337,82 +255,6 @@ jacocoTestReport { } } -//avroVersions.each { def avroVersion -> -// gradleVersions.each { def gradleVersion -> -// def kotlinVersion = GradleVersion.version(gradleVersion) < GradleVersion.version("5.3") ? pre5_3KotlinVersion : latestKotlinVersion -// def newTask = tasks.create(name: "testAvro${avroVersion}Gradle${gradleVersion}", type: Test) { -// description = "Test cross-compatibility of the plugin with Avro ${avroVersion} and Gradle ${gradleVersion}" -// systemProperties = [ -// avroVersion: avroVersion, -// gradleVersion: gradleVersion, -// kotlinVersion: kotlinVersion, -// ] -// reports { -// html.destination = file("$buildDir/reports/tests-avro${avroVersion}-gradle${gradleVersion}") -// junitXml.destination = file("$buildDir/reports/tests-avro${avroVersion}-gradle${gradleVersion}") -// } -// } -// testVersionCompatibility.dependsOn newTask -// if (avroVersion == latestAvroVersion) { -// testGradleCompatibility.dependsOn newTask -// } -// if (gradleVersion == latestGradleVersion) { -// testAvroCompatibility.dependsOn newTask -// } -// if (gradleVersion in keyGradleVersions && avroVersion in keyAvroVersions) { -// testRecentVersionCompatibility.dependsOn newTask -// } -// } -//} - -//gradle5KotlinVersions.each { def kotlinVersion -> -// def avroVersion = latestAvroVersion -// def gradleVersion = firstSupportedGradleVersion -// if (gradleVersion) { -// def newTask = tasks.create(name: "testKotlin${kotlinVersion}", type: Test) { -// description = "Test cross-compatibility of the plugin with Kotlin ${kotlinVersion}" -// systemProperties = [ -// avroVersion : avroVersion, -// gradleVersion: gradleVersion, -// kotlinVersion: kotlinVersion, -// ] -// include("**/KotlinCompatibilityFunctionalSpec.class") -// reports { -// html.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") -// junitXml.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") -// } -// } -// testVersionCompatibility.dependsOn newTask -// testKotlinCompatibility.dependsOn newTask -// if (kotlinVersion in keyKotlinVersions) { -// testRecentVersionCompatibility.dependsOn newTask -// } -// } -//} - -//latestGradleKotlinVersions.each { def kotlinVersion -> -// def avroVersion = latestAvroVersion -// def gradleVersion = latestGradleVersion -// def newTask = tasks.create(name: "testKotlin${kotlinVersion}", type: Test) { -// description = "Test cross-compatibility of the plugin with Kotlin ${kotlinVersion}" -// systemProperties = [ -// avroVersion : avroVersion, -// gradleVersion: gradleVersion, -// kotlinVersion: kotlinVersion, -// ] -// include("**/KotlinCompatibilityFunctionalSpec.class") -// reports { -// html.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") -// junitXml.destination = file("$buildDir/reports/tests-kotlin${kotlinVersion}-gradle${gradleVersion}") -// } -// } -// testVersionCompatibility.dependsOn newTask -// testKotlinCompatibility.dependsOn newTask -// if (kotlinVersion in keyKotlinVersions) { -// testRecentVersionCompatibility.dependsOn newTask -// } -//} - tasks.withType(Test) { jvmArgs "-Xss320k" minHeapSize "120m" diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java index 707bad5c80a..d51e6ab0b0b 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java @@ -35,15 +35,17 @@ static ConfigurableFileCollection createConfigurableFileCollection(Project proje if (GradleFeatures.objectFactoryFileCollection.isSupported()) { return project.getObjects().fileCollection(); } else { - return invokeAccessorMethod(project.getLayout(), "configurableFiles"); + Class[] parameterTypes = { Object[].class }; + Object[] args = { new Object[0] }; + return invokeMethod(project.getLayout(), "configurableFiles", parameterTypes, args); } } @SuppressWarnings("unchecked") - private static T invokeAccessorMethod(Object object, String methodName) { + private static T invokeMethod(Object object, String methodName, Class[] parameterTypes, Object[] args) { try { - Method method = object.getClass().getMethod(methodName); - return (T) method.invoke(object); + Method method = object.getClass().getMethod(methodName, parameterTypes); + return (T) method.invoke(object, args); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { throw new RuntimeException("Failed to invoke method via reflection", ex); } diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy index 22c342d590d..f6b44afadde 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy @@ -60,8 +60,7 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { then: result.task(":generateSchema").outcome == SUCCESS def expectedFileContents = getClass().getResource("Message.avsc").text.trim() - def generateFileContents = new File(testProjectDir.root, - "build/generated-main-avro-avsc/org/apache/avro/test/Message.avsc").text.trim() + def generateFileContents = projectFile("build/generated-main-avro-avsc/org/apache/avro/test/Message.avsc").text.trim() expectedFileContents == generateFileContents } diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index 2941fff9f95..6ab7f0513b5 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -51,8 +51,7 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { |""".stripMargin() addDefaultRepository() addAvroDependency() - testProjectDir.newFolder("buildSrc") - testProjectDir.newFile("buildSrc/build.gradle") << """ + projectFile("buildSrc/build.gradle") << """ |repositories { | mavenCentral() |} @@ -98,8 +97,7 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { |""".stripMargin() addDefaultRepository() addAvroDependency() - testProjectDir.newFolder("buildSrc") - testProjectDir.newFile("buildSrc/build.gradle") << """ + projectFile("buildSrc/build.gradle") << """ |repositories { | mavenCentral() |} @@ -145,8 +143,7 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { |""".stripMargin() addDefaultRepository() addAvroDependency() - testProjectDir.newFolder("buildSrc") - testProjectDir.newFile("buildSrc/build.gradle") << """ + projectFile("buildSrc/build.gradle") << """ |repositories { | mavenCentral() |} diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy index 48545dec117..b4cd472d744 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy @@ -39,9 +39,9 @@ abstract class FunctionalSpec extends Specification { println "Testing using Avro version ${avroVersion}." println "Testing using Gradle version ${gradleVersion}." - buildFile = new File(testProjectDir, "build.gradle") - avroDir = new File(testProjectDir, "src/main/avro") - avroSubDir = new File(testProjectDir, "src/main/avro/foo") + buildFile = projectFile("build.gradle") + avroDir = projectFile("src/main/avro") + avroSubDir = projectFile("src/main/avro/foo") } protected String readPluginClasspath() { @@ -108,11 +108,19 @@ abstract class FunctionalSpec extends Specification { } protected File projectFile(String path) { - return new File(testProjectDir.root, path) + File file = new File(testProjectDir, path) + file.parentFile.mkdirs() + return file + } + + protected File projectFolder(String path) { + File file = new File(testProjectDir, path) + file.mkdirs() + return file } protected GradleRunner createGradleRunner() { - return GradleRunner.create().withProjectDir(testProjectDir.root).withGradleVersion(gradleVersion.version).withPluginClasspath() + return GradleRunner.create().withProjectDir(testProjectDir).withGradleVersion(gradleVersion.version).withPluginClasspath() } protected BuildResult run(String... args = ["build"]) { diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy index 7c0533d8800..4c1f71645a9 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy @@ -40,8 +40,8 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { |} |""".stripMargin() - copyResource("shared.avdl", testProjectDir.newFolder("src", "shared")) - copyResource("dependent.avdl", testProjectDir.newFolder("src", "dependent")) + copyResource("shared.avdl", projectFolder("src/shared")) + copyResource("dependent.avdl", projectFolder("src/dependent")) when: "running the task" def result = run("generateProtocol") @@ -64,7 +64,7 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { |} |""".stripMargin() - copyResource("shared.avdl", testProjectDir.newFolder("src", "shared")) + copyResource("shared.avdl", projectFolder("src/shared")) copyResource("dependent.avdl", avroDir) when: "running the task" @@ -80,8 +80,8 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { given: "a project with two IDL files with the same name, but in different directories" applyAvroPlugin() - copyResource("namespaced-idl/v1/test.avdl", testProjectDir.newFolder("src", "main", "avro", "v1")) - copyResource("namespaced-idl/v2/test.avdl", testProjectDir.newFolder("src", "main", "avro", "v2")) + copyResource("namespaced-idl/v1/test.avdl", projectFolder("src/main/avro/v1")) + copyResource("namespaced-idl/v2/test.avdl", projectFolder("src/main/avro/v2")) when: "running the task" def result = run("generateAvroProtocol") diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy index 7d7b7403bad..f6362148e19 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy @@ -28,15 +28,15 @@ class IntellijFunctionalSpec extends FunctionalSpec { def "generated intellij project files include source directories for generated source"() { given: copyResource("user.avsc", avroDir) - testProjectDir.newFolder("src", "main", "java") - testProjectDir.newFolder("src", "test", "java") - testProjectDir.newFolder("src", "test", "avro") + projectFolder("src/main/java") + projectFolder("src/test/java") + projectFolder("src/test/avro") when: runIdea() then: - def moduleFile = new File(testProjectDir.root, "${testProjectDir.root.name}.iml") + def moduleFile = projectFile("${testProjectDir.name}.iml") def module = new XmlSlurper().parseText(moduleFile.text) module.component.content.sourceFolder.findAll { it.@isTestSource.text() == "false" }.@url*.text().sort() == [ 'file://$MODULE_DIR\$/build/generated-main-avro-java', diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy index 87f5fe7b819..dee1f2f1c34 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy @@ -7,7 +7,7 @@ class KotlinDSLCompatibilityFunctionalSpec extends FunctionalSpec { def "setup"() { buildFile.delete() // Don't use the Groovy build file created by the superclass - kotlinBuildFile = testProjectDir.newFile("build.gradle.kts") + kotlinBuildFile = projectFile("build.gradle.kts") kotlinBuildFile << """ |plugins { | java diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy index bf14102dd92..e248690cb74 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy @@ -29,7 +29,7 @@ class KotlinPluginCompatibilityFunctionalSpec extends FunctionalSpec { def "works with kotlin-gradle-plugin"() { given: - File kotlinDir = testProjectDir.newFolder("src", "main", "kotlin") + File kotlinDir = projectFolder("src/main/kotlin") applyAvroPlugin() applyPlugin("org.jetbrains.kotlin.jvm", kotlinPluginVersion) applyPlugin("application") diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy index d73502e0f61..22e185fcd3e 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -238,7 +238,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { def "supports configuring templateDirectory"() { given: - def templatesDir = testProjectDir.newFolder("templates", "alternateTemplates") + def templatesDir = projectFolder("templates/alternateTemplates") copyResource("user.avsc", avroDir) copyResource("record.vm", templatesDir) // This functionality doesn't work with the plugins DSL syntax. diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy index 616f1978031..b9204417c36 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy @@ -9,7 +9,7 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @Subject(ResolveAvroDependenciesTask) class ResolveAvroDependenciesTaskFunctionalSpec extends FunctionalSpec { def "resolves dependencies"() { - def srcDir = testProjectDir.newFolder("src", "avro", "normalized") + def srcDir = projectFolder("src/avro/normalized") given: "a build with the task declared" applyAvroBasePlugin() From 1ede2cba5793c2295dd1ff2440d458aea54e62ec Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 23:11:10 -0400 Subject: [PATCH 391/479] Fix checkstyle violation --- .../davidmc24/gradle/plugin/avro/GradleCompatibility.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java index d51e6ab0b0b..0ac2b04e175 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java @@ -35,8 +35,8 @@ static ConfigurableFileCollection createConfigurableFileCollection(Project proje if (GradleFeatures.objectFactoryFileCollection.isSupported()) { return project.getObjects().fileCollection(); } else { - Class[] parameterTypes = { Object[].class }; - Object[] args = { new Object[0] }; + Class[] parameterTypes = {Object[].class}; + Object[] args = {new Object[0]}; return invokeMethod(project.getLayout(), "configurableFiles", parameterTypes, args); } } From 5066bb322be0b234b01bef3d7f15ca7ae379616f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 23:17:37 -0400 Subject: [PATCH 392/479] Tweak CI targets --- .github/workflows/os-compatibility.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/os-compatibility.yml b/.github/workflows/os-compatibility.yml index 90d8137b3f2..e512e477ebf 100644 --- a/.github/workflows/os-compatibility.yml +++ b/.github/workflows/os-compatibility.yml @@ -15,6 +15,6 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --no-daemon --info --stacktrace build + arguments: --no-daemon --info --stacktrace testCompatibility dependencies-cache-enabled: true configuration-cache-enabled: true From 1b845b7c81af2cdf03877ea3c19f9267b21c19b8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 23:26:01 -0400 Subject: [PATCH 393/479] Adjust compatibility notes/testing for java 16/17 --- .github/workflows/java-compatibility.yml | 24 +++++++++++++++++++++--- README.md | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 353d9127a5b..1c1a7ae7823 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -73,14 +73,32 @@ jobs: arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} dependencies-cache-enabled: true configuration-cache-enabled: true - java16-17: + java16: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: avro: ["1.10.2"] - gradle: ["6.8.3", "7.0-rc-1"] # See here for latest versions: https://services.gradle.org/versions/ - java: ["16", "17-ea"] + gradle: ["7.0-rc-1"] # See here for latest versions: https://services.gradle.org/versions/ + java: ["16"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + dependencies-cache-enabled: true + configuration-cache-enabled: true + java17: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.10.2"] + gradle: ["7.0-rc-1"] # See here for latest versions: https://services.gradle.org/versions/ + java: ["17-ea"] fail-fast: false steps: - uses: actions/checkout@v2 diff --git a/README.md b/README.md index 1ead50a0b51..8bfcff22382 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav **NOTE**: Pre-1.0 versions used a different publishing process/namespace. It is strongly recommended to upgrade to a newer version. Further details can be found in the [change log](CHANGES.md). * Currently tested against Java 8-15 + * Java 17 is not yet supported + * Java 16 appears to work in Gradle 7.0-rc-1; use at your own risk * Java 15 support requires Gradle 6.7 or higher (as per Gradle's release notes) * Java 14 support requires Gradle 6.3 or higher (as per Gradle's release notes) * Java 13 support requires Gradle 6.0 or higher From a7a4a7c09708410fe9da86d70cdb08f77e29cc5b Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 1 Apr 2021 23:56:59 -0400 Subject: [PATCH 394/479] Use nexus publish plugin to automate management of OSSRH interactions --- .github/workflows/publish.yml | 6 +++--- build.gradle | 16 +++++----------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 996f8746685..b797edac8a6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,10 +12,10 @@ jobs: with: java-version: 8 - name: Publish package - run: ./gradlew publish + run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository env: - MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + ORG_GRADLE_PROJECT_SONATYPEPASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPEPASSWORD }} + ORG_GRADLE_PROJECT_SONATYPEUSERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPEUSERNAME }} SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} SIGNING_KEY: ${{ secrets.SIGNING_KEY }} SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} diff --git a/build.gradle b/build.gradle index 97cc6477ed2..a26b4804e48 100644 --- a/build.gradle +++ b/build.gradle @@ -10,13 +10,13 @@ plugins { id "signing" id "java-gradle-plugin" id "org.nosphere.gradle.github.actions" version "1.2.0" + id "io.github.gradle-nexus.publish-plugin" version "1.0.0" } group = "com.github.davidmc24.gradle.plugin" version = "1.0.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" -def isSnapshot = version.endsWith('-SNAPSHOT') repositories { mavenCentral() @@ -118,17 +118,11 @@ publishing { } } } +} + +nexusPublishing { repositories { - maven { - def snapshotUrl = "https://oss.sonatype.org/content/repositories/snapshots/" - def releaseUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - name = "OSSRH" - url = isSnapshot ? snapshotUrl : releaseUrl - credentials { - username = System.getenv("MAVEN_USERNAME") - password = System.getenv("MAVEN_PASSWORD") - } - } + sonatype() } } From e15472b5c9a57fb710c04335ffcfd5dd5a9ffc3c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 2 Apr 2021 00:14:19 -0400 Subject: [PATCH 395/479] Adjust test report directories --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 8ee373430ba..e36f3a9a3ce 100644 --- a/build.gradle +++ b/build.gradle @@ -214,8 +214,8 @@ tasks.create(name: "testCompatibility", type: Test) { excludeTestsMatching "*KotlinPlugin*" } reports { - html.destination = file("$buildDir/reports/tests-compatibility") - junitXml.destination = file("$buildDir/reports/tests-compatibility") + html.destination = file("$buildDir/reports/tests/compatibility") + junitXml.destination = file("$buildDir/reports/tests/compatibility") } } @@ -231,8 +231,8 @@ tasks.create(name: "testKotlinPluginCompatibility", type: Test) { includeTestsMatching "*KotlinPlugin*" } reports { - html.destination = file("$buildDir/reports/tests-kotlinPluginCompatibility") - junitXml.destination = file("$buildDir/reports/tests-kotlinPluginCompatibility") + html.destination = file("$buildDir/reports/tests/kotlinPluginCompatibility") + junitXml.destination = file("$buildDir/reports/tests/kotlinPluginCompatibility") } } From d4bec4ce90992f6e7a900b761c8cf04896d8f285 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 2 Apr 2021 00:16:41 -0400 Subject: [PATCH 396/479] Fix os compatibility tests --- .github/workflows/os-compatibility.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/os-compatibility.yml b/.github/workflows/os-compatibility.yml index e512e477ebf..6c1d646ffc5 100644 --- a/.github/workflows/os-compatibility.yml +++ b/.github/workflows/os-compatibility.yml @@ -15,6 +15,6 @@ jobs: java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: - arguments: --no-daemon --info --stacktrace testCompatibility + arguments: --no-daemon --info --stacktrace test dependencies-cache-enabled: true configuration-cache-enabled: true From bb799dddc4bf3b51a3f02837cc703053a8c99f84 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 2 Apr 2021 00:34:31 -0400 Subject: [PATCH 397/479] Update changelog --- CHANGES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 52db4d2b3f4..06b153de365 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,8 +3,10 @@ ## Unreleased * Built using Avro 1.10.2 * Built using Gradle 7.0-rc-1 -* Updated compatibility testing through Gradle 6.8.3 +* Updated compatibility testing through Gradle 6.8.3/7.0-rc-1 * Updated compatibility testing through Kotlin 1.4.32 +* Updated compatibility testing to include Java 16/17-ea +* Adopted Github Actions for compatibility testing ## 1.0.0 * Published to Maven Central (no longer published to JCenter) From 0a5dad3f8e34eccf1234edfeb969717d4a5ea9c7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 2 Apr 2021 08:16:07 -0400 Subject: [PATCH 398/479] version: 1.1.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 06b153de365..8de2e95c0dc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 1.1.0 * Built using Avro 1.10.2 * Built using Gradle 7.0-rc-1 * Updated compatibility testing through Gradle 6.8.3/7.0-rc-1 diff --git a/build.gradle b/build.gradle index e36f3a9a3ce..87e4d0b7983 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ plugins { } group = "com.github.davidmc24.gradle.plugin" -version = "1.0.1-SNAPSHOT" +version = "1.1.0" def isCI = System.getenv("CI") == "true" From 31abdf968e86893a5aeddd231a8a665b7c9e6179 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 2 Apr 2021 08:21:06 -0400 Subject: [PATCH 399/479] version: 1.1.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 87e4d0b7983..dc5a8fe6894 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ plugins { } group = "com.github.davidmc24.gradle.plugin" -version = "1.1.0" +version = "1.1.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" From 7cd0ed787183376edd09e5ecdfc02283edba0de4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 2 Apr 2021 09:21:02 -0400 Subject: [PATCH 400/479] Try to fix publishing --- .github/workflows/publish.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b1ac2776963..7d2b3b4dc89 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,12 +12,11 @@ jobs: java-version: 8 - uses: eskatos/gradle-command-action@v1 with: - arguments: --no-daemon --info --stacktrace publishToSonatype closeAndReleaseSonatypeStagingRepository + # For now, release manually; closeAndReleaseSonatypeStagingRepository when I have confidence + arguments: --no-daemon --info --stacktrace publishToSonatype closeSonatypeStagingRepository -PsonatypeUsername=${{ secrets.SONATYPE_USERNAME }} -PsonatypePassword=${{ secrets.SONATYPE_PASSWORD }} dependencies-cache-enabled: true configuration-cache-enabled: true env: - ORG_GRADLE_PROJECT_SONATYPEPASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPEPASSWORD }} - ORG_GRADLE_PROJECT_SONATYPEUSERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPEUSERNAME }} SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} SIGNING_KEY: ${{ secrets.SIGNING_KEY }} SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} From 4fb85a479e8b6cf42e9e969fe42516dffa113711 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 2 Apr 2021 09:22:14 -0400 Subject: [PATCH 401/479] Temporary change to test the CI publishing fix --- .github/workflows/publish.yml | 3 +++ build.gradle | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7d2b3b4dc89..5a31e4a813f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,6 +2,9 @@ name: Publish package to the Maven Central Repository on: release: types: [created] + push: + branches: + - fix-publish jobs: publish: runs-on: ubuntu-latest diff --git a/build.gradle b/build.gradle index dc5a8fe6894..8af2e14c014 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ plugins { } group = "com.github.davidmc24.gradle.plugin" -version = "1.1.1-SNAPSHOT" +version = "1.1.1" def isCI = System.getenv("CI") == "true" From 9cda2c7c4e89d070cf2dec066ff44b5ecef74d4a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 2 Apr 2021 09:27:25 -0400 Subject: [PATCH 402/479] Revert "Temporary change to test the CI publishing fix" This reverts commit 4fb85a479e8b6cf42e9e969fe42516dffa113711. --- .github/workflows/publish.yml | 3 --- build.gradle | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5a31e4a813f..7d2b3b4dc89 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,9 +2,6 @@ name: Publish package to the Maven Central Repository on: release: types: [created] - push: - branches: - - fix-publish jobs: publish: runs-on: ubuntu-latest diff --git a/build.gradle b/build.gradle index 8af2e14c014..dc5a8fe6894 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ plugins { } group = "com.github.davidmc24.gradle.plugin" -version = "1.1.1" +version = "1.1.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" From 71583e8ca7f18b863ca9d3e8ef2ebe105580145d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 12 Apr 2021 19:35:05 -0400 Subject: [PATCH 403/479] Re-add support for Avro 1.9.x --- .github/workflows/avro-compatibility.yml | 2 +- .../workflows/kotlin-plugin-compatibility.yml | 4 +- README.md | 2 +- build.gradle | 3 + .../avro/AvroPluginFunctionalSpec.groovy | 8 ++- .../BuildCacheSupportFunctionalSpec.groovy | 2 +- .../gradle/plugin/avro/FunctionalSpec.groovy | 11 +++- .../gradle/plugin/avro/interop-1.9.avdl | 55 +++++++++++++++++++ 8 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop-1.9.avdl diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index 9263523f4e8..0d015869185 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -6,7 +6,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.0", "1.10.1", "1.10.2"] + avro: ["1.9.0", "1.9.1", "1.9.2", "1.10.0", "1.10.1", "1.10.2"] gradle: ["5.1", "6.8.3"] java: ["8"] steps: diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index 7cc942db426..b8d94ce57b6 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -6,7 +6,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.0"] # Minimum version that this plugin supports + avro: ["1.9.0"] # Minimum version that this plugin supports gradle: ["5.1"] # Minimum version that this plugin supports java: ["8"] # Minimum version that this plugin supports kotlin: [ @@ -31,7 +31,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.0"] # Minimum version that this plugin supports + avro: ["1.9.0"] # Minimum version that this plugin supports gradle: ["5.3"] # Minimum version supported by these versions of the Kotlin plugin java: ["8"] # Minimum version that this plugin supports kotlin: [ diff --git a/README.md b/README.md index 8bfcff22382..fac514c3941 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently built against Gradle 6.8.3 * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.8.3 * Currently built against Avro 1.10.2 - * Currently tested against Avro 1.10.0-1.10.2 + * Currently tested against Avro 1.9.0-1.10.2 * Support for Kotlin * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 diff --git a/build.gradle b/build.gradle index dc5a8fe6894..bd778437271 100644 --- a/build.gradle +++ b/build.gradle @@ -46,6 +46,7 @@ dependencies { testImplementation "org.spockframework:spock-core:2.0-M5-groovy-3.0" testImplementation gradleTestKit() testImplementation "uk.co.datumedge:hamcrest-json:0.2" + testImplementation "com.vdurmont:semver4j:3.1.0" testRuntimeOnly files(createClasspathManifest) // Add the classpath file to the test runtime classpath } @@ -205,6 +206,7 @@ test { tasks.create(name: "testCompatibility", type: Test) { description = "Test cross-compatibility of the plugin with Avro/Gradle" + group = "Verification" useJUnitPlatform() systemProperties = [ avroVersion: findProperty("avroVersion"), @@ -221,6 +223,7 @@ tasks.create(name: "testCompatibility", type: Test) { tasks.create(name: "testKotlinPluginCompatibility", type: Test) { description = "Test cross-compatibility of the plugin with the Kotlin plugin" + group = "Verification" useJUnitPlatform() systemProperties = [ avroVersion: findProperty("avroVersion"), diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy index 94054f48658..5e7532e73af 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy @@ -55,7 +55,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def "can generate and compile java files from IDL"() { given: - copyResource("interop.avdl", avroDir) + copyResource(interopIDLResourceName, avroDir) when: def result = run() @@ -89,7 +89,9 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { interopJavaContent.contains("LocalDate dateField") interopJavaContent.contains("LocalTime timeField") interopJavaContent.contains("Instant timeStampField") - interopJavaContent.contains("LocalDateTime localTimeStampField") + if (localTimestampConversionSupported) { + interopJavaContent.contains("LocalDateTime localTimeStampField") + } } def "supports json schema files in subdirectories"() { @@ -122,7 +124,7 @@ class AvroPluginFunctionalSpec extends FunctionalSpec { def "supports IDL files in subdirectories"() { given: - copyResource("interop.avdl", avroSubDir) + copyResource(interopIDLResourceName, avroSubDir) when: def result = run() diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy index 8906f9e57b8..bcf7b06c188 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy @@ -58,7 +58,7 @@ class BuildCacheSupportFunctionalSpec extends FunctionalSpec { @IgnoreIf({ OperatingSystem.current.windows }) def "supports build cache for IDL to protocol conversion"() { given: "a project is built once with build cache enabled" - copyResource("interop.avdl", avroDir) + copyResource(interopIDLResourceName, avroDir) run("build", "--build-cache") and: "the project is cleaned" diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy index b4cd472d744..01496b040de 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy @@ -15,6 +15,7 @@ */ package com.github.davidmc24.gradle.plugin.avro +import com.vdurmont.semver4j.Semver import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner import org.gradle.util.GradleVersion @@ -24,7 +25,7 @@ import spock.lang.TempDir @SuppressWarnings(["Println"]) abstract class FunctionalSpec extends Specification { @SuppressWarnings(["FieldName"]) - protected static final String avroVersion = System.getProperty("avroVersion", "undefined") + protected static final Semver avroVersion = new Semver(System.getProperty("avroVersion", "undefined")) @SuppressWarnings(["FieldName"]) protected static final GradleVersion gradleVersion = GradleVersion.version(System.getProperty("gradleVersion", "undefined")) @@ -143,4 +144,12 @@ abstract class FunctionalSpec extends Specification { } return arguments } + + protected boolean isLocalTimestampConversionSupported() { + return avroVersion.isGreaterThanOrEqualTo(new Semver("1.10.0")) + } + + protected String getInteropIDLResourceName() { + return localTimestampConversionSupported ? "interop.avdl" : "interop-1.9.avdl" + } } diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop-1.9.avdl b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop-1.9.avdl new file mode 100644 index 00000000000..9adcb7d7bc5 --- /dev/null +++ b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop-1.9.avdl @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +// Currently genavro only does Protocols. +@namespace("org.apache.avro") +protocol InteropProtocol { + record Foo { + string label; + } + + enum Kind { A, B, C } + fixed MD5(16); + + record Node { + string label; + array children = []; + } + + record Interop { + int intField = 1; + long longField = -1; + string stringField; + boolean boolField = false; + float floatField = 0.0; + double doubleField = -1.0e12; + null nullField; + array arrayField = []; + map mapField; + union { boolean, double, array } unionField; + Kind enumField; + MD5 fixedField; + Node recordField; + decimal(10,2) decimalField; + date dateField; + time_ms timeField; + timestamp_ms timeStampField; +// local_timestamp_ms is not supported in Avro 1.9.x +// local_timestamp_ms localTimeStampField; + } +} From a519def9d10038e9cdcbd59c4640fe735ba159b2 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 12 Apr 2021 19:36:17 -0400 Subject: [PATCH 404/479] Update release notes --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 8de2e95c0dc..8066d808529 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Avro 1.9.0-1.9.2 is supported again (no changed needed; just change in support policy and testing) ## 1.1.0 * Built using Avro 1.10.2 From b78769e7c320e7d7f0b47b6e4331ad201851b3d4 Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Wed, 21 Apr 2021 15:07:25 -0700 Subject: [PATCH 405/479] Throw error if avdl will be overwritten --- .../plugin/avro/GenerateAvroProtocolTask.java | 10 +++++++++- ...GenerateAvroProtocolTaskFunctionalSpec.groovy | 16 ++++++++++++++++ .../namespaced-idl/v1/test_same_protocol.avdl | 6 ++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test_same_protocol.avdl diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java index 9ae839e25b2..627a6add378 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -20,8 +20,10 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Set; import org.apache.avro.Protocol; import org.apache.avro.compiler.idl.Idl; import org.apache.avro.compiler.idl.ParseException; @@ -41,10 +43,12 @@ public class GenerateAvroProtocolTask extends OutputDirTask { private FileCollection classpath; + private Set processedFiles; public GenerateAvroProtocolTask() { super(); this.classpath = GradleCompatibility.createConfigurableFileCollection(getProject()); + this.processedFiles = new HashSet(); } public void setClasspath(FileCollection classpath) { @@ -89,11 +93,15 @@ private void processIDLFile(File idlFile, ClassLoader loader) { getLogger().info("Processing {}", idlFile); try (Idl idl = new Idl(idlFile, loader)) { Protocol protocol = idl.CompilationUnit(); + String filePath = AvroUtils.assemblePath(protocol); + if (!processedFiles.add(filePath)) { + throw new GradleException("File already processed with same namespace and protocol name."); + } File protoFile = new File(getOutputDir().get().getAsFile(), AvroUtils.assemblePath(protocol)); String protoJson = protocol.toString(true); FileUtils.writeJsonFile(protoFile, protoJson); getLogger().debug("Wrote {}", protoFile.getPath()); - } catch (IOException | ParseException ex) { + } catch (IOException | ParseException | GradleException ex) { throw new GradleException(String.format("Failed to compile IDL file %s", idlFile), ex); } } diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy index 4c1f71645a9..ad7e17b118e 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy @@ -91,4 +91,20 @@ class GenerateAvroProtocolTaskFunctionalSpec extends FunctionalSpec { projectFile("build/generated-main-avro-avpr/org/example/v1/TestProtocol.avpr").file projectFile("build/generated-main-avro-avpr/org/example/v2/TestProtocol.avpr").file } + + def "fails if avpr will be overwritten"() { + given: "a project with two IDL files with the same protocol name and namespace" + applyAvroPlugin() + + copyResource("namespaced-idl/v1/test.avdl", projectFolder("src/main/avro/v1")) + copyResource("namespaced-idl/v1/test_same_protocol.avdl", projectFolder("src/main/avro/v1")) + + when: "running the task" + run("generateAvroProtocol") + + then: + def ex = thrown(Exception) + ex.message.contains("Failed to compile IDL file") + ex.message.contains("File already processed with same namespace and protocol name.") + } } diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test_same_protocol.avdl b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test_same_protocol.avdl new file mode 100644 index 00000000000..f388f899ad6 --- /dev/null +++ b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test_same_protocol.avdl @@ -0,0 +1,6 @@ +@namespace("org.example.v1") +protocol TestProtocol { + record SomeOtherTestRecord { + string field1; + } +} From fcedbd643c27c49fbde9342bca2f9d644e370b2d Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Wed, 21 Apr 2021 16:00:56 -0700 Subject: [PATCH 406/479] Add to changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 8066d808529..573d4789bfa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## Unreleased * Avro 1.9.0-1.9.2 is supported again (no changed needed; just change in support policy and testing) +* `generateAvroProtocol` task fails if avpr file will get overwritten (due to mutliple IDL files using the same namespace and protocol) ## 1.1.0 * Built using Avro 1.10.2 From 269014e6b3802e856989a52c3a4c81969d4a7c54 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 21 Apr 2021 22:22:02 -0400 Subject: [PATCH 407/479] Minor touchups on avpr conflict detection --- CHANGES.md | 2 +- .../davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 573d4789bfa..9f51dbd48b6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ ## Unreleased * Avro 1.9.0-1.9.2 is supported again (no changed needed; just change in support policy and testing) -* `generateAvroProtocol` task fails if avpr file will get overwritten (due to mutliple IDL files using the same namespace and protocol) +* `generateAvroProtocol` task fails if avpr file will get overwritten (due to multiple IDL files using the same namespace and protocol) ## 1.1.0 * Built using Avro 1.10.2 diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java index 627a6add378..7323f82a5f4 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -92,12 +92,13 @@ private void processFiles() { private void processIDLFile(File idlFile, ClassLoader loader) { getLogger().info("Processing {}", idlFile); try (Idl idl = new Idl(idlFile, loader)) { + File outputDir = getOutputDir().get().getAsFile(); Protocol protocol = idl.CompilationUnit(); String filePath = AvroUtils.assemblePath(protocol); if (!processedFiles.add(filePath)) { throw new GradleException("File already processed with same namespace and protocol name."); } - File protoFile = new File(getOutputDir().get().getAsFile(), AvroUtils.assemblePath(protocol)); + File protoFile = new File(outputDir, filePath); String protoJson = protocol.toString(true); FileUtils.writeJsonFile(protoFile, protoJson); getLogger().debug("Wrote {}", protoFile.getPath()); From 9b0a7d9a26f0f610ee06731ba1777e2449024584 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 21 Apr 2021 22:22:40 -0400 Subject: [PATCH 408/479] Add support for better coverage reporting... and disable it because it conflicts with configuration caching in Gradle 7.0 --- .github/workflows/ci.yml | 8 ++--- build.gradle | 35 ++++++++++++------- .../gradle/plugin/avro/FunctionalSpec.groovy | 12 ++++++- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7592f2042ae..33b9131d5bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: arguments: --no-daemon --info --stacktrace build dependencies-cache-enabled: true configuration-cache-enabled: true - - uses: codecov/codecov-action@v1 - with: - file: ./build/reports/jacoco/test/jacocoTestReport.xml - fail_ci_if_error: true +# - uses: codecov/codecov-action@v1 +# with: +# file: ./build/reports/jacoco/test/jacocoTestReport.xml +# fail_ci_if_error: true diff --git a/build.gradle b/build.gradle index bd778437271..c0fd0d4c593 100644 --- a/build.gradle +++ b/build.gradle @@ -3,14 +3,23 @@ plugins { id "checkstyle" id "codenarc" id "idea" - id "jacoco" +// id "jacoco" id "maven-publish" id "signing" id "java-gradle-plugin" id "org.nosphere.gradle.github.actions" version "1.2.0" id "io.github.gradle-nexus.publish-plugin" version "1.0.0" +// id "pl.droidsonroids.jacoco.testkit" version "1.0.8" } +// Gradle TestKit (which most of this plugins tests run using) runs the builds in a separate +// JVM than the tests. Thus, for Jacoco to pick up on it, you need to do some extra legwork. +// https://github.com/koral--/jacoco-gradle-testkit-plugin seeks to solve that +// However, Gradle 7.0-rc-1 doesn't currently support the combination of the configuration cache +// with a Java agent (such as Jacoco) and TestKit. +// Thus, for now, no coverage reporting, as I place a higher value on testing configuration cache +// support. + group = "com.github.davidmc24.gradle.plugin" version = "1.1.1-SNAPSHOT" @@ -201,7 +210,7 @@ test { gradleVersion: gradle.gradleVersion, kotlinPluginVersion: latestKotlinVersion, ] - finalizedBy jacocoTestReport // report is always generated after tests run +// finalizedBy jacocoTestReport // report is always generated after tests run } tasks.create(name: "testCompatibility", type: Test) { @@ -239,18 +248,18 @@ tasks.create(name: "testKotlinPluginCompatibility", type: Test) { } } -jacoco { - // 0.8.7+ needed for Java 15 support - // See https://www.jacoco.org/jacoco/trunk/doc/changes.html - toolVersion = "0.8.7-SNAPSHOT" -} +//jacoco { +// // 0.8.7+ needed for Java 15 support +// // See https://www.jacoco.org/jacoco/trunk/doc/changes.html +// toolVersion = "0.8.7-SNAPSHOT" +//} -jacocoTestReport { - reports { - html.enabled true - xml.enabled true - } -} +//jacocoTestReport { +// reports { +// html.enabled true +// xml.enabled true +// } +//} tasks.withType(Test) { jvmArgs "-Xss320k" diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy index 01496b040de..a247987ed1d 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy @@ -96,7 +96,15 @@ abstract class FunctionalSpec extends Specification { } protected void copyResource(String name, File targetFolder) { - def file = new File(targetFolder, name) + copyResource(name, targetFolder, name) + } + + protected void copyResource(String name, File targetFolder, String targetName) { + def resource = getClass().getResourceAsStream(name) + def file = new File(targetFolder, targetName) + if (resource == null) { + throw new FileNotFoundException("Could not resource with name ${name}") + } file.parentFile.mkdirs() file << getClass().getResourceAsStream(name) } @@ -121,6 +129,8 @@ abstract class FunctionalSpec extends Specification { } protected GradleRunner createGradleRunner() { +// // Set up code coverage reporting based on https://github.com/koral--/jacoco-gradle-testkit-plugin +// copyResource("/testkit-gradle.properties", testProjectDir, "gradle.properties") return GradleRunner.create().withProjectDir(testProjectDir).withGradleVersion(gradleVersion.version).withPluginClasspath() } From eca77e9088c1119f00c2ccffdf71fd757934fe8f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 21 Apr 2021 22:51:01 -0400 Subject: [PATCH 409/479] version: 1.2.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 9f51dbd48b6..16bb9b40b6e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 1.2.0 * Avro 1.9.0-1.9.2 is supported again (no changed needed; just change in support policy and testing) * `generateAvroProtocol` task fails if avpr file will get overwritten (due to multiple IDL files using the same namespace and protocol) diff --git a/build.gradle b/build.gradle index c0fd0d4c593..0cd0a84de71 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.1.1-SNAPSHOT" +version = "1.2.0" def isCI = System.getenv("CI") == "true" From 326331c44948c7645ce66813f137cf32369173c5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 21 Apr 2021 23:05:26 -0400 Subject: [PATCH 410/479] version: 1.2.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0cd0a84de71..d09dfb28215 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.2.0" +version = "1.2.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" From 3a6f03406db1a2c5a7de3bb87fbf93a4d90d8469 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 27 Apr 2021 22:55:13 -0400 Subject: [PATCH 411/479] Add examples/default-custom-types --- README.md | 5 + examples/default-custom-types/README.md | 4 + examples/default-custom-types/build.gradle | 9 + .../buildSrc/build.gradle | 8 + .../java/custom/AvroConventionPlugin.java | 15 ++ .../main/java/custom/TimeZoneConversion.java | 36 ++++ .../main/java/custom/TimeZoneLogicalType.java | 20 ++ .../custom/TimeZoneLogicalTypeFactory.java | 12 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + examples/default-custom-types/gradlew | 185 ++++++++++++++++++ examples/default-custom-types/gradlew.bat | 89 +++++++++ examples/default-custom-types/settings.gradle | 1 + .../src/main/avro/customConversion.avsc | 9 + .../main/java/custom/TimeZoneConversion.java | 36 ++++ .../main/java/custom/TimeZoneLogicalType.java | 20 ++ .../custom/TimeZoneLogicalTypeFactory.java | 12 ++ 17 files changed, 466 insertions(+) create mode 100644 examples/default-custom-types/README.md create mode 100644 examples/default-custom-types/build.gradle create mode 100644 examples/default-custom-types/buildSrc/build.gradle create mode 100644 examples/default-custom-types/buildSrc/src/main/java/custom/AvroConventionPlugin.java create mode 100644 examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneConversion.java create mode 100644 examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalType.java create mode 100644 examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalTypeFactory.java create mode 100644 examples/default-custom-types/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/default-custom-types/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/default-custom-types/gradlew create mode 100644 examples/default-custom-types/gradlew.bat create mode 100644 examples/default-custom-types/settings.gradle create mode 100644 examples/default-custom-types/src/main/avro/customConversion.avsc create mode 100644 examples/default-custom-types/src/main/java/custom/TimeZoneConversion.java create mode 100644 examples/default-custom-types/src/main/java/custom/TimeZoneLogicalType.java create mode 100644 examples/default-custom-types/src/main/java/custom/TimeZoneLogicalTypeFactory.java diff --git a/README.md b/README.md index fac514c3941..d27d3912639 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,11 @@ There are a number of configuration options supported in the `avro` block. | templateDirectory | see below | `templateDir` passed to Avro compiler | | enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | +Additionally, the `avro` extension exposes the following methods: + +* `logicalTypeFactory(String typeName, Class typeFactoryClass)`: register an additional logical type factory +* `customConversion(Class conversionClass)`: register a custom conversion + ## createSetters Valid values: `true` (default), `false`; supports equivalent `String` values diff --git a/examples/default-custom-types/README.md b/examples/default-custom-types/README.md new file mode 100644 index 00000000000..cad11f77323 --- /dev/null +++ b/examples/default-custom-types/README.md @@ -0,0 +1,4 @@ +This example demonstrates a custom plugin that registers a logical type factory and custom conversion. + +To simplify the example, the custom conversion/logicalTypeFactory classes are duplicated in both buildSrc and the project. +In the real world, you would likely put them in a separate project, publish them as a JAR, and depend on them in both places. diff --git a/examples/default-custom-types/build.gradle b/examples/default-custom-types/build.gradle new file mode 100644 index 00000000000..a4a7ef4b8b6 --- /dev/null +++ b/examples/default-custom-types/build.gradle @@ -0,0 +1,9 @@ +apply plugin: custom.AvroConventionPlugin + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.apache.avro:avro:1.10.2' +} diff --git a/examples/default-custom-types/buildSrc/build.gradle b/examples/default-custom-types/buildSrc/build.gradle new file mode 100644 index 00000000000..2ec9a96d8e6 --- /dev/null +++ b/examples/default-custom-types/buildSrc/build.gradle @@ -0,0 +1,8 @@ +repositories { + mavenCentral() +} + +dependencies { + implementation 'com.github.davidmc24.gradle.plugin:gradle-avro-plugin:1.2.0' + implementation 'org.apache.avro:avro:1.10.2' +} diff --git a/examples/default-custom-types/buildSrc/src/main/java/custom/AvroConventionPlugin.java b/examples/default-custom-types/buildSrc/src/main/java/custom/AvroConventionPlugin.java new file mode 100644 index 00000000000..40734d866e7 --- /dev/null +++ b/examples/default-custom-types/buildSrc/src/main/java/custom/AvroConventionPlugin.java @@ -0,0 +1,15 @@ +package custom; + +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import com.github.davidmc24.gradle.plugin.avro.AvroPlugin; +import com.github.davidmc24.gradle.plugin.avro.AvroExtension; + +public class AvroConventionPlugin implements Plugin { + public void apply(Project project) { + project.getPluginManager().apply(AvroPlugin.class); + AvroExtension avroExtension = project.getExtensions().findByType(AvroExtension.class); + avroExtension.logicalTypeFactory("timezone", TimeZoneLogicalTypeFactory.class); + avroExtension.customConversion(TimeZoneConversion.class); + } +} diff --git a/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneConversion.java b/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneConversion.java new file mode 100644 index 00000000000..bc89a6255aa --- /dev/null +++ b/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneConversion.java @@ -0,0 +1,36 @@ +package custom; + +import java.util.TimeZone; +import org.apache.avro.Conversion; +import org.apache.avro.LogicalType; +import org.apache.avro.Schema; + +@SuppressWarnings("unused") +public class TimeZoneConversion extends Conversion { + public static final String LOGICAL_TYPE_NAME = "timezone"; + + @Override + public Class getConvertedType() { + return TimeZone.class; + } + + @Override + public String getLogicalTypeName() { + return LOGICAL_TYPE_NAME; + } + + @Override + public TimeZone fromCharSequence(CharSequence value, Schema schema, LogicalType type) { + return TimeZone.getTimeZone(value.toString()); + } + + @Override + public CharSequence toCharSequence(TimeZone value, Schema schema, LogicalType type) { + return value.getID(); + } + + @Override + public Schema getRecommendedSchema() { + return TimeZoneLogicalType.INSTANCE.addToSchema(Schema.create(Schema.Type.STRING)); + } +} diff --git a/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalType.java b/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalType.java new file mode 100644 index 00000000000..bf9361780cb --- /dev/null +++ b/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalType.java @@ -0,0 +1,20 @@ +package custom; + +import org.apache.avro.LogicalType; +import org.apache.avro.Schema; + +public class TimeZoneLogicalType extends LogicalType { + static final TimeZoneLogicalType INSTANCE = new TimeZoneLogicalType(); + + private TimeZoneLogicalType() { + super(TimeZoneConversion.LOGICAL_TYPE_NAME); + } + + @Override + public void validate(Schema schema) { + super.validate(schema); + if (schema.getType() != Schema.Type.STRING) { + throw new IllegalArgumentException("Timezone can only be used with an underlying string type"); + } + } +} diff --git a/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalTypeFactory.java b/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalTypeFactory.java new file mode 100644 index 00000000000..f5e16553be6 --- /dev/null +++ b/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalTypeFactory.java @@ -0,0 +1,12 @@ +package custom; + +import org.apache.avro.LogicalType; +import org.apache.avro.LogicalTypes; +import org.apache.avro.Schema; + +public class TimeZoneLogicalTypeFactory implements LogicalTypes.LogicalTypeFactory { + @Override + public LogicalType fromSchema(Schema schema) { + return TimeZoneLogicalType.INSTANCE; + } +} diff --git a/examples/default-custom-types/gradle/wrapper/gradle-wrapper.jar b/examples/default-custom-types/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 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

K7UpUK$>l@ zw`1S}(D?mUXu_C{wupRS-jiX~w=Uqqhf|Vb3Cm9L=T+w91Cu^ z*&Ty%sN?x*h~mJc4g~k{xD4ZmF%FXZNC;oVDwLZ_WvrnzY|{v8hc1nmx4^}Z;yriXsAf+Lp+OFLbR!&Ox?xABwl zu8w&|5pCxmu#$?Cv2_-Vghl2LZ6m7}VLEfR5o2Ou$x02uA-%QB2$c(c1rH3R9hesc zfpn#oqpbKuVsdfV#cv@5pV4^f_!WS+F>SV6N0JQ9E!T90EX((_{bSSFv9ld%I0&}9 zH&Jd4MEX1e0iqDtq~h?DBrxQX1iI0lIs<|kB$Yrh&cpeK0-^K%=FBsCBT46@h#yi!AyDq1V(#V}^;{{V*@T4WJ&U-NTq43w=|K>z8%pr_nC>%C(Wa_l78Ufib$r8Od)IIN=u>417 z`Hl{9A$mI5A(;+-Q&$F&h-@;NR>Z<2U;Y21>>Z;s@0V@SbkMQQj%_;~+qTuQ?c|AV zcWm3XZQHhP&R%QWarS%mJ!9R^&!_)*s(v+VR@I#QrAT}`17Y+l<`b-nvmDNW`De%y zrwTZ9EJrj1AFA>B`1jYDow}~*dfPs}IZMO3=a{Fy#IOILc8F0;JS4x(k-NSpbN@qM z`@aE_e}5{!$v3+qVs7u?sOV(y@1Os*Fgu`fCW9=G@F_#VQ%xf$hj0~wnnP0$hFI+@ zkQj~v#V>xn)u??YutKsX>pxKCl^p!C-o?+9;!Nug^ z{rP!|+KsP5%uF;ZCa5F;O^9TGac=M|=V z_H(PfkV1rz4jl?gJ(ArXMyWT4y(86d3`$iI4^l9`vLdZkzpznSd5Ikfrs8qcSy&>z zTIZgWZGXw0n9ibQxYWE@gI0(3#KA-dAdPcsL_|hg2@~C!VZDM}5;v_Nykfq!*@*Zf zE_wVgx82GMDryKO{U{D>vSzSc%B~|cjDQrt5BN=Ugpsf8H8f1lR4SGo#hCuXPL;QQ z#~b?C4MoepT3X`qdW2dNn& zo8)K}%Lpu>0tQei+{>*VGErz|qjbK#9 zvtd8rcHplw%YyQCKR{kyo6fgg!)6tHUYT(L>B7er5)41iG`j$qe*kSh$fY!PehLcD zWeKZHn<492B34*JUQh=CY1R~jT9Jt=k=jCU2=SL&&y5QI2uAG2?L8qd2U(^AW#{(x zThSy=C#>k+QMo^7caQcpU?Qn}j-`s?1vXuzG#j8(A+RUAY})F@=r&F(8nI&HspAy4 z4>(M>hI9c7?DCW8rw6|23?qQMSq?*Vx?v30U%luBo)B-k2mkL)Ljk5xUha3pK>EEj z@(;tH|M@xkuN?gsz;*bygizwYR!6=(Xgcg^>WlGtRYCozY<rFX2E>kaZo)O<^J7a`MX8Pf`gBd4vrtD|qKn&B)C&wp0O-x*@-|m*0egT=-t@%dD zgP2D+#WPptnc;_ugD6%zN}Z+X4=c61XNLb7L1gWd8;NHrBXwJ7s0ce#lWnnFUMTR& z1_R9Fin4!d17d4jpKcfh?MKRxxQk$@)*hradH2$3)nyXep5Z;B z?yX+-Bd=TqO2!11?MDtG0n(*T^!CIiF@ZQymqq1wPM_X$Iu9-P=^}v7npvvPBu!d$ z7K?@CsA8H38+zjA@{;{kG)#AHME>Ix<711_iQ@WWMObXyVO)a&^qE1GqpP47Q|_AG zP`(AD&r!V^MXQ^e+*n5~Lp9!B+#y3#f8J^5!iC@3Y@P`;FoUH{G*pj*q7MVV)29+j z>BC`a|1@U_v%%o9VH_HsSnM`jZ-&CDvbiqDg)tQEnV>b%Ptm)T|1?TrpIl)Y$LnG_ zzKi5j2Fx^K^PG1=*?GhK;$(UCF-tM~^=Z*+Wp{FSuy7iHt9#4n(sUuHK??@v+6*|10Csdnyg9hAsC5_OrSL;jVkLlf zHXIPukLqbhs~-*oa^gqgvtpgTk_7GypwH><53riYYL*M=Q@F-yEPLqQ&1Sc zZB%w}T~RO|#jFjMWcKMZccxm-SL)s_ig?OC?y_~gLFj{n8D$J_Kw%{r0oB8?@dWzn zB528d-wUBQzrrSSLq?fR!K%59Zv9J4yCQhhDGwhptpA5O5U?Hjqt>8nOD zi{)0CI|&Gu%zunGI*XFZh(ix)q${jT8wnnzbBMPYVJc4HX*9d^mz|21$=R$J$(y7V zo0dxdbX3N#=F$zjstTf*t8vL)2*{XH!+<2IJ1VVFa67|{?LP&P41h$2i2;?N~RA30LV`BsUcj zfO9#Pg1$t}7zpv#&)8`mis3~o+P(DxOMgz-V*(?wWaxi?R=NhtW}<#^Z?(BhSwyar zG|A#Q7wh4OfK<|DAcl9THc-W4*>J4nTevsD%dkj`U~wSUCh15?_N@uMdF^Kw+{agk zJ`im^wDqj`Ev)W3k3stasP`88-M0ZBs7;B6{-tSm3>I@_e-QfT?7|n0D~0RRqDb^G zyHb=is;IwuQ&ITzL4KsP@Z`b$d%B0Wuhioo1CWttW8yhsER1ZUZzA{F*K=wmi-sb#Ju+j z-l@In^IKnb{bQG}Ps>+Vu_W#grNKNGto+yjA)?>0?~X`4I3T@5G1)RqGUZuP^NJCq&^HykuYtMDD8qq+l8RcZNJsvN(10{ zQ1$XcGt}QH-U^WU!-wRR1d--{B$%vY{JLWIV%P4-KQuxxDeJaF#{eu&&r!3Qu{w}0f--8^H|KwE>)ORrcR+2Qf zb})DRcH>k0zWK8@{RX}NYvTF;E~phK{+F;MkIP$)T$93Ba2R2TvKc>`D??#mv9wg$ zd~|-`Qx5LwwsZ2hb*Rt4S9dsF%Cny5<1fscy~)d;0m2r$f=83<->c~!GNyb!U)PA; zq^!`@@)UaG)Ew(9V?5ZBq#c%dCWZrplmuM`o~TyHjAIMh0*#1{B>K4po-dx$Tk-Cq z=WZDkP5x2W&Os`N8KiYHRH#UY*n|nvd(U>yO=MFI-2BEp?x@=N<~CbLJBf6P)}vLS?xJXYJ2^<3KJUdrwKnJnTp{ zjIi|R=L7rn9b*D#Xxr4*R<3T5AuOS+#U8hNlfo&^9JO{VbH!v9^JbK=TCGR-5EWR@ zN8T-_I|&@A}(hKeL4_*eb!1G8p~&_Im8|wc>Cdir+gg90n1dw?QaXcx6Op_W1r=axRw>4;rM*UOpT#Eb9xU1IiWo@h?|5uP zka>-XW0Ikp@dIe;MN8B01a7+5V@h3WN{J=HJ*pe0uwQ3S&MyWFni47X32Q7SyCTNQ z+sR!_9IZa5!>f&V$`q!%H8ci!a|RMx5}5MA_kr+bhtQy{-^)(hCVa@I!^TV4RBi zAFa!Nsi3y37I5EK;0cqu|9MRj<^r&h1lF}u0KpKQD^5Y+LvFEwM zLU@@v4_Na#Axy6tn3P%sD^5P#<7F;sd$f4a7LBMk zGU^RZHBcxSA%kCx*eH&wgA?Qwazm8>9SCSz_!;MqY-QX<1@p$*T8lc?@`ikEqJ>#w zcG``^CoFMAhdEXT9qt47g0IZkaU)4R7wkGs^Ax}usqJ5HfDYAV$!=6?>J6+Ha1I<5 z|6=9soU4>E))tW$<#>F ziZ$6>KJf0bPfbx_)7-}tMINlc=}|H+$uX)mhC6-Hz+XZxsKd^b?RFB6et}O#+>Wmw9Ec9) z{q}XFWp{3@qmyK*Jvzpyqv57LIR;hPXKsrh{G?&dRjF%Zt5&m20Ll?OyfUYC3WRn{cgQ?^V~UAv+5 z&_m#&nIwffgX1*Z2#5^Kl4DbE#NrD&Hi4|7SPqZ}(>_+JMz=s|k77aEL}<=0Zfb)a z%F(*L3zCA<=xO)2U3B|pcTqDbBoFp>QyAEU(jMu8(jLA61-H!ucI804+B!$E^cQQa z)_ERrW3g!B9iLb3nn3dlkvD7KsY?sRvls3QC0qPi>o<)GHx%4Xb$5a3GBTJ(k@`e@ z$RUa^%S15^1oLEmA=sayrP5;9qtf!Z1*?e$ORVPsXpL{jL<6E)0sj&swP3}NPmR%FM?O>SQgN5XfHE< zo(4#Cv11(%Nnw_{_Ro}r6=gKd{k?NebJ~<~Kv0r(r0qe4n3LFx$5%x(BKvrz$m?LG zjLIc;hbj0FMdb9aH9Lpsof#yG$(0sG2%RL;d(n>;#jb!R_+dad+K;Ccw!|RY?uS(a zj~?=&M!4C(5LnlH6k%aYvz@7?xRa^2gml%vn&eKl$R_lJ+e|xsNfXzr#xuh(>`}9g zLHSyiFwK^-p!;p$yt7$F|3*IfO3Mlu9e>Dpx8O`37?fA`cj`C0B-m9uRhJjs^mRp# zWB;Aj6|G^1V6`jg7#7V9UFvnB4((nIwG?k%c7h`?0tS8J3Bn0t#pb#SA}N-|45$-j z$R>%7cc2ebAClXc(&0UtHX<>pd)akR3Kx_cK+n<}FhzmTx!8e9^u2e4%x{>T6pQ`6 zO182bh$-W5A3^wos0SV_TgPmF4WUP-+D25KjbC{y_6W_9I2_vNKwU(^qSdn&>^=*t z&uvp*@c8#2*paD!ZMCi3;K{Na;I4Q35zw$YrW5U@Kk~)&rw;G?d7Q&c9|x<Hg|CNMsxovmfth*|E*GHezPTWa^Hd^F4!B3sF;)? z(NaPyAhocu1jUe(!5Cy|dh|W2=!@fNmuNOzxi^tE_jAtzNJ0JR-avc_H|ve#KO}#S z#a(8secu|^Tx553d4r@3#6^MHbH)vmiBpn0X^29xEv!Vuh1n(Sr5I0V&`jA2;WS|Y zbf0e}X|)wA-Pf5gBZ>r4YX3Mav1kKY(ulAJ0Q*jB)YhviHK)w!TJsi3^dMa$L@^{` z_De`fF4;M87vM3Ph9SzCoCi$#Fsd38u!^0#*sPful^p5oI(xGU?yeYjn;Hq1!wzFk zG&2w}W3`AX4bxoVm03y>ts{KaDf!}b&7$(P4KAMP=vK5?1In^-YYNtx1f#}+2QK@h zeSeAI@E6Z8a?)>sZ`fbq9_snl6LCu6g>o)rO;ijp3|$vig+4t} zylEo7$SEW<_U+qgVcaVhk+4k+C9THI5V10qV*dOV6pPtAI$)QN{!JRBKh-D zk2^{j@bZ}yqW?<#VVuI_27*cI-V~sJiqQv&m07+10XF+#ZnIJdr8t`9s_EE;T2V;B z4UnQUH9EdX%zwh-5&wflY#ve!IWt0UE-My3?L#^Bh%kcgP1q{&26eXLn zTkjJ*w+(|_>Pq0v8{%nX$QZbf)tbJaLY$03;MO=Ic-uqYUmUCuXD>J>o6BCRF=xa% z3R4SK9#t1!K4I_d>tZgE>&+kZ?Q}1qo4&h%U$GfY058s%*=!kac{0Z+4Hwm!)pFLR zJ+5*OpgWUrm0FPI2ib4NPJ+Sk07j(`diti^i#kh&f}i>P4~|d?RFb#!JN)~D@)beox}bw?4VCf^y*`2{4`-@%SFTry2h z>9VBc9#JxEs1+0i2^LR@B1J`B9Ac=#FW=(?2;5;#U$0E0UNag_!jY$&2diQk_n)bT zl5Me_SUvqUjwCqmVcyb`igygB_4YUB*m$h5oeKv3uIF0sk}~es!{D>4r%PC*F~FN3owq5e0|YeUTSG#Vq%&Gk7uwW z0lDo#_wvflqHeRm*}l?}o;EILszBt|EW*zNPmq#?4A+&i0xx^?9obLyY4xx=Y9&^G;xYXYPxG)DOpPg!i_Ccl#3L}6xAAZzNhPK1XaC_~ z!A|mlo?Be*8Nn=a+FhgpOj@G7yYs(Qk(8&|h@_>w8Y^r&5nCqe0V60rRz?b5%J;GYeBqSAjo|K692GxD4` zRZyM2FdI+-jK2}WAZTZ()w_)V{n5tEb@>+JYluDozCb$fA4H)$bzg(Ux{*hXurjO^ zwAxc+UXu=&JV*E59}h3kzQPG4M)X8E*}#_&}w*KEgtX)cU{vm9b$atHa;s>| z+L6&cn8xUL*OSjx4YGjf6{Eq+Q3{!ZyhrL&^6Vz@jGbI%cAM9GkmFlamTbcQGvOlL zmJ?(FI)c86=JEs|*;?h~o)88>12nXlpMR4@yh%qdwFNpct;vMlc=;{FSo*apJ;p}! zAX~t;3tb~VuP|ZW;z$=IHf->F@Ml)&-&Bnb{iQyE#;GZ@C$PzEf6~q}4D>9jic@mTO5x76ulDz@+XAcm35!VSu zT*Gs>;f0b2TNpjU_BjHZ&S6Sqk6V1370+!eppV2H+FY!q*n=GHQ!9Rn6MjY!Jc77A zG7Y!lFp8?TIHN!LXO?gCnsYM-gQxsm=Ek**VmZu7vnuufD7K~GIxfxbsQ@qv2T zPa`tvHB$fFCyZl>3oYg?_wW)C>^_iDOc^B7klnTOoytQH18WkOk)L2BSD0r%xgRSW zQS9elF^?O=_@|58zKLK;(f77l-Zzu}4{fXed2saq!5k#UZAoDBqYQS{sn@j@Vtp|$ zG%gnZ$U|9@u#w1@11Sjl8ze^Co=)7yS(}=;68a3~g;NDe_X^}yJj;~s8xq9ahQ5_r zxAlTMnep*)w1e(TG%tWsjo3RR;yVGPEO4V{Zp?=a_0R#=V^ioQu4YL=BO4r0$$XTX zZfnw#_$V}sDAIDrezGQ+h?q24St0QNug_?{s-pI(^jg`#JRxM1YBV;a@@JQvH8*>> zIJvku74E0NlXkYe_624>znU0J@L<-c=G#F3k4A_)*;ky!C(^uZfj%WB3-*{*B$?9+ zDm$WFp=0(xnt6`vDQV3Jl5f&R(Mp};;q8d3I%Kn>Kx=^;uSVCw0L=gw53%Bp==8Sw zxtx=cs!^-_+i{2OK`Q;913+AXc_&Z5$@z3<)So0CU3;JAv=H?@Zpi~riQ{z-zLtVL z!oF<}@IgJp)Iyz1zVJ42!SPHSkjYNS4%ulVVIXdRuiZ@5Mx8LJS}J#qD^Zi_xQ@>DKDr-_e#>5h3dtje*NcwH_h;i{Sx7}dkdpuW z(yUCjckQsagv*QGMSi9u1`Z|V^}Wjf7B@q%j2DQXyd0nOyqg%m{CK_lAoKlJ7#8M} z%IvR?Vh$6aDWK2W!=i?*<77q&B8O&3?zP(Cs@kapc)&p7En?J;t-TX9abGT#H?TW? ztO5(lPKRuC7fs}zwcUKbRh=7E8wzTsa#Z{a`WR}?UZ%!HohN}d&xJ=JQhpO1PI#>X zHkb>pW04pU%Bj_mf~U}1F1=wxdBZu1790>3Dm44bQ#F=T4V3&HlOLsGH)+AK$cHk6 zia$=$kog?)07HCL*PI6}DRhpM^*%I*kHM<#1Se+AQ!!xyhcy6j7`iDX7Z-2i73_n# zas*?7LkxS-XSqv;YBa zW_n*32D(HTYQ0$feV_Fru1ZxW0g&iwqixPX3=9t4o)o|kOo79V$?$uh?#8Q8e>4e)V6;_(x&ViUVxma+i25qea;d-oK7ouuDsB^ab{ zu1qjQ%`n56VtxBE#0qAzb7lph`Eb-}TYpXB!H-}3Ykqyp`otprp7{VEuW*^IR2n$Fb99*nAtqT&oOFIf z@w*6>YvOGw@Ja?Pp1=whZqydzx@9X4n^2!n83C5{C?G@|E?&$?p*g68)kNvUTJ)I6 z1Q|(#UuP6pj78GUxq11m-GSszc+)X{C2eo-?8ud9sB=3(D47v?`JAa{V(IF zPZQ_0AY*9M97>Jf<o%#O_%Wq}8>YM=q0|tGY+hlXcpE=Z4Od z`NT7Hu2hnvRoqOw@g1f=bv`+nba{GwA$Ak0INlqI1k<9!x_!sL()h?hEWoWrdU3w` zZ%%)VR+Bc@_v!C#koM1p-3v_^L6)_Ktj4HE>aUh%2XZE@JFMOn)J~c`_7VWNb9c-N z2b|SZMR4Z@E7j&q&9(6H3yjEu6HV7{2!1t0lgizD;mZ9$r(r7W5G$ky@w(T_dFnOD z*p#+z$@pKE+>o@%eT(2-p_C}wbQ5s(%Sn_{$HDN@MB+Ev?t@3dPy`%TZ!z}AThZSu zN<1i$siJhXFdjV zP*y|V<`V8t=h#XTRUR~5`c`Z9^-`*BZf?WAehGdg)E2Je)hqFa!k{V(u+(hTf^Yq& zoruUh2(^3pe)2{bvt4&4Y9CY3js)PUHtd4rVG57}uFJL)D(JfSIo^{P=7liFXG zq5yqgof0V8paQcP!gy+;^pp-DA5pj=gbMN0eW=-eY+N8~y+G>t+x}oa!5r>tW$xhI zPQSv=pi;~653Gvf6~*JcQ%t1xOrH2l3Zy@8AoJ+wz@daW@m7?%LXkr!bw9GY@ns3e zSfuWF_gkWnesv?s3I`@}NgE2xwgs&rj?kH-FEy82=O8`+szN ziHch`vvS`zNfap14!&#i9H@wF7}yIPm=UB%(o(}F{wsZ(wA0nJ2aD^@B41>>o-_U6 zUqD~vdo48S8~FTb^+%#zcbQiiYoDKYcj&$#^;Smmb+Ljp(L=1Kt_J!;0s%1|JK}Wi z;={~oL!foo5n8=}rs6MmUW~R&;SIJO3TL4Ky?kh+b2rT9B1Jl4>#Uh-Bec z`Hsp<==#UEW6pGPhNk8H!!DUQR~#F9jEMI6T*OWfN^Ze&X(4nV$wa8QUJ>oTkruH# zm~O<`J7Wxseo@FqaZMl#Y(mrFW9AHM9Kb|XBMqaZ2a)DvJgYipkDD_VUF_PKd~dT7 z#02}bBfPn9a!X!O#83=lbJSK#E}K&yx-HI#T6ua)6o0{|={*HFusCkHzs|Fn&|C3H zBck1cmfcWVUN&i>X$YU^Sn6k2H;r3zuXbJFz)r5~3$d$tUj(l1?o={MM){kjgqXRO zc5R*#{;V7AQh|G|)jLM@wGAK&rm2~@{Pewv#06pHbKn#wL0P6F1!^qw9g&cW3Z=9} zj)POhOlwsh@eF=>z?#sIs*C-Nl(yU!#DaiaxhEs#iJqQ8w%(?+6lU02MYSeDkr!B- zPjMv+on6OLXgGnAtl(ao>|X2Y8*Hb}GRW5}-IzXnoo-d0!m4Vy$GS!XOLy>3_+UGs z2D|YcQx@M#M|}TDOetGi{9lGo9m-=0-^+nKE^*?$^uHkxZh}I{#UTQd;X!L+W@jm( zDg@N4+lUqI92o_rNk{3P>1gxAL=&O;x)ZT=q1mk0kLlE$WeWuY_$0`0jY-Kkt zP*|m3AF}Ubd=`<>(Xg0har*_@x2YH}bn0Wk*OZz3*e5;Zc;2uBdnl8?&XjupbkOeNZsNh6pvsq_ydmJI+*z**{I{0K)-;p1~k8cpJXL$^t!-`E}=*4G^-E8>H!LjTPxSx zcF+cS`ommfKMhNSbas^@YbTpH1*RFrBuATUR zt{oFWSk^$xU&kbFQ;MCX22RAN5F6eq9UfR$ut`Jw--p2YX)A*J69m^!oYfj2y7NYcH6&r+0~_sH^c^nzeN1AU4Ga7=FlR{S|Mm~MpzY0$Z+p2W(a={b-pR9EO1Rs zB%KY|@wLcAA@)KXi!d2_BxrkhDn`DT1=Dec}V!okd{$+wK z4E{n8R*xKyci1(CnNdhf$Dp2(Jpof0-0%-38X=Dd9PQgT+w%Lshx9+loPS~MOm%ZT zt%2B2iL_KU_ita%N>xjB!#71_3=3c}o zgeW~^U_ZTJQ2!PqXulQd=3b=XOQhwATK$y(9$#1jOQ4}4?~l#&nek)H(04f(Sr=s| zWv7Lu1=%WGk4FSw^;;!8&YPM)pQDCY9DhU`hMty1@sq1=Tj7bFsOOBZOFlpR`W>-J$-(kezWJj;`?x-v>ev{*8V z8p|KXJPV$HyQr1A(9LVrM47u-XpcrIyO`yWvx1pVYc&?154aneRpLqgx)EMvRaa#|9?Wwqs2+W8n5~79G z(}iCiLk;?enn}ew`HzhG+tu+Ru@T+K5juvZN)wY;x6HjvqD!&!)$$;1VAh~7fg0K| zEha#aN=Yv|3^~YFH}cc38ovVb%L|g@9W6fo(JtT6$fa?zf@Ct88e}m?i)b*Jgc{fl zExfdvw-BYDmH6>(4QMt#p0;FUIQqkhD}aH?a7)_%JtA~soqj{ppP_82yi9kaxuK>~ ze_)Zt>1?q=ZH*kF{1iq9sr*tVuy=u>Zev}!gEZx@O6-fjyu9X00gpIl-fS_pzjpqJ z1yqBmf9NF!jaF<+YxgH6oXBdK)sH(>VZ)1siyA$P<#KDt;8NT*l_0{xit~5j1P)FN zI8hhYKhQ)i z37^aP13B~u65?sg+_@2Kr^iWHN=U;EDSZ@2W2!5ALhGNWXnFBY%7W?1 z=HI9JzQ-pLKZDYTv<0-lt|6c-RwhxZ)mU2Os{bsX_i^@*fKUj8*aDO5pks=qn3Dv6 zwggpKLuyRCTVPwmw1r}B#AS}?X7b837UlXwp~E2|PJw2SGVueL7){Y&z!jL!XN=0i zU^Eig`S2`{+gU$68aRdWx?BZ{sU_f=8sn~>s~M?GU~`fH5kCc; z8ICp+INM3(3{#k32RZdv6b9MQYdZXNuk7ed8;G?S2nT+NZBG=Tar^KFl2SvhW$bGW#kdWL-I)s_IqVnCDDM9fm8g;P;8 z7t4yZn3^*NQfx7SwmkzP$=fwdC}bafQSEF@pd&P8@H#`swGy_rz;Z?Ty5mkS%>m#% zp_!m9e<()sfKiY(nF<1zBz&&`ZlJf6QLvLhl`_``%RW&{+O>Xhp;lwSsyRqGf=RWd zpftiR`={2(siiPAS|p}@q=NhVc0ELprt%=fMXO3B)4ryC2LT(o=sLM7hJC!}T1@)E zA3^J$3&1*M6Xq>03FX`R&w*NkrZE?FwU+Muut;>qNhj@bX17ZJxnOlPSZ=Zeiz~T_ zOu#yc3t6ONHB;?|r4w+pI)~KGN;HOGC)txxiUN8#mexj+W(cz%9a4sx|IRG=}ia zuEBuba3AHsV2feqw-3MvuL`I+2|`Ud4~7ZkN=JZ;L20|Oxna5vx1qbIh#k2O4$RQF zo`tL()zxaqibg^GbB+BS5#U{@K;WWQj~GcB1zb}zJkPwH|5hZ9iH2308!>_;%msji zJHSL~s)YHBR=Koa1mLEOHos*`gp=s8KA-C zu0aE+W!#iJ*0xqKm3A`fUGy#O+X+5W36myS>Uh2!R*s$aCU^`K&KKLCCDkejX2p=5 z%o7-fl03x`gaSNyr?3_JLv?2RLS3F*8ub>Jd@^Cc17)v8vYEK4aqo?OS@W9mt%ITJ z9=S2%R8M){CugT@k~~0x`}Vl!svYqX=E)c_oU6o}#Hb^%G1l3BudxA{F*tbjG;W_>=xV73pKY53v%>I)@D36I_@&p$h|Aw zonQS`07z_F#@T-%@-Tb|)7;;anoD_WH>9ewFy(ZcEOM$#Y)8>qi7rCnsH9GO-_7zF zu*C87{Df1P4TEOsnzZ@H%&lvV(3V@;Q!%+OYRp`g05PjY^gL$^$-t0Y>H*CDDs?FZly*oZ&dxvsxaUWF!{em4{A>n@vpXg$dwvt@_rgmHF z-MER`ABa8R-t_H*kv>}CzOpz;!>p^^9ztHMsHL|SRnS<-y5Z*r(_}c4=fXF`l^-i}>e7v!qs_jv zqvWhX^F=2sDNWA9c@P0?lUlr6ecrTKM%pNQ^?*Lq?p-0~?_j50xV%^(+H>sMul#Tw zeciF*1=?a7cI(}352%>LO96pD+?9!fNyl^9v3^v&Y4L)mNGK0FN43&Xf8jUlxW1Bw zyiu2;qW-aGNhs=zbuoxnxiwZ3{PFZM#Kw)9H@(hgX23h(`Wm~m4&TvoZoYp{plb^> z_#?vXcxd>r7K+1HKJvhed>gtK`TAbJUazUWQY6T~t2af%#<+Veyr%7-#*A#@&*;@g58{i|E%6yC_InGXCOd{L0;$)z#?n7M`re zh!kO{6=>7I?*}czyF7_frt#)s1CFJ_XE&VrDA?Dp3XbvF{qsEJgb&OLSNz_5g?HpK z9)8rsr4JN!Af3G9!#Qn(6zaUDqLN(g2g8*M)Djap?WMK9NKlkC)E2|-g|#-rp%!Gz zAHd%`iq|81efi93m3yTBw3g0j#;Yb2X{mhRAI?&KDmbGqou(2xiRNb^sV}%%Wu0?< z?($L>(#BO*)^)rSgyNRni$i`R4v;GhlCZ8$@e^ROX(p=2_v6Y!%^As zu022)fHdv_-~Yu_H6WVPLpHQx!W%^6j)cBhS`O3QBW#x(eX54d&I22op(N59b*&$v zFiSRY6rOc^(dgSV1>a7-5C;(5S5MvKcM2Jm-LD9TGqDpP097%52V+0>Xqq!! zq4e3vj53SE6i8J`XcQB|MZPP8j;PAOnpGnllH6#Ku~vS42xP*Nz@~y%db7Xi8s09P z1)e%8ys6&M8D=Dt6&t`iKG_4X=!kgRQoh%Z`dc&mlOUqXk-k`jKv9@(a^2-Upw>?< zt5*^DV~6Zedbec4NVl($2T{&b)zA@b#dUyd>`2JC0=xa_fIm8{5um zr-!ApXZhC8@=vC2WyxO|!@0Km)h8ep*`^he92$@YwP>VcdoS5OC^s38e#7RPsg4j+ zbVGG}WRSET&ZfrcR(x~k8n1rTP%CnfUNKUonD$P?FtNFF#cn!wEIab-;jU=B1dHK@ z(;(yAQJ`O$sMn>h;pf^8{JISW%d+@v6@CnXh9n5TXGC}?FI9i-D0OMaIg&mAg=0Kn zNJ7oz5*ReJukD55fUsMuaP+H4tDN&V9zfqF@ zr=#ecUk9wu{0;!+gl;3Bw=Vn^)z$ahVhhw)io!na&9}LmWurLb0zubxK=UEnU*{5P z+SP}&*(iBKSO4{alBHaY^)5Q=mZ+2OwIooJ7*Q5XJ+2|q`9#f?6myq!&oz?klihLq z4C)$XP!BNS0G_Z1&TM>?Jk{S~{F3n83ioli=IO6f%wkvCl(RFFw~j0tb{GvXTx>*sB0McY0s&SNvj4+^h`9nJ_wM>F!Uc>X}9PifQekn0sKI2SAJP!a4h z5cyGTuCj3ZBM^&{dRelIlT^9zcfaAuL5Y~bl!ppSf`wZbK$z#6U~rdclk``e+!qhe z6Qspo*%<)eu6?C;Bp<^VuW6JI|Ncvyn+LlSl;Mp22Bl7ARQ0Xc24%29(ZrdsIPw&-=yHQ7_Vle|5h>AST0 zUGX2Zk34vp?U~IHT|;$U86T+UUHl_NE4m|}>E~6q``7hccCaT^#y+?wD##Q%HwPd8 zV3x4L4|qqu`B$4(LXqDJngNy-{&@aFBvVsywt@X^}iH7P%>bR?ciC$I^U-4Foa`YKI^qDyGK7k%E%c_P=yzAi`YnxGA%DeNd++j3*h^ z=rn>oBd0|~lZ<6YvmkKY*ZJlJ;Im0tqgWu&E92eqt;+NYdxx`eS(4Hw_Jb5|yVvBg z*tbdY^!AN;luEyN4VRhS@-_DC{({ziH{&Z}iGElSV~qvT>L-8G%+yEL zX#MFOhj{InyKG=mvW-<1B@c-}x$vA(nU?>S>0*eN#!SLzQ)Ex7fvQ)S4D<8|I#N$3 zT5Ei`Z?cxBODHX8(Xp73v`IsAYC@9b;t}z0wxVuQSY1J^GRwDPN@qbM-ZF48T$GZ< z8WU+;Pqo?{ghI-KZ-i*ydXu`Ep0Xw^McH_KE9J0S7G;x8Fe`DVG?j3Pv=0YzJ}yZR z%2=oqHiUjvuk0~Ca>Kol4CFi0_xQT~;_F?=u+!kIDl-9g`#ZNZ9HCy17Ga1v^Jv9# z{T4Kb1-AzUxq*MutfOWWZgD*HnFfyYg0&e9f(5tZ>krPF6{VikNeHoc{linPPt#Si z&*g>(c54V8rT_AX!J&bNm-!umPvOR}vDai#`CX___J#=zeB*{4<&2WpaDncZsOkp* zsg<%@@rbrMkR_ux9?LsQxzoBa1s%$BBn6vk#{&&zUwcfzeCBJUwFYSF$08qDsB;gWQN*g!p8pxjofWbqNSZOEKOaTx@+* zwdt5*Q47@EOZ~EZL9s?1o?A%9TJT=Ob_13yyugvPg*e&ZU(r6^k4=2+D-@n=Hv5vu zSXG|hM(>h9^zn=eQ=$6`JO&70&2|%V5Lsx>)(%#;pcOfu>*nk_3HB_BNaH$`jM<^S zcSftDU1?nL;jy)+sfonQN}(}gUW?d_ikr*3=^{G)=tjBtEPe>TO|0ddVB zTklrSHiW+!#26frPXQQ(YN8DG$PZo?(po(QUCCf_OJC`pw*uey00%gmH!`WJkrKXj2!#6?`T25mTu9OJp2L8z3! z=arrL$ZqxuE{%yV)14Kd>k}j7pxZ6#$Dz8$@WV5p8kTqN<-7W)Q7Gt2{KoOPK_tZ| zf2WG~O5@{qPI+W<4f_;reuFVdO^5`ADC1!JQE|N`s3cq@(0WB!n0uh@*c{=LAd;~} zyGK@hbF-Oo+!nN)@i*O(`@FA#u?o=~e{`4O#5}z&=UkU*50fOrzi11D^&FOqe>wii z?*k+2|EcUs;Gx{!@KBT~>PAwLrIDT7Th=Utu?~?np@t^gFs?zgX=D${RwOY^WGh-+ z+#4$066ISh8eYW#FXWp~S`<*%O^ZuItL1Tyqt8#tZ zY120E;^VG`!lZn&3sPd$RkdHpU#|w+bYV)pJC|SH9g%|5IkxVTQcBA4CL0}$&}ef@ zW^Vtj%M;;_1xxP9x#ex17&4N*{ksO*_4O}xYu(p*JkL#yr}@7b)t5X?%CY<+s5_MJ zuiqt+N_;A(_)%lumoyRFixWa-M7qK_9s6<1X?JDa9fP!+_6u~~M$5L=ipB=7(j#f< zZ34J%=bs549%~_mA(|={uZNs_0?o7;-LBP(ZRnkd{-^|2|=4vUTmtByHL8 zEph`(LSEzQj68a+`d$V<45J7cyv^#|^|%fD#si1Nx!4NW*`l*{->HEWNh6-|g>-=r zXmQ|-i}Ku$ndUeHQ^&ieT!Lf}vf6GaqW9$DJ2NWrqwPY%%4nip$@vK$nRp*_C-v<| zuKz~ZyN&<%!NS26&x?jhy+@awJipMQ-8(X4#Ae5??U<1QMt1l9R=w9fAnEF}NYu$2 z>6}Vkc zIb*A?G*z8^IvibmBKn_u^5&T_1oey0gZS2~obf(#xk=erZGTEdQnt3DMGM+0oPwss zj5zXD;(oWhB_T@~Ig#9@v)AKtXu3>Inmgf@A|-lD-1U>cNyl3h?ADD9)GG4}zUGPk zZzaXe!~Kf?<~@$G?Uql3t8jy9{2!doq4=J}j9ktTxss{p6!9UdjyDERlA*xZ!=Q)KDs5O)phz>Vq3BNGoM(H|=1*Q4$^2fTZw z(%nq1P|5Rt81}SYJpEEzMPl5VJsV5&4e)ZWKDyoZ>1EwpkHx-AQVQc8%JMz;{H~p{=FXV>jIxvm4X*qv52e?Y-f%DJ zxEA165GikEASQ^fH6K#d!Tpu2HP{sFs%E=e$gYd$aj$+xue6N+Wc(rAz~wUsk2`(b z8Kvmyz%bKQxpP}~baG-rwYcYCvkHOi zlkR<=>ZBTU*8RF_d#Bl@zZsRIhx<%~Z@Z=ik z>adw3!DK(8R|q$vy{FTxw%#xliD~6qXmY^7_9kthVPTF~Xy1CfBqbU~?1QmxmU=+k z(ggxvEuA;0e&+ci-zQR{-f7aO{O(Pz_OsEjLh_K>MbvoZ4nxtk5u{g@nPv)cgW_R} z9}EA4K4@z0?7ue}Z(o~R(X&FjejUI2g~08PH1E4w>9o{)S(?1>Z0XMvTb|;&EuyOE zGvWNpYX)Nv<8|a^;1>bh#&znEcl-r!T#pn= z4$?Yudha6F%4b>*8@=BdtXXY4N+`U4Dmx$}>HeVJk-QdTG@t!tVT#0(LeV0gvqyyw z2sEp^9eY0N`u10Tm4n8No&A=)IeEC|gnmEXoNSzu!1<4R<%-9kY_8~5Ej?zRegMn78wuMs#;i&eUA0Zk_RXQ3b&TT} z;SCI=7-FUB@*&;8|n>(_g^HGf3@QODE3LpmX~ELnymQm{Sx9xrKS zK29p~?v@R$0=v6Dr5aW>-!{+h@?Q58|Kz8{{W`%J+lDAdb&M5VHrX_mDY;1-JLnf)ezmPau$)1;=`-FU=-r-83tX=C`S#}GZufju zQ>sXNT0Ny=k@nc%cFnvA_i4SC)?_ORXHq8B4D%el1uPX`c~uG#S1M7C+*MMqLw78E zhY2dI8@+N^qrMI1+;TUda(vGqGSRyU{Fnm`aqrr7bz42c5xsOO-~oZpkzorD1g}Y<6rk&3>PsSGy}W?MtqFky@A(X# zIuNZK0cK?^=;PUAu>j0#HtjbHCV*6?jzA&OoE$*Jlga*}LF`SF?WLhv1O|zqC<>*> zYB;#lsYKx0&kH@BFpW8n*yDcc6?;_zaJs<-jPSkCsSX-!aV=P5kUgF@Nu<{a%#K*F z134Q{9|YX7X(v$62_cY3^G%t~rD>Q0z@)1|zs)vjJ6Jq9;7#Ki`w+eS**En?7;n&7 zu==V3T&eFboN3ZiMx3D8qYc;VjFUk_H-WWCau(VFXSQf~viH0L$gwD$UfFHqNcgN`x}M+YQ6RnN<+@t>JUp#)9YOkqst-Ga?{FsDpEeX0(5v{0J~SEbWiL zXC2}M4?UH@u&|;%0y`eb33ldo4~z-x8zY!oVmV=c+f$m?RfDC35mdQ2E>Pze7KWP- z>!Bh<&57I+O_^s}9Tg^k)h7{xx@0a0IA~GAOt2yy!X%Q$1rt~LbTB6@Du!_0%HV>N zlf)QI1&gvERKwso23mJ!Ou6ZS#zCS5W`gxE5T>C#E|{i<1D35C222I33?Njaz`On7 zi<+VWFP6D{e-{yiN#M|Jgk<44u1TiMI78S5W`Sdb5f+{zu34s{CfWN7a3Cf^@L%!& zN$?|!!9j2c)j$~+R6n#891w-z8(!oBpL2K=+%a$r2|~8-(vQj5_XT`<0Ksf;oP+tz z9CObS!0m)Tgg`K#xBM8B(|Z)Wb&DYL{WTYv`;A=q6~Nnx2+!lTIXtj8J7dZE!P_{z z#f8w6F}^!?^KE#+ZDv+xd5O&3EmomZzsv?>E-~ygGum45fk!SBN&|eo1rKw^?aZJ4 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/examples/default-custom-types/gradle/wrapper/gradle-wrapper.properties b/examples/default-custom-types/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..f371643eed7 --- /dev/null +++ b/examples/default-custom-types/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/default-custom-types/gradlew b/examples/default-custom-types/gradlew new file mode 100755 index 00000000000..4f906e0c811 --- /dev/null +++ b/examples/default-custom-types/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/examples/default-custom-types/gradlew.bat b/examples/default-custom-types/gradlew.bat new file mode 100644 index 00000000000..107acd32c4e --- /dev/null +++ b/examples/default-custom-types/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/default-custom-types/settings.gradle b/examples/default-custom-types/settings.gradle new file mode 100644 index 00000000000..beb40b1cbf2 --- /dev/null +++ b/examples/default-custom-types/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'default-custom-types' diff --git a/examples/default-custom-types/src/main/avro/customConversion.avsc b/examples/default-custom-types/src/main/avro/customConversion.avsc new file mode 100644 index 00000000000..eca16922833 --- /dev/null +++ b/examples/default-custom-types/src/main/avro/customConversion.avsc @@ -0,0 +1,9 @@ +{"namespace": "example", + "type": "record", + "name": "Event", + "fields": [ + {"name": "name", "type": "string"}, + {"name": "start", "type": {"type": "long", "logicalType": "timestamp-millis"} }, + {"name": "timezone", "type": {"type": "string", "logicalType": "timezone"} } + ] +} diff --git a/examples/default-custom-types/src/main/java/custom/TimeZoneConversion.java b/examples/default-custom-types/src/main/java/custom/TimeZoneConversion.java new file mode 100644 index 00000000000..bc89a6255aa --- /dev/null +++ b/examples/default-custom-types/src/main/java/custom/TimeZoneConversion.java @@ -0,0 +1,36 @@ +package custom; + +import java.util.TimeZone; +import org.apache.avro.Conversion; +import org.apache.avro.LogicalType; +import org.apache.avro.Schema; + +@SuppressWarnings("unused") +public class TimeZoneConversion extends Conversion { + public static final String LOGICAL_TYPE_NAME = "timezone"; + + @Override + public Class getConvertedType() { + return TimeZone.class; + } + + @Override + public String getLogicalTypeName() { + return LOGICAL_TYPE_NAME; + } + + @Override + public TimeZone fromCharSequence(CharSequence value, Schema schema, LogicalType type) { + return TimeZone.getTimeZone(value.toString()); + } + + @Override + public CharSequence toCharSequence(TimeZone value, Schema schema, LogicalType type) { + return value.getID(); + } + + @Override + public Schema getRecommendedSchema() { + return TimeZoneLogicalType.INSTANCE.addToSchema(Schema.create(Schema.Type.STRING)); + } +} diff --git a/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalType.java b/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalType.java new file mode 100644 index 00000000000..bf9361780cb --- /dev/null +++ b/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalType.java @@ -0,0 +1,20 @@ +package custom; + +import org.apache.avro.LogicalType; +import org.apache.avro.Schema; + +public class TimeZoneLogicalType extends LogicalType { + static final TimeZoneLogicalType INSTANCE = new TimeZoneLogicalType(); + + private TimeZoneLogicalType() { + super(TimeZoneConversion.LOGICAL_TYPE_NAME); + } + + @Override + public void validate(Schema schema) { + super.validate(schema); + if (schema.getType() != Schema.Type.STRING) { + throw new IllegalArgumentException("Timezone can only be used with an underlying string type"); + } + } +} diff --git a/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalTypeFactory.java b/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalTypeFactory.java new file mode 100644 index 00000000000..f5e16553be6 --- /dev/null +++ b/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalTypeFactory.java @@ -0,0 +1,12 @@ +package custom; + +import org.apache.avro.LogicalType; +import org.apache.avro.LogicalTypes; +import org.apache.avro.Schema; + +public class TimeZoneLogicalTypeFactory implements LogicalTypes.LogicalTypeFactory { + @Override + public LogicalType fromSchema(Schema schema) { + return TimeZoneLogicalType.INSTANCE; + } +} From 361bc67abee8215b9be74e77bdc9a6a118b1fe31 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 30 Jun 2021 19:45:28 -0400 Subject: [PATCH 412/479] Update for Gradle 7.1 --- .github/workflows/gradle-compatibility.yml | 5 +++-- .github/workflows/java-compatibility.yml | 4 ++-- CHANGES.md | 2 ++ README.md | 4 ++-- gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- .../gradle/plugin/avro/AvroPlugin.java | 3 +-- .../gradle/plugin/avro/FunctionalSpec.groovy | 18 ++++++++++++++---- 9 files changed, 26 insertions(+), 14 deletions(-) diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index b5e1018a21b..00395d26d5c 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -11,8 +11,9 @@ jobs: "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", - "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3", - "7.0-rc-1" # See here for latest versions: https://services.gradle.org/versions/ + "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", + "7.0", "7.0.1", "7.0.2", "7.1" + # See here for latest versions: https://services.gradle.org/versions/ ] java: ["8", "11"] steps: diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 1c1a7ae7823..0255d20c376 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -79,7 +79,7 @@ jobs: strategy: matrix: avro: ["1.10.2"] - gradle: ["7.0-rc-1"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.1"] # See here for latest versions: https://services.gradle.org/versions/ java: ["16"] steps: - uses: actions/checkout@v2 @@ -97,7 +97,7 @@ jobs: strategy: matrix: avro: ["1.10.2"] - gradle: ["7.0-rc-1"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.1"] # See here for latest versions: https://services.gradle.org/versions/ java: ["17-ea"] fail-fast: false steps: diff --git a/CHANGES.md b/CHANGES.md index 16bb9b40b6e..eb02983817f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased +* Built using Gradle 7.1 +* Updated compatibility testing through Gradle 7.1 ## 1.2.0 * Avro 1.9.0-1.9.2 is supported again (no changed needed; just change in support policy and testing) diff --git a/README.md b/README.md index d27d3912639..a85f3325084 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 13 support requires Gradle 6.0 or higher * Java 8-12 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) * Though not supported yet, tests are also run against Java 16/17 to provide early notification of potential incompatibilities. It is expected that Java 16+ support will require Gradle 7.0 or higher. -* Currently built against Gradle 6.8.3 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-6.8.3 +* Currently built against Gradle 7.1 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.1 * Currently built against Avro 1.10.2 * Currently tested against Avro 1.9.0-1.10.2 * Support for Kotlin diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 18435 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 B8dv}T delta 17845 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 X49Luk)baa85H9$5YCsTPT`SVRWMtMW diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e4bf89ebb80..69a9715077f 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.0-rc-1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c811..744e882ed57 100755 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java index 313f44d45a5..ccd3e18d48d 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java @@ -23,7 +23,6 @@ import org.gradle.api.Project; import org.gradle.api.file.Directory; import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; @@ -144,7 +143,7 @@ private static Provider getGeneratedOutputDir(Project project, Source } private static SourceSetContainer getSourceSets(Project project) { - return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets(); + return project.getExtensions().getByType(SourceSetContainer.class); } private static SourceSet getMainSourceSet(Project project) { diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy index a247987ed1d..9585392c276 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy @@ -24,10 +24,20 @@ import spock.lang.TempDir @SuppressWarnings(["Println"]) abstract class FunctionalSpec extends Specification { - @SuppressWarnings(["FieldName"]) - protected static final Semver avroVersion = new Semver(System.getProperty("avroVersion", "undefined")) - @SuppressWarnings(["FieldName"]) - protected static final GradleVersion gradleVersion = GradleVersion.version(System.getProperty("gradleVersion", "undefined")) + protected Semver getAvroVersion() { + def version = System.getProperty("avroVersion") + if (!version) { + throw new IllegalArgumentException("avroVersion project property is required") + } + return new Semver(version) + } + protected GradleVersion getGradleVersion() { + def version = System.getProperty("gradleVersion") + if (!version) { + throw new IllegalArgumentException("gradleVersion project property is required") + } + return GradleVersion.version(version) + } @TempDir File testProjectDir From 877db97179ea51763cb9b5321644de1255865352 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 30 Jun 2021 22:12:12 -0400 Subject: [PATCH 413/479] CI: update to setup-java v2 --- .github/workflows/avro-compatibility.yml | 3 ++- .github/workflows/ci.yml | 3 ++- .github/workflows/gradle-compatibility.yml | 3 ++- .github/workflows/java-compatibility.yml | 23 ++++++++++++------- .../workflows/kotlin-plugin-compatibility.yml | 12 ++++++---- .github/workflows/os-compatibility.yml | 3 ++- .github/workflows/publish.yml | 3 ++- 7 files changed, 33 insertions(+), 17 deletions(-) diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index 0d015869185..e4d1c72d271 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -11,8 +11,9 @@ jobs: java: ["8"] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33b9131d5bc..b6584248c4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,8 +6,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: 8 - uses: eskatos/gradle-command-action@v1 with: diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index 00395d26d5c..68bc890bee8 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -18,8 +18,9 @@ jobs: java: ["8", "11"] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 0255d20c376..2b4d3c9d9aa 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -1,3 +1,4 @@ +# See https://docs.gradle.org/current/userguide/compatibility.html name: Java Compatibility Tests on: [push, pull_request] jobs: @@ -11,8 +12,9 @@ jobs: java: ["8", "9", "10", "11", "12"] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: @@ -29,8 +31,9 @@ jobs: java: ["13"] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: @@ -47,8 +50,9 @@ jobs: java: ["14"] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: @@ -65,8 +69,9 @@ jobs: java: ["15"] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: @@ -83,27 +88,29 @@ jobs: java: ["16"] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} dependencies-cache-enabled: true configuration-cache-enabled: true - java17: + java-ea: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: avro: ["1.10.2"] gradle: ["7.1"] # See here for latest versions: https://services.gradle.org/versions/ - java: ["17-ea"] + java: ["17-ea", "18-ea"] fail-fast: false steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 continue-on-error: true diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index b8d94ce57b6..8e3c237ccca 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -18,8 +18,9 @@ jobs: ] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: @@ -40,8 +41,9 @@ jobs: ] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: @@ -64,8 +66,9 @@ jobs: ] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: @@ -88,8 +91,9 @@ jobs: ] steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: diff --git a/.github/workflows/os-compatibility.yml b/.github/workflows/os-compatibility.yml index 6c1d646ffc5..be6460c6d9c 100644 --- a/.github/workflows/os-compatibility.yml +++ b/.github/workflows/os-compatibility.yml @@ -10,8 +10,9 @@ jobs: os: [ubuntu-latest, windows-latest, macOS-latest] # All supported OS steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: ${{ matrix.java }} - uses: eskatos/gradle-command-action@v1 with: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7d2b3b4dc89..3d6154987bd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,8 +7,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v2 with: + distribution: "zulu" java-version: 8 - uses: eskatos/gradle-command-action@v1 with: From 0c34b673cd2fc78ebe89f625d0c146b45d43dbe4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 30 Jun 2021 22:28:05 -0400 Subject: [PATCH 414/479] Update comment on code coverage support --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d09dfb28215..8a37b6d74ec 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ plugins { // Gradle TestKit (which most of this plugins tests run using) runs the builds in a separate // JVM than the tests. Thus, for Jacoco to pick up on it, you need to do some extra legwork. // https://github.com/koral--/jacoco-gradle-testkit-plugin seeks to solve that -// However, Gradle 7.0-rc-1 doesn't currently support the combination of the configuration cache +// However, Gradle 7.1 doesn't currently support the combination of the configuration cache // with a Java agent (such as Jacoco) and TestKit. // Thus, for now, no coverage reporting, as I place a higher value on testing configuration cache // support. From 055f74c7b9257135e8a74abfe375e605b52265b4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 21 Jul 2021 22:41:41 -0400 Subject: [PATCH 415/479] Update build/test to Gradle 7.1.1 --- .github/workflows/gradle-compatibility.yml | 2 +- .github/workflows/java-compatibility.yml | 4 ++-- CHANGES.md | 4 ++-- README.md | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.jar | Bin 58910 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- test-project/gradlew | 4 ++-- test-project/gradlew.bat | 21 +++--------------- 9 files changed, 14 insertions(+), 29 deletions(-) diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index 68bc890bee8..93c654b7269 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -12,7 +12,7 @@ jobs: "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", - "7.0", "7.0.1", "7.0.2", "7.1" + "7.0", "7.0.1", "7.0.2", "7.1", "7.1.1" # See here for latest versions: https://services.gradle.org/versions/ ] java: ["8", "11"] diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 2b4d3c9d9aa..76df1b9c980 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -84,7 +84,7 @@ jobs: strategy: matrix: avro: ["1.10.2"] - gradle: ["7.1"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.1.1"] # See here for latest versions: https://services.gradle.org/versions/ java: ["16"] steps: - uses: actions/checkout@v2 @@ -103,7 +103,7 @@ jobs: strategy: matrix: avro: ["1.10.2"] - gradle: ["7.1"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.1.1"] # See here for latest versions: https://services.gradle.org/versions/ java: ["17-ea", "18-ea"] fail-fast: false steps: diff --git a/CHANGES.md b/CHANGES.md index eb02983817f..cf37b6b90ee 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,8 +1,8 @@ # Change Log ## Unreleased -* Built using Gradle 7.1 -* Updated compatibility testing through Gradle 7.1 +* Built using Gradle 7.1.1 +* Updated compatibility testing through Gradle 7.1.1 ## 1.2.0 * Avro 1.9.0-1.9.2 is supported again (no changed needed; just change in support policy and testing) diff --git a/README.md b/README.md index a85f3325084..bf23a9a9dff 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 13 support requires Gradle 6.0 or higher * Java 8-12 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) * Though not supported yet, tests are also run against Java 16/17 to provide early notification of potential incompatibilities. It is expected that Java 16+ support will require Gradle 7.0 or higher. -* Currently built against Gradle 7.1 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.1 +* Currently built against Gradle 7.1.1 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.1.1 * Currently built against Avro 1.10.2 * Currently tested against Avro 1.9.0-1.10.2 * Support for Kotlin diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 69a9715077f..05679dc3c18 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.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/test-project/gradle/wrapper/gradle-wrapper.jar b/test-project/gradle/wrapper/gradle-wrapper.jar index 62d4c053550b91381bbd28b1afc82d634bf73a8a..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 18328 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 Y(TzS~Xdo8@nTUZrK}a{fL*HNQe=4o%4FCWD delta 17568 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 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +64,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From 70214ffc9444aa7ccb9cb701bcdce4ebe1871695 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 21 Jul 2021 23:12:37 -0400 Subject: [PATCH 416/479] Update test-project to reproduce #167 --- test-project/build.gradle | 8 +++++++- test-project/settings.gradle | 1 + .../src/{test => main}/java/project/SystemUtil.java | 0 3 files changed, 8 insertions(+), 1 deletion(-) rename test-project/src/{test => main}/java/project/SystemUtil.java (100%) diff --git a/test-project/build.gradle b/test-project/build.gradle index 5d3188abe34..6e0c45ba7cf 100644 --- a/test-project/build.gradle +++ b/test-project/build.gradle @@ -1,6 +1,7 @@ plugins { id "idea" - id "com.github.davidmc24.gradle.plugin.avro" version "1.0.0" + id "com.github.davidmc24.gradle.plugin.avro" version "1.2.0" +// id "com.github.davidmc24.gradle.plugin.avro" version "1.2.1-SNAPSHOT" } repositories { @@ -28,3 +29,8 @@ avro { stringType = "CharSequence" fieldVisibility = "private" } + +java { +// withJavadocJar() + withSourcesJar() +} diff --git a/test-project/settings.gradle b/test-project/settings.gradle index c9800b4942d..1b5d1a8cdea 100644 --- a/test-project/settings.gradle +++ b/test-project/settings.gradle @@ -2,6 +2,7 @@ pluginManagement { repositories { gradlePluginPortal() mavenCentral() + mavenLocal() } } diff --git a/test-project/src/test/java/project/SystemUtil.java b/test-project/src/main/java/project/SystemUtil.java similarity index 100% rename from test-project/src/test/java/project/SystemUtil.java rename to test-project/src/main/java/project/SystemUtil.java From f20f20069cc91f2d5d3ab71f4c37e4eb28b5fd6d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 22 Jul 2021 00:16:30 -0400 Subject: [PATCH 417/479] Explicitly declare dependencies between sources jar tasks and GenerateAvroJavaTasks (#167) --- CHANGES.md | 1 + .../github/davidmc24/gradle/plugin/avro/AvroPlugin.java | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index cf37b6b90ee..8c055aac0b1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ ## Unreleased * Built using Gradle 7.1.1 * Updated compatibility testing through Gradle 7.1.1 +* When `sourcesJar` is used, declares dependency on `GenerateAvroJavaTask`s to avoid disabling execution optimizations introduced in Gradle 7.1. (see #167) ## 1.2.0 * Avro 1.9.0-1.9.2 is supported again (no changed needed; just change in support policy and testing) diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java index ccd3e18d48d..a5d49081cbb 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java @@ -29,6 +29,7 @@ import org.gradle.api.tasks.SourceTask; import org.gradle.api.tasks.TaskProvider; import org.gradle.api.tasks.compile.JavaCompile; +import org.gradle.jvm.tasks.Jar; import org.gradle.plugins.ide.idea.GenerateIdeaModule; import org.gradle.plugins.ide.idea.IdeaPlugin; import org.gradle.plugins.ide.idea.model.IdeaModule; @@ -118,6 +119,12 @@ private static TaskProvider configureJavaGenerationTask(fi project.getTasks().named(sourceSet.getCompileJavaTaskName(), JavaCompile.class, compileJavaTask -> { compileJavaTask.source(javaTaskProvider); }); + // When the Gradle's JVM plugin's withSourcesJar capability is used, it automatically includes all directories listed in the SourceSet's `allSource`. + // However, in Gradle 7.1, they started including a warning that execution optimizations are disabled unless you explicitly declare what task produced the directory you're using. + // Gradle doesn't currently have a way to declare a source directory and the task that creates it, so for now we need to manually declare the task dependency. + project.getTasks().withType(Jar.class).matching(task -> sourceSet.getSourcesJarTaskName().equals(task.getName())).all(sourcesJarTask -> { + sourcesJarTask.dependsOn(javaTaskProvider); + }); return javaTaskProvider; } From 20f63378c5c8f66fc0e883bc08ba00377e5dffc5 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 22 Jul 2021 00:20:57 -0400 Subject: [PATCH 418/479] Satisfy checkstyle --- config/checkstyle/import-control.xml | 1 + .../davidmc24/gradle/plugin/avro/AvroPlugin.java | 16 ++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 920e5ea3e29..618d850821b 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -20,6 +20,7 @@ + diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java index a5d49081cbb..96dea530014 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java @@ -119,12 +119,16 @@ private static TaskProvider configureJavaGenerationTask(fi project.getTasks().named(sourceSet.getCompileJavaTaskName(), JavaCompile.class, compileJavaTask -> { compileJavaTask.source(javaTaskProvider); }); - // When the Gradle's JVM plugin's withSourcesJar capability is used, it automatically includes all directories listed in the SourceSet's `allSource`. - // However, in Gradle 7.1, they started including a warning that execution optimizations are disabled unless you explicitly declare what task produced the directory you're using. - // Gradle doesn't currently have a way to declare a source directory and the task that creates it, so for now we need to manually declare the task dependency. - project.getTasks().withType(Jar.class).matching(task -> sourceSet.getSourcesJarTaskName().equals(task.getName())).all(sourcesJarTask -> { - sourcesJarTask.dependsOn(javaTaskProvider); - }); + // When the Gradle's JVM plugin's withSourcesJar capability is used, it automatically includes all directories listed in the + // SourceSet's `allSource`. However, in Gradle 7.1, they started including a warning that execution optimizations are disabled + // unless you explicitly declare what task produced the directory you're using. Gradle doesn't currently have a way to declare a + // source directory and the task that creates it, so for now we need to manually declare the task dependency. + project.getTasks() + .withType(Jar.class) + .matching(task -> sourceSet.getSourcesJarTaskName().equals(task.getName())) + .all(sourcesJarTask -> + sourcesJarTask.dependsOn(javaTaskProvider) + ); return javaTaskProvider; } From 38240de9125bfd623e67d5a50a6b23e7d05d9a9b Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 22 Jul 2021 00:43:48 -0400 Subject: [PATCH 419/479] Simplify sources jar handling and fix configuration avoidance --- config/checkstyle/import-control.xml | 1 - .../com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 618d850821b..920e5ea3e29 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -20,7 +20,6 @@ - diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java index 96dea530014..6eb4568be9a 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java @@ -29,7 +29,6 @@ import org.gradle.api.tasks.SourceTask; import org.gradle.api.tasks.TaskProvider; import org.gradle.api.tasks.compile.JavaCompile; -import org.gradle.jvm.tasks.Jar; import org.gradle.plugins.ide.idea.GenerateIdeaModule; import org.gradle.plugins.ide.idea.IdeaPlugin; import org.gradle.plugins.ide.idea.model.IdeaModule; @@ -124,11 +123,8 @@ private static TaskProvider configureJavaGenerationTask(fi // unless you explicitly declare what task produced the directory you're using. Gradle doesn't currently have a way to declare a // source directory and the task that creates it, so for now we need to manually declare the task dependency. project.getTasks() - .withType(Jar.class) .matching(task -> sourceSet.getSourcesJarTaskName().equals(task.getName())) - .all(sourcesJarTask -> - sourcesJarTask.dependsOn(javaTaskProvider) - ); + .configureEach(sourcesJarTask -> sourcesJarTask.dependsOn(javaTaskProvider)); return javaTaskProvider; } From dd422f9a109fc4544f036507520bd6aab1375868 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 22 Jul 2021 14:46:40 -0400 Subject: [PATCH 420/479] Fix compatibility with Gradle before 6.0 --- .../github/davidmc24/gradle/plugin/avro/AvroPlugin.java | 2 +- .../gradle/plugin/avro/GradleCompatibility.java | 9 +++++++++ .../davidmc24/gradle/plugin/avro/GradleFeatures.java | 6 ++++++ .../davidmc24/gradle/plugin/avro/GradleVersions.java | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java index 6eb4568be9a..1aace73051b 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java @@ -123,7 +123,7 @@ private static TaskProvider configureJavaGenerationTask(fi // unless you explicitly declare what task produced the directory you're using. Gradle doesn't currently have a way to declare a // source directory and the task that creates it, so for now we need to manually declare the task dependency. project.getTasks() - .matching(task -> sourceSet.getSourcesJarTaskName().equals(task.getName())) + .matching(task -> GradleCompatibility.getSourcesJarTaskName(sourceSet).equals(task.getName())) .configureEach(sourcesJarTask -> sourcesJarTask.dependsOn(javaTaskProvider)); return javaTaskProvider; } diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java index 0ac2b04e175..01a46e9012e 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java @@ -20,6 +20,7 @@ import java.lang.reflect.Method; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.tasks.SourceSet; class GradleCompatibility { static T createExtensionWithObjectFactory(Project project, String extensionName, Class extensionType) { @@ -41,6 +42,14 @@ static ConfigurableFileCollection createConfigurableFileCollection(Project proje } } + static String getSourcesJarTaskName(SourceSet sourceSet) { + if (GradleFeatures.getSourcesJarTaskName.isSupported()) { + return sourceSet.getSourcesJarTaskName(); + } else { + return sourceSet.getTaskName(null, "sourcesJar"); + } + } + @SuppressWarnings("unchecked") private static T invokeMethod(Object object, String methodName, Class[] parameterTypes, Object[] args) { try { diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java index 09e851c74ab..27aba95ec0f 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java @@ -36,6 +36,12 @@ boolean isSupportedBy(GradleVersion version) { boolean isSupportedBy(GradleVersion version) { return version.compareTo(GradleVersions.v6_6) >= 0; } + }, + getSourcesJarTaskName() { + @Override + boolean isSupportedBy(GradleVersion version) { + return version.compareTo(GradleVersions.v6_0) >= 0; + } }; abstract boolean isSupportedBy(GradleVersion version); diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java index bca78419f67..1a7573555f1 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java @@ -21,5 +21,6 @@ class GradleVersions { static final GradleVersion v5_2 = GradleVersion.version("5.2"); static final GradleVersion v5_3 = GradleVersion.version("5.3"); + static final GradleVersion v6_0 = GradleVersion.version("6.0"); static final GradleVersion v6_6 = GradleVersion.version("6.6"); } From ff461cd733ae821db3838de804aba624f4d54d13 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 22 Jul 2021 21:28:01 -0400 Subject: [PATCH 421/479] version: 1.2.1 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 8c055aac0b1..f925d44092d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 1.2.1 * Built using Gradle 7.1.1 * Updated compatibility testing through Gradle 7.1.1 * When `sourcesJar` is used, declares dependency on `GenerateAvroJavaTask`s to avoid disabling execution optimizations introduced in Gradle 7.1. (see #167) diff --git a/build.gradle b/build.gradle index 8a37b6d74ec..98282b38687 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.2.1-SNAPSHOT" +version = "1.2.1" def isCI = System.getenv("CI") == "true" From 5187e40602333e67b102e498e09f311ee4b9e278 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 22 Jul 2021 21:31:54 -0400 Subject: [PATCH 422/479] version: 1.2.2-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 98282b38687..3f5ddaa9962 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.2.1" +version = "1.2.2-SNAPSHOT" def isCI = System.getenv("CI") == "true" From c0aad521f4ffda427c7174ebb62a2e53251e4678 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 20 Sep 2021 00:02:36 -0400 Subject: [PATCH 423/479] Upgrade to Gradle 7.2 --- .github/workflows/gradle-compatibility.yml | 2 +- .github/workflows/java-compatibility.yml | 4 +- CHANGES.md | 2 + README.md | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 257 ++++++++++++--------- 6 files changed, 161 insertions(+), 110 deletions(-) diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index 93c654b7269..299ceb968d7 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -12,7 +12,7 @@ jobs: "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", - "7.0", "7.0.1", "7.0.2", "7.1", "7.1.1" + "7.0", "7.0.1", "7.0.2", "7.1", "7.1.1", "7.2" # See here for latest versions: https://services.gradle.org/versions/ ] java: ["8", "11"] diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 76df1b9c980..51b1f74da11 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -84,7 +84,7 @@ jobs: strategy: matrix: avro: ["1.10.2"] - gradle: ["7.1.1"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.2"] # See here for latest versions: https://services.gradle.org/versions/ java: ["16"] steps: - uses: actions/checkout@v2 @@ -103,7 +103,7 @@ jobs: strategy: matrix: avro: ["1.10.2"] - gradle: ["7.1.1"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.2"] # See here for latest versions: https://services.gradle.org/versions/ java: ["17-ea", "18-ea"] fail-fast: false steps: diff --git a/CHANGES.md b/CHANGES.md index f925d44092d..d4afc67be9e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased +* Built using Gradle 7.2 +* Updated compatibility testing through Gradle 7.2 ## 1.2.1 * Built using Gradle 7.1.1 diff --git a/README.md b/README.md index bf23a9a9dff..4c4c3cc769d 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 13 support requires Gradle 6.0 or higher * Java 8-12 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) * Though not supported yet, tests are also run against Java 16/17 to provide early notification of potential incompatibilities. It is expected that Java 16+ support will require Gradle 7.0 or higher. -* Currently built against Gradle 7.1.1 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.1.1 +* Currently built against Gradle 7.2 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.2 * Currently built against Avro 1.10.2 * Currently tested against Avro 1.9.0-1.10.2 * Support for Kotlin diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 05679dc3c18..ffed3a254e9 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.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 744e882ed57..1b6c787337f 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 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. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" From ee31f566f69e04d82c7582719d471c82a35f7a5a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 20 Sep 2021 00:08:16 -0400 Subject: [PATCH 424/479] Update CI to indicate that Java 17 has been released, even though it's not supported yet. --- .github/workflows/java-compatibility.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 51b1f74da11..6705999d4f1 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -104,7 +104,7 @@ jobs: matrix: avro: ["1.10.2"] gradle: ["7.2"] # See here for latest versions: https://services.gradle.org/versions/ - java: ["17-ea", "18-ea"] + java: ["17", "18-ea"] fail-fast: false steps: - uses: actions/checkout@v2 From 7d46f11ad4c5200c1f83b598a0c1a3ceedc1e550 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 20 Sep 2021 00:31:28 -0400 Subject: [PATCH 425/479] Upgrade CodeNarc to build cleanly on Java 17 --- .github/workflows/java-compatibility.yml | 2 +- build.gradle | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 6705999d4f1..b460843f4d3 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -84,7 +84,7 @@ jobs: strategy: matrix: avro: ["1.10.2"] - gradle: ["7.2"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.1.1", "7.2"] # See here for latest versions: https://services.gradle.org/versions/ java: ["16"] steps: - uses: actions/checkout@v2 diff --git a/build.gradle b/build.gradle index 3f5ddaa9962..41e0ffc4286 100644 --- a/build.gradle +++ b/build.gradle @@ -57,6 +57,9 @@ dependencies { testImplementation "uk.co.datumedge:hamcrest-json:0.2" testImplementation "com.vdurmont:semver4j:3.1.0" testRuntimeOnly files(createClasspathManifest) // Add the classpath file to the test runtime classpath + // tool version specified in dependencies in order to override Groovy version for Java compatibility + codenarc "org.codenarc:CodeNarc:2.2.0" + codenarc "org.codehaus.groovy:groovy-all:3.0.9" } tasks.withType(AbstractCompile) { @@ -188,7 +191,8 @@ codenarc { maxPriority1Violations = 0 maxPriority2Violations = 0 maxPriority3Violations = 0 - toolVersion = "2.0.0" + // tool version specified in dependencies in order to override Groovy version for Java compatibility +// toolVersion = "2.2.0" } // Java 8+ is required due to requirements introduced in Avro 1.9.0 From 9519330344a5f0a7d0e3b257b3f4c0f149012c1f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 22 Sep 2021 22:56:36 -0400 Subject: [PATCH 426/479] Add some scripts to aid troubleshooting --- .gitignore | 3 +++ scripts/run-avro-cli.sh | 7 +++++++ scripts/run-compile-schema.sh | 7 +++++++ 3 files changed, 17 insertions(+) create mode 100755 scripts/run-avro-cli.sh create mode 100755 scripts/run-compile-schema.sh diff --git a/.gitignore b/.gitignore index f92a2e4f5f7..80eac73d517 100644 --- a/.gitignore +++ b/.gitignore @@ -74,3 +74,6 @@ atlassian-ide-plugin.xml # Scripts for use on the local machine /local-*.sh +/scripts/downloads/ +/scripts/input/ +/scripts/output/ diff --git a/scripts/run-avro-cli.sh b/scripts/run-avro-cli.sh new file mode 100755 index 00000000000..3267dc38117 --- /dev/null +++ b/scripts/run-avro-cli.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -ex +avroVersion=${1?"Usage: $0 AVRO_VERSION ARGUMENTS"}; +shift +mkdir -p downloads +wget --timestamping --directory-prefix=downloads/ http://archive.apache.org/dist/avro/avro-${avroVersion}/java/avro-tools-${avroVersion}.jar +java -jar downloads/avro-tools-${avroVersion}.jar $* diff --git a/scripts/run-compile-schema.sh b/scripts/run-compile-schema.sh new file mode 100755 index 00000000000..15d46cd75c8 --- /dev/null +++ b/scripts/run-compile-schema.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -ex +avroVersion=${1?"Usage: $0 AVRO_VERSION SCHEMA_FILE"}; +schemaFile=${2?"Usage: $0 AVRO_VERSION SCHEMA_FILE"}; +mkdir -p input/ +mkdir -p output/ +./run-avro-cli.sh $1 compile schema input/$2 output/ From 1c8fcf116431269fbf58449d5e7786e5e0c3c694 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 22 Sep 2021 22:57:13 -0400 Subject: [PATCH 427/479] Update readme to use implementation rather than compile configuration --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4c4c3cc769d..d42ff154686 100644 --- a/README.md +++ b/README.md @@ -50,14 +50,14 @@ plugins { } ``` -Additionally, ensure that you have a compile dependency on Avro, such as: +Additionally, ensure that you have an implementation dependency on Avro, such as: ```groovy repositories { mavenCentral() } dependencies { - compile "org.apache.avro:avro:1.10.1" + implementation "org.apache.avro:avro:1.10.1" } ``` From 346c4f63f76d7067d542361bf3ff811d66beebf1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 22 Sep 2021 23:34:18 -0400 Subject: [PATCH 428/479] Add avsc-from-external-jar and avsc-from-subproject examples --- examples/avsc-from-external-jar/README.md | 8 + examples/avsc-from-external-jar/build.gradle | 14 ++ .../external-files/Breed.avsc | 6 + .../external-files/Cat.avsc | 8 + .../external-libs/schema.jar | Bin 0 -> 289 bytes .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + examples/avsc-from-external-jar/gradlew | 234 ++++++++++++++++++ examples/avsc-from-external-jar/gradlew.bat | 89 +++++++ .../avsc-from-external-jar/settings.gradle | 9 + .../src/main/avro/Cat.avsc | 8 + examples/avsc-from-subproject/README.md | 4 + .../avsc-from-subproject/cat/build.gradle | 21 ++ .../cat/src/main/avro/Cat.avsc | 8 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + examples/avsc-from-subproject/gradlew | 234 ++++++++++++++++++ examples/avsc-from-subproject/gradlew.bat | 89 +++++++ .../avsc-from-subproject/schema/build.gradle | 3 + .../schema/src/main/resources/Breed.avsc | 6 + examples/avsc-from-subproject/settings.gradle | 12 + .../src/main/avro/Cat.avsc | 8 + 22 files changed, 771 insertions(+) create mode 100644 examples/avsc-from-external-jar/README.md create mode 100644 examples/avsc-from-external-jar/build.gradle create mode 100644 examples/avsc-from-external-jar/external-files/Breed.avsc create mode 100644 examples/avsc-from-external-jar/external-files/Cat.avsc create mode 100644 examples/avsc-from-external-jar/external-libs/schema.jar create mode 100644 examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/avsc-from-external-jar/gradlew create mode 100644 examples/avsc-from-external-jar/gradlew.bat create mode 100644 examples/avsc-from-external-jar/settings.gradle create mode 100644 examples/avsc-from-external-jar/src/main/avro/Cat.avsc create mode 100644 examples/avsc-from-subproject/README.md create mode 100644 examples/avsc-from-subproject/cat/build.gradle create mode 100644 examples/avsc-from-subproject/cat/src/main/avro/Cat.avsc create mode 100644 examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties create mode 100755 examples/avsc-from-subproject/gradlew create mode 100644 examples/avsc-from-subproject/gradlew.bat create mode 100644 examples/avsc-from-subproject/schema/build.gradle create mode 100644 examples/avsc-from-subproject/schema/src/main/resources/Breed.avsc create mode 100644 examples/avsc-from-subproject/settings.gradle create mode 100644 examples/avsc-from-subproject/src/main/avro/Cat.avsc diff --git a/examples/avsc-from-external-jar/README.md b/examples/avsc-from-external-jar/README.md new file mode 100644 index 00000000000..8f6cb2ab77b --- /dev/null +++ b/examples/avsc-from-external-jar/README.md @@ -0,0 +1,8 @@ +# Purpose + +An example project for having dependencies on .avsc schema files loaded from an external JAR file +(not produced by the current Gradle project). + +# Maintainer Notes + +* Command to create JAR: `(cd external-files && jar --create --no-manifest --file ../external-libs/schema.jar Breed.avsc)` diff --git a/examples/avsc-from-external-jar/build.gradle b/examples/avsc-from-external-jar/build.gradle new file mode 100644 index 00000000000..c7aafeeb146 --- /dev/null +++ b/examples/avsc-from-external-jar/build.gradle @@ -0,0 +1,14 @@ +plugins { + id "com.github.davidmc24.gradle.plugin.avro" version "1.2.1" +} + +repositories { + mavenCentral() +} +dependencies { + implementation "org.apache.avro:avro:1.10.1" +} + +generateAvroJava { + source zipTree("external-libs/schema.jar") +} diff --git a/examples/avsc-from-external-jar/external-files/Breed.avsc b/examples/avsc-from-external-jar/external-files/Breed.avsc new file mode 100644 index 00000000000..ce752ac4ea1 --- /dev/null +++ b/examples/avsc-from-external-jar/external-files/Breed.avsc @@ -0,0 +1,6 @@ +{ + "name": "Breed", + "namespace": "example", + "type": "enum", + "symbols" : ["ABYSSINIAN", "AMERICAN_SHORTHAIR", "BIRMAN", "MAINE_COON", "ORIENTAL", "PERSIAN", "RAGDOLL", "SIAMESE", "SPHYNX"] +} diff --git a/examples/avsc-from-external-jar/external-files/Cat.avsc b/examples/avsc-from-external-jar/external-files/Cat.avsc new file mode 100644 index 00000000000..cb5aa8be4f3 --- /dev/null +++ b/examples/avsc-from-external-jar/external-files/Cat.avsc @@ -0,0 +1,8 @@ +{ + "name": "Cat", + "namespace": "example", + "type": "record", + "fields" : [ + {"name": "breed", "type": "Breed"} + ] +} diff --git a/examples/avsc-from-external-jar/external-libs/schema.jar b/examples/avsc-from-external-jar/external-libs/schema.jar new file mode 100644 index 0000000000000000000000000000000000000000..f512f36a489e18ef42a71793fd27799a687bf154 GIT binary patch literal 289 zcmWIWW@Zs#;Nak3`0Qd9%zy;A7+4sbic(Wk^b*U8lmDG!U~oNikgLf-fbGF<|BYvE zs(&!MHHrD%x-(TCN=LHt*LjMmT-?1p`_i0$|9>amn>d62*EMSomL=uS*9rVDl)2>{ zacA{c=jYqr8uDs?_uqfh;^*hJ(vB*RIA&bCHc9P@0JnqcOrtBkXL-Xdh4g0$tu77s zh%%dLxKL7UrMAwr7_V*n)q8%=)oePqWXV*;X_agF3%cwsiU)YJb4*MAnKl{d@UuW1 i;LXS+!hrA)vK+`mr~uV_0p6@^AbCb0v;orR!HNOc3u1Zz literal 0 HcmV?d00001 diff --git a/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.jar b/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties b/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..ffed3a254e9 --- /dev/null +++ b/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/avsc-from-external-jar/gradlew b/examples/avsc-from-external-jar/gradlew new file mode 100755 index 00000000000..1b6c787337f --- /dev/null +++ b/examples/avsc-from-external-jar/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/examples/avsc-from-external-jar/gradlew.bat b/examples/avsc-from-external-jar/gradlew.bat new file mode 100644 index 00000000000..107acd32c4e --- /dev/null +++ b/examples/avsc-from-external-jar/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/avsc-from-external-jar/settings.gradle b/examples/avsc-from-external-jar/settings.gradle new file mode 100644 index 00000000000..731be1519c4 --- /dev/null +++ b/examples/avsc-from-external-jar/settings.gradle @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + mavenLocal() + } +} + +rootProject.name = "avsc-from-external-jar" diff --git a/examples/avsc-from-external-jar/src/main/avro/Cat.avsc b/examples/avsc-from-external-jar/src/main/avro/Cat.avsc new file mode 100644 index 00000000000..cb5aa8be4f3 --- /dev/null +++ b/examples/avsc-from-external-jar/src/main/avro/Cat.avsc @@ -0,0 +1,8 @@ +{ + "name": "Cat", + "namespace": "example", + "type": "record", + "fields" : [ + {"name": "breed", "type": "Breed"} + ] +} diff --git a/examples/avsc-from-subproject/README.md b/examples/avsc-from-subproject/README.md new file mode 100644 index 00000000000..9b28bf5e3d9 --- /dev/null +++ b/examples/avsc-from-subproject/README.md @@ -0,0 +1,4 @@ +# Purpose + +An example project for having dependencies on .avsc schema files loaded from an JAR file +produced by a subproject of the current multi-project Gradle build. diff --git a/examples/avsc-from-subproject/cat/build.gradle b/examples/avsc-from-subproject/cat/build.gradle new file mode 100644 index 00000000000..c50c4863965 --- /dev/null +++ b/examples/avsc-from-subproject/cat/build.gradle @@ -0,0 +1,21 @@ +plugins { + id "com.github.davidmc24.gradle.plugin.avro" version "1.2.1" +} + +repositories { + mavenCentral() +} +configurations { + additionalSchema +} +dependencies { + implementation "org.apache.avro:avro:1.10.1" + additionalSchema project(":schema") +} + +generateAvroJava { + dependsOn configurations.additionalSchema + source { + configurations.additionalSchema.collect { zipTree(it) } + } +} diff --git a/examples/avsc-from-subproject/cat/src/main/avro/Cat.avsc b/examples/avsc-from-subproject/cat/src/main/avro/Cat.avsc new file mode 100644 index 00000000000..cb5aa8be4f3 --- /dev/null +++ b/examples/avsc-from-subproject/cat/src/main/avro/Cat.avsc @@ -0,0 +1,8 @@ +{ + "name": "Cat", + "namespace": "example", + "type": "record", + "fields" : [ + {"name": "breed", "type": "Breed"} + ] +} diff --git a/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.jar b/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties b/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..ffed3a254e9 --- /dev/null +++ b/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/avsc-from-subproject/gradlew b/examples/avsc-from-subproject/gradlew new file mode 100755 index 00000000000..1b6c787337f --- /dev/null +++ b/examples/avsc-from-subproject/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 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 +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/examples/avsc-from-subproject/gradlew.bat b/examples/avsc-from-subproject/gradlew.bat new file mode 100644 index 00000000000..107acd32c4e --- /dev/null +++ b/examples/avsc-from-subproject/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/avsc-from-subproject/schema/build.gradle b/examples/avsc-from-subproject/schema/build.gradle new file mode 100644 index 00000000000..be7f6955318 --- /dev/null +++ b/examples/avsc-from-subproject/schema/build.gradle @@ -0,0 +1,3 @@ +plugins { + id "java" +} diff --git a/examples/avsc-from-subproject/schema/src/main/resources/Breed.avsc b/examples/avsc-from-subproject/schema/src/main/resources/Breed.avsc new file mode 100644 index 00000000000..ce752ac4ea1 --- /dev/null +++ b/examples/avsc-from-subproject/schema/src/main/resources/Breed.avsc @@ -0,0 +1,6 @@ +{ + "name": "Breed", + "namespace": "example", + "type": "enum", + "symbols" : ["ABYSSINIAN", "AMERICAN_SHORTHAIR", "BIRMAN", "MAINE_COON", "ORIENTAL", "PERSIAN", "RAGDOLL", "SIAMESE", "SPHYNX"] +} diff --git a/examples/avsc-from-subproject/settings.gradle b/examples/avsc-from-subproject/settings.gradle new file mode 100644 index 00000000000..2023d97da8e --- /dev/null +++ b/examples/avsc-from-subproject/settings.gradle @@ -0,0 +1,12 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + mavenLocal() + } +} + +rootProject.name = "avsc-from-subproject" + +include "schema" +include "cat" diff --git a/examples/avsc-from-subproject/src/main/avro/Cat.avsc b/examples/avsc-from-subproject/src/main/avro/Cat.avsc new file mode 100644 index 00000000000..cb5aa8be4f3 --- /dev/null +++ b/examples/avsc-from-subproject/src/main/avro/Cat.avsc @@ -0,0 +1,8 @@ +{ + "name": "Cat", + "namespace": "example", + "type": "record", + "fields" : [ + {"name": "breed", "type": "Breed"} + ] +} From 0dca7b3c8d5ff5f5f6912d9abf7e5cfde2c60815 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 23 Sep 2021 00:15:06 -0400 Subject: [PATCH 429/479] Make some minor adjustments to GradleAvroProtocolTask due to investigation of #174 --- CHANGES.md | 2 ++ .../gradle/plugin/avro/GenerateAvroProtocolTask.java | 7 ++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d4afc67be9e..c98a204f197 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,8 @@ ## Unreleased * Built using Gradle 7.2 * Updated compatibility testing through Gradle 7.2 +* `GenerateAvroProtocolTask` now has a debug log to output its classpath +* `GenerateAvroProtocolTask` will no longer include a debug log to notify that it's using the system classloader if the classpath is empty ## 1.2.1 * Built using Gradle 7.1.1 diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java index 7323f82a5f4..fdc84990e36 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -108,6 +108,7 @@ private void processIDLFile(File idlFile, ClassLoader loader) { } private ClassLoader assembleClassLoader() { + getLogger().debug("Using classpath: {}", classpath.getFiles()); List urls = new LinkedList<>(); for (File file : classpath) { try { @@ -116,10 +117,6 @@ private ClassLoader assembleClassLoader() { getLogger().debug(e.getMessage()); } } - if (urls.isEmpty()) { - getLogger().debug("No classpath configured; defaulting to system classloader"); - } - return urls.isEmpty() ? ClassLoader.getSystemClassLoader() - : new URLClassLoader(urls.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); + return new URLClassLoader(urls.toArray(new URL[0])); } } From 0ba17b6a22ac1e63b7f2e993b125aed936768f19 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 23 Sep 2021 08:01:37 -0400 Subject: [PATCH 430/479] Add design for potential "additional schema" configurations feature --- .../configurations-for-additional-schema.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 design-docs/configurations-for-additional-schema.md diff --git a/design-docs/configurations-for-additional-schema.md b/design-docs/configurations-for-additional-schema.md new file mode 100644 index 00000000000..af7723752ce --- /dev/null +++ b/design-docs/configurations-for-additional-schema.md @@ -0,0 +1,17 @@ +Periodically, we get requests for help figuring out how to +load schema files from a JAR, whether it is a JAR from a +repository or the outputs of a subproject. + +`examples/avsc-from-subproject` gives an example of how +this can be configured based on a new configuration. +We might want to consider having the Avro plugin create +and configure such configurations as part of the +conventional usage pattern. + +If we do this, a few gotchas: + +1. We need to take into account all sourceSets (main, test, etc.) +2. We need to consider the naming so it's clear what the + configurations are for and don't conflict with other plugins. + For example, `additionalSchema` is too ambiguous. + `additionalAvroSchema` might be better. From 2aac7409eee4aa9e55d24d058b872332c0785ba1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 23 Sep 2021 08:01:54 -0400 Subject: [PATCH 431/479] Add block to example to show custom resource dir usage --- examples/avsc-from-subproject/schema/build.gradle | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/avsc-from-subproject/schema/build.gradle b/examples/avsc-from-subproject/schema/build.gradle index be7f6955318..bb817d8c8e3 100644 --- a/examples/avsc-from-subproject/schema/build.gradle +++ b/examples/avsc-from-subproject/schema/build.gradle @@ -1,3 +1,13 @@ plugins { id "java" } + +// If you'd rather have the Avro schema files in `src/main/avro` (and Java classes generated), +// you can use a block like this: +//sourceSets { +// main { +// resources { +// srcDirs "src/main/avro" +// } +// } +//} From 48671b96116e8052bc70c8738a79225113e772a4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 23 Sep 2021 08:52:49 -0400 Subject: [PATCH 432/479] Update avsc-from-subproject example to compile schema for schema project, exclude generated classes from cat jar --- .../configurations-for-additional-schema.md | 1 + examples/avsc-from-subproject/README.md | 7 ++++++ .../avsc-from-subproject/cat/build.gradle | 19 ++++++++++++++ .../avsc-from-subproject/schema/build.gradle | 25 +++++++++++-------- .../src/main/{resources => avro}/Breed.avsc | 0 .../src/main/avro/Cat.avsc | 8 ------ 6 files changed, 42 insertions(+), 18 deletions(-) rename examples/avsc-from-subproject/schema/src/main/{resources => avro}/Breed.avsc (100%) delete mode 100644 examples/avsc-from-subproject/src/main/avro/Cat.avsc diff --git a/design-docs/configurations-for-additional-schema.md b/design-docs/configurations-for-additional-schema.md index af7723752ce..d87364ab7c0 100644 --- a/design-docs/configurations-for-additional-schema.md +++ b/design-docs/configurations-for-additional-schema.md @@ -15,3 +15,4 @@ If we do this, a few gotchas: configurations are for and don't conflict with other plugins. For example, `additionalSchema` is too ambiguous. `additionalAvroSchema` might be better. +3. Whether it makes sense to exclude generated classes from jars diff --git a/examples/avsc-from-subproject/README.md b/examples/avsc-from-subproject/README.md index 9b28bf5e3d9..73a4610c249 100644 --- a/examples/avsc-from-subproject/README.md +++ b/examples/avsc-from-subproject/README.md @@ -2,3 +2,10 @@ An example project for having dependencies on .avsc schema files loaded from an JAR file produced by a subproject of the current multi-project Gradle build. + +# Variants + +## schema project JAR doesn't contain classes + +If you'd rather have the `schema` project **not** generate Java classes, you can rename `src/main/avro` to `src/main/resources`. +In that case, you can also replace the Avro plugin with the `java` plugin. diff --git a/examples/avsc-from-subproject/cat/build.gradle b/examples/avsc-from-subproject/cat/build.gradle index c50c4863965..ec634fd4b0a 100644 --- a/examples/avsc-from-subproject/cat/build.gradle +++ b/examples/avsc-from-subproject/cat/build.gradle @@ -1,3 +1,5 @@ +import java.util.zip.ZipFile + plugins { id "com.github.davidmc24.gradle.plugin.avro" version "1.2.1" } @@ -16,6 +18,23 @@ dependencies { generateAvroJava { dependsOn configurations.additionalSchema source { + // As of Gradle 7.2, Using zipTree within source appears to disable build caching configurations.additionalSchema.collect { zipTree(it) } } } + +tasks.named("jar") { + it.doFirst { + // Exclude classes that are already in schema.jar from this jar + tasks.jar.exclude( + configurations.additionalSchema + .findAll { it.name.endsWith("jar") } + .collect { File file -> + new ZipFile(file).entries() + .findAll { it.name.endsWith(".class") } + .collect { it.name } + } + .flatten() + ) + } +} diff --git a/examples/avsc-from-subproject/schema/build.gradle b/examples/avsc-from-subproject/schema/build.gradle index bb817d8c8e3..de7e12dcadd 100644 --- a/examples/avsc-from-subproject/schema/build.gradle +++ b/examples/avsc-from-subproject/schema/build.gradle @@ -1,13 +1,18 @@ plugins { - id "java" + id "com.github.davidmc24.gradle.plugin.avro" version "1.2.1" } -// If you'd rather have the Avro schema files in `src/main/avro` (and Java classes generated), -// you can use a block like this: -//sourceSets { -// main { -// resources { -// srcDirs "src/main/avro" -// } -// } -//} +repositories { + mavenCentral() +} +dependencies { + compileOnly "org.apache.avro:avro:1.10.1" +} + +sourceSets { + main { + resources { + srcDirs "src/main/avro" + } + } +} diff --git a/examples/avsc-from-subproject/schema/src/main/resources/Breed.avsc b/examples/avsc-from-subproject/schema/src/main/avro/Breed.avsc similarity index 100% rename from examples/avsc-from-subproject/schema/src/main/resources/Breed.avsc rename to examples/avsc-from-subproject/schema/src/main/avro/Breed.avsc diff --git a/examples/avsc-from-subproject/src/main/avro/Cat.avsc b/examples/avsc-from-subproject/src/main/avro/Cat.avsc deleted file mode 100644 index cb5aa8be4f3..00000000000 --- a/examples/avsc-from-subproject/src/main/avro/Cat.avsc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Cat", - "namespace": "example", - "type": "record", - "fields" : [ - {"name": "breed", "type": "Breed"} - ] -} From 605004825e63998cbc9526c4837a8b157f63e60a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 23 Sep 2021 09:00:58 -0400 Subject: [PATCH 433/479] Fix cachability for cat jar in example --- examples/avsc-from-subproject/cat/build.gradle | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/avsc-from-subproject/cat/build.gradle b/examples/avsc-from-subproject/cat/build.gradle index ec634fd4b0a..8984807202b 100644 --- a/examples/avsc-from-subproject/cat/build.gradle +++ b/examples/avsc-from-subproject/cat/build.gradle @@ -23,8 +23,8 @@ generateAvroJava { } } -tasks.named("jar") { - it.doFirst { +def configureJar = tasks.register("configureJar") { + it.doLast { // Exclude classes that are already in schema.jar from this jar tasks.jar.exclude( configurations.additionalSchema @@ -37,4 +37,11 @@ tasks.named("jar") { .flatten() ) } + // otherwise the jars of dependent projects might not have been built + // TODO is there a way to copy the dependencies of the jar task? classes is not part of tasks.jar.dependsOn + it.dependsOn(tasks.classes) +} + +tasks.named("jar") { + it.dependsOn(configureJar) } From 035a0380763a542beaeb3678fef592126ed2b6e8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 23 Sep 2021 15:52:32 -0400 Subject: [PATCH 434/479] GenerateAvroProtocolTask: don't delegate to the system classloader, even implicitly --- CHANGES.md | 2 +- .../davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c98a204f197..c33fe0bbea0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,7 +4,7 @@ * Built using Gradle 7.2 * Updated compatibility testing through Gradle 7.2 * `GenerateAvroProtocolTask` now has a debug log to output its classpath -* `GenerateAvroProtocolTask` will no longer include a debug log to notify that it's using the system classloader if the classpath is empty +* `GenerateAvroProtocolTask` will no longer delegate to the system classloader ## 1.2.1 * Built using Gradle 7.1.1 diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java index fdc84990e36..725a758ebda 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java @@ -117,6 +117,7 @@ private ClassLoader assembleClassLoader() { getLogger().debug(e.getMessage()); } } - return new URLClassLoader(urls.toArray(new URL[0])); + // No parent classloader; either it's in the specified classpath or it shouldn't be resolved. + return new URLClassLoader(urls.toArray(new URL[0]), null); } } From e8412e4c2a58483b4271c5eb6a7e792600289db8 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sat, 2 Oct 2021 16:13:16 +0200 Subject: [PATCH 435/479] Add an example that generated a UUID field --- test-project/build.gradle | 1 + test-project/src/main/avro/UUIDTestRecord.avsc | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 test-project/src/main/avro/UUIDTestRecord.avsc diff --git a/test-project/build.gradle b/test-project/build.gradle index 6e0c45ba7cf..5f9e0bfc867 100644 --- a/test-project/build.gradle +++ b/test-project/build.gradle @@ -28,6 +28,7 @@ test { avro { stringType = "CharSequence" fieldVisibility = "private" + customConversion org.apache.avro.Conversions.UUIDConversion } java { diff --git a/test-project/src/main/avro/UUIDTestRecord.avsc b/test-project/src/main/avro/UUIDTestRecord.avsc new file mode 100644 index 00000000000..a835110902a --- /dev/null +++ b/test-project/src/main/avro/UUIDTestRecord.avsc @@ -0,0 +1,13 @@ +{ + "name": "UUIDTestRecord", + "type": "record", + "fields": [ + { + "name": "id", + "type": { + "type": "string", + "logicalType": "uuid" + } + } + ] +} From 25f7a0e42347d3f51141830777fd0c5eeadfb781 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Sun, 3 Oct 2021 16:53:59 +0200 Subject: [PATCH 436/479] Add test project for kotlin --- test-project-kotlin/build.gradle.kts | 29 +++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + test-project-kotlin/gradlew | 185 ++++++++++++++++++ test-project-kotlin/gradlew.bat | 89 +++++++++ test-project-kotlin/settings.gradle.kts | 9 + .../src/main/avro/BuggyRecord.avsc | 26 +++ .../src/main/avro/BuggyRecordWorkaround.avsc | 26 +++ .../src/main/avro/Messages.avsc | 26 +++ .../src/main/avro/UUIDTestRecord.avsc | 13 ++ .../src/main/java/project/SystemUtil.java | 38 ++++ .../test/java/project/CLIComparisonTest.java | 56 ++++++ .../src/test/java/project/CLIUtil.java | 19 ++ .../test/java/project/RandomRecordTest.java | 46 +++++ .../src/test/java/project/RecordTest.java | 50 +++++ 15 files changed, 617 insertions(+) create mode 100644 test-project-kotlin/build.gradle.kts create mode 100644 test-project-kotlin/gradle/wrapper/gradle-wrapper.jar create mode 100644 test-project-kotlin/gradle/wrapper/gradle-wrapper.properties create mode 100755 test-project-kotlin/gradlew create mode 100644 test-project-kotlin/gradlew.bat create mode 100644 test-project-kotlin/settings.gradle.kts create mode 100644 test-project-kotlin/src/main/avro/BuggyRecord.avsc create mode 100644 test-project-kotlin/src/main/avro/BuggyRecordWorkaround.avsc create mode 100644 test-project-kotlin/src/main/avro/Messages.avsc create mode 100644 test-project-kotlin/src/main/avro/UUIDTestRecord.avsc create mode 100644 test-project-kotlin/src/main/java/project/SystemUtil.java create mode 100644 test-project-kotlin/src/test/java/project/CLIComparisonTest.java create mode 100644 test-project-kotlin/src/test/java/project/CLIUtil.java create mode 100644 test-project-kotlin/src/test/java/project/RandomRecordTest.java create mode 100644 test-project-kotlin/src/test/java/project/RecordTest.java diff --git a/test-project-kotlin/build.gradle.kts b/test-project-kotlin/build.gradle.kts new file mode 100644 index 00000000000..95a3aff0197 --- /dev/null +++ b/test-project-kotlin/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + id("idea") + id("com.github.davidmc24.gradle.plugin.avro") version ("1.2.0") +// id "com.github.davidmc24.gradle.plugin.avro" version "1.2.1-SNAPSHOT" +} + +repositories { + mavenCentral() +} + +project.ext.set("avroVersion", "1.10.1") +dependencies { + implementation("org.apache.avro:avro:${project.ext.get("avroVersion")}") + implementation("org.apache.avro:avro-tools:${project.ext.get("avroVersion")}") + testImplementation("org.junit.jupiter:junit-jupiter:5.6.2") +} + +tasks.test { + useJUnitPlatform() + testLogging { + events("passed", "skipped", "failed") + } +} + +avro { + stringType.set("CharSequence") + fieldVisibility.set("private") + customConversion(org.apache.avro.Conversions.UUIDConversion::class.java) +} diff --git a/test-project-kotlin/gradle/wrapper/gradle-wrapper.jar b/test-project-kotlin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/test-project-kotlin/gradle/wrapper/gradle-wrapper.properties b/test-project-kotlin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..05679dc3c18 --- /dev/null +++ b/test-project-kotlin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/test-project-kotlin/gradlew b/test-project-kotlin/gradlew new file mode 100755 index 00000000000..744e882ed57 --- /dev/null +++ b/test-project-kotlin/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/test-project-kotlin/gradlew.bat b/test-project-kotlin/gradlew.bat new file mode 100644 index 00000000000..107acd32c4e --- /dev/null +++ b/test-project-kotlin/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/test-project-kotlin/settings.gradle.kts b/test-project-kotlin/settings.gradle.kts new file mode 100644 index 00000000000..1b5d1a8cdea --- /dev/null +++ b/test-project-kotlin/settings.gradle.kts @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + mavenLocal() + } +} + +rootProject.name = "test-project" diff --git a/test-project-kotlin/src/main/avro/BuggyRecord.avsc b/test-project-kotlin/src/main/avro/BuggyRecord.avsc new file mode 100644 index 00000000000..57f422504aa --- /dev/null +++ b/test-project-kotlin/src/main/avro/BuggyRecord.avsc @@ -0,0 +1,26 @@ +{ + "namespace":"com.example", + "type":"record", + "name":"BuggyRecord", + "fields":[ + { + "name":"my_mandatory_date", + "type":{ + "type":"long", + "logicalType":"timestamp-millis" + }, + "default":1502250227187 + }, + { + "name":"my_optional_date", + "type":[ + { + "type":"long", + "logicalType":"timestamp-millis" + }, + "null" + ], + "default":1502250227187 + } + ] +} diff --git a/test-project-kotlin/src/main/avro/BuggyRecordWorkaround.avsc b/test-project-kotlin/src/main/avro/BuggyRecordWorkaround.avsc new file mode 100644 index 00000000000..e397d55a025 --- /dev/null +++ b/test-project-kotlin/src/main/avro/BuggyRecordWorkaround.avsc @@ -0,0 +1,26 @@ +{ + "namespace":"com.example", + "type":"record", + "name":"BuggyRecordWorkaround", + "fields":[ + { + "name":"my_mandatory_date", + "type":{ + "type":"long", + "logicalType":"timestamp-millis" + }, + "default":1502250227187 + }, + { + "name":"my_optional_date", + "type":[ + "null", + { + "type":"long", + "logicalType":"timestamp-millis" + } + ], + "default":null + } + ] +} diff --git a/test-project-kotlin/src/main/avro/Messages.avsc b/test-project-kotlin/src/main/avro/Messages.avsc new file mode 100644 index 00000000000..1dc457940ff --- /dev/null +++ b/test-project-kotlin/src/main/avro/Messages.avsc @@ -0,0 +1,26 @@ +{ + "type": "record", + "name": "Messages", + "namespace": "com.somedomain", + "fields": [ + { + "name": "start", + "type": { + "type": "long", + "logicalType": "timestamp-millis" + } + }, + { + "name": "end", + "type": [ + "null", + { + "type": "long", + "logicalType": "timestamp-millis" + } + ], + "default": null + } + ] + } +} diff --git a/test-project-kotlin/src/main/avro/UUIDTestRecord.avsc b/test-project-kotlin/src/main/avro/UUIDTestRecord.avsc new file mode 100644 index 00000000000..a835110902a --- /dev/null +++ b/test-project-kotlin/src/main/avro/UUIDTestRecord.avsc @@ -0,0 +1,13 @@ +{ + "name": "UUIDTestRecord", + "type": "record", + "fields": [ + { + "name": "id", + "type": { + "type": "string", + "logicalType": "uuid" + } + } + ] +} diff --git a/test-project-kotlin/src/main/java/project/SystemUtil.java b/test-project-kotlin/src/main/java/project/SystemUtil.java new file mode 100644 index 00000000000..5a04d2b5c66 --- /dev/null +++ b/test-project-kotlin/src/main/java/project/SystemUtil.java @@ -0,0 +1,38 @@ +package project; + +import java.security.Permission; + +class SystemUtil { + private static final String PERMISSION_PREFIX = "exitVM."; + + static class ExitTrappedException extends SecurityException { + private final int status; + + ExitTrappedException(int status) { + super("Trapped System.exit(" + status + ")"); + this.status = status; + } + + int getStatus() { + return status; + } + } + + static void forbidSystemExitCall() { + final SecurityManager securityManager = new SecurityManager() { + public void checkPermission(Permission permission) { + String permissionName = permission.getName(); + if (permissionName.startsWith(PERMISSION_PREFIX)) { + String suffix = permissionName.substring(PERMISSION_PREFIX.length()); + int status = Integer.parseInt(suffix); + throw new ExitTrappedException(status); + } + } + }; + System.setSecurityManager(securityManager); + } + + static void allowSystemExitCall() { + System.setSecurityManager(null); + } +} diff --git a/test-project-kotlin/src/test/java/project/CLIComparisonTest.java b/test-project-kotlin/src/test/java/project/CLIComparisonTest.java new file mode 100644 index 00000000000..9990da98e10 --- /dev/null +++ b/test-project-kotlin/src/test/java/project/CLIComparisonTest.java @@ -0,0 +1,56 @@ +package project; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import static project.CLIUtil.runCLITool; + +public class CLIComparisonTest { + @TempDir + Path cliGeneratedDir; + Path schemaDir = Paths.get("src/main/avro"); + Path pluginGeneratedDir = Paths.get("build/generated-main-avro-java"); + + @SuppressWarnings("unused") + private static Stream compareSpecificCompilerOutput() { + return Stream.of( + // From https://stackoverflow.com/questions/45581437/how-to-specify-converter-for-default-value-in-avro-union-logical-type-fields + Arguments.of("BuggyRecord.avsc", "com/example/BuggyRecord.java", "compile schema".split(" ")), + // From https://github.com/davidmc24/gradle-avro-plugin/issues/120 + Arguments.of("Messages.avsc", "com/somedomain/Messages.java", "compile schema".split(" ")) + ); + } + + @ParameterizedTest + @MethodSource + void compareSpecificCompilerOutput(String schemaPath, String generatedPath, String... toolArgs) throws Exception { + Path schemaFile = schemaDir.resolve(schemaPath); + Path pluginGeneratedFile = pluginGeneratedDir.resolve(generatedPath); + Path cliGeneratedFile = cliGeneratedDir.resolve(generatedPath); + + List args = new ArrayList<>(Arrays.asList(toolArgs)); + args.add(schemaFile.toString()); + args.add(cliGeneratedDir.toString()); + runCLITool(args.toArray(new String[0])); + + String pluginGeneratedContent = readFile(pluginGeneratedFile); + String cliGeneratedContent = readFile(cliGeneratedFile); + Assertions.assertEquals(cliGeneratedContent, pluginGeneratedContent); + } + + private static String readFile(Path file) throws Exception { + return new String(Files.readAllBytes(file), StandardCharsets.UTF_8); + } +} diff --git a/test-project-kotlin/src/test/java/project/CLIUtil.java b/test-project-kotlin/src/test/java/project/CLIUtil.java new file mode 100644 index 00000000000..326e33d2586 --- /dev/null +++ b/test-project-kotlin/src/test/java/project/CLIUtil.java @@ -0,0 +1,19 @@ +package project; + +import org.apache.avro.tool.Main; +import org.junit.jupiter.api.Assertions; + +class CLIUtil { + private static final int STATUS_SUCCESS = 0; + + static void runCLITool(String... args) throws Exception { + SystemUtil.forbidSystemExitCall(); + try { + Main.main(args); + } catch (SystemUtil.ExitTrappedException ex) { + Assertions.assertEquals(STATUS_SUCCESS, ex.getStatus(), "CLI tool failed"); + } finally { + SystemUtil.allowSystemExitCall(); + } + } +} diff --git a/test-project-kotlin/src/test/java/project/RandomRecordTest.java b/test-project-kotlin/src/test/java/project/RandomRecordTest.java new file mode 100644 index 00000000000..47b4d306393 --- /dev/null +++ b/test-project-kotlin/src/test/java/project/RandomRecordTest.java @@ -0,0 +1,46 @@ +package project; + +import org.apache.avro.specific.SpecificRecord; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import static project.CLIUtil.runCLITool; + +public class RandomRecordTest { + @TempDir + Path cliGeneratedDir; + Path schemaDir = Paths.get("src/main/avro"); + + @SuppressWarnings("unused") + private static Stream generateRandomRecords() { + return Stream.of( + // From https://stackoverflow.com/questions/45581437/how-to-specify-converter-for-default-value-in-avro-union-logical-type-fields + Arguments.of("BuggyRecord.avsc"), + // From https://github.com/davidmc24/gradle-avro-plugin/issues/120 + Arguments.of("Messages.avsc") + ); + } + + @ParameterizedTest + @MethodSource + void generateRandomRecords(String schemaPath) throws Exception { + Path schemaFile = schemaDir.resolve(schemaPath); + Path outputFile = cliGeneratedDir.resolve("random.avro"); + List args = new ArrayList<>(); + args.add("random"); + args.add("--count"); + args.add("1"); + args.add("--schema-file"); + args.add(schemaFile.toString()); + args.add(outputFile.toString()); + runCLITool(args.toArray(new String[0])); + } +} diff --git a/test-project-kotlin/src/test/java/project/RecordTest.java b/test-project-kotlin/src/test/java/project/RecordTest.java new file mode 100644 index 00000000000..8f979a6a7a5 --- /dev/null +++ b/test-project-kotlin/src/test/java/project/RecordTest.java @@ -0,0 +1,50 @@ +package project; + +import com.example.BuggyRecord; +import com.example.BuggyRecordWorkaround; +import com.somedomain.Messages; +import org.apache.avro.Schema; +import org.apache.avro.io.Encoder; +import org.apache.avro.io.EncoderFactory; +import org.apache.avro.specific.SpecificDatumWriter; +import org.apache.avro.specific.SpecificRecord; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.time.Instant; +import java.util.stream.Stream; + +public class RecordTest { + private static final EncoderFactory encoderFactory = EncoderFactory.get(); + + @SuppressWarnings("unused") + private static Stream buildAndWriteRecord() { + return Stream.of( + // From https://stackoverflow.com/questions/45581437/how-to-specify-converter-for-default-value-in-avro-union-logical-type-fields + // Broken due to an Avro bug + Arguments.of(BuggyRecord.newBuilder().setMyMandatoryDate(Instant.now()).build()), + // Broken due to an Avro bug + Arguments.of(BuggyRecordWorkaround.newBuilder().setMyMandatoryDate(Instant.now()).build()), + // From https://github.com/davidmc24/gradle-avro-plugin/issues/120 + // Broken due to an Avro bug + Arguments.of(Messages.newBuilder().setStart(Instant.now()).build()) + ); + } + + // Broken due to an Avro bug + @Disabled + @ParameterizedTest + @MethodSource + void buildAndWriteRecord(T record) throws Exception { + Schema schema = record.getSchema(); + SpecificDatumWriter writer = new SpecificDatumWriter<>(); + OutputStream outputStream = new ByteArrayOutputStream(); + Encoder jsonEncoder = encoderFactory.jsonEncoder(schema, outputStream, true); + Encoder validatingEncoder = encoderFactory.validatingEncoder(schema, jsonEncoder); + writer.write(record, validatingEncoder); + } +} From 023d4f92a7027162573780f10be1d9cfc7d3b1d4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 8 Nov 2021 22:20:11 -0500 Subject: [PATCH 437/479] Update for avro 1.11.0 --- .github/workflows/avro-compatibility.yml | 2 +- .github/workflows/gradle-compatibility.yml | 4 +- .github/workflows/java-compatibility.yml | 12 +-- .../workflows/kotlin-plugin-compatibility.yml | 4 +- CHANGES.md | 2 + README.md | 18 ++-- build.gradle | 2 +- examples/default-custom-types/build.gradle | 2 +- .../buildSrc/build.gradle | 2 +- .../gradle/plugin/avro/Constants.java | 2 +- ...otlinDSLCompatibilityFunctionalSpec.groovy | 2 +- .../plugin/avro/OptionsFunctionalSpec.groovy | 7 +- .../davidmc24/gradle/plugin/avro/record.vm | 96 ++++++++++++------- test-project-kotlin/build.gradle.kts | 2 +- test-project/build.gradle | 2 +- 15 files changed, 93 insertions(+), 66 deletions(-) diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index e4d1c72d271..ff61b8e4666 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -6,7 +6,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.9.0", "1.9.1", "1.9.2", "1.10.0", "1.10.1", "1.10.2"] + avro: ["1.9.0", "1.9.1", "1.9.2", "1.10.0", "1.10.1", "1.10.2", "1.11.0"] gradle: ["5.1", "6.8.3"] java: ["8"] steps: diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index 299ceb968d7..67033dbdcb0 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -6,12 +6,12 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] + avro: ["1.11.0"] gradle: [ "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", - "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", + "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", "6.9.1", "7.0", "7.0.1", "7.0.2", "7.1", "7.1.1", "7.2" # See here for latest versions: https://services.gradle.org/versions/ ] diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index b460843f4d3..c5abd66863c 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -7,7 +7,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] + avro: ["1.11.0"] gradle: ["5.1", "6.8.3"] java: ["8", "9", "10", "11", "12"] steps: @@ -26,7 +26,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] + avro: ["1.11.0"] gradle: ["6.0", "6.8.3"] java: ["13"] steps: @@ -45,7 +45,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] + avro: ["1.11.0"] gradle: ["6.3", "6.8.3"] java: ["14"] steps: @@ -64,7 +64,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] + avro: ["1.11.0"] gradle: ["6.7", "6.8.3"] java: ["15"] steps: @@ -83,7 +83,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] + avro: ["1.11.0"] gradle: ["7.1.1", "7.2"] # See here for latest versions: https://services.gradle.org/versions/ java: ["16"] steps: @@ -102,7 +102,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] + avro: ["1.11.0"] gradle: ["7.2"] # See here for latest versions: https://services.gradle.org/versions/ java: ["17", "18-ea"] fail-fast: false diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index 8e3c237ccca..a8cec259a37 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -55,7 +55,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] # Latest version that this plugin supports + avro: ["1.11.0"] # Latest version that this plugin supports gradle: ["5.6.4"] java: ["11"] # Latest LTS version that this plugin supports kotlin: [ @@ -81,7 +81,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.10.2"] # Latest version that this plugin supports + avro: ["1.11.0"] # Latest version that this plugin supports gradle: ["6.8.3"] # Latest version that this plugin supports java: ["11"] # Latest LTS version that this plugin supports kotlin: [ diff --git a/CHANGES.md b/CHANGES.md index c33fe0bbea0..59314619ff0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased +* Built using Avro 1.11.0 +* Default field visibility is now "PRIVATE" to match Avro's new default, as "PUBLIC_DEPRECATED" is no longer supported in Avro 1.11.0 * Built using Gradle 7.2 * Updated compatibility testing through Gradle 7.2 * `GenerateAvroProtocolTask` now has a debug log to output its classpath diff --git a/README.md b/README.md index d42ff154686..7772342af36 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Though not supported yet, tests are also run against Java 16/17 to provide early notification of potential incompatibilities. It is expected that Java 16+ support will require Gradle 7.0 or higher. * Currently built against Gradle 7.2 * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.2 -* Currently built against Avro 1.10.2 - * Currently tested against Avro 1.9.0-1.10.2 +* Currently built against Avro 1.11.0 + * Currently tested against Avro 1.9.0-1.11.0 * Support for Kotlin * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 @@ -57,7 +57,7 @@ repositories { mavenCentral() } dependencies { - implementation "org.apache.avro:avro:1.10.1" + implementation "org.apache.avro:avro:1.11.0" } ``` @@ -74,7 +74,7 @@ There are a number of configuration options supported in the `avro` block. | createOptionalGetters | `false` | `createOptionalGetters` passed to Avro compiler | | gettersReturnOptional | `false` | `gettersReturnOptional` passed to Avro compiler | | optionalGettersForNullableFieldsOnly | `false` | `optionalGettersForNullableFieldsOnly` passed to Avro compiler | -| fieldVisibility | `"PUBLIC_DEPRECATED"` | `fieldVisibility` passed to Avro compiler | +| fieldVisibility | `"PRIVATE"` | `fieldVisibility` passed to Avro compiler | | outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | | stringType | `"String"` | `stringType` passed to Avro compiler | | templateDirectory | see below | `templateDir` passed to Avro compiler | @@ -153,16 +153,16 @@ avro { ## fieldVisibility -Valid values: any [FieldVisibility](http://avro.apache.org/docs/1.8.1/api/java/org/apache/avro/compiler/specific/SpecificCompiler.FieldVisibility.html) or equivalent `String` name (matched case-insensitively); default `"PUBLIC_DEPRECATED"` (default) +Valid values: any [FieldVisibility](https://avro.apache.org/docs/1.11.0/api/java/org/apache/avro/compiler/specific/SpecificCompiler.FieldVisibility.html) or equivalent `String` name (matched case-insensitively); default `"PRIVATE"` (default) -By default, the fields in generated Java files will have public visibility and be annotated with `@Deprecated`. -Set to `"PRIVATE"` to restrict visibility of the fields, or `"PUBLIC"` to remove the `@Deprecated` annotations. +By default, the fields in generated Java files will have private visibility. +Set to `"PRIVATE"` to explicitly specify private visibility of the fields, or `"PUBLIC"` to specify public visibility of the fields. Example: ```groovy avro { - fieldVisibility = "PRIVATE" + fieldVisibility = "PUBLIC" } ``` @@ -247,7 +247,7 @@ apply plugin: "java" apply plugin: "com.github.davidmc24.gradle.plugin.avro-base" dependencies { - implementation "org.apache.avro:avro:1.10.1" + implementation "org.apache.avro:avro:1.11.0" } def generateAvro = tasks.register("generateAvro", GenerateAvroJavaTask) { diff --git a/build.gradle b/build.gradle index 41e0ffc4286..4316a413c35 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ repositories { } } -def compileAvroVersion = "1.10.2" +def compileAvroVersion = "1.11.0" // Write the plugin's classpath to a file to share with the tests task createClasspathManifest { diff --git a/examples/default-custom-types/build.gradle b/examples/default-custom-types/build.gradle index a4a7ef4b8b6..8643d410fef 100644 --- a/examples/default-custom-types/build.gradle +++ b/examples/default-custom-types/build.gradle @@ -5,5 +5,5 @@ repositories { } dependencies { - implementation 'org.apache.avro:avro:1.10.2' + implementation 'org.apache.avro:avro:1.11.0' } diff --git a/examples/default-custom-types/buildSrc/build.gradle b/examples/default-custom-types/buildSrc/build.gradle index 2ec9a96d8e6..b55abe34eb0 100644 --- a/examples/default-custom-types/buildSrc/build.gradle +++ b/examples/default-custom-types/buildSrc/build.gradle @@ -4,5 +4,5 @@ repositories { dependencies { implementation 'com.github.davidmc24.gradle.plugin:gradle-avro-plugin:1.2.0' - implementation 'org.apache.avro:avro:1.10.2' + implementation 'org.apache.avro:avro:1.11.0' } diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java index 3ac50152c6e..117b4a51161 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java @@ -34,7 +34,7 @@ class Constants { static final String UTF8_ENCODING = "UTF-8"; static final String DEFAULT_STRING_TYPE = StringType.String.name(); - static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PUBLIC_DEPRECATED.name(); + static final String DEFAULT_FIELD_VISIBILITY = FieldVisibility.PRIVATE.name(); static final boolean DEFAULT_CREATE_SETTERS = true; static final boolean DEFAULT_CREATE_OPTIONAL_GETTERS = false; static final boolean DEFAULT_GETTERS_RETURN_OPTIONAL = false; diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy index dee1f2f1c34..b0b612685d3 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy @@ -44,7 +44,7 @@ class KotlinDSLCompatibilityFunctionalSpec extends FunctionalSpec { | isCreateOptionalGetters.set(false) | isGettersReturnOptional.set(false) | isOptionalGettersForNullableFieldsOnly.set(false) - | fieldVisibility.set("PUBLIC_DEPRECATED") + | fieldVisibility.set("PUBLIC") | outputCharacterEncoding.set("UTF-8") | stringType.set("String") | templateDirectory.set(null as String?) diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 22e185fcd3e..10eb98c5636 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -44,8 +44,8 @@ class OptionsFunctionalSpec extends FunctionalSpec { and: "the stringType is string" content.contains("public java.lang.String getName()") - and: "the fieldVisibility is PUBLIC_DEPRECATED" - content.contains("@Deprecated public java.lang.String name;") + and: "the fieldVisibility is PRIVATE" + content.contains("private java.lang.String name;") and: "the default template is used" !content.contains("Custom template") @@ -122,7 +122,6 @@ class OptionsFunctionalSpec extends FunctionalSpec { FieldVisibility.PRIVATE.name().toLowerCase() | "private java.lang.String name;" FieldVisibility.PRIVATE.name() | "private java.lang.String name;" FieldVisibility.PUBLIC.name() | "public java.lang.String name;" - FieldVisibility.PUBLIC_DEPRECATED.name() | "@Deprecated public java.lang.String name;" } @Unroll @@ -300,7 +299,7 @@ class OptionsFunctionalSpec extends FunctionalSpec { then: result.task(":generateAvroJava").outcome == FAILED - result.output.contains("Invalid fieldVisibility 'badValue'. Value values are: [PUBLIC, PUBLIC_DEPRECATED, PRIVATE]") + result.output.contains("Invalid fieldVisibility 'badValue'. Value values are: [PUBLIC, PRIVATE]") } @Unroll diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm index 286aa9dbab4..ae8f0f08d5f 100644 --- a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm +++ b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm @@ -16,7 +16,7 @@ ## limitations under the License. ## #if ($schema.getNamespace()) -package $schema.getNamespace(); +package $this.mangle($schema.getNamespace()); #end import org.apache.avro.generic.GenericArray; @@ -39,13 +39,24 @@ import org.apache.avro.message.SchemaStore; public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends org.apache.avro.specific.SpecificExceptionBase#else extends org.apache.avro.specific.SpecificRecordBase#end implements org.apache.avro.specific.SpecificRecord { // Custom template private static final long serialVersionUID = ${this.fingerprint64($schema)}L; - public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse(${this.javaSplit($schema.toString())}); + +#set ($schemaString = $this.javaSplit($schema.toString())) +#set ($customLogicalTypeFactories = $this.getUsedCustomLogicalTypeFactories($schema).entrySet()) +#if (!$customLogicalTypeFactories.isEmpty()) + static { +#foreach ($customLogicalTypeFactory in $customLogicalTypeFactories) + org.apache.avro.LogicalTypes.register("${customLogicalTypeFactory.getKey()}", new ${customLogicalTypeFactory.getValue()}()); +#end + } +#end + + public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse($schemaString); public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; } - private static SpecificData MODEL$ = new SpecificData(); + private static final SpecificData MODEL$ = new SpecificData(); #set ($usedConversions = $this.getUsedConversionClasses($schema)) #if (!$usedConversions.isEmpty()) -static { + static { #foreach ($conversion in $usedConversions) MODEL$.addLogicalTypeConversion(new ${conversion}()); #end @@ -112,7 +123,7 @@ static { #foreach ($annotation in $this.javaAnnotations($field)) @$annotation #end - #if (${this.deprecatedFields()})@Deprecated#end #if (${this.publicFields()})public#elseif (${this.privateFields()})private#end ${this.javaUnbox($field.schema())} ${this.mangle($field.name(), $schema.isError())}; + #if (${this.publicFields()})public#elseif (${this.privateFields()})private#end ${this.javaUnbox($field.schema(), false)} ${this.mangle($field.name(), $schema.isError())}; #end #if ($schema.isError()) @@ -177,7 +188,7 @@ static { case $i: return ${this.mangle($field.name(), $schema.isError())}; #set ($i = $i + 1) #end - default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + default: throw new IndexOutOfBoundsException("Invalid index: " + field$); } } @@ -205,14 +216,14 @@ static { case $i: ${this.mangle($field.name(), $schema.isError())} = #if(${this.javaType($field.schema())} != "java.lang.Object" && ${this.javaType($field.schema())} != "java.lang.String")(${this.javaType($field.schema())})#{end}value$#if(${this.javaType($field.schema())} == "java.lang.String") != null ? value$.toString() : null#{end}; break; #set ($i = $i + 1) #end - default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + default: throw new IndexOutOfBoundsException("Invalid index: " + field$); } } #foreach ($field in $schema.getFields()) #if (${this.gettersReturnOptional} && (!${this.optionalGettersForNullableFieldsOnly} || ${field.schema().isNullable()})) /** - * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. #if ($field.doc()) * $field.doc() #end * @return The value wrapped in an Optional<${this.javaType($field.schema())}>. @@ -227,14 +238,14 @@ static { #else * @return The value of the '${this.mangle($field.name(), $schema.isError())}' field. #end */ - public ${this.javaUnbox($field.schema())} ${this.generateGetMethod($schema, $field)}() { + public ${this.javaUnbox($field.schema(), false)} ${this.generateGetMethod($schema, $field)}() { return ${this.mangle($field.name(), $schema.isError())}; } #end #if (${this.createOptionalGetters}) /** - * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. #if ($field.doc()) * $field.doc() #end * @return The value wrapped in an Optional<${this.javaType($field.schema())}>. @@ -251,7 +262,7 @@ static { #end * @param value the value to set. */ - public void ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema())} value) { + public void ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema(), false)} value) { ${this.generateSetterCode($field.schema(), ${this.mangle($field.name(), $schema.isError())}, "value")} } #end @@ -261,8 +272,8 @@ static { * Creates a new ${this.mangle($schema.getName())} RecordBuilder. * @return A new ${this.mangle($schema.getName())} RecordBuilder */ - public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder() { - return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(); + public static #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder newBuilder() { + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(); } /** @@ -270,11 +281,11 @@ static { * @param other The existing builder to copy. * @return A new ${this.mangle($schema.getName())} RecordBuilder */ - public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder other) { + public static #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder other) { if (other == null) { - return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(); + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(); } else { - return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other); + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(other); } } @@ -283,11 +294,11 @@ static { * @param other The existing instance to copy. * @return A new ${this.mangle($schema.getName())} RecordBuilder */ - public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())} other) { + public static #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())} other) { if (other == null) { - return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(); + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(); } else { - return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other); + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(other); } } @@ -303,22 +314,22 @@ static { #if ($field.doc()) /** $field.doc() */ #end - private ${this.javaUnbox($field.schema())} ${this.mangle($field.name(), $schema.isError())}; + private ${this.javaUnbox($field.schema(), false)} ${this.mangle($field.name(), $schema.isError())}; #if (${this.hasBuilder($field.schema())}) - private ${this.javaUnbox($field.schema())}.Builder ${this.mangle($field.name(), $schema.isError())}Builder; + private ${this.javaUnbox($field.schema(), false)}.Builder ${this.mangle($field.name(), $schema.isError())}Builder; #end #end /** Creates a new Builder */ private Builder() { - super(SCHEMA$); + super(SCHEMA$, MODEL$); } /** * Creates a Builder by copying an existing Builder. * @param other The existing Builder to copy. */ - private Builder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder other) { + private Builder(#if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder other) { super(other); #foreach ($field in $schema.getFields()) if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) { @@ -337,9 +348,9 @@ static { * Creates a Builder by copying an existing $this.mangle($schema.getName()) instance * @param other The existing instance to copy. */ - private Builder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())} other) { + private Builder(#if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())} other) { #if ($schema.isError()) super(other)#else - super(SCHEMA$)#end; + super(SCHEMA$, MODEL$)#end; #foreach ($field in $schema.getFields()) if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) { this.${this.mangle($field.name(), $schema.isError())} = data().deepCopy(fields()[$field.pos()].schema(), other.${this.mangle($field.name(), $schema.isError())}); @@ -353,25 +364,25 @@ static { #if ($schema.isError()) @Override - public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder setValue(Object value) { + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder setValue(Object value) { super.setValue(value); return this; } @Override - public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder clearValue() { + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder clearValue() { super.clearValue(); return this; } @Override - public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder setCause(Throwable cause) { + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder setCause(Throwable cause) { super.setCause(cause); return this; } @Override - public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder clearCause() { + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder clearCause() { super.clearCause(); return this; } @@ -384,16 +395,16 @@ static { #end * @return The value. */ - public ${this.javaUnbox($field.schema())} ${this.generateGetMethod($schema, $field)}() { + public ${this.javaUnbox($field.schema(), false)} ${this.generateGetMethod($schema, $field)}() { return ${this.mangle($field.name(), $schema.isError())}; } #if (${this.createOptionalGetters}) /** - * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. #if ($field.doc()) * $field.doc() #end - * @return The Optional<value>. + * @return The value wrapped in an Optional<${this.javaType($field.schema())}>. */ public Optional<${this.javaType($field.schema())}> ${this.generateGetOptionalMethod($schema, $field)}() { return Optional.<${this.javaType($field.schema())}>ofNullable(${this.mangle($field.name(), $schema.isError())}); @@ -407,7 +418,7 @@ static { * @param value The value of '${this.mangle($field.name(), $schema.isError())}'. * @return This builder. */ - public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema())} value) { + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema(), false)} value) { validate(fields()[$field.pos()], value); #if (${this.hasBuilder($field.schema())}) this.${this.mangle($field.name(), $schema.isError())}Builder = null; @@ -452,7 +463,8 @@ static { * @param value The builder instance that must be set. * @return This builder. */ - public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateSetBuilderMethod($schema, $field)}(${this.javaUnbox($field.schema())}.Builder value) { + + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder ${this.generateSetBuilderMethod($schema, $field)}(${this.javaUnbox($field.schema(), false)}.Builder value) { ${this.generateClearMethod($schema, $field)}(); ${this.mangle($field.name(), $schema.isError())}Builder = value; return this; @@ -475,7 +487,7 @@ static { #end * @return This builder. */ - public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateClearMethod($schema, $field)}() { + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder ${this.generateClearMethod($schema, $field)}() { #if (${this.isUnboxedJavaTypeNullable($field.schema())}) ${this.mangle($field.name(), $schema.isError())} = null; #end @@ -759,7 +771,21 @@ $I $var = ${this.javaType($s)}.values()[in.readEnum()]; #macro( decodeString $II $var $s ) #set ($st = ${this.getStringType($s)}) #if ($this.isStringable($s)) +#if ($st.equals("java.net.URI")) +$II try { +$II ${var} = new ${st}(in.readString()); +$II } catch (java.net.URISyntaxException e) { +$II throw new java.io.IOException(e.getMessage()); +$II } +#elseif ($st.equals("java.net.URL")) +$II try { +$II ${var} = new ${st}(in.readString()); +$II } catch (java.net.MalformedURLException e) { +$II throw new java.io.IOException(e.getMessage()); +$II } +#else $II ${var} = new ${st}(in.readString()); +#end #elseif ($st.equals("java.lang.String")) $II $var = in.readString(); #elseif ($st.equals("org.apache.avro.util.Utf8")) diff --git a/test-project-kotlin/build.gradle.kts b/test-project-kotlin/build.gradle.kts index 95a3aff0197..8ef313a8127 100644 --- a/test-project-kotlin/build.gradle.kts +++ b/test-project-kotlin/build.gradle.kts @@ -8,7 +8,7 @@ repositories { mavenCentral() } -project.ext.set("avroVersion", "1.10.1") +project.ext.set("avroVersion", "1.11.0") dependencies { implementation("org.apache.avro:avro:${project.ext.get("avroVersion")}") implementation("org.apache.avro:avro-tools:${project.ext.get("avroVersion")}") diff --git a/test-project/build.gradle b/test-project/build.gradle index 5f9e0bfc867..e93d555e84f 100644 --- a/test-project/build.gradle +++ b/test-project/build.gradle @@ -9,7 +9,7 @@ repositories { } ext { - avroVersion = "1.10.1" + avroVersion = "1.11.0" } dependencies { From 7a91926a6eefc091ece2414f8f7ef6189ee8b504 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 8 Nov 2021 22:57:58 -0500 Subject: [PATCH 438/479] Drop support for Avro 1.9.0-1.10.2 Due to an incompatibility introduced in Avro 1.11.0 error: no suitable constructor found for SpecificRecordBuilderBase(Schema,SpecificData) --- .github/workflows/avro-compatibility.yml | 2 +- .github/workflows/kotlin-plugin-compatibility.yml | 4 ++-- CHANGES.md | 1 + README.md | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index ff61b8e4666..f22d4f2a2df 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -6,7 +6,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.9.0", "1.9.1", "1.9.2", "1.10.0", "1.10.1", "1.10.2", "1.11.0"] + avro: ["1.11.0"] gradle: ["5.1", "6.8.3"] java: ["8"] steps: diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index a8cec259a37..ff531d1c359 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -6,7 +6,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.9.0"] # Minimum version that this plugin supports + avro: ["1.11.0"] # Minimum version that this plugin supports gradle: ["5.1"] # Minimum version that this plugin supports java: ["8"] # Minimum version that this plugin supports kotlin: [ @@ -32,7 +32,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.9.0"] # Minimum version that this plugin supports + avro: ["1.11.0"] # Minimum version that this plugin supports gradle: ["5.3"] # Minimum version supported by these versions of the Kotlin plugin java: ["8"] # Minimum version that this plugin supports kotlin: [ diff --git a/CHANGES.md b/CHANGES.md index 59314619ff0..a31457a8c10 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## Unreleased * Built using Avro 1.11.0 +* Dropped support for Avro 1.9.0-1.10.2 due to use of new SpecificRecordBuilderBase constructor in Avro 1.11.0 * Default field visibility is now "PRIVATE" to match Avro's new default, as "PUBLIC_DEPRECATED" is no longer supported in Avro 1.11.0 * Built using Gradle 7.2 * Updated compatibility testing through Gradle 7.2 diff --git a/README.md b/README.md index 7772342af36..3eca048214f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently built against Gradle 7.2 * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.2 * Currently built against Avro 1.11.0 - * Currently tested against Avro 1.9.0-1.11.0 + * Currently tested against Avro 1.11.0 + * Avro 1.9.0-1.10.2 were last supported in version 1.2.1 * Support for Kotlin * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 From 7b8d3ee0654be548984012849c545bb47d17578c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 8 Nov 2021 23:09:01 -0500 Subject: [PATCH 439/479] Update kotlin compatibility testing --- .github/workflows/kotlin-plugin-compatibility.yml | 5 +++-- CHANGES.md | 1 + README.md | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index ff531d1c359..f2e83a0f7cf 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -82,12 +82,13 @@ jobs: strategy: matrix: avro: ["1.11.0"] # Latest version that this plugin supports - gradle: ["6.8.3"] # Latest version that this plugin supports + gradle: ["7.2"] # Latest version that this plugin supports java: ["11"] # Latest LTS version that this plugin supports kotlin: [ # Earlier versions lack support for either Java 10+ or Gradle 6+ "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", - "1.4.0", "1.4.10", "1.4.20", "1.4.21", "1.4.30", "1.4.31", "1.4.32" + "1.4.0", "1.4.10", "1.4.20", "1.4.21", "1.4.30", "1.4.31", "1.4.32", + "1.5.0", "1.5.10", "1.5.20", "1.5.21", "1.5.30", "1.5.31" ] steps: - uses: actions/checkout@v2 diff --git a/CHANGES.md b/CHANGES.md index a31457a8c10..387e9e811f6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ * Default field visibility is now "PRIVATE" to match Avro's new default, as "PUBLIC_DEPRECATED" is no longer supported in Avro 1.11.0 * Built using Gradle 7.2 * Updated compatibility testing through Gradle 7.2 +* Updated compatibility testing through Kotlin 1.5.31 * `GenerateAvroProtocolTask` now has a debug log to output its classpath * `GenerateAvroProtocolTask` will no longer delegate to the system classloader diff --git a/README.md b/README.md index 3eca048214f..33dcf22a660 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Avro 1.11.0 * Avro 1.9.0-1.10.2 were last supported in version 1.2.1 * Support for Kotlin - * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 using the latest compatible version of Gradle + * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 and 1.5.0-1.5.31 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 * Kotlin plugin versions starting with 1.4.0 require Gradle 5.3+ * Kotlin plugin versions prior to 1.3.20 do not support Gradle 6.0+ From 2aef20aae835fbe2719ad5341945c9da4f0d3800 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 8 Nov 2021 23:33:36 -0500 Subject: [PATCH 440/479] Update Java compatibility testing --- .github/workflows/java-compatibility.yml | 12 ++++++------ README.md | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index c5abd66863c..d87af011b74 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["5.1", "6.8.3"] + gradle: ["5.1", "7.2"] java: ["8", "9", "10", "11", "12"] steps: - uses: actions/checkout@v2 @@ -27,7 +27,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["6.0", "6.8.3"] + gradle: ["6.0", "7.2"] java: ["13"] steps: - uses: actions/checkout@v2 @@ -46,7 +46,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["6.3", "6.8.3"] + gradle: ["6.3", "7.2"] java: ["14"] steps: - uses: actions/checkout@v2 @@ -65,7 +65,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["6.7", "6.8.3"] + gradle: ["6.7", "7.2"] java: ["15"] steps: - uses: actions/checkout@v2 @@ -84,7 +84,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["7.1.1", "7.2"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.0", "7.2"] # See here for latest versions: https://services.gradle.org/versions/ java: ["16"] steps: - uses: actions/checkout@v2 @@ -103,7 +103,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["7.2"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.3-rc-5"] # See here for latest versions: https://services.gradle.org/versions/ java: ["17", "18-ea"] fail-fast: false steps: diff --git a/README.md b/README.md index 33dcf22a660..87aced91317 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,14 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav **NOTE**: Pre-1.0 versions used a different publishing process/namespace. It is strongly recommended to upgrade to a newer version. Further details can be found in the [change log](CHANGES.md). -* Currently tested against Java 8-15 - * Java 17 is not yet supported - * Java 16 appears to work in Gradle 7.0-rc-1; use at your own risk +* Currently tested against Java 8-16 + * Though not supported yet, tests are also run against Java 17/18 to provide early notification of potential incompatibilities. + * Java 17 is not yet supported (expected to require Gradle 7.3 or higher) + * Java 16 support requires Gradle 7.0 or higher (as per Gradle's release notes) * Java 15 support requires Gradle 6.7 or higher (as per Gradle's release notes) * Java 14 support requires Gradle 6.3 or higher (as per Gradle's release notes) * Java 13 support requires Gradle 6.0 or higher * Java 8-12 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) - * Though not supported yet, tests are also run against Java 16/17 to provide early notification of potential incompatibilities. It is expected that Java 16+ support will require Gradle 7.0 or higher. * Currently built against Gradle 7.2 * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.2 * Currently built against Avro 1.11.0 From 6024396d416b1d7d675ff52c1943324621713166 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 10 Nov 2021 22:38:09 -0500 Subject: [PATCH 441/479] Update to build with Gradle 7.3; add Java 17 compatibility --- .github/workflows/avro-compatibility.yml | 2 +- .github/workflows/gradle-compatibility.yml | 2 +- .github/workflows/java-compatibility.yml | 33 +++++++++++++++---- .../workflows/kotlin-plugin-compatibility.yml | 2 +- CHANGES.md | 5 +-- README.md | 8 ++--- build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 10 files changed, 40 insertions(+), 20 deletions(-) diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index f22d4f2a2df..8202078915a 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["5.1", "6.8.3"] + gradle: ["5.1", "7.3"] java: ["8"] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index 67033dbdcb0..7c1369650b9 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -12,7 +12,7 @@ jobs: "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", "6.9.1", - "7.0", "7.0.1", "7.0.2", "7.1", "7.1.1", "7.2" + "7.0", "7.0.1", "7.0.2", "7.1", "7.1.1", "7.2", "7.3" # See here for latest versions: https://services.gradle.org/versions/ ] java: ["8", "11"] diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index d87af011b74..b1a517e2125 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["5.1", "7.2"] + gradle: ["5.1", "7.3"] java: ["8", "9", "10", "11", "12"] steps: - uses: actions/checkout@v2 @@ -27,7 +27,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["6.0", "7.2"] + gradle: ["6.0", "7.3"] java: ["13"] steps: - uses: actions/checkout@v2 @@ -46,7 +46,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["6.3", "7.2"] + gradle: ["6.3", "7.3"] java: ["14"] steps: - uses: actions/checkout@v2 @@ -65,7 +65,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["6.7", "7.2"] + gradle: ["6.7", "7.3"] java: ["15"] steps: - uses: actions/checkout@v2 @@ -84,7 +84,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["7.0", "7.2"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.0", "7.3"] # See here for latest versions: https://services.gradle.org/versions/ java: ["16"] steps: - uses: actions/checkout@v2 @@ -97,14 +97,33 @@ jobs: arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} dependencies-cache-enabled: true configuration-cache-enabled: true + java17: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.11.0"] + gradle: ["7.3"] # See here for latest versions: https://services.gradle.org/versions/ + java: ["17"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + dependencies-cache-enabled: true + configuration-cache-enabled: true java-ea: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: avro: ["1.11.0"] - gradle: ["7.3-rc-5"] # See here for latest versions: https://services.gradle.org/versions/ - java: ["17", "18-ea"] + gradle: ["7.3"] # See here for latest versions: https://services.gradle.org/versions/ + java: ["18-ea"] fail-fast: false steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index f2e83a0f7cf..fe5e7807e26 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -82,7 +82,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] # Latest version that this plugin supports - gradle: ["7.2"] # Latest version that this plugin supports + gradle: ["7.3"] # Latest version that this plugin supports java: ["11"] # Latest LTS version that this plugin supports kotlin: [ # Earlier versions lack support for either Java 10+ or Gradle 6+ diff --git a/CHANGES.md b/CHANGES.md index 387e9e811f6..d7f93861118 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,9 +4,10 @@ * Built using Avro 1.11.0 * Dropped support for Avro 1.9.0-1.10.2 due to use of new SpecificRecordBuilderBase constructor in Avro 1.11.0 * Default field visibility is now "PRIVATE" to match Avro's new default, as "PUBLIC_DEPRECATED" is no longer supported in Avro 1.11.0 -* Built using Gradle 7.2 -* Updated compatibility testing through Gradle 7.2 +* Built using Gradle 7.3 +* Updated compatibility testing through Gradle 7.3 * Updated compatibility testing through Kotlin 1.5.31 +* Added compatibility with Java 17 * `GenerateAvroProtocolTask` now has a debug log to output its classpath * `GenerateAvroProtocolTask` will no longer delegate to the system classloader diff --git a/README.md b/README.md index 87aced91317..cf975588dab 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,15 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav **NOTE**: Pre-1.0 versions used a different publishing process/namespace. It is strongly recommended to upgrade to a newer version. Further details can be found in the [change log](CHANGES.md). * Currently tested against Java 8-16 - * Though not supported yet, tests are also run against Java 17/18 to provide early notification of potential incompatibilities. - * Java 17 is not yet supported (expected to require Gradle 7.3 or higher) + * Though not supported yet, tests are also run against Java 18 to provide early notification of potential incompatibilities. + * Java 17 support requires Gradle 7.3 or higher (as per Gradle's release notes) * Java 16 support requires Gradle 7.0 or higher (as per Gradle's release notes) * Java 15 support requires Gradle 6.7 or higher (as per Gradle's release notes) * Java 14 support requires Gradle 6.3 or higher (as per Gradle's release notes) * Java 13 support requires Gradle 6.0 or higher * Java 8-12 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) -* Currently built against Gradle 7.2 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.2 +* Currently built against Gradle 7.3 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.3 * Currently built against Avro 1.11.0 * Currently tested against Avro 1.11.0 * Avro 1.9.0-1.10.2 were last supported in version 1.2.1 diff --git a/build.gradle b/build.gradle index 4316a413c35..bc30e9e0687 100644 --- a/build.gradle +++ b/build.gradle @@ -205,7 +205,7 @@ if (JavaVersion.current().java10Compatible) { sourceCompatibility = 8 } -def latestKotlinVersion = "1.4.21" +def latestKotlinVersion = "1.5.31" test { useJUnitPlatform() diff --git a/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties b/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties index ffed3a254e9..e750102e092 100644 --- a/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties +++ b/examples/avsc-from-external-jar/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-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties b/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties index ffed3a254e9..e750102e092 100644 --- a/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties +++ b/examples/avsc-from-subproject/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-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ffed3a254e9..e750102e092 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-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 4f3e11c6fc4f34d61dbecc7131169163e0cc4fc1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 10 Nov 2021 23:18:36 -0500 Subject: [PATCH 442/479] CI: Attempt to fix kotlin compatibility testing --- .../workflows/kotlin-plugin-compatibility.yml | 26 ++++++++++++++++--- README.md | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index fe5e7807e26..cfff38c0602 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -75,6 +75,26 @@ jobs: arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} dependencies-cache-enabled: true configuration-cache-enabled: true + v1_3_30: # This version breaks on Gradle 7.0 or later + name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.11.0"] # Latest version that this plugin supports + gradle: ["6.9.1"] # Latest version that this version of kotlin plugin supports + java: ["11"] # Latest LTS version that this version of kotlin plugin supports + kotlin: ["1.3.30"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + dependencies-cache-enabled: true + configuration-cache-enabled: true modern: name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" @@ -83,10 +103,10 @@ jobs: matrix: avro: ["1.11.0"] # Latest version that this plugin supports gradle: ["7.3"] # Latest version that this plugin supports - java: ["11"] # Latest LTS version that this plugin supports + java: ["17"] # Latest LTS version that this plugin supports kotlin: [ - # Earlier versions lack support for either Java 10+ or Gradle 6+ - "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", + # Earlier versions lack support for either Java 17+ or Gradle 7+ + "1.3.20", "1.3.21", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", "1.4.0", "1.4.10", "1.4.20", "1.4.21", "1.4.30", "1.4.31", "1.4.32", "1.5.0", "1.5.10", "1.5.20", "1.5.21", "1.5.30", "1.5.31" ] diff --git a/README.md b/README.md index cf975588dab..c4bb8471c8f 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Support for Kotlin * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 and 1.5.0-1.5.31 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 + * Kotlin plugin version 1.3.30 is not compatible with Gradle 7.0+ * Kotlin plugin versions starting with 1.4.0 require Gradle 5.3+ * Kotlin plugin versions prior to 1.3.20 do not support Gradle 6.0+ * Kotlin plugin versions prior to 1.2.30 do not support Java 10+ From bf833937db0093ee35789c4c1147a31f33eed134 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 11 Nov 2021 07:34:08 -0500 Subject: [PATCH 443/479] More kotlin compatibility testing fixes --- .../workflows/kotlin-plugin-compatibility.yml | 29 ++++++++++++++++--- README.md | 1 + 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index cfff38c0602..21005a21c90 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -75,7 +75,7 @@ jobs: arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} dependencies-cache-enabled: true configuration-cache-enabled: true - v1_3_30: # This version breaks on Gradle 7.0 or later + java11_gradle_6_9_1: # This version breaks on Gradle 7.0 or later name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" strategy: @@ -95,7 +95,28 @@ jobs: arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} dependencies-cache-enabled: true configuration-cache-enabled: true - + java11-gradle_latest: # These versions breaks on Java 17 or later; see https://youtrack.jetbrains.com/issue/KT-43704 + name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.11.0"] # Latest version that this plugin supports + gradle: ["7.3"] # Latest version that this plugin supports + java: ["11"] # Latest LTS version that this version of kotlin plugin supports + kotlin: [ + "1.4.20", "1.4.21", "1.4.30","1.4.31", "1.4.32" + ] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java }} + - uses: eskatos/gradle-command-action@v1 + with: + arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} + dependencies-cache-enabled: true + configuration-cache-enabled: true modern: name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" @@ -105,9 +126,9 @@ jobs: gradle: ["7.3"] # Latest version that this plugin supports java: ["17"] # Latest LTS version that this plugin supports kotlin: [ - # Earlier versions lack support for either Java 17+ or Gradle 7+ + # Other versions lack support for either Java 17+ or Gradle 7+ "1.3.20", "1.3.21", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", - "1.4.0", "1.4.10", "1.4.20", "1.4.21", "1.4.30", "1.4.31", "1.4.32", + "1.4.0", "1.4.10", "1.5.0", "1.5.10", "1.5.20", "1.5.21", "1.5.30", "1.5.31" ] steps: diff --git a/README.md b/README.md index c4bb8471c8f..dbc3b8377d5 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Support for Kotlin * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 and 1.5.0-1.5.31 using the latest compatible version of Gradle * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 + * Kotlin plugin versions 1.4.20-1.4.32 require special settings to work with Java 17+; see [KT-43704](https://youtrack.jetbrains.com/issue/KT-43704#focus=Comments-27-4639603.0-0) * Kotlin plugin version 1.3.30 is not compatible with Gradle 7.0+ * Kotlin plugin versions starting with 1.4.0 require Gradle 5.3+ * Kotlin plugin versions prior to 1.3.20 do not support Gradle 6.0+ From 0969beafa9695453d34a11f65e072c78a8f804f7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 11 Nov 2021 07:50:39 -0500 Subject: [PATCH 444/479] CI: update to gradle-build-action v2 --- .github/workflows/avro-compatibility.yml | 6 +-- .github/workflows/ci.yml | 6 +-- .github/workflows/gradle-compatibility.yml | 6 +-- .github/workflows/java-compatibility.yml | 42 +++++++------------ .../workflows/kotlin-plugin-compatibility.yml | 36 ++++++---------- .github/workflows/os-compatibility.yml | 6 +-- .github/workflows/publish.yml | 6 +-- 7 files changed, 36 insertions(+), 72 deletions(-) diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index 8202078915a..0dd38dee374 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -15,8 +15,6 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6584248c4e..580eeb6e60a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,11 +10,9 @@ jobs: with: distribution: "zulu" java-version: 8 - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace build - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: build # - uses: codecov/codecov-action@v1 # with: # file: ./build/reports/jacoco/test/jacocoTestReport.xml diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index 7c1369650b9..a00a1c179ca 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -22,8 +22,6 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index b1a517e2125..6b14431e8d7 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -16,11 +16,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} java13: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" @@ -35,11 +33,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} java14: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" @@ -54,11 +50,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} java15: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" @@ -73,11 +67,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} java16: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" @@ -92,11 +84,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} java17: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" @@ -111,11 +101,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} java-ea: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" @@ -131,9 +119,7 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 continue-on-error: true with: - arguments: --no-daemon --info --stacktrace testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml index 21005a21c90..19f1735dc57 100644 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ b/.github/workflows/kotlin-plugin-compatibility.yml @@ -22,11 +22,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} java8-gradle5_3: name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" @@ -45,11 +43,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} java11-gradle5_6_4: name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" @@ -70,11 +66,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} java11_gradle_6_9_1: # This version breaks on Gradle 7.0 or later name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" @@ -90,11 +84,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} java11-gradle_latest: # These versions breaks on Java 17 or later; see https://youtrack.jetbrains.com/issue/KT-43704 name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" @@ -112,11 +104,9 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} modern: name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" runs-on: "ubuntu-latest" @@ -137,8 +127,6 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} diff --git a/.github/workflows/os-compatibility.yml b/.github/workflows/os-compatibility.yml index be6460c6d9c..79e8257b266 100644 --- a/.github/workflows/os-compatibility.yml +++ b/.github/workflows/os-compatibility.yml @@ -14,8 +14,6 @@ jobs: with: distribution: "zulu" java-version: ${{ matrix.java }} - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: - arguments: --no-daemon --info --stacktrace test - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3d6154987bd..e71aec3ec43 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,12 +11,10 @@ jobs: with: distribution: "zulu" java-version: 8 - - uses: eskatos/gradle-command-action@v1 + - uses: gradle/gradle-build-action@v2 with: # For now, release manually; closeAndReleaseSonatypeStagingRepository when I have confidence - arguments: --no-daemon --info --stacktrace publishToSonatype closeSonatypeStagingRepository -PsonatypeUsername=${{ secrets.SONATYPE_USERNAME }} -PsonatypePassword=${{ secrets.SONATYPE_PASSWORD }} - dependencies-cache-enabled: true - configuration-cache-enabled: true + arguments: publishToSonatype closeSonatypeStagingRepository -PsonatypeUsername=${{ secrets.SONATYPE_USERNAME }} -PsonatypePassword=${{ secrets.SONATYPE_PASSWORD }} env: SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} SIGNING_KEY: ${{ secrets.SIGNING_KEY }} From 6fa428d0298af500ca5d3ee269948ec08f8e6adf Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 11 Nov 2021 08:27:01 -0500 Subject: [PATCH 445/479] version: 1.3.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index d7f93861118..d837a2c7280 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 1.3.0 * Built using Avro 1.11.0 * Dropped support for Avro 1.9.0-1.10.2 due to use of new SpecificRecordBuilderBase constructor in Avro 1.11.0 * Default field visibility is now "PRIVATE" to match Avro's new default, as "PUBLIC_DEPRECATED" is no longer supported in Avro 1.11.0 diff --git a/build.gradle b/build.gradle index bc30e9e0687..572f6fb8454 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.2.2-SNAPSHOT" +version = "1.3.0" def isCI = System.getenv("CI") == "true" From a672c48a535c360c37f4b5851ea3bf54717da35f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 11 Nov 2021 08:32:00 -0500 Subject: [PATCH 446/479] version: 1.3.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 572f6fb8454..0765faa0a62 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.3.0" +version = "1.3.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" From e524dc3441eb02401e2e99f07a78399af4aa3ef6 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Thu, 9 Dec 2021 18:30:23 -0500 Subject: [PATCH 447/479] CI: enable automatic staging repository releasing --- .github/workflows/publish.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e71aec3ec43..715f70ce36d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,8 +13,7 @@ jobs: java-version: 8 - uses: gradle/gradle-build-action@v2 with: - # For now, release manually; closeAndReleaseSonatypeStagingRepository when I have confidence - arguments: publishToSonatype closeSonatypeStagingRepository -PsonatypeUsername=${{ secrets.SONATYPE_USERNAME }} -PsonatypePassword=${{ secrets.SONATYPE_PASSWORD }} + arguments: publishToSonatype closeAndReleaseSonatypeStagingRepository -PsonatypeUsername=${{ secrets.SONATYPE_USERNAME }} -PsonatypePassword=${{ secrets.SONATYPE_PASSWORD }} env: SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} SIGNING_KEY: ${{ secrets.SIGNING_KEY }} From 603c4a17c275255838e3c8a31e0ff8cd16384bd7 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 6 Sep 2022 23:23:23 -0400 Subject: [PATCH 448/479] Drop kotlin plugin integration --- .../workflows/kotlin-plugin-compatibility.yml | 132 ------------------ CHANGES.md | 1 + README.md | 8 +- build.gradle | 24 ---- ...inPluginCompatibilityFunctionalSpec.groovy | 63 --------- 5 files changed, 7 insertions(+), 221 deletions(-) delete mode 100644 .github/workflows/kotlin-plugin-compatibility.yml delete mode 100644 src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy diff --git a/.github/workflows/kotlin-plugin-compatibility.yml b/.github/workflows/kotlin-plugin-compatibility.yml deleted file mode 100644 index 19f1735dc57..00000000000 --- a/.github/workflows/kotlin-plugin-compatibility.yml +++ /dev/null @@ -1,132 +0,0 @@ -name: Kotlin Plugin Compatibility Tests -on: [push, pull_request] -jobs: - java8-gradle5_1: - name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] # Minimum version that this plugin supports - gradle: ["5.1"] # Minimum version that this plugin supports - java: ["8"] # Minimum version that this plugin supports - kotlin: [ - "1.2.20", "1.2.21", # These don't support Java 10+ - "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", - "1.3.0", "1.3.10", "1.3.11", - "1.3.20", "1.3.21", "1.3.30", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72" - # Later versions require Gradle 5.3+ - ] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - java8-gradle5_3: - name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] # Minimum version that this plugin supports - gradle: ["5.3"] # Minimum version supported by these versions of the Kotlin plugin - java: ["8"] # Minimum version that this plugin supports - kotlin: [ - # These versions require Gradle 5.3+ - "1.4.0", "1.4.10", "1.4.20", "1.4.21", "1.4.30", "1.4.31", "1.4.32" - ] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - java11-gradle5_6_4: - name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] # Latest version that this plugin supports - gradle: ["5.6.4"] - java: ["11"] # Latest LTS version that this plugin supports - kotlin: [ - # Earlier versions don't support Java 10+ - # These versions don't support Gradle 6+ - "1.2.30", "1.2.31", "1.2.40", "1.2.41", "1.2.50", "1.2.51", "1.2.60", "1.2.61", "1.2.70", "1.2.71", - "1.3.0", "1.3.10", "1.3.11", - ] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - java11_gradle_6_9_1: # This version breaks on Gradle 7.0 or later - name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] # Latest version that this plugin supports - gradle: ["6.9.1"] # Latest version that this version of kotlin plugin supports - java: ["11"] # Latest LTS version that this version of kotlin plugin supports - kotlin: ["1.3.30"] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - java11-gradle_latest: # These versions breaks on Java 17 or later; see https://youtrack.jetbrains.com/issue/KT-43704 - name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] # Latest version that this plugin supports - gradle: ["7.3"] # Latest version that this plugin supports - java: ["11"] # Latest LTS version that this version of kotlin plugin supports - kotlin: [ - "1.4.20", "1.4.21", "1.4.30","1.4.31", "1.4.32" - ] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} - modern: - name: "Compatibility: kotlin ${{ matrix.kotlin }}/gradle ${{ matrix.gradle }}/java ${{ matrix.java }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] # Latest version that this plugin supports - gradle: ["7.3"] # Latest version that this plugin supports - java: ["17"] # Latest LTS version that this plugin supports - kotlin: [ - # Other versions lack support for either Java 17+ or Gradle 7+ - "1.3.20", "1.3.21", "1.3.31", "1.3.40", "1.3.41", "1.3.50", "1.3.60", "1.3.61", "1.3.70", "1.3.71", "1.3.72", - "1.4.0", "1.4.10", - "1.5.0", "1.5.10", "1.5.20", "1.5.21", "1.5.30", "1.5.31" - ] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testKotlinPluginCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} -PkotlinPluginVersion=${{ matrix.kotlin }} diff --git a/CHANGES.md b/CHANGES.md index d837a2c7280..6b8391df5ff 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Drop support for Kotlin plugin integration ## 1.3.0 * Built using Avro 1.11.0 diff --git a/README.md b/README.md index dbc3b8377d5..bb08e3469b8 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,12 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Currently tested against Avro 1.11.0 * Avro 1.9.0-1.10.2 were last supported in version 1.2.1 * Support for Kotlin - * Currently tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 and 1.5.0-1.5.31 using the latest compatible version of Gradle - * Currently tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 + * Dropped integration with the Kotlin plugin in plugin version 1.4.0, as Kotlin 1.7.x would require compile-time dependency on a specific Kotlin version + * Wiring between the tasks added by the plugin and the Kotlin compilation tasks can either be added by your build logic, or a derived plugin + * Plugin version 1.3.0 was the last version with tested support for Kotlin + * It is believed to work with Kotlin 1.6.x as well + * It was tested against Kotlin plugin versions 1.3.20-1.3.72 and 1.4.0-1.4.32 and 1.5.0-1.5.31 using the latest compatible version of Gradle + * It was tested against Kotlin plugin versions 1.2.20-1.2.71 and 1.3.0-1.3.11 using Gradle 5.1 * Kotlin plugin versions 1.4.20-1.4.32 require special settings to work with Java 17+; see [KT-43704](https://youtrack.jetbrains.com/issue/KT-43704#focus=Comments-27-4639603.0-0) * Kotlin plugin version 1.3.30 is not compatible with Gradle 7.0+ * Kotlin plugin versions starting with 1.4.0 require Gradle 5.3+ diff --git a/build.gradle b/build.gradle index 0765faa0a62..8767813dd41 100644 --- a/build.gradle +++ b/build.gradle @@ -205,14 +205,11 @@ if (JavaVersion.current().java10Compatible) { sourceCompatibility = 8 } -def latestKotlinVersion = "1.5.31" - test { useJUnitPlatform() systemProperties = [ avroVersion: compileAvroVersion, gradleVersion: gradle.gradleVersion, - kotlinPluginVersion: latestKotlinVersion, ] // finalizedBy jacocoTestReport // report is always generated after tests run } @@ -225,33 +222,12 @@ tasks.create(name: "testCompatibility", type: Test) { avroVersion: findProperty("avroVersion"), gradleVersion: findProperty("gradleVersion"), ] - filter { - excludeTestsMatching "*KotlinPlugin*" - } reports { html.destination = file("$buildDir/reports/tests/compatibility") junitXml.destination = file("$buildDir/reports/tests/compatibility") } } -tasks.create(name: "testKotlinPluginCompatibility", type: Test) { - description = "Test cross-compatibility of the plugin with the Kotlin plugin" - group = "Verification" - useJUnitPlatform() - systemProperties = [ - avroVersion: findProperty("avroVersion"), - gradleVersion: findProperty("gradleVersion"), - kotlinPluginVersion: findProperty("kotlinPluginVersion"), - ] - filter { - includeTestsMatching "*KotlinPlugin*" - } - reports { - html.destination = file("$buildDir/reports/tests/kotlinPluginCompatibility") - junitXml.destination = file("$buildDir/reports/tests/kotlinPluginCompatibility") - } -} - //jacoco { // // 0.8.7+ needed for Java 15 support // // See https://www.jacoco.org/jacoco/trunk/doc/changes.html diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy deleted file mode 100644 index e248690cb74..00000000000 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinPluginCompatibilityFunctionalSpec.groovy +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright © 2017 Commerce Technologies, LLC. - * - * 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 com.github.davidmc24.gradle.plugin.avro - -import org.gradle.testkit.runner.BuildResult -import org.gradle.util.GradleVersion - -@SuppressWarnings(["Println"]) -class KotlinPluginCompatibilityFunctionalSpec extends FunctionalSpec { - @SuppressWarnings(["FieldName"]) - protected static final String kotlinPluginVersion = System.getProperty("kotlinPluginVersion", "undefined") - - def "setup"() { - println "Testing using Kotlin plugin version ${kotlinPluginVersion}." - } - - def "works with kotlin-gradle-plugin"() { - given: - File kotlinDir = projectFolder("src/main/kotlin") - applyAvroPlugin() - applyPlugin("org.jetbrains.kotlin.jvm", kotlinPluginVersion) - applyPlugin("application") - addDefaultRepository() - addAvroDependency() - addImplementationDependency("org.jetbrains.kotlin:kotlin-stdlib") - addRuntimeDependency("joda-time:joda-time:2.9.9") - buildFile << 'mainClassName = "demo.HelloWorldKt"' - copyResource("user.avsc", avroDir) - copyResource("helloWorld.kt", kotlinDir) - - when: - def result = runBuild() - - then: - result.output.contains("Hello, David") - } - - private BuildResult runBuild() { - def args = ["run"] - if (GradleFeatures.configCache.isSupportedBy(gradleVersion)) { - // The kotlin plugin prior to 1.4.20 doesn't support the configuration cache, so we need to disable it. - // This is a bit of a mis-use of the GradleVersion class, but it's way easier than writing our own - // version comparison logic. - if (GradleVersion.version(kotlinPluginVersion) < GradleVersion.version("1.4.20")) { - args << "--no-configuration-cache" - } - } - return run(args as String[]) - } -} From 6feee57c4768302439270c33d29fd8cb2276fae1 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 6 Sep 2022 23:25:33 -0400 Subject: [PATCH 449/479] Add note about seeking new maintainer to readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index bb08e3469b8..ea4c3a9d439 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +# Seeking New Maintainer + +For more details, see [the discussion](https://github.com/davidmc24/gradle-avro-plugin/discussions/208). + +If no new maintainer is found, this project will be archived on October 22, 2023 (the 10 year anniversary of this project's first public commit). + # Overview This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Java code generation for [Apache Avro](http://avro.apache.org/). It supports JSON schema declaration files, JSON protocol declaration files, and Avro IDL files. From b4bd11efb582cbafae8927923cd20ac7d19c4a0e Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 6 Sep 2022 23:40:47 -0400 Subject: [PATCH 450/479] version: 1.4.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 6b8391df5ff..46738d73216 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 1.4.0 * Drop support for Kotlin plugin integration ## 1.3.0 diff --git a/build.gradle b/build.gradle index 8767813dd41..e8980cdf538 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.3.1-SNAPSHOT" +version = "1.4.0" def isCI = System.getenv("CI") == "true" From 6784b20bb2956dcbb61ec7b84215cc2ad1187a12 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 6 Sep 2022 23:43:13 -0400 Subject: [PATCH 451/479] version: 1.4.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e8980cdf538..9574a69cd5a 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.4.0" +version = "1.4.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" From 9dd97908a71cff763187c094f9d32fcd0f1502ff Mon Sep 17 00:00:00 2001 From: Dave Cracauer Date: Thu, 15 Sep 2022 07:33:29 -0500 Subject: [PATCH 452/479] Add 'additionalVelocityTool' capability. Allows user to provide tools that will be available in Velocity templates at generation time. --- README.md | 17 +- .../gradle/plugin/avro/AvroBasePlugin.java | 1 + .../gradle/plugin/avro/AvroExtension.java | 1 + .../plugin/avro/DefaultAvroExtension.java | 17 + .../plugin/avro/GenerateAvroJavaTask.java | 38 + .../plugin/avro/OptionsFunctionalSpec.groovy | 45 + .../avro/test/custom/CommentGenerator.java | 11 + .../avro/test/custom/TimestampGenerator.java | 13 + .../gradle/plugin/avro/record-tools.vm | 872 ++++++++++++++++++ 9 files changed, 1014 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java create mode 100644 src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java create mode 100644 src/test/resources/com/github/davidmc24/gradle/plugin/avro/record-tools.vm diff --git a/README.md b/README.md index ea4c3a9d439..04897cb3292 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Actually, it will attempt to process an "avro" directory in every `SourceSet` (m There are a number of configuration options supported in the `avro` block. | option | default | description | -| -------------------------------------| --------------------- | ---------------------------------------------------------------| +|--------------------------------------| --------------------- |----------------------------------------------------------------| | createSetters | `true` | `createSetters` passed to Avro compiler | | createOptionalGetters | `false` | `createOptionalGetters` passed to Avro compiler | | gettersReturnOptional | `false` | `gettersReturnOptional` passed to Avro compiler | @@ -91,6 +91,7 @@ There are a number of configuration options supported in the `avro` block. | outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | | stringType | `"String"` | `stringType` passed to Avro compiler | | templateDirectory | see below | `templateDir` passed to Avro compiler | +| additionalVelocityToolClasses | see below | `additionalVelocityTools` passed to Avro compiler | | enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | Additionally, the `avro` extension exposes the following methods: @@ -224,6 +225,20 @@ avro { } ``` +## additionalVelocityToolClasses + +When overriding the default set of Velocity templates provided with Avro, it is often desirable to provide additional tools to use during generation. +The class names you provide will be made available for use in your Velocity templates. An instance of each class provided will be created using +the default constructor (required). When registered, they will be available as $class.simpleName(). Given the example configuration below, +two tools would be registered, and be available as escape and json. + + +```groovy +avro { + additionalVelocityToolClasses = ['com.yourpackage.Escape', 'com.yourpackage.JSON'] +} +``` + ## enableDecimalLogicalType Valid values: `true` (default), `false`; supports equivalent `String` values diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java index 6fe6f7cfc8e..037d1d47518 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java @@ -32,6 +32,7 @@ private static void configureExtension(final Project project) { task.getStringType().convention(avroExtension.getStringType()); task.getFieldVisibility().convention(avroExtension.getFieldVisibility()); task.getTemplateDirectory().convention(avroExtension.getTemplateDirectory()); + task.getAdditionalVelocityToolClasses().convention(avroExtension.getAdditionalVelocityToolClasses()); task.isCreateSetters().convention(avroExtension.isCreateSetters()); task.isCreateOptionalGetters().convention(avroExtension.isCreateOptionalGetters()); task.isGettersReturnOptional().convention(avroExtension.isGettersReturnOptional()); diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java index bd5b817cb06..87dc144e0ee 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java @@ -27,6 +27,7 @@ public interface AvroExtension { Property getStringType(); Property getFieldVisibility(); Property getTemplateDirectory(); + ListProperty getAdditionalVelocityToolClasses(); Property isCreateSetters(); Property isCreateOptionalGetters(); Property isGettersReturnOptional(); diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java index 9b78c3dd31b..aabd713eacf 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java @@ -16,6 +16,8 @@ package com.github.davidmc24.gradle.plugin.avro; import java.nio.charset.Charset; +import java.util.Collections; +import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.avro.Conversion; @@ -27,6 +29,8 @@ import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; @SuppressWarnings({"unused", "WeakerAccess"}) public class DefaultAvroExtension implements AvroExtension { @@ -34,6 +38,7 @@ public class DefaultAvroExtension implements AvroExtension { private final Property stringType; private final Property fieldVisibility; private final Property templateDirectory; + private final ListProperty additionalVelocityToolClasses; private final Property createSetters; private final Property createOptionalGetters; private final Property gettersReturnOptional; @@ -48,6 +53,8 @@ public DefaultAvroExtension(ObjectFactory objects) { this.stringType = objects.property(String.class).convention(Constants.DEFAULT_STRING_TYPE); this.fieldVisibility = objects.property(String.class).convention(Constants.DEFAULT_FIELD_VISIBILITY); this.templateDirectory = objects.property(String.class); + this.additionalVelocityToolClasses = + objects.listProperty(String.class).convention(Collections.emptyList()); this.createSetters = objects.property(Boolean.class).convention(Constants.DEFAULT_CREATE_SETTERS); this.createOptionalGetters = objects.property(Boolean.class).convention(Constants.DEFAULT_CREATE_OPTIONAL_GETTERS); this.gettersReturnOptional = objects.property(Boolean.class).convention(Constants.DEFAULT_GETTERS_RETURN_OPTIONAL); @@ -108,6 +115,16 @@ public void setTemplateDirectory(String templateDirectory) { this.templateDirectory.set(templateDirectory); } + @Optional + @Input + public ListProperty getAdditionalVelocityToolClasses() { + return additionalVelocityToolClasses; + } + + public void setAdditionalVelocityToolClasses(List additionalVelocityToolClasses) { + this.additionalVelocityToolClasses.set(additionalVelocityToolClasses); + } + @Override public Property isCreateSetters() { return createSetters; diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java index 366a3c56f29..6415f092726 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -17,7 +17,10 @@ import java.io.File; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.nio.charset.Charset; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -58,6 +61,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Property stringType; private final Property fieldVisibility; private final Property templateDirectory; + private final ListProperty additionalVelocityToolClasses; private final Property createOptionalGetters; private final Property gettersReturnOptional; private final Property optionalGettersForNullableFieldsOnly; @@ -79,6 +83,8 @@ public GenerateAvroJavaTask(ObjectFactory objects) { this.stringType = objects.property(String.class).convention(Constants.DEFAULT_STRING_TYPE); this.fieldVisibility = objects.property(String.class).convention(Constants.DEFAULT_FIELD_VISIBILITY); this.templateDirectory = objects.property(String.class); + this.additionalVelocityToolClasses = + objects.listProperty(String.class).convention(Collections.emptyList()); this.createOptionalGetters = objects.property(Boolean.class).convention(Constants.DEFAULT_CREATE_OPTIONAL_GETTERS); this.gettersReturnOptional = objects.property(Boolean.class).convention(Constants.DEFAULT_GETTERS_RETURN_OPTIONAL); this.optionalGettersForNullableFieldsOnly = objects.property(Boolean.class) @@ -147,6 +153,16 @@ public void setTemplateDirectory(String templateDirectory) { this.templateDirectory.set(templateDirectory); } + @Optional + @Input + public ListProperty getAdditionalVelocityToolClasses() { + return additionalVelocityToolClasses; + } + + public void setAdditionalVelocityToolClasses(List additionalVelocityToolClasses) { + this.additionalVelocityToolClasses.set(additionalVelocityToolClasses); + } + public Property isCreateSetters() { return createSetters; } @@ -248,6 +264,7 @@ protected void process() { getLogger().debug("Using stringType {}", stringTypeProvider.get().name()); getLogger().debug("Using fieldVisibility {}", fieldVisibilityProvider.get().name()); getLogger().debug("Using templateDirectory '{}'", getTemplateDirectory().getOrNull()); + getLogger().debug("Using additionalVelocityToolClasses '{}'", getAdditionalVelocityToolClasses().getOrNull()); getLogger().debug("Using createSetters {}", isCreateSetters().get()); getLogger().debug("Using createOptionalGetters {}", isCreateOptionalGetters().get()); getLogger().debug("Using gettersReturnOptional {}", isGettersReturnOptional().get()); @@ -322,6 +339,27 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept if (getTemplateDirectory().isPresent()) { compiler.setTemplateDir(getTemplateDirectory().get()); } + if (getAdditionalVelocityToolClasses().isPresent()) { + List tools = getAdditionalVelocityToolClasses().get().stream() + .map(s -> { + try { + return Class.forName(s); + } catch (ClassNotFoundException e) { + throw new RuntimeException("unable to load velocity tool class " + s, e); + } + }) + .map(aClass -> { + try { + return aClass.getConstructor().newInstance(); + } catch (InstantiationException + | NoSuchMethodException + | InvocationTargetException + | IllegalAccessException e) { + throw new RuntimeException("Unable to instantiate velocity tool class using default constructor: " + aClass, e); + } + }).collect(Collectors.toList()); + compiler.setAdditionalVelocityTools(tools); + } compiler.setCreateOptionalGetters(createOptionalGetters.get()); compiler.setGettersReturnOptional(gettersReturnOptional.get()); compiler.setOptionalGettersForNullableFieldsOnly(optionalGettersForNullableFieldsOnly.get()); diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy index 10eb98c5636..4b9efc8dc8b 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy @@ -15,6 +15,8 @@ */ package com.github.davidmc24.gradle.plugin.avro +import com.github.davidmc24.gradle.plugin.avro.test.custom.CommentGenerator +import com.github.davidmc24.gradle.plugin.avro.test.custom.TimestampGenerator import org.apache.avro.compiler.specific.SpecificCompiler.FieldVisibility import org.apache.avro.generic.GenericData.StringType import spock.lang.Unroll @@ -266,6 +268,42 @@ class OptionsFunctionalSpec extends FunctionalSpec { content.contains("Custom template") } + def "supports configuring velocity tool classes"() { + given: + copyAvroTools("buildSrc/src/main/java") + copyAvroTools("src/main/java") + def templatesDir = projectFolder("templates/alternateTemplates") + copyResource("user.avsc", avroDir) + copyResource("record-tools.vm", templatesDir, "record.vm") + // This functionality doesn't work with the plugins DSL syntax. + // To load files from the buildscript classpath you need to load the plugin from it as well. + buildFile << """ + |buildscript { + | dependencies { + | classpath files(${readPluginClasspath()}) + | classpath files(["${templatesDir.parentFile.toURI()}"]) + | } + |} + |apply plugin: "com.github.davidmc24.gradle.plugin.avro" + |avro { + | templateDirectory = "/alternateTemplates/" + | additionalVelocityToolClasses = ['com.github.davidmc24.gradle.plugin.avro.test.custom.TimestampGenerator', + | 'com.github.davidmc24.gradle.plugin.avro.test.custom.CommentGenerator'] + |} + |""".stripMargin() + + when: + def result = run("generateAvroJava") + + then: "the task succeeds" + result.task(":generateAvroJava").outcome == SUCCESS + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + + and: "the velocity tools have been applied" + content.contains(CommentGenerator.CUSTOM_COMMENT) + content.contains(TimestampGenerator.MESSAGE_PREFIX) + } + def "rejects unsupported stringType values"() { given: copyResource("user.avsc", avroDir) @@ -348,4 +386,11 @@ class OptionsFunctionalSpec extends FunctionalSpec { assert matcher.find() return matcher.group("mainClassContent") } + + private void copyAvroTools(String destDir) { + copyFile("src/test/java", destDir, + "com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java") + copyFile("src/test/java", destDir, + "com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java") + } } diff --git a/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java new file mode 100644 index 00000000000..767763bebaf --- /dev/null +++ b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java @@ -0,0 +1,11 @@ +package com.github.davidmc24.gradle.plugin.avro.test.custom; + +public class CommentGenerator { + + public static final String CUSTOM_COMMENT = "/** Custom generated comment. */"; + + public String generateComment() { + return CommentGenerator.CUSTOM_COMMENT; + } + +} diff --git a/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java new file mode 100644 index 00000000000..1fa300bf6e4 --- /dev/null +++ b/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java @@ -0,0 +1,13 @@ +package com.github.davidmc24.gradle.plugin.avro.test.custom; + + +public class TimestampGenerator { + + public static final String MESSAGE_PREFIX = "Current timestamp is"; + + public String generateTimestampMessage() { + return String.format("%s %s", MESSAGE_PREFIX, + java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ISO_DATE_TIME)); + } + +} diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record-tools.vm b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record-tools.vm new file mode 100644 index 00000000000..1e8b6891268 --- /dev/null +++ b/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record-tools.vm @@ -0,0 +1,872 @@ +## +## Licensed to the Apache Software Foundation (ASF) under one +## or more contributor license agreements. See the NOTICE file +## distributed with this work for additional information +## regarding copyright ownership. The ASF licenses this file +## to you under the Apache License, Version 2.0 (the +## "License"); you may not use this file except in compliance +## with the License. You may obtain a copy of the License at +## +## https://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## +#if ($schema.getNamespace()) +package $this.mangle($schema.getNamespace()); +#end + +import org.apache.avro.generic.GenericArray; +import org.apache.avro.specific.SpecificData; +import org.apache.avro.util.Utf8; +#if (!$schema.isError()) +import org.apache.avro.message.BinaryMessageEncoder; +import org.apache.avro.message.BinaryMessageDecoder; +import org.apache.avro.message.SchemaStore; +#end +#if (${this.gettersReturnOptional} || ${this.createOptionalGetters})import java.util.Optional;#end + +#if ($schema.getDoc()) +/** $schema.getDoc() */ +#end +#foreach ($annotation in $this.javaAnnotations($schema)) +@$annotation +#end +/** +${timestampgenerator.generateTimestampMessage()} +*/ +@org.apache.avro.specific.AvroGenerated +public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends org.apache.avro.specific.SpecificExceptionBase#else extends org.apache.avro.specific.SpecificRecordBase#end implements org.apache.avro.specific.SpecificRecord { + ${commentgenerator.generateComment()} + private static final long serialVersionUID = ${this.fingerprint64($schema)}L; + +#set ($schemaString = $this.javaSplit($schema.toString())) +#set ($customLogicalTypeFactories = $this.getUsedCustomLogicalTypeFactories($schema).entrySet()) +#if (!$customLogicalTypeFactories.isEmpty()) + static { +#foreach ($customLogicalTypeFactory in $customLogicalTypeFactories) + org.apache.avro.LogicalTypes.register("${customLogicalTypeFactory.getKey()}", new ${customLogicalTypeFactory.getValue()}()); +#end + } +#end + + public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse($schemaString); + public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; } + + private static final SpecificData MODEL$ = new SpecificData(); +#set ($usedConversions = $this.getUsedConversionClasses($schema)) +#if (!$usedConversions.isEmpty()) + static { +#foreach ($conversion in $usedConversions) + MODEL$.addLogicalTypeConversion(new ${conversion}()); +#end + } +#end + +#if (!$schema.isError()) + private static final BinaryMessageEncoder<${this.mangle($schema.getName())}> ENCODER = + new BinaryMessageEncoder<${this.mangle($schema.getName())}>(MODEL$, SCHEMA$); + + private static final BinaryMessageDecoder<${this.mangle($schema.getName())}> DECODER = + new BinaryMessageDecoder<${this.mangle($schema.getName())}>(MODEL$, SCHEMA$); + + /** + * Return the BinaryMessageEncoder instance used by this class. + * @return the message encoder used by this class + */ + public static BinaryMessageEncoder<${this.mangle($schema.getName())}> getEncoder() { + return ENCODER; + } + + /** + * Return the BinaryMessageDecoder instance used by this class. + * @return the message decoder used by this class + */ + public static BinaryMessageDecoder<${this.mangle($schema.getName())}> getDecoder() { + return DECODER; + } + + /** + * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}. + * @param resolver a {@link SchemaStore} used to find schemas by fingerprint + * @return a BinaryMessageDecoder instance for this class backed by the given SchemaStore + */ + public static BinaryMessageDecoder<${this.mangle($schema.getName())}> createDecoder(SchemaStore resolver) { + return new BinaryMessageDecoder<${this.mangle($schema.getName())}>(MODEL$, SCHEMA$, resolver); + } + + /** + * Serializes this ${schema.getName()} to a ByteBuffer. + * @return a buffer holding the serialized data for this instance + * @throws java.io.IOException if this instance could not be serialized + */ + public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException { + return ENCODER.encode(this); + } + + /** + * Deserializes a ${schema.getName()} from a ByteBuffer. + * @param b a byte buffer holding serialized data for an instance of this class + * @return a ${schema.getName()} instance decoded from the given buffer + * @throws java.io.IOException if the given bytes could not be deserialized into an instance of this class + */ + public static ${this.mangle($schema.getName())} fromByteBuffer( + java.nio.ByteBuffer b) throws java.io.IOException { + return DECODER.decode(b); + } +#end + +#foreach ($field in $schema.getFields()) +#if ($field.doc()) + /** $field.doc() */ +#end +#foreach ($annotation in $this.javaAnnotations($field)) + @$annotation +#end + #if (${this.publicFields()})public#elseif (${this.privateFields()})private#end ${this.javaUnbox($field.schema(), false)} ${this.mangle($field.name(), $schema.isError())}; +#end +#if ($schema.isError()) + + public ${this.mangle($schema.getName())}() { + super(); + } + + public ${this.mangle($schema.getName())}(Object value) { + super(value); + } + + public ${this.mangle($schema.getName())}(Throwable cause) { + super(cause); + } + + public ${this.mangle($schema.getName())}(Object value, Throwable cause) { + super(value, cause); + } + +#else +#if ($schema.getFields().size() > 0) + + /** + * Default constructor. Note that this does not initialize fields + * to their default values from the schema. If that is desired then + * one should use newBuilder(). + */ + public ${this.mangle($schema.getName())}() {} +#if ($this.isCreateAllArgsConstructor()) + + /** + * All-args constructor. +#foreach ($field in $schema.getFields()) +#if ($field.doc()) * @param ${this.mangle($field.name())} $field.doc() +#else * @param ${this.mangle($field.name())} The new value for ${field.name()} +#end +#end + */ + public ${this.mangle($schema.getName())}(#foreach($field in $schema.getFields())${this.javaType($field.schema())} ${this.mangle($field.name())}#if($foreach.count < $schema.getFields().size()), #end#end) { +#foreach ($field in $schema.getFields()) + ${this.generateSetterCode($field.schema(), ${this.mangle($field.name())}, ${this.mangle($field.name())})} +#end + } +#else + /** + * This schema contains more than 254 fields which exceeds the maximum number + * of permitted constructor parameters in the JVM. An all-args constructor + * will not be generated. Please use newBuilder() to instantiate + * objects instead. + */ +#end +#end + +#end + public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; } + public org.apache.avro.Schema getSchema() { return SCHEMA$; } + // Used by DatumWriter. Applications should not call. + public java.lang.Object get(int field$) { + switch (field$) { +#set ($i = 0) +#foreach ($field in $schema.getFields()) + case $i: return ${this.mangle($field.name(), $schema.isError())}; +#set ($i = $i + 1) +#end + default: throw new IndexOutOfBoundsException("Invalid index: " + field$); + } + } + +#if ($this.hasLogicalTypeField($schema)) + private static final org.apache.avro.Conversion[] conversions = + new org.apache.avro.Conversion[] { +#foreach ($field in $schema.getFields()) + ${this.conversionInstance($field.schema())}, +#end + null + }; + + @Override + public org.apache.avro.Conversion getConversion(int field) { + return conversions[field]; + } + +#end + // Used by DatumReader. Applications should not call. + @SuppressWarnings(value="unchecked") + public void put(int field$, java.lang.Object value$) { + switch (field$) { +#set ($i = 0) +#foreach ($field in $schema.getFields()) + case $i: ${this.mangle($field.name(), $schema.isError())} = #if(${this.javaType($field.schema())} != "java.lang.Object" && ${this.javaType($field.schema())} != "java.lang.String")(${this.javaType($field.schema())})#{end}value$#if(${this.javaType($field.schema())} == "java.lang.String") != null ? value$.toString() : null#{end}; break; +#set ($i = $i + 1) +#end + default: throw new IndexOutOfBoundsException("Invalid index: " + field$); + } + } + +#foreach ($field in $schema.getFields()) +#if (${this.gettersReturnOptional} && (!${this.optionalGettersForNullableFieldsOnly} || ${field.schema().isNullable()})) + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. +#if ($field.doc()) * $field.doc() +#end + * @return The value wrapped in an Optional<${this.javaType($field.schema())}>. + */ + public Optional<${this.javaType($field.schema())}> ${this.generateGetMethod($schema, $field)}() { + return Optional.<${this.javaType($field.schema())}>ofNullable(${this.mangle($field.name(), $schema.isError())}); + } +#else + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * @return $field.doc() +#else * @return The value of the '${this.mangle($field.name(), $schema.isError())}' field. +#end + */ + public ${this.javaUnbox($field.schema(), false)} ${this.generateGetMethod($schema, $field)}() { + return ${this.mangle($field.name(), $schema.isError())}; + } +#end + +#if (${this.createOptionalGetters}) + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. +#if ($field.doc()) * $field.doc() +#end + * @return The value wrapped in an Optional<${this.javaType($field.schema())}>. + */ + public Optional<${this.javaType($field.schema())}> ${this.generateGetOptionalMethod($schema, $field)}() { + return Optional.<${this.javaType($field.schema())}>ofNullable(${this.mangle($field.name(), $schema.isError())}); + } +#end + +#if ($this.createSetters) + /** + * Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * $field.doc() +#end + * @param value the value to set. + */ + public void ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema(), false)} value) { + ${this.generateSetterCode($field.schema(), ${this.mangle($field.name(), $schema.isError())}, "value")} + } +#end + +#end + /** + * Creates a new ${this.mangle($schema.getName())} RecordBuilder. + * @return A new ${this.mangle($schema.getName())} RecordBuilder + */ + public static #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder newBuilder() { + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(); + } + + /** + * Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing Builder. + * @param other The existing builder to copy. + * @return A new ${this.mangle($schema.getName())} RecordBuilder + */ + public static #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder other) { + if (other == null) { + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(); + } else { + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(other); + } + } + + /** + * Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing $this.mangle($schema.getName()) instance. + * @param other The existing instance to copy. + * @return A new ${this.mangle($schema.getName())} RecordBuilder + */ + public static #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())} other) { + if (other == null) { + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(); + } else { + return new #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder(other); + } + } + + /** + * RecordBuilder for ${this.mangle($schema.getName())} instances. + */ + @org.apache.avro.specific.AvroGenerated + public static class Builder extends#if ($schema.isError()) org.apache.avro.specific.SpecificErrorBuilderBase<${this.mangle($schema.getName())}>#else org.apache.avro.specific.SpecificRecordBuilderBase<${this.mangle($schema.getName())}>#end + + implements#if ($schema.isError()) org.apache.avro.data.ErrorBuilder<${this.mangle($schema.getName())}>#else org.apache.avro.data.RecordBuilder<${this.mangle($schema.getName())}>#end { + +#foreach ($field in $schema.getFields()) +#if ($field.doc()) + /** $field.doc() */ +#end + private ${this.javaUnbox($field.schema(), false)} ${this.mangle($field.name(), $schema.isError())}; +#if (${this.hasBuilder($field.schema())}) + private ${this.javaUnbox($field.schema(), false)}.Builder ${this.mangle($field.name(), $schema.isError())}Builder; +#end +#end + + /** Creates a new Builder */ + private Builder() { + super(SCHEMA$, MODEL$); + } + + /** + * Creates a Builder by copying an existing Builder. + * @param other The existing Builder to copy. + */ + private Builder(#if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder other) { + super(other); +#foreach ($field in $schema.getFields()) + if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) { + this.${this.mangle($field.name(), $schema.isError())} = data().deepCopy(fields()[$field.pos()].schema(), other.${this.mangle($field.name(), $schema.isError())}); + fieldSetFlags()[$field.pos()] = other.fieldSetFlags()[$field.pos()]; + } +#if (${this.hasBuilder($field.schema())}) + if (other.${this.generateHasBuilderMethod($schema, $field)}()) { + this.${this.mangle($field.name(), $schema.isError())}Builder = ${this.javaType($field.schema())}.newBuilder(other.${this.generateGetBuilderMethod($schema, $field)}()); + } +#end +#end + } + + /** + * Creates a Builder by copying an existing $this.mangle($schema.getName()) instance + * @param other The existing instance to copy. + */ + private Builder(#if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())} other) { +#if ($schema.isError()) super(other)#else + super(SCHEMA$, MODEL$)#end; +#foreach ($field in $schema.getFields()) + if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) { + this.${this.mangle($field.name(), $schema.isError())} = data().deepCopy(fields()[$field.pos()].schema(), other.${this.mangle($field.name(), $schema.isError())}); + fieldSetFlags()[$field.pos()] = true; + } +#if (${this.hasBuilder($field.schema())}) + this.${this.mangle($field.name(), $schema.isError())}Builder = null; +#end +#end + } +#if ($schema.isError()) + + @Override + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder setValue(Object value) { + super.setValue(value); + return this; + } + + @Override + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder clearValue() { + super.clearValue(); + return this; + } + + @Override + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder setCause(Throwable cause) { + super.setCause(cause); + return this; + } + + @Override + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder clearCause() { + super.clearCause(); + return this; + } +#end + +#foreach ($field in $schema.getFields()) + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * $field.doc() +#end + * @return The value. + */ + public ${this.javaUnbox($field.schema(), false)} ${this.generateGetMethod($schema, $field)}() { + return ${this.mangle($field.name(), $schema.isError())}; + } + +#if (${this.createOptionalGetters}) + /** + * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.javaType($field.schema())}>. +#if ($field.doc()) * $field.doc() +#end + * @return The value wrapped in an Optional<${this.javaType($field.schema())}>. + */ + public Optional<${this.javaType($field.schema())}> ${this.generateGetOptionalMethod($schema, $field)}() { + return Optional.<${this.javaType($field.schema())}>ofNullable(${this.mangle($field.name(), $schema.isError())}); + } +#end + + /** + * Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * $field.doc() +#end + * @param value The value of '${this.mangle($field.name(), $schema.isError())}'. + * @return This builder. + */ + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema(), false)} value) { + validate(fields()[$field.pos()], value); +#if (${this.hasBuilder($field.schema())}) + this.${this.mangle($field.name(), $schema.isError())}Builder = null; +#end + ${this.generateSetterCode($field.schema(), ${this.mangle($field.name(), $schema.isError())}, "value")} + fieldSetFlags()[$field.pos()] = true; + return this; + } + + /** + * Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has been set. +#if ($field.doc()) * $field.doc() +#end + * @return True if the '${this.mangle($field.name(), $schema.isError())}' field has been set, false otherwise. + */ + public boolean ${this.generateHasMethod($schema, $field)}() { + return fieldSetFlags()[$field.pos()]; + } + +#if (${this.hasBuilder($field.schema())}) + /** + * Gets the Builder instance for the '${this.mangle($field.name(), $schema.isError())}' field and creates one if it doesn't exist yet. +#if ($field.doc()) * $field.doc() +#end + * @return This builder. + */ + public ${this.javaType($field.schema())}.Builder ${this.generateGetBuilderMethod($schema, $field)}() { + if (${this.mangle($field.name(), $schema.isError())}Builder == null) { + if (${this.generateHasMethod($schema, $field)}()) { + ${this.generateSetBuilderMethod($schema, $field)}(${this.javaType($field.schema())}.newBuilder(${this.mangle($field.name(), $schema.isError())})); + } else { + ${this.generateSetBuilderMethod($schema, $field)}(${this.javaType($field.schema())}.newBuilder()); + } + } + return ${this.mangle($field.name(), $schema.isError())}Builder; + } + + /** + * Sets the Builder instance for the '${this.mangle($field.name(), $schema.isError())}' field +#if ($field.doc()) * $field.doc() +#end + * @param value The builder instance that must be set. + * @return This builder. + */ + + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder ${this.generateSetBuilderMethod($schema, $field)}(${this.javaUnbox($field.schema(), false)}.Builder value) { + ${this.generateClearMethod($schema, $field)}(); + ${this.mangle($field.name(), $schema.isError())}Builder = value; + return this; + } + + /** + * Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has an active Builder instance +#if ($field.doc()) * $field.doc() +#end + * @return True if the '${this.mangle($field.name(), $schema.isError())}' field has an active Builder instance + */ + public boolean ${this.generateHasBuilderMethod($schema, $field)}() { + return ${this.mangle($field.name(), $schema.isError())}Builder != null; + } +#end + + /** + * Clears the value of the '${this.mangle($field.name(), $schema.isError())}' field. +#if ($field.doc()) * $field.doc() +#end + * @return This builder. + */ + public #if ($schema.getNamespace())$this.mangle($schema.getNamespace()).#end${this.mangle($schema.getName())}.Builder ${this.generateClearMethod($schema, $field)}() { +#if (${this.isUnboxedJavaTypeNullable($field.schema())}) + ${this.mangle($field.name(), $schema.isError())} = null; +#end +#if (${this.hasBuilder($field.schema())}) + ${this.mangle($field.name(), $schema.isError())}Builder = null; +#end + fieldSetFlags()[$field.pos()] = false; + return this; + } + +#end + @Override + @SuppressWarnings("unchecked") + public ${this.mangle($schema.getName())} build() { + try { + ${this.mangle($schema.getName())} record = new ${this.mangle($schema.getName())}(#if ($schema.isError())getValue(), getCause()#end); +#foreach ($field in $schema.getFields()) +#if (${this.hasBuilder($field.schema())}) + if (${this.mangle($field.name(), $schema.isError())}Builder != null) { + try { + record.${this.mangle($field.name(), $schema.isError())} = this.${this.mangle($field.name(), $schema.isError())}Builder.build(); + } catch (org.apache.avro.AvroMissingFieldException e) { + e.addParentField(record.getSchema().getField("${this.mangle($field.name(), $schema.isError())}")); + throw e; + } + } else { + record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : #if(${this.javaType($field.schema())} != "java.lang.Object")(${this.javaType($field.schema())})#{end} defaultValue(fields()[$field.pos()]); + } +#else + record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : #if(${this.javaType($field.schema())} != "java.lang.Object")(${this.javaType($field.schema())})#{end} defaultValue(fields()[$field.pos()]); +#end +#end + return record; + } catch (org.apache.avro.AvroMissingFieldException e) { + throw e; + } catch (java.lang.Exception e) { + throw new org.apache.avro.AvroRuntimeException(e); + } + } + } + + @SuppressWarnings("unchecked") + private static final org.apache.avro.io.DatumWriter<${this.mangle($schema.getName())}> + WRITER$ = (org.apache.avro.io.DatumWriter<${this.mangle($schema.getName())}>)MODEL$.createDatumWriter(SCHEMA$); + + @Override public void writeExternal(java.io.ObjectOutput out) + throws java.io.IOException { + WRITER$.write(this, SpecificData.getEncoder(out)); + } + + @SuppressWarnings("unchecked") + private static final org.apache.avro.io.DatumReader<${this.mangle($schema.getName())}> + READER$ = (org.apache.avro.io.DatumReader<${this.mangle($schema.getName())}>)MODEL$.createDatumReader(SCHEMA$); + + @Override public void readExternal(java.io.ObjectInput in) + throws java.io.IOException { + READER$.read(this, SpecificData.getDecoder(in)); + } + +#if ($this.isCustomCodable($schema)) + @Override protected boolean hasCustomCoders() { return true; } + + @Override public void customEncode(org.apache.avro.io.Encoder out) + throws java.io.IOException + { +#set ($nv = 0)## Counter to ensure unique var-names +#set ($maxnv = 0)## Holds high-water mark during recursion +#foreach ($field in $schema.getFields()) +#set ($n = $this.mangle($field.name(), $schema.isError())) +#set ($s = $field.schema()) +#encodeVar(0 "this.${n}" $s) + +#set ($nv = $maxnv) +#end + } + + @Override public void customDecode(org.apache.avro.io.ResolvingDecoder in) + throws java.io.IOException + { + org.apache.avro.Schema.Field[] fieldOrder = in.readFieldOrderIfDiff(); + if (fieldOrder == null) { +## Common case: order of fields hasn't changed, so read them in a +## fixed order according to reader's schema +#set ($nv = 0)## Counter to ensure unique var-names +#set ($maxnv = 0)## Holds high-water mark during recursion +#foreach ($field in $schema.getFields()) +#set ($n = $this.mangle($field.name(), $schema.isError())) +#set ($s = $field.schema()) +#set ($rs = "SCHEMA$.getField(""${n}"").schema()") +#decodeVar(2 "this.${n}" $s $rs) + +#set ($nv = $maxnv) +#end + } else { + for (int i = 0; i < $schema.getFields().size(); i++) { + switch (fieldOrder[i].pos()) { +#set ($fieldno = 0) +#set ($nv = 0)## Counter to ensure unique var-names +#set ($maxnv = 0)## Holds high-water mark during recursion +#foreach ($field in $schema.getFields()) + case $fieldno: +#set ($n = $this.mangle($field.name(), $schema.isError())) +#set ($s = $field.schema()) +#set ($rs = "SCHEMA$.getField(""${n}"").schema()") +#decodeVar(6 "this.${n}" $s $rs) + break; + +#set ($nv = $maxnv) +#set ($fieldno = $fieldno + 1) +#end + default: + throw new java.io.IOException("Corrupt ResolvingDecoder."); + } + } + } + } +#end +} + +#macro( encodeVar $indent $var $s ) +#set ($I = $this.indent($indent)) +##### Compound types (array, map, and union) require calls +##### that will recurse back into this encodeVar macro: +#if ($s.Type.Name.equals("array")) +#encodeArray($indent $var $s) +#elseif ($s.Type.Name.equals("map")) +#encodeMap($indent $var $s) +#elseif ($s.Type.Name.equals("union")) +#encodeUnion($indent $var $s) +##### Use the generated "encode" method as fast way to write +##### (specific) record types: +#elseif ($s.Type.Name.equals("record")) +$I ${var}.customEncode(out); +##### For rest of cases, generate calls out.writeXYZ: +#elseif ($s.Type.Name.equals("null")) +$I out.writeNull(); +#elseif ($s.Type.Name.equals("boolean")) +$I out.writeBoolean(${var}); +#elseif ($s.Type.Name.equals("int")) +$I out.writeInt(${var}); +#elseif ($s.Type.Name.equals("long")) +$I out.writeLong(${var}); +#elseif ($s.Type.Name.equals("float")) +$I out.writeFloat(${var}); +#elseif ($s.Type.Name.equals("double")) +$I out.writeDouble(${var}); +#elseif ($s.Type.Name.equals("string")) +#if ($this.isStringable($s)) +$I out.writeString(${var}.toString()); +#else +$I out.writeString(${var}); +#end +#elseif ($s.Type.Name.equals("bytes")) +$I out.writeBytes(${var}); +#elseif ($s.Type.Name.equals("fixed")) +$I out.writeFixed(${var}.bytes(), 0, ${s.FixedSize}); +#elseif ($s.Type.Name.equals("enum")) +$I out.writeEnum(${var}.ordinal()); +#else +## TODO -- singal a code-gen-time error +#end +#end + +#macro( encodeArray $indent $var $s ) +#set ($I = $this.indent($indent)) +#set ($et = $this.javaType($s.ElementType)) +$I long size${nv} = ${var}.size(); +$I out.writeArrayStart(); +$I out.setItemCount(size${nv}); +$I long actualSize${nv} = 0; +$I for ($et e${nv}: ${var}) { +$I actualSize${nv}++; +$I out.startItem(); +#set ($var = "e${nv}") +#set ($nv = $nv + 1) +#set ($maxnv = $nv) +#set ($indent = $indent + 2) +#encodeVar($indent $var $s.ElementType) +#set ($nv = $nv - 1) +#set ($indent = $indent - 2) +#set ($I = $this.indent($indent)) +$I } +$I out.writeArrayEnd(); +$I if (actualSize${nv} != size${nv}) +$I throw new java.util.ConcurrentModificationException("Array-size written was " + size${nv} + ", but element count was " + actualSize${nv} + "."); +#end + +#macro( encodeMap $indent $var $s ) +#set ($I = $this.indent($indent)) +#set ($kt = $this.getStringType($s)) +#set ($vt = $this.javaType($s.ValueType)) +$I long size${nv} = ${var}.size(); +$I out.writeMapStart(); +$I out.setItemCount(size${nv}); +$I long actualSize${nv} = 0; +$I for (java.util.Map.Entry<$kt, $vt> e${nv}: ${var}.entrySet()) { +$I actualSize${nv}++; +$I out.startItem(); +#if ($this.isStringable($s)) +$I out.writeString(e${nv}.getKey().toString()); +#else +$I out.writeString(e${nv}.getKey()); +#end +$I $vt v${nv} = e${nv}.getValue(); +#set ($var = "v${nv}") +#set ($nv = $nv + 1) +#set ($maxnv = $nv) +#set ($indent = $indent + 2) +#encodeVar($indent $var $s.ValueType) +#set ($nv = $nv - 1) +#set ($indent = $indent - 2) +#set ($I = $this.indent($indent)) +$I } +$I out.writeMapEnd(); +$I if (actualSize${nv} != size${nv}) + throw new java.util.ConcurrentModificationException("Map-size written was " + size${nv} + ", but element count was " + actualSize${nv} + "."); +#end + +#macro( encodeUnion $indent $var $s ) +#set ($I = $this.indent($indent)) +#set ($et = $this.javaType($s.Types.get($this.getNonNullIndex($s)))) +$I if (${var} == null) { +$I out.writeIndex(#if($this.getNonNullIndex($s)==0)1#{else}0#end); +$I out.writeNull(); +$I } else { +$I out.writeIndex(${this.getNonNullIndex($s)}); +#set ($indent = $indent + 2) +#encodeVar($indent $var $s.Types.get($this.getNonNullIndex($s))) +#set ($indent = $indent - 2) +#set ($I = $this.indent($indent)) +$I } +#end + + +#macro( decodeVar $indent $var $s $rs ) +#set ($I = $this.indent($indent)) +##### Compound types (array, map, and union) require calls +##### that will recurse back into this decodeVar macro: +#if ($s.Type.Name.equals("array")) +#decodeArray($indent $var $s $rs) +#elseif ($s.Type.Name.equals("map")) +#decodeMap($indent $var $s $rs) +#elseif ($s.Type.Name.equals("union")) +#decodeUnion($indent $var $s $rs) +##### Use the generated "decode" method as fast way to write +##### (specific) record types: +#elseif ($s.Type.Name.equals("record")) +$I if (${var} == null) { +$I ${var} = new ${this.javaType($s)}(); +$I } +$I ${var}.customDecode(in); +##### For rest of cases, generate calls in.readXYZ: +#elseif ($s.Type.Name.equals("null")) +$I in.readNull(); +#elseif ($s.Type.Name.equals("boolean")) +$I $var = in.readBoolean(); +#elseif ($s.Type.Name.equals("int")) +$I $var = in.readInt(); +#elseif ($s.Type.Name.equals("long")) +$I $var = in.readLong(); +#elseif ($s.Type.Name.equals("float")) +$I $var = in.readFloat(); +#elseif ($s.Type.Name.equals("double")) +$I $var = in.readDouble(); +#elseif ($s.Type.Name.equals("string")) +#decodeString( "$I" $var $s ) +#elseif ($s.Type.Name.equals("bytes")) +$I $var = in.readBytes(${var}); +#elseif ($s.Type.Name.equals("fixed")) +$I if (${var} == null) { +$I ${var} = new ${this.javaType($s)}(); +$I } +$I in.readFixed(${var}.bytes(), 0, ${s.FixedSize}); +#elseif ($s.Type.Name.equals("enum")) +$I $var = ${this.javaType($s)}.values()[in.readEnum()]; +#else +## TODO -- singal a code-gen-time error +#end +#end + +#macro( decodeString $II $var $s ) +#set ($st = ${this.getStringType($s)}) +#if ($this.isStringable($s)) +#if ($st.equals("java.net.URI")) +$II try { +$II ${var} = new ${st}(in.readString()); +$II } catch (java.net.URISyntaxException e) { +$II throw new java.io.IOException(e.getMessage()); +$II } +#elseif ($st.equals("java.net.URL")) +$II try { +$II ${var} = new ${st}(in.readString()); +$II } catch (java.net.MalformedURLException e) { +$II throw new java.io.IOException(e.getMessage()); +$II } +#else +$II ${var} = new ${st}(in.readString()); +#end +#elseif ($st.equals("java.lang.String")) +$II $var = in.readString(); +#elseif ($st.equals("org.apache.avro.util.Utf8")) +$II $var = in.readString(${var}); +#else +$II $var = in.readString(${var} instanceof Utf8 ? (Utf8)${var} : null); +#end +#end + +#macro( decodeArray $indent $var $s $rs ) +#set ($I = $this.indent($indent)) +#set ($t = $this.javaType($s)) +#set ($et = $this.javaType($s.ElementType)) +#set ($gat = "SpecificData.Array<${et}>") +$I long size${nv} = in.readArrayStart(); +## Need fresh variable name due to limitation of macro system +$I $t a${nv} = ${var}; +$I if (a${nv} == null) { +$I a${nv} = new ${gat}((int)size${nv}, ${rs}); +$I $var = a${nv}; +$I } else a${nv}.clear(); +$I $gat ga${nv} = (a${nv} instanceof SpecificData.Array ? (${gat})a${nv} : null); +$I for ( ; 0 < size${nv}; size${nv} = in.arrayNext()) { +$I for ( ; size${nv} != 0; size${nv}--) { +$I $et e${nv} = (ga${nv} != null ? ga${nv}.peek() : null); +#set ($var = "e${nv}") +#set ($nv = $nv + 1) +#set ($maxnv = $nv) +#set ($indent = $indent + 4) +#decodeVar($indent $var $s.ElementType "${rs}.getElementType()") +#set ($nv = $nv - 1) +#set ($indent = $indent - 4) +#set ($I = $this.indent($indent)) +$I a${nv}.add(e${nv}); +$I } +$I } +#end + +#macro( decodeMap $indent $var $s $rs ) +#set ($I = $this.indent($indent)) +#set ($t = $this.javaType($s)) +#set ($kt = $this.getStringType($s)) +#set ($vt = $this.javaType($s.ValueType)) +$I long size${nv} = in.readMapStart(); +$I $t m${nv} = ${var}; // Need fresh name due to limitation of macro system +$I if (m${nv} == null) { +$I m${nv} = new java.util.HashMap<${kt},${vt}>((int)size${nv}); +$I $var = m${nv}; +$I } else m${nv}.clear(); +$I for ( ; 0 < size${nv}; size${nv} = in.mapNext()) { +$I for ( ; size${nv} != 0; size${nv}--) { +$I $kt k${nv} = null; +#decodeString( "$I " "k${nv}" $s ) +$I $vt v${nv} = null; +#set ($var = "v${nv}") +#set ($nv = $nv + 1) +#set ($maxnv = $nv) +#set ($indent = $indent + 4) +#decodeVar($indent $var $s.ValueType "${rs}.getValueType()") +#set ($nv = $nv - 1) +#set ($indent = $indent - 4) +#set ($I = $this.indent($indent)) +$I m${nv}.put(k${nv}, v${nv}); +$I } +$I } +#end + +#macro( decodeUnion $indent $var $s $rs ) +#set ($I = $this.indent($indent)) +#set ($et = $this.javaType($s.Types.get($this.getNonNullIndex($s)))) +#set ($si = $this.getNonNullIndex($s)) +$I if (in.readIndex() != ${si}) { +$I in.readNull(); +$I ${var} = null; +$I } else { +#set ($indent = $indent + 2) +#decodeVar($indent $var $s.Types.get($si) "${rs}.getTypes().get(${si})") +#set ($indent = $indent - 2) +#set ($I = $this.indent($indent)) +$I } +#end From 8e2ac1a4692fd95ec94a4a42e858107ceada2e3c Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 16 Sep 2022 22:15:35 -0400 Subject: [PATCH 453/479] Update changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 46738d73216..b8943a29a93 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Added support for `additionalVelocityTool` thanks to a contribution from [dcracauer](https://github.com/dcracauer); see https://github.com/davidmc24/gradle-avro-plugin/pull/211 ## 1.4.0 * Drop support for Kotlin plugin integration From 7ad29b17686edb5ba3c279e4d6486f9890d97257 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 16 Sep 2022 22:37:54 -0400 Subject: [PATCH 454/479] Update versions of Gradle/Avro/Java --- .github/workflows/avro-compatibility.yml | 2 +- .github/workflows/gradle-compatibility.yml | 7 ++--- .github/workflows/java-compatibility.yml | 33 ++++++++++++++++----- CHANGES.md | 4 +++ README.md | 13 ++++---- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 60756 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 6 ++++ gradlew.bat | 14 +++++---- 10 files changed, 56 insertions(+), 27 deletions(-) diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index 0dd38dee374..e078177e0b8 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -6,7 +6,7 @@ jobs: runs-on: "ubuntu-latest" strategy: matrix: - avro: ["1.11.0"] + avro: ["1.11.0", "1.11.1"] gradle: ["5.1", "7.3"] java: ["8"] steps: diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index a00a1c179ca..388d67c4d20 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -9,10 +9,9 @@ jobs: avro: ["1.11.0"] gradle: [ "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", - "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", - "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", - "6.7", "6.7.1", "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", "6.9.1", - "7.0", "7.0.1", "7.0.2", "7.1", "7.1.1", "7.2", "7.3" + "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", "6.7", "6.7.1", + "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", "6.9.1", "6.9.2", + "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" # See here for latest versions: https://services.gradle.org/versions/ ] java: ["8", "11"] diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 6b14431e8d7..2993dc864b3 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["5.1", "7.3"] + gradle: ["5.1", "7.5.1"] java: ["8", "9", "10", "11", "12"] steps: - uses: actions/checkout@v2 @@ -25,7 +25,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["6.0", "7.3"] + gradle: ["6.0", "7.5.1"] java: ["13"] steps: - uses: actions/checkout@v2 @@ -42,7 +42,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["6.3", "7.3"] + gradle: ["6.3", "7.5.1"] java: ["14"] steps: - uses: actions/checkout@v2 @@ -59,7 +59,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["6.7", "7.3"] + gradle: ["6.7", "7.5.1"] java: ["15"] steps: - uses: actions/checkout@v2 @@ -76,7 +76,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["7.0", "7.3"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.0", "7.5.1"] # See here for latest versions: https://services.gradle.org/versions/ java: ["16"] steps: - uses: actions/checkout@v2 @@ -93,7 +93,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["7.3"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.3", "7.5.1"] # See here for latest versions: https://services.gradle.org/versions/ java: ["17"] steps: - uses: actions/checkout@v2 @@ -104,14 +104,31 @@ jobs: - uses: gradle/gradle-build-action@v2 with: arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + java18: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.11.0"] + gradle: ["7.5", "7.5.1"] # See here for latest versions: https://services.gradle.org/versions/ + java: ["18"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java }} + - uses: gradle/gradle-build-action@v2 + with: + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} java-ea: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: avro: ["1.11.0"] - gradle: ["7.3"] # See here for latest versions: https://services.gradle.org/versions/ - java: ["18-ea"] + gradle: ["7.5.1"] # See here for latest versions: https://services.gradle.org/versions/ + java: ["19-ea"] fail-fast: false steps: - uses: actions/checkout@v2 diff --git a/CHANGES.md b/CHANGES.md index b8943a29a93..43ec60c12f9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,10 @@ ## Unreleased * Added support for `additionalVelocityTool` thanks to a contribution from [dcracauer](https://github.com/dcracauer); see https://github.com/davidmc24/gradle-avro-plugin/pull/211 +* Built using Avro 1.11.1 +* Built using Gradle 7.5.1 +* Updated compatibility testing through Gradle 7.5.1 +* Updated compatibility testing through Java 18 ## 1.4.0 * Drop support for Kotlin plugin integration diff --git a/README.md b/README.md index 04897cb3292..f7269e59182 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,19 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav **NOTE**: Pre-1.0 versions used a different publishing process/namespace. It is strongly recommended to upgrade to a newer version. Further details can be found in the [change log](CHANGES.md). -* Currently tested against Java 8-16 - * Though not supported yet, tests are also run against Java 18 to provide early notification of potential incompatibilities. +* Currently tested against Java 8-18 + * Though not supported yet, tests are also run against Java 19 to provide early notification of potential incompatibilities. + * Java 18 support requires Gradle 7.5 or higher (as per Gradle's release notes) * Java 17 support requires Gradle 7.3 or higher (as per Gradle's release notes) * Java 16 support requires Gradle 7.0 or higher (as per Gradle's release notes) * Java 15 support requires Gradle 6.7 or higher (as per Gradle's release notes) * Java 14 support requires Gradle 6.3 or higher (as per Gradle's release notes) * Java 13 support requires Gradle 6.0 or higher * Java 8-12 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) -* Currently built against Gradle 7.3 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.3 -* Currently built against Avro 1.11.0 - * Currently tested against Avro 1.11.0 +* Currently built against Gradle 7.5.1 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.5.1 +* Currently built against Avro 1.11.1 + * Currently tested against Avro 1.11.0-1.11.1 * Avro 1.9.0-1.10.2 were last supported in version 1.2.1 * Support for Kotlin * Dropped integration with the Kotlin plugin in plugin version 1.4.0, as Kotlin 1.7.x would require compile-time dependency on a specific Kotlin version diff --git a/build.gradle b/build.gradle index 9574a69cd5a..e6cc7720452 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ repositories { } } -def compileAvroVersion = "1.11.0" +def compileAvroVersion = "1.11.1" // Write the plugin's classpath to a file to share with the tests task createClasspathManifest { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..249e5832f090a2944b7473328c07c9755baa3196 100644 GIT binary patch delta 10158 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 delta 9041 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102e092..ae04661ee73 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.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787337f..a69d9cb6c20 100755 --- a/gradlew +++ b/gradlew @@ -205,6 +205,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd32c4e..f127cfd49d4 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal From 9e8c9affae88fb36f8e2d0583262f09d6801720f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 19 Sep 2022 11:30:51 -0400 Subject: [PATCH 455/479] version: 1.5.0 --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 43ec60c12f9..72403b03bb4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 1.5.0 * Added support for `additionalVelocityTool` thanks to a contribution from [dcracauer](https://github.com/dcracauer); see https://github.com/davidmc24/gradle-avro-plugin/pull/211 * Built using Avro 1.11.1 * Built using Gradle 7.5.1 diff --git a/build.gradle b/build.gradle index e6cc7720452..971073bd7ba 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.4.1-SNAPSHOT" +version = "1.5.0" def isCI = System.getenv("CI") == "true" From 9b81a23af71ccdc9df0ed3e2a46ca9837c0bd110 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 19 Sep 2022 11:33:25 -0400 Subject: [PATCH 456/479] version: 1.5.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 971073bd7ba..b27902907b8 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.5.0" +version = "1.5.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" From 5a7e497225bdd3bccad2f9f537875664b994cb9d Mon Sep 17 00:00:00 2001 From: Paul Kofmann Date: Mon, 30 Jan 2023 15:56:46 +0100 Subject: [PATCH 457/479] Support specifying classpath for additional velocity tool classes --- .../plugin/avro/GenerateAvroJavaTask.java | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java index 6415f092726..878a4acbc7d 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -18,11 +18,11 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; import java.nio.charset.Charset; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import javax.inject.Inject; import org.apache.avro.Conversion; @@ -42,10 +42,8 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.specs.NotSpec; -import org.gradle.api.tasks.CacheableTask; -import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.*; import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.TaskAction; /** * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and @@ -54,6 +52,7 @@ @SuppressWarnings("WeakerAccess") @CacheableTask public class GenerateAvroJavaTask extends OutputDirTask { + private FileCollection classpath; private static Set SUPPORTED_EXTENSIONS = new SetBuilder().add(Constants.PROTOCOL_EXTENSION).add(Constants.SCHEMA_EXTENSION).build(); @@ -79,6 +78,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { @Inject public GenerateAvroJavaTask(ObjectFactory objects) { super(); + this.classpath = GradleCompatibility.createConfigurableFileCollection(getProject()); this.outputCharacterEncoding = objects.property(String.class); this.stringType = objects.property(String.class).convention(Constants.DEFAULT_STRING_TYPE); this.fieldVisibility = objects.property(String.class).convention(Constants.DEFAULT_FIELD_VISIBILITY); @@ -103,6 +103,19 @@ public GenerateAvroJavaTask(ObjectFactory objects) { this.resolver = new SchemaResolver(projectLayout, getLogger()); } + public void setClasspath(FileCollection classpath) { + this.classpath = classpath; + } + + public void classpath(Object... paths) { + this.classpath.plus(getProject().files(paths)); + } + + @Classpath + public FileCollection getClasspath() { + return this.classpath; + } + @Optional @Input public Property getOutputCharacterEncoding() { @@ -340,10 +353,11 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept compiler.setTemplateDir(getTemplateDirectory().get()); } if (getAdditionalVelocityToolClasses().isPresent()) { + ClassLoader loader = assembleClassLoader(); List tools = getAdditionalVelocityToolClasses().get().stream() .map(s -> { try { - return Class.forName(s); + return Class.forName(s, true, loader); } catch (ClassNotFoundException e) { throw new RuntimeException("unable to load velocity tool class " + s, e); } @@ -394,4 +408,17 @@ private void registerLogicalTypes() { private void registerCustomConversions(SpecificCompiler compiler) { customConversions.get().forEach(compiler::addCustomConversion); } + + private ClassLoader assembleClassLoader() { + getLogger().debug("Using additional classpath: {}", classpath.getFiles()); + List urls = new LinkedList<>(); + for (File file : classpath) { + try { + urls.add(file.toURI().toURL()); + } catch (MalformedURLException e) { + getLogger().debug(e.getMessage()); + } + } + return new URLClassLoader(urls.toArray(new URL[0]), Thread.currentThread().getContextClassLoader()); + } } From e4f1ede99f714808eb5998b1410857dc849258b5 Mon Sep 17 00:00:00 2001 From: Paul Kofmann Date: Tue, 31 Jan 2023 10:25:39 +0100 Subject: [PATCH 458/479] Add test for classpath property in GenerateAvroJavaTask --- .../avro/AvroBasePluginFunctionalSpec.groovy | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy index f6b44afadde..e726893e557 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy @@ -15,6 +15,9 @@ */ package com.github.davidmc24.gradle.plugin.avro +import com.github.davidmc24.gradle.plugin.avro.test.custom.CommentGenerator +import com.github.davidmc24.gradle.plugin.avro.test.custom.TimestampGenerator + import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class AvroBasePluginFunctionalSpec extends FunctionalSpec { @@ -125,4 +128,50 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { projectFile("build/generated-main-avro-avsc/org/apache/avro/Node.avsc").file projectFile("build/generated-main-avro-avsc/org/apache/avro/Interop.avsc").file } + + def "supports classpath property for instantiating of velocity tools"() { + given: + copyAvroTools("src/main/java") + def templatesDir = projectFolder("templates") + copyResource("user.avsc", avroDir) + copyResource("record-tools.vm", templatesDir, "record.vm") + applyPlugin("java") + buildFile << """ + |avro { + | templateDirectory = "${templatesDir.toString()}/" + | additionalVelocityToolClasses = ['com.github.davidmc24.gradle.plugin.avro.test.custom.TimestampGenerator', + | 'com.github.davidmc24.gradle.plugin.avro.test.custom.CommentGenerator'] + |} + |tasks.register("compileTools", JavaCompile) { + | source = sourceSets.main.java + | classpath = sourceSets.main.compileClasspath + | destinationDir = file("build/classes/java/main") + |} + |tasks.register("generateAvro", com.github.davidmc24.gradle.plugin.avro.GenerateAvroJavaTask) { + | dependsOn compileTools + | classpath = files("build/classes/java/main") + | source file("src/main/avro") + | include("**/*.avsc") + | outputDir = file("build/generated-main-avro-java") + |} + |""".stripMargin() + + when: + def result = run("generateAvro") + + then: "the task succeeds" + result.task(":generateAvro").outcome == SUCCESS + def content = projectFile("build/generated-main-avro-java/example/avro/User.java").text + + and: "the velocity tools have been applied" + content.contains(CommentGenerator.CUSTOM_COMMENT) + content.contains(TimestampGenerator.MESSAGE_PREFIX) + } + + private void copyAvroTools(String destDir) { + copyFile("src/test/java", destDir, + "com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java") + copyFile("src/test/java", destDir, + "com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java") + } } From 19478029f469d03bd78600117d97501bec2672fe Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Tue, 31 Jan 2023 09:27:18 -0500 Subject: [PATCH 459/479] Minor cleanup --- CONTRIBUTING.md | 2 +- .../plugin/avro/GenerateAvroJavaTask.java | 23 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca5fceac861..96b183f23e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ All enhancements should be accompanied by test coverage. Our tests are based on [Spock](https://github.com/spockframework/spock). Generally, it's best to extend our `FunctionalSpec` class, which provides useful functions for running the plugin within Gradle. -Note that the "build" task only tests the plugin against the a single version of Gradle/Avro. +Note that the "build" task only tests the plugin against a single version of Gradle/Avro. If you want to test compatibility with a larger range, consider using the `testRecentVersionCompatibility` task or `testVersionCompatibility` task. For information on how to use GitHub to submit a pull request, see [Collaborating on projects using issues and pull requests](https://help.github.com/categories/collaborating-on-projects-using-issues-and-pull-requests/). diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java index 878a4acbc7d..63cd0acd355 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -22,7 +22,11 @@ import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.Charset; -import java.util.*; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; import org.apache.avro.Conversion; @@ -42,8 +46,11 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.specs.NotSpec; -import org.gradle.api.tasks.*; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.TaskAction; /** * Task to generate Java source files based on Avro protocol files and Avro schema files using {@link Protocol} and @@ -52,7 +59,6 @@ @SuppressWarnings("WeakerAccess") @CacheableTask public class GenerateAvroJavaTask extends OutputDirTask { - private FileCollection classpath; private static Set SUPPORTED_EXTENSIONS = new SetBuilder().add(Constants.PROTOCOL_EXTENSION).add(Constants.SCHEMA_EXTENSION).build(); @@ -66,6 +72,7 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Property optionalGettersForNullableFieldsOnly; private final Property createSetters; private final Property enableDecimalLogicalType; + private FileCollection classpath; private final MapProperty> logicalTypeFactories; private final ListProperty>> customConversions; @@ -78,7 +85,6 @@ public class GenerateAvroJavaTask extends OutputDirTask { @Inject public GenerateAvroJavaTask(ObjectFactory objects) { super(); - this.classpath = GradleCompatibility.createConfigurableFileCollection(getProject()); this.outputCharacterEncoding = objects.property(String.class); this.stringType = objects.property(String.class).convention(Constants.DEFAULT_STRING_TYPE); this.fieldVisibility = objects.property(String.class).convention(Constants.DEFAULT_FIELD_VISIBILITY); @@ -91,14 +97,15 @@ public GenerateAvroJavaTask(ObjectFactory objects) { .convention(Constants.DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY); this.createSetters = objects.property(Boolean.class).convention(Constants.DEFAULT_CREATE_SETTERS); this.enableDecimalLogicalType = objects.property(Boolean.class).convention(Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); - this.stringTypeProvider = getStringType() - .map(input -> Enums.parseCaseInsensitive(Constants.OPTION_STRING_TYPE, StringType.values(), input)); - this.fieldVisibilityProvider = getFieldVisibility() - .map(input -> Enums.parseCaseInsensitive(Constants.OPTION_FIELD_VISIBILITY, FieldVisibility.values(), input)); + this.classpath = GradleCompatibility.createConfigurableFileCollection(getProject()); this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) .convention(Constants.DEFAULT_LOGICAL_TYPE_FACTORIES); this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(Constants.DEFAULT_CUSTOM_CONVERSIONS); + this.stringTypeProvider = getStringType() + .map(input -> Enums.parseCaseInsensitive(Constants.OPTION_STRING_TYPE, StringType.values(), input)); + this.fieldVisibilityProvider = getFieldVisibility() + .map(input -> Enums.parseCaseInsensitive(Constants.OPTION_FIELD_VISIBILITY, FieldVisibility.values(), input)); this.projectLayout = getProject().getLayout(); this.resolver = new SchemaResolver(projectLayout, getLogger()); } From e778f213c3913738c223ea2e934e4ae354f7ff27 Mon Sep 17 00:00:00 2001 From: Paul Kofmann Date: Wed, 1 Feb 2023 12:50:43 +0100 Subject: [PATCH 460/479] Fix test: escape backslashes in a Windows path --- .../gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy index e726893e557..241782a0edf 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy @@ -138,7 +138,7 @@ class AvroBasePluginFunctionalSpec extends FunctionalSpec { applyPlugin("java") buildFile << """ |avro { - | templateDirectory = "${templatesDir.toString()}/" + | templateDirectory = "${templatesDir.toString().replace('\\', '\\\\')}/" | additionalVelocityToolClasses = ['com.github.davidmc24.gradle.plugin.avro.test.custom.TimestampGenerator', | 'com.github.davidmc24.gradle.plugin.avro.test.custom.CommentGenerator'] |} From b18c0fd71feb90f52737f06a4ffe33db711e53bb Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 3 Feb 2023 10:48:38 -0500 Subject: [PATCH 461/479] Drop Java compatibility testing for outdated versions --- .github/workflows/java-compatibility.yml | 70 +----------------------- CHANGES.md | 1 + README.md | 2 +- 3 files changed, 3 insertions(+), 70 deletions(-) diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 2993dc864b3..c6af9e64908 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -9,75 +9,7 @@ jobs: matrix: avro: ["1.11.0"] gradle: ["5.1", "7.5.1"] - java: ["8", "9", "10", "11", "12"] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - java13: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] - gradle: ["6.0", "7.5.1"] - java: ["13"] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - java14: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] - gradle: ["6.3", "7.5.1"] - java: ["14"] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - java15: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] - gradle: ["6.7", "7.5.1"] - java: ["15"] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "zulu" - java-version: ${{ matrix.java }} - - uses: gradle/gradle-build-action@v2 - with: - arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} - java16: - name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" - runs-on: "ubuntu-latest" - strategy: - matrix: - avro: ["1.11.0"] - gradle: ["7.0", "7.5.1"] # See here for latest versions: https://services.gradle.org/versions/ - java: ["16"] + java: ["8", "11"] steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v2 diff --git a/CHANGES.md b/CHANGES.md index 72403b03bb4..cedc341c021 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Drop compatibility testing for old versions of Java (9, 10, 12, 13, 14, 15, 16) ## 1.5.0 * Added support for `additionalVelocityTool` thanks to a contribution from [dcracauer](https://github.com/dcracauer); see https://github.com/davidmc24/gradle-avro-plugin/pull/211 diff --git a/README.md b/README.md index f7269e59182..b1d56093b78 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav **NOTE**: Pre-1.0 versions used a different publishing process/namespace. It is strongly recommended to upgrade to a newer version. Further details can be found in the [change log](CHANGES.md). -* Currently tested against Java 8-18 +* Currently tested against Java 8, 11, and 17-18 * Though not supported yet, tests are also run against Java 19 to provide early notification of potential incompatibilities. * Java 18 support requires Gradle 7.5 or higher (as per Gradle's release notes) * Java 17 support requires Gradle 7.3 or higher (as per Gradle's release notes) From e8f7ee71b9da07f8a7d412597586a1ac20307ff0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 3 Feb 2023 11:17:52 -0500 Subject: [PATCH 462/479] Update for Gradle 7.6 and Java 19 --- .github/workflows/avro-compatibility.yml | 2 +- .github/workflows/gradle-compatibility.yml | 4 +-- .github/workflows/java-compatibility.yml | 28 ++++++++++++++---- CHANGES.md | 3 ++ README.md | 9 +++--- gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 61574 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 12 +++++--- gradlew.bat | 1 + .../gradle/plugin/avro/AvroPlugin.java | 8 ++--- 10 files changed, 48 insertions(+), 22 deletions(-) diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index e078177e0b8..31816f81a2e 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: avro: ["1.11.0", "1.11.1"] - gradle: ["5.1", "7.3"] + gradle: ["5.1", "7.6"] java: ["8"] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index 388d67c4d20..22c3c30d245 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -10,8 +10,8 @@ jobs: gradle: [ "5.1", "5.1.1", "5.2", "5.2.1", "5.3", "5.3.1", "5.4", "5.4.1", "5.5", "5.5.1", "5.6", "5.6.1", "5.6.2", "5.6.3", "5.6.4", "6.0", "6.0.1", "6.1", "6.1.1", "6.2", "6.2.1", "6.2.2", "6.3", "6.4", "6.4.1", "6.5", "6.5.1", "6.6", "6.6.1", "6.7", "6.7.1", - "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", "6.9.1", "6.9.2", - "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" + "6.8", "6.8.1", "6.8.2", "6.8.3", "6.9", "6.9.1", "6.9.2", "6.9.3", + "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" # See here for latest versions: https://services.gradle.org/versions/ ] java: ["8", "11"] diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index c6af9e64908..5c65375d71a 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["5.1", "7.5.1"] + gradle: ["5.1", "7.6"] java: ["8", "11"] steps: - uses: actions/checkout@v2 @@ -25,7 +25,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["7.3", "7.5.1"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.3", "7.6"] # See here for latest versions: https://services.gradle.org/versions/ java: ["17"] steps: - uses: actions/checkout@v2 @@ -42,7 +42,7 @@ jobs: strategy: matrix: avro: ["1.11.0"] - gradle: ["7.5", "7.5.1"] # See here for latest versions: https://services.gradle.org/versions/ + gradle: ["7.5", "7.6"] # See here for latest versions: https://services.gradle.org/versions/ java: ["18"] steps: - uses: actions/checkout@v2 @@ -53,14 +53,32 @@ jobs: - uses: gradle/gradle-build-action@v2 with: arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} + java-19: + name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" + runs-on: "ubuntu-latest" + strategy: + matrix: + avro: ["1.11.0"] + gradle: ["7.6"] # See here for latest versions: https://services.gradle.org/versions/ + java: ["19"] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java }} + - uses: gradle/gradle-build-action@v2 + continue-on-error: true + with: + arguments: testCompatibility -PavroVersion=${{ matrix.avro }} -PgradleVersion=${{ matrix.gradle }} java-ea: name: "Compatibility: java ${{ matrix.java }}/gradle ${{ matrix.gradle }}" runs-on: "ubuntu-latest" strategy: matrix: avro: ["1.11.0"] - gradle: ["7.5.1"] # See here for latest versions: https://services.gradle.org/versions/ - java: ["19-ea"] + gradle: ["7.6"] # See here for latest versions: https://services.gradle.org/versions/ + java: ["20-ea"] fail-fast: false steps: - uses: actions/checkout@v2 diff --git a/CHANGES.md b/CHANGES.md index cedc341c021..d45d82c3a94 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,9 @@ ## Unreleased * Drop compatibility testing for old versions of Java (9, 10, 12, 13, 14, 15, 16) +* Built using Gradle 7.6 +* Updated compatibility testing through Gradle 7.6 +* Updated compatibility testing through Java 19 ## 1.5.0 * Added support for `additionalVelocityTool` thanks to a contribution from [dcracauer](https://github.com/dcracauer); see https://github.com/davidmc24/gradle-avro-plugin/pull/211 diff --git a/README.md b/README.md index b1d56093b78..fff20983eba 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,9 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav **NOTE**: Pre-1.0 versions used a different publishing process/namespace. It is strongly recommended to upgrade to a newer version. Further details can be found in the [change log](CHANGES.md). -* Currently tested against Java 8, 11, and 17-18 - * Though not supported yet, tests are also run against Java 19 to provide early notification of potential incompatibilities. +* Currently tested against Java 8, 11, and 17-19 + * Though not supported yet, tests are also run against Java 20 to provide early notification of potential incompatibilities. + * Java 19 support requires Gradle 7.6 or higher (as per Gradle's release notes) * Java 18 support requires Gradle 7.5 or higher (as per Gradle's release notes) * Java 17 support requires Gradle 7.3 or higher (as per Gradle's release notes) * Java 16 support requires Gradle 7.0 or higher (as per Gradle's release notes) @@ -23,8 +24,8 @@ This is a [Gradle](http://www.gradle.org/) plugin to allow easily performing Jav * Java 14 support requires Gradle 6.3 or higher (as per Gradle's release notes) * Java 13 support requires Gradle 6.0 or higher * Java 8-12 support requires Gradle 5.1 or higher (versions lower than 5.1 are no longer supported) -* Currently built against Gradle 7.5.1 - * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.5.1 +* Currently built against Gradle 7.6 + * Currently tested against Gradle 5.1-5.6.4 and 6.0-7.6 * Currently built against Avro 1.11.1 * Currently tested against Avro 1.11.0-1.11.1 * Avro 1.9.0-1.10.2 were last supported in version 1.2.1 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..943f0cbfa754578e88a3dae77fce6e3dea56edbf 100644 GIT binary patch delta 36524 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%0DGK?7GHTj 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 VwlMN}`%er%aGR6olj~j${vQ;P=LY}) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661ee73..f398c33c4b0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a69d9cb6c20..65dcd68d65c 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,10 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' @@ -143,12 +143,16 @@ fi if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac diff --git a/gradlew.bat b/gradlew.bat index f127cfd49d4..93e3f59f135 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java index 1aace73051b..3261a6df657 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java @@ -62,11 +62,9 @@ private static void configureIntelliJ(final Project project) { .add(getAvroSourceDir(project, mainSourceSet)) .add(getGeneratedOutputDir(project, mainSourceSet, Constants.JAVA_EXTENSION).map(Directory::getAsFile).get()) .build()); - module.setTestSourceDirs(new SetBuilder() - .addAll(module.getTestSourceDirs()) - .add(getAvroSourceDir(project, testSourceSet)) - .add(getGeneratedOutputDir(project, testSourceSet, Constants.JAVA_EXTENSION).map(Directory::getAsFile).get()) - .build()); + module.getTestSources() + .from(getAvroSourceDir(project, testSourceSet)) + .from(getGeneratedOutputDir(project, testSourceSet, Constants.JAVA_EXTENSION).map(Directory::getAsFile).get()); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. SetBuilder excludeDirs = new SetBuilder<>(); From f1d84f789b2abc806a78e23dffb6eec4ba1ff7c0 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Fri, 3 Feb 2023 11:56:44 -0500 Subject: [PATCH 463/479] Fix up cross-version compatibility for the Gradle 7.6 adjustments --- .../gradle/plugin/avro/AvroPlugin.java | 7 +++--- .../plugin/avro/GradleCompatibility.java | 22 +++++++++++++++++++ .../gradle/plugin/avro/GradleFeatures.java | 6 +++++ .../gradle/plugin/avro/GradleVersions.java | 1 + 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java index 3261a6df657..bc288e24864 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java @@ -62,9 +62,10 @@ private static void configureIntelliJ(final Project project) { .add(getAvroSourceDir(project, mainSourceSet)) .add(getGeneratedOutputDir(project, mainSourceSet, Constants.JAVA_EXTENSION).map(Directory::getAsFile).get()) .build()); - module.getTestSources() - .from(getAvroSourceDir(project, testSourceSet)) - .from(getGeneratedOutputDir(project, testSourceSet, Constants.JAVA_EXTENSION).map(Directory::getAsFile).get()); + GradleCompatibility.addTestSources(module, + getAvroSourceDir(project, testSourceSet), + getGeneratedOutputDir(project, testSourceSet, Constants.JAVA_EXTENSION).map(Directory::getAsFile).get() + ); // IntelliJ doesn't allow source directories beneath an excluded directory. // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes. SetBuilder excludeDirs = new SetBuilder<>(); diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java index 01a46e9012e..57c1f00d9da 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java @@ -16,13 +16,18 @@ package com.github.davidmc24.gradle.plugin.avro; +import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.tasks.SourceSet; +import org.gradle.plugins.ide.idea.model.IdeaModule; class GradleCompatibility { + private static final Class[] NO_PARAMETERS = {}; + private static final Object[] NO_ARGUMENTS = {}; + static T createExtensionWithObjectFactory(Project project, String extensionName, Class extensionType) { if (GradleFeatures.extensionInjection.isSupported()) { return project.getExtensions().create(extensionName, extensionType); @@ -50,6 +55,23 @@ static String getSourcesJarTaskName(SourceSet sourceSet) { } } + @SuppressWarnings("deprecation") + static void addTestSources(IdeaModule module, File... files) { + if (GradleFeatures.ideaModuleTestSources.isSupported()) { + // Can't use these methods directly as they didn't exist until 7.4 + Object testSources = invokeMethod(module, "getTestSources", NO_PARAMETERS, NO_ARGUMENTS); + Class[] parameterTypes = {Object[].class}; + Object[] args = {files}; + invokeMethod(testSources, "from", parameterTypes, args); + } else { + // Deprecated in 7.6 + module.setTestSourceDirs(new SetBuilder() + .addAll(module.getTestSourceDirs()) + .addAll(files) + .build()); + } + } + @SuppressWarnings("unchecked") private static T invokeMethod(Object object, String methodName, Class[] parameterTypes, Object[] args) { try { diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java index 27aba95ec0f..180f771bfa9 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java @@ -42,6 +42,12 @@ boolean isSupportedBy(GradleVersion version) { boolean isSupportedBy(GradleVersion version) { return version.compareTo(GradleVersions.v6_0) >= 0; } + }, + ideaModuleTestSources() { + @Override + boolean isSupportedBy(GradleVersion version) { + return version.compareTo(GradleVersions.v7_4) >= 0; + } }; abstract boolean isSupportedBy(GradleVersion version); diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java index 1a7573555f1..ba6ff9f8481 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java @@ -23,4 +23,5 @@ class GradleVersions { static final GradleVersion v5_3 = GradleVersion.version("5.3"); static final GradleVersion v6_0 = GradleVersion.version("6.0"); static final GradleVersion v6_6 = GradleVersion.version("6.6"); + static final GradleVersion v7_4 = GradleVersion.version("7.4"); } From 96cffb38e3ba04a645e4dea4a38dde146949ea88 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 6 Feb 2023 09:40:16 -0500 Subject: [PATCH 464/479] Update changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index d45d82c3a94..11349409fc5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Add support for configuring classpath for `GenerateAvroJavaTask` (thanks to [crtlib](https://github.com/crtlib)); see https://github.com/davidmc24/gradle-avro-plugin/pull/222 * Drop compatibility testing for old versions of Java (9, 10, 12, 13, 14, 15, 16) * Built using Gradle 7.6 * Updated compatibility testing through Gradle 7.6 From 05e1a8b2a832d5c9699750a7ec9d2040543ad03d Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 6 Feb 2023 09:41:05 -0500 Subject: [PATCH 465/479] version: 1.6.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b27902907b8..36857884a84 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.5.1-SNAPSHOT" +version = "1.6.0" def isCI = System.getenv("CI") == "true" From af1134c896e8ee44c2560a32ab561f9169b724c4 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 6 Feb 2023 09:46:19 -0500 Subject: [PATCH 466/479] version: 1.6.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 36857884a84..a3603354bc4 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.6.0" +version = "1.6.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" From cc62833c5295d438655bf98f7fbfe14a5c120dc3 Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Mon, 6 Feb 2023 09:48:07 -0500 Subject: [PATCH 467/479] Update changelog --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 11349409fc5..e934aa11f3a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 1.6.0 * Add support for configuring classpath for `GenerateAvroJavaTask` (thanks to [crtlib](https://github.com/crtlib)); see https://github.com/davidmc24/gradle-avro-plugin/pull/222 * Drop compatibility testing for old versions of Java (9, 10, 12, 13, 14, 15, 16) * Built using Gradle 7.6 From c1651198e0f795fee7b79133f23eac32037e92fe Mon Sep 17 00:00:00 2001 From: Marcin Erdmann Date: Tue, 4 Apr 2023 13:43:16 +0100 Subject: [PATCH 468/479] Add ability to use conversions and type factories residing outside of build classpath --- .../gradle/plugin/avro/AvroBasePlugin.java | 3 + .../gradle/plugin/avro/AvroExtension.java | 6 ++ .../gradle/plugin/avro/Constants.java | 2 + .../plugin/avro/DefaultAvroExtension.java | 56 +++++++++- .../plugin/avro/GenerateAvroJavaTask.java | 101 +++++++++++++++++- .../plugin/avro/GradleCompatibility.java | 2 +- .../CustomConversionFunctionalSpec.groovy | 49 +++++++++ 7 files changed, 216 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java index 037d1d47518..9e3b9b1d45b 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java @@ -38,8 +38,11 @@ private static void configureExtension(final Project project) { task.isGettersReturnOptional().convention(avroExtension.isGettersReturnOptional()); task.isOptionalGettersForNullableFieldsOnly().convention(avroExtension.isOptionalGettersForNullableFieldsOnly()); task.isEnableDecimalLogicalType().convention(avroExtension.isEnableDecimalLogicalType()); + task.getConversionsAndTypeFactoriesClasspath().from(avroExtension.getConversionsAndTypeFactoriesClasspath()); task.getLogicalTypeFactories().convention(avroExtension.getLogicalTypeFactories()); + task.getLogicalTypeFactoryClassNames().convention(avroExtension.getLogicalTypeFactoryClassNames()); task.getCustomConversions().convention(avroExtension.getCustomConversions()); + task.getCustomConversionClassNames().convention(avroExtension.getCustomConversionClassNames()); }); } } diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java index 87dc144e0ee..1d64cbee214 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java @@ -17,6 +17,7 @@ import org.apache.avro.Conversion; import org.apache.avro.LogicalTypes; +import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; @@ -33,8 +34,13 @@ public interface AvroExtension { Property isGettersReturnOptional(); Property isOptionalGettersForNullableFieldsOnly(); Property isEnableDecimalLogicalType(); + ConfigurableFileCollection getConversionsAndTypeFactoriesClasspath(); MapProperty> getLogicalTypeFactories(); + MapProperty getLogicalTypeFactoryClassNames(); ListProperty>> getCustomConversions(); + ListProperty getCustomConversionClassNames(); AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass); + AvroExtension logicalTypeFactory(String typeName, String typeFactoryClassName); AvroExtension customConversion(Class> conversionClass); + AvroExtension customConversion(String conversionClassName); } diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java index 117b4a51161..919ec35326a 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java @@ -41,7 +41,9 @@ class Constants { static final boolean DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY = false; static final boolean DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE = true; static final Map> DEFAULT_LOGICAL_TYPE_FACTORIES = Collections.emptyMap(); + static final Map DEFAULT_LOGICAL_TYPE_FACTORY_CLASS_NAMES = Collections.emptyMap(); static final List>> DEFAULT_CUSTOM_CONVERSIONS = Collections.emptyList(); + static final List DEFAULT_CUSTOM_CONVERSION_CLASS_NAMES = Collections.emptyList(); static final String SCHEMA_EXTENSION = "avsc"; static final String PROTOCOL_EXTENSION = "avpr"; diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java index aabd713eacf..3b0478b2f2d 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java @@ -24,6 +24,8 @@ import org.apache.avro.LogicalTypes; import org.apache.avro.compiler.specific.SpecificCompiler; import org.apache.avro.generic.GenericData; +import org.gradle.api.Project; +import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.MapProperty; @@ -44,11 +46,14 @@ public class DefaultAvroExtension implements AvroExtension { private final Property gettersReturnOptional; private final Property optionalGettersForNullableFieldsOnly; private final Property enableDecimalLogicalType; + private final ConfigurableFileCollection conversionsAndTypeFactoriesClasspath; private final MapProperty> logicalTypeFactories; + private final MapProperty logicalTypeFactoryClassNames; private final ListProperty>> customConversions; + private final ListProperty customConversionClassNames; @Inject - public DefaultAvroExtension(ObjectFactory objects) { + public DefaultAvroExtension(Project project, ObjectFactory objects) { this.outputCharacterEncoding = objects.property(String.class); this.stringType = objects.property(String.class).convention(Constants.DEFAULT_STRING_TYPE); this.fieldVisibility = objects.property(String.class).convention(Constants.DEFAULT_FIELD_VISIBILITY); @@ -61,10 +66,15 @@ public DefaultAvroExtension(ObjectFactory objects) { this.optionalGettersForNullableFieldsOnly = objects.property(Boolean.class) .convention(Constants.DEFAULT_OPTIONAL_GETTERS_FOR_NULLABLE_FIELDS_ONLY); this.enableDecimalLogicalType = objects.property(Boolean.class).convention(Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); + this.conversionsAndTypeFactoriesClasspath = GradleCompatibility.createConfigurableFileCollection(project); this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) .convention(Constants.DEFAULT_LOGICAL_TYPE_FACTORIES); + this.logicalTypeFactoryClassNames = objects.mapProperty(String.class, String.class) + .convention(Constants.DEFAULT_LOGICAL_TYPE_FACTORY_CLASS_NAMES); this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(Constants.DEFAULT_CUSTOM_CONVERSIONS); + this.customConversionClassNames = + objects.listProperty(String.class).convention(Constants.DEFAULT_CUSTOM_CONVERSION_CLASS_NAMES); } @Override @@ -190,6 +200,11 @@ public void setEnableDecimalLogicalType(boolean enableDecimalLogicalType) { this.enableDecimalLogicalType.set(enableDecimalLogicalType); } + @Override + public ConfigurableFileCollection getConversionsAndTypeFactoriesClasspath() { + return conversionsAndTypeFactoriesClasspath; + } + @Override public MapProperty> getLogicalTypeFactories() { return logicalTypeFactories; @@ -205,6 +220,21 @@ public void setLogicalTypeFactories(Map getLogicalTypeFactoryClassNames() { + return logicalTypeFactoryClassNames; + } + + public void setLogicalTypeFactoryClassNames(Provider> provider) { + this.logicalTypeFactoryClassNames.set(provider); + } + + public void setLogicalTypeFactoryClassNames(Map logicalTypeFactoryClassNames) { + this.logicalTypeFactoryClassNames.set(logicalTypeFactoryClassNames); + } + @Override public ListProperty>> getCustomConversions() { return customConversions; @@ -218,15 +248,39 @@ public void setCustomConversions(Iterable>> custom this.customConversions.set(customConversions); } + public ListProperty getCustomConversionClassNames() { + return customConversionClassNames; + } + + public void setCustomConversionClassNames(Provider> provider) { + this.customConversionClassNames.set(provider); + } + + public void setCustomConversionClassNames(Iterable customConversionClassNames) { + this.customConversionClassNames.set(customConversionClassNames); + } + @Override public AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass) { logicalTypeFactories.put(typeName, typeFactoryClass); return this; } + @Override + public AvroExtension logicalTypeFactory(String typeName, String typeFactoryClassName) { + logicalTypeFactoryClassNames.put(typeName, typeFactoryClassName); + return this; + } + @Override public AvroExtension customConversion(Class> conversionClass) { customConversions.add(conversionClass); return this; } + + @Override + public AvroExtension customConversion(String conversionClassName) { + customConversionClassNames.add(conversionClassName); + return this; + } } diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java index 63cd0acd355..477f718427b 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -23,14 +23,17 @@ import java.net.URLClassLoader; import java.nio.charset.Charset; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; import org.apache.avro.Conversion; import org.apache.avro.LogicalTypes; +import org.apache.avro.LogicalTypes.LogicalTypeFactory; import org.apache.avro.Protocol; import org.apache.avro.Schema; import org.apache.avro.compiler.specific.SpecificCompiler; @@ -38,6 +41,7 @@ import org.apache.avro.generic.GenericData; import org.apache.avro.generic.GenericData.StringType; import org.gradle.api.GradleException; +import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; import org.gradle.api.file.ProjectLayout; import org.gradle.api.model.ObjectFactory; @@ -73,8 +77,11 @@ public class GenerateAvroJavaTask extends OutputDirTask { private final Property createSetters; private final Property enableDecimalLogicalType; private FileCollection classpath; + private final ConfigurableFileCollection conversionsAndTypeFactoriesClasspath; private final MapProperty> logicalTypeFactories; + private final MapProperty logicalTypeFactoryClassNames; private final ListProperty>> customConversions; + private final ListProperty customConversionClassNames; private final Provider stringTypeProvider; private final Provider fieldVisibilityProvider; @@ -98,10 +105,15 @@ public GenerateAvroJavaTask(ObjectFactory objects) { this.createSetters = objects.property(Boolean.class).convention(Constants.DEFAULT_CREATE_SETTERS); this.enableDecimalLogicalType = objects.property(Boolean.class).convention(Constants.DEFAULT_ENABLE_DECIMAL_LOGICAL_TYPE); this.classpath = GradleCompatibility.createConfigurableFileCollection(getProject()); + this.conversionsAndTypeFactoriesClasspath = GradleCompatibility.createConfigurableFileCollection(getProject()); this.logicalTypeFactories = objects.mapProperty(String.class, Constants.LOGICAL_TYPE_FACTORY_TYPE.getConcreteClass()) .convention(Constants.DEFAULT_LOGICAL_TYPE_FACTORIES); + this.logicalTypeFactoryClassNames = objects.mapProperty(String.class, String.class) + .convention(Constants.DEFAULT_LOGICAL_TYPE_FACTORY_CLASS_NAMES); this.customConversions = objects.listProperty(Constants.CONVERSION_TYPE.getConcreteClass()).convention(Constants.DEFAULT_CUSTOM_CONVERSIONS); + this.customConversionClassNames = + objects.listProperty(String.class).convention(Constants.DEFAULT_CUSTOM_CONVERSION_CLASS_NAMES); this.stringTypeProvider = getStringType() .map(input -> Enums.parseCaseInsensitive(Constants.OPTION_STRING_TYPE, StringType.values(), input)); this.fieldVisibilityProvider = getFieldVisibility() @@ -248,6 +260,12 @@ public void setEnableDecimalLogicalType(String enableDecimalLogicalType) { this.enableDecimalLogicalType.set(Boolean.parseBoolean(enableDecimalLogicalType)); } + @Optional + @Classpath + public ConfigurableFileCollection getConversionsAndTypeFactoriesClasspath() { + return conversionsAndTypeFactoriesClasspath; + } + @Optional @Input public MapProperty> getLogicalTypeFactories() { @@ -264,6 +282,22 @@ public void setLogicalTypeFactories(Map getLogicalTypeFactoryClassNames() { + return logicalTypeFactoryClassNames; + } + + public void setLogicalTypeFactoryClassNames(Provider> provider) { + this.logicalTypeFactoryClassNames.set(provider); + } + + public void setLogicalTypeFactoryClassNames(Map logicalTypeFactoryClassNames) { + this.logicalTypeFactoryClassNames.set(logicalTypeFactoryClassNames); + } + @Optional @Input public ListProperty>> getCustomConversions() { @@ -278,6 +312,20 @@ public void setCustomConversions(Iterable>> custom this.customConversions.set(customConversions); } + @Optional + @Input + public ListProperty getCustomConversionClassNames() { + return customConversionClassNames; + } + + public void setCustomConversionClassNames(Provider> provider) { + this.customConversionClassNames.set(provider); + } + + public void setCustomConversionClassNames(Iterable customConversionClassNames) { + this.customConversionClassNames.set(customConversionClassNames); + } + @TaskAction protected void process() { getLogger().debug("Using outputCharacterEncoding {}", getOutputCharacterEncoding().getOrNull()); @@ -397,7 +445,7 @@ private void compile(SpecificCompiler compiler, File sourceFile) throws IOExcept * Since {@link LogicalTypes} is a static registry, this may result in side-effects. */ private void registerLogicalTypes() { - Map> logicalTypeFactoryMap = logicalTypeFactories.get(); + Map> logicalTypeFactoryMap = resolveLocalTypeFactories(); Set>> logicalTypeFactoryEntries = logicalTypeFactoryMap.entrySet(); for (Map.Entry> entry : logicalTypeFactoryEntries) { @@ -412,10 +460,61 @@ private void registerLogicalTypes() { } } + @SuppressWarnings("unchecked") + private Map> resolveLocalTypeFactories() { + Map> result = new HashMap<>(); + if (logicalTypeFactoryClassNames.isPresent()) { + ClassLoader typeFactoriesClassLoader = createConversionsAndTypeFactoriesClassLoader(); + for (Entry entry : logicalTypeFactoryClassNames.get().entrySet()) { + String logicalTypeFactoryClassName = entry.getValue(); + try { + Class aClass = Class.forName(logicalTypeFactoryClassName, true, typeFactoriesClassLoader); + result.put(entry.getKey(), (Class) aClass); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Unable to load logical type factory class " + logicalTypeFactoryClassName, e); + } + } + } + result.putAll(logicalTypeFactories.get()); + return result; + } + private void registerCustomConversions(SpecificCompiler compiler) { + loadCustomConversionClasses().forEach(compiler::addCustomConversion); customConversions.get().forEach(compiler::addCustomConversion); } + private List> loadCustomConversionClasses() { + if (customConversionClassNames.isPresent()) { + ClassLoader customConversionsClassLoader = createConversionsAndTypeFactoriesClassLoader(); + return customConversionClassNames.get().stream() + .map(conversionClassName -> { + try { + return Class.forName(conversionClassName, true, customConversionsClassLoader); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Unable to load custom conversion class " + conversionClassName, e); + } + }).collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + private ClassLoader createConversionsAndTypeFactoriesClassLoader() { + URL[] urls = conversionsAndTypeFactoriesClasspath.getFiles().stream() + .map(File::toURI) + .map(uri -> { + try { + return uri.toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException("Unable to resolve URL in conversions and type factories classpath", e); + } + }) + .toArray(URL[]::new); + + return new URLClassLoader(urls, getClass().getClassLoader()); + } + private ClassLoader assembleClassLoader() { getLogger().debug("Using additional classpath: {}", classpath.getFiles()); List urls = new LinkedList<>(); diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java index 57c1f00d9da..e8cd716b4ad 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java @@ -32,7 +32,7 @@ static T createExtensionWithObjectFactory(Project project, String extensionN if (GradleFeatures.extensionInjection.isSupported()) { return project.getExtensions().create(extensionName, extensionType); } else { - return project.getExtensions().create(extensionName, extensionType, project.getObjects()); + return project.getExtensions().create(extensionName, extensionType, project, project.getObjects()); } } diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy index 6ab7f0513b5..94b9354db96 100644 --- a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy +++ b/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy @@ -166,6 +166,55 @@ class CustomConversionFunctionalSpec extends FunctionalSpec { javaSource.contains("java.util.TimeZone timezone;") } + def "can use a custom conversion from outside of the build classpath when generating java from a protocol"() { + given: + copyResource("customConversion.avpr", avroDir) + applyAvroPlugin() + buildFile << """ + |configurations { + | customConversions + | implementation.extendsFrom(customConversions) + |} + |dependencies { + | customConversions(project(":custom-conversions")) + |} + |avro { + | stringType = "CharSequence" + | conversionsAndTypeFactoriesClasspath.from(configurations.customConversions) + | logicalTypeFactory("timezone", "com.github.davidmc24.gradle.plugin.avro.test.custom.TimeZoneLogicalTypeFactory") + | customConversion("com.github.davidmc24.gradle.plugin.avro.test.custom.TimeZoneConversion") + |} + |""".stripMargin() + addDefaultRepository() + addAvroDependency() + projectFile("custom-conversions/build.gradle") << """ + |plugins { + | id "java-library" + |} + |repositories { + | mavenCentral() + |} + |dependencies { + | implementation "org.apache.avro:avro:${avroVersion}" + |} + |""".stripMargin() + projectFile("settings.gradle") << """ + |include("custom-conversions") + |""".stripMargin() + copyCustomConversion("custom-conversions/src/main/java") + + when: + def result = run() + + then: + result.task(":generateAvroJava").outcome == SUCCESS + result.task(":compileJava").outcome == SUCCESS + projectFile(buildOutputClassPath("test/Event.class")).file + def javaSource = projectFile("build/generated-main-avro-java/test/Event.java").text + javaSource.contains("java.time.Instant start;") + javaSource.contains("java.util.TimeZone timezone;") + } + def "can use a custom logical type while generating a schema from a protocol"() { given: copyResource("customConversion.avpr", avroDir) From 5ede65a80919582f5956ba106ea95430b867335b Mon Sep 17 00:00:00 2001 From: Marcin Erdmann Date: Tue, 4 Apr 2023 16:11:51 +0100 Subject: [PATCH 469/479] Fix compatibility with Gradle < 7.1 --- .../davidmc24/gradle/plugin/avro/GradleCompatibility.java | 2 +- .../github/davidmc24/gradle/plugin/avro/GradleFeatures.java | 5 ++--- .../github/davidmc24/gradle/plugin/avro/GradleVersions.java | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java index e8cd716b4ad..c62c983246e 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java @@ -29,7 +29,7 @@ class GradleCompatibility { private static final Object[] NO_ARGUMENTS = {}; static T createExtensionWithObjectFactory(Project project, String extensionName, Class extensionType) { - if (GradleFeatures.extensionInjection.isSupported()) { + if (GradleFeatures.projectIntoExtensionInjection.isSupported()) { return project.getExtensions().create(extensionName, extensionType); } else { return project.getExtensions().create(extensionName, extensionType, project, project.getObjects()); diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java index 180f771bfa9..c918f962664 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java @@ -19,10 +19,9 @@ import org.gradle.util.GradleVersion; enum GradleFeatures { - extensionInjection() { - @Override + projectIntoExtensionInjection() { boolean isSupportedBy(GradleVersion version) { - return version.compareTo(GradleVersions.v5_2) >= 0; + return version.compareTo(GradleVersions.v7_1) >= 0; } }, objectFactoryFileCollection() { diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java index ba6ff9f8481..42367748a10 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java @@ -19,9 +19,9 @@ import org.gradle.util.GradleVersion; class GradleVersions { - static final GradleVersion v5_2 = GradleVersion.version("5.2"); static final GradleVersion v5_3 = GradleVersion.version("5.3"); static final GradleVersion v6_0 = GradleVersion.version("6.0"); static final GradleVersion v6_6 = GradleVersion.version("6.6"); + static final GradleVersion v7_1 = GradleVersion.version("7.1"); static final GradleVersion v7_4 = GradleVersion.version("7.4"); } From 09fafb24fd4459ac4000ff57f0de9f75d63737f5 Mon Sep 17 00:00:00 2001 From: Marcin Erdmann Date: Tue, 4 Apr 2023 16:33:06 +0100 Subject: [PATCH 470/479] Add documentation for using conversions and type factories located outside of build classpath --- CHANGES.md | 1 + README.md | 49 +++++++++++++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e934aa11f3a..328d9fd7ed0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # Change Log ## Unreleased +* Support for using conversions and type factories located outside of build classpath (contribution from [erdi](https://github.com/erdi)); see https://github.com/davidmc24/gradle-avro-plugin/pull/228 ## 1.6.0 * Add support for configuring classpath for `GenerateAvroJavaTask` (thanks to [crtlib](https://github.com/crtlib)); see https://github.com/davidmc24/gradle-avro-plugin/pull/222 diff --git a/README.md b/README.md index fff20983eba..24582e2f648 100644 --- a/README.md +++ b/README.md @@ -83,18 +83,21 @@ Actually, it will attempt to process an "avro" directory in every `SourceSet` (m There are a number of configuration options supported in the `avro` block. -| option | default | description | -|--------------------------------------| --------------------- |----------------------------------------------------------------| -| createSetters | `true` | `createSetters` passed to Avro compiler | -| createOptionalGetters | `false` | `createOptionalGetters` passed to Avro compiler | -| gettersReturnOptional | `false` | `gettersReturnOptional` passed to Avro compiler | -| optionalGettersForNullableFieldsOnly | `false` | `optionalGettersForNullableFieldsOnly` passed to Avro compiler | -| fieldVisibility | `"PRIVATE"` | `fieldVisibility` passed to Avro compiler | -| outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | -| stringType | `"String"` | `stringType` passed to Avro compiler | -| templateDirectory | see below | `templateDir` passed to Avro compiler | -| additionalVelocityToolClasses | see below | `additionalVelocityTools` passed to Avro compiler | -| enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | +| option | default | description | +|--------------------------------------|------------------------------------|-------------------------------------------------------------------------------------------------------------------| +| createSetters | `true` | `createSetters` passed to Avro compiler | +| createOptionalGetters | `false` | `createOptionalGetters` passed to Avro compiler | +| gettersReturnOptional | `false` | `gettersReturnOptional` passed to Avro compiler | +| optionalGettersForNullableFieldsOnly | `false` | `optionalGettersForNullableFieldsOnly` passed to Avro compiler | +| fieldVisibility | `"PRIVATE"` | `fieldVisibility` passed to Avro compiler | +| outputCharacterEncoding | see below | `outputCharacterEncoding` passed to Avro compiler | +| stringType | `"String"` | `stringType` passed to Avro compiler | +| templateDirectory | see below | `templateDir` passed to Avro compiler | +| additionalVelocityToolClasses | see below | `additionalVelocityTools` passed to Avro compiler | +| enableDecimalLogicalType | `true` | `enableDecimalLogicalType` passed to Avro compiler | +| conversionsAndTypeFactoriesClasspath | empty `ConfigurableFileCollection` | used for loading custom conversions and logical type factories | +| logicalTypeFactoryClassNames | empty `Map` | map from names to class names of logical types factories to be loaded from `conversionsAndTypeFactoriesClasspath` | +| customConversionClassNames | empty `List` | class names of custom conversions to be loaded from `conversionsAndTypeFactoriesClasspath` | Additionally, the `avro` extension exposes the following methods: @@ -257,6 +260,28 @@ avro { } ``` +## conversionsAndTypeFactoriesClasspath, logicalTypeFactoryClassNames and customConversionClassNames + +Properties that can be used for loading [Conversion](https://avro.apache.org/docs/current/api/java/org/apache/avro/Conversion.html) and [LogicalTypeFactory](https://avro.apache.org/docs/current/api/java/org/apache/avro/LogicalTypes.LogicalTypeFactory.html) classes from outside of the build classpath. + +Example: + +```groovy +configurations { + customConversions +} + +dependencies { + customConversions(project(":custom-conversions")) +} + +avro { + conversionsAndTypeFactoriesClasspath.from(configurations.customConversions) + logicalTypeFactoryClassNames.put("timezone", "com.github.davidmc24.gradle.plugin.avro.test.custom.TimeZoneLogicalTypeFactory") + customConversionClassNames.add("com.github.davidmc24.gradle.plugin.avro.test.custom.TimeZoneConversion") +} +``` + # IntelliJ Integration The plugin attempts to make IntelliJ play more smoothly with generated sources when using Gradle-generated project files. From b4ac5bab8cd4409e1ccb1f2b1f3d39229a453fb1 Mon Sep 17 00:00:00 2001 From: Marcin Erdmann Date: Tue, 4 Apr 2023 16:55:08 +0100 Subject: [PATCH 471/479] Add deprecations for methods used to configure conversions and type factories with classes --- .../gradle/plugin/avro/AvroBasePlugin.java | 1 + .../gradle/plugin/avro/AvroExtension.java | 20 ++++++++++++ .../plugin/avro/DefaultAvroExtension.java | 32 +++++++++++++++++++ .../plugin/avro/GenerateAvroJavaTask.java | 24 ++++++++++++++ 4 files changed, 77 insertions(+) diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java index 9e3b9b1d45b..e83971c116f 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java @@ -24,6 +24,7 @@ public void apply(final Project project) { configureExtension(project); } + @SuppressWarnings("deprecation") private static void configureExtension(final Project project) { final AvroExtension avroExtension = GradleCompatibility.createExtensionWithObjectFactory(project, Constants.AVRO_EXTENSION_NAME, DefaultAvroExtension.class); diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java index 1d64cbee214..e0ef45cd707 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java @@ -35,12 +35,32 @@ public interface AvroExtension { Property isOptionalGettersForNullableFieldsOnly(); Property isEnableDecimalLogicalType(); ConfigurableFileCollection getConversionsAndTypeFactoriesClasspath(); + + /** + * @deprecated use {@link #getLogicalTypeFactoryClassNames()} instead + */ + @Deprecated MapProperty> getLogicalTypeFactories(); MapProperty getLogicalTypeFactoryClassNames(); + + /** + * @deprecated use {@link #getCustomConversionClassNames()} instead + */ + @Deprecated ListProperty>> getCustomConversions(); ListProperty getCustomConversionClassNames(); + + /** + * @deprecated use {@link #logicalTypeFactory(String, String)} + */ + @Deprecated AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass); AvroExtension logicalTypeFactory(String typeName, String typeFactoryClassName); + + /** + * @deprecated use {@link #customConversion(String)} instead + */ + @Deprecated AvroExtension customConversion(Class> conversionClass); AvroExtension customConversion(String conversionClassName); } diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java index 3b0478b2f2d..2182da4160b 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java @@ -205,16 +205,28 @@ public ConfigurableFileCollection getConversionsAndTypeFactoriesClasspath() { return conversionsAndTypeFactoriesClasspath; } + /** + * @deprecated use {@link #getLogicalTypeFactoryClassNames()} instead + */ + @Deprecated @Override public MapProperty> getLogicalTypeFactories() { return logicalTypeFactories; } + /** + * @deprecated use {@link #setLogicalTypeFactoryClassNames(Provider)} ()} instead + */ + @Deprecated public void setLogicalTypeFactories(Provider>> provider) { this.logicalTypeFactories.set(provider); } + /** + * @deprecated use {@link #setLogicalTypeFactoryClassNames(Map)} ()} instead + */ + @Deprecated public void setLogicalTypeFactories(Map> logicalTypeFactories) { this.logicalTypeFactories.set(logicalTypeFactories); @@ -235,15 +247,27 @@ public void setLogicalTypeFactoryClassNames(Map>> getCustomConversions() { return customConversions; } + /** + * @deprecated use {@link #setCustomConversionClassNames(Provider)} ()} instead + */ + @Deprecated public void setCustomConversions(Provider>>> provider) { this.customConversions.set(provider); } + /** + * @deprecated use {@link #setCustomConversionClassNames(Iterable)} instead + */ + @Deprecated public void setCustomConversions(Iterable>> customConversions) { this.customConversions.set(customConversions); } @@ -260,6 +284,10 @@ public void setCustomConversionClassNames(Iterable customConversionClass this.customConversionClassNames.set(customConversionClassNames); } + /** + * @deprecated use {@link #logicalTypeFactory(String, String)} ()} instead + */ + @Deprecated @Override public AvroExtension logicalTypeFactory(String typeName, Class typeFactoryClass) { logicalTypeFactories.put(typeName, typeFactoryClass); @@ -272,6 +300,10 @@ public AvroExtension logicalTypeFactory(String typeName, String typeFactoryClass return this; } + /** + * @deprecated use {@link #customConversion(String)} ()} instead + */ + @Deprecated @Override public AvroExtension customConversion(Class> conversionClass) { customConversions.add(conversionClass); diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java index 477f718427b..a9fe3796d24 100644 --- a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java +++ b/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java @@ -266,17 +266,29 @@ public ConfigurableFileCollection getConversionsAndTypeFactoriesClasspath() { return conversionsAndTypeFactoriesClasspath; } + /** + * @deprecated use {@link #getLogicalTypeFactoryClassNames()} ()} instead + */ + @Deprecated @Optional @Input public MapProperty> getLogicalTypeFactories() { return logicalTypeFactories; } + /** + * @deprecated use {@link #setLogicalTypeFactoryClassNames(Provider)} ()} instead + */ + @Deprecated public void setLogicalTypeFactories(Provider>> provider) { this.logicalTypeFactories.set(provider); } + /** + * @deprecated use {@link #setLogicalTypeFactoryClassNames(Map)} ()} instead + */ + @Deprecated public void setLogicalTypeFactories(Map> logicalTypeFactories) { this.logicalTypeFactories.set(logicalTypeFactories); @@ -298,16 +310,28 @@ public void setLogicalTypeFactoryClassNames(Map>> getCustomConversions() { return customConversions; } + /** + * @deprecated use {@link #setCustomConversionClassNames(Provider)} ()} instead + */ + @Deprecated public void setCustomConversions(Provider>>> provider) { this.customConversions.set(provider); } + /** + * @deprecated use {@link #setCustomConversionClassNames(Iterable)} ()} instead + */ + @Deprecated public void setCustomConversions(Iterable>> customConversions) { this.customConversions.set(customConversions); } From dda836f65bafb7aaf4984953b936aae93656457a Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 5 Apr 2023 10:36:34 -0400 Subject: [PATCH 472/479] Prep for 1.7.0 release --- CHANGES.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 328d9fd7ed0..0f8019d8c65 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Change Log ## Unreleased + +## 1.7.0 * Support for using conversions and type factories located outside of build classpath (contribution from [erdi](https://github.com/erdi)); see https://github.com/davidmc24/gradle-avro-plugin/pull/228 ## 1.6.0 diff --git a/build.gradle b/build.gradle index a3603354bc4..22a6fc48323 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.6.1-SNAPSHOT" +version = "1.7.0" def isCI = System.getenv("CI") == "true" From 55608b3871c1694fe4adceebbdf6bd65e3e279eb Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 5 Apr 2023 10:40:27 -0400 Subject: [PATCH 473/479] version: 1.7.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 22a6fc48323..1a030be1185 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.7.0" +version = "1.7.1-SNAPSHOT" def isCI = System.getenv("CI") == "true" From 036875fa9d2cbe0bcc4b9f805c095db35fb84ae5 Mon Sep 17 00:00:00 2001 From: Marcel Henrich Date: Wed, 3 May 2023 11:31:22 +0200 Subject: [PATCH 474/479] Fix vulnerabilities in transitive dependencies --- build.gradle | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1a030be1185..65978a92988 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.7.1-SNAPSHOT" +version = "1.7.1" def isCI = System.getenv("CI") == "true" @@ -52,6 +52,14 @@ task createClasspathManifest { dependencies { implementation localGroovy() implementation "org.apache.avro:avro-compiler:${compileAvroVersion}" + constraints { + implementation ('com.fasterxml.jackson.core:jackson-databind:2.12.7.1') { + because 'previous versions have vulnerabilities: CVE-2022-42004, CVE-2022-42003' + } + implementation ('org.apache.commons:commons-text:1.10.0') { + because 'previous versions have vulnerability: CVE-2022-42889' + } + } testImplementation "org.spockframework:spock-core:2.0-M5-groovy-3.0" testImplementation gradleTestKit() testImplementation "uk.co.datumedge:hamcrest-json:0.2" From a81ffc622f62f5ca58be840b430d7631f3cb792f Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 3 May 2023 08:40:44 -0400 Subject: [PATCH 475/479] version: 1.7.1 --- CHANGES.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 0f8019d8c65..ecb01369c1e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,8 +2,11 @@ ## Unreleased +## 1.7.1 +* Fix vulnerabilities in transitive dependencies (contribution from [BlacCello](https://github.com/BlacCello)); see https://github.com/davidmc24/gradle-avro-plugin/pull/229 + ## 1.7.0 -* Support for using conversions and type factories located outside of build classpath (contribution from [erdi](https://github.com/erdi)); see https://github.com/davidmc24/gradle-avro-plugin/pull/228 +* Support for using conversions and type factories located outside of build classpath (contribution from [erdi](https://github.com/erdi)); see https://github.com/davidmc24/gradle-avro-plugin/pull/228 ## 1.6.0 * Add support for configuring classpath for `GenerateAvroJavaTask` (thanks to [crtlib](https://github.com/crtlib)); see https://github.com/davidmc24/gradle-avro-plugin/pull/222 From bf84ab2bfee8be1a7febe6272801ca6096e978db Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 3 May 2023 08:44:41 -0400 Subject: [PATCH 476/479] version: 1.7.2-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 65978a92988..7b47e5048b5 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ plugins { // support. group = "com.github.davidmc24.gradle.plugin" -version = "1.7.1" +version = "1.7.2-SNAPSHOT" def isCI = System.getenv("CI") == "true" From 17210cdb427427641a926dc5cd9ddeab82d46ddd Mon Sep 17 00:00:00 2001 From: "David M. Carr" Date: Wed, 3 May 2023 17:47:34 -0400 Subject: [PATCH 477/479] Update github actions that ran in node 12 --- .github/workflows/avro-compatibility.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- .github/workflows/gradle-compatibility.yml | 4 ++-- .../workflows/gradle-wrapper-validation.yml | 2 +- .github/workflows/java-compatibility.yml | 20 +++++++++---------- .github/workflows/os-compatibility.yml | 4 ++-- .github/workflows/publish.yml | 4 ++-- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/avro-compatibility.yml b/.github/workflows/avro-compatibility.yml index 31816f81a2e..9304f495872 100644 --- a/.github/workflows/avro-compatibility.yml +++ b/.github/workflows/avro-compatibility.yml @@ -10,8 +10,8 @@ jobs: gradle: ["5.1", "7.6"] java: ["8"] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: ${{ matrix.java }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 580eeb6e60a..04029994afa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,8 +5,8 @@ jobs: name: "Build" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: 8 diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index 22c3c30d245..a2a195ded7f 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -16,8 +16,8 @@ jobs: ] java: ["8", "11"] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: ${{ matrix.java }} diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 09d2a7fd1e6..a2b20bd7c02 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -7,5 +7,5 @@ jobs: name: "Validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/java-compatibility.yml b/.github/workflows/java-compatibility.yml index 5c65375d71a..047e08e512d 100644 --- a/.github/workflows/java-compatibility.yml +++ b/.github/workflows/java-compatibility.yml @@ -11,8 +11,8 @@ jobs: gradle: ["5.1", "7.6"] java: ["8", "11"] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: ${{ matrix.java }} @@ -28,8 +28,8 @@ jobs: gradle: ["7.3", "7.6"] # See here for latest versions: https://services.gradle.org/versions/ java: ["17"] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: ${{ matrix.java }} @@ -45,8 +45,8 @@ jobs: gradle: ["7.5", "7.6"] # See here for latest versions: https://services.gradle.org/versions/ java: ["18"] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: ${{ matrix.java }} @@ -62,8 +62,8 @@ jobs: gradle: ["7.6"] # See here for latest versions: https://services.gradle.org/versions/ java: ["19"] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: ${{ matrix.java }} @@ -81,8 +81,8 @@ jobs: java: ["20-ea"] fail-fast: false steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: ${{ matrix.java }} diff --git a/.github/workflows/os-compatibility.yml b/.github/workflows/os-compatibility.yml index 79e8257b266..58f8e30dd76 100644 --- a/.github/workflows/os-compatibility.yml +++ b/.github/workflows/os-compatibility.yml @@ -9,8 +9,8 @@ jobs: java: [8] # Minimum supported major version os: [ubuntu-latest, windows-latest, macOS-latest] # All supported OS steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: ${{ matrix.java }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 715f70ce36d..69e66b6638f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -6,8 +6,8 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: distribution: "zulu" java-version: 8 From a953c193a4b9f59cfd70cb44886498cbaa51c35f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Martinovi=C4=87?= Date: Sat, 13 May 2023 19:08:40 +0200 Subject: [PATCH 478/479] Fix Kotlin DSL setup snippet --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24582e2f648..dab55f446e6 100644 --- a/README.md +++ b/README.md @@ -414,7 +414,7 @@ avro { isCreateSetters.set(true) isCreateOptionalGetters.set(false) isGettersReturnOptional.set(false) - isOptionalGettersForNullableFieldsOnly(false) + isOptionalGettersForNullableFieldsOnly.set(false) fieldVisibility.set("PUBLIC_DEPRECATED") outputCharacterEncoding.set("UTF-8") stringType.set("String") From cb17b3dcafc73ff6f996d279c08e7f6d3a1dae02 Mon Sep 17 00:00:00 2001 From: singingbush Date: Thu, 29 Jun 2023 11:43:55 +0100 Subject: [PATCH 479/479] move everything to lang/java/gradle-plugin --- .../java/gradle-plugin/.editorconfig | 0 CHANGES.md => lang/java/gradle-plugin/CHANGES.md | 0 .../java/gradle-plugin/CODE_OF_CONDUCT.md | 0 .../java/gradle-plugin/CONTRIBUTING.md | 0 LICENSE => lang/java/gradle-plugin/LICENSE | 0 README.md => lang/java/gradle-plugin/README.md | 0 .../java/gradle-plugin/RELEASING.md | 0 .../java/gradle-plugin/build.gradle | 0 .../gradle-plugin/config}/checkstyle/checkstyle.xml | 0 .../config}/checkstyle/import-control.xml | 0 .../gradle-plugin/config}/codenarc/codenarc.groovy | 0 .../configurations-for-additional-schema.md | 0 .../design-docs}/external-schemata-and-protocols.md | 0 .../design-docs}/run-avro-as-an-external-process.md | 0 .../examples}/avsc-from-external-jar/README.md | 0 .../examples}/avsc-from-external-jar/build.gradle | 0 .../external-files/Breed.avsc | 0 .../avsc-from-external-jar/external-files/Cat.avsc | 0 .../avsc-from-external-jar/external-libs/schema.jar | Bin .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../examples}/avsc-from-external-jar/gradlew | 0 .../examples}/avsc-from-external-jar/gradlew.bat | 0 .../avsc-from-external-jar/settings.gradle | 0 .../avsc-from-external-jar/src/main/avro/Cat.avsc | 0 .../examples}/avsc-from-subproject/README.md | 0 .../examples}/avsc-from-subproject/cat/build.gradle | 0 .../avsc-from-subproject/cat/src/main/avro/Cat.avsc | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../examples}/avsc-from-subproject/gradlew | 0 .../examples}/avsc-from-subproject/gradlew.bat | 0 .../avsc-from-subproject/schema/build.gradle | 0 .../schema/src/main/avro/Breed.avsc | 0 .../examples}/avsc-from-subproject/settings.gradle | 0 .../examples}/default-custom-types/README.md | 0 .../examples}/default-custom-types/build.gradle | 0 .../default-custom-types/buildSrc/build.gradle | 0 .../src/main/java/custom/AvroConventionPlugin.java | 0 .../src/main/java/custom/TimeZoneConversion.java | 0 .../src/main/java/custom/TimeZoneLogicalType.java | 0 .../java/custom/TimeZoneLogicalTypeFactory.java | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../examples}/default-custom-types/gradlew | 0 .../examples}/default-custom-types/gradlew.bat | 0 .../examples}/default-custom-types/settings.gradle | 0 .../src/main/avro/customConversion.avsc | 0 .../src/main/java/custom/TimeZoneConversion.java | 0 .../src/main/java/custom/TimeZoneLogicalType.java | 0 .../java/custom/TimeZoneLogicalTypeFactory.java | 0 .../java/gradle-plugin/gradle.properties | 0 .../gradle}/wrapper/gradle-wrapper.jar | Bin .../gradle}/wrapper/gradle-wrapper.properties | 0 gradlew => lang/java/gradle-plugin/gradlew | 0 gradlew.bat => lang/java/gradle-plugin/gradlew.bat | 0 .../java/gradle-plugin/scripts}/run-avro-cli.sh | 0 .../gradle-plugin/scripts}/run-compile-schema.sh | 0 .../java/gradle-plugin/settings.gradle | 0 .../gradle/plugin/avro/AvroBasePlugin.java | 0 .../davidmc24/gradle/plugin/avro/AvroExtension.java | 0 .../davidmc24/gradle/plugin/avro/AvroPlugin.java | 0 .../davidmc24/gradle/plugin/avro/AvroUtils.java | 0 .../davidmc24/gradle/plugin/avro/Constants.java | 0 .../gradle/plugin/avro/DefaultAvroExtension.java | 0 .../github/davidmc24/gradle/plugin/avro/Enums.java | 0 .../gradle/plugin/avro/FileExtensionSpec.java | 0 .../davidmc24/gradle/plugin/avro/FileState.java | 0 .../davidmc24/gradle/plugin/avro/FileUtils.java | 0 .../davidmc24/gradle/plugin/avro/FilenameUtils.java | 0 .../gradle/plugin/avro/GenerateAvroJavaTask.java | 0 .../plugin/avro/GenerateAvroProtocolTask.java | 0 .../gradle/plugin/avro/GenerateAvroSchemaTask.java | 0 .../gradle/plugin/avro/GradleCompatibility.java | 0 .../gradle/plugin/avro/GradleFeatures.java | 0 .../gradle/plugin/avro/GradleVersions.java | 0 .../davidmc24/gradle/plugin/avro/MapUtils.java | 0 .../davidmc24/gradle/plugin/avro/OutputDirTask.java | 0 .../gradle/plugin/avro/ProcessingState.java | 0 .../plugin/avro/ResolveAvroDependenciesTask.java | 0 .../gradle/plugin/avro/SchemaResolver.java | 0 .../davidmc24/gradle/plugin/avro/SetBuilder.java | 0 .../davidmc24/gradle/plugin/avro/Strings.java | 0 .../davidmc24/gradle/plugin/avro/TypeState.java | 0 .../plugin/avro/AvroBasePluginFunctionalSpec.groovy | 0 .../plugin/avro/AvroPluginFunctionalSpec.groovy | 0 .../gradle/plugin/avro/AvroPluginSpec.groovy | 0 .../gradle/plugin/avro/AvroUtilsSpec.groovy | 0 .../avro/BuildCacheSupportFunctionalSpec.groovy | 0 .../avro/CustomConversionFunctionalSpec.groovy | 0 .../avro/DuplicateHandlingFunctionalSpec.groovy | 0 .../plugin/avro/EncodingFunctionalSpec.groovy | 0 .../plugin/avro/EnumHandlingFunctionalSpec.groovy | 0 .../plugin/avro/ExamplesFunctionalSpec.groovy | 0 .../gradle/plugin/avro/FunctionalSpec.groovy | 0 .../GenerateAvroProtocolTaskFunctionalSpec.groovy | 0 .../plugin/avro/IntellijFunctionalSpec.groovy | 0 .../KotlinDSLCompatibilityFunctionalSpec.groovy | 0 .../gradle/plugin/avro/OptionsFunctionalSpec.groovy | 0 ...ResolveAvroDependenciesTaskFunctionalSpec.groovy | 0 .../gradle/plugin/avro/SchemaResolverSpec.groovy | 0 .../davidmc24/gradle/plugin/avro/StringsSpec.groovy | 0 .../plugin/avro/test/custom/CommentGenerator.java | 0 .../plugin/avro/test/custom/TimeZoneConversion.java | 0 .../avro/test/custom/TimeZoneLogicalType.java | 0 .../test/custom/TimeZoneLogicalTypeFactory.java | 0 .../plugin/avro/test/custom/TimestampGenerator.java | 0 .../davidmc24/gradle/plugin/avro/Message.avsc | 0 .../gradle/plugin/avro/customConversion.avpr | 0 .../gradle/plugin/avro/customConversion.avsc | 0 .../davidmc24/gradle/plugin/avro/dependent.avdl | 0 .../davidmc24/gradle/plugin/avro/duplicate/Cat.avsc | 0 .../plugin/avro/duplicate/ContainsFixed1.avsc | 0 .../plugin/avro/duplicate/ContainsFixed2.avsc | 0 .../plugin/avro/duplicate/ContainsFixed3.avsc | 0 .../davidmc24/gradle/plugin/avro/duplicate/Dog.avsc | 0 .../gradle/plugin/avro/duplicate/Fish.avsc | 0 .../gradle/plugin/avro/duplicate/Person.avsc | 0 .../gradle/plugin/avro/duplicate/Spider.avsc | 0 .../avro/duplicate/duplicateInSingleFile.avsc | 0 .../davidmc24/gradle/plugin/avro/enumField.avsc | 0 .../davidmc24/gradle/plugin/avro/enumMalformed.avsc | 0 .../davidmc24/gradle/plugin/avro/enumSimple.avsc | 0 .../davidmc24/gradle/plugin/avro/enumUnion.avsc | 0 .../davidmc24/gradle/plugin/avro/enumUseSimple.avsc | 0 .../davidmc24/gradle/plugin/avro/helloWorld.kt | 0 .../github/davidmc24/gradle/plugin/avro/idioma.avsc | 0 .../davidmc24/gradle/plugin/avro/interop-1.9.avdl | 0 .../davidmc24/gradle/plugin/avro/interop.avdl | 0 .../github/davidmc24/gradle/plugin/avro/mail.avpr | 0 .../gradle/plugin/avro/namespaced-idl/v1/test.avdl | 0 .../avro/namespaced-idl/v1/test_same_protocol.avdl | 0 .../gradle/plugin/avro/namespaced-idl/v2/test.avdl | 0 .../davidmc24/gradle/plugin/avro/record-tools.vm | 0 .../github/davidmc24/gradle/plugin/avro/record.vm | 0 .../github/davidmc24/gradle/plugin/avro/shared.avdl | 0 .../github/davidmc24/gradle/plugin/avro/user.avsc | 0 .../src}/test/resources/examples/inline/Cat.avsc | 0 .../test/resources/examples/separate/Breed.avsc | 0 .../src}/test/resources/examples/separate/Cat.avsc | 0 .../src}/test/resources/resolver/SimpleEnum.avsc | 0 .../src}/test/resources/resolver/SimpleFixed.avsc | 0 .../src}/test/resources/resolver/SimpleRecord.avsc | 0 .../src}/test/resources/resolver/UseArray.avsc | 0 .../test/resources/resolver/UseArrayWithType.avsc | 0 .../src}/test/resources/resolver/UseEnum.avsc | 0 .../test/resources/resolver/UseEnumWithType.avsc | 0 .../src}/test/resources/resolver/UseFixed.avsc | 0 .../test/resources/resolver/UseFixedWithType.avsc | 0 .../src}/test/resources/resolver/UseMap.avsc | 0 .../test/resources/resolver/UseMapWithType.avsc | 0 .../src}/test/resources/resolver/UseRecord.avsc | 0 .../test/resources/resolver/UseRecordWithType.avsc | 0 .../test-project-kotlin}/build.gradle.kts | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../java/gradle-plugin/test-project-kotlin}/gradlew | 0 .../gradle-plugin/test-project-kotlin}/gradlew.bat | 0 .../test-project-kotlin}/settings.gradle.kts | 0 .../src/main/avro/BuggyRecord.avsc | 0 .../src/main/avro/BuggyRecordWorkaround.avsc | 0 .../src/main/avro/Messages.avsc | 0 .../src/main/avro/UUIDTestRecord.avsc | 0 .../src/main/java/project/SystemUtil.java | 0 .../src/test/java/project/CLIComparisonTest.java | 0 .../src/test/java/project/CLIUtil.java | 0 .../src/test/java/project/RandomRecordTest.java | 0 .../src/test/java/project/RecordTest.java | 0 .../java/gradle-plugin/test-project}/build.gradle | 0 .../test-project}/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../java/gradle-plugin/test-project}/gradlew | 0 .../java/gradle-plugin/test-project}/gradlew.bat | 0 .../gradle-plugin/test-project}/settings.gradle | 0 .../test-project}/src/main/avro/BuggyRecord.avsc | 0 .../src/main/avro/BuggyRecordWorkaround.avsc | 0 .../test-project}/src/main/avro/Messages.avsc | 0 .../test-project}/src/main/avro/UUIDTestRecord.avsc | 0 .../src/main/java/project/SystemUtil.java | 0 .../src/test/java/project/CLIComparisonTest.java | 0 .../src/test/java/project/CLIUtil.java | 0 .../src/test/java/project/RandomRecordTest.java | 0 .../src/test/java/project/RecordTest.java | 0 183 files changed, 0 insertions(+), 0 deletions(-) rename .editorconfig => lang/java/gradle-plugin/.editorconfig (100%) rename CHANGES.md => lang/java/gradle-plugin/CHANGES.md (100%) rename CODE_OF_CONDUCT.md => lang/java/gradle-plugin/CODE_OF_CONDUCT.md (100%) rename CONTRIBUTING.md => lang/java/gradle-plugin/CONTRIBUTING.md (100%) rename LICENSE => lang/java/gradle-plugin/LICENSE (100%) rename README.md => lang/java/gradle-plugin/README.md (100%) rename RELEASING.md => lang/java/gradle-plugin/RELEASING.md (100%) rename build.gradle => lang/java/gradle-plugin/build.gradle (100%) rename {config => lang/java/gradle-plugin/config}/checkstyle/checkstyle.xml (100%) rename {config => lang/java/gradle-plugin/config}/checkstyle/import-control.xml (100%) rename {config => lang/java/gradle-plugin/config}/codenarc/codenarc.groovy (100%) rename {design-docs => lang/java/gradle-plugin/design-docs}/configurations-for-additional-schema.md (100%) rename {design-docs => lang/java/gradle-plugin/design-docs}/external-schemata-and-protocols.md (100%) rename {design-docs => lang/java/gradle-plugin/design-docs}/run-avro-as-an-external-process.md (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/README.md (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/build.gradle (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/external-files/Breed.avsc (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/external-files/Cat.avsc (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/external-libs/schema.jar (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.jar (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/gradlew (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/gradlew.bat (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/settings.gradle (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-external-jar/src/main/avro/Cat.avsc (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/README.md (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/cat/build.gradle (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/cat/src/main/avro/Cat.avsc (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/gradle/wrapper/gradle-wrapper.jar (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/gradlew (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/gradlew.bat (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/schema/build.gradle (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/schema/src/main/avro/Breed.avsc (100%) rename {examples => lang/java/gradle-plugin/examples}/avsc-from-subproject/settings.gradle (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/README.md (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/build.gradle (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/buildSrc/build.gradle (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/buildSrc/src/main/java/custom/AvroConventionPlugin.java (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/buildSrc/src/main/java/custom/TimeZoneConversion.java (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalType.java (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalTypeFactory.java (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/gradle/wrapper/gradle-wrapper.jar (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/gradle/wrapper/gradle-wrapper.properties (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/gradlew (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/gradlew.bat (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/settings.gradle (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/src/main/avro/customConversion.avsc (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/src/main/java/custom/TimeZoneConversion.java (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/src/main/java/custom/TimeZoneLogicalType.java (100%) rename {examples => lang/java/gradle-plugin/examples}/default-custom-types/src/main/java/custom/TimeZoneLogicalTypeFactory.java (100%) rename gradle.properties => lang/java/gradle-plugin/gradle.properties (100%) rename {gradle => lang/java/gradle-plugin/gradle}/wrapper/gradle-wrapper.jar (100%) rename {gradle => lang/java/gradle-plugin/gradle}/wrapper/gradle-wrapper.properties (100%) rename gradlew => lang/java/gradle-plugin/gradlew (100%) rename gradlew.bat => lang/java/gradle-plugin/gradlew.bat (100%) rename {scripts => lang/java/gradle-plugin/scripts}/run-avro-cli.sh (100%) rename {scripts => lang/java/gradle-plugin/scripts}/run-compile-schema.sh (100%) rename settings.gradle => lang/java/gradle-plugin/settings.gradle (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/AvroUtils.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/Enums.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/FileExtensionSpec.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/FileState.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/FileUtils.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/FilenameUtils.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroSchemaTask.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/MapUtils.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/OutputDirTask.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/ProcessingState.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTask.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/SchemaResolver.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/SetBuilder.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/Strings.java (100%) rename {src => lang/java/gradle-plugin/src}/main/java/com/github/davidmc24/gradle/plugin/avro/TypeState.java (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroUtilsSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/EncodingFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/ExamplesFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/SchemaResolverSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/groovy/com/github/davidmc24/gradle/plugin/avro/StringsSpec.groovy (100%) rename {src => lang/java/gradle-plugin/src}/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java (100%) rename {src => lang/java/gradle-plugin/src}/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneConversion.java (100%) rename {src => lang/java/gradle-plugin/src}/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java (100%) rename {src => lang/java/gradle-plugin/src}/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java (100%) rename {src => lang/java/gradle-plugin/src}/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/Message.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avpr (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/dependent.avdl (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Cat.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed1.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed2.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed3.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Dog.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Fish.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Person.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Spider.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/enumField.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/enumMalformed.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/enumSimple.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUnion.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUseSimple.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/helloWorld.kt (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/idioma.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/interop-1.9.avdl (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/interop.avdl (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/mail.avpr (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test.avdl (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test_same_protocol.avdl (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v2/test.avdl (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/record-tools.vm (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/shared.avdl (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/com/github/davidmc24/gradle/plugin/avro/user.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/examples/inline/Cat.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/examples/separate/Breed.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/examples/separate/Cat.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/SimpleEnum.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/SimpleFixed.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/SimpleRecord.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseArray.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseArrayWithType.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseEnum.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseEnumWithType.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseFixed.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseFixedWithType.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseMap.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseMapWithType.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseRecord.avsc (100%) rename {src => lang/java/gradle-plugin/src}/test/resources/resolver/UseRecordWithType.avsc (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/build.gradle.kts (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/gradle/wrapper/gradle-wrapper.jar (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/gradle/wrapper/gradle-wrapper.properties (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/gradlew (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/gradlew.bat (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/settings.gradle.kts (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/src/main/avro/BuggyRecord.avsc (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/src/main/avro/BuggyRecordWorkaround.avsc (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/src/main/avro/Messages.avsc (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/src/main/avro/UUIDTestRecord.avsc (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/src/main/java/project/SystemUtil.java (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/src/test/java/project/CLIComparisonTest.java (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/src/test/java/project/CLIUtil.java (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/src/test/java/project/RandomRecordTest.java (100%) rename {test-project-kotlin => lang/java/gradle-plugin/test-project-kotlin}/src/test/java/project/RecordTest.java (100%) rename {test-project => lang/java/gradle-plugin/test-project}/build.gradle (100%) rename {test-project => lang/java/gradle-plugin/test-project}/gradle/wrapper/gradle-wrapper.jar (100%) rename {test-project => lang/java/gradle-plugin/test-project}/gradle/wrapper/gradle-wrapper.properties (100%) rename {test-project => lang/java/gradle-plugin/test-project}/gradlew (100%) rename {test-project => lang/java/gradle-plugin/test-project}/gradlew.bat (100%) rename {test-project => lang/java/gradle-plugin/test-project}/settings.gradle (100%) rename {test-project => lang/java/gradle-plugin/test-project}/src/main/avro/BuggyRecord.avsc (100%) rename {test-project => lang/java/gradle-plugin/test-project}/src/main/avro/BuggyRecordWorkaround.avsc (100%) rename {test-project => lang/java/gradle-plugin/test-project}/src/main/avro/Messages.avsc (100%) rename {test-project => lang/java/gradle-plugin/test-project}/src/main/avro/UUIDTestRecord.avsc (100%) rename {test-project => lang/java/gradle-plugin/test-project}/src/main/java/project/SystemUtil.java (100%) rename {test-project => lang/java/gradle-plugin/test-project}/src/test/java/project/CLIComparisonTest.java (100%) rename {test-project => lang/java/gradle-plugin/test-project}/src/test/java/project/CLIUtil.java (100%) rename {test-project => lang/java/gradle-plugin/test-project}/src/test/java/project/RandomRecordTest.java (100%) rename {test-project => lang/java/gradle-plugin/test-project}/src/test/java/project/RecordTest.java (100%) diff --git a/.editorconfig b/lang/java/gradle-plugin/.editorconfig similarity index 100% rename from .editorconfig rename to lang/java/gradle-plugin/.editorconfig diff --git a/CHANGES.md b/lang/java/gradle-plugin/CHANGES.md similarity index 100% rename from CHANGES.md rename to lang/java/gradle-plugin/CHANGES.md diff --git a/CODE_OF_CONDUCT.md b/lang/java/gradle-plugin/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to lang/java/gradle-plugin/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/lang/java/gradle-plugin/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to lang/java/gradle-plugin/CONTRIBUTING.md diff --git a/LICENSE b/lang/java/gradle-plugin/LICENSE similarity index 100% rename from LICENSE rename to lang/java/gradle-plugin/LICENSE diff --git a/README.md b/lang/java/gradle-plugin/README.md similarity index 100% rename from README.md rename to lang/java/gradle-plugin/README.md diff --git a/RELEASING.md b/lang/java/gradle-plugin/RELEASING.md similarity index 100% rename from RELEASING.md rename to lang/java/gradle-plugin/RELEASING.md diff --git a/build.gradle b/lang/java/gradle-plugin/build.gradle similarity index 100% rename from build.gradle rename to lang/java/gradle-plugin/build.gradle diff --git a/config/checkstyle/checkstyle.xml b/lang/java/gradle-plugin/config/checkstyle/checkstyle.xml similarity index 100% rename from config/checkstyle/checkstyle.xml rename to lang/java/gradle-plugin/config/checkstyle/checkstyle.xml diff --git a/config/checkstyle/import-control.xml b/lang/java/gradle-plugin/config/checkstyle/import-control.xml similarity index 100% rename from config/checkstyle/import-control.xml rename to lang/java/gradle-plugin/config/checkstyle/import-control.xml diff --git a/config/codenarc/codenarc.groovy b/lang/java/gradle-plugin/config/codenarc/codenarc.groovy similarity index 100% rename from config/codenarc/codenarc.groovy rename to lang/java/gradle-plugin/config/codenarc/codenarc.groovy diff --git a/design-docs/configurations-for-additional-schema.md b/lang/java/gradle-plugin/design-docs/configurations-for-additional-schema.md similarity index 100% rename from design-docs/configurations-for-additional-schema.md rename to lang/java/gradle-plugin/design-docs/configurations-for-additional-schema.md diff --git a/design-docs/external-schemata-and-protocols.md b/lang/java/gradle-plugin/design-docs/external-schemata-and-protocols.md similarity index 100% rename from design-docs/external-schemata-and-protocols.md rename to lang/java/gradle-plugin/design-docs/external-schemata-and-protocols.md diff --git a/design-docs/run-avro-as-an-external-process.md b/lang/java/gradle-plugin/design-docs/run-avro-as-an-external-process.md similarity index 100% rename from design-docs/run-avro-as-an-external-process.md rename to lang/java/gradle-plugin/design-docs/run-avro-as-an-external-process.md diff --git a/examples/avsc-from-external-jar/README.md b/lang/java/gradle-plugin/examples/avsc-from-external-jar/README.md similarity index 100% rename from examples/avsc-from-external-jar/README.md rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/README.md diff --git a/examples/avsc-from-external-jar/build.gradle b/lang/java/gradle-plugin/examples/avsc-from-external-jar/build.gradle similarity index 100% rename from examples/avsc-from-external-jar/build.gradle rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/build.gradle diff --git a/examples/avsc-from-external-jar/external-files/Breed.avsc b/lang/java/gradle-plugin/examples/avsc-from-external-jar/external-files/Breed.avsc similarity index 100% rename from examples/avsc-from-external-jar/external-files/Breed.avsc rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/external-files/Breed.avsc diff --git a/examples/avsc-from-external-jar/external-files/Cat.avsc b/lang/java/gradle-plugin/examples/avsc-from-external-jar/external-files/Cat.avsc similarity index 100% rename from examples/avsc-from-external-jar/external-files/Cat.avsc rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/external-files/Cat.avsc diff --git a/examples/avsc-from-external-jar/external-libs/schema.jar b/lang/java/gradle-plugin/examples/avsc-from-external-jar/external-libs/schema.jar similarity index 100% rename from examples/avsc-from-external-jar/external-libs/schema.jar rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/external-libs/schema.jar diff --git a/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.jar b/lang/java/gradle-plugin/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.jar rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties b/lang/java/gradle-plugin/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/avsc-from-external-jar/gradlew b/lang/java/gradle-plugin/examples/avsc-from-external-jar/gradlew similarity index 100% rename from examples/avsc-from-external-jar/gradlew rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/gradlew diff --git a/examples/avsc-from-external-jar/gradlew.bat b/lang/java/gradle-plugin/examples/avsc-from-external-jar/gradlew.bat similarity index 100% rename from examples/avsc-from-external-jar/gradlew.bat rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/gradlew.bat diff --git a/examples/avsc-from-external-jar/settings.gradle b/lang/java/gradle-plugin/examples/avsc-from-external-jar/settings.gradle similarity index 100% rename from examples/avsc-from-external-jar/settings.gradle rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/settings.gradle diff --git a/examples/avsc-from-external-jar/src/main/avro/Cat.avsc b/lang/java/gradle-plugin/examples/avsc-from-external-jar/src/main/avro/Cat.avsc similarity index 100% rename from examples/avsc-from-external-jar/src/main/avro/Cat.avsc rename to lang/java/gradle-plugin/examples/avsc-from-external-jar/src/main/avro/Cat.avsc diff --git a/examples/avsc-from-subproject/README.md b/lang/java/gradle-plugin/examples/avsc-from-subproject/README.md similarity index 100% rename from examples/avsc-from-subproject/README.md rename to lang/java/gradle-plugin/examples/avsc-from-subproject/README.md diff --git a/examples/avsc-from-subproject/cat/build.gradle b/lang/java/gradle-plugin/examples/avsc-from-subproject/cat/build.gradle similarity index 100% rename from examples/avsc-from-subproject/cat/build.gradle rename to lang/java/gradle-plugin/examples/avsc-from-subproject/cat/build.gradle diff --git a/examples/avsc-from-subproject/cat/src/main/avro/Cat.avsc b/lang/java/gradle-plugin/examples/avsc-from-subproject/cat/src/main/avro/Cat.avsc similarity index 100% rename from examples/avsc-from-subproject/cat/src/main/avro/Cat.avsc rename to lang/java/gradle-plugin/examples/avsc-from-subproject/cat/src/main/avro/Cat.avsc diff --git a/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.jar b/lang/java/gradle-plugin/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.jar rename to lang/java/gradle-plugin/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties b/lang/java/gradle-plugin/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties rename to lang/java/gradle-plugin/examples/avsc-from-subproject/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/avsc-from-subproject/gradlew b/lang/java/gradle-plugin/examples/avsc-from-subproject/gradlew similarity index 100% rename from examples/avsc-from-subproject/gradlew rename to lang/java/gradle-plugin/examples/avsc-from-subproject/gradlew diff --git a/examples/avsc-from-subproject/gradlew.bat b/lang/java/gradle-plugin/examples/avsc-from-subproject/gradlew.bat similarity index 100% rename from examples/avsc-from-subproject/gradlew.bat rename to lang/java/gradle-plugin/examples/avsc-from-subproject/gradlew.bat diff --git a/examples/avsc-from-subproject/schema/build.gradle b/lang/java/gradle-plugin/examples/avsc-from-subproject/schema/build.gradle similarity index 100% rename from examples/avsc-from-subproject/schema/build.gradle rename to lang/java/gradle-plugin/examples/avsc-from-subproject/schema/build.gradle diff --git a/examples/avsc-from-subproject/schema/src/main/avro/Breed.avsc b/lang/java/gradle-plugin/examples/avsc-from-subproject/schema/src/main/avro/Breed.avsc similarity index 100% rename from examples/avsc-from-subproject/schema/src/main/avro/Breed.avsc rename to lang/java/gradle-plugin/examples/avsc-from-subproject/schema/src/main/avro/Breed.avsc diff --git a/examples/avsc-from-subproject/settings.gradle b/lang/java/gradle-plugin/examples/avsc-from-subproject/settings.gradle similarity index 100% rename from examples/avsc-from-subproject/settings.gradle rename to lang/java/gradle-plugin/examples/avsc-from-subproject/settings.gradle diff --git a/examples/default-custom-types/README.md b/lang/java/gradle-plugin/examples/default-custom-types/README.md similarity index 100% rename from examples/default-custom-types/README.md rename to lang/java/gradle-plugin/examples/default-custom-types/README.md diff --git a/examples/default-custom-types/build.gradle b/lang/java/gradle-plugin/examples/default-custom-types/build.gradle similarity index 100% rename from examples/default-custom-types/build.gradle rename to lang/java/gradle-plugin/examples/default-custom-types/build.gradle diff --git a/examples/default-custom-types/buildSrc/build.gradle b/lang/java/gradle-plugin/examples/default-custom-types/buildSrc/build.gradle similarity index 100% rename from examples/default-custom-types/buildSrc/build.gradle rename to lang/java/gradle-plugin/examples/default-custom-types/buildSrc/build.gradle diff --git a/examples/default-custom-types/buildSrc/src/main/java/custom/AvroConventionPlugin.java b/lang/java/gradle-plugin/examples/default-custom-types/buildSrc/src/main/java/custom/AvroConventionPlugin.java similarity index 100% rename from examples/default-custom-types/buildSrc/src/main/java/custom/AvroConventionPlugin.java rename to lang/java/gradle-plugin/examples/default-custom-types/buildSrc/src/main/java/custom/AvroConventionPlugin.java diff --git a/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneConversion.java b/lang/java/gradle-plugin/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneConversion.java similarity index 100% rename from examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneConversion.java rename to lang/java/gradle-plugin/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneConversion.java diff --git a/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalType.java b/lang/java/gradle-plugin/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalType.java similarity index 100% rename from examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalType.java rename to lang/java/gradle-plugin/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalType.java diff --git a/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalTypeFactory.java b/lang/java/gradle-plugin/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalTypeFactory.java similarity index 100% rename from examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalTypeFactory.java rename to lang/java/gradle-plugin/examples/default-custom-types/buildSrc/src/main/java/custom/TimeZoneLogicalTypeFactory.java diff --git a/examples/default-custom-types/gradle/wrapper/gradle-wrapper.jar b/lang/java/gradle-plugin/examples/default-custom-types/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from examples/default-custom-types/gradle/wrapper/gradle-wrapper.jar rename to lang/java/gradle-plugin/examples/default-custom-types/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/default-custom-types/gradle/wrapper/gradle-wrapper.properties b/lang/java/gradle-plugin/examples/default-custom-types/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from examples/default-custom-types/gradle/wrapper/gradle-wrapper.properties rename to lang/java/gradle-plugin/examples/default-custom-types/gradle/wrapper/gradle-wrapper.properties diff --git a/examples/default-custom-types/gradlew b/lang/java/gradle-plugin/examples/default-custom-types/gradlew similarity index 100% rename from examples/default-custom-types/gradlew rename to lang/java/gradle-plugin/examples/default-custom-types/gradlew diff --git a/examples/default-custom-types/gradlew.bat b/lang/java/gradle-plugin/examples/default-custom-types/gradlew.bat similarity index 100% rename from examples/default-custom-types/gradlew.bat rename to lang/java/gradle-plugin/examples/default-custom-types/gradlew.bat diff --git a/examples/default-custom-types/settings.gradle b/lang/java/gradle-plugin/examples/default-custom-types/settings.gradle similarity index 100% rename from examples/default-custom-types/settings.gradle rename to lang/java/gradle-plugin/examples/default-custom-types/settings.gradle diff --git a/examples/default-custom-types/src/main/avro/customConversion.avsc b/lang/java/gradle-plugin/examples/default-custom-types/src/main/avro/customConversion.avsc similarity index 100% rename from examples/default-custom-types/src/main/avro/customConversion.avsc rename to lang/java/gradle-plugin/examples/default-custom-types/src/main/avro/customConversion.avsc diff --git a/examples/default-custom-types/src/main/java/custom/TimeZoneConversion.java b/lang/java/gradle-plugin/examples/default-custom-types/src/main/java/custom/TimeZoneConversion.java similarity index 100% rename from examples/default-custom-types/src/main/java/custom/TimeZoneConversion.java rename to lang/java/gradle-plugin/examples/default-custom-types/src/main/java/custom/TimeZoneConversion.java diff --git a/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalType.java b/lang/java/gradle-plugin/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalType.java similarity index 100% rename from examples/default-custom-types/src/main/java/custom/TimeZoneLogicalType.java rename to lang/java/gradle-plugin/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalType.java diff --git a/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalTypeFactory.java b/lang/java/gradle-plugin/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalTypeFactory.java similarity index 100% rename from examples/default-custom-types/src/main/java/custom/TimeZoneLogicalTypeFactory.java rename to lang/java/gradle-plugin/examples/default-custom-types/src/main/java/custom/TimeZoneLogicalTypeFactory.java diff --git a/gradle.properties b/lang/java/gradle-plugin/gradle.properties similarity index 100% rename from gradle.properties rename to lang/java/gradle-plugin/gradle.properties diff --git a/gradle/wrapper/gradle-wrapper.jar b/lang/java/gradle-plugin/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from gradle/wrapper/gradle-wrapper.jar rename to lang/java/gradle-plugin/gradle/wrapper/gradle-wrapper.jar diff --git a/gradle/wrapper/gradle-wrapper.properties b/lang/java/gradle-plugin/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from gradle/wrapper/gradle-wrapper.properties rename to lang/java/gradle-plugin/gradle/wrapper/gradle-wrapper.properties diff --git a/gradlew b/lang/java/gradle-plugin/gradlew similarity index 100% rename from gradlew rename to lang/java/gradle-plugin/gradlew diff --git a/gradlew.bat b/lang/java/gradle-plugin/gradlew.bat similarity index 100% rename from gradlew.bat rename to lang/java/gradle-plugin/gradlew.bat diff --git a/scripts/run-avro-cli.sh b/lang/java/gradle-plugin/scripts/run-avro-cli.sh similarity index 100% rename from scripts/run-avro-cli.sh rename to lang/java/gradle-plugin/scripts/run-avro-cli.sh diff --git a/scripts/run-compile-schema.sh b/lang/java/gradle-plugin/scripts/run-compile-schema.sh similarity index 100% rename from scripts/run-compile-schema.sh rename to lang/java/gradle-plugin/scripts/run-compile-schema.sh diff --git a/settings.gradle b/lang/java/gradle-plugin/settings.gradle similarity index 100% rename from settings.gradle rename to lang/java/gradle-plugin/settings.gradle diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroBasePlugin.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroExtension.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroPlugin.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroUtils.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroUtils.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroUtils.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/AvroUtils.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/Constants.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/DefaultAvroExtension.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/Enums.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/Enums.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/Enums.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/Enums.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileExtensionSpec.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileExtensionSpec.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/FileExtensionSpec.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileExtensionSpec.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileState.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileState.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/FileState.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileState.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileUtils.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileUtils.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/FileUtils.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/FileUtils.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/FilenameUtils.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/FilenameUtils.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/FilenameUtils.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/FilenameUtils.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroJavaTask.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTask.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroSchemaTask.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroSchemaTask.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroSchemaTask.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GenerateAvroSchemaTask.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleCompatibility.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleFeatures.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/GradleVersions.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/MapUtils.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/MapUtils.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/MapUtils.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/MapUtils.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/OutputDirTask.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/OutputDirTask.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/OutputDirTask.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/OutputDirTask.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/ProcessingState.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/ProcessingState.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/ProcessingState.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/ProcessingState.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTask.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTask.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTask.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTask.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/SchemaResolver.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/SchemaResolver.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/SchemaResolver.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/SchemaResolver.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/SetBuilder.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/SetBuilder.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/SetBuilder.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/SetBuilder.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/Strings.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/Strings.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/Strings.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/Strings.java diff --git a/src/main/java/com/github/davidmc24/gradle/plugin/avro/TypeState.java b/lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/TypeState.java similarity index 100% rename from src/main/java/com/github/davidmc24/gradle/plugin/avro/TypeState.java rename to lang/java/gradle-plugin/src/main/java/com/github/davidmc24/gradle/plugin/avro/TypeState.java diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroBasePluginFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroPluginSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroUtilsSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroUtilsSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroUtilsSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/AvroUtilsSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/BuildCacheSupportFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/CustomConversionFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/DuplicateHandlingFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EncodingFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EncodingFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EncodingFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EncodingFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/EnumHandlingFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ExamplesFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ExamplesFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ExamplesFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ExamplesFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/FunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/GenerateAvroProtocolTaskFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/IntellijFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/KotlinDSLCompatibilityFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/OptionsFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/ResolveAvroDependenciesTaskFunctionalSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/SchemaResolverSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/SchemaResolverSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/SchemaResolverSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/SchemaResolverSpec.groovy diff --git a/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/StringsSpec.groovy b/lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/StringsSpec.groovy similarity index 100% rename from src/test/groovy/com/github/davidmc24/gradle/plugin/avro/StringsSpec.groovy rename to lang/java/gradle-plugin/src/test/groovy/com/github/davidmc24/gradle/plugin/avro/StringsSpec.groovy diff --git a/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java b/lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java similarity index 100% rename from src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java rename to lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/CommentGenerator.java diff --git a/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneConversion.java b/lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneConversion.java similarity index 100% rename from src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneConversion.java rename to lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneConversion.java diff --git a/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java b/lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java similarity index 100% rename from src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java rename to lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalType.java diff --git a/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java b/lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java similarity index 100% rename from src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java rename to lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimeZoneLogicalTypeFactory.java diff --git a/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java b/lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java similarity index 100% rename from src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java rename to lang/java/gradle-plugin/src/test/java/com/github/davidmc24/gradle/plugin/avro/test/custom/TimestampGenerator.java diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/Message.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/Message.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/Message.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/Message.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avpr b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avpr similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avpr rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avpr diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/customConversion.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/dependent.avdl b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/dependent.avdl similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/dependent.avdl rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/dependent.avdl diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Cat.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Cat.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Cat.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Cat.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed1.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed1.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed1.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed1.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed2.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed2.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed2.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed2.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed3.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed3.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed3.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/ContainsFixed3.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Dog.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Dog.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Dog.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Dog.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Fish.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Fish.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Fish.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Fish.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Person.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Person.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Person.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Person.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Spider.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Spider.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Spider.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/Spider.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/duplicate/duplicateInSingleFile.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumField.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumField.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumField.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumField.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumMalformed.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumMalformed.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumMalformed.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumMalformed.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumSimple.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumSimple.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumSimple.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumSimple.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUnion.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUnion.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUnion.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUnion.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUseSimple.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUseSimple.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUseSimple.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/enumUseSimple.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/helloWorld.kt b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/helloWorld.kt similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/helloWorld.kt rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/helloWorld.kt diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/idioma.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/idioma.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/idioma.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/idioma.avsc diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop-1.9.avdl b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop-1.9.avdl similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop-1.9.avdl rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop-1.9.avdl diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop.avdl b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop.avdl similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop.avdl rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/interop.avdl diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/mail.avpr b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/mail.avpr similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/mail.avpr rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/mail.avpr diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test.avdl b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test.avdl similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test.avdl rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test.avdl diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test_same_protocol.avdl b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test_same_protocol.avdl similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test_same_protocol.avdl rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v1/test_same_protocol.avdl diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v2/test.avdl b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v2/test.avdl similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v2/test.avdl rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/namespaced-idl/v2/test.avdl diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record-tools.vm b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record-tools.vm similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/record-tools.vm rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record-tools.vm diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/record.vm diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/shared.avdl b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/shared.avdl similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/shared.avdl rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/shared.avdl diff --git a/src/test/resources/com/github/davidmc24/gradle/plugin/avro/user.avsc b/lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/user.avsc similarity index 100% rename from src/test/resources/com/github/davidmc24/gradle/plugin/avro/user.avsc rename to lang/java/gradle-plugin/src/test/resources/com/github/davidmc24/gradle/plugin/avro/user.avsc diff --git a/src/test/resources/examples/inline/Cat.avsc b/lang/java/gradle-plugin/src/test/resources/examples/inline/Cat.avsc similarity index 100% rename from src/test/resources/examples/inline/Cat.avsc rename to lang/java/gradle-plugin/src/test/resources/examples/inline/Cat.avsc diff --git a/src/test/resources/examples/separate/Breed.avsc b/lang/java/gradle-plugin/src/test/resources/examples/separate/Breed.avsc similarity index 100% rename from src/test/resources/examples/separate/Breed.avsc rename to lang/java/gradle-plugin/src/test/resources/examples/separate/Breed.avsc diff --git a/src/test/resources/examples/separate/Cat.avsc b/lang/java/gradle-plugin/src/test/resources/examples/separate/Cat.avsc similarity index 100% rename from src/test/resources/examples/separate/Cat.avsc rename to lang/java/gradle-plugin/src/test/resources/examples/separate/Cat.avsc diff --git a/src/test/resources/resolver/SimpleEnum.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/SimpleEnum.avsc similarity index 100% rename from src/test/resources/resolver/SimpleEnum.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/SimpleEnum.avsc diff --git a/src/test/resources/resolver/SimpleFixed.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/SimpleFixed.avsc similarity index 100% rename from src/test/resources/resolver/SimpleFixed.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/SimpleFixed.avsc diff --git a/src/test/resources/resolver/SimpleRecord.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/SimpleRecord.avsc similarity index 100% rename from src/test/resources/resolver/SimpleRecord.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/SimpleRecord.avsc diff --git a/src/test/resources/resolver/UseArray.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseArray.avsc similarity index 100% rename from src/test/resources/resolver/UseArray.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseArray.avsc diff --git a/src/test/resources/resolver/UseArrayWithType.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseArrayWithType.avsc similarity index 100% rename from src/test/resources/resolver/UseArrayWithType.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseArrayWithType.avsc diff --git a/src/test/resources/resolver/UseEnum.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseEnum.avsc similarity index 100% rename from src/test/resources/resolver/UseEnum.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseEnum.avsc diff --git a/src/test/resources/resolver/UseEnumWithType.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseEnumWithType.avsc similarity index 100% rename from src/test/resources/resolver/UseEnumWithType.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseEnumWithType.avsc diff --git a/src/test/resources/resolver/UseFixed.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseFixed.avsc similarity index 100% rename from src/test/resources/resolver/UseFixed.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseFixed.avsc diff --git a/src/test/resources/resolver/UseFixedWithType.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseFixedWithType.avsc similarity index 100% rename from src/test/resources/resolver/UseFixedWithType.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseFixedWithType.avsc diff --git a/src/test/resources/resolver/UseMap.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseMap.avsc similarity index 100% rename from src/test/resources/resolver/UseMap.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseMap.avsc diff --git a/src/test/resources/resolver/UseMapWithType.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseMapWithType.avsc similarity index 100% rename from src/test/resources/resolver/UseMapWithType.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseMapWithType.avsc diff --git a/src/test/resources/resolver/UseRecord.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseRecord.avsc similarity index 100% rename from src/test/resources/resolver/UseRecord.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseRecord.avsc diff --git a/src/test/resources/resolver/UseRecordWithType.avsc b/lang/java/gradle-plugin/src/test/resources/resolver/UseRecordWithType.avsc similarity index 100% rename from src/test/resources/resolver/UseRecordWithType.avsc rename to lang/java/gradle-plugin/src/test/resources/resolver/UseRecordWithType.avsc diff --git a/test-project-kotlin/build.gradle.kts b/lang/java/gradle-plugin/test-project-kotlin/build.gradle.kts similarity index 100% rename from test-project-kotlin/build.gradle.kts rename to lang/java/gradle-plugin/test-project-kotlin/build.gradle.kts diff --git a/test-project-kotlin/gradle/wrapper/gradle-wrapper.jar b/lang/java/gradle-plugin/test-project-kotlin/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from test-project-kotlin/gradle/wrapper/gradle-wrapper.jar rename to lang/java/gradle-plugin/test-project-kotlin/gradle/wrapper/gradle-wrapper.jar diff --git a/test-project-kotlin/gradle/wrapper/gradle-wrapper.properties b/lang/java/gradle-plugin/test-project-kotlin/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from test-project-kotlin/gradle/wrapper/gradle-wrapper.properties rename to lang/java/gradle-plugin/test-project-kotlin/gradle/wrapper/gradle-wrapper.properties diff --git a/test-project-kotlin/gradlew b/lang/java/gradle-plugin/test-project-kotlin/gradlew similarity index 100% rename from test-project-kotlin/gradlew rename to lang/java/gradle-plugin/test-project-kotlin/gradlew diff --git a/test-project-kotlin/gradlew.bat b/lang/java/gradle-plugin/test-project-kotlin/gradlew.bat similarity index 100% rename from test-project-kotlin/gradlew.bat rename to lang/java/gradle-plugin/test-project-kotlin/gradlew.bat diff --git a/test-project-kotlin/settings.gradle.kts b/lang/java/gradle-plugin/test-project-kotlin/settings.gradle.kts similarity index 100% rename from test-project-kotlin/settings.gradle.kts rename to lang/java/gradle-plugin/test-project-kotlin/settings.gradle.kts diff --git a/test-project-kotlin/src/main/avro/BuggyRecord.avsc b/lang/java/gradle-plugin/test-project-kotlin/src/main/avro/BuggyRecord.avsc similarity index 100% rename from test-project-kotlin/src/main/avro/BuggyRecord.avsc rename to lang/java/gradle-plugin/test-project-kotlin/src/main/avro/BuggyRecord.avsc diff --git a/test-project-kotlin/src/main/avro/BuggyRecordWorkaround.avsc b/lang/java/gradle-plugin/test-project-kotlin/src/main/avro/BuggyRecordWorkaround.avsc similarity index 100% rename from test-project-kotlin/src/main/avro/BuggyRecordWorkaround.avsc rename to lang/java/gradle-plugin/test-project-kotlin/src/main/avro/BuggyRecordWorkaround.avsc diff --git a/test-project-kotlin/src/main/avro/Messages.avsc b/lang/java/gradle-plugin/test-project-kotlin/src/main/avro/Messages.avsc similarity index 100% rename from test-project-kotlin/src/main/avro/Messages.avsc rename to lang/java/gradle-plugin/test-project-kotlin/src/main/avro/Messages.avsc diff --git a/test-project-kotlin/src/main/avro/UUIDTestRecord.avsc b/lang/java/gradle-plugin/test-project-kotlin/src/main/avro/UUIDTestRecord.avsc similarity index 100% rename from test-project-kotlin/src/main/avro/UUIDTestRecord.avsc rename to lang/java/gradle-plugin/test-project-kotlin/src/main/avro/UUIDTestRecord.avsc diff --git a/test-project-kotlin/src/main/java/project/SystemUtil.java b/lang/java/gradle-plugin/test-project-kotlin/src/main/java/project/SystemUtil.java similarity index 100% rename from test-project-kotlin/src/main/java/project/SystemUtil.java rename to lang/java/gradle-plugin/test-project-kotlin/src/main/java/project/SystemUtil.java diff --git a/test-project-kotlin/src/test/java/project/CLIComparisonTest.java b/lang/java/gradle-plugin/test-project-kotlin/src/test/java/project/CLIComparisonTest.java similarity index 100% rename from test-project-kotlin/src/test/java/project/CLIComparisonTest.java rename to lang/java/gradle-plugin/test-project-kotlin/src/test/java/project/CLIComparisonTest.java diff --git a/test-project-kotlin/src/test/java/project/CLIUtil.java b/lang/java/gradle-plugin/test-project-kotlin/src/test/java/project/CLIUtil.java similarity index 100% rename from test-project-kotlin/src/test/java/project/CLIUtil.java rename to lang/java/gradle-plugin/test-project-kotlin/src/test/java/project/CLIUtil.java diff --git a/test-project-kotlin/src/test/java/project/RandomRecordTest.java b/lang/java/gradle-plugin/test-project-kotlin/src/test/java/project/RandomRecordTest.java similarity index 100% rename from test-project-kotlin/src/test/java/project/RandomRecordTest.java rename to lang/java/gradle-plugin/test-project-kotlin/src/test/java/project/RandomRecordTest.java diff --git a/test-project-kotlin/src/test/java/project/RecordTest.java b/lang/java/gradle-plugin/test-project-kotlin/src/test/java/project/RecordTest.java similarity index 100% rename from test-project-kotlin/src/test/java/project/RecordTest.java rename to lang/java/gradle-plugin/test-project-kotlin/src/test/java/project/RecordTest.java diff --git a/test-project/build.gradle b/lang/java/gradle-plugin/test-project/build.gradle similarity index 100% rename from test-project/build.gradle rename to lang/java/gradle-plugin/test-project/build.gradle diff --git a/test-project/gradle/wrapper/gradle-wrapper.jar b/lang/java/gradle-plugin/test-project/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from test-project/gradle/wrapper/gradle-wrapper.jar rename to lang/java/gradle-plugin/test-project/gradle/wrapper/gradle-wrapper.jar diff --git a/test-project/gradle/wrapper/gradle-wrapper.properties b/lang/java/gradle-plugin/test-project/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from test-project/gradle/wrapper/gradle-wrapper.properties rename to lang/java/gradle-plugin/test-project/gradle/wrapper/gradle-wrapper.properties diff --git a/test-project/gradlew b/lang/java/gradle-plugin/test-project/gradlew similarity index 100% rename from test-project/gradlew rename to lang/java/gradle-plugin/test-project/gradlew diff --git a/test-project/gradlew.bat b/lang/java/gradle-plugin/test-project/gradlew.bat similarity index 100% rename from test-project/gradlew.bat rename to lang/java/gradle-plugin/test-project/gradlew.bat diff --git a/test-project/settings.gradle b/lang/java/gradle-plugin/test-project/settings.gradle similarity index 100% rename from test-project/settings.gradle rename to lang/java/gradle-plugin/test-project/settings.gradle diff --git a/test-project/src/main/avro/BuggyRecord.avsc b/lang/java/gradle-plugin/test-project/src/main/avro/BuggyRecord.avsc similarity index 100% rename from test-project/src/main/avro/BuggyRecord.avsc rename to lang/java/gradle-plugin/test-project/src/main/avro/BuggyRecord.avsc diff --git a/test-project/src/main/avro/BuggyRecordWorkaround.avsc b/lang/java/gradle-plugin/test-project/src/main/avro/BuggyRecordWorkaround.avsc similarity index 100% rename from test-project/src/main/avro/BuggyRecordWorkaround.avsc rename to lang/java/gradle-plugin/test-project/src/main/avro/BuggyRecordWorkaround.avsc diff --git a/test-project/src/main/avro/Messages.avsc b/lang/java/gradle-plugin/test-project/src/main/avro/Messages.avsc similarity index 100% rename from test-project/src/main/avro/Messages.avsc rename to lang/java/gradle-plugin/test-project/src/main/avro/Messages.avsc diff --git a/test-project/src/main/avro/UUIDTestRecord.avsc b/lang/java/gradle-plugin/test-project/src/main/avro/UUIDTestRecord.avsc similarity index 100% rename from test-project/src/main/avro/UUIDTestRecord.avsc rename to lang/java/gradle-plugin/test-project/src/main/avro/UUIDTestRecord.avsc diff --git a/test-project/src/main/java/project/SystemUtil.java b/lang/java/gradle-plugin/test-project/src/main/java/project/SystemUtil.java similarity index 100% rename from test-project/src/main/java/project/SystemUtil.java rename to lang/java/gradle-plugin/test-project/src/main/java/project/SystemUtil.java diff --git a/test-project/src/test/java/project/CLIComparisonTest.java b/lang/java/gradle-plugin/test-project/src/test/java/project/CLIComparisonTest.java similarity index 100% rename from test-project/src/test/java/project/CLIComparisonTest.java rename to lang/java/gradle-plugin/test-project/src/test/java/project/CLIComparisonTest.java diff --git a/test-project/src/test/java/project/CLIUtil.java b/lang/java/gradle-plugin/test-project/src/test/java/project/CLIUtil.java similarity index 100% rename from test-project/src/test/java/project/CLIUtil.java rename to lang/java/gradle-plugin/test-project/src/test/java/project/CLIUtil.java diff --git a/test-project/src/test/java/project/RandomRecordTest.java b/lang/java/gradle-plugin/test-project/src/test/java/project/RandomRecordTest.java similarity index 100% rename from test-project/src/test/java/project/RandomRecordTest.java rename to lang/java/gradle-plugin/test-project/src/test/java/project/RandomRecordTest.java diff --git a/test-project/src/test/java/project/RecordTest.java b/lang/java/gradle-plugin/test-project/src/test/java/project/RecordTest.java similarity index 100% rename from test-project/src/test/java/project/RecordTest.java rename to lang/java/gradle-plugin/test-project/src/test/java/project/RecordTest.java