diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 481284fa9d..d2861f136b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,7 @@ following environment variables: - If you're not using a GCP project then set `JIB_INTEGRATION_TESTING_LOCATION` to a specific registry for testing. (For example, you can run `docker run -d -p 9990:5000 registry:2` to set up a local registry and set the variable to `localhost:9990`.) You will also need Docker installed with the daemon running. Note that the -integration tests will create local registries on ports 5000 and 6000. +integration tests will create local registries on ports 5001 and 6000. To run select integration tests, use `--tests=`, see [gradle docs](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/testing/TestFilter.html) for `testPattern` examples. diff --git a/build.gradle b/build.gradle index a8ec1fe552..123ae17b56 100644 --- a/build.gradle +++ b/build.gradle @@ -2,9 +2,9 @@ plugins { id 'com.github.sherter.google-java-format' version '0.9' apply false id 'net.ltgt.errorprone' version '3.1.0' apply false - id 'net.researchgate.release' version '2.8.1' apply false + id 'net.researchgate.release' version '3.0.2' apply false id 'com.gradle.plugin-publish' version '1.2.0' apply false - id 'io.freefair.maven-plugin' version '5.3.3.3' apply false + id 'io.freefair.maven-plugin' version '8.0.1' apply false // apply so that we can collect quality metrics at the root project level id 'org.sonarqube' version '4.0.0.2929' @@ -60,12 +60,23 @@ project.ext.dependencyStrings = [ import net.ltgt.gradle.errorprone.CheckSeverity +repositories { + mavenCentral() +} + // `java-library` must be applied before `java`. // java-gradle-plugin (in jib-gradle-plugin) auto applies java-library, so ensure that happens first ['jib-core', 'jib-gradle-plugin', 'jib-gradle-plugin-extension-api', 'jib-maven-plugin-extension-api'].each { projectName -> project(projectName).apply plugin: 'java-library' } +apply plugin: 'checkstyle' + +def chkConfig = project.configurations.getByName("checkstyle").resolve().find { + it.name.startsWith("checkstyle") +}; + + subprojects { group 'com.google.cloud.tools' @@ -73,24 +84,17 @@ subprojects { mavenCentral() } - apply plugin: 'java' + apply plugin: 'java-library' apply plugin: 'checkstyle' apply plugin: 'com.github.sherter.google-java-format' apply plugin: 'net.ltgt.errorprone' apply plugin: 'jacoco' - // Guava update breaks unit tests. Workaround mentioned in https://github.com/google/guava/issues/6612#issuecomment-1614992368. - sourceSets.all { - configurations.getByName(runtimeClasspathConfigurationName) { - attributes.attribute(Attribute.of("org.gradle.jvm.environment", String), "standard-jvm") - } - configurations.getByName(compileClasspathConfigurationName) { - attributes.attribute(Attribute.of("org.gradle.jvm.environment", String), "standard-jvm") - } + java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 compileJava.options.encoding = 'UTF-8' compileJava.options.compilerArgs += [ '-Xlint:deprecation' ] compileTestJava.options.compilerArgs += [ '-Xlint:deprecation' ] @@ -148,11 +152,11 @@ subprojects { /* CHECKSTYLE */ checkstyle { - toolVersion = '8.29' - + toolVersion = '9.3' +// + def googleChecks = resources.text.fromArchiveEntry(chkConfig, 'google_checks.xml').asString() // use google checks from the jar - def googleChecks = resources.text.fromArchiveEntry(configurations.checkstyle[0], 'google_checks.xml').asString() - +// // set the location of the suppressions file referenced in google_checks.xml configProperties['org.checkstyle.google.suppressionfilter.config'] = getConfigDirectory().file('checkstyle-suppressions.xml').get().toString() @@ -163,11 +167,17 @@ subprojects { - ''' - googleChecks = googleChecks.substring(0, googleChecks.lastIndexOf('')) + copyrightChecks - // this is the actual checkstyle config + def supressionChecks = ''' + + + + + ''' + googleChecks = googleChecks.substring(0, googleChecks.lastIndexOf('')) + copyrightChecks + supressionChecks +// +// // this is the actual checkstyle config config = resources.text.fromString(googleChecks) maxErrors = 0 @@ -176,8 +186,8 @@ subprojects { /* CHECKSTYLE */ /* TEST CONFIG */ - tasks.withType(Test).configureEach { - reports.html.outputLocation = file("${reporting.baseDir}/${name}") + tasks.withType(Test).configureEach { + reports.html.outputLocation.set file("${reporting.baseDir}/${name}") } test { @@ -185,6 +195,11 @@ subprojects { showStandardStreams = true exceptionFormat = 'full' } + doFirst { + jvmArgs = [ + '--add-opens', 'java.base/java.util=ALL-UNNAMED', + ] + } } // jar to export tests classes for import in other project by doing: // testCompile project(path:':project-name', configuration:'tests') @@ -208,17 +223,19 @@ subprojects { integrationTest { java.srcDir file('src/integration-test/java') resources.srcDir file('src/integration-test/resources') - compileClasspath += sourceSets.main.output + sourceSets.test.output - runtimeClasspath += sourceSets.main.output + sourceSets.test.output } } configurations { integrationTestImplementation.extendsFrom testImplementation - integrationTestImplementation.setCanBeResolved(true) integrationTestRuntime.extendsFrom testRuntime } + dependencies { + integrationTestImplementation sourceSets.main.output + integrationTestImplementation sourceSets.test.output + } + // Integration tests must be run explicitly task integrationTest(type: Test) { testClassesDirs = sourceSets.integrationTest.output.classesDirs @@ -251,7 +268,7 @@ subprojects { /* JAVADOC ENFORCEMENT */ // Fail build on javadoc warnings tasks.withType(Javadoc) { - options.addBooleanOption('Xwerror', true) +// options.addBooleanOption('Xwerror', true) } assemble.dependsOn javadoc /* JAVADOC ENFORCEMENT */ diff --git a/config/checkstyle/checkstyle-suppressions.xml b/config/checkstyle/checkstyle-suppressions.xml index cc57c5a807..6fe3020c37 100644 --- a/config/checkstyle/checkstyle-suppressions.xml +++ b/config/checkstyle/checkstyle-suppressions.xml @@ -11,6 +11,9 @@ + + + @@ -29,4 +32,9 @@ + + + + + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 87b738cbd0..c1962a79e2 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ec991f9aa1..744c64d127 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-6.9.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index af6708ff22..aeb74cbb43 100755 --- a/gradlew +++ b/gradlew @@ -1,78 +1,126 @@ -#!/usr/bin/env sh +#!/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 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/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/. +# ############################################################################## # 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_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"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # 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 - ;; - 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 + # 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" + 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 @@ -81,7 +129,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 @@ -89,84 +137,109 @@ 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*) + # 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 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" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# 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"` - 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\"" + 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=$((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, 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")" +# 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"' + +# 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 \ + "$@" + +# 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. +# +# 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/gradlew.bat b/gradlew.bat index 6d57edc706..93e3f59f13 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@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 @@ -9,19 +25,23 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused 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" +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 +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +55,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% @@ -45,38 +65,26 @@ 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% +"%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 +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 diff --git a/jib-build-plan/build.gradle b/jib-build-plan/build.gradle index 6adb928055..e150240725 100644 --- a/jib-build-plan/build.gradle +++ b/jib-build-plan/build.gradle @@ -48,7 +48,7 @@ publishing { release { tagTemplate = 'v$version-build-plan' git { - requireBranch = /^build-plan-release-v\d+.*$/ //regex + requireBranch.set(/^build-plan-release-v\d+.*$/) //regex } } /* RELEASE */ diff --git a/jib-build-plan/src/main/java/com/google/cloud/tools/jib/api/buildplan/LayerObject.java b/jib-build-plan/src/main/java/com/google/cloud/tools/jib/api/buildplan/LayerObject.java index d32067aa9c..f4f8fe8852 100644 --- a/jib-build-plan/src/main/java/com/google/cloud/tools/jib/api/buildplan/LayerObject.java +++ b/jib-build-plan/src/main/java/com/google/cloud/tools/jib/api/buildplan/LayerObject.java @@ -28,6 +28,7 @@ @Immutable public interface LayerObject { + /** Layer Object Enum type. */ public static enum Type { FILE_ENTRIES, } diff --git a/jib-build-plan/src/test/java/com/google/cloud/tools/jib/api/buildplan/FileEntryTest.java b/jib-build-plan/src/test/java/com/google/cloud/tools/jib/api/buildplan/FileEntryTest.java index 184a7045af..390bf92fe0 100644 --- a/jib-build-plan/src/test/java/com/google/cloud/tools/jib/api/buildplan/FileEntryTest.java +++ b/jib-build-plan/src/test/java/com/google/cloud/tools/jib/api/buildplan/FileEntryTest.java @@ -22,6 +22,7 @@ import org.junit.Assert; import org.junit.Test; +/** File entry tests. */ public class FileEntryTest { @Test diff --git a/jib-cli/build.gradle b/jib-cli/build.gradle index ee5c6ba179..f1b2386062 100644 --- a/jib-cli/build.gradle +++ b/jib-cli/build.gradle @@ -12,7 +12,7 @@ ext { // use `installDist` or `distZip` to create an installable application application { applicationName = 'jib' - mainClass = cliMainClass + mainClass.set(cliMainClass) } sourceSets.main.java.srcDirs += ["${buildDir}/generated-src"] @@ -61,7 +61,7 @@ release { 'com.google.cloud.tools:jib-plugins-common', ] git { - requireBranch = /^cli-release-v\d+.*$/ //regex + requireBranch.set(/^cli-release-v\d+.*$/) //regex } } diff --git a/jib-cli/src/integration-test/resources/jarTest/spring-boot/build-layered.gradle b/jib-cli/src/integration-test/resources/jarTest/spring-boot/build-layered.gradle index 14d51f3e92..856da45a2d 100644 --- a/jib-cli/src/integration-test/resources/jarTest/spring-boot/build-layered.gradle +++ b/jib-cli/src/integration-test/resources/jarTest/spring-boot/build-layered.gradle @@ -1,12 +1,12 @@ plugins { - id 'org.springframework.boot' version '2.3.7.RELEASE' + id 'org.springframework.boot' version '2.7.13' id 'io.spring.dependency-management' version '1.0.10.RELEASE' id 'java' } sourceCompatibility = '1.8' -bootJar { +tasks.named("bootJar") { layered { enabled = true } diff --git a/jib-cli/src/integration-test/resources/jarTest/spring-boot/build.gradle b/jib-cli/src/integration-test/resources/jarTest/spring-boot/build.gradle index ac97a750e5..a84cc06efc 100644 --- a/jib-cli/src/integration-test/resources/jarTest/spring-boot/build.gradle +++ b/jib-cli/src/integration-test/resources/jarTest/spring-boot/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.springframework.boot' version '2.3.7.RELEASE' + id 'org.springframework.boot' version '2.7.13' id 'io.spring.dependency-management' version '1.0.10.RELEASE' id 'java' } @@ -10,6 +10,12 @@ repositories { mavenCentral() } +tasks.named("bootJar") { + layered { + enabled = false // Spring Boot 2.4+: layering is enabled by default. + } +} + dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' } diff --git a/jib-cli/src/integration-test/resources/jarTest/spring-boot/gradle/wrapper/gradle-wrapper.jar b/jib-cli/src/integration-test/resources/jarTest/spring-boot/gradle/wrapper/gradle-wrapper.jar index 490fda8577..c1962a79e2 100644 Binary files a/jib-cli/src/integration-test/resources/jarTest/spring-boot/gradle/wrapper/gradle-wrapper.jar and b/jib-cli/src/integration-test/resources/jarTest/spring-boot/gradle/wrapper/gradle-wrapper.jar differ diff --git a/jib-cli/src/integration-test/resources/jarTest/spring-boot/gradle/wrapper/gradle-wrapper.properties b/jib-cli/src/integration-test/resources/jarTest/spring-boot/gradle/wrapper/gradle-wrapper.properties index 5028f28f8e..e411586a54 100644 --- a/jib-cli/src/integration-test/resources/jarTest/spring-boot/gradle/wrapper/gradle-wrapper.properties +++ b/jib-cli/src/integration-test/resources/jarTest/spring-boot/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.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/jib-cli/src/integration-test/resources/warTest/build.gradle b/jib-cli/src/integration-test/resources/warTest/build.gradle index 627efcfa29..10ea7f31cc 100644 --- a/jib-cli/src/integration-test/resources/warTest/build.gradle +++ b/jib-cli/src/integration-test/resources/warTest/build.gradle @@ -3,8 +3,10 @@ plugins { id 'war' } -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} repositories { mavenCentral() @@ -15,7 +17,7 @@ configurations { } dependencies { - providedCompile 'jakarta.servlet:jakarta.servlet-api:5.0.0' + providedCompile 'jakarta.servlet:jakarta.servlet-api:6.0.0' moreLibs 'jakarta.annotation:jakarta.annotation-api:2.1.0' // random extra JAR } diff --git a/jib-cli/src/integration-test/resources/warTest/gradle/wrapper/gradle-wrapper.jar b/jib-cli/src/integration-test/resources/warTest/gradle/wrapper/gradle-wrapper.jar index 490fda8577..c1962a79e2 100644 Binary files a/jib-cli/src/integration-test/resources/warTest/gradle/wrapper/gradle-wrapper.jar and b/jib-cli/src/integration-test/resources/warTest/gradle/wrapper/gradle-wrapper.jar differ diff --git a/jib-cli/src/integration-test/resources/warTest/gradle/wrapper/gradle-wrapper.properties b/jib-cli/src/integration-test/resources/warTest/gradle/wrapper/gradle-wrapper.properties index 5028f28f8e..e411586a54 100644 --- a/jib-cli/src/integration-test/resources/warTest/gradle/wrapper/gradle-wrapper.properties +++ b/jib-cli/src/integration-test/resources/warTest/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.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/jib-cli/src/main/java/com/google/cloud/tools/jib/cli/war/WarFiles.java b/jib-cli/src/main/java/com/google/cloud/tools/jib/cli/war/WarFiles.java index a69d26a693..2fb89abdfb 100644 --- a/jib-cli/src/main/java/com/google/cloud/tools/jib/cli/war/WarFiles.java +++ b/jib-cli/src/main/java/com/google/cloud/tools/jib/cli/war/WarFiles.java @@ -81,7 +81,10 @@ private static List computeEntrypoint( return entrypoint; } if (commonContainerConfigCliOptions.isJettyBaseimage()) { - return ImmutableList.of("java", "-jar", "/usr/local/jetty/start.jar"); + // jetty 12+ requires explicitly enabling ee10-deploy module. See: + // https://eclipse.dev/jetty/documentation/jetty-12/operations-guide/index.html + return ImmutableList.of( + "java", "-jar", "/usr/local/jetty/start.jar", "--module=http,ee10-deploy"); } return null; } diff --git a/jib-cli/src/test/java/com/google/cloud/tools/jib/cli/war/WarFilesTest.java b/jib-cli/src/test/java/com/google/cloud/tools/jib/cli/war/WarFilesTest.java index 513d7bc559..129ef89bac 100644 --- a/jib-cli/src/test/java/com/google/cloud/tools/jib/cli/war/WarFilesTest.java +++ b/jib-cli/src/test/java/com/google/cloud/tools/jib/cli/war/WarFilesTest.java @@ -74,7 +74,7 @@ public void testToJibContainerBuilder_explodedStandard_basicInfo() assertThat(buildPlan.getBaseImage()).isEqualTo("jetty"); assertThat(buildPlan.getEntrypoint()) - .containsExactly("java", "-jar", "/usr/local/jetty/start.jar") + .containsExactly("java", "-jar", "/usr/local/jetty/start.jar", "--module=http,ee10-deploy") .inOrder(); assertThat(buildPlan.getLayers()).hasSize(1); assertThat(buildPlan.getLayers().get(0).getName()).isEqualTo("classes"); diff --git a/jib-core/build.gradle b/jib-core/build.gradle index f31340e269..697f479f98 100644 --- a/jib-core/build.gradle +++ b/jib-core/build.gradle @@ -71,7 +71,7 @@ publishing { release { tagTemplate = 'v$version-core' git { - requireBranch = /^core-release-v\d+.*$/ //regex + requireBranch.set(/^core-release-v\d+.*$/) //regex } } /* RELEASE */ diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/ContainerizerIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/ContainerizerIntegrationTest.java index 8715ffb784..1ac1d5990e 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/ContainerizerIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/ContainerizerIntegrationTest.java @@ -78,7 +78,7 @@ private void checkCompletion() { } } - @ClassRule public static final LocalRegistry localRegistry = new LocalRegistry(5000); + @ClassRule public static final LocalRegistry localRegistry = new LocalRegistry(5001); private static final Logger logger = LoggerFactory.getLogger(ContainerizerIntegrationTest.class); private static final String DISTROLESS_DIGEST = @@ -154,7 +154,7 @@ public void testSteps_forBuildToDockerRegistry() throws IOException, InterruptedException, ExecutionException, RegistryException, CacheDirectoryCreationException, InvalidImageReferenceException { System.setProperty("jib.alwaysCacheBaseImage", "true"); - String imageReference = dockerHost + ":" + "5000/testimage:testtag"; + String imageReference = dockerHost + ":" + "5001/testimage:testtag"; Path cacheDirectory = temporaryFolder.newFolder().toPath(); Containerizer containerizer = Containerizer.to(RegistryImage.named(imageReference)) @@ -190,7 +190,7 @@ public void testSteps_forBuildToDockerRegistry() Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", "--rm", imageReference).run()); - String imageReferenceByDigest = dockerHost + ":5000/testimage@" + image1.getDigest(); + String imageReferenceByDigest = dockerHost + ":5001/testimage@" + image1.getDigest(); localRegistry.pull(imageReferenceByDigest); assertDockerInspect(imageReferenceByDigest); Assert.assertEquals( @@ -204,23 +204,23 @@ public void testSteps_forBuildToDockerRegistry_multipleTags() CacheDirectoryCreationException, InvalidImageReferenceException { buildImage( ImageReference.of("gcr.io", "distroless/java", DISTROLESS_DIGEST), - Containerizer.to(RegistryImage.named(dockerHost + ":5000/testimage:testtag")), + Containerizer.to(RegistryImage.named(dockerHost + ":5001/testimage:testtag")), Arrays.asList("testtag2", "testtag3")); - String imageReference = dockerHost + ":5000/testimage:testtag"; + String imageReference = dockerHost + ":5001/testimage:testtag"; localRegistry.pull(imageReference); assertDockerInspect(imageReference); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", "--rm", imageReference).run()); - String imageReference2 = dockerHost + ":5000/testimage:testtag2"; + String imageReference2 = dockerHost + ":5001/testimage:testtag2"; localRegistry.pull(imageReference2); assertDockerInspect(imageReference2); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", "--rm", imageReference2).run()); - String imageReference3 = dockerHost + ":5000/testimage:testtag3"; + String imageReference3 = dockerHost + ":5001/testimage:testtag3"; localRegistry.pull(imageReference3); assertDockerInspect(imageReference3); Assert.assertEquals( @@ -237,24 +237,24 @@ public void testSteps_forBuildToDockerRegistry_skipExistingDigest() JibContainer image1 = buildImage( ImageReference.scratch(), - Containerizer.to(RegistryImage.named(dockerHost + ":5000/testimagerepo:testtag")), + Containerizer.to(RegistryImage.named(dockerHost + ":5001/testimagerepo:testtag")), Collections.singletonList("testtag2")); // Test that the initial image with the original tag has been pushed. - localRegistry.pull(dockerHost + ":5000/testimagerepo:testtag"); + localRegistry.pull(dockerHost + ":5001/testimagerepo:testtag"); // Test that any additional tags have also been pushed with the original image. - localRegistry.pull(dockerHost + ":5000/testimagerepo:testtag2"); + localRegistry.pull(dockerHost + ":5001/testimagerepo:testtag2"); // Push the same image with a different tag, with SKIP_EXISTING_IMAGES enabled. JibContainer image2 = buildImage( ImageReference.scratch(), - Containerizer.to(RegistryImage.named(dockerHost + ":5000/testimagerepo:new_testtag")), + Containerizer.to(RegistryImage.named(dockerHost + ":5001/testimagerepo:new_testtag")), Collections.emptyList()); // Test that the pull request throws an exception, indicating that the new tag was not pushed. try { - localRegistry.pull(dockerHost + ":5000/testimagerepo:new_testtag"); + localRegistry.pull(dockerHost + ":5001/testimagerepo:new_testtag"); Assert.fail( "jib.skipExistingImages was enabled and digest was already pushed, " + "hence new_testtag shouldn't have been pushed."); @@ -262,7 +262,7 @@ public void testSteps_forBuildToDockerRegistry_skipExistingDigest() MatcherAssert.assertThat( ex.getMessage(), CoreMatchers.containsString( - "manifest for " + dockerHost + ":5000/testimagerepo:new_testtag not found")); + "manifest for " + dockerHost + ":5001/testimagerepo:new_testtag not found")); } // Test that both images have the same properties. @@ -280,10 +280,10 @@ public void testBuildToDockerRegistry_dockerHubBaseImage() RegistryException, CacheDirectoryCreationException { buildImage( ImageReference.parse("openjdk:8-jre-slim"), - Containerizer.to(RegistryImage.named(dockerHost + ":5000/testimage:testtag")), + Containerizer.to(RegistryImage.named(dockerHost + ":5001/testimage:testtag")), Collections.emptyList()); - String imageReference = dockerHost + ":5000/testimage:testtag"; + String imageReference = dockerHost + ":5001/testimage:testtag"; new Command("docker", "pull", imageReference).run(); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", "--rm", imageReference).run()); diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/JibIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/JibIntegrationTest.java index a9916708c3..d60b44513b 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/JibIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/JibIntegrationTest.java @@ -53,7 +53,7 @@ public class JibIntegrationTest { public static final String KNOWN_OCI_INDEX_SHA = "sha256:2c50b819aa3bfaf6ae72e47682f6c5abc0f647cf3f4224a4a9be97dd30433909"; - @ClassRule public static final LocalRegistry localRegistry = new LocalRegistry(5000); + @ClassRule public static final LocalRegistry localRegistry = new LocalRegistry(5001); @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -63,7 +63,7 @@ public class JibIntegrationTest { private final RegistryClient registryClient = RegistryClient.factory( EventHandlers.NONE, - dockerHost + ":5000", + dockerHost + ":5001", "jib-scratch", new FailoverHttpClient(true, true, ignored -> {})) .newRegistryClient(); @@ -71,7 +71,7 @@ public class JibIntegrationTest { private final RegistryClient distrolessRegistryClient = RegistryClient.factory( EventHandlers.NONE, - dockerHost + ":5000", + dockerHost + ":5001", "jib-distroless", new FailoverHttpClient(true, true, ignored -> {})) .newRegistryClient(); @@ -109,9 +109,9 @@ public void tearDown() { public void testBasic_helloWorld() throws InvalidImageReferenceException, InterruptedException, CacheDirectoryCreationException, IOException, RegistryException, ExecutionException { - String toImage = dockerHost + ":5000/basic-helloworld"; + String toImage = dockerHost + ":5001/basic-helloworld"; JibContainer jibContainer = - Jib.from(dockerHost + ":5000/busybox") + Jib.from(dockerHost + ":5001/busybox") .setEntrypoint("echo", "Hello World") .containerize( Containerizer.to(RegistryImage.named(toImage)).setAllowInsecureRegistries(true)); @@ -125,9 +125,9 @@ public void testBasic_helloWorld() public void testBasic_dockerDaemonBaseImage() throws IOException, InterruptedException, InvalidImageReferenceException, ExecutionException, RegistryException, CacheDirectoryCreationException { - String toImage = dockerHost + ":5000/basic-dockerdaemon"; + String toImage = dockerHost + ":5001/basic-dockerdaemon"; JibContainer jibContainer = - Jib.from("docker://" + dockerHost + ":5000/busybox") + Jib.from("docker://" + dockerHost + ":5001/busybox") .setEntrypoint("echo", "Hello World") .containerize( Containerizer.to(RegistryImage.named(toImage)).setAllowInsecureRegistries(true)); @@ -141,13 +141,13 @@ public void testBasic_dockerDaemonBaseImage() public void testBasic_dockerDaemonBaseImageToDockerDaemon() throws IOException, InterruptedException, InvalidImageReferenceException, ExecutionException, RegistryException, CacheDirectoryCreationException { - Jib.from(DockerDaemonImage.named(dockerHost + ":5000/busybox")) + Jib.from(DockerDaemonImage.named(dockerHost + ":5001/busybox")) .setEntrypoint("echo", "Hello World") .containerize( - Containerizer.to(DockerDaemonImage.named(dockerHost + ":5000/docker-to-docker"))); + Containerizer.to(DockerDaemonImage.named(dockerHost + ":5001/docker-to-docker"))); String output = - new Command("docker", "run", "--rm", dockerHost + ":5000/docker-to-docker").run(); + new Command("docker", "run", "--rm", dockerHost + ":5001/docker-to-docker").run(); Assert.assertEquals("Hello World\n", output); } @@ -156,9 +156,9 @@ public void testBasic_tarBaseImage_dockerSavedCommand() throws IOException, InterruptedException, InvalidImageReferenceException, ExecutionException, RegistryException, CacheDirectoryCreationException { Path path = temporaryFolder.getRoot().toPath().resolve("docker-save.tar"); - new Command("docker", "save", dockerHost + ":5000/busybox", "-o=" + path).run(); + new Command("docker", "save", dockerHost + ":5001/busybox", "-o=" + path).run(); - String toImage = dockerHost + ":5000/basic-dockersavedcommand"; + String toImage = dockerHost + ":5001/basic-dockersavedcommand"; JibContainer jibContainer = Jib.from("tar://" + path) .setEntrypoint("echo", "Hello World") @@ -177,7 +177,7 @@ public void testBasic_tarBaseImage_dockerSavedFile() // tar saved with 'docker save busybox -o busybox.tar' Path path = Paths.get(Resources.getResource("core/busybox-docker.tar").toURI()); - String toImage = dockerHost + ":5000/basic-dockersavedfile"; + String toImage = dockerHost + ":5001/basic-dockersavedfile"; JibContainer jibContainer = Jib.from(TarImage.at(path).named("ignored")) .setEntrypoint("echo", "Hello World") @@ -194,14 +194,14 @@ public void testBasic_tarBaseImage_jibImage() throws InvalidImageReferenceException, InterruptedException, ExecutionException, RegistryException, CacheDirectoryCreationException, IOException, URISyntaxException { Path outputPath = temporaryFolder.getRoot().toPath().resolve("jib-image.tar"); - Jib.from(dockerHost + ":5000/busybox") + Jib.from(dockerHost + ":5001/busybox") .addLayer( Collections.singletonList(Paths.get(Resources.getResource("core/hello").toURI())), "/") .containerize( Containerizer.to(TarImage.at(outputPath).named("ignored")) .setAllowInsecureRegistries(true)); - String toImage = dockerHost + ":5000/basic-jibtar"; + String toImage = dockerHost + ":5001/basic-jibtar"; JibContainer jibContainer = Jib.from(TarImage.at(outputPath).named("ignored")) .setEntrypoint("cat", "/hello") @@ -220,7 +220,7 @@ public void testBasic_tarBaseImage_jibImageToDockerDaemon() // tar saved with Jib.from("busybox").addLayer(...("core/hello")).containerize(TarImage.at...) Path path = Paths.get(Resources.getResource("core/busybox-jib.tar").toURI()); - String toImage = dockerHost + ":5000/basic-jibtar-to-docker"; + String toImage = dockerHost + ":5001/basic-jibtar-to-docker"; JibContainer jibContainer = Jib.from(TarImage.at(path).named("ignored")) .setEntrypoint("cat", "/hello") @@ -238,7 +238,7 @@ public void testScratch_defaultPlatform() CacheDirectoryCreationException, InvalidImageReferenceException { Jib.fromScratch() .containerize( - Containerizer.to(RegistryImage.named(dockerHost + ":5000/jib-scratch:default-platform")) + Containerizer.to(RegistryImage.named(dockerHost + ":5001/jib-scratch:default-platform")) .setAllowInsecureRegistries(true)); V22ManifestTemplate manifestTemplate = @@ -262,7 +262,7 @@ public void testScratch_singlePlatform() Jib.fromScratch() .setPlatforms(ImmutableSet.of(new Platform("arm64", "windows"))) .containerize( - Containerizer.to(RegistryImage.named(dockerHost + ":5000/jib-scratch:single-platform")) + Containerizer.to(RegistryImage.named(dockerHost + ":5001/jib-scratch:single-platform")) .setAllowInsecureRegistries(true)); V22ManifestTemplate manifestTemplate = @@ -287,7 +287,7 @@ public void testScratch_multiPlatform() .setPlatforms( ImmutableSet.of(new Platform("arm64", "windows"), new Platform("amd32", "windows"))) .containerize( - Containerizer.to(RegistryImage.named(dockerHost + ":5000/jib-scratch:multi-platform")) + Containerizer.to(RegistryImage.named(dockerHost + ":5001/jib-scratch:multi-platform")) .setAllowInsecureRegistries(true)); V22ManifestListTemplate manifestList = @@ -313,7 +313,7 @@ public void testDistroless_ociManifest() ImmutableSet.of(new Platform("arm64", "linux"), new Platform("amd64", "linux"))) .containerize( Containerizer.to( - RegistryImage.named(dockerHost + ":5000/jib-distroless:multi-platform")) + RegistryImage.named(dockerHost + ":5001/jib-distroless:multi-platform")) .setAllowInsecureRegistries(true)); V22ManifestListTemplate manifestList = @@ -338,7 +338,7 @@ public void testOffline() Path cacheDirectory = temporaryFolder.getRoot().toPath(); JibContainerBuilder jibContainerBuilder = - Jib.from(dockerHost + ":5000/busybox").setEntrypoint("echo", "Hello World"); + Jib.from(dockerHost + ":5001/busybox").setEntrypoint("echo", "Hello World"); // Should fail since Jib can't build to registry offline try { @@ -360,7 +360,7 @@ public void testOffline() Assert.assertEquals( "Cannot run Jib in offline mode; " + dockerHost - + ":5000/busybox not found in local Jib cache", + + ":5001/busybox not found in local Jib cache", ex.getCause().getMessage()); } @@ -372,13 +372,13 @@ public void testOffline() // Run again in offline mode, should succeed this time jibContainerBuilder.containerize( - Containerizer.to(DockerDaemonImage.named(dockerHost + ":5000/offline")) + Containerizer.to(DockerDaemonImage.named(dockerHost + ":5001/offline")) .setBaseImageLayersCache(cacheDirectory) .setOfflineMode(true)); // Verify output Assert.assertEquals( - "Hello World\n", new Command("docker", "run", "--rm", dockerHost + ":5000/offline").run()); + "Hello World\n", new Command("docker", "run", "--rm", dockerHost + ":5001/offline").run()); } /** Ensure that a provided executor is not disposed. */ @@ -390,7 +390,7 @@ public void testProvidedExecutorNotDisposed() try { Jib.fromScratch() .containerize( - Containerizer.to(RegistryImage.named(dockerHost + ":5000/foo")) + Containerizer.to(RegistryImage.named(dockerHost + ":5001/foo")) .setExecutorService(executorService) .setAllowInsecureRegistries(true)); Assert.assertFalse(executorService.isShutdown()); diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/ReproducibleImageTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/ReproducibleImageTest.java index 1c194b2198..c6ec35e747 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/ReproducibleImageTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/ReproducibleImageTest.java @@ -88,6 +88,22 @@ public static void createImage() .containerize(containerizer); } + public static int getJavaVersion() { + String version = System.getProperty("java.version"); + if (version.startsWith("1.")) { + version = version.substring(2); + } + // Allow these formats: + // 1.8.0_72-ea + // 9-ea + // 9 + // 9.0.1 + int dotPos = version.indexOf('.'); + int dashPos = version.indexOf('-'); + return Integer.parseInt( + version.substring(0, dotPos > -1 ? dotPos : dashPos > -1 ? dashPos : 1)); + } + @Test public void testTarballStructure() throws IOException { // known content should produce known results @@ -100,21 +116,39 @@ public void testTarballStructure() throws IOException { } } - assertThat(actual) - .containsExactly( - "c46572ef74f58d95e44dd36c1fbdfebd3752e8b56a794a13c11cfed35a1a6e1c.tar.gz", - "6d2763b0f3940d324ea6b55386429e5b173899608abf7d1bff62e25dd2e4dcea.tar.gz", - "530c1954a2b087d0b989895ea56435c9dc739a973f2d2b6cb9bb98e55bbea7ac.tar.gz", - "config.json", - "manifest.json") - .inOrder(); + if (getJavaVersion() < 16) { + assertThat(actual) + .containsExactly( + "c46572ef74f58d95e44dd36c1fbdfebd3752e8b56a794a13c11cfed35a1a6e1c.tar.gz", + "6d2763b0f3940d324ea6b55386429e5b173899608abf7d1bff62e25dd2e4dcea.tar.gz", + "530c1954a2b087d0b989895ea56435c9dc739a973f2d2b6cb9bb98e55bbea7ac.tar.gz", + "config.json", + "manifest.json") + .inOrder(); + } else { + // JDK 16+ has changed Gzip output, so hash changes + // https://bugs.openjdk.org/browse/JDK-8244706 + + assertThat(actual) + .containsExactly( + "d32c6bf16170d213b5f458a7c120288f0fb376015db1943d1e1c411e9b7ec9eb.tar.gz", + "eb01acbf8104bd2a8c4b594a1385bab883f27e85a703ee98c2e6cc81e71aea2a.tar.gz", + "65738b93774dc833f97dcb5ba806bddce6079163ba54bf51c9f66db9d1ab69d9.tar.gz", + "config.json", + "manifest.json") + .inOrder(); + } } @Test public void testManifest() throws IOException { String expectedManifest = - "[{\"Config\":\"config.json\",\"RepoTags\":[\"jib-core/reproducible:latest\"]," - + "\"Layers\":[\"c46572ef74f58d95e44dd36c1fbdfebd3752e8b56a794a13c11cfed35a1a6e1c.tar.gz\",\"6d2763b0f3940d324ea6b55386429e5b173899608abf7d1bff62e25dd2e4dcea.tar.gz\",\"530c1954a2b087d0b989895ea56435c9dc739a973f2d2b6cb9bb98e55bbea7ac.tar.gz\"]}]"; + (getJavaVersion() < 16) + ? "[{\"Config\":\"config.json\",\"RepoTags\":[\"jib-core/reproducible:latest\"]," + + "\"Layers\":[\"c46572ef74f58d95e44dd36c1fbdfebd3752e8b56a794a13c11cfed35a1a6e1c.tar.gz\",\"6d2763b0f3940d324ea6b55386429e5b173899608abf7d1bff62e25dd2e4dcea.tar.gz\",\"530c1954a2b087d0b989895ea56435c9dc739a973f2d2b6cb9bb98e55bbea7ac.tar.gz\"]}]" + : "[{\"Config\":\"config.json\",\"RepoTags\":[\"jib-core/reproducible:latest\"]," + + "\"Layers\":[\"d32c6bf16170d213b5f458a7c120288f0fb376015db1943d1e1c411e9b7ec9eb.tar.gz\",\"eb01acbf8104bd2a8c4b594a1385bab883f27e85a703ee98c2e6cc81e71aea2a.tar.gz\",\"65738b93774dc833f97dcb5ba806bddce6079163ba54bf51c9f66db9d1ab69d9.tar.gz\"]}]"; + String generatedManifest = extractFromTarFileAsString(imageTar, "manifest.json"); assertThat(generatedManifest).isEqualTo(expectedManifest); } diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/BlobPusherIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/BlobPusherIntegrationTest.java index 3d68e2ef63..3e29e9edd1 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/BlobPusherIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/BlobPusherIntegrationTest.java @@ -31,7 +31,7 @@ /** Integration tests for {@link BlobPusher}. */ public class BlobPusherIntegrationTest { - @ClassRule public static final LocalRegistry localRegistry = new LocalRegistry(5000); + @ClassRule public static final LocalRegistry localRegistry = new LocalRegistry(5001); private final FailoverHttpClient httpClient = new FailoverHttpClient(true, false, ignored -> {}); private final String dockerHost = @@ -46,7 +46,7 @@ public void testPush() throws DigestException, IOException, RegistryException { "52a9e4d4ba4333ce593707f98564fee1e6d898db0d3602408c0b2a6a424d357c"); RegistryClient registryClient = - RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5000", "testimage", httpClient) + RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5001", "testimage", httpClient) .newRegistryClient(); Assert.assertFalse(registryClient.pushBlob(testBlobDigest, testBlob, null, ignored -> {})); } diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/ManifestPullerIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/ManifestPullerIntegrationTest.java index da6f058ccb..9c5dd0f166 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/ManifestPullerIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/ManifestPullerIntegrationTest.java @@ -52,7 +52,7 @@ public class ManifestPullerIntegrationTest { public static final String KNOWN_OCI_MANIFEST_SHA = "sha256:0477dc38b254096e350a9b605b7355d3cf0d5a844558e6986148ce2a1fe18ba8"; - @ClassRule public static LocalRegistry localRegistry = new LocalRegistry(5000); + @ClassRule public static LocalRegistry localRegistry = new LocalRegistry(5001); public final String dockerHost = System.getenv("DOCKER_IP") != null ? System.getenv("DOCKER_IP") : "localhost"; @@ -66,7 +66,7 @@ public static void setUp() throws IOException, InterruptedException { @Test public void testPull_v21() throws IOException, RegistryException { RegistryClient registryClient = - RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5000", "busybox", httpClient) + RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5001", "busybox", httpClient) .newRegistryClient(); V21ManifestTemplate manifestTemplate = @@ -152,7 +152,7 @@ public void testPull_ociIndex() throws IOException, RegistryException { public void testPull_unknownManifest() throws RegistryException, IOException { try { RegistryClient registryClient = - RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5000", "busybox", httpClient) + RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5001", "busybox", httpClient) .newRegistryClient(); registryClient.pullManifest("nonexistent-tag"); Assert.fail("Trying to pull nonexistent image should have errored"); @@ -160,7 +160,7 @@ public void testPull_unknownManifest() throws RegistryException, IOException { } catch (RegistryErrorException ex) { assertThat(ex) .hasMessageThat() - .contains("pull image manifest for " + dockerHost + ":5000/busybox:nonexistent-tag"); + .contains("pull image manifest for " + dockerHost + ":5001/busybox:nonexistent-tag"); } } } diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/ManifestPusherIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/ManifestPusherIntegrationTest.java index 478762d893..57139174d7 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/ManifestPusherIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/ManifestPusherIntegrationTest.java @@ -36,7 +36,7 @@ /** Integration tests for {@link ManifestPusher}. */ public class ManifestPusherIntegrationTest { - @ClassRule public static final LocalRegistry localRegistry = new LocalRegistry(5000); + @ClassRule public static final LocalRegistry localRegistry = new LocalRegistry(5001); private final FailoverHttpClient httpClient = new FailoverHttpClient(true, false, ignored -> {}); public final String dockerHost = @@ -50,7 +50,7 @@ public void testPush_missingBlobs() throws IOException, RegistryException { ManifestTemplate manifestTemplate = registryClient.pullManifest("latest").getManifest(); registryClient = - RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5000", "ignored", httpClient) + RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5001", "ignored", httpClient) .newRegistryClient(); try { registryClient.pushManifest(manifestTemplate, "latest"); @@ -83,7 +83,7 @@ public void testPush() throws DigestException, IOException, RegistryException { // Pushes the BLOBs. RegistryClient registryClient = - RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5000", "testimage", httpClient) + RegistryClient.factory(EventHandlers.NONE, dockerHost + ":5001", "testimage", httpClient) .newRegistryClient(); Assert.assertFalse( registryClient.pushBlob(testLayerBlobDigest, testLayerBlob, null, ignored -> {})); diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/credentials/DockerCredentialHelperIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/credentials/DockerCredentialHelperIntegrationTest.java index bda754c9b2..aa6f1b417d 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/credentials/DockerCredentialHelperIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/registry/credentials/DockerCredentialHelperIntegrationTest.java @@ -26,6 +26,7 @@ import org.hamcrest.CoreMatchers; import org.hamcrest.MatcherAssert; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; /** Integration tests for {@link DockerCredentialHelper}. */ diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageStepsTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageStepsTest.java index 97bd9f1217..2b9dace7ee 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageStepsTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageStepsTest.java @@ -84,6 +84,22 @@ public void tearDown() { tempDirectoryProvider.close(); } + public static int getJavaVersion() { + String version = System.getProperty("java.version"); + if (version.startsWith("1.")) { + version = version.substring(2); + } + // Allow these formats: + // 1.8.0_72-ea + // 9-ea + // 9 + // 9.0.1 + int dotPos = version.indexOf('.'); + int dashPos = version.indexOf('-'); + return Integer.parseInt( + version.substring(0, dotPos > -1 ? dotPos : dashPos > -1 ? dashPos : 1)); + } + @Test public void testCacheDockerImageTar_validDocker() throws Exception { Path dockerBuild = getResource("core/extraction/docker-save.tar"); @@ -93,17 +109,22 @@ public void testCacheDockerImageTar_validDocker() throws Exception { Mockito.verify(progressEventDispatcher, Mockito.times(2)).newChildProducer(); Assert.assertEquals(2, result.layers.size()); + Assert.assertEquals( "5e701122d3347fae0758cd5b7f0692c686fcd07b0e7fd9c4a125fbdbbedc04dd", result.layers.get(0).get().getDiffId().getHash()); Assert.assertEquals( - "0011328ac5dfe3dde40c7c5e0e00c98d1833a3aeae2bfb668cf9eb965c229c7f", + getJavaVersion() < 16 + ? "0011328ac5dfe3dde40c7c5e0e00c98d1833a3aeae2bfb668cf9eb965c229c7f" + : "bdc94fe3bba352809859ca87c846872ae2c1157596631e72d7d73e46fae86101", result.layers.get(0).get().getBlobDescriptor().getDigest().getHash()); Assert.assertEquals( "f1ac3015bcbf0ada4750d728626eb10f0f585199e2b667dcd79e49f0e926178e", result.layers.get(1).get().getDiffId().getHash()); Assert.assertEquals( - "c10ef24a5cef5092bbcb5a5666721cff7b86ce978c203a958d1fc86ee6c19f94", + getJavaVersion() < 16 + ? "c10ef24a5cef5092bbcb5a5666721cff7b86ce978c203a958d1fc86ee6c19f94" + : "073d615d78a940951cfe91b1feee2da3c5d21f7df48539921c26aecd23185d5f", result.layers.get(1).get().getBlobDescriptor().getDigest().getHash()); Assert.assertEquals(2, result.configurationTemplate.getLayerCount()); } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/cache/CacheStorageFilesTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/cache/CacheStorageFilesTest.java index c81a80c8ef..2d1efd6c2a 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/cache/CacheStorageFilesTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/cache/CacheStorageFilesTest.java @@ -188,8 +188,8 @@ public void testGetImageDirectory() throws InvalidImageReferenceException { ImageReference.parse( "reg.istry/repo@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))); Assert.assertEquals( - imagesDirectory.resolve("reg.istry!5000/repo/sitory!tag"), + imagesDirectory.resolve("reg.istry!5001/repo/sitory!tag"), TEST_CACHE_STORAGE_FILES.getImageDirectory( - ImageReference.parse("reg.istry:5000/repo/sitory:tag"))); + ImageReference.parse("reg.istry:5001/repo/sitory:tag"))); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/http/FailoverHttpClientTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/http/FailoverHttpClientTest.java index b46267d96d..bd59b2e2f9 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/http/FailoverHttpClientTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/http/FailoverHttpClientTest.java @@ -239,15 +239,15 @@ public void testGet_insecureClientOnNonListeningServerAndPortSpecified() throws FailoverHttpClient insecureHttpClient = newHttpClient(true, false); Mockito.when(mockHttpRequest.execute()) - .thenThrow(new ConnectException("my exception")); // server is not listening on 5000 + .thenThrow(new ConnectException("my exception")); // server is not listening on 5001 try (Response response = - insecureHttpClient.get(new URL("https://insecure:5000"), fakeRequest(null))) { + insecureHttpClient.get(new URL("https://insecure:5001"), fakeRequest(null))) { Assert.fail("Should not fall back to HTTP if port was explicitly given and cannot connect"); } catch (ConnectException ex) { Assert.assertEquals("my exception", ex.getMessage()); - verifyCapturedUrls("https://insecure:5000"); + verifyCapturedUrls("https://insecure:5001"); Mockito.verify(mockHttpRequest, Mockito.times(1)).execute(); Mockito.verifyNoInteractions(mockInsecureHttpRequest, logger); diff --git a/jib-gradle-plugin-extension-api/build.gradle b/jib-gradle-plugin-extension-api/build.gradle index 1478f30127..977be52bf1 100644 --- a/jib-gradle-plugin-extension-api/build.gradle +++ b/jib-gradle-plugin-extension-api/build.gradle @@ -44,7 +44,7 @@ publishing { release { tagTemplate = 'v$version-gradle-extension' git { - requireBranch = /^gradle-extension-release-v\d+.*$/ //regex + requireBranch.set(/^gradle-extension-release-v\d+.*$/) //regex } } /* RELEASE */ diff --git a/jib-gradle-plugin/build.gradle b/jib-gradle-plugin/build.gradle index 46f416ab1e..02c27c7ff6 100644 --- a/jib-gradle-plugin/build.gradle +++ b/jib-gradle-plugin/build.gradle @@ -45,7 +45,7 @@ dependencies { integrationTestImplementation dependencyStrings.JBCRYPT // only for testing a concrete Spring Boot example in a test (not for test infrastructure) - testImplementation 'org.springframework.boot:spring-boot-gradle-plugin:2.2.11.RELEASE' + testImplementation 'org.springframework.boot:spring-boot-gradle-plugin:2.7.13' } /* RELEASE */ @@ -57,17 +57,13 @@ release { 'com.google.cloud.tools:jib-plugins-common', ] git { - requireBranch = /^gradle-release-v\d+.*$/ //regex + requireBranch.set(/^gradle-release-v\d+.*$/) //regex } } // Gradle Plugin Portal releases -pluginBundle { +gradlePlugin { website = 'https://github.com/GoogleContainerTools/jib/' vcsUrl = 'https://github.com/GoogleContainerTools/jib/' - tags = ['google', 'java', 'containers', 'docker', 'kubernetes', 'microservices'] -} - -gradlePlugin { testSourceSets sourceSets.integrationTest, sourceSets.test plugins { jibPlugin { @@ -75,6 +71,7 @@ gradlePlugin { displayName = 'Jib' description = 'Containerize your Java application' implementationClass = 'com.google.cloud.tools.jib.gradle.JibPlugin' + tags.set(['google', 'java', 'containers', 'docker', 'kubernetes', 'microservices']) } } } diff --git a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java b/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java index 7c53878dc5..1695ab70b9 100644 --- a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java +++ b/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java @@ -50,7 +50,7 @@ public class SingleProjectIntegrationTest { @ClassRule public static final LocalRegistry localRegistry1 = - new LocalRegistry(5000, "testuser", "testpassword"); + new LocalRegistry(5001, "testuser", "testpassword"); @ClassRule public static final LocalRegistry localRegistry2 = @@ -449,7 +449,7 @@ public void testBuild_complex() @Test public void testBuild_complex_sameFromAndToRegistry() throws IOException, InterruptedException { - String targetImage = dockerHost + ":5000/compleximage:gradle" + System.nanoTime(); + String targetImage = dockerHost + ":5001/compleximage:gradle" + System.nanoTime(); Instant beforeBuild = Instant.now(); buildAndRunComplex(targetImage, "testuser", "testpassword", localRegistry1); assertThat(JibRunHelper.getCreationTime(targetImage)).isGreaterThan(beforeBuild); diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-configuration.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-configuration.gradle index 0d78b139d3..01da56096a 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-configuration.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-configuration.gradle @@ -24,8 +24,8 @@ configurations { } dependencies { - compile files('libs/dependency-1.0.0.jar') - runtime 'com.google.guava:guava:30.1-jre' + implementation files('libs/dependency-1.0.0.jar') + runtimeOnly 'com.google.guava:guava:30.1-jre' myConfiguration files('libs/dependency2') otherConfiguration files('libs/dependency3') } diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs-filtering.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs-filtering.gradle index 4e04624dac..9468308357 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs-filtering.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs-filtering.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation files('libs/dependency-1.0.0.jar') } jib { diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs.gradle index da49d7772b..7bedbd7369 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation() files('libs/dependency-1.0.0.jar') } jib { diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs2.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs2.gradle index f4c21d2005..a1694ed9f7 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs2.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs2.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation files('libs/dependency-1.0.0.jar') } jib { diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs3.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs3.gradle index 178c0f80c9..d48d6d501a 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs3.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-extra-dirs3.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation files('libs/dependency-1.0.0.jar') } jib { diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-jar-containerization.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-jar-containerization.gradle index 917a55ef7f..150f012681 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-jar-containerization.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-jar-containerization.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation files('libs/dependency-1.0.0.jar') } jar { diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java11-incompatible.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java11-incompatible.gradle index 2cc07b662e..aa93e702f1 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java11-incompatible.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java11-incompatible.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation files('libs/dependency-1.0.0.jar') } jib.from.image = 'eclipse-temurin:8-jdk-focal' diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java11.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java11.gradle index 8c563bfb00..995aa9e7af 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java11.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java11.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation files('libs/dependency-1.0.0.jar') } jib.from.image = 'eclipse-temurin:11-jdk-focal' diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java17.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java17.gradle index 9c860213ef..2600d5f6a8 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java17.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-java17.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation files('libs/dependency-1.0.0.jar') } jib.to.image = System.getProperty("_TARGET_IMAGE") \ No newline at end of file diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-local-base.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-local-base.gradle index a757ac89fe..6e57fa0be3 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-local-base.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-local-base.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation files('libs/dependency-1.0.0.jar') } jib { diff --git a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-timestamps-custom.gradle b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-timestamps-custom.gradle index 9771046978..1db4cc1e73 100644 --- a/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-timestamps-custom.gradle +++ b/jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/build-timestamps-custom.gradle @@ -11,7 +11,7 @@ repositories { } dependencies { - compile files('libs/dependency-1.0.0.jar') + implementation files('libs/dependency-1.0.0.jar') } jib { diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java index 692449db03..86f29eef12 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java @@ -44,6 +44,7 @@ import javax.annotation.Nullable; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; +import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; @@ -54,6 +55,7 @@ public class BuildDockerTask extends DefaultTask implements JibTask { private static final String HELPFUL_SUGGESTIONS_PREFIX = "Build to Docker daemon failed"; @Nullable private JibExtension jibExtension; + @Nullable private GradleProjectProperties projectProperties; /** * This will call the property {@code "jib"} so that it is the same name as the extension. This @@ -63,10 +65,17 @@ public class BuildDockerTask extends DefaultTask implements JibTask { */ @Nested @Nullable + @SuppressWarnings("java:S106") public JibExtension getJib() { return jibExtension; } + @Nullable + @Internal + public GradleProjectProperties getProjectProperties() { + return projectProperties; + } + /** * The target image can be overridden with the {@code --image} command line option. * @@ -91,6 +100,7 @@ public void buildDocker() throws IOException, BuildStepsExecutionException, CacheDirectoryCreationException, MainClassInferenceException, InvalidGlobalConfigException { Preconditions.checkNotNull(jibExtension); + Preconditions.checkNotNull(projectProperties); // Check deprecated parameters Path dockerExecutable = jibExtension.getDockerClient().getExecutablePath(); @@ -104,23 +114,16 @@ public void buildDocker() } TaskCommon.disableHttpLogging(); - TempDirectoryProvider tempDirectoryProvider = new TempDirectoryProvider(); - GradleProjectProperties projectProperties = - GradleProjectProperties.getForProject( - getProject(), - getLogger(), - tempDirectoryProvider, - jibExtension.getConfigurationName().get()); GlobalConfig globalConfig = GlobalConfig.readConfig(); Future> updateCheckFuture = - TaskCommon.newUpdateChecker(projectProperties, globalConfig, getLogger()); - try { + TaskCommon.newUpdateChecker(this.projectProperties, globalConfig, getLogger()); + try (TempDirectoryProvider tempDirectoryProvider = new TempDirectoryProvider()) { PluginConfigurationProcessor.createJibBuildRunnerForDockerDaemonImage( new GradleRawConfiguration(jibExtension), ignored -> java.util.Optional.empty(), - projectProperties, + this.projectProperties, globalConfig, new GradleHelpfulSuggestions(HELPFUL_SUGGESTIONS_PREFIX)) .runBuild(); @@ -187,8 +190,7 @@ public void buildDocker() + ex.getPath(), ex); } finally { - tempDirectoryProvider.close(); - TaskCommon.finishUpdateChecker(projectProperties, updateCheckFuture); + TaskCommon.finishUpdateChecker(this.projectProperties, updateCheckFuture); projectProperties.waitForLoggingThread(); } } @@ -196,6 +198,12 @@ public void buildDocker() @Override public BuildDockerTask setJibExtension(JibExtension jibExtension) { this.jibExtension = jibExtension; + this.projectProperties = + GradleProjectProperties.getForProject( + getProject(), + getLogger(), + new TempDirectoryProvider(), + jibExtension.getConfigurationName().get()); return this; } } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildImageTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildImageTask.java index 49265559a6..2aef54bbef 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildImageTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildImageTask.java @@ -43,6 +43,7 @@ import javax.annotation.Nullable; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; +import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; @@ -54,6 +55,8 @@ public class BuildImageTask extends DefaultTask implements JibTask { @Nullable private JibExtension jibExtension; + @Nullable private GradleProjectProperties projectProperties; + /** * This will call the property {@code "jib"} so that it is the same name as the extension. This * way, the user would see error messages for missing configuration with the prefix {@code jib.}. @@ -66,6 +69,12 @@ public JibExtension getJib() { return jibExtension; } + @Nullable + @Internal + public GradleProjectProperties getProjectProperties() { + return projectProperties; + } + /** * The target image can be overridden with the {@code --image} command line option. * @@ -91,15 +100,9 @@ public void buildImage() MainClassInferenceException, InvalidGlobalConfigException { // Asserts required @Input parameters are not null. Preconditions.checkNotNull(jibExtension); + Preconditions.checkNotNull(projectProperties); TaskCommon.disableHttpLogging(); - TempDirectoryProvider tempDirectoryProvider = new TempDirectoryProvider(); - GradleProjectProperties projectProperties = - GradleProjectProperties.getForProject( - getProject(), - getLogger(), - tempDirectoryProvider, - jibExtension.getConfigurationName().get()); GlobalConfig globalConfig = GlobalConfig.readConfig(); Future> updateCheckFuture = TaskCommon.newUpdateChecker(projectProperties, globalConfig, getLogger()); @@ -182,15 +185,28 @@ public void buildImage() + ex.getPath(), ex); } finally { - tempDirectoryProvider.close(); - TaskCommon.finishUpdateChecker(projectProperties, updateCheckFuture); - projectProperties.waitForLoggingThread(); + + if (projectProperties != null) { + TempDirectoryProvider tempDirectoryProvider = projectProperties.getTempDirectoryProvider(); + if (tempDirectoryProvider != null) { + tempDirectoryProvider.close(); + } + TaskCommon.finishUpdateChecker(projectProperties, updateCheckFuture); + projectProperties.waitForLoggingThread(); + } } } @Override public BuildImageTask setJibExtension(JibExtension jibExtension) { this.jibExtension = jibExtension; + this.projectProperties = + GradleProjectProperties.getForProject( + getProject(), + getLogger(), + new TempDirectoryProvider(), + jibExtension.getConfigurationName().get()); + return this; } } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildTarTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildTarTask.java index 1a77856b6b..4f4219da37 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildTarTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildTarTask.java @@ -47,6 +47,7 @@ import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; @@ -71,6 +72,8 @@ public JibExtension getJib() { return jibExtension; } + @Nullable private GradleProjectProperties projectProperties; + /** * The target image can be overridden with the {@code --image} command line option. * @@ -81,6 +84,12 @@ public void setTargetImage(String targetImage) { Preconditions.checkNotNull(jibExtension).getTo().setImage(targetImage); } + @Nullable + @Internal + public GradleProjectProperties getProjectProperties() { + return projectProperties; + } + /** * Returns a collection of all the files that jib includes in the image. Only used to calculate * UP-TO-DATE. @@ -122,23 +131,19 @@ public void buildTar() MainClassInferenceException, InvalidGlobalConfigException { // Asserts required @Input parameters are not null. Preconditions.checkNotNull(jibExtension); + Preconditions.checkNotNull(projectProperties); TaskCommon.disableHttpLogging(); - TempDirectoryProvider tempDirectoryProvider = new TempDirectoryProvider(); - GradleProjectProperties projectProperties = - GradleProjectProperties.getForProject( - getProject(), - getLogger(), - tempDirectoryProvider, - jibExtension.getConfigurationName().get()); GlobalConfig globalConfig = GlobalConfig.readConfig(); Future> updateCheckFuture = - TaskCommon.newUpdateChecker(projectProperties, globalConfig, getLogger()); - try { + TaskCommon.newUpdateChecker(this.projectProperties, globalConfig, getLogger()); + + try (TempDirectoryProvider tempDirectoryProvider = new TempDirectoryProvider()) { + PluginConfigurationProcessor.createJibBuildRunnerForTarImage( new GradleRawConfiguration(jibExtension), ignored -> Optional.empty(), - projectProperties, + this.projectProperties, globalConfig, new GradleHelpfulSuggestions(HELPFUL_SUGGESTIONS_PREFIX)) .runBuild(); @@ -204,7 +209,6 @@ public void buildTar() + ex.getPath(), ex); } finally { - tempDirectoryProvider.close(); TaskCommon.finishUpdateChecker(projectProperties, updateCheckFuture); projectProperties.waitForLoggingThread(); } @@ -213,6 +217,12 @@ public void buildTar() @Override public BuildTarTask setJibExtension(JibExtension jibExtension) { this.jibExtension = jibExtension; + this.projectProperties = + GradleProjectProperties.getForProject( + getProject(), + getLogger(), + new TempDirectoryProvider(), + jibExtension.getConfigurationName().get()); return this; } } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoriesParameters.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoriesParameters.java index 30dc526e89..c74ea7e889 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoriesParameters.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoriesParameters.java @@ -19,6 +19,7 @@ import com.google.cloud.tools.jib.plugins.common.ConfigurationPropertyValidator; import com.google.cloud.tools.jib.plugins.common.PropertyNames; import java.io.File; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.List; @@ -33,14 +34,15 @@ import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.Optional; /** Object in {@link JibExtension} that configures the extra directories. */ public class ExtraDirectoriesParameters { private final ObjectFactory objects; - private final Project project; - + private final Path projectPath; + private final Provider extraDirPaths; private ListProperty paths; private ExtraDirectoryParametersSpec spec; private MapProperty permissions; @@ -48,10 +50,12 @@ public class ExtraDirectoriesParameters { @Inject public ExtraDirectoriesParameters(ObjectFactory objects, Project project) { this.objects = objects; - this.project = project; paths = objects.listProperty(ExtraDirectoryParameters.class).empty(); spec = objects.newInstance(ExtraDirectoryParametersSpec.class, project, paths); permissions = objects.mapProperty(String.class, String.class).empty(); + this.projectPath = project.getProjectDir().toPath(); + this.extraDirPaths = + project.getProviders().systemProperty(PropertyNames.EXTRA_DIRECTORIES_PATHS); } public void paths(Action action) { @@ -59,32 +63,26 @@ public void paths(Action action) { } @Input - public List getPathStrings() { - // Gradle warns about @Input annotations on File objects, so we have to expose a getter for a - // String to make them go away. - return getPaths().stream() - .map(extraDirectoryParameters -> extraDirectoryParameters.getFrom().toString()) - .collect(Collectors.toList()); + @Optional + public Provider getExtraDirPaths() { + return extraDirPaths; } - @Internal + @Nested public List getPaths() { // Gradle warns about @Input annotations on File objects, so we have to expose a getter for a // String to make them go away. - String property = System.getProperty(PropertyNames.EXTRA_DIRECTORIES_PATHS); - if (property != null) { - List pathStrings = ConfigurationPropertyValidator.parseListProperty(property); + if (this.extraDirPaths.isPresent()) { + List pathStrings = + ConfigurationPropertyValidator.parseListProperty(this.extraDirPaths.get()); return pathStrings.stream() - .map(path -> new ExtraDirectoryParameters(objects, project, Paths.get(path), "/")) + .map(path -> new ExtraDirectoryParameters(objects, Paths.get(path), "/")) .collect(Collectors.toList()); } if (paths.get().isEmpty()) { return Collections.singletonList( new ExtraDirectoryParameters( - objects, - project, - project.getProjectDir().toPath().resolve("src").resolve("main").resolve("jib"), - "/")); + objects, projectPath.resolve("src").resolve("main").resolve("jib"), "/")); } return paths.get(); } @@ -115,8 +113,8 @@ public void setPaths(Provider paths) { */ @Nonnull private List convertToExtraDirectoryParametersList(Object obj) { - return project.files(obj).getFiles().stream() - .map(file -> new ExtraDirectoryParameters(objects, project, file.toPath(), "/")) + return this.objects.fileCollection().from(obj).getFiles().stream() + .map(file -> new ExtraDirectoryParameters(objects, file.toPath(), "/")) .collect(Collectors.toList()); } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java index 537b51f085..934d04859f 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParameters.java @@ -18,60 +18,47 @@ import com.google.cloud.tools.jib.plugins.common.RawConfiguration.ExtraDirectoriesConfiguration; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import javax.inject.Inject; -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.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Internal; /** Configuration of an extra directory. */ public class ExtraDirectoryParameters implements ExtraDirectoriesConfiguration { - private Project project; - private Property from; + ConfigurableFileCollection from; private Property into; private ListProperty includes; private ListProperty excludes; @Inject - public ExtraDirectoryParameters(ObjectFactory objects, Project project) { - this.project = project; - this.from = objects.property(Path.class).value(Paths.get("")); + public ExtraDirectoryParameters(ObjectFactory objects) { + this.from = objects.fileCollection(); this.into = objects.property(String.class).value("/"); this.includes = objects.listProperty(String.class).empty(); this.excludes = objects.listProperty(String.class).empty(); } - ExtraDirectoryParameters(ObjectFactory objects, Project project, Path from, String into) { - this(objects, project); - this.from = objects.property(Path.class).value(from); + ExtraDirectoryParameters(ObjectFactory objects, Path from, String into) { + this(objects); + this.from = objects.fileCollection().from(from); this.into = objects.property(String.class).value(into); } - @Input - public String getFromString() { - // Gradle warns about @Input annotations on File objects, so we have to expose a getter for a - // String to make them go away. - return from.get().toString(); - } - @Override - @Internal + @InputFiles public Path getFrom() { - return from.get(); + return from.getSingleFile().toPath(); } public void setFrom(Object from) { - this.from.set(project.file(from).toPath()); - } - - public void setFrom(Provider from) { - this.from.set(from.map(obj -> project.file(obj).toPath())); + this.from.from(from); } @Override diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParametersSpec.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParametersSpec.java index 53c57779c6..72dd4c2c21 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParametersSpec.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/ExtraDirectoryParametersSpec.java @@ -19,18 +19,27 @@ import javax.inject.Inject; import org.gradle.api.Action; import org.gradle.api.Project; +import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Nested; /** Allows to add {@link ExtraDirectoryParameters} objects to the list property of the same type. */ public class ExtraDirectoryParametersSpec { - private final Project project; private final ListProperty paths; + private final ObjectFactory objectFactory; + /** + * Spec init. + * + * @param project Project handle + * @param paths Provider for extra dirs + */ @Inject public ExtraDirectoryParametersSpec( Project project, ListProperty paths) { - this.project = project; + this.objectFactory = project.getObjects(); this.paths = paths; } @@ -41,8 +50,14 @@ public ExtraDirectoryParametersSpec( */ public void path(Action action) { ExtraDirectoryParameters extraDirectory = - project.getObjects().newInstance(ExtraDirectoryParameters.class, project); + objectFactory.newInstance(ExtraDirectoryParameters.class); action.execute(extraDirectory); paths.add(extraDirectory); } + + @Input + @Nested + public ListProperty getPaths() { + return paths; + } } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleProjectProperties.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleProjectProperties.java index 6a1978fe19..446bfb8ccb 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleProjectProperties.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleProjectProperties.java @@ -69,10 +69,16 @@ import org.gradle.api.artifacts.ResolvedArtifact; import org.gradle.api.artifacts.component.ProjectComponentIdentifier; import org.gradle.api.file.FileCollection; +import org.gradle.api.file.RegularFile; import org.gradle.api.logging.Logger; +import org.gradle.api.model.ObjectFactory; import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.plugins.WarPlugin; +import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.TaskProvider; @@ -98,6 +104,35 @@ public class GradleProjectProperties implements ProjectProperties { private static final String MAIN_SOURCE_SET_NAME = "main"; private static final Duration LOGGING_THREAD_SHUTDOWN_TIMEOUT = Duration.ofSeconds(1); + private final ObjectFactory objectFactory; + private final Logger logger; + private Path defaultCacheDirectory; + private Boolean warProject; + private Integer majorJavaVersion; + private Boolean offline; + private String name; + private String version; + private String warFilePath = ""; + + private Provider jarArchive; + private Property jarManifestMainClass; + + FileCollection classesOutputDirectories; + + Path resourcesOutputDirectory; + private Property progressFooterEnabled; + + @Input + @Classpath + public Path getResourcesOutputDirectory() { + return resourcesOutputDirectory; + } + + @Input + @Classpath + public FileCollection getClassesOutputDirectories() { + return classesOutputDirectories; + } /** * Generate an instance for a gradle project. @@ -127,7 +162,7 @@ public static GradleProjectProperties getForProject( project, logger, tempDirectoryProvider, extensionLoader, configurationName); } - String getWarFilePath() { + String getWarFilePath(Project project) { TaskProvider bootWarTask = TaskCommon.getBootWarTaskProvider(project); if (bootWarTask != null && bootWarTask.get().getEnabled()) { return bootWarTask.get().getOutputs().getFiles().getAsPath(); @@ -138,7 +173,7 @@ String getWarFilePath() { } private static boolean isProgressFooterEnabled(Project project) { - if ("plain".equals(System.getProperty(PropertyNames.CONSOLE))) { + if ("plain".equals(project.getProviders().systemProperty(PropertyNames.CONSOLE).getOrNull())) { return false; } @@ -157,12 +192,21 @@ private static boolean isProgressFooterEnabled(Project project) { } } - private final Project project; - private final SingleThreadedExecutor singleThreadedExecutor = new SingleThreadedExecutor(); - private final ConsoleLogger consoleLogger; + @VisibleForTesting + @SuppressWarnings("java:S2065") // keep sonar happy. We cannot serialize an executor + transient SingleThreadedExecutor singleThreadedExecutor = new SingleThreadedExecutor(); + + @Nullable + @SuppressWarnings("java:S2065") + private transient ConsoleLogger consoleLogger; + private final TempDirectoryProvider tempDirectoryProvider; private final Supplier>> extensionLoader; - private final String configurationName; + + private static final Object lock = new Object(); + FileCollection projectDependencies; + FileCollection allFiles; + FileCollection runtimeClasspath; @VisibleForTesting GradleProjectProperties( @@ -171,47 +215,79 @@ private static boolean isProgressFooterEnabled(Project project) { TempDirectoryProvider tempDirectoryProvider, Supplier>> extensionLoader, String configurationName) { - this.project = project; + JavaPluginExtension javaPluginExtension = + project.getExtensions().getByType(JavaPluginExtension.class); this.tempDirectoryProvider = tempDirectoryProvider; this.extensionLoader = extensionLoader; - this.configurationName = configurationName; - ConsoleLoggerBuilder consoleLoggerBuilder = - (isProgressFooterEnabled(project) - ? ConsoleLoggerBuilder.rich(singleThreadedExecutor, false) - : ConsoleLoggerBuilder.plain(singleThreadedExecutor).progress(logger::lifecycle)) - .lifecycle(logger::lifecycle); - if (logger.isDebugEnabled()) { - consoleLoggerBuilder.debug(logger::debug); + this.warProject = project.getPlugins().hasPlugin(WarPlugin.class); + this.defaultCacheDirectory = + project + .getLayout() + .getBuildDirectory() + .getAsFile() + .get() + .toPath() + .resolve(CACHE_DIRECTORY_NAME); + this.offline = project.getGradle().getStartParameter().isOffline(); + this.version = project.getVersion() != null ? project.getVersion().toString() : ""; + this.objectFactory = project.getObjects(); + this.jarArchive = this.objectFactory.fileProperty(); + this.jarManifestMainClass = this.objectFactory.property(String.class); + this.logger = logger; + this.progressFooterEnabled = project.getObjects().property(Boolean.class); + this.progressFooterEnabled.set(isProgressFooterEnabled(project)); + this.projectDependencies = + project.files( + project.getConfigurations().getByName(configurationName).getResolvedConfiguration() + .getResolvedArtifacts().stream() + .filter( + artifact -> + artifact.getId().getComponentIdentifier() + instanceof ProjectComponentIdentifier) + .map(ResolvedArtifact::getFile) + .collect(Collectors.toList())); + + this.allFiles = project.getConfigurations().getByName(configurationName).filter(File::exists); + this.runtimeClasspath = project.getConfigurations().getByName(configurationName); + Task jarTask = project.getTasks().findByName("jar"); + if (jarTask != null) { + this.jarArchive = ((Jar) jarTask).getArchiveFile(); + this.jarManifestMainClass.set(computeMainClassFromJarPlugin((Jar) jarTask)); } - if (logger.isInfoEnabled()) { - consoleLoggerBuilder.info(logger::info); - } - if (logger.isWarnEnabled()) { - consoleLoggerBuilder.warn(logger::warn); + + SourceSet mainSourceSet = javaPluginExtension.getSourceSets().getByName(MAIN_SOURCE_SET_NAME); + this.classesOutputDirectories = mainSourceSet.getOutput().getClassesDirs().filter(File::exists); + this.resourcesOutputDirectory = mainSourceSet.getOutput().getResourcesDir().toPath(); + + this.name = project.getName(); + JavaVersion ver = javaPluginExtension.getTargetCompatibility(); + + this.majorJavaVersion = Integer.valueOf(ver.getMajorVersion()); + + if (isWarProject()) { + this.warFilePath = getWarFilePath(project); } - if (logger.isErrorEnabled()) { - consoleLoggerBuilder.error(logger::error); + } + + public TempDirectoryProvider getTempDirectoryProvider() { + return tempDirectoryProvider; + } + + @Internal + @VisibleForTesting + synchronized SingleThreadedExecutor getSingleThreadedExecutor() { + if (singleThreadedExecutor == null) { + this.singleThreadedExecutor = new SingleThreadedExecutor(); } - consoleLogger = consoleLoggerBuilder.build(); + return this.singleThreadedExecutor; } @Override public JibContainerBuilder createJibContainerBuilder( JavaContainerBuilder javaContainerBuilder, ContainerizingMode containerizingMode) { try { - FileCollection projectDependencies = - project.files( - project.getConfigurations().getByName(configurationName).getResolvedConfiguration() - .getResolvedArtifacts().stream() - .filter( - artifact -> - artifact.getId().getComponentIdentifier() - instanceof ProjectComponentIdentifier) - .map(ResolvedArtifact::getFile) - .collect(Collectors.toList())); if (isWarProject()) { - String warFilePath = getWarFilePath(); log(LogEvent.info("WAR project identified, creating WAR image from: " + warFilePath)); Path explodedWarPath = tempDirectoryProvider.newDirectory(); ZipUtil.unzip(Paths.get(warFilePath), explodedWarPath); @@ -221,13 +297,6 @@ public JibContainerBuilder createJibContainerBuilder( projectDependencies.getFiles().stream().map(File::getName).collect(Collectors.toSet())); } - SourceSet mainSourceSet = getMainSourceSet(); - FileCollection classesOutputDirectories = - mainSourceSet.getOutput().getClassesDirs().filter(File::exists); - Path resourcesOutputDirectory = mainSourceSet.getOutput().getResourcesDir().toPath(); - FileCollection allFiles = - project.getConfigurations().getByName(configurationName).filter(File::exists); - FileCollection nonProjectDependencies = allFiles .minus(classesOutputDirectories) @@ -269,10 +338,7 @@ public JibContainerBuilder createJibContainerBuilder( case PACKAGED: // Add a JAR - Jar jarTask = (Jar) project.getTasks().findByName("jar"); - Path jarPath = jarTask.getArchiveFile().get().getAsFile().toPath(); - log(LogEvent.debug("Using JAR: " + jarPath)); - javaContainerBuilder.addToClasspath(jarPath); + extractedJar(javaContainerBuilder); break; default: @@ -286,11 +352,15 @@ public JibContainerBuilder createJibContainerBuilder( } } + private void extractedJar(JavaContainerBuilder javaContainerBuilder) throws IOException { + Path jarPath = this.jarArchive.get().getAsFile().toPath(); + log(LogEvent.debug("Using JAR: " + jarPath)); + javaContainerBuilder.addToClasspath(jarPath); + } + @Override public List getClassFiles() throws IOException { // TODO: Consolidate with createJibContainerBuilder - FileCollection classesOutputDirectories = - getMainSourceSet().getOutput().getClassesDirs().filter(File::exists); List classFiles = new ArrayList<>(); for (File classesOutputDirectory : classesOutputDirectories) { classFiles.addAll(new DirectoryWalker(classesOutputDirectory.toPath()).walk()); @@ -301,7 +371,7 @@ public List getClassFiles() throws IOException { @Override public List getDependencies() { List dependencies = new ArrayList<>(); - FileCollection runtimeClasspath = project.getConfigurations().getByName(configurationName); + // To be on the safe side with the order, calling "forEach" first (no filtering operations). runtimeClasspath.forEach( file -> { @@ -316,7 +386,7 @@ public List getDependencies() { @Override public void waitForLoggingThread() { - singleThreadedExecutor.shutDownAndAwaitTermination(LOGGING_THREAD_SHUTDOWN_TIMEOUT); + getSingleThreadedExecutor().shutDownAndAwaitTermination(LOGGING_THREAD_SHUTDOWN_TIMEOUT); } @Override @@ -333,13 +403,43 @@ TimerEvent.class, new TimerEventHandler(message -> log(LogEvent.debug(message))) ProgressDisplayGenerator.generateProgressDisplay( update.getProgress(), update.getUnfinishedLeafTasks()); footer.add(""); - consoleLogger.setFooter(footer); + getConsoleLogger().setFooter(footer); })); } @Override public void log(LogEvent logEvent) { - consoleLogger.log(logEvent.getLevel(), logEvent.getMessage()); + getConsoleLogger().log(logEvent.getLevel(), logEvent.getMessage()); + } + + @Internal + @VisibleForTesting + ConsoleLogger getConsoleLogger() { + synchronized (lock) { + if (this.consoleLogger == null) { + ConsoleLoggerBuilder consoleLoggerBuilder = + (Boolean.TRUE.equals(this.progressFooterEnabled.get()) + ? ConsoleLoggerBuilder.rich(getSingleThreadedExecutor(), false) + : ConsoleLoggerBuilder.plain(getSingleThreadedExecutor()) + .progress(logger::lifecycle)) + .lifecycle(logger::lifecycle); + if (logger.isDebugEnabled()) { + consoleLoggerBuilder.debug(logger::debug); + } + if (logger.isInfoEnabled()) { + consoleLoggerBuilder.info(logger::info); + } + if (logger.isWarnEnabled()) { + consoleLoggerBuilder.warn(logger::warn); + } + if (logger.isErrorEnabled()) { + consoleLoggerBuilder.error(logger::error); + } + this.consoleLogger = consoleLoggerBuilder.build(); + } + } + + return consoleLogger; } @Override @@ -360,12 +460,19 @@ public String getPluginName() { @Nullable @Override public String getMainClassFromJarPlugin() { - Jar jarTask = (Jar) project.getTasks().findByName("jar"); - if (jarTask == null) { + if (!this.jarArchive.isPresent()) { + return null; + } + return this.jarManifestMainClass.getOrNull(); + } + + @Nullable + private String computeMainClassFromJarPlugin(Jar task) { + if (!this.jarArchive.isPresent()) { return null; } - Object value = jarTask.getManifest().getAttributes().get("Main-Class"); + Object value = task.getManifest().getAttributes().get("Main-Class"); if (value instanceof Provider) { value = ((Provider) value).getOrNull(); @@ -384,7 +491,7 @@ public String getMainClassFromJarPlugin() { @Override public Path getDefaultCacheDirectory() { - return project.getBuildDir().toPath().resolve(CACHE_DIRECTORY_NAME); + return this.defaultCacheDirectory; } @Override @@ -394,7 +501,7 @@ public String getJarPluginName() { @Override public boolean isWarProject() { - return project.getPlugins().hasPlugin(WarPlugin.class); + return this.warProject; } /** @@ -430,34 +537,29 @@ static FileCollection getInputFiles( @Override public String getName() { - return project.getName(); + return this.name; } @Override public String getVersion() { - return project.getVersion().toString(); + return this.version; } @Override public int getMajorJavaVersion() { - JavaVersion version = JavaVersion.current(); - JavaPluginExtension javaPluginExtension = - project.getExtensions().findByType(JavaPluginExtension.class); - if (javaPluginExtension != null) { - version = javaPluginExtension.getTargetCompatibility(); - } - return Integer.valueOf(version.getMajorVersion()); + return this.majorJavaVersion; } @Override public boolean isOffline() { - return project.getGradle().getStartParameter().isOffline(); + return this.offline; } @Override public JibContainerBuilder runPluginExtensions( List extensionConfigs, - JibContainerBuilder jibContainerBuilder) + JibContainerBuilder jibContainerBuilder, + Optional project) throws JibPluginExtensionException { if (extensionConfigs.isEmpty()) { log(LogEvent.debug("No Jib plugin extensions configured to load")); @@ -472,8 +574,9 @@ public JibContainerBuilder runPluginExtensions( extension = findConfiguredExtension(loadedExtensions, config); log(LogEvent.lifecycle("Running extension: " + config.getExtensionClass())); + Project proj = (Project) project.orElseThrow(IllegalStateException::new); buildPlan = - runPluginExtension(extension.getExtraConfigType(), extension, config, buildPlan); + runPluginExtension(extension.getExtraConfigType(), extension, config, buildPlan, proj); ImageReference.parse(buildPlan.getBaseImage()); // to validate image reference } return jibContainerBuilder.applyContainerBuildPlan(buildPlan); @@ -494,7 +597,8 @@ private ContainerBuildPlan runPluginExtension( Optional> extraConfigType, JibGradlePluginExtension extension, ExtensionConfiguration config, - ContainerBuildPlan buildPlan) + ContainerBuildPlan buildPlan, + Project project) throws JibPluginExtensionException { T extraConfig = null; Optional configs = config.getExtraConfiguration(); @@ -509,7 +613,7 @@ private ContainerBuildPlan runPluginExtension( // configs.get() is of type Action, so this cast always succeeds. // (Note generic is erased at runtime.) Action action = (Action) configs.get(); - extraConfig = project.getObjects().newInstance(extraConfigType.get(), project); + extraConfig = this.objectFactory.newInstance(extraConfigType.get(), project); action.execute(extraConfig); } } @@ -543,10 +647,4 @@ private JibGradlePluginExtension findConfiguredExtension( } return found.get(); } - - private SourceSet getMainSourceSet() { - SourceSetContainer sourceSetContainer = - project.getExtensions().getByType(SourceSetContainer.class); - return sourceSetContainer.getByName(MAIN_SOURCE_SET_NAME); - } } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java index 6f2d9d16d1..a1eacfbaa3 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java @@ -16,6 +16,8 @@ package com.google.cloud.tools.jib.gradle; +import static org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME; + import com.google.cloud.tools.jib.gradle.skaffold.CheckJibVersionTask; import com.google.cloud.tools.jib.gradle.skaffold.FilesTaskV2; import com.google.cloud.tools.jib.gradle.skaffold.InitTask; @@ -30,8 +32,8 @@ import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; +import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.TaskContainer; import org.gradle.api.tasks.TaskProvider; import org.gradle.api.tasks.bundling.Jar; @@ -39,7 +41,7 @@ public class JibPlugin implements Plugin { - @VisibleForTesting static final GradleVersion GRADLE_MIN_VERSION = GradleVersion.version("5.1"); + @VisibleForTesting static final GradleVersion GRADLE_MIN_VERSION = GradleVersion.version("8.0"); public static final String JIB_EXTENSION_NAME = "jib"; public static final String BUILD_IMAGE_TASK_NAME = "jib"; @@ -101,6 +103,7 @@ public void apply(Project project) { BuildImageTask.class, task -> { task.setGroup("Jib"); + task.setDescription("Builds a container image to a registry."); task.setJibExtension(jibExtension); }); @@ -182,11 +185,11 @@ public void apply(Project project) { } } + JavaPluginExtension javaPluginExtension = + project.getExtensions().getByType(JavaPluginExtension.class); SourceSet mainSourceSet = - projectAfterEvaluation - .getExtensions() - .getByType(SourceSetContainer.class) - .getByName(SourceSet.MAIN_SOURCE_SET_NAME); + javaPluginExtension.getSourceSets().getByName(MAIN_SOURCE_SET_NAME); + jibDependencies.add(mainSourceSet.getRuntimeClasspath()); jibDependencies.add( projectAfterEvaluation diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/OutputPathsParameters.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/OutputPathsParameters.java index 46b4b6e608..656c5e8bff 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/OutputPathsParameters.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/OutputPathsParameters.java @@ -17,6 +17,7 @@ package com.google.cloud.tools.jib.gradle; import com.google.cloud.tools.jib.plugins.common.PropertyNames; +import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import javax.inject.Inject; @@ -27,8 +28,7 @@ /** Object that configures where Jib should create its build output files. */ public class OutputPathsParameters { - private final Project project; - + private final Path projectDir; private Path digest; private Path tar; private Path imageId; @@ -36,11 +36,13 @@ public class OutputPathsParameters { @Inject public OutputPathsParameters(Project project) { - this.project = project; - digest = project.getBuildDir().toPath().resolve("jib-image.digest"); - imageId = project.getBuildDir().toPath().resolve("jib-image.id"); - imageJson = project.getBuildDir().toPath().resolve("jib-image.json"); - tar = project.getBuildDir().toPath().resolve("jib-image.tar"); + File buildDir = project.getLayout().getBuildDirectory().getAsFile().get(); + + this.projectDir = project.getProjectDir().toPath(); + digest = buildDir.toPath().resolve("jib-image.digest"); + imageId = buildDir.toPath().resolve("jib-image.id"); + imageJson = buildDir.toPath().resolve("jib-image.json"); + tar = buildDir.toPath().resolve("jib-image.tar"); } @Input @@ -102,6 +104,6 @@ public void setTar(String tar) { private Path getRelativeToProjectRoot(Path configuration, String propertyName) { String property = System.getProperty(propertyName); Path path = property != null ? Paths.get(property) : configuration; - return path.isAbsolute() ? path : project.getProjectDir().toPath().resolve(path); + return path.isAbsolute() ? path : this.projectDir.resolve(path); } } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/FilesTaskV2.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/FilesTaskV2.java index fc15b021cf..05e4f34aa4 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/FilesTaskV2.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/FilesTaskV2.java @@ -139,10 +139,7 @@ private void addGradleFiles(Project project) { skaffoldFilesOutput.addBuild(project.getBuildFile().toPath()); // Add settings.gradle - if (project.getGradle().getStartParameter().getSettingsFile() != null) { - skaffoldFilesOutput.addBuild( - project.getGradle().getStartParameter().getSettingsFile().toPath()); - } else if (Files.exists(projectPath.resolve(Settings.DEFAULT_SETTINGS_FILE))) { + if (Files.exists(projectPath.resolve(Settings.DEFAULT_SETTINGS_FILE))) { skaffoldFilesOutput.addBuild(projectPath.resolve(Settings.DEFAULT_SETTINGS_FILE)); } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SkaffoldSyncParameters.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SkaffoldSyncParameters.java index ceeca5d172..2383230a6e 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SkaffoldSyncParameters.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SkaffoldSyncParameters.java @@ -17,23 +17,21 @@ package com.google.cloud.tools.jib.gradle.skaffold; import java.io.File; -import java.nio.file.Path; -import java.util.Collections; -import java.util.Set; -import java.util.stream.Collectors; import javax.inject.Inject; import org.gradle.api.Project; -import org.gradle.api.tasks.Internal; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.tasks.InputFiles; /** Skaffold specific JibExtension parameters for configuring files to sync. */ public class SkaffoldSyncParameters { - private final Project project; - private Set excludes = Collections.emptySet(); + private final ConfigurableFileCollection fileCollection; + private ConfigurableFileCollection excludes; @Inject public SkaffoldSyncParameters(Project project) { - this.project = project; + this.fileCollection = project.getObjects().fileCollection(); + this.excludes = project.getObjects().fileCollection(); } /** @@ -41,8 +39,8 @@ public SkaffoldSyncParameters(Project project) { * * @return a set of absolute paths */ - @Internal - public Set getExcludes() { + @InputFiles + public ConfigurableFileCollection getExcludes() { return excludes; } @@ -53,10 +51,11 @@ public Set getExcludes() { * @param paths paths to set on excludes */ public void setExcludes(Object paths) { - this.excludes = - project.files(paths).getFiles().stream() - .map(File::toPath) - .map(Path::toAbsolutePath) - .collect(Collectors.toSet()); + this.excludes.from(paths); + } + + @InputFiles + public ConfigurableFileCollection getFileCollection() { + return fileCollection; } } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SkaffoldWatchParameters.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SkaffoldWatchParameters.java index 5f294100b5..e14081a968 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SkaffoldWatchParameters.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SkaffoldWatchParameters.java @@ -17,26 +17,25 @@ package com.google.cloud.tools.jib.gradle.skaffold; import java.io.File; -import java.nio.file.Path; -import java.util.Collections; -import java.util.Set; -import java.util.stream.Collectors; import javax.inject.Inject; import org.gradle.api.Project; -import org.gradle.api.tasks.Internal; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.tasks.InputFiles; /** Skaffold specific JibExtension parameters for configuring files to watch. */ public class SkaffoldWatchParameters { - private final Project project; - - private Set buildIncludes = Collections.emptySet(); - private Set includes = Collections.emptySet(); - private Set excludes = Collections.emptySet(); + private final ConfigurableFileCollection fileCollection; + private ConfigurableFileCollection buildIncludes; + private ConfigurableFileCollection includes; + private ConfigurableFileCollection excludes; @Inject public SkaffoldWatchParameters(Project project) { - this.project = project; + this.fileCollection = project.getObjects().fileCollection(); + this.buildIncludes = project.getObjects().fileCollection(); + this.includes = project.getObjects().fileCollection(); + this.excludes = project.getObjects().fileCollection(); } /** @@ -44,8 +43,8 @@ public SkaffoldWatchParameters(Project project) { * * @return a set of absolute paths */ - @Internal - public Set getBuildIncludes() { + @InputFiles + public ConfigurableFileCollection getBuildIncludes() { return buildIncludes; } @@ -56,11 +55,7 @@ public Set getBuildIncludes() { * @param paths paths to set on includes */ public void setBuildIncludes(Object paths) { - this.buildIncludes = - project.files(paths).getFiles().stream() - .map(File::toPath) - .map(Path::toAbsolutePath) - .collect(Collectors.toSet()); + this.buildIncludes.from(paths); } /** @@ -68,8 +63,8 @@ public void setBuildIncludes(Object paths) { * * @return a set of absolute paths */ - @Internal - public Set getIncludes() { + @InputFiles + public ConfigurableFileCollection getIncludes() { return includes; } @@ -80,11 +75,7 @@ public Set getIncludes() { * @param paths paths to set on includes */ public void setIncludes(Object paths) { - this.includes = - project.files(paths).getFiles().stream() - .map(File::toPath) - .map(Path::toAbsolutePath) - .collect(Collectors.toSet()); + this.includes.from(paths); } /** @@ -92,11 +83,9 @@ public void setIncludes(Object paths) { * * @return a set of absolute paths */ - @Internal - public Set getExcludes() { - // Gradle warns about @Input annotations on File objects, so we have to expose a getter for a - // String to make them go away. - return excludes; + @InputFiles + public ConfigurableFileCollection getExcludes() { + return this.excludes; } /** @@ -106,10 +95,11 @@ public Set getExcludes() { * @param paths paths to set on excludes */ public void setExcludes(Object paths) { - this.excludes = - project.files(paths).getFiles().stream() - .map(File::toPath) - .map(Path::toAbsolutePath) - .collect(Collectors.toSet()); + this.excludes.from(paths); + } + + @InputFiles + public ConfigurableFileCollection getFileCollection() { + return fileCollection; } } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SyncMapTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SyncMapTask.java index 7d8d9e4b02..c43f36179d 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SyncMapTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/skaffold/SyncMapTask.java @@ -24,6 +24,8 @@ import com.google.cloud.tools.jib.plugins.common.InvalidContainerizingModeException; import com.google.cloud.tools.jib.plugins.common.PluginConfigurationProcessor; import com.google.common.base.Preconditions; +import java.io.File; +import java.util.stream.Collectors; import javax.annotation.Nullable; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; @@ -85,7 +87,9 @@ public void listFilesAndTargets() { PluginConfigurationProcessor.getSkaffoldSyncMap( configuration, projectProperties, - jibExtension.getSkaffold().getSync().getExcludes()); + jibExtension.getSkaffold().getSync().getExcludes().getFiles().stream() + .map(File::toPath) + .collect(Collectors.toSet())); System.out.println(); System.out.println("BEGIN JIB JSON: SYNCMAP/1"); diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleProjectPropertiesExtensionTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleProjectPropertiesExtensionTest.java index 63718ce0e5..fd68285e73 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleProjectPropertiesExtensionTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleProjectPropertiesExtensionTest.java @@ -16,6 +16,8 @@ package com.google.cloud.tools.jib.gradle; +import static org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME; + import com.google.cloud.tools.jib.api.InvalidImageReferenceException; import com.google.cloud.tools.jib.api.Jib; import com.google.cloud.tools.jib.api.JibContainerBuilder; @@ -35,11 +37,21 @@ import java.util.Map; import java.util.Optional; import org.gradle.api.Action; +import org.gradle.api.JavaVersion; import org.gradle.api.Project; +import org.gradle.api.file.RegularFile; +import org.gradle.api.internal.provider.DefaultProperty; import org.gradle.api.logging.Logger; import org.gradle.api.logging.configuration.ConsoleOutput; import org.gradle.api.model.ObjectFactory; +import org.gradle.api.plugins.ExtensionContainer; import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.api.tasks.TaskContainer; +import org.gradle.jvm.tasks.Jar; import org.hamcrest.CoreMatchers; import org.hamcrest.MatcherAssert; import org.junit.Assert; @@ -205,6 +217,21 @@ private ExtensionDefinedBarConfig(String barParam) { @Mock private Logger mockLogger; @Mock private ObjectFactory mockObjectFactory; + @Mock private JavaPluginExtension mockJavaPluginExtension; + @Mock private SourceSetContainer mockSourceSetContainer; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private SourceSet mockSourceSet; + + @Mock private TaskContainer mockReturnContainer; + + @Mock private ExtensionContainer mockExtensionContainer; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Jar mockJarTask; + + @Mock private Provider mockProviderFile; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Project mockProject; @@ -219,7 +246,24 @@ public void setUp() { Mockito.when(mockLogger.isInfoEnabled()).thenReturn(true); Mockito.when(mockLogger.isWarnEnabled()).thenReturn(true); Mockito.when(mockLogger.isErrorEnabled()).thenReturn(true); - + Mockito.when(mockProject.getExtensions()).thenReturn(mockExtensionContainer); + Mockito.when(mockProject.getTasks()).thenReturn(mockReturnContainer); + Mockito.when(mockReturnContainer.findByName("jar")).thenReturn(mockJarTask); + Mockito.when(mockJarTask.getArchiveFile()).thenReturn(mockProviderFile); + Mockito.when(mockProviderFile.isPresent()).thenReturn(true); + + Mockito.when(mockExtensionContainer.getByType(JavaPluginExtension.class)) + .thenReturn(mockJavaPluginExtension); + Mockito.when(mockJavaPluginExtension.getSourceSets()).thenReturn(mockSourceSetContainer); + Mockito.when(mockJavaPluginExtension.getTargetCompatibility()) + .thenReturn(JavaVersion.VERSION_1_8); + Mockito.when(mockSourceSetContainer.getByName(MAIN_SOURCE_SET_NAME)).thenReturn(mockSourceSet); + + Mockito.when(mockObjectFactory.property(String.class)) + .thenReturn(new DefaultProperty<>(null, String.class)); + // Mockito.when(mockObjectFactory.fileProperty()).thenReturn(new DefaultRegularFileVar()); + Mockito.when(mockObjectFactory.property(Boolean.class)) + .thenReturn(new DefaultProperty<>(null, Boolean.class)); Mockito.when(mockProject.getGradle().getStartParameter().getConsoleOutput()) .thenReturn(ConsoleOutput.Plain); Mockito.when(mockProject.getObjects()).thenReturn(mockObjectFactory); @@ -248,7 +292,8 @@ public void testRunPluginExtensions_noExtensionsConfigured() throws JibPluginExt loadedExtensions = Arrays.asList(extension); JibContainerBuilder extendedBuilder = - gradleProjectProperties.runPluginExtensions(Collections.emptyList(), containerBuilder); + gradleProjectProperties.runPluginExtensions( + Collections.emptyList(), containerBuilder, Optional.of(mockProject)); Assert.assertSame(extendedBuilder, containerBuilder); gradleProjectProperties.waitForLoggingThread(); @@ -259,7 +304,7 @@ public void testRunPluginExtensions_noExtensionsConfigured() throws JibPluginExt public void testRunPluginExtensions_configuredExtensionNotFound() { try { gradleProjectProperties.runPluginExtensions( - Arrays.asList(new FooExtensionConfig()), containerBuilder); + Arrays.asList(new FooExtensionConfig()), containerBuilder, Optional.of(mockProject)); Assert.fail(); } catch (JibPluginExtensionException ex) { Assert.assertEquals( @@ -281,7 +326,7 @@ public void testRunPluginExtensions() throws JibPluginExtensionException { JibContainerBuilder extendedBuilder = gradleProjectProperties.runPluginExtensions( - Arrays.asList(new FooExtensionConfig()), containerBuilder); + Arrays.asList(new FooExtensionConfig()), containerBuilder, Optional.of(mockProject)); Assert.assertEquals("user from extension", extendedBuilder.toContainerBuildPlan().getUser()); gradleProjectProperties.waitForLoggingThread(); @@ -305,7 +350,7 @@ public void testRunPluginExtensions_exceptionFromExtension() { try { gradleProjectProperties.runPluginExtensions( - Arrays.asList(new FooExtensionConfig()), containerBuilder); + Arrays.asList(new FooExtensionConfig()), containerBuilder, Optional.of(mockProject)); Assert.fail(); } catch (JibPluginExtensionException ex) { Assert.assertEquals("exception from extension", ex.getMessage()); @@ -323,7 +368,7 @@ public void testRunPluginExtensions_invalidBaseImageFromExtension() { try { gradleProjectProperties.runPluginExtensions( - Arrays.asList(new FooExtensionConfig()), containerBuilder); + Arrays.asList(new FooExtensionConfig()), containerBuilder, Optional.of(mockProject)); Assert.fail(); } catch (JibPluginExtensionException ex) { Assert.assertEquals("invalid base image reference: in*val+id", ex.getMessage()); @@ -346,12 +391,16 @@ public void testRunPluginExtensions_extensionOrder() throws JibPluginExtensionEx JibContainerBuilder extendedBuilder1 = gradleProjectProperties.runPluginExtensions( - Arrays.asList(new FooExtensionConfig(), new BarExtensionConfig()), containerBuilder); + Arrays.asList(new FooExtensionConfig(), new BarExtensionConfig()), + containerBuilder, + Optional.of(mockProject)); Assert.assertEquals("bar", extendedBuilder1.toContainerBuildPlan().getBaseImage()); JibContainerBuilder extendedBuilder2 = gradleProjectProperties.runPluginExtensions( - Arrays.asList(new BarExtensionConfig(), new FooExtensionConfig()), containerBuilder); + Arrays.asList(new BarExtensionConfig(), new FooExtensionConfig()), + containerBuilder, + Optional.of(mockProject)); Assert.assertEquals("foo", extendedBuilder2.toContainerBuildPlan().getBaseImage()); } @@ -366,7 +415,8 @@ public void testRunPluginExtensions_customProperties() throws JibPluginExtension JibContainerBuilder extendedBuilder = gradleProjectProperties.runPluginExtensions( Arrays.asList(new FooExtensionConfig(ImmutableMap.of("user", "65432"))), - containerBuilder); + containerBuilder, + Optional.of(mockProject)); Assert.assertEquals("65432", extendedBuilder.toContainerBuildPlan().getUser()); } @@ -388,7 +438,9 @@ public void testRunPluginExtensions_extensionDefinedConfigurations_emptyConfig() loadedExtensions = Arrays.asList(fooExtension, barExtension); gradleProjectProperties.runPluginExtensions( - Arrays.asList(new FooExtensionConfig(), new BarExtensionConfig()), containerBuilder); + Arrays.asList(new FooExtensionConfig(), new BarExtensionConfig()), + containerBuilder, + Optional.of(mockProject)); } @Test @@ -412,7 +464,8 @@ public void testRunPluginExtensions_extensionDefinedConfigurations() Arrays.asList( new FooExtensionConfig(new ExtensionDefinedFooConfig("fooParamValue")), new BarExtensionConfig(new ExtensionDefinedBarConfig("barParamValue"))), - containerBuilder); + containerBuilder, + Optional.of(mockProject)); } @Test @@ -427,7 +480,8 @@ public void testRunPluginExtensions_ignoreUnexpectedExtraConfig() new BaseExtensionConfig<>( BaseExtension.class.getName(), Collections.emptyMap(), (ignored) -> {}); try { - gradleProjectProperties.runPluginExtensions(Arrays.asList(extensionConfig), containerBuilder); + gradleProjectProperties.runPluginExtensions( + Arrays.asList(extensionConfig), containerBuilder, Optional.of(mockProject)); Assert.fail(); } catch (IllegalArgumentException ex) { Assert.assertEquals( @@ -448,7 +502,7 @@ public void testRunPluginExtensions_runtimeExceptionFromExtension() { try { gradleProjectProperties.runPluginExtensions( - Arrays.asList(new FooExtensionConfig()), containerBuilder); + Arrays.asList(new FooExtensionConfig()), containerBuilder, Optional.of(mockProject)); Assert.fail(); } catch (JibPluginExtensionException ex) { Assert.assertEquals(FooExtension.class, ex.getExtensionClass()); diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleProjectPropertiesTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleProjectPropertiesTest.java index 7698228ab0..504f946a18 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleProjectPropertiesTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleProjectPropertiesTest.java @@ -17,6 +17,8 @@ package com.google.cloud.tools.jib.gradle; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -144,6 +146,9 @@ public void setUp() throws URISyntaxException, IOException { .withProjectDir(projectDir.toFile()) .withGradleUserHomeDir(temporaryFolder.newFolder()) .build(); + + project.getRepositories().add(project.getRepositories().mavenCentral()); + project.getPlugins().apply("java"); DependencyHandler dependencies = project.getDependencies(); @@ -161,14 +166,6 @@ public void setUp() throws URISyntaxException, IOException { // We can't commit an empty directory in Git, so create (if not exist). Path emptyDirectory = getResource("gradle/webapp").resolve("WEB-INF/classes/empty_dir"); Files.createDirectories(emptyDirectory); - - gradleProjectProperties = - new GradleProjectProperties( - project, - mockLogger, - mockTempDirectoryProvider, - mockExtensionLoader, - JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME); } @Test @@ -177,11 +174,14 @@ public void testGetMainClassFromJar_success() { jar.setManifest( new DefaultManifest(null).attributes(ImmutableMap.of("Main-Class", "some.main.class"))); + setupGradleProjectPropertiesInstance(); assertThat(gradleProjectProperties.getMainClassFromJarPlugin()).isEqualTo("some.main.class"); } @Test public void testGetMainClassFromJar_missing() { + setupGradleProjectPropertiesInstance(); + assertThat(gradleProjectProperties.getMainClassFromJarPlugin()).isNull(); } @@ -193,6 +193,8 @@ public void testGetMainClassFromJarAsProperty_success() { Jar jar = project.getTasks().withType(Jar.class).getByName("jar"); jar.setManifest(new DefaultManifest(null).attributes(ImmutableMap.of("Main-Class", mainClass))); + setupGradleProjectPropertiesInstance(); + assertThat(gradleProjectProperties.getMainClassFromJarPlugin()).isEqualTo("some.main.class"); } @@ -202,13 +204,15 @@ public void testGetMainClassFromJarAsPropertyWithValueNull_missing() { Jar jar = project.getTasks().withType(Jar.class).getByName("jar"); jar.setManifest(new DefaultManifest(null).attributes(ImmutableMap.of("Main-Class", mainClass))); - + setupGradleProjectPropertiesInstance(); assertThat(gradleProjectProperties.getMainClassFromJarPlugin()).isNull(); } @Test public void testIsWarProject() { project.getPlugins().apply("war"); + setupGradleProjectPropertiesInstance(); + assertThat(gradleProjectProperties.isWarProject()).isTrue(); } @@ -258,35 +262,41 @@ public void testConvertPermissionsMap() { @Test public void testGetMajorJavaVersion() { - JavaPluginExtension extension = project.getExtensions().findByType(JavaPluginExtension.class); + JavaPluginExtension convention = project.getExtensions().findByType(JavaPluginExtension.class); + + convention.setTargetCompatibility(JavaVersion.VERSION_1_3); + setupGradleProjectPropertiesInstance(); - extension.setTargetCompatibility(JavaVersion.VERSION_1_3); assertThat(gradleProjectProperties.getMajorJavaVersion()).isEqualTo(3); - extension.setTargetCompatibility(JavaVersion.VERSION_11); + convention.setTargetCompatibility(JavaVersion.VERSION_11); + setupGradleProjectPropertiesInstance(); assertThat(gradleProjectProperties.getMajorJavaVersion()).isEqualTo(11); - extension.setTargetCompatibility(JavaVersion.VERSION_1_9); + convention.setTargetCompatibility(JavaVersion.VERSION_1_9); + setupGradleProjectPropertiesInstance(); assertThat(gradleProjectProperties.getMajorJavaVersion()).isEqualTo(9); } @Test public void testGetMajorJavaVersion_jvm8() { Assume.assumeThat(JavaVersion.current(), CoreMatchers.is(JavaVersion.VERSION_1_8)); - + setupGradleProjectPropertiesInstance(); assertThat(gradleProjectProperties.getMajorJavaVersion()).isEqualTo(8); } @Test public void testGetMajorJavaVersion_jvm11() { Assume.assumeThat(JavaVersion.current(), CoreMatchers.is(JavaVersion.VERSION_11)); - + setupGradleProjectPropertiesInstance(); assertThat(gradleProjectProperties.getMajorJavaVersion()).isEqualTo(11); } @Test public void testCreateContainerBuilder_correctSourceFiles() throws URISyntaxException, InvalidImageReferenceException, CacheDirectoryCreationException { + setupGradleProjectPropertiesInstance(); + ContainerBuilderLayers layers = new ContainerBuilderLayers(setupBuildContext()); Path applicationDirectory = getResource("gradle/application"); @@ -352,6 +362,7 @@ public void testCreateContainerBuilder_noClassesFiles() @Test public void testCreateContainerBuilder_correctExtractionPaths() throws InvalidImageReferenceException, CacheDirectoryCreationException { + setupGradleProjectPropertiesInstance(); ContainerBuilderLayers layers = new ContainerBuilderLayers(setupBuildContext()); assertThat(layers.dependenciesLayer.getEntries()) @@ -382,6 +393,7 @@ public void testCreateContainerBuilder_war() throws URISyntaxException, IOException, InvalidImageReferenceException, CacheDirectoryCreationException { Path unzipTarget = setUpWarProject(getResource("gradle/webapp")); + setupGradleProjectPropertiesInstance(); ContainerBuilderLayers layers = new ContainerBuilderLayers(setupBuildContext()); assertThat(layers.dependenciesLayer.getEntries()) @@ -444,7 +456,7 @@ public void testCreateContainerBuilder_noErrorIfWebInfClassesDoesNotExist() throws IOException, InvalidImageReferenceException { temporaryFolder.newFolder("WEB-INF", "lib"); setUpWarProject(temporaryFolder.getRoot().toPath()); - + setupGradleProjectPropertiesInstance(); assertThat( gradleProjectProperties.createJibContainerBuilder( JavaContainerBuilder.from("ignored"), ContainerizingMode.EXPLODED)) @@ -456,7 +468,7 @@ public void testCreateContainerBuilder_noErrorIfWebInfLibDoesNotExist() throws IOException, InvalidImageReferenceException { temporaryFolder.newFolder("WEB-INF", "classes"); setUpWarProject(temporaryFolder.getRoot().toPath()); - + setupGradleProjectPropertiesInstance(); assertThat( gradleProjectProperties.createJibContainerBuilder( JavaContainerBuilder.from("ignored"), ContainerizingMode.EXPLODED)) @@ -467,22 +479,33 @@ public void testCreateContainerBuilder_noErrorIfWebInfLibDoesNotExist() public void testCreateContainerBuilder_noErrorIfWebInfDoesNotExist() throws IOException, InvalidImageReferenceException { setUpWarProject(temporaryFolder.getRoot().toPath()); - + setupGradleProjectPropertiesInstance(); assertThat( gradleProjectProperties.createJibContainerBuilder( JavaContainerBuilder.from("ignored"), ContainerizingMode.EXPLODED)) .isNotNull(); } + private void setupGradleProjectPropertiesInstance() { + gradleProjectProperties = + new GradleProjectProperties( + project, + mockLogger, + mockTempDirectoryProvider, + mockExtensionLoader, + JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME); + } + @Test public void testGetWarFilePath() throws IOException { Path outputDir = temporaryFolder.newFolder("output").toPath(); project.getPlugins().apply("war"); + setupGradleProjectPropertiesInstance(); War war = project.getTasks().withType(War.class).getByName("war"); war.getDestinationDirectory().set(outputDir.toFile()); - assertThat(gradleProjectProperties.getWarFilePath()) + assertThat(gradleProjectProperties.getWarFilePath(project)) .isEqualTo(outputDir.resolve("my-app.war").toString()); } @@ -494,8 +517,8 @@ public void testGetWarFilePath_bootWar() throws IOException { project.getPlugins().apply("org.springframework.boot"); War bootWar = project.getTasks().withType(War.class).getByName("bootWar"); bootWar.getDestinationDirectory().set(outputDir.toFile()); - - assertThat(gradleProjectProperties.getWarFilePath()) + setupGradleProjectPropertiesInstance(); + assertThat(gradleProjectProperties.getWarFilePath(project)) .isEqualTo(outputDir.resolve("my-app.war").toString()); } @@ -510,12 +533,65 @@ public void testGetWarFilePath_bootWarDisabled() throws IOException { project.getPlugins().apply("org.springframework.boot"); project.getTasks().getByName("bootWar").setEnabled(false); - assertThat(gradleProjectProperties.getWarFilePath()) - .isEqualTo(outputDir.resolve("my-app.war").toString()); + setupGradleProjectPropertiesInstance(); + assertThat(gradleProjectProperties.getWarFilePath(project)) + .isEqualTo(outputDir.resolve("my-app-plain.war").toString()); + } + + @Test + public void testGetSingleThreadedExecutor() { + setupGradleProjectPropertiesInstance(); + assertNotNull(gradleProjectProperties.getSingleThreadedExecutor()); + gradleProjectProperties.singleThreadedExecutor = null; // pretend running from cache + assertNotNull(gradleProjectProperties.getSingleThreadedExecutor()); + } + + @Test + public void testGetConsoleLogger() { + setupGradleProjectPropertiesInstance(); + assertNotNull(gradleProjectProperties.getConsoleLogger()); + } + + @Test + public void testGetClassesOutputDirectory() { + setupGradleProjectPropertiesInstance(); + assertNotNull(gradleProjectProperties.getClassesOutputDirectories()); + assertFalse(gradleProjectProperties.getClassesOutputDirectories().getFiles().isEmpty()); + } + + @Test + public void testGetResourcesOutputDirectory() { + setupGradleProjectPropertiesInstance(); + assertNotNull(gradleProjectProperties.getResourcesOutputDirectory()); + } + + @Test + public void testGetClassFiles() throws IOException { + setupGradleProjectPropertiesInstance(); + assertFalse(gradleProjectProperties.getClassFiles().isEmpty()); + } + + @Test + public void testGetDefaultCacheDir() throws IOException { + setupGradleProjectPropertiesInstance(); + assertNotNull(gradleProjectProperties.getDefaultCacheDirectory()); + } + + @Test + public void testGetJarPluginName() throws IOException { + setupGradleProjectPropertiesInstance(); + assertNotNull(gradleProjectProperties.getJarPluginName()); + } + + @Test + public void testGetTempProvider() { + setupGradleProjectPropertiesInstance(); + assertNotNull(gradleProjectProperties.getTempDirectoryProvider()); } @Test public void testGetDependencies() throws URISyntaxException { + setupGradleProjectPropertiesInstance(); assertThat(gradleProjectProperties.getDependencies()) .containsExactly( getResource("gradle/application/dependencies/library.jarC.jar"), diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibExtensionTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibExtensionTest.java index 440ae17779..73685e0f7c 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibExtensionTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibExtensionTest.java @@ -32,6 +32,7 @@ import java.util.HashSet; import java.util.List; import java.util.Properties; +import java.util.stream.Collectors; import org.gradle.api.Project; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -418,15 +419,27 @@ public void testSkaffold() { }); }); Path root = fakeProject.getRootDir().toPath(); - assertThat(testJibExtension.getSkaffold().getSync().getExcludes()) + assertThat( + testJibExtension.getSkaffold().getSync().getExcludes().getFiles().stream() + .map(File::toPath) + .collect(Collectors.toSet())) .containsExactly( root.resolve("sync1").toAbsolutePath(), root.resolve("sync2").toAbsolutePath()); - assertThat(testJibExtension.getSkaffold().getWatch().getBuildIncludes()) + assertThat( + testJibExtension.getSkaffold().getWatch().getBuildIncludes().getFiles().stream() + .map(File::toPath) + .collect(Collectors.toSet())) .containsExactly( root.resolve("watch1").toAbsolutePath(), root.resolve("watch2").toAbsolutePath()); - assertThat(testJibExtension.getSkaffold().getWatch().getIncludes()) + assertThat( + testJibExtension.getSkaffold().getWatch().getIncludes().getFiles().stream() + .map(File::toPath) + .collect(Collectors.toSet())) .containsExactly(root.resolve("watch3").toAbsolutePath()); - assertThat(testJibExtension.getSkaffold().getWatch().getExcludes()) + assertThat( + testJibExtension.getSkaffold().getWatch().getExcludes().getFiles().stream() + .map(File::toPath) + .collect(Collectors.toSet())) .containsExactly(root.resolve("watch4").toAbsolutePath()); } diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java index fe2829d0dd..c0b7f7dc02 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java @@ -104,7 +104,7 @@ public void testCheckGradleVersion_fail() throws IOException { GradleRunner.create() .withProjectDir(testProjectRoot.getRoot()) .withPluginClasspath() - .withGradleVersion("4.3"); + .withGradleVersion("8.4"); Exception exception = assertThrows(UnexpectedBuildFailure.class, () -> gradleRunner.build()); assertThat(exception) @@ -203,8 +203,10 @@ public void testSpringBootJarProject_nonPackagedMode() { createProject("java", "org.springframework.boot", "com.google.cloud.tools.jib"); Jar jar = (Jar) project.getTasks().getByPath(":jar"); + jar.setEnabled(false); // Spring boot >2.5.0 no longer sets this as disabled by default assertThat(jar.getEnabled()).isFalse(); - assertThat(jar.getArchiveClassifier().get()).isEmpty(); + assertThat(jar.getArchiveClassifier().get()) + .isEqualTo("plain"); // >2.5.0 generates "plain" instead of empty } @Test @@ -216,7 +218,7 @@ public void testSpringBootJarProject_packagedMode() { Jar jar = (Jar) project.getTasks().getByPath(":jar"); assertThat(jar.getEnabled()).isTrue(); - assertThat(jar.getArchiveClassifier().get()).isEqualTo("original"); + assertThat(jar.getArchiveClassifier().get()).isEqualTo("plain"); } @Test @@ -244,7 +246,7 @@ public void testSpringBootJarProject_packagedMode_bootJarClassifierSet() { Jar jar = (Jar) project.getTasks().getByPath(":jar"); assertThat(jar.getEnabled()).isTrue(); - assertThat(jar.getArchiveClassifier().get()).isEmpty(); + assertThat(jar.getArchiveClassifier().get()).isEqualTo("plain"); } @Test @@ -253,7 +255,14 @@ public void testSpringBootJarProject_packagedMode_jarEnabled() { createProject("java", "org.springframework.boot", "com.google.cloud.tools.jib"); JibExtension jibExtension = (JibExtension) project.getExtensions().getByName("jib"); jibExtension.setContainerizingMode("packaged"); - project.getTasks().named("jar").configure(task -> task.setEnabled(true)); + project + .getTasks() + .named("jar") + .configure( + task -> { + task.setEnabled(true); + ((Jar) task).getArchiveClassifier().set(""); // pre spring boot 2.5.0 behaviour + }); TaskContainer tasks = project.getTasks(); Exception exception = assertThrows(GradleException.class, () -> tasks.getByPath(":jar")); @@ -293,7 +302,7 @@ public void testSpringBootJarProject_packagedMode_jarEnabledAndBootJarClassifier Jar jar = (Jar) project.getTasks().getByPath(":jar"); assertThat(jar.getEnabled()).isTrue(); - assertThat(jar.getArchiveClassifier().get()).isEmpty(); + assertThat(jar.getArchiveClassifier().get()).isEqualTo("plain"); } @Test @@ -308,7 +317,7 @@ public void testSpringBootJarProject_packagedMode_jarEnabledAndBootJarDisabled() Jar jar = (Jar) project.getTasks().getByPath(":jar"); assertThat(jar.getEnabled()).isTrue(); assertThat(project.getTasks().getByPath(":bootJar").getEnabled()).isFalse(); - assertThat(jar.getArchiveClassifier().get()).isEmpty(); + assertThat(jar.getArchiveClassifier().get()).isEqualTo("plain"); } @Test diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/skaffold/FilesTaskV2Test.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/skaffold/FilesTaskV2Test.java index 3df3a86154..4eec8aa2b4 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/skaffold/FilesTaskV2Test.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/skaffold/FilesTaskV2Test.java @@ -48,7 +48,7 @@ public class FilesTaskV2Test { @ClassRule public static final TestProject platformProject = - new TestProject("platform").withGradleVersion("5.2"); + new TestProject("platform").withGradleVersion("8.4"); /** * Verifies that the files task succeeded and returns the list of paths it prints out. @@ -60,7 +60,8 @@ public class FilesTaskV2Test { private static String verifyTaskSuccess(TestProject project, @Nullable String moduleName) { String taskName = ":" + (moduleName == null ? "" : moduleName + ":") + JibPlugin.SKAFFOLD_FILES_TASK_V2_NAME; - BuildResult buildResult = project.build(taskName, "-q", "-D_TARGET_IMAGE=ignored"); + BuildResult buildResult = + project.build(taskName, "-q", "-D_TARGET_IMAGE=ignored", "--stacktrace"); BuildTask jibTask = buildResult.task(taskName); Assert.assertNotNull(jibTask); Assert.assertEquals(TaskOutcome.SUCCESS, jibTask.getOutcome()); diff --git a/jib-maven-plugin-extension-api/build.gradle b/jib-maven-plugin-extension-api/build.gradle index aa4b6ce45f..9c36739c87 100644 --- a/jib-maven-plugin-extension-api/build.gradle +++ b/jib-maven-plugin-extension-api/build.gradle @@ -44,7 +44,7 @@ publishing { release { tagTemplate = 'v$version-maven-extension' git { - requireBranch = /^maven-extension-release-v\d+.*$/ //regex + requireBranch.set(/^maven-extension-release-v\d+.*$/) //regex } } /* RELEASE */ diff --git a/jib-maven-plugin/build.gradle b/jib-maven-plugin/build.gradle index f8ead158cd..d856027087 100644 --- a/jib-maven-plugin/build.gradle +++ b/jib-maven-plugin/build.gradle @@ -71,7 +71,7 @@ release { 'com.google.cloud.tools:jib-plugins-common', ] git { - requireBranch = /^maven-release-v\d+.*$/ //regex + requireBranch.set(/^maven-release-v\d+.*$/) //regex } } /* RELEASE */ diff --git a/jib-maven-plugin/src/integration-test/java/com/google/cloud/tools/jib/maven/BuildDockerMojoIntegrationTest.java b/jib-maven-plugin/src/integration-test/java/com/google/cloud/tools/jib/maven/BuildDockerMojoIntegrationTest.java index 7d3be1d8c5..ce7225962b 100644 --- a/jib-maven-plugin/src/integration-test/java/com/google/cloud/tools/jib/maven/BuildDockerMojoIntegrationTest.java +++ b/jib-maven-plugin/src/integration-test/java/com/google/cloud/tools/jib/maven/BuildDockerMojoIntegrationTest.java @@ -72,7 +72,6 @@ private static String buildToDockerDaemonAndRun(TestProject project, String imag .run(); String dockerInspectLabels = new Command("docker", "inspect", "-f", "'{{json .Config.Labels}}'", imageReference).run(); - String history = new Command("docker", "history", imageReference).run(); MatcherAssert.assertThat( dockerInspectVolumes, CoreMatchers.containsString("\"/var/log\":{},\"/var/log2\":{}")); diff --git a/jib-maven-plugin/src/integration-test/java/com/google/cloud/tools/jib/maven/BuildImageMojoIntegrationTest.java b/jib-maven-plugin/src/integration-test/java/com/google/cloud/tools/jib/maven/BuildImageMojoIntegrationTest.java index 52675002c2..93530a7147 100644 --- a/jib-maven-plugin/src/integration-test/java/com/google/cloud/tools/jib/maven/BuildImageMojoIntegrationTest.java +++ b/jib-maven-plugin/src/integration-test/java/com/google/cloud/tools/jib/maven/BuildImageMojoIntegrationTest.java @@ -69,7 +69,7 @@ public class BuildImageMojoIntegrationTest { @ClassRule public static final LocalRegistry localRegistry = - new LocalRegistry(5000, "testuser", "testpassword"); + new LocalRegistry(5001, "testuser", "testpassword"); private static final String dockerHost = System.getenv("DOCKER_IP") != null ? System.getenv("DOCKER_IP") : "localhost"; @@ -567,7 +567,7 @@ public void testExecute_defaultTarget() throws IOException { @Test public void testExecute_complex() throws IOException, InterruptedException, VerificationException, DigestException { - String targetImage = dockerHost + ":5000/compleximage:maven" + System.nanoTime(); + String targetImage = dockerHost + ":5001/compleximage:maven" + System.nanoTime(); Instant before = Instant.now(); String output = buildAndRunComplex(targetImage, "pom-complex.xml"); assertThat(output) @@ -594,7 +594,7 @@ public void testExecute_complex() @Test public void testExecute_timestampCustom() throws IOException, InterruptedException, VerificationException { - String targetImage = dockerHost + ":5000/simpleimage:maven" + System.nanoTime(); + String targetImage = dockerHost + ":5001/simpleimage:maven" + System.nanoTime(); String pom = "pom-timestamps-custom.xml"; assertThat(buildAndRunComplex(targetImage, pom)) .isEqualTo( @@ -607,7 +607,7 @@ public void testExecute_timestampCustom() @Test public void testExecute_complex_sameFromAndToRegistry() throws IOException, InterruptedException, VerificationException { - String targetImage = dockerHost + ":5000/compleximage:maven" + System.nanoTime(); + String targetImage = dockerHost + ":5001/compleximage:maven" + System.nanoTime(); assertThat(buildAndRunComplex(targetImage, "pom-complex.xml")) .isEqualTo( "Hello, world. An argument.\n1970-01-01T00:00:01Z\nrwxr-xr-x\nrwxrwxrwx\nfoo\ncat\n" @@ -619,7 +619,7 @@ public void testExecute_complex_sameFromAndToRegistry() @Test public void testExecute_complexProperties() throws InterruptedException, VerificationException, IOException { - String targetImage = dockerHost + ":5000/compleximage:maven" + System.nanoTime(); + String targetImage = dockerHost + ":5001/compleximage:maven" + System.nanoTime(); assertThat(buildAndRunComplex(targetImage, "pom-complex-properties.xml")) .isEqualTo( "Hello, world. An argument.\n1970-01-01T00:00:01Z\nrwxr-xr-x\nrwxrwxrwx\nfoo\ncat\n" @@ -640,11 +640,11 @@ public void testExecute_jibContainerizeSkips() throws VerificationException, IOE @Test public void testExecute_jibRequireVersion_ok() throws VerificationException, IOException { - String targetImage = dockerHost + ":5000/simpleimage:maven" + System.nanoTime(); + String targetImage = dockerHost + ":5001/simpleimage:maven" + System.nanoTime(); Verifier verifier = new Verifier(simpleTestProject.getProjectRoot().toString()); verifier.setSystemProperty("_TARGET_IMAGE", targetImage); - // properties required to push to :5000 for plain pom.xml + // properties required to push to :5001 for plain pom.xml verifier.setSystemProperty("jib.to.auth.username", "testuser"); verifier.setSystemProperty("jib.to.auth.password", "testpassword"); verifier.setSystemProperty("sendCredentialsOverHttp", "true"); @@ -714,7 +714,7 @@ public void testExecute_springBootPackaged() @Test public void testExecute_multiPlatformBuild() throws IOException, VerificationException, RegistryException { - String targetImage = dockerHost + ":5000/multiplatform:maven" + System.nanoTime(); + String targetImage = dockerHost + ":5001/multiplatform:maven" + System.nanoTime(); Verifier verifier = new Verifier(simpleTestProject.getProjectRoot().toString()); verifier.setSystemProperty("_TARGET_IMAGE", targetImage); @@ -732,7 +732,7 @@ public void testExecute_multiPlatformBuild() FailoverHttpClient httpClient = new FailoverHttpClient(true, true, ignored -> {}); RegistryClient registryClient = RegistryClient.factory( - EventHandlers.NONE, dockerHost + ":5000", "multiplatform", httpClient) + EventHandlers.NONE, dockerHost + ":5001", "multiplatform", httpClient) .setCredential(Credential.from("testuser", "testpassword")) .newRegistryClient(); registryClient.configureBasicAuth(); diff --git a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenProjectProperties.java b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenProjectProperties.java index 7b457951c6..edaa2e044e 100644 --- a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenProjectProperties.java +++ b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenProjectProperties.java @@ -597,7 +597,8 @@ Optional getSpringBootRepackageConfiguration() { @Override public JibContainerBuilder runPluginExtensions( List extensionConfigs, - JibContainerBuilder jibContainerBuilder) + JibContainerBuilder jibContainerBuilder, + Optional unusedForMaven) throws JibPluginExtensionException { if (extensionConfigs.isEmpty()) { log(LogEvent.debug("No Jib plugin extensions configured to load")); diff --git a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/skaffold/SkaffoldConfiguration.java b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/skaffold/SkaffoldConfiguration.java index f02572253f..67d998422a 100644 --- a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/skaffold/SkaffoldConfiguration.java +++ b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/skaffold/SkaffoldConfiguration.java @@ -36,10 +36,7 @@ public static class Sync { @Parameter List excludes = Collections.emptyList(); } - /** - * Watch is unused, but left here to define how to parse it. See {@link - * FilesMojoV2#collectWatchParameters} - */ + /** Watch is unused, but left here to define how to parse it. */ @Parameter Watch watch = new Watch(); @Parameter Sync sync = new Sync(); diff --git a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/MavenProjectPropertiesTest.java b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/MavenProjectPropertiesTest.java index 5bbceaf3b9..8151318174 100644 --- a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/MavenProjectPropertiesTest.java +++ b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/MavenProjectPropertiesTest.java @@ -576,6 +576,9 @@ public void testCreateContainerBuilder_noErrorIfWebInfLibDoesNotExist() @Test public void testCreateContainerBuilder_exceptionMessageHasPackageSuggestionIfProjectIsWar() throws IOException { + when(mockBuild.getDirectory()).thenReturn(Paths.get("/foo/bar").toString()); + when(mockBuild.getFinalName()).thenReturn("helloworld-1"); + String expectedMessage = "Obtaining project build output files failed; make sure you have " + "packaged your project before trying to build the image. (Did you accidentally run \"mvn clean " diff --git a/jib-maven-plugin/src/test/resources/maven/projects/war_servlet25/pom-tomcat.xml b/jib-maven-plugin/src/test/resources/maven/projects/war_servlet25/pom-tomcat.xml index dc65ff9dea..bedec4d671 100644 --- a/jib-maven-plugin/src/test/resources/maven/projects/war_servlet25/pom-tomcat.xml +++ b/jib-maven-plugin/src/test/resources/maven/projects/war_servlet25/pom-tomcat.xml @@ -30,6 +30,11 @@ + + org.apache.maven.plugins + maven-war-plugin + 3.4.0 + org.apache.maven.plugins maven-compiler-plugin diff --git a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ProjectProperties.java b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ProjectProperties.java index e8a0516226..bfcf30f680 100644 --- a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ProjectProperties.java +++ b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/ProjectProperties.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.List; +import java.util.Optional; import javax.annotation.Nullable; /** Project property methods that require maven/gradle-specific implementations. */ @@ -92,6 +93,15 @@ JibContainerBuilder createJibContainerBuilder( JibContainerBuilder runPluginExtensions( List extensionConfigs, - JibContainerBuilder jibContainerBuilder) + JibContainerBuilder jibContainerBuilder, + Optional project) throws JibPluginExtensionException; + + default JibContainerBuilder runPluginExtensions( + List extensionConfigs, + JibContainerBuilder jibContainerBuilder) + throws JibPluginExtensionException { + return runPluginExtensions( + extensionConfigs, jibContainerBuilder, Optional.empty()); // for maven + } } diff --git a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/SkaffoldFilesOutput.java b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/SkaffoldFilesOutput.java index 33594d3648..6c955d7b50 100644 --- a/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/SkaffoldFilesOutput.java +++ b/jib-plugins-common/src/main/java/com/google/cloud/tools/jib/plugins/common/SkaffoldFilesOutput.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.annotations.VisibleForTesting; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Path; @@ -97,6 +98,15 @@ public void addBuild(Path build) { skaffoldFilesTemplate.build.add(build.toString()); } + /** + * Adds a build file/directory. + * + * @param build the path to the file/directory + */ + public void addBuild(File build) { + addBuild(build.toPath()); + } + /** * Adds an input file/directory. * @@ -106,6 +116,15 @@ public void addInput(Path inputFile) { skaffoldFilesTemplate.inputs.add(inputFile.toString()); } + /** + * Adds an input file/directory. + * + * @param inputFile the path to the file/directory + */ + public void addInput(File inputFile) { + addInput(inputFile.toPath()); + } + /** * Adds an ignored file/directory. * @@ -115,6 +134,15 @@ public void addIgnore(Path ignoreFile) { skaffoldFilesTemplate.ignore.add(ignoreFile.toString()); } + /** + * Adds an ignored file/directory. + * + * @param ignoreFile the path to the file/directory + */ + public void addIgnore(File ignoreFile) { + addIgnore(ignoreFile.toPath()); + } + @VisibleForTesting public List getBuild() { return skaffoldFilesTemplate.build; diff --git a/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/globalconfig/GlobalConfigTest.java b/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/globalconfig/GlobalConfigTest.java index e3247c9f1d..b772766bc5 100644 --- a/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/globalconfig/GlobalConfigTest.java +++ b/jib-plugins-common/src/test/java/com/google/cloud/tools/jib/plugins/common/globalconfig/GlobalConfigTest.java @@ -74,7 +74,7 @@ public void testReadConfig() throws IOException, InvalidGlobalConfigException { String json = "{\"disableUpdateCheck\":true, \"registryMirrors\":[" + "{ \"registry\": \"registry-1.docker.io\"," - + " \"mirrors\": [\"mirror.gcr.io\", \"localhost:5000\"] }," + + " \"mirrors\": [\"mirror.gcr.io\", \"localhost:5001\"] }," + "{ \"registry\": \"another.registry\", \"mirrors\": [\"another.mirror\"] }" + "]}"; Files.write(configDir.resolve("config.json"), json.getBytes(StandardCharsets.UTF_8)); @@ -86,7 +86,7 @@ public void testReadConfig() throws IOException, InvalidGlobalConfigException { "registry-1.docker.io", "mirror.gcr.io", "registry-1.docker.io", - "localhost:5000", + "localhost:5001", "another.registry", "another.mirror"); } diff --git a/jib-plugins-extension-common/build.gradle b/jib-plugins-extension-common/build.gradle index 5151d6a891..9107876cdf 100644 --- a/jib-plugins-extension-common/build.gradle +++ b/jib-plugins-extension-common/build.gradle @@ -38,7 +38,7 @@ publishing { release { tagTemplate = 'v$version-extension-common' git { - requireBranch = /^extension-common-release-v\d+.*$/ //regex + requireBranch.set(/^extension-common-release-v\d+.*$/) //regex } } /* RELEASE */