##// END OF EJS Templates
Upgrade Gradle to 9.4.1 and fix functional tests
cin -
r62:c7861b56e1d8 default
parent child
Show More
@@ -1,57 +1,57
1 plugins {
1 plugins {
2 id "java-library"
2 id "java-library"
3 id "ivy-publish"
3 id "ivy-publish"
4 }
4 }
5
5
6 description = "Shared Gradle build utilities used by Implab plugins"
6 description = "Shared Gradle build utilities used by Implab plugins"
7
7
8 java {
8 java {
9 withJavadocJar()
9 withJavadocJar()
10 withSourcesJar()
10 withSourcesJar()
11 toolchain {
11 toolchain {
12 languageVersion = JavaLanguageVersion.of(21)
12 languageVersion = JavaLanguageVersion.of(21)
13 }
13 }
14 }
14 }
15
15
16 dependencies {
16 dependencies {
17 compileOnly libs.jdt.annotations
17 compileOnly libs.jdt.annotations
18
18
19 api gradleApi(),
19 api gradleApi(),
20 libs.bundles.jackson
20 libs.bundles.jackson
21
21
22 testImplementation gradleTestKit()
22 testImplementation gradleTestKit()
23 testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4"
23 testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4"
24 testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.11.4"
24 testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.11.4"
25 testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.4"
25 testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.4"
26 }
26 }
27
27
28 task printVersion{
28 task printVersion{
29 doLast {
29 doLast {
30 println "project: $project.group:$project.name:$project.version"
30 println "project: $project.group:$project.name:$project.version"
31 println "jar: ${->jar.archiveFileName.get()}"
31 println "jar: ${->jar.archiveFileName.get()}"
32 }
32 }
33 }
33 }
34
34
35 test {
35 test {
36 useJUnitPlatform()
36 useJUnitPlatform()
37 }
37 }
38
38
39 publishing {
39 publishing {
40 repositories {
40 repositories {
41 ivy {
41 ivy {
42 url "${System.properties["user.home"]}/ivy-repo"
42 url = "${System.properties["user.home"]}/ivy-repo"
43 }
43 }
44 }
44 }
45 publications {
45 publications {
46 ivy(IvyPublication) {
46 ivy(IvyPublication) {
47 from components.java
47 from components.java
48 descriptor.description {
48 descriptor.description {
49 text = providers.provider({ description })
49 text = providers.provider({ description })
50 }
50 }
51 descriptor.license {
51 descriptor.license {
52 name = "BSD-2-Clause"
52 name = "BSD-2-Clause"
53 url = "https://spdx.org/licenses/BSD-2-Clause.html"
53 url = "https://spdx.org/licenses/BSD-2-Clause.html"
54 }
54 }
55 }
55 }
56 }
56 }
57 }
57 }
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -1,7 +1,7
1 distributionBase=GRADLE_USER_HOME
1 distributionBase=GRADLE_USER_HOME
2 distributionPath=wrapper/dists
2 distributionPath=wrapper/dists
3 distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
3 distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
4 networkTimeout=10000
4 networkTimeout=10000
5 validateDistributionUrl=true
5 validateDistributionUrl=true
6 zipStoreBase=GRADLE_USER_HOME
6 zipStoreBase=GRADLE_USER_HOME
7 zipStorePath=wrapper/dists
7 zipStorePath=wrapper/dists
@@ -1,249 +1,252
1 #!/bin/sh
1 #!/bin/sh
2
2
3 #
3 #
4 # Copyright Β© 2015-2021 the original authors.
4 # Copyright Β© 2015-2021 the original authors.
5 #
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
8 # You may obtain a copy of the License at
9 #
9 #
10 # https://www.apache.org/licenses/LICENSE-2.0
10 # https://www.apache.org/licenses/LICENSE-2.0
11 #
11 #
12 # Unless required by applicable law or agreed to in writing, software
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
16 # limitations under the License.
17 #
17 #
18 # SPDX-License-Identifier: Apache-2.0
19 #
18
20
19 ##############################################################################
21 ##############################################################################
20 #
22 #
21 # Gradle start up script for POSIX generated by Gradle.
23 # Gradle start up script for POSIX generated by Gradle.
22 #
24 #
23 # Important for running:
25 # Important for running:
24 #
26 #
25 # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
27 # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 # noncompliant, but you have some other compliant shell such as ksh or
28 # noncompliant, but you have some other compliant shell such as ksh or
27 # bash, then to run this script, type that shell name before the whole
29 # bash, then to run this script, type that shell name before the whole
28 # command line, like:
30 # command line, like:
29 #
31 #
30 # ksh Gradle
32 # ksh Gradle
31 #
33 #
32 # Busybox and similar reduced shells will NOT work, because this script
34 # Busybox and similar reduced shells will NOT work, because this script
33 # requires all of these POSIX shell features:
35 # requires all of these POSIX shell features:
34 # * functions;
36 # * functions;
35 # * expansions Β«$varΒ», Β«${var}Β», Β«${var:-default}Β», Β«${var+SET}Β»,
37 # * expansions Β«$varΒ», Β«${var}Β», Β«${var:-default}Β», Β«${var+SET}Β»,
36 # Β«${var#prefix}Β», Β«${var%suffix}Β», and Β«$( cmd )Β»;
38 # Β«${var#prefix}Β», Β«${var%suffix}Β», and Β«$( cmd )Β»;
37 # * compound commands having a testable exit status, especially Β«caseΒ»;
39 # * compound commands having a testable exit status, especially Β«caseΒ»;
38 # * various built-in commands including Β«commandΒ», Β«setΒ», and Β«ulimitΒ».
40 # * various built-in commands including Β«commandΒ», Β«setΒ», and Β«ulimitΒ».
39 #
41 #
40 # Important for patching:
42 # Important for patching:
41 #
43 #
42 # (2) This script targets any POSIX shell, so it avoids extensions provided
44 # (2) This script targets any POSIX shell, so it avoids extensions provided
43 # by Bash, Ksh, etc; in particular arrays are avoided.
45 # by Bash, Ksh, etc; in particular arrays are avoided.
44 #
46 #
45 # The "traditional" practice of packing multiple parameters into a
47 # The "traditional" practice of packing multiple parameters into a
46 # space-separated string is a well documented source of bugs and security
48 # space-separated string is a well documented source of bugs and security
47 # problems, so this is (mostly) avoided, by progressively accumulating
49 # problems, so this is (mostly) avoided, by progressively accumulating
48 # options in "$@", and eventually passing that to Java.
50 # options in "$@", and eventually passing that to Java.
49 #
51 #
50 # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
52 # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
53 # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 # see the in-line comments for details.
54 # see the in-line comments for details.
53 #
55 #
54 # There are tweaks for specific operating systems such as AIX, CygWin,
56 # There are tweaks for specific operating systems such as AIX, CygWin,
55 # Darwin, MinGW, and NonStop.
57 # Darwin, MinGW, and NonStop.
56 #
58 #
57 # (3) This script is generated from the Groovy template
59 # (3) This script is generated from the Groovy template
58 # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
60 # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 # within the Gradle project.
61 # within the Gradle project.
60 #
62 #
61 # You can find Gradle at https://github.com/gradle/gradle/.
63 # You can find Gradle at https://github.com/gradle/gradle/.
62 #
64 #
63 ##############################################################################
65 ##############################################################################
64
66
65 # Attempt to set APP_HOME
67 # Attempt to set APP_HOME
66
68
67 # Resolve links: $0 may be a link
69 # Resolve links: $0 may be a link
68 app_path=$0
70 app_path=$0
69
71
70 # Need this for daisy-chained symlinks.
72 # Need this for daisy-chained symlinks.
71 while
73 while
72 APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
74 APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 [ -h "$app_path" ]
75 [ -h "$app_path" ]
74 do
76 do
75 ls=$( ls -ld "$app_path" )
77 ls=$( ls -ld "$app_path" )
76 link=${ls#*' -> '}
78 link=${ls#*' -> '}
77 case $link in #(
79 case $link in #(
78 /*) app_path=$link ;; #(
80 /*) app_path=$link ;; #(
79 *) app_path=$APP_HOME$link ;;
81 *) app_path=$APP_HOME$link ;;
80 esac
82 esac
81 done
83 done
82
84
83 # This is normally unused
85 # This is normally unused
84 # shellcheck disable=SC2034
86 # shellcheck disable=SC2034
85 APP_BASE_NAME=${0##*/}
87 APP_BASE_NAME=${0##*/}
86 # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
88 # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
87 APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
89 APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
90 ' "$PWD" ) || exit
88
91
89 # Use the maximum available, or set MAX_FD != -1 to use that value.
92 # Use the maximum available, or set MAX_FD != -1 to use that value.
90 MAX_FD=maximum
93 MAX_FD=maximum
91
94
92 warn () {
95 warn () {
93 echo "$*"
96 echo "$*"
94 } >&2
97 } >&2
95
98
96 die () {
99 die () {
97 echo
100 echo
98 echo "$*"
101 echo "$*"
99 echo
102 echo
100 exit 1
103 exit 1
101 } >&2
104 } >&2
102
105
103 # OS specific support (must be 'true' or 'false').
106 # OS specific support (must be 'true' or 'false').
104 cygwin=false
107 cygwin=false
105 msys=false
108 msys=false
106 darwin=false
109 darwin=false
107 nonstop=false
110 nonstop=false
108 case "$( uname )" in #(
111 case "$( uname )" in #(
109 CYGWIN* ) cygwin=true ;; #(
112 CYGWIN* ) cygwin=true ;; #(
110 Darwin* ) darwin=true ;; #(
113 Darwin* ) darwin=true ;; #(
111 MSYS* | MINGW* ) msys=true ;; #(
114 MSYS* | MINGW* ) msys=true ;; #(
112 NONSTOP* ) nonstop=true ;;
115 NONSTOP* ) nonstop=true ;;
113 esac
116 esac
114
117
115 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
116
119
117
120
118 # Determine the Java command to use to start the JVM.
121 # Determine the Java command to use to start the JVM.
119 if [ -n "$JAVA_HOME" ] ; then
122 if [ -n "$JAVA_HOME" ] ; then
120 if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
121 # IBM's JDK on AIX uses strange locations for the executables
124 # IBM's JDK on AIX uses strange locations for the executables
122 JAVACMD=$JAVA_HOME/jre/sh/java
125 JAVACMD=$JAVA_HOME/jre/sh/java
123 else
126 else
124 JAVACMD=$JAVA_HOME/bin/java
127 JAVACMD=$JAVA_HOME/bin/java
125 fi
128 fi
126 if [ ! -x "$JAVACMD" ] ; then
129 if [ ! -x "$JAVACMD" ] ; then
127 die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
128
131
129 Please set the JAVA_HOME variable in your environment to match the
132 Please set the JAVA_HOME variable in your environment to match the
130 location of your Java installation."
133 location of your Java installation."
131 fi
134 fi
132 else
135 else
133 JAVACMD=java
136 JAVACMD=java
134 if ! command -v java >/dev/null 2>&1
137 if ! command -v java >/dev/null 2>&1
135 then
138 then
136 die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
139 die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137
140
138 Please set the JAVA_HOME variable in your environment to match the
141 Please set the JAVA_HOME variable in your environment to match the
139 location of your Java installation."
142 location of your Java installation."
140 fi
143 fi
141 fi
144 fi
142
145
143 # Increase the maximum file descriptors if we can.
146 # Increase the maximum file descriptors if we can.
144 if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
147 if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
145 case $MAX_FD in #(
148 case $MAX_FD in #(
146 max*)
149 max*)
147 # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
150 # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
148 # shellcheck disable=SC2039,SC3045
151 # shellcheck disable=SC2039,SC3045
149 MAX_FD=$( ulimit -H -n ) ||
152 MAX_FD=$( ulimit -H -n ) ||
150 warn "Could not query maximum file descriptor limit"
153 warn "Could not query maximum file descriptor limit"
151 esac
154 esac
152 case $MAX_FD in #(
155 case $MAX_FD in #(
153 '' | soft) :;; #(
156 '' | soft) :;; #(
154 *)
157 *)
155 # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
158 # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
156 # shellcheck disable=SC2039,SC3045
159 # shellcheck disable=SC2039,SC3045
157 ulimit -n "$MAX_FD" ||
160 ulimit -n "$MAX_FD" ||
158 warn "Could not set maximum file descriptor limit to $MAX_FD"
161 warn "Could not set maximum file descriptor limit to $MAX_FD"
159 esac
162 esac
160 fi
163 fi
161
164
162 # Collect all arguments for the java command, stacking in reverse order:
165 # Collect all arguments for the java command, stacking in reverse order:
163 # * args from the command line
166 # * args from the command line
164 # * the main class name
167 # * the main class name
165 # * -classpath
168 # * -classpath
166 # * -D...appname settings
169 # * -D...appname settings
167 # * --module-path (only if needed)
170 # * --module-path (only if needed)
168 # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
171 # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
169
172
170 # For Cygwin or MSYS, switch paths to Windows format before running java
173 # For Cygwin or MSYS, switch paths to Windows format before running java
171 if "$cygwin" || "$msys" ; then
174 if "$cygwin" || "$msys" ; then
172 APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
175 APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
173 CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
176 CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
174
177
175 JAVACMD=$( cygpath --unix "$JAVACMD" )
178 JAVACMD=$( cygpath --unix "$JAVACMD" )
176
179
177 # Now convert the arguments - kludge to limit ourselves to /bin/sh
180 # Now convert the arguments - kludge to limit ourselves to /bin/sh
178 for arg do
181 for arg do
179 if
182 if
180 case $arg in #(
183 case $arg in #(
181 -*) false ;; # don't mess with options #(
184 -*) false ;; # don't mess with options #(
182 /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
185 /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
183 [ -e "$t" ] ;; #(
186 [ -e "$t" ] ;; #(
184 *) false ;;
187 *) false ;;
185 esac
188 esac
186 then
189 then
187 arg=$( cygpath --path --ignore --mixed "$arg" )
190 arg=$( cygpath --path --ignore --mixed "$arg" )
188 fi
191 fi
189 # Roll the args list around exactly as many times as the number of
192 # Roll the args list around exactly as many times as the number of
190 # args, so each arg winds up back in the position where it started, but
193 # args, so each arg winds up back in the position where it started, but
191 # possibly modified.
194 # possibly modified.
192 #
195 #
193 # NB: a `for` loop captures its iteration list before it begins, so
196 # NB: a `for` loop captures its iteration list before it begins, so
194 # changing the positional parameters here affects neither the number of
197 # changing the positional parameters here affects neither the number of
195 # iterations, nor the values presented in `arg`.
198 # iterations, nor the values presented in `arg`.
196 shift # remove old arg
199 shift # remove old arg
197 set -- "$@" "$arg" # push replacement arg
200 set -- "$@" "$arg" # push replacement arg
198 done
201 done
199 fi
202 fi
200
203
201
204
202 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
205 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
203 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
206 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
204
207
205 # Collect all arguments for the java command:
208 # Collect all arguments for the java command:
206 # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
209 # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
207 # and any embedded shellness will be escaped.
210 # and any embedded shellness will be escaped.
208 # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
211 # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
209 # treated as '${Hostname}' itself on the command line.
212 # treated as '${Hostname}' itself on the command line.
210
213
211 set -- \
214 set -- \
212 "-Dorg.gradle.appname=$APP_BASE_NAME" \
215 "-Dorg.gradle.appname=$APP_BASE_NAME" \
213 -classpath "$CLASSPATH" \
216 -classpath "$CLASSPATH" \
214 org.gradle.wrapper.GradleWrapperMain \
217 org.gradle.wrapper.GradleWrapperMain \
215 "$@"
218 "$@"
216
219
217 # Stop when "xargs" is not available.
220 # Stop when "xargs" is not available.
218 if ! command -v xargs >/dev/null 2>&1
221 if ! command -v xargs >/dev/null 2>&1
219 then
222 then
220 die "xargs is not available"
223 die "xargs is not available"
221 fi
224 fi
222
225
223 # Use "xargs" to parse quoted args.
226 # Use "xargs" to parse quoted args.
224 #
227 #
225 # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
228 # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
226 #
229 #
227 # In Bash we could simply go:
230 # In Bash we could simply go:
228 #
231 #
229 # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
232 # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
230 # set -- "${ARGS[@]}" "$@"
233 # set -- "${ARGS[@]}" "$@"
231 #
234 #
232 # but POSIX shell has neither arrays nor command substitution, so instead we
235 # but POSIX shell has neither arrays nor command substitution, so instead we
233 # post-process each arg (as a line of input to sed) to backslash-escape any
236 # post-process each arg (as a line of input to sed) to backslash-escape any
234 # character that might be a shell metacharacter, then use eval to reverse
237 # character that might be a shell metacharacter, then use eval to reverse
235 # that process (while maintaining the separation between arguments), and wrap
238 # that process (while maintaining the separation between arguments), and wrap
236 # the whole thing up as a single "set" statement.
239 # the whole thing up as a single "set" statement.
237 #
240 #
238 # This will of course break if any of these variables contains a newline or
241 # This will of course break if any of these variables contains a newline or
239 # an unmatched quote.
242 # an unmatched quote.
240 #
243 #
241
244
242 eval "set -- $(
245 eval "set -- $(
243 printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
246 printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
244 xargs -n1 |
247 xargs -n1 |
245 sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
248 sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
246 tr '\n' ' '
249 tr '\n' ' '
247 )" '"$@"'
250 )" '"$@"'
248
251
249 exec "$JAVACMD" "$@"
252 exec "$JAVACMD" "$@"
@@ -1,92 +1,94
1 @rem
1 @rem
2 @rem Copyright 2015 the original author or authors.
2 @rem Copyright 2015 the original author or authors.
3 @rem
3 @rem
4 @rem Licensed under the Apache License, Version 2.0 (the "License");
4 @rem Licensed under the Apache License, Version 2.0 (the "License");
5 @rem you may not use this file except in compliance with the License.
5 @rem you may not use this file except in compliance with the License.
6 @rem You may obtain a copy of the License at
6 @rem You may obtain a copy of the License at
7 @rem
7 @rem
8 @rem https://www.apache.org/licenses/LICENSE-2.0
8 @rem https://www.apache.org/licenses/LICENSE-2.0
9 @rem
9 @rem
10 @rem Unless required by applicable law or agreed to in writing, software
10 @rem Unless required by applicable law or agreed to in writing, software
11 @rem distributed under the License is distributed on an "AS IS" BASIS,
11 @rem distributed under the License is distributed on an "AS IS" BASIS,
12 @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 @rem See the License for the specific language governing permissions and
13 @rem See the License for the specific language governing permissions and
14 @rem limitations under the License.
14 @rem limitations under the License.
15 @rem
15 @rem
16 @rem SPDX-License-Identifier: Apache-2.0
17 @rem
16
18
17 @if "%DEBUG%"=="" @echo off
19 @if "%DEBUG%"=="" @echo off
18 @rem ##########################################################################
20 @rem ##########################################################################
19 @rem
21 @rem
20 @rem Gradle startup script for Windows
22 @rem Gradle startup script for Windows
21 @rem
23 @rem
22 @rem ##########################################################################
24 @rem ##########################################################################
23
25
24 @rem Set local scope for the variables with windows NT shell
26 @rem Set local scope for the variables with windows NT shell
25 if "%OS%"=="Windows_NT" setlocal
27 if "%OS%"=="Windows_NT" setlocal
26
28
27 set DIRNAME=%~dp0
29 set DIRNAME=%~dp0
28 if "%DIRNAME%"=="" set DIRNAME=.
30 if "%DIRNAME%"=="" set DIRNAME=.
29 @rem This is normally unused
31 @rem This is normally unused
30 set APP_BASE_NAME=%~n0
32 set APP_BASE_NAME=%~n0
31 set APP_HOME=%DIRNAME%
33 set APP_HOME=%DIRNAME%
32
34
33 @rem Resolve any "." and ".." in APP_HOME to make it shorter.
35 @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
36 for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35
37
36 @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
38 @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
39 set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38
40
39 @rem Find java.exe
41 @rem Find java.exe
40 if defined JAVA_HOME goto findJavaFromJavaHome
42 if defined JAVA_HOME goto findJavaFromJavaHome
41
43
42 set JAVA_EXE=java.exe
44 set JAVA_EXE=java.exe
43 %JAVA_EXE% -version >NUL 2>&1
45 %JAVA_EXE% -version >NUL 2>&1
44 if %ERRORLEVEL% equ 0 goto execute
46 if %ERRORLEVEL% equ 0 goto execute
45
47
46 echo. 1>&2
48 echo. 1>&2
47 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
49 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
48 echo. 1>&2
50 echo. 1>&2
49 echo Please set the JAVA_HOME variable in your environment to match the 1>&2
51 echo Please set the JAVA_HOME variable in your environment to match the 1>&2
50 echo location of your Java installation. 1>&2
52 echo location of your Java installation. 1>&2
51
53
52 goto fail
54 goto fail
53
55
54 :findJavaFromJavaHome
56 :findJavaFromJavaHome
55 set JAVA_HOME=%JAVA_HOME:"=%
57 set JAVA_HOME=%JAVA_HOME:"=%
56 set JAVA_EXE=%JAVA_HOME%/bin/java.exe
58 set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57
59
58 if exist "%JAVA_EXE%" goto execute
60 if exist "%JAVA_EXE%" goto execute
59
61
60 echo. 1>&2
62 echo. 1>&2
61 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
63 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
62 echo. 1>&2
64 echo. 1>&2
63 echo Please set the JAVA_HOME variable in your environment to match the 1>&2
65 echo Please set the JAVA_HOME variable in your environment to match the 1>&2
64 echo location of your Java installation. 1>&2
66 echo location of your Java installation. 1>&2
65
67
66 goto fail
68 goto fail
67
69
68 :execute
70 :execute
69 @rem Setup the command line
71 @rem Setup the command line
70
72
71 set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72
74
73
75
74 @rem Execute Gradle
76 @rem Execute Gradle
75 "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
77 "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76
78
77 :end
79 :end
78 @rem End local scope for the variables with windows NT shell
80 @rem End local scope for the variables with windows NT shell
79 if %ERRORLEVEL% equ 0 goto mainEnd
81 if %ERRORLEVEL% equ 0 goto mainEnd
80
82
81 :fail
83 :fail
82 rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
84 rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 rem the _cmd.exe /c_ return code!
85 rem the _cmd.exe /c_ return code!
84 set EXIT_CODE=%ERRORLEVEL%
86 set EXIT_CODE=%ERRORLEVEL%
85 if %EXIT_CODE% equ 0 set EXIT_CODE=1
87 if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
88 if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 exit /b %EXIT_CODE%
89 exit /b %EXIT_CODE%
88
90
89 :mainEnd
91 :mainEnd
90 if "%OS%"=="Windows_NT" endlocal
92 if "%OS%"=="Windows_NT" endlocal
91
93
92 :omega
94 :omega
@@ -1,24 +1,24
1 /*
1 /*
2 * This settings file was generated by the Gradle 'init' task.
2 * This settings file was generated by the Gradle 'init' task.
3 *
3 *
4 * The settings file is used to specify which projects to include in your build.
4 * The settings file is used to specify which projects to include in your build.
5 * In a single project build this file can be empty or even removed.
5 * In a single project build this file can be empty or even removed.
6 *
6 *
7 * Detailed information about configuring a multi-project build in Gradle can be found
7 * Detailed information about configuring a multi-project build in Gradle can be found
8 * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html
8 * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html
9 */
9 */
10
10
11 dependencyResolutionManagement {
11 dependencyResolutionManagement {
12 repositories {
12 repositories {
13 mavenCentral()
13 mavenCentral()
14 mavenLocal()
14 mavenLocal()
15 ivy {
15 ivy {
16 url "${System.properties["user.home"]}/ivy-repo"
16 url = "${System.properties["user.home"]}/ivy-repo"
17 }
17 }
18 }
18 }
19 }
19 }
20
20
21 rootProject.name = 'gradle-common'
21 rootProject.name = 'gradle-common'
22
22
23 include 'common'
23 include 'common'
24 include 'variants'
24 include 'variants'
@@ -1,61 +1,61
1 plugins {
1 plugins {
2 id "java-library"
2 id "java-library"
3 id "ivy-publish"
3 id "ivy-publish"
4 }
4 }
5
5
6 description = "Variant, source-set, and outgoing artifact model plugins for Gradle builds"
6 description = "Variant, source-set, and outgoing artifact model plugins for Gradle builds"
7
7
8 java {
8 java {
9 withJavadocJar()
9 withJavadocJar()
10 withSourcesJar()
10 withSourcesJar()
11 toolchain {
11 toolchain {
12 languageVersion = JavaLanguageVersion.of(21)
12 languageVersion = JavaLanguageVersion.of(21)
13 }
13 }
14 }
14 }
15
15
16 dependencies {
16 dependencies {
17 compileOnly libs.jdt.annotations
17 compileOnly libs.jdt.annotations
18
18
19 api gradleApi(),
19 api gradleApi(),
20 project(":common")
20 project(":common")
21
21
22 testImplementation gradleTestKit()
22 testImplementation gradleTestKit()
23 testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4"
23 testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.4"
24 testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.11.4"
24 testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.11.4"
25 testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.4"
25 testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.11.4"
26 }
26 }
27
27
28 task printVersion{
28 task printVersion{
29 doLast {
29 doLast {
30 println "project: $project.group:$project.name:$project.version"
30 println "project: $project.group:$project.name:$project.version"
31 println "jar: ${->jar.archiveFileName.get()}"
31 println "jar: ${->jar.archiveFileName.get()}"
32 }
32 }
33 }
33 }
34
34
35 test {
35 test {
36 useJUnitPlatform()
36 useJUnitPlatform()
37 }
37 }
38
38
39 javadoc {
39 javadoc {
40 exclude "**/internal/**"
40 exclude "**/internal/**"
41 }
41 }
42
42
43 publishing {
43 publishing {
44 repositories {
44 repositories {
45 ivy {
45 ivy {
46 url "${System.properties["user.home"]}/ivy-repo"
46 url = "${System.properties["user.home"]}/ivy-repo"
47 }
47 }
48 }
48 }
49 publications {
49 publications {
50 ivy(IvyPublication) {
50 ivy(IvyPublication) {
51 from components.java
51 from components.java
52 descriptor.description {
52 descriptor.description {
53 text = providers.provider({ description })
53 text = providers.provider({ description })
54 }
54 }
55 descriptor.license {
55 descriptor.license {
56 name = "BSD-2-Clause"
56 name = "BSD-2-Clause"
57 url = "https://spdx.org/licenses/BSD-2-Clause.html"
57 url = "https://spdx.org/licenses/BSD-2-Clause.html"
58 }
58 }
59 }
59 }
60 }
60 }
61 }
61 }
@@ -1,98 +1,123
1 package org.implab.gradle.variants;
1 package org.implab.gradle.variants;
2
2
3 import static org.junit.jupiter.api.Assertions.assertTrue;
3 import static org.junit.jupiter.api.Assertions.assertTrue;
4
4
5 import java.io.File;
5 import java.io.File;
6 import java.io.IOException;
6 import java.io.IOException;
7 import java.nio.file.Files;
7 import java.nio.file.Files;
8 import java.nio.file.Path;
8 import java.nio.file.Path;
9 import java.util.LinkedHashSet;
9 import java.util.LinkedHashSet;
10 import java.util.List;
10 import java.util.List;
11 import java.util.stream.Collectors;
11 import java.util.stream.Collectors;
12 import java.util.regex.Pattern;
12
13
13 import org.gradle.testkit.runner.GradleRunner;
14 import org.gradle.testkit.runner.GradleRunner;
14 import org.gradle.testkit.runner.UnexpectedBuildFailure;
15 import org.gradle.testkit.runner.UnexpectedBuildFailure;
15 import org.implab.gradle.common.core.lang.Deferred;
16 import org.implab.gradle.common.core.lang.Deferred;
16 import org.implab.gradle.variants.sources.GenericSourceSet;
17 import org.implab.gradle.variants.sources.GenericSourceSet;
17 import org.junit.jupiter.api.io.TempDir;
18 import org.junit.jupiter.api.io.TempDir;
18
19
19 abstract class AbstractFunctionalTest {
20 abstract class AbstractFunctionalTest {
20 private static final String SETTINGS_FILE = "settings.gradle";
21 private static final String SETTINGS_FILE = "settings.gradle";
21 private static final String BUILD_FILE = "build.gradle";
22 private static final String BUILD_FILE = "build.gradle";
23 private static final Pattern INCLUDE_DECLARATION = Pattern.compile("^include(?:\\s|\\().*");
24 private static final Pattern QUOTED_LITERAL = Pattern.compile("['\"]([^'\"]+)['\"]");
22
25
23 @TempDir
26 @TempDir
24 Path testProjectDir;
27 Path testProjectDir;
25
28
26 protected void writeSettings(String rootProjectName) throws IOException {
29 protected void writeSettings(String rootProjectName) throws IOException {
27 writeFile(SETTINGS_FILE, "rootProject.name = '" + rootProjectName + "'\n");
30 writeFile(SETTINGS_FILE, "rootProject.name = '" + rootProjectName + "'\n");
28 }
31 }
29
32
30 protected void writeBuildFile(String body) throws IOException {
33 protected void writeBuildFile(String body) throws IOException {
31 writeFile(BUILD_FILE, buildscriptClasspathBlock() + "\n" + body);
34 writeFile(BUILD_FILE, buildscriptClasspathBlock() + "\n" + body);
32 }
35 }
33
36
34 protected GradleRunner runner(String... arguments) {
37 protected GradleRunner runner(String... arguments) {
35 return GradleRunner.create()
38 return GradleRunner.create()
36 .withProjectDir(testProjectDir.toFile())
39 .withProjectDir(testProjectDir.toFile())
37 .withArguments(arguments)
40 .withArguments(arguments)
38 .forwardOutput();
41 .forwardOutput();
39 }
42 }
40
43
41 protected void assertBuildFails(String expectedError, String... arguments) {
44 protected void assertBuildFails(String expectedError, String... arguments) {
42 var ex = org.junit.jupiter.api.Assertions.assertThrows(
45 var ex = org.junit.jupiter.api.Assertions.assertThrows(
43 UnexpectedBuildFailure.class,
46 UnexpectedBuildFailure.class,
44 () -> runner(arguments).build());
47 () -> runner(arguments).build());
45
48
46 var output = ex.getBuildResult().getOutput();
49 var output = ex.getBuildResult().getOutput();
47 assertTrue(output.contains(expectedError), () -> "Expected [" + expectedError + "] in output:\n" + output);
50 assertTrue(output.contains(expectedError), () -> "Expected [" + expectedError + "] in output:\n" + output);
48 }
51 }
49
52
50 private static String buildscriptClasspathBlock() {
53 private static String buildscriptClasspathBlock() {
51 var classpath = pluginClasspath().stream()
54 var classpath = pluginClasspath().stream()
52 .map(file -> "'" + file.getAbsolutePath().replace("\\", "\\\\") + "'")
55 .map(file -> "'" + file.getAbsolutePath().replace("\\", "\\\\") + "'")
53 .collect(Collectors.joining(", "));
56 .collect(Collectors.joining(", "));
54
57
55 return """
58 return """
56 buildscript {
59 buildscript {
57 dependencies {
60 dependencies {
58 classpath files(%s)
61 classpath files(%s)
59 }
62 }
60 }
63 }
61 """.formatted(classpath);
64 """.formatted(classpath);
62 }
65 }
63
66
64 private static List<File> pluginClasspath() {
67 private static List<File> pluginClasspath() {
65 try {
68 try {
66 var files = new LinkedHashSet<File>();
69 var files = new LinkedHashSet<File>();
67 files.add(codeSource(VariantSourcesPlugin.class));
70 files.add(codeSource(VariantSourcesPlugin.class));
68 files.add(resourceRoot("META-INF/gradle-plugins/org.implab.gradle-variants.properties"));
71 files.add(resourceRoot("META-INF/gradle-plugins/org.implab.gradle-variants.properties"));
69 files.add(codeSource(GenericSourceSet.class));
72 files.add(codeSource(GenericSourceSet.class));
70 files.add(codeSource(Deferred.class));
73 files.add(codeSource(Deferred.class));
71 return List.copyOf(files);
74 return List.copyOf(files);
72 } catch (Exception e) {
75 } catch (Exception e) {
73 throw new RuntimeException("Unable to build plugin classpath for test", e);
76 throw new RuntimeException("Unable to build plugin classpath for test", e);
74 }
77 }
75 }
78 }
76
79
77 private static File codeSource(Class<?> type) throws Exception {
80 private static File codeSource(Class<?> type) throws Exception {
78 return Path.of(type.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile();
81 return Path.of(type.getProtectionDomain().getCodeSource().getLocation().toURI()).toFile();
79 }
82 }
80
83
81 private static File resourceRoot(String resourceName) throws Exception {
84 private static File resourceRoot(String resourceName) throws Exception {
82 var url = VariantSourcesPlugin.class.getClassLoader().getResource(resourceName);
85 var url = VariantSourcesPlugin.class.getClassLoader().getResource(resourceName);
83 if (url == null)
86 if (url == null)
84 throw new IllegalStateException("Classpath resource isn't found: " + resourceName);
87 throw new IllegalStateException("Classpath resource isn't found: " + resourceName);
85
88
86 var path = Path.of(url.toURI());
89 var path = Path.of(url.toURI());
87 var segments = resourceName.split("/").length;
90 var segments = resourceName.split("/").length;
88 for (var i = 0; i < segments; i++)
91 for (var i = 0; i < segments; i++)
89 path = path.getParent();
92 path = path.getParent();
90 return path.toFile();
93 return path.toFile();
91 }
94 }
92
95
93 protected void writeFile(String relativePath, String content) throws IOException {
96 protected void writeFile(String relativePath, String content) throws IOException {
94 Path path = testProjectDir.resolve(relativePath);
97 Path path = testProjectDir.resolve(relativePath);
95 Files.createDirectories(path.getParent());
98 Files.createDirectories(path.getParent());
96 Files.writeString(path, content);
99 Files.writeString(path, content);
100
101 if (SETTINGS_FILE.equals(relativePath))
102 ensureIncludedProjectDirectories(content);
103 }
104
105 private void ensureIncludedProjectDirectories(String settingsContent) throws IOException {
106 for (var line : settingsContent.split("\\R")) {
107 var trimmed = line.strip();
108 if (!INCLUDE_DECLARATION.matcher(trimmed).matches())
109 continue;
110
111 var matcher = QUOTED_LITERAL.matcher(trimmed);
112 while (matcher.find()) {
113 var projectPath = matcher.group(1);
114 if (projectPath.startsWith(":"))
115 projectPath = projectPath.substring(1);
116 if (projectPath.isBlank())
117 continue;
118
119 Files.createDirectories(testProjectDir.resolve(projectPath.replace(':', File.separatorChar)));
120 }
121 }
97 }
122 }
98 }
123 }
@@ -1,867 +1,867
1 package org.implab.gradle.variants;
1 package org.implab.gradle.variants;
2
2
3 import static org.junit.jupiter.api.Assertions.assertTrue;
3 import static org.junit.jupiter.api.Assertions.assertTrue;
4
4
5 import org.gradle.testkit.runner.BuildResult;
5 import org.gradle.testkit.runner.BuildResult;
6 import org.gradle.testkit.runner.TaskOutcome;
6 import org.gradle.testkit.runner.TaskOutcome;
7 import org.junit.jupiter.api.Test;
7 import org.junit.jupiter.api.Test;
8
8
9 class VariantArtifactsPluginFunctionalTest extends AbstractFunctionalTest {
9 class VariantArtifactsPluginFunctionalTest extends AbstractFunctionalTest {
10
10
11 @Test
11 @Test
12 void gradleReferenceLazyOutgoingConfigurationAllowsSecondaryArtifactSelection() throws Exception {
12 void gradleReferenceLazyOutgoingConfigurationAllowsSecondaryArtifactSelection() throws Exception {
13 writeFile("settings.gradle", """
13 writeFile("settings.gradle", """
14 rootProject.name = 'gradle-reference-outgoing-resolution'
14 rootProject.name = 'gradle-reference-outgoing-resolution'
15 include 'producer', 'consumer'
15 include 'producer', 'consumer'
16 """);
16 """);
17 writeFile("producer/inputs/typesPackage", "types\n");
17 writeFile("producer/inputs/typesPackage", "types\n");
18 writeFile("producer/inputs/js", "js\n");
18 writeFile("producer/inputs/js", "js\n");
19 writeBuildFile("""
19 writeBuildFile("""
20 import org.gradle.api.attributes.Attribute
20 import org.gradle.api.attributes.Attribute
21
21
22 def variantAttr = Attribute.of('test.variant', String)
22 def variantAttr = Attribute.of('test.variant', String)
23 def slotAttr = Attribute.of('test.slot', String)
23 def slotAttr = Attribute.of('test.slot', String)
24
24
25 project(':producer') {
25 project(':producer') {
26 def browserElements = configurations.consumable('browserElements')
26 def browserElements = configurations.consumable('browserElements')
27
27
28 println('reference: registered browserElements provider')
28 println('reference: registered browserElements provider')
29
29
30 browserElements.configure { configuration ->
30 browserElements.configure { configuration ->
31 println('reference: configuring browserElements')
31 println('reference: configuring browserElements')
32
32
33 configuration.attributes.attribute(variantAttr, 'browser')
33 configuration.attributes.attribute(variantAttr, 'browser')
34 configuration.outgoing.attributes.attribute(slotAttr, 'typesPackage')
34 configuration.outgoing.attributes.attribute(slotAttr, 'typesPackage')
35 configuration.outgoing.artifact(layout.projectDirectory.file('inputs/typesPackage'))
35 configuration.outgoing.artifact(layout.projectDirectory.file('inputs/typesPackage'))
36
36
37 configuration.outgoing.variants.create('js') { secondary ->
37 configuration.outgoing.variants.create('js') { secondary ->
38 println('reference: creating js outgoing variant')
38 println('reference: creating js outgoing variant')
39
39
40 secondary.attributes.attribute(slotAttr, 'js')
40 secondary.attributes.attribute(slotAttr, 'js')
41 secondary.artifact(layout.projectDirectory.file('inputs/js'))
41 secondary.artifact(layout.projectDirectory.file('inputs/js'))
42 }
42 }
43 }
43 }
44 }
44 }
45
45
46 project(':consumer') {
46 project(':consumer') {
47 configurations {
47 configurations {
48 compileView {
48 compileView {
49 canBeResolved = true
49 canBeResolved = true
50 canBeConsumed = false
50 canBeConsumed = false
51 canBeDeclared = true
51 canBeDeclared = true
52 attributes {
52 attributes {
53 attribute(variantAttr, 'browser')
53 attribute(variantAttr, 'browser')
54 attribute(slotAttr, 'typesPackage')
54 attribute(slotAttr, 'typesPackage')
55 }
55 }
56 }
56 }
57 }
57 }
58
58
59 dependencies {
59 dependencies {
60 compileView project(':producer')
60 compileView project(':producer')
61 }
61 }
62
62
63 tasks.register('probe') {
63 tasks.register('probe') {
64 doLast {
64 doLast {
65 println('reference: resolving primary files')
65 println('reference: resolving primary files')
66
66
67 def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',')
67 def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',')
68
68
69 println('reference: resolving secondary files')
69 println('reference: resolving secondary files')
70
70
71 def jsFiles = configurations.compileView.incoming.artifactView {
71 def jsFiles = configurations.compileView.incoming.artifactView {
72 attributes {
72 attributes {
73 attribute(slotAttr, 'js')
73 attribute(slotAttr, 'js')
74 }
74 }
75 }.files.files.collect { it.name }.sort().join(',')
75 }.files.files.collect { it.name }.sort().join(',')
76
76
77 println('compileFiles=' + compileFiles)
77 println('compileFiles=' + compileFiles)
78 println('jsFiles=' + jsFiles)
78 println('jsFiles=' + jsFiles)
79 }
79 }
80 }
80 }
81 }
81 }
82 """);
82 """);
83
83
84 BuildResult result = runner(":consumer:probe").build();
84 BuildResult result = runner(":consumer:probe").build();
85 var output = result.getOutput();
85 var output = result.getOutput();
86 var registered = output.indexOf("reference: registered browserElements provider");
86 var registered = output.indexOf("reference: registered browserElements provider");
87 var resolvingPrimary = output.indexOf("reference: resolving primary files");
87 var resolvingPrimary = output.indexOf("reference: resolving primary files");
88 var configuring = output.indexOf("reference: configuring browserElements");
88 var configuring = output.indexOf("reference: configuring browserElements");
89 var creatingSecondary = output.indexOf("reference: creating js outgoing variant");
89 var creatingSecondary = output.indexOf("reference: creating js outgoing variant");
90 var resolvingSecondary = output.indexOf("reference: resolving secondary files");
90 var resolvingSecondary = output.indexOf("reference: resolving secondary files");
91
91
92 assertTrue(registered >= 0);
92 assertTrue(registered >= 0);
93 assertTrue(resolvingPrimary >= 0);
93 assertTrue(resolvingPrimary >= 0);
94 assertTrue(configuring >= 0);
94 assertTrue(configuring >= 0);
95 assertTrue(creatingSecondary >= 0);
95 assertTrue(creatingSecondary >= 0);
96 assertTrue(resolvingSecondary >= 0);
96 assertTrue(resolvingSecondary >= 0);
97 assertTrue(registered < resolvingPrimary);
97 assertTrue(registered < resolvingPrimary);
98 assertTrue(resolvingPrimary < configuring);
98 assertTrue(resolvingPrimary < configuring);
99 assertTrue(configuring < creatingSecondary);
99 assertTrue(configuring < creatingSecondary);
100 assertTrue(creatingSecondary < resolvingSecondary);
100 assertTrue(creatingSecondary < resolvingSecondary);
101 assertTrue(output.contains("compileFiles=typesPackage"));
101 assertTrue(output.contains("compileFiles=typesPackage"));
102 assertTrue(output.contains("jsFiles=js"));
102 assertTrue(output.contains("jsFiles=js"));
103 }
103 }
104
104
105 @Test
105 @Test
106 void gradleReferenceRegisteredSecondaryArtifactVariantIsNotRealizedBeforeResolution() throws Exception {
106 void gradleReferenceRegisteredSecondaryArtifactVariantAllowsSecondaryArtifactSelection() throws Exception {
107 // Gradle issue: https://github.com/gradle/gradle/issues/27441
108 // Registered outgoing artifact variants are not realized before dependency resolution.
109 writeFile("settings.gradle", """
107 writeFile("settings.gradle", """
110 rootProject.name = 'gradle-reference-registered-secondary-variant'
108 rootProject.name = 'gradle-reference-registered-secondary-variant'
111 include 'producer', 'consumer'
109 include 'producer', 'consumer'
112 """);
110 """);
113 writeFile("producer/inputs/typesPackage", "types\n");
111 writeFile("producer/inputs/typesPackage", "types\n");
114 writeFile("producer/inputs/js", "js\n");
112 writeFile("producer/inputs/js", "js\n");
115 writeFile("build.gradle", """
113 writeFile("build.gradle", """
116 import org.gradle.api.attributes.Attribute
114 import org.gradle.api.attributes.Attribute
117
115
118 def variantAttr = Attribute.of('test.variant', String)
116 def variantAttr = Attribute.of('test.variant', String)
119 def slotAttr = Attribute.of('test.slot', String)
117 def slotAttr = Attribute.of('test.slot', String)
120
118
121 project(':producer') {
119 project(':producer') {
122 def browserElements = configurations.consumable('browserElements')
120 def browserElements = configurations.consumable('browserElements')
123
121
124 browserElements.configure { configuration ->
122 browserElements.configure { configuration ->
125 configuration.attributes.attribute(variantAttr, 'browser')
123 configuration.attributes.attribute(variantAttr, 'browser')
126 configuration.outgoing.attributes.attribute(slotAttr, 'typesPackage')
124 configuration.outgoing.attributes.attribute(slotAttr, 'typesPackage')
127 configuration.outgoing.artifact(layout.projectDirectory.file('inputs/typesPackage'))
125 configuration.outgoing.artifact(layout.projectDirectory.file('inputs/typesPackage'))
128
126
129 configuration.outgoing.variants.register('js') { secondary ->
127 configuration.outgoing.variants.register('js') { secondary ->
130 secondary.attributes.attribute(slotAttr, 'js')
128 secondary.attributes.attribute(slotAttr, 'js')
131 secondary.artifact(layout.projectDirectory.file('inputs/js'))
129 secondary.artifact(layout.projectDirectory.file('inputs/js'))
132 }
130 }
133 }
131 }
134 }
132 }
135
133
136 project(':consumer') {
134 project(':consumer') {
137 configurations {
135 configurations {
138 compileView {
136 compileView {
139 canBeResolved = true
137 canBeResolved = true
140 canBeConsumed = false
138 canBeConsumed = false
141 canBeDeclared = true
139 canBeDeclared = true
142 attributes {
140 attributes {
143 attribute(variantAttr, 'browser')
141 attribute(variantAttr, 'browser')
144 attribute(slotAttr, 'typesPackage')
142 attribute(slotAttr, 'typesPackage')
145 }
143 }
146 }
144 }
147 }
145 }
148
146
149 dependencies {
147 dependencies {
150 compileView project(':producer')
148 compileView project(':producer')
151 }
149 }
152
150
153 tasks.register('probe') {
151 tasks.register('probe') {
154 doLast {
152 doLast {
155 def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',')
153 def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',')
156 def jsFiles = configurations.compileView.incoming.artifactView {
154 def jsFiles = configurations.compileView.incoming.artifactView {
157 attributes {
155 attributes {
158 attribute(slotAttr, 'js')
156 attribute(slotAttr, 'js')
159 }
157 }
160 }.files.files.collect { it.name }.sort().join(',')
158 }.files.files.collect { it.name }.sort().join(',')
161
159
162 println('compileFiles=' + compileFiles)
160 println('compileFiles=' + compileFiles)
163 println('jsFiles=' + jsFiles)
161 println('jsFiles=' + jsFiles)
164 }
162 }
165 }
163 }
166 }
164 }
167 """);
165 """);
168
166
169 assertBuildFails("Cannot create variant 'js' after dependency configuration ':producer:browserElements' has been resolved",
167 BuildResult result = runner(":consumer:probe").build();
170 ":consumer:probe");
168
169 assertTrue(result.getOutput().contains("compileFiles=typesPackage"));
170 assertTrue(result.getOutput().contains("jsFiles=js"));
171 }
171 }
172
172
173 @Test
173 @Test
174 void materializesPrimaryAndSecondarySlotsAndInvokesOutgoingHooks() throws Exception {
174 void materializesPrimaryAndSecondarySlotsAndInvokesOutgoingHooks() throws Exception {
175 writeSettings("variant-artifacts-slots");
175 writeSettings("variant-artifacts-slots");
176 writeFile("inputs/base.js", "console.log('base')\n");
176 writeFile("inputs/base.js", "console.log('base')\n");
177 writeFile("inputs/amd.js", "console.log('amd')\n");
177 writeFile("inputs/amd.js", "console.log('amd')\n");
178 writeFile("inputs/mainJs.txt", "mainJs marker\n");
178 writeFile("inputs/mainJs.txt", "mainJs marker\n");
179 writeFile("inputs/amdJs.txt", "amdJs marker\n");
179 writeFile("inputs/amdJs.txt", "amdJs marker\n");
180 writeBuildFile("""
180 writeBuildFile("""
181 import org.gradle.api.attributes.Attribute
181 import org.gradle.api.attributes.Attribute
182
182
183 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
183 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
184
184
185 def variantAttr = Attribute.of('test.variant', String)
185 def variantAttr = Attribute.of('test.variant', String)
186 def slotAttr = Attribute.of('test.slot', String)
186 def slotAttr = Attribute.of('test.slot', String)
187
187
188 variants.layers.create('mainBase')
188 variants.layers.create('mainBase')
189 variants.layers.create('mainAmd')
189 variants.layers.create('mainAmd')
190 variants.roles.create('main')
190 variants.roles.create('main')
191 variants.roles.create('test')
191 variants.roles.create('test')
192 variants.variant('browser') {
192 variants.variant('browser') {
193 role('main') {
193 role('main') {
194 layers('mainBase', 'mainAmd')
194 layers('mainBase', 'mainAmd')
195 }
195 }
196 }
196 }
197
197
198 variantSources {
198 variantSources {
199 layer('mainBase') {
199 layer('mainBase') {
200 sourceSet {
200 sourceSet {
201 declareOutputs('js')
201 declareOutputs('js')
202 registerOutput('js', layout.projectDirectory.file('inputs/base.js'))
202 registerOutput('js', layout.projectDirectory.file('inputs/base.js'))
203 }
203 }
204 }
204 }
205 layer('mainAmd') {
205 layer('mainAmd') {
206 sourceSet {
206 sourceSet {
207 declareOutputs('js')
207 declareOutputs('js')
208 registerOutput('js', layout.projectDirectory.file('inputs/amd.js'))
208 registerOutput('js', layout.projectDirectory.file('inputs/amd.js'))
209 }
209 }
210 }
210 }
211 }
211 }
212
212
213 variantArtifacts {
213 variantArtifacts {
214 variant('browser') {
214 variant('browser') {
215 primarySlot('mainJs') {
215 primarySlot('mainJs') {
216 fromRole('main') {
216 fromRole('main') {
217 output('js')
217 output('js')
218 }
218 }
219 from(layout.projectDirectory.file('inputs/mainJs.txt'))
219 from(layout.projectDirectory.file('inputs/mainJs.txt'))
220 }
220 }
221 slot('amdJs') {
221 slot('amdJs') {
222 fromLayer('mainAmd') {
222 fromLayer('mainAmd') {
223 output('js')
223 output('js')
224 }
224 }
225 from(layout.projectDirectory.file('inputs/amdJs.txt'))
225 from(layout.projectDirectory.file('inputs/amdJs.txt'))
226 }
226 }
227 }
227 }
228
228
229 whenOutgoingConfiguration { publication ->
229 whenOutgoingConfiguration { publication ->
230 publication.configuration {
230 publication.configuration {
231 attributes.attribute(variantAttr, publication.variant.name)
231 attributes.attribute(variantAttr, publication.variant.name)
232 }
232 }
233 }
233 }
234
234
235 whenOutgoingSlot { publication ->
235 whenOutgoingSlot { publication ->
236 def slotName = publication.artifactSlot.slot.name
236 def slotName = publication.artifactSlot.slot.name
237 publication.artifactAttributes {
237 publication.artifactAttributes {
238 attribute(slotAttr, slotName)
238 attribute(slotAttr, slotName)
239 }
239 }
240 }
240 }
241 }
241 }
242
242
243 tasks.register('probe') {
243 tasks.register('probe') {
244 dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_mainJs'
244 dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_mainJs'
245 dependsOn 'assembleVariantArtifactSlot_v7_browser_s5_amdJs'
245 dependsOn 'assembleVariantArtifactSlot_v7_browser_s5_amdJs'
246
246
247 doLast {
247 doLast {
248 def mainDir = layout.buildDirectory.dir('variant-assemblies/browser/mainJs').get().asFile
248 def mainDir = layout.buildDirectory.dir('variant-assemblies/browser/mainJs').get().asFile
249 def amdDir = layout.buildDirectory.dir('variant-assemblies/browser/amdJs').get().asFile
249 def amdDir = layout.buildDirectory.dir('variant-assemblies/browser/amdJs').get().asFile
250
250
251 assert new File(mainDir, 'base.js').exists()
251 assert new File(mainDir, 'base.js').exists()
252 assert new File(mainDir, 'amd.js').exists()
252 assert new File(mainDir, 'amd.js').exists()
253 assert new File(mainDir, 'mainJs.txt').exists()
253 assert new File(mainDir, 'mainJs.txt').exists()
254
254
255 assert !new File(amdDir, 'base.js').exists()
255 assert !new File(amdDir, 'base.js').exists()
256 assert new File(amdDir, 'amd.js').exists()
256 assert new File(amdDir, 'amd.js').exists()
257 assert new File(amdDir, 'amdJs.txt').exists()
257 assert new File(amdDir, 'amdJs.txt').exists()
258
258
259 def elements = configurations.getByName('browserElements')
259 def elements = configurations.getByName('browserElements')
260 def amdVariant = elements.outgoing.variants.getByName('amdJs')
260 def amdVariant = elements.outgoing.variants.getByName('amdJs')
261
261
262 println('variantAttr=' + elements.attributes.getAttribute(variantAttr))
262 println('variantAttr=' + elements.attributes.getAttribute(variantAttr))
263 println('primarySlotAttr=' + elements.outgoing.attributes.getAttribute(slotAttr))
263 println('primarySlotAttr=' + elements.outgoing.attributes.getAttribute(slotAttr))
264 println('amdSlotAttr=' + amdVariant.attributes.getAttribute(slotAttr))
264 println('amdSlotAttr=' + amdVariant.attributes.getAttribute(slotAttr))
265 println('configurations=' + configurations.matching { it.name == 'browserElements' }.collect { it.name }.join(','))
265 println('configurations=' + configurations.matching { it.name == 'browserElements' }.collect { it.name }.join(','))
266 println('secondaryVariants=' + elements.outgoing.variants.collect { it.name }.sort().join(','))
266 println('secondaryVariants=' + elements.outgoing.variants.collect { it.name }.sort().join(','))
267 }
267 }
268 }
268 }
269 """);
269 """);
270
270
271 BuildResult result = runner("probe").build();
271 BuildResult result = runner("probe").build();
272
272
273 assertTrue(result.getOutput().contains("variantAttr=browser"));
273 assertTrue(result.getOutput().contains("variantAttr=browser"));
274 assertTrue(result.getOutput().contains("primarySlotAttr=mainJs"));
274 assertTrue(result.getOutput().contains("primarySlotAttr=mainJs"));
275 assertTrue(result.getOutput().contains("amdSlotAttr=amdJs"));
275 assertTrue(result.getOutput().contains("amdSlotAttr=amdJs"));
276 assertTrue(result.getOutput().contains("configurations=browserElements"));
276 assertTrue(result.getOutput().contains("configurations=browserElements"));
277 assertTrue(result.getOutput().contains("secondaryVariants=amdJs"));
277 assertTrue(result.getOutput().contains("secondaryVariants=amdJs"));
278 assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS);
278 assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS);
279 }
279 }
280
280
281 @Test
281 @Test
282 void outgoingSlotHookFollowsMaterializedGradleArtifactVariants() throws Exception {
282 void outgoingSlotHookFollowsMaterializedGradleArtifactVariants() throws Exception {
283 writeSettings("variant-artifacts-materialized-gradle-variant");
283 writeSettings("variant-artifacts-materialized-gradle-variant");
284 writeFile("inputs/typesPackage", "types\n");
284 writeFile("inputs/typesPackage", "types\n");
285 writeFile("inputs/js", "js\n");
285 writeFile("inputs/js", "js\n");
286 writeBuildFile("""
286 writeBuildFile("""
287 import org.gradle.api.attributes.Attribute
287 import org.gradle.api.attributes.Attribute
288
288
289 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
289 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
290
290
291 def slotAttr = Attribute.of('test.slot', String)
291 def slotAttr = Attribute.of('test.slot', String)
292
292
293 variants.layers.create('main')
293 variants.layers.create('main')
294 variants.roles.create('main')
294 variants.roles.create('main')
295 variants.variant('browser') {
295 variants.variant('browser') {
296 role('main') {
296 role('main') {
297 layers('main')
297 layers('main')
298 }
298 }
299 }
299 }
300
300
301 variantArtifacts {
301 variantArtifacts {
302 variant('browser') {
302 variant('browser') {
303 primarySlot('typesPackage') {
303 primarySlot('typesPackage') {
304 from(layout.projectDirectory.file('inputs/typesPackage'))
304 from(layout.projectDirectory.file('inputs/typesPackage'))
305 }
305 }
306 }
306 }
307
307
308 whenOutgoingConfiguration { publication ->
308 whenOutgoingConfiguration { publication ->
309 publication.configuration {
309 publication.configuration {
310 outgoing.variants.create('js') { secondary ->
310 outgoing.variants.create('js') { secondary ->
311 secondary.artifact(layout.projectDirectory.file('inputs/js'))
311 secondary.artifact(layout.projectDirectory.file('inputs/js'))
312 }
312 }
313 }
313 }
314 }
314 }
315
315
316 whenOutgoingSlot { publication ->
316 whenOutgoingSlot { publication ->
317 publication.artifactAttributes {
317 publication.artifactAttributes {
318 attribute(slotAttr, publication.artifactSlot.slot.name)
318 attribute(slotAttr, publication.artifactSlot.slot.name)
319 }
319 }
320 }
320 }
321 }
321 }
322
322
323 tasks.register('probe') {
323 tasks.register('probe') {
324 doLast {
324 doLast {
325 def elements = configurations.getByName('browserElements')
325 def elements = configurations.getByName('browserElements')
326 def jsVariant = elements.outgoing.variants.getByName('js')
326 def jsVariant = elements.outgoing.variants.getByName('js')
327
327
328 println('primarySlotAttr=' + elements.outgoing.attributes.getAttribute(slotAttr))
328 println('primarySlotAttr=' + elements.outgoing.attributes.getAttribute(slotAttr))
329 println('jsSlotAttr=' + jsVariant.attributes.getAttribute(slotAttr))
329 println('jsSlotAttr=' + jsVariant.attributes.getAttribute(slotAttr))
330 }
330 }
331 }
331 }
332 """);
332 """);
333
333
334 BuildResult result = runner("probe").build();
334 BuildResult result = runner("probe").build();
335
335
336 assertTrue(result.getOutput().contains("primarySlotAttr=typesPackage"));
336 assertTrue(result.getOutput().contains("primarySlotAttr=typesPackage"));
337 assertTrue(result.getOutput().contains("jsSlotAttr=js"));
337 assertTrue(result.getOutput().contains("jsSlotAttr=js"));
338 assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS);
338 assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS);
339 }
339 }
340
340
341 @Test
341 @Test
342 void allowsSingleSlotVariantWithoutExplicitPrimarySlot() throws Exception {
342 void allowsSingleSlotVariantWithoutExplicitPrimarySlot() throws Exception {
343 writeSettings("variant-artifacts-single-slot");
343 writeSettings("variant-artifacts-single-slot");
344 writeBuildFile("""
344 writeBuildFile("""
345 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
345 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
346
346
347 variants.layers.create('main')
347 variants.layers.create('main')
348 variants.roles.create('main')
348 variants.roles.create('main')
349 variants.variant('browser') {
349 variants.variant('browser') {
350 role('main') {
350 role('main') {
351 layers('main')
351 layers('main')
352 }
352 }
353 }
353 }
354
354
355 variantSources.layer('main') {
355 variantSources.layer('main') {
356 sourceSet {
356 sourceSet {
357 declareOutputs('types')
357 declareOutputs('types')
358 }
358 }
359 }
359 }
360
360
361 variantArtifacts {
361 variantArtifacts {
362 variant('browser') {
362 variant('browser') {
363 slot('typesPackage') {
363 slot('typesPackage') {
364 fromVariant {
364 fromVariant {
365 output('types')
365 output('types')
366 }
366 }
367 }
367 }
368 }
368 }
369 }
369 }
370
370
371 tasks.register('probe') {
371 tasks.register('probe') {
372 doLast {
372 doLast {
373 variantArtifacts.whenAvailable { ctx ->
373 variantArtifacts.whenAvailable { ctx ->
374 def browser = objects.named(org.implab.gradle.variants.core.Variant, 'browser')
374 def browser = objects.named(org.implab.gradle.variants.core.Variant, 'browser')
375 println('primary=' + ctx.findOutgoing(browser).get().primarySlot.get().name)
375 println('primary=' + ctx.findOutgoing(browser).get().primarySlot.get().name)
376 }
376 }
377 }
377 }
378 }
378 }
379 """);
379 """);
380
380
381 BuildResult result = runner("probe").build();
381 BuildResult result = runner("probe").build();
382
382
383 assertTrue(result.getOutput().contains("primary=typesPackage"));
383 assertTrue(result.getOutput().contains("primary=typesPackage"));
384 }
384 }
385
385
386 @Test
386 @Test
387 void materializesDirectSlotInputsWithoutVariantSourceBindings() throws Exception {
387 void materializesDirectSlotInputsWithoutVariantSourceBindings() throws Exception {
388 writeSettings("variant-artifacts-direct-input");
388 writeSettings("variant-artifacts-direct-input");
389 writeFile("inputs/bundle.js", "console.log('bundle')\n");
389 writeFile("inputs/bundle.js", "console.log('bundle')\n");
390 writeBuildFile("""
390 writeBuildFile("""
391 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
391 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
392
392
393 variants.layers.create('main')
393 variants.layers.create('main')
394 variants.roles.create('main')
394 variants.roles.create('main')
395 variants.variant('browser') {
395 variants.variant('browser') {
396 role('main') {
396 role('main') {
397 layers('main')
397 layers('main')
398 }
398 }
399 }
399 }
400
400
401 variantArtifacts {
401 variantArtifacts {
402 variant('browser') {
402 variant('browser') {
403 primarySlot('bundle') {
403 primarySlot('bundle') {
404 from(layout.projectDirectory.file('inputs/bundle.js'))
404 from(layout.projectDirectory.file('inputs/bundle.js'))
405 }
405 }
406 }
406 }
407 }
407 }
408
408
409 tasks.register('probe') {
409 tasks.register('probe') {
410 dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_bundle'
410 dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_bundle'
411
411
412 doLast {
412 doLast {
413 def bundleDir = layout.buildDirectory.dir('variant-assemblies/browser/bundle').get().asFile
413 def bundleDir = layout.buildDirectory.dir('variant-assemblies/browser/bundle').get().asFile
414 assert new File(bundleDir, 'bundle.js').exists()
414 assert new File(bundleDir, 'bundle.js').exists()
415 }
415 }
416 }
416 }
417 """);
417 """);
418
418
419 BuildResult result = runner("probe").build();
419 BuildResult result = runner("probe").build();
420
420
421 assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS);
421 assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS);
422 }
422 }
423
423
424 @Test
424 @Test
425 void publishesTaskProducedFileArtifactDirectly() throws Exception {
425 void publishesTaskProducedFileArtifactDirectly() throws Exception {
426 writeFile("settings.gradle", """
426 writeFile("settings.gradle", """
427 rootProject.name = 'variant-artifacts-task-produced-file'
427 rootProject.name = 'variant-artifacts-task-produced-file'
428 include 'producer', 'consumer'
428 include 'producer', 'consumer'
429 """);
429 """);
430 writeBuildFile("""
430 writeBuildFile("""
431 import org.gradle.api.DefaultTask
431 import org.gradle.api.DefaultTask
432 import org.gradle.api.attributes.Attribute
432 import org.gradle.api.attributes.Attribute
433 import org.gradle.api.file.RegularFileProperty
433 import org.gradle.api.file.RegularFileProperty
434 import org.gradle.api.tasks.OutputFile
434 import org.gradle.api.tasks.OutputFile
435 import org.gradle.api.tasks.TaskAction
435 import org.gradle.api.tasks.TaskAction
436
436
437 def variantAttr = Attribute.of('test.variant', String)
437 def variantAttr = Attribute.of('test.variant', String)
438 def slotAttr = Attribute.of('test.slot', String)
438 def slotAttr = Attribute.of('test.slot', String)
439
439
440 abstract class WritePackageMetadata extends DefaultTask {
440 abstract class WritePackageMetadata extends DefaultTask {
441 @OutputFile
441 @OutputFile
442 abstract RegularFileProperty getOutputFile()
442 abstract RegularFileProperty getOutputFile()
443
443
444 @TaskAction
444 @TaskAction
445 void write() {
445 void write() {
446 def file = outputFile.get().asFile
446 def file = outputFile.get().asFile
447 file.parentFile.mkdirs()
447 file.parentFile.mkdirs()
448 file.text = '{"name":"demo"}\\n'
448 file.text = '{"name":"demo"}\\n'
449 }
449 }
450 }
450 }
451
451
452 project(':producer') {
452 project(':producer') {
453 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
453 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
454
454
455 variants.layers.create('main')
455 variants.layers.create('main')
456 variants.roles.create('main')
456 variants.roles.create('main')
457 variants.variant('browser') {
457 variants.variant('browser') {
458 role('main') {
458 role('main') {
459 layers('main')
459 layers('main')
460 }
460 }
461 }
461 }
462
462
463 def writePackageMetadata = tasks.register('writePackageMetadata', WritePackageMetadata) {
463 def writePackageMetadata = tasks.register('writePackageMetadata', WritePackageMetadata) {
464 outputFile.set(layout.buildDirectory.file('generated/package.json'))
464 outputFile.set(layout.buildDirectory.file('generated/package.json'))
465 }
465 }
466
466
467 variantArtifacts {
467 variantArtifacts {
468 variant('browser') {
468 variant('browser') {
469 primarySlot('packageMetadata') {
469 primarySlot('packageMetadata') {
470 producedBy(writePackageMetadata) {
470 producedBy(writePackageMetadata) {
471 outputFile
471 outputFile
472 }
472 }
473 }
473 }
474 }
474 }
475
475
476 whenOutgoingConfiguration { publication ->
476 whenOutgoingConfiguration { publication ->
477 publication.configuration {
477 publication.configuration {
478 attributes.attribute(variantAttr, publication.variant.name)
478 attributes.attribute(variantAttr, publication.variant.name)
479 }
479 }
480 }
480 }
481
481
482 whenOutgoingSlot { publication ->
482 whenOutgoingSlot { publication ->
483 publication.artifactAttributes {
483 publication.artifactAttributes {
484 attribute(slotAttr, publication.artifactSlot.slot.name)
484 attribute(slotAttr, publication.artifactSlot.slot.name)
485 }
485 }
486 }
486 }
487 }
487 }
488
488
489 tasks.register('checkNoManagedAssembly') {
489 tasks.register('checkNoManagedAssembly') {
490 doLast {
490 doLast {
491 def assemblyTasks = tasks.names
491 def assemblyTasks = tasks.names
492 .findAll { it.startsWith('assembleVariantArtifactSlot') }
492 .findAll { it.startsWith('assembleVariantArtifactSlot') }
493 .sort()
493 .sort()
494 println('producerAssemblyTasks=' + assemblyTasks.join(','))
494 println('producerAssemblyTasks=' + assemblyTasks.join(','))
495 assert assemblyTasks.empty
495 assert assemblyTasks.empty
496 }
496 }
497 }
497 }
498 }
498 }
499
499
500 project(':consumer') {
500 project(':consumer') {
501 configurations {
501 configurations {
502 compileView {
502 compileView {
503 canBeResolved = true
503 canBeResolved = true
504 canBeConsumed = false
504 canBeConsumed = false
505 canBeDeclared = true
505 canBeDeclared = true
506 attributes {
506 attributes {
507 attribute(variantAttr, 'browser')
507 attribute(variantAttr, 'browser')
508 attribute(slotAttr, 'packageMetadata')
508 attribute(slotAttr, 'packageMetadata')
509 }
509 }
510 }
510 }
511 }
511 }
512
512
513 dependencies {
513 dependencies {
514 compileView project(':producer')
514 compileView project(':producer')
515 }
515 }
516
516
517 tasks.register('probe') {
517 tasks.register('probe') {
518 dependsOn configurations.compileView
518 dependsOn configurations.compileView
519 dependsOn ':producer:checkNoManagedAssembly'
519 dependsOn ':producer:checkNoManagedAssembly'
520
520
521 doLast {
521 doLast {
522 def files = configurations.compileView.files
522 def files = configurations.compileView.files
523 println('resolvedFiles=' + files.collect { it.name }.sort().join(','))
523 println('resolvedFiles=' + files.collect { it.name }.sort().join(','))
524 println('metadata=' + files.iterator().next().text.trim())
524 println('metadata=' + files.iterator().next().text.trim())
525 }
525 }
526 }
526 }
527 }
527 }
528 """);
528 """);
529
529
530 BuildResult result = runner(":consumer:probe").build();
530 BuildResult result = runner(":consumer:probe").build();
531
531
532 assertTrue(result.getOutput().contains("producerAssemblyTasks="));
532 assertTrue(result.getOutput().contains("producerAssemblyTasks="));
533 assertTrue(result.getOutput().contains("resolvedFiles=package.json"));
533 assertTrue(result.getOutput().contains("resolvedFiles=package.json"));
534 assertTrue(result.getOutput().contains("metadata={\"name\":\"demo\"}"));
534 assertTrue(result.getOutput().contains("metadata={\"name\":\"demo\"}"));
535 assertTrue(result.task(":producer:writePackageMetadata").getOutcome() == TaskOutcome.SUCCESS);
535 assertTrue(result.task(":producer:writePackageMetadata").getOutcome() == TaskOutcome.SUCCESS);
536 assertTrue(result.task(":consumer:probe").getOutcome() == TaskOutcome.SUCCESS);
536 assertTrue(result.task(":consumer:probe").getOutcome() == TaskOutcome.SUCCESS);
537 }
537 }
538
538
539 @Test
539 @Test
540 void failsWhenTaskProducedArtifactIsMixedWithContributionAssembly() throws Exception {
540 void failsWhenTaskProducedArtifactIsMixedWithContributionAssembly() throws Exception {
541 writeSettings("variant-artifacts-mixed-assembly-mode");
541 writeSettings("variant-artifacts-mixed-assembly-mode");
542 writeFile("inputs/marker.txt", "marker\n");
542 writeFile("inputs/marker.txt", "marker\n");
543 writeBuildFile("""
543 writeBuildFile("""
544 import org.gradle.api.DefaultTask
544 import org.gradle.api.DefaultTask
545 import org.gradle.api.file.RegularFileProperty
545 import org.gradle.api.file.RegularFileProperty
546 import org.gradle.api.tasks.OutputFile
546 import org.gradle.api.tasks.OutputFile
547 import org.gradle.api.tasks.TaskAction
547 import org.gradle.api.tasks.TaskAction
548
548
549 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
549 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
550
550
551 abstract class WritePackageMetadata extends DefaultTask {
551 abstract class WritePackageMetadata extends DefaultTask {
552 @OutputFile
552 @OutputFile
553 abstract RegularFileProperty getOutputFile()
553 abstract RegularFileProperty getOutputFile()
554
554
555 @TaskAction
555 @TaskAction
556 void write() {
556 void write() {
557 outputFile.get().asFile.text = '{}\\n'
557 outputFile.get().asFile.text = '{}\\n'
558 }
558 }
559 }
559 }
560
560
561 variants.layers.create('main')
561 variants.layers.create('main')
562 variants.roles.create('main')
562 variants.roles.create('main')
563 variants.variant('browser') {
563 variants.variant('browser') {
564 role('main') {
564 role('main') {
565 layers('main')
565 layers('main')
566 }
566 }
567 }
567 }
568
568
569 def writePackageMetadata = tasks.register('writePackageMetadata', WritePackageMetadata) {
569 def writePackageMetadata = tasks.register('writePackageMetadata', WritePackageMetadata) {
570 outputFile.set(layout.buildDirectory.file('generated/package.json'))
570 outputFile.set(layout.buildDirectory.file('generated/package.json'))
571 }
571 }
572
572
573 variantArtifacts {
573 variantArtifacts {
574 variant('browser') {
574 variant('browser') {
575 primarySlot('packageMetadata') {
575 primarySlot('packageMetadata') {
576 producedBy(writePackageMetadata) {
576 producedBy(writePackageMetadata) {
577 outputFile
577 outputFile
578 }
578 }
579 from(layout.projectDirectory.file('inputs/marker.txt'))
579 from(layout.projectDirectory.file('inputs/marker.txt'))
580 }
580 }
581 }
581 }
582 }
582 }
583 """);
583 """);
584
584
585 assertBuildFails("cannot mix task-produced artifact and contribution-based assembly", "help");
585 assertBuildFails("cannot mix task-produced artifact and contribution-based assembly", "help");
586 }
586 }
587
587
588 @Test
588 @Test
589 void combinesDirectAndTopologyAwareSlotInputs() throws Exception {
589 void combinesDirectAndTopologyAwareSlotInputs() throws Exception {
590 writeSettings("variant-artifacts-combined-inputs");
590 writeSettings("variant-artifacts-combined-inputs");
591 writeFile("inputs/base.js", "console.log('base')\n");
591 writeFile("inputs/base.js", "console.log('base')\n");
592 writeFile("inputs/marker.txt", "marker\n");
592 writeFile("inputs/marker.txt", "marker\n");
593 writeBuildFile("""
593 writeBuildFile("""
594 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
594 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
595
595
596 variants.layers.create('main')
596 variants.layers.create('main')
597 variants.roles.create('main')
597 variants.roles.create('main')
598 variants.variant('browser') {
598 variants.variant('browser') {
599 role('main') {
599 role('main') {
600 layers('main')
600 layers('main')
601 }
601 }
602 }
602 }
603
603
604 variantSources.layer('main') {
604 variantSources.layer('main') {
605 sourceSet {
605 sourceSet {
606 declareOutputs('js')
606 declareOutputs('js')
607 registerOutput('js', layout.projectDirectory.file('inputs/base.js'))
607 registerOutput('js', layout.projectDirectory.file('inputs/base.js'))
608 }
608 }
609 }
609 }
610
610
611 variantArtifacts {
611 variantArtifacts {
612 variant('browser') {
612 variant('browser') {
613 primarySlot('bundle') {
613 primarySlot('bundle') {
614 fromVariant {
614 fromVariant {
615 output('js')
615 output('js')
616 }
616 }
617 from(layout.projectDirectory.file('inputs/marker.txt'))
617 from(layout.projectDirectory.file('inputs/marker.txt'))
618 }
618 }
619 }
619 }
620 }
620 }
621
621
622 tasks.register('probe') {
622 tasks.register('probe') {
623 dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_bundle'
623 dependsOn 'assembleVariantArtifactSlot_v7_browser_s6_bundle'
624
624
625 doLast {
625 doLast {
626 def bundleDir = layout.buildDirectory.dir('variant-assemblies/browser/bundle').get().asFile
626 def bundleDir = layout.buildDirectory.dir('variant-assemblies/browser/bundle').get().asFile
627 assert new File(bundleDir, 'base.js').exists()
627 assert new File(bundleDir, 'base.js').exists()
628 assert new File(bundleDir, 'marker.txt').exists()
628 assert new File(bundleDir, 'marker.txt').exists()
629 }
629 }
630 }
630 }
631 """);
631 """);
632
632
633 BuildResult result = runner("probe").build();
633 BuildResult result = runner("probe").build();
634
634
635 assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS);
635 assertTrue(result.task(":probe").getOutcome() == TaskOutcome.SUCCESS);
636 }
636 }
637
637
638 @Test
638 @Test
639 void failsOnUnknownVariantReference() throws Exception {
639 void failsOnUnknownVariantReference() throws Exception {
640 writeSettings("variant-artifacts-missing-variant");
640 writeSettings("variant-artifacts-missing-variant");
641 writeBuildFile("""
641 writeBuildFile("""
642 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
642 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
643
643
644 variants.layers.create('main')
644 variants.layers.create('main')
645
645
646 variantArtifacts {
646 variantArtifacts {
647 variant('browser') {
647 variant('browser') {
648 slot('mainJs') {
648 slot('mainJs') {
649 fromVariant {
649 fromVariant {
650 output('js')
650 output('js')
651 }
651 }
652 }
652 }
653 }
653 }
654 }
654 }
655 """);
655 """);
656
656
657 assertBuildFails("isn't declared", "help");
657 assertBuildFails("isn't declared", "help");
658 }
658 }
659
659
660 @Test
660 @Test
661 void failsOnUnknownRoleReference() throws Exception {
661 void failsOnUnknownRoleReference() throws Exception {
662 writeSettings("variant-artifacts-missing-role");
662 writeSettings("variant-artifacts-missing-role");
663 writeBuildFile("""
663 writeBuildFile("""
664 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
664 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
665
665
666 variants.layers.create('main')
666 variants.layers.create('main')
667 variants.roles.create('main')
667 variants.roles.create('main')
668 variants.variant('browser') {
668 variants.variant('browser') {
669 role('main') {
669 role('main') {
670 layers('main')
670 layers('main')
671 }
671 }
672 }
672 }
673
673
674 variantArtifacts {
674 variantArtifacts {
675 variant('browser') {
675 variant('browser') {
676 slot('mainJs') {
676 slot('mainJs') {
677 fromRole('test') {
677 fromRole('test') {
678 output('js')
678 output('js')
679 }
679 }
680 }
680 }
681 }
681 }
682 }
682 }
683 """);
683 """);
684
684
685 assertBuildFails("Role projection for variant 'browser' and role 'test' not found", "help");
685 assertBuildFails("Role projection for variant 'browser' and role 'test' not found", "help");
686 }
686 }
687
687
688 @Test
688 @Test
689 void failsWhenPrimarySlotIsMissingForMultipleSlots() throws Exception {
689 void failsWhenPrimarySlotIsMissingForMultipleSlots() throws Exception {
690 writeSettings("variant-artifacts-missing-primary");
690 writeSettings("variant-artifacts-missing-primary");
691 writeBuildFile("""
691 writeBuildFile("""
692 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
692 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
693
693
694 variants.layers.create('main')
694 variants.layers.create('main')
695 variants.roles.create('main')
695 variants.roles.create('main')
696 variants.variant('browser') {
696 variants.variant('browser') {
697 role('main') {
697 role('main') {
698 layers('main')
698 layers('main')
699 }
699 }
700 }
700 }
701
701
702 variantSources.layer('main') {
702 variantSources.layer('main') {
703 sourceSet {
703 sourceSet {
704 declareOutputs('types', 'js')
704 declareOutputs('types', 'js')
705 }
705 }
706 }
706 }
707
707
708 variantArtifacts {
708 variantArtifacts {
709 variant('browser') {
709 variant('browser') {
710 slot('typesPackage') {
710 slot('typesPackage') {
711 fromVariant {
711 fromVariant {
712 output('types')
712 output('types')
713 }
713 }
714 }
714 }
715 slot('js') {
715 slot('js') {
716 fromVariant {
716 fromVariant {
717 output('js')
717 output('js')
718 }
718 }
719 }
719 }
720 }
720 }
721 }
721 }
722
722
723 tasks.register('probe') {
723 tasks.register('probe') {
724 doLast {
724 doLast {
725 variantArtifacts.whenAvailable { ctx ->
725 variantArtifacts.whenAvailable { ctx ->
726 def browser = objects.named(org.implab.gradle.variants.core.Variant, 'browser')
726 def browser = objects.named(org.implab.gradle.variants.core.Variant, 'browser')
727 ctx.findOutgoing(browser).get().primarySlot.get()
727 ctx.findOutgoing(browser).get().primarySlot.get()
728 }
728 }
729 }
729 }
730 }
730 }
731 """);
731 """);
732
732
733 assertBuildFails("Multiple slots declared for browser, please specify primary slot explicitly", "probe");
733 assertBuildFails("Multiple slots declared for browser, please specify primary slot explicitly", "probe");
734 }
734 }
735
735
736 @Test
736 @Test
737 void failsOnLayerReferenceOutsideVariantTopology() throws Exception {
737 void failsOnLayerReferenceOutsideVariantTopology() throws Exception {
738 writeSettings("variant-artifacts-layer-outside-topology");
738 writeSettings("variant-artifacts-layer-outside-topology");
739 writeBuildFile("""
739 writeBuildFile("""
740 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
740 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
741
741
742 variants.layers.create('mainBase')
742 variants.layers.create('mainBase')
743 variants.layers.create('extra')
743 variants.layers.create('extra')
744 variants.roles.create('main')
744 variants.roles.create('main')
745 variants.variant('browser') {
745 variants.variant('browser') {
746 role('main') {
746 role('main') {
747 layers('mainBase')
747 layers('mainBase')
748 }
748 }
749 }
749 }
750
750
751 variantArtifacts {
751 variantArtifacts {
752 variant('browser') {
752 variant('browser') {
753 slot('extraJs') {
753 slot('extraJs') {
754 fromLayer('extra') {
754 fromLayer('extra') {
755 output('js')
755 output('js')
756 }
756 }
757 }
757 }
758 }
758 }
759 }
759 }
760 """);
760 """);
761
761
762 assertBuildFails("Compile unit for variant 'browser' and layer 'extra' not found", "help");
762 assertBuildFails("Compile unit for variant 'browser' and layer 'extra' not found", "help");
763 }
763 }
764
764
765 @Test
765 @Test
766 void preservesPrimaryResolutionAndAllowsSecondaryArtifactSelection() throws Exception {
766 void preservesPrimaryResolutionAndAllowsSecondaryArtifactSelection() throws Exception {
767 writeFile("settings.gradle", """
767 writeFile("settings.gradle", """
768 rootProject.name = 'variant-artifacts-resolution'
768 rootProject.name = 'variant-artifacts-resolution'
769 include 'producer', 'consumer'
769 include 'producer', 'consumer'
770 """);
770 """);
771 writeFile("producer/inputs/types.d.ts", "export type Foo = string\n");
771 writeFile("producer/inputs/types.d.ts", "export type Foo = string\n");
772 writeFile("producer/inputs/index.js", "export const foo = 'bar'\n");
772 writeFile("producer/inputs/index.js", "export const foo = 'bar'\n");
773 writeBuildFile("""
773 writeBuildFile("""
774 import org.gradle.api.attributes.Attribute
774 import org.gradle.api.attributes.Attribute
775
775
776 def variantAttr = Attribute.of('test.variant', String)
776 def variantAttr = Attribute.of('test.variant', String)
777 def slotAttr = Attribute.of('test.slot', String)
777 def slotAttr = Attribute.of('test.slot', String)
778
778
779 subprojects {
779 subprojects {
780 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
780 apply plugin: org.implab.gradle.variants.VariantArtifactsPlugin
781 }
781 }
782
782
783 project(':producer') {
783 project(':producer') {
784 variants.layers.create('main')
784 variants.layers.create('main')
785 variants.roles.create('main')
785 variants.roles.create('main')
786 variants.variant('browser') {
786 variants.variant('browser') {
787 role('main') {
787 role('main') {
788 layers('main')
788 layers('main')
789 }
789 }
790 }
790 }
791
791
792 variantSources.layer('main') {
792 variantSources.layer('main') {
793 sourceSet {
793 sourceSet {
794 declareOutputs('types', 'js')
794 declareOutputs('types', 'js')
795 registerOutput('types', layout.projectDirectory.file('inputs/types.d.ts'))
795 registerOutput('types', layout.projectDirectory.file('inputs/types.d.ts'))
796 registerOutput('js', layout.projectDirectory.file('inputs/index.js'))
796 registerOutput('js', layout.projectDirectory.file('inputs/index.js'))
797 }
797 }
798 }
798 }
799
799
800 variantArtifacts {
800 variantArtifacts {
801 variant('browser') {
801 variant('browser') {
802 primarySlot('typesPackage') {
802 primarySlot('typesPackage') {
803 fromVariant {
803 fromVariant {
804 output('types')
804 output('types')
805 }
805 }
806 }
806 }
807 slot('js') {
807 slot('js') {
808 fromVariant {
808 fromVariant {
809 output('js')
809 output('js')
810 }
810 }
811 }
811 }
812 }
812 }
813
813
814 whenOutgoingConfiguration { publication ->
814 whenOutgoingConfiguration { publication ->
815 publication.configuration {
815 publication.configuration {
816 attributes.attribute(variantAttr, publication.variant.name)
816 attributes.attribute(variantAttr, publication.variant.name)
817 }
817 }
818 }
818 }
819
819
820 whenOutgoingSlot { publication ->
820 whenOutgoingSlot { publication ->
821 publication.artifactAttributes {
821 publication.artifactAttributes {
822 attribute(slotAttr, publication.artifactSlot.slot.name)
822 attribute(slotAttr, publication.artifactSlot.slot.name)
823 }
823 }
824 }
824 }
825 }
825 }
826
826
827 }
827 }
828
828
829 project(':consumer') {
829 project(':consumer') {
830 configurations {
830 configurations {
831 compileView {
831 compileView {
832 canBeResolved = true
832 canBeResolved = true
833 canBeConsumed = false
833 canBeConsumed = false
834 canBeDeclared = true
834 canBeDeclared = true
835 attributes {
835 attributes {
836 attribute(variantAttr, 'browser')
836 attribute(variantAttr, 'browser')
837 attribute(slotAttr, 'typesPackage')
837 attribute(slotAttr, 'typesPackage')
838 }
838 }
839 }
839 }
840 }
840 }
841
841
842 dependencies {
842 dependencies {
843 compileView project(':producer')
843 compileView project(':producer')
844 }
844 }
845
845
846 tasks.register('probe') {
846 tasks.register('probe') {
847 doLast {
847 doLast {
848 def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',')
848 def compileFiles = configurations.compileView.files.collect { it.name }.sort().join(',')
849 def jsFiles = configurations.compileView.incoming.artifactView {
849 def jsFiles = configurations.compileView.incoming.artifactView {
850 attributes {
850 attributes {
851 attribute(slotAttr, 'js')
851 attribute(slotAttr, 'js')
852 }
852 }
853 }.files.files.collect { it.name }.sort().join(',')
853 }.files.files.collect { it.name }.sort().join(',')
854
854
855 println('compileFiles=' + compileFiles)
855 println('compileFiles=' + compileFiles)
856 println('jsFiles=' + jsFiles)
856 println('jsFiles=' + jsFiles)
857 }
857 }
858 }
858 }
859 }
859 }
860 """);
860 """);
861
861
862 BuildResult result = runner(":consumer:probe").build();
862 BuildResult result = runner(":consumer:probe").build();
863
863
864 assertTrue(result.getOutput().contains("compileFiles=typesPackage"));
864 assertTrue(result.getOutput().contains("compileFiles=typesPackage"));
865 assertTrue(result.getOutput().contains("jsFiles=js"));
865 assertTrue(result.getOutput().contains("jsFiles=js"));
866 }
866 }
867 }
867 }
General Comments 0
You need to be logged in to leave comments. Login now