mirror of
https://github.com/gradle/gradle-build-action.git
synced 2025-10-19 22:38:58 +08:00
Compare commits
378 Commits
v2.2.0-rc.
...
v2.5.0
Author | SHA1 | Date | |
---|---|---|---|
|
8e02c8272a | ||
|
f63cb02cfc | ||
|
198484d871 | ||
|
fce96e0d6a | ||
|
75a86cfe02 | ||
|
be413309fa | ||
|
1b2daf5833 | ||
|
4388b1f9e5 | ||
|
07023d3e3e | ||
|
c94d573317 | ||
|
680037c65b | ||
|
2bf6bc3646 | ||
|
631021bf98 | ||
|
d1c4012c0d | ||
|
c097126a28 | ||
|
b4a540a61f | ||
|
c9a87440e3 | ||
|
d23c38fad3 | ||
|
a810b86311 | ||
|
7e48093f71 | ||
|
12681a2972 | ||
|
a8aa75965b | ||
|
a580d9bd57 | ||
|
a13870c94e | ||
|
55d241b8a2 | ||
|
9cf99034d2 | ||
|
6778644d75 | ||
|
749f47bda3 | ||
|
eb126d771e | ||
|
5056fa9d50 | ||
|
8a0051ffb2 | ||
|
4f87177da0 | ||
|
ff62946998 | ||
|
2eddd207d6 | ||
|
887e0bda35 | ||
|
dac0b87334 | ||
|
a8f0f0d523 | ||
|
951bc8ab16 | ||
|
c0e9e4809f | ||
|
c5df77b4dd | ||
|
f04973c111 | ||
|
2287707267 | ||
|
530c579a03 | ||
|
f65e80839b | ||
|
fed795f38c | ||
|
a63ae37710 | ||
|
6095a76664 | ||
|
96015f1e52 | ||
|
4a570433d8 | ||
|
601a5d4aa4 | ||
|
6df3b5baf5 | ||
|
96374ed57d | ||
|
59d37bdb61 | ||
|
5abf330283 | ||
|
86ee4f1f60 | ||
|
e0391a3985 | ||
|
09af07ef76 | ||
|
b47aad4750 | ||
|
758ee5a303 | ||
|
50f436c485 | ||
|
32863c1a40 | ||
|
b744d1079a | ||
|
bff802913e | ||
|
cacfec068e | ||
|
935e8941dd | ||
|
cfc50b189a | ||
|
7e68f96bb3 | ||
|
e444647395 | ||
|
970a1475f1 | ||
|
d9106fb21d | ||
|
6f59210bbe | ||
|
a8cfaf666b | ||
|
c82ad7fca4 | ||
|
e70e4c5e6b | ||
|
2bc6cca4b8 | ||
|
38bf8d67e6 | ||
|
1c56ebc005 | ||
|
7b3886699e | ||
|
c7ca785b85 | ||
|
dbca794d9a | ||
|
cbd0ff0688 | ||
|
1e6c29c1af | ||
|
d518883ba8 | ||
|
b3d342ca6a | ||
|
f7e0e454da | ||
|
60499ea6fd | ||
|
e4ca0fdab0 | ||
|
9adc0d5566 | ||
|
b1d3b7d6a0 | ||
|
43879ebea6 | ||
|
a64e4c087d | ||
|
3952b17b6f | ||
|
cb48b1f38e | ||
|
68ef9a8880 | ||
|
980f056e16 | ||
|
57f5c44cc6 | ||
|
e34d59c741 | ||
|
3d966761cf | ||
|
1b220aef6b | ||
|
a40cc892c0 | ||
|
7a088f07a3 | ||
|
ce77f6daf4 | ||
|
ba25077191 | ||
|
ea2e601207 | ||
|
4ebaed58ba | ||
|
9884d8f3dc | ||
|
2e30e4cc65 | ||
|
2fcb85ffb5 | ||
|
617a29d5b5 | ||
|
0ea8b0085d | ||
|
084bf86b45 | ||
|
a1c0141aa8 | ||
|
19307c73ca | ||
|
12054785f0 | ||
|
5d67aff3ea | ||
|
c2abdfc02b | ||
|
4d24cb28d8 | ||
|
9db683d515 | ||
|
45abe419bb | ||
|
d9799478b8 | ||
|
579b14502b | ||
|
a0cffe83e1 | ||
|
add2af0efd | ||
|
1fcc75d614 | ||
|
5df685c7b2 | ||
|
ee7cbb6fb4 | ||
|
1d2e9eb287 | ||
|
2df8f7bc66 | ||
|
3fbe033aaa | ||
|
0842a550d1 | ||
|
3b959539de | ||
|
c267ad1fcb | ||
|
fab7664a6a | ||
|
a5b34e05de | ||
|
a4b5212a9d | ||
|
ad59e53998 | ||
|
c224a16628 | ||
|
ec783957f3 | ||
|
6b08b7d2b5 | ||
|
fd32ae9081 | ||
|
8545e5aed7 | ||
|
d92395703c | ||
|
af916fa394 | ||
|
3d9f1fdd28 | ||
|
387c8bc97a | ||
|
31c4390f56 | ||
|
05b706c1e7 | ||
|
b9a8697f71 | ||
|
394498f89f | ||
|
c295a4096e | ||
|
74a56b60ce | ||
|
aeb3e0fcd7 | ||
|
8a17724c3e | ||
|
76ed799d26 | ||
|
dd8493d4f2 | ||
|
66061a0409 | ||
|
1a66a38284 | ||
|
bf471096d3 | ||
|
e8a7e1402f | ||
|
0e3ce37aac | ||
|
8d2472536e | ||
|
832889a6eb | ||
|
61f7cb1f75 | ||
|
e440eaf750 | ||
|
570f67893a | ||
|
402732a560 | ||
|
a6f860c57c | ||
|
657d21ac23 | ||
|
688380a438 | ||
|
cce16c4e36 | ||
|
b50380a07d | ||
|
aa2854e6ea | ||
|
471bcda20a | ||
|
91306f47ea | ||
|
65c865a172 | ||
|
1761dcff13 | ||
|
356abb47e7 | ||
|
fc9e8feb61 | ||
|
0e4b100458 | ||
|
82bc72e1e7 | ||
|
8be955ee80 | ||
|
531cc21aeb | ||
|
164712adb1 | ||
|
535b494721 | ||
|
d6110ecac2 | ||
|
cc60593845 | ||
|
fb549a8417 | ||
|
c64fe31590 | ||
|
6e56b59601 | ||
|
c77676cc69 | ||
|
f39ea084f9 | ||
|
27a2f232f6 | ||
|
b4c3d51488 | ||
|
99ec710825 | ||
|
d427a379a8 | ||
|
ed5f3e6998 | ||
|
11c5fa73ac | ||
|
3e3c80e9b4 | ||
|
25ec178747 | ||
|
3cc0a8f6bb | ||
|
915123c493 | ||
|
ef638c00fd | ||
|
05257c7a5f | ||
|
c1a6f51e61 | ||
|
865815e1b6 | ||
|
eb22e65b5b | ||
|
8a386f6915 | ||
|
84bc83e639 | ||
|
cd579d970f | ||
|
f0ec7fb780 | ||
|
bf2a15ee94 | ||
|
c85b5e1be7 | ||
|
330980897f | ||
|
9411346324 | ||
|
8f9b7c7d7f | ||
|
8df5664474 | ||
|
25e9b4d3f6 | ||
|
b49446f8e1 | ||
|
cbebff71e9 | ||
|
e4e8267f88 | ||
|
1e61c9a322 | ||
|
1a981dbaeb | ||
|
58e9059de1 | ||
|
a62a2e6297 | ||
|
daa635c20c | ||
|
9ee08ff30d | ||
|
f4ef189a47 | ||
|
8e9c25766c | ||
|
8ca744f938 | ||
|
f1b090783c | ||
|
8624823510 | ||
|
203397ae27 | ||
|
2aee3e724e | ||
|
a1707fcc88 | ||
|
b173558d72 | ||
|
d1ddcc2b6a | ||
|
1f2d557283 | ||
|
544b84f77b | ||
|
23d17c1372 | ||
|
ba3953a01d | ||
|
02e50e0dcd | ||
|
cd48d2d9f1 | ||
|
a81a96bcb6 | ||
|
7a5430f22f | ||
|
6b46ca579b | ||
|
933706c9f3 | ||
|
f524932f69 | ||
|
115127d4c2 | ||
|
115f70f942 | ||
|
1c23b66302 | ||
|
7a714ca5cb | ||
|
f559e1b425 | ||
|
5c38a9cbe9 | ||
|
ede6deb03b | ||
|
e3c7fbbbf0 | ||
|
a5bedc5d4f | ||
|
97590ddc37 | ||
|
41839de420 | ||
|
ad8dc7ef6a | ||
|
35da154adf | ||
|
3e0e3a6dea | ||
|
25d3ae13f9 | ||
|
5db8d22748 | ||
|
86acd2a1fd | ||
|
3f1275846c | ||
|
ef1e109eb6 | ||
|
5c54c52839 | ||
|
89ea1bd733 | ||
|
444dfef7d6 | ||
|
957e1cc621 | ||
|
731c4e9bf4 | ||
|
6700f3a162 | ||
|
1691ab51b6 | ||
|
27f9f12663 | ||
|
474cf85207 | ||
|
37c9711406 | ||
|
cd3cedc781 | ||
|
e54bfe60d4 | ||
|
d70ff19b06 | ||
|
45417006b1 | ||
|
925e60d017 | ||
|
47a028a7f5 | ||
|
7df347a3ca | ||
|
d742f2f6db | ||
|
e4c0d1d512 | ||
|
64a1064eca | ||
|
bc57473979 | ||
|
11ea84dec5 | ||
|
5a614fb332 | ||
|
d3a8ea948b | ||
|
fba23f26a1 | ||
|
683f9d4247 | ||
|
f87d5a33c9 | ||
|
42014fb4fa | ||
|
2da06d5689 | ||
|
792a93a5e3 | ||
|
86da5e6c4e | ||
|
6daf446e27 | ||
|
8a8f74b15c | ||
|
15453523bd | ||
|
b1b0eab63d | ||
|
f580ce7b99 | ||
|
2a7ffc9c95 | ||
|
ff6b0e0388 | ||
|
71e1e1b52b | ||
|
02b67b8bfe | ||
|
5ce69a34b6 | ||
|
e7f3e4d839 | ||
|
7645d3e274 | ||
|
be13141ec7 | ||
|
db33711f5a | ||
|
84dee23dd9 | ||
|
a603ab7405 | ||
|
bc41b8f654 | ||
|
32923891b5 | ||
|
fecf3693b5 | ||
|
6965e8ed4c | ||
|
884bca012f | ||
|
7f46dbd76f | ||
|
ea4554d4d2 | ||
|
d8b58e3519 | ||
|
4cb86e9712 | ||
|
eaed5520c4 | ||
|
ec939a8c10 | ||
|
6594e9d359 | ||
|
52e6e7d89f | ||
|
2bf1894aa3 | ||
|
795895fc71 | ||
|
98376690f1 | ||
|
67421db6bd | ||
|
ce3874fec9 | ||
|
67f42d16a1 | ||
|
56036f8577 | ||
|
1903bd4674 | ||
|
df4c1902a6 | ||
|
132237ba05 | ||
|
2335d51128 | ||
|
2f7e5c0d4b | ||
|
2248b3f239 | ||
|
7d8a9a65e5 | ||
|
bc39e4abaa | ||
|
26cd1c9794 | ||
|
5ccc7fa6a6 | ||
|
badf18c0a6 | ||
|
1ee84620f9 | ||
|
f1c1269910 | ||
|
c09f41c4bd | ||
|
829c7a236d | ||
|
c1ed8b1925 | ||
|
3d091fa7a8 | ||
|
a8d44c9749 | ||
|
6125b490f2 | ||
|
f75a77b009 | ||
|
3510b43886 | ||
|
61ba2ad220 | ||
|
4b449e5b54 | ||
|
b8f0ecc408 | ||
|
c2bd86551b | ||
|
92087b6bb6 | ||
|
9355458b6c | ||
|
4ec1021d58 | ||
|
f3e4903860 | ||
|
c5d80a628f | ||
|
ee54c1fd71 | ||
|
f33d84950e | ||
|
d20c5c0356 | ||
|
c207cf448f | ||
|
a534572737 | ||
|
acf6027bd2 | ||
|
f6ab09b0bf | ||
|
55ddd21594 | ||
|
33ed11e54c | ||
|
93c31ca3b5 | ||
|
7a15005377 | ||
|
e88ed3e650 | ||
|
de51428ba5 | ||
|
8096e65e0a | ||
|
9cd70b5460 |
@@ -28,8 +28,8 @@
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-inferrable-types": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-useless-constructor": "error",
|
||||
|
2
.github/actions/build-dist/action.yml
vendored
2
.github/actions/build-dist/action.yml
vendored
@@ -7,7 +7,7 @@ runs:
|
||||
shell: bash
|
||||
run: |
|
||||
npm install
|
||||
npm run all
|
||||
npm run build
|
||||
- name: Upload distribution
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
13
.github/dependabot.yml
vendored
13
.github/dependabot.yml
vendored
@@ -6,11 +6,14 @@ registries:
|
||||
username: dummy # Required by dependabot
|
||||
password: dummy # Required by dependabot
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 10
|
||||
interval: "weekly"
|
||||
ignore:
|
||||
- dependency-name: "@types/node"
|
||||
- package-ecosystem: "gradle"
|
||||
@@ -49,3 +52,9 @@ updates:
|
||||
- gradle-plugin-portal
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "gradle"
|
||||
directory: "test/init-scripts"
|
||||
registries:
|
||||
- gradle-plugin-portal
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
25
.github/workflow-samples/gradle-plugin/gradlew
vendored
25
.github/workflow-samples/gradle-plugin/gradlew
vendored
@@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -80,13 +80,10 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# 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"'
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -143,12 +140,16 @@ fi
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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
|
||||
@@ -205,6 +210,12 @@ set -- \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,8 @@
|
||||
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%
|
||||
|
||||
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
@@ -29,7 +29,7 @@ testing {
|
||||
functionalTest(JvmTestSuite) {
|
||||
dependencies {
|
||||
// functionalTest test suite depends on the production code in tests
|
||||
implementation project
|
||||
implementation(project(':plugin'))
|
||||
}
|
||||
|
||||
targets {
|
||||
|
@@ -11,8 +11,8 @@ dependencies {
|
||||
}
|
||||
|
||||
tasks.named("test").configure {
|
||||
// Echo an output value so we can detect configuration-cache usage
|
||||
println "::set-output name=task_configured::yes"
|
||||
// Write marker file so we can detect if task was configured
|
||||
file("task-configured.txt").text = "true"
|
||||
|
||||
doLast {
|
||||
if (System.properties.verifyCachedBuild) {
|
||||
|
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
25
.github/workflow-samples/groovy-dsl/gradlew
vendored
25
.github/workflow-samples/groovy-dsl/gradlew
vendored
@@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -80,13 +80,10 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# 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"'
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -143,12 +140,16 @@ fi
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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
|
||||
@@ -205,6 +210,12 @@ set -- \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
15
.github/workflow-samples/groovy-dsl/gradlew.bat
vendored
15
.github/workflow-samples/groovy-dsl/gradlew.bat
vendored
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,8 @@
|
||||
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%
|
||||
|
||||
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
@@ -1,5 +1,6 @@
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.10.1"
|
||||
id "com.gradle.enterprise" version "3.13.4"
|
||||
id "com.gradle.common-custom-user-data-gradle-plugin" version "1.11"
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
|
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
25
.github/workflow-samples/java-toolchain/gradlew
vendored
25
.github/workflow-samples/java-toolchain/gradlew
vendored
@@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -80,13 +80,10 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# 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"'
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -143,12 +140,16 @@ fi
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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
|
||||
@@ -205,6 +210,12 @@ set -- \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,8 @@
|
||||
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%
|
||||
|
||||
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
@@ -1 +1,5 @@
|
||||
plugins {
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version("0.4.0")
|
||||
}
|
||||
|
||||
rootProject.name = 'basic'
|
||||
|
@@ -8,9 +8,9 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
api("org.apache.commons:commons-math3:3.6.1")
|
||||
implementation("com.google.guava:guava:31.1-jre")
|
||||
implementation("com.google.guava:guava:32.0.1-jre")
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.9.3")
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
@@ -18,8 +18,8 @@ tasks.test {
|
||||
}
|
||||
|
||||
tasks.named("test").configure {
|
||||
// Echo an output value so we can detect configuration-cache usage
|
||||
println("::set-output name=task_configured::yes")
|
||||
// Write marker file so we can detect if task was configured
|
||||
file("task-configured.txt").writeText("true")
|
||||
|
||||
doLast {
|
||||
if (System.getProperties().containsKey("verifyCachedBuild")) {
|
||||
|
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
25
.github/workflow-samples/kotlin-dsl/gradlew
vendored
25
.github/workflow-samples/kotlin-dsl/gradlew
vendored
@@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -80,13 +80,10 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# 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"'
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -143,12 +140,16 @@ fi
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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
|
||||
@@ -205,6 +210,12 @@ set -- \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
15
.github/workflow-samples/kotlin-dsl/gradlew.bat
vendored
15
.github/workflow-samples/kotlin-dsl/gradlew.bat
vendored
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,8 @@
|
||||
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%
|
||||
|
||||
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
@@ -1,5 +1,6 @@
|
||||
plugins {
|
||||
id("com.gradle.enterprise") version "3.10.1"
|
||||
id("com.gradle.enterprise") version "3.13.4"
|
||||
id("com.gradle.common-custom-user-data-gradle-plugin") version "1.11"
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id "com.gradle.build-scan" version "3.10.1"
|
||||
id "com.gradle.build-scan" version "3.13.4"
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.10.1"
|
||||
id "com.gradle.enterprise" version "3.13.4"
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
|
20
.github/workflows/ci-dependency-review.yml
vendored
Normal file
20
.github/workflows/ci-dependency-review.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# Dependency Review Action
|
||||
#
|
||||
# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging.
|
||||
#
|
||||
# Source repository: https://github.com/actions/dependency-review-action
|
||||
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
|
||||
name: CI-dependency-review
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@v3
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@v3
|
16
.github/workflows/ci-full-check.yml
vendored
16
.github/workflows/ci-full-check.yml
vendored
@@ -1,6 +1,7 @@
|
||||
name: CI-full-check
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
types:
|
||||
- assigned
|
||||
@@ -9,7 +10,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '.github/workflows/**'
|
||||
- '.github/**'
|
||||
- 'dist/**'
|
||||
|
||||
jobs:
|
||||
@@ -18,6 +19,11 @@ jobs:
|
||||
with:
|
||||
cache-key-prefix: ${{github.run_number}}-
|
||||
|
||||
cache-cleanup:
|
||||
uses: ./.github/workflows/integ-test-cache-cleanup.yml
|
||||
with:
|
||||
cache-key-prefix: ${{github.run_number}}-
|
||||
|
||||
caching-config:
|
||||
uses: ./.github/workflows/integ-test-action-inputs-caching.yml
|
||||
with:
|
||||
@@ -38,10 +44,10 @@ jobs:
|
||||
with:
|
||||
cache-key-prefix: ${{github.run_number}}-
|
||||
|
||||
restore-configuration-cache:
|
||||
uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
|
||||
with:
|
||||
cache-key-prefix: ${{github.run_number}}-
|
||||
# restore-configuration-cache:
|
||||
# uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
|
||||
# with:
|
||||
# cache-key-prefix: ${{github.run_number}}-
|
||||
|
||||
restore-custom-gradle-home:
|
||||
uses: ./.github/workflows/integ-test-restore-custom-gradle-home.yml
|
||||
|
9
.github/workflows/ci-init-script-check.yml
vendored
9
.github/workflows/ci-init-script-check.yml
vendored
@@ -2,6 +2,11 @@ name: CI-init-script-check
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/ci-init-script-check.yml'
|
||||
- 'src/resources/init-scripts/**'
|
||||
- 'test/init-scripts/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test-init-scripts:
|
||||
@@ -15,7 +20,7 @@ jobs:
|
||||
distribution: temurin
|
||||
java-version: 8
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2 # Use a released version to avoid breakages
|
||||
uses: gradle/gradle-build-action@v2.4.2 # Use a released version to avoid breakages
|
||||
- name: Run integration tests
|
||||
working-directory: test/test-init-scripts
|
||||
working-directory: test/init-scripts
|
||||
run: ./gradlew check
|
||||
|
35
.github/workflows/ci-quick-check.yml
vendored
35
.github/workflows/ci-quick-check.yml
vendored
@@ -1,6 +1,7 @@
|
||||
name: CI-quick-check
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches-ignore: main
|
||||
|
||||
@@ -13,6 +14,20 @@ jobs:
|
||||
- name: Build and upload distribution
|
||||
uses: ./.github/actions/build-dist
|
||||
|
||||
run-unit-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Configure Gradle as default for unit test
|
||||
uses: ./
|
||||
with:
|
||||
gradle-version: 8.1.1
|
||||
- name: Run tests
|
||||
run: |
|
||||
npm install
|
||||
npm run all
|
||||
|
||||
action-inputs:
|
||||
needs: build-distribution
|
||||
uses: ./.github/workflows/integ-test-action-inputs.yml
|
||||
@@ -20,6 +35,14 @@ jobs:
|
||||
runner-os: '["ubuntu-latest"]'
|
||||
download-dist: true
|
||||
|
||||
cache-cleanup:
|
||||
needs: build-distribution
|
||||
uses: ./.github/workflows/integ-test-cache-cleanup.yml
|
||||
with:
|
||||
runner-os: '["ubuntu-latest"]'
|
||||
download-dist: true
|
||||
cache-key-prefix: ${{github.run_number}}- # Requires a fresh cache entry each run
|
||||
|
||||
caching-config:
|
||||
needs: build-distribution
|
||||
uses: ./.github/workflows/integ-test-action-inputs-caching.yml
|
||||
@@ -48,12 +71,12 @@ jobs:
|
||||
runner-os: '["ubuntu-latest"]'
|
||||
download-dist: true
|
||||
|
||||
restore-configuration-cache:
|
||||
needs: build-distribution
|
||||
uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
|
||||
with:
|
||||
runner-os: '["ubuntu-latest"]'
|
||||
download-dist: true
|
||||
# restore-configuration-cache:
|
||||
# needs: build-distribution
|
||||
# uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
|
||||
# with:
|
||||
# runner-os: '["ubuntu-latest"]'
|
||||
# download-dist: true
|
||||
|
||||
restore-containerized-gradle-home:
|
||||
needs: build-distribution
|
||||
|
8
.github/workflows/ci-verify-outputs.yml
vendored
8
.github/workflows/ci-verify-outputs.yml
vendored
@@ -8,9 +8,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '.github/workflows/**'
|
||||
- 'dist/**'
|
||||
- dependabot/**
|
||||
|
||||
jobs:
|
||||
check:
|
||||
@@ -20,8 +18,10 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Build
|
||||
run: |
|
||||
npm -v
|
||||
node -v
|
||||
npm install
|
||||
npm run all
|
||||
npm run build
|
||||
|
||||
- name: Compare the expected and actual dist/ directories
|
||||
run: |
|
||||
|
5
.github/workflows/demo-job-summary.yml
vendored
5
.github/workflows/demo-job-summary.yml
vendored
@@ -25,7 +25,10 @@ jobs:
|
||||
run: ./gradlew assemble
|
||||
- name: Build kotlin-dsl project without build scan
|
||||
working-directory: .github/workflow-samples/kotlin-dsl
|
||||
run: ./gradlew check --no-scan
|
||||
run: ./gradlew assemble check --no-scan
|
||||
- name: Build kotlin-dsl project with build scan publish failure
|
||||
working-directory: .github/workflow-samples/kotlin-dsl
|
||||
run: ./gradlew check -Dgradle.enterprise.url=https://not.valid.server
|
||||
- name: Build groovy-dsl project
|
||||
working-directory: .github/workflow-samples/groovy-dsl
|
||||
run: ./gradlew assemble
|
||||
|
87
.github/workflows/integ-test-cache-cleanup.yml
vendored
Normal file
87
.github/workflows/integ-test-cache-cleanup.yml
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
name: Test cache cleanup
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
cache-key-prefix:
|
||||
type: string
|
||||
runner-os:
|
||||
type: string
|
||||
default: '["ubuntu-latest", "windows-latest", "macos-latest"]'
|
||||
download-dist:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
env:
|
||||
DOWNLOAD_DIST: ${{ inputs.download-dist }}
|
||||
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: integ-test-cache-cleanup-${{ inputs.cache-key-prefix }}
|
||||
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||
|
||||
jobs:
|
||||
full-build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: ${{fromJSON(inputs.runner-os)}}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Download distribution if required
|
||||
uses: ./.github/actions/download-dist
|
||||
- name: Setup Gradle
|
||||
uses: ./
|
||||
with:
|
||||
cache-read-only: false # For testing, allow writing cache entries on non-default branches
|
||||
- name: Build with 3.1
|
||||
working-directory: test/jest/resources/cache-cleanup
|
||||
run: gradle --no-daemon --build-cache -Dcommons_math3_version="3.1" build
|
||||
|
||||
# Second build will use the cache from the first build, but cleanup should remove unused artifacts
|
||||
assemble-build:
|
||||
needs: full-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: ${{fromJSON(inputs.runner-os)}}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Download distribution if required
|
||||
uses: ./.github/actions/download-dist
|
||||
- name: Setup Gradle
|
||||
uses: ./
|
||||
with:
|
||||
cache-read-only: false
|
||||
gradle-home-cache-cleanup: true
|
||||
- name: Build with 3.1.1
|
||||
working-directory: test/jest/resources/cache-cleanup
|
||||
run: gradle --no-daemon --build-cache -Dcommons_math3_version="3.1.1" build
|
||||
|
||||
check-clean-cache:
|
||||
needs: assemble-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: ${{fromJSON(inputs.runner-os)}}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Download distribution if required
|
||||
uses: ./.github/actions/download-dist
|
||||
- name: Setup Gradle
|
||||
uses: ./
|
||||
with:
|
||||
cache-read-only: true
|
||||
- name: Report Gradle User Home
|
||||
run: du -hc ~/.gradle/caches/modules-2
|
||||
- name: Verify cleaned cache
|
||||
shell: bash
|
||||
run: |
|
||||
if [ ! -e ~/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.1.1 ]; then
|
||||
echo "::error ::Should find commons-math3 3.1.1 in cache"
|
||||
exit 1
|
||||
fi
|
||||
if [ -e ~/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.1 ]; then
|
||||
echo "::error ::Should NOT find commons-math3 3.1 in cache"
|
||||
exit 1
|
||||
fi
|
4
.github/workflows/integ-test-execution.yml
vendored
4
.github/workflows/integ-test-execution.yml
vendored
@@ -51,12 +51,12 @@ jobs:
|
||||
with:
|
||||
gradle-executable: .github/workflow-samples/groovy-dsl/gradlew${{ matrix.script-suffix }}
|
||||
build-root-directory: .github/workflow-samples/no-wrapper
|
||||
arguments: help -DgradleVersionCheck=7.4.2
|
||||
arguments: help
|
||||
|
||||
gradle-versions:
|
||||
strategy:
|
||||
matrix:
|
||||
gradle: [7.3, 6.9, 5.6.4, 4.10.3, 3.5.1]
|
||||
gradle: [7.5.1, 6.9.2, 5.6.4, 4.10.3, 3.5.1]
|
||||
os: ${{fromJSON(inputs.runner-os)}}
|
||||
include:
|
||||
- gradle: 5.6.4
|
||||
|
@@ -60,11 +60,13 @@ jobs:
|
||||
working-directory: .github/workflow-samples/groovy-dsl
|
||||
run: ./gradlew test --configuration-cache
|
||||
- name: Check that configuration-cache was used
|
||||
if: ${{ steps.execute.outputs.task_configured == 'yes' }}
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Configuration cache was not used - task was configured unexpectedly')
|
||||
const fs = require('fs')
|
||||
if (fs.existsSync('.github/workflow-samples/groovy-dsl/task-configured.txt')) {
|
||||
core.setFailed('Configuration cache was not used - task was configured unexpectedly')
|
||||
}
|
||||
|
||||
# Check that the build can run when no extracted cache entries are restored
|
||||
gradle-user-home-not-fully-restored:
|
||||
@@ -154,9 +156,11 @@ jobs:
|
||||
working-directory: .github/workflow-samples/kotlin-dsl
|
||||
run: ./gradlew test --configuration-cache
|
||||
- name: Check that configuration-cache was used
|
||||
if: ${{ steps.execute.outputs.task_configured == 'yes' }}
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Configuration cache was not used - task was configured unexpectedly')
|
||||
const fs = require('fs')
|
||||
if (fs.existsSync('.github/workflow-samples/kotlin-dsl/task-configured.txt')) {
|
||||
core.setFailed('Configuration cache was not used - task was configured unexpectedly')
|
||||
}
|
||||
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -102,5 +102,3 @@ __tests__/runner/*
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# ASDF tool configuration
|
||||
.tool-versions
|
||||
|
3
.tool-versions
Normal file
3
.tool-versions
Normal file
@@ -0,0 +1,3 @@
|
||||
# Configuration file for asdf version manager
|
||||
nodejs 16.18.1
|
||||
gradle 8.1.1
|
14
CONTRIBUTING.md
Normal file
14
CONTRIBUTING.md
Normal file
@@ -0,0 +1,14 @@
|
||||
### How to merge a Dependabot PR
|
||||
|
||||
The "distribution" for a GitHub Action is checked into the repository itself.
|
||||
In the case of the `gradle-build-action`, the transpiled sources are committed to the `dist` directory.
|
||||
Any production dependencies are inlined into the distribution.
|
||||
So if a Dependabot PR updates a production dependency (or a dev dependency that changes the distribution, like the Typescript compiler),
|
||||
then a manual step is required to rebuild the dist and commit.
|
||||
|
||||
The simplest process to follow is:
|
||||
1. Checkout the dependabot branch locally eg: `git checkout dependabot/npm_and_yarn/actions/github-5.1.0`
|
||||
2. Run `npm install` to download and the new dependencies and install locally
|
||||
3. Run `npm run build` to regenerate the distribution
|
||||
4. Push the changes to the dependabot branch
|
||||
5. If/when the checks pass, you can merge the dependabot PR
|
140
README.md
140
README.md
@@ -38,7 +38,7 @@ It is possible to directly invoke Gradle in your workflow, and the `actions/setu
|
||||
|
||||
However, the `gradle-build-action` offers a number of advantages over this approach:
|
||||
|
||||
- Easily [run the build with different versions of Gradle](#download-install-and-use-a-specific-gradle-version) using the `gradle-version` parameter. Gradle distributions are automatically downloaded and cached.
|
||||
- Easily [run the build with different versions of Gradle](#use-a-specific-gradle-version) using the `gradle-version` parameter. Gradle distributions are automatically downloaded and cached.
|
||||
- More sophisticated and more efficient caching of Gradle User Home between invocations, compared to `setup-java` and most custom configurations using `actions/cache`. [More details below](#caching).
|
||||
- Detailed reporting of cache usage and cache configuration options allow you to [optimize the use of the GitHub actions cache](#optimizing-cache-effectiveness).
|
||||
- [Automatic capture of build scan links](#build-scans) from the build, making these easier to locate for workflow run.
|
||||
@@ -85,6 +85,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
@@ -111,6 +112,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11
|
||||
|
||||
- name: Setup and execute Gradle 'test' task
|
||||
@@ -195,7 +197,6 @@ By default, this action aims to cache any and all reusable state that may be spe
|
||||
The state that is cached includes:
|
||||
- Any distributions downloaded to satisfy a `gradle-version` parameter ;
|
||||
- A subset of the Gradle User Home directory, including downloaded dependencies, wrapper distributions, and the local build cache ;
|
||||
- Any [configuration-cache](https://docs.gradle.org/nightly/userguide/configuration_cache.html) data stored in the project `.gradle` directory. (Only supported for Gradle 7 or higher.)
|
||||
|
||||
To reduce the space required for caching, this action makes a best effort to reduce duplication in cache entries.
|
||||
|
||||
@@ -203,12 +204,11 @@ Caching is enabled by default. You can disable caching for the action as follows
|
||||
```yaml
|
||||
cache-disabled: true
|
||||
```
|
||||
|
||||
### Cache keys
|
||||
|
||||
Distributions downloaded to satisfy a `gradle-version` parameter are stored outside of Gradle User Home and cached separately. The cache key is unique to the downloaded distribution and will not change over time.
|
||||
|
||||
The state of the Gradle User Home and configuration-cache are highly dependent on the Gradle execution, so the cache key is composed of the current commit hash and the GitHub actions job id.
|
||||
The state of the Gradle User Home is highly dependent on the Gradle execution, so the cache key is composed of the current commit hash and the GitHub actions job id.
|
||||
As such, the cache key is likely to change on each subsequent run of GitHub actions.
|
||||
This allows the most recent state to always be available in the GitHub actions cache.
|
||||
|
||||
@@ -218,17 +218,27 @@ For example, this means that all jobs executing a particular version of the Grad
|
||||
|
||||
### Using the caches read-only
|
||||
|
||||
In some circumstances, it makes sense for a Gradle invocation to read any existing cache entries but not to write changes back.
|
||||
For example, you may want to write cache entries for builds on your `main` branch, but not for any PR build invocations.
|
||||
By default, the `gradle-build-action` will only write to the cache from Jobs on the default (`main`/`master`) branch.
|
||||
Jobs on other branches will read entries from the cache but will not write updated entries.
|
||||
See [Optimizing cache effectiveness](#optimizing-cache-effectiveness) for a more detailed explanation.
|
||||
|
||||
You can enable read-only caching for any of the caches as follows:
|
||||
In some circumstances it makes sense to change this default, and to configure a workflow Job to read existing cache entries but not to write changes back.
|
||||
|
||||
You can configure read-only caching for the `gradle-build-action` as follows:
|
||||
|
||||
```yaml
|
||||
# Only write to the cache for builds on the 'main' branch.
|
||||
# Only write to the cache for builds on the 'main' and 'release' branches. (Default is 'main' only.)
|
||||
# Builds on other branches will only read existing entries from the cache.
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/release' }}
|
||||
```
|
||||
|
||||
### Stopping the Gradle daemon
|
||||
|
||||
By default, the action will stop all running Gradle daemons in the post-action step, prior to saving the Gradle User Home state.
|
||||
This allows for any Gradle User Home cleanup to occur, and avoid file-locking issues on Windows.
|
||||
|
||||
If caching is unavailable or the cache is in read-only mode, the daemon will not be stopped and will continue running after the job is completed.
|
||||
|
||||
### Gradle User Home cache tuning
|
||||
|
||||
As well as any wrapper distributions, the action will attempt to save and restore the `caches` and `notifications` directories from Gradle User Home.
|
||||
@@ -241,9 +251,10 @@ gradle-home-cache-includes: |
|
||||
caches
|
||||
notifications
|
||||
jdks
|
||||
# Exclude the local build-cache from the directories cached.
|
||||
# Exclude the local build-cache and keyrings from the directories cached.
|
||||
gradle-home-cache-excludes: |
|
||||
caches/build-cache-1
|
||||
caches/keyrings
|
||||
```
|
||||
|
||||
You can specify any number of fixed paths or patterns to include or exclude.
|
||||
@@ -253,7 +264,7 @@ File pattern support is documented at https://docs.github.com/en/actions/learn-g
|
||||
|
||||
Gradle User Home state will be restored from the cache during the first `gradle-build-action` step for any workflow job.
|
||||
This state will be saved back to the cache at the end of the job, after all Gradle executions have completed.
|
||||
A report of all cache entries restored and saved is printed to the action log when saving the cache entries.
|
||||
A report of all cache entries restored and saved is printed to the Job Summary when saving the cache entries.
|
||||
This report can provide valuable insignt into how much cache space is being used.
|
||||
|
||||
It is possible to enable additional debug logging for cache operations. You do via the `GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED` environment variable:
|
||||
@@ -267,18 +278,25 @@ Note that this setting will also prevent certain cache operations from running i
|
||||
|
||||
### Optimizing cache effectiveness
|
||||
|
||||
Cache storage space for GitHub actions is limited, and writing new cache entries can trigger the deletion of exising entries.
|
||||
Cache storage space for GitHub actions is limited, and writing new cache entries can trigger the deletion of existing entries.
|
||||
Eviction of shared cache entries can reduce cache effectiveness, slowing down your `gradle-build-action` steps.
|
||||
|
||||
There are a number of actions you can take if your cache use is less effective due to entry eviction.
|
||||
|
||||
#### Only write to the cache from the default branch
|
||||
#### Select branches that should write to the cache
|
||||
|
||||
GitHub cache entries are not shared between builds on different branches. This means that identical cache entries will be stored separately for different branches.
|
||||
The exception to the is cache entries for the default (`master`/`main`) branch can be read by actions invoked for other branches.
|
||||
GitHub cache entries are not shared between builds on different branches.
|
||||
This means that each PR branch will have it's own Gradle User Home cache, and will not benefit from cache entries written by other PR branches.
|
||||
An exception to this is that cache entries written in parent and upstream branches are visible to child branches, and cache entries for the default (`master`/`main`) branch can be read by actions invoked for any other branch.
|
||||
|
||||
An easy way to reduce cache usage when you run builds on many different branches is to only permit your default branch to write to the cache,
|
||||
with all other branch builds using `cache-read-only`. See [Using the caches read-only](#using-the-caches-read-only) for more details.
|
||||
By default, the `gradle-build-action` will only _write_ to the cache for builds run on the default (`master`/`main`) branch.
|
||||
Jobs run on other branches will only read from the cache. In most cases, this is the desired behaviour,
|
||||
because Jobs run against other branches will benefit from the cache Gradle User Home from `main`,
|
||||
without writing private cache entries that could lead to evicting shared entries.
|
||||
|
||||
If you have other long-lived development branches that would benefit from writing to the cache,
|
||||
you can configure these by overriding the `cache-read-only` action parameter.
|
||||
See [Using the caches read-only](#using-the-caches-read-only) for more details.
|
||||
|
||||
Similarly, you could use `cache-read-only` for certain jobs in the workflow, and instead have these jobs reuse the cache content from upstream jobs.
|
||||
|
||||
@@ -288,37 +306,43 @@ Each build is different, and some builds produce more Gradle User Home content t
|
||||
[Cache debugging ](#cache-debugging-and-analysis) can provide insight into which cache entries are the largest,
|
||||
and you can selectively [exclude content using `gradle-home-cache-exclude`](#gradle-user-home-cache-tuning).
|
||||
|
||||
## Saving build outputs
|
||||
#### Removing unused files from Gradle User Home before saving to cache
|
||||
|
||||
By default, a GitHub Actions workflow using `gradle-build-action` will record the log output and any Build Scan links for your build,
|
||||
but any output files generated by the build will not be saved.
|
||||
The Gradle User Home directory has a tendency to grow over time. When you switch to a new Gradle wrapper version or upgrade a dependency version
|
||||
the old files are not automatically and immediately removed. While this can make sense in a local environment, in a GitHub Actions environment
|
||||
it can lead to ever-larger Gradle User Home cache entries being saved and restored.
|
||||
|
||||
To save selected files from your build execution, you can use the core [Upload-Artifact](https://github.com/actions/upload-artifact) action.
|
||||
For example:
|
||||
In order to avoid this situation, the `gradle-build-action` supports the `gradle-home-cache-cleanup` parameter.
|
||||
When enabled, this feature will attempt to delete any files in the Gradle User Home that were not used by Gradle during the GitHub Actions workflow,
|
||||
prior to saving the Gradle User Home to the GitHub Actions cache.
|
||||
|
||||
Gradle Home cache cleanup is disabled by default. You can enable this feature for the action as follows:
|
||||
```yaml
|
||||
jobs:
|
||||
gradle:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout project sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
- name: Run build with Gradle wrapper
|
||||
run: ./gradlew build --scan
|
||||
- name: Upload build reports
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build-reports
|
||||
path: build/reports/
|
||||
gradle-home-cache-cleanup: true
|
||||
```
|
||||
|
||||
## Build scans
|
||||
## Build reporting
|
||||
|
||||
If your build publishes a [build scan](https://gradle.com/build-scans/) the `gradle-build-action` action will:
|
||||
- Add a notice with the link to the GitHub Actions user interface
|
||||
- For each step that executes Gradle, adds the link to the published build scan as a Step output named `build-scan-url`.
|
||||
The `gradle-build-action` collects information about any Gradle executions that occur in a workflow, and reports these via
|
||||
a Job Summary, visible in the GitHub Actions UI. For each Gradle execution, details about the invocation are listed, together with
|
||||
a link to any Build Scan® published.
|
||||
|
||||
Generation of a Job Summary is enabled by default. If this is not desired, it can be disable as follows:
|
||||
```yaml
|
||||
generate-job-summary: false
|
||||
```
|
||||
|
||||
Note that the action collects information about Gradle invocations via an [Initialization Script](https://docs.gradle.org/current/userguide/init_scripts.html#sec:using_an_init_script)
|
||||
located at `USER_HOME/.gradle/init.d/build-result-capture.init.gradle`.
|
||||
If you are using init scripts for the [Gradle Enterprise Gradle Plugin](https://plugins.gradle.org/plugin/com.gradle.enterprise) like
|
||||
[`scans-init.gradle` or `gradle-enterprise-init.gradle`](https://docs.gradle.com/enterprise/gradle-plugin/#scans_gradle_com),
|
||||
you'll need to ensure these files are applied prior to `build-result-capture.init.gradle`.
|
||||
Since Gradle applies init scripts in alphabetical order, one way to ensure this is via file naming.
|
||||
|
||||
### Build scan link as Step output
|
||||
|
||||
As well as reporting the [Build Scan](https://gradle.com/build-scans/) link in the Job Summary,
|
||||
the `gradle-build-action` action makes this link available as a Step output named `build-scan-url`.
|
||||
|
||||
You can then use that link in subsequent actions of your workflow. For example:
|
||||
|
||||
@@ -350,3 +374,37 @@ jobs:
|
||||
body: '❌ ${{ github.workflow }} failed: ${{ steps.gradle.outputs.build-scan-url }}'
|
||||
})
|
||||
```
|
||||
|
||||
### Saving build outputs
|
||||
|
||||
By default, a GitHub Actions workflow using `gradle-build-action` will record the log output and any Build Scan links for your build,
|
||||
but any output files generated by the build will not be saved.
|
||||
|
||||
To save selected files from your build execution, you can use the core [Upload-Artifact](https://github.com/actions/upload-artifact) action.
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
gradle:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout project sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
- name: Run build with Gradle wrapper
|
||||
run: ./gradlew build --scan
|
||||
- name: Upload build reports
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build-reports
|
||||
path: build/reports/
|
||||
```
|
||||
|
||||
## Support for GitHub Enterprise Server (GHES)
|
||||
|
||||
You can use the `gradle-build-action` on GitHub Enterprise Server, and benefit from the improved integration with Gradle. Depending on the version of GHES you are running, certain features may be limited:
|
||||
- Build scan links are captured and displayed in the GitHub Actions UI
|
||||
- Easily run your build with different versions of Gradle
|
||||
- Save/restore of Gradle User Home (requires GHES v3.5+ : GitHub Actions cache was introduced in GHES 3.5)
|
||||
- Support for GitHub Actions Job Summary (requires GHES 3.6+ : GitHub Actions Job Summary support was introduced in GHES 3.6). In earlier versions of GHES the build-results summary and caching report will be written to the workflow log, as part of the post-action step.
|
||||
|
@@ -1,11 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation('junit:junit:4.12')
|
||||
}
|
Binary file not shown.
@@ -1,5 +0,0 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
185
__tests__/data/crypto-utils-test/gradlew
vendored
185
__tests__/data/crypto-utils-test/gradlew
vendored
@@ -1,185 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
*
|
||||
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||
* in the user manual at https://docs.gradle.org/6.5/userguide/multi_project_builds.html
|
||||
*/
|
||||
|
||||
rootProject.name = 'basic'
|
@@ -1,10 +0,0 @@
|
||||
package basic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class BasicTest {
|
||||
@Test
|
||||
public void test() {
|
||||
assert true;
|
||||
}
|
||||
}
|
24
action.yml
24
action.yml
@@ -5,7 +5,15 @@ description: 'Configures Gradle for use in GitHub actions, caching useful state
|
||||
|
||||
inputs:
|
||||
gradle-version:
|
||||
description: Gradle version to use
|
||||
description: Gradle version to use. If specified, this Gradle version will be downloaded, added to the PATH and used for invoking Gradle.
|
||||
required: false
|
||||
|
||||
gradle-executable:
|
||||
description: Path to the Gradle executable. If specified, this executable will be added to the PATH and used for invoking Gradle.
|
||||
required: false
|
||||
|
||||
build-root-directory:
|
||||
description: Path to the root directory of the build. Default is the root of the GitHub workspace.
|
||||
required: false
|
||||
|
||||
cache-disabled:
|
||||
@@ -18,7 +26,7 @@ inputs:
|
||||
When 'true', existing entries will be read from the cache but no entries will be written.
|
||||
By default this value is 'false' for workflows on the GitHub default branch and 'true' for workflows on other branches.
|
||||
required: false
|
||||
default: ${{ github.ref_name != github.event.repository.default_branch }}
|
||||
default: ${{ github.event.repository != null && github.ref_name != github.event.repository.default_branch }}
|
||||
|
||||
cache-write-only:
|
||||
description: |
|
||||
@@ -45,14 +53,6 @@ inputs:
|
||||
description: Gradle command line arguments (supports multi-line input)
|
||||
required: false
|
||||
|
||||
build-root-directory:
|
||||
description: Path to the root directory of the build
|
||||
required: false
|
||||
|
||||
gradle-executable:
|
||||
description: Path to the Gradle executable
|
||||
required: false
|
||||
|
||||
generate-job-summary:
|
||||
description: When 'false', no Job Summary will be generated for the Job.
|
||||
required: false
|
||||
@@ -70,6 +70,10 @@ inputs:
|
||||
description: Used to uniquely identify the current job invocation. Defaults to the matrix values for this job; this should not be overridden by users (INTERNAL).
|
||||
required: false
|
||||
default: ${{ toJSON(matrix) }}
|
||||
gradle-home-cache-cleanup:
|
||||
description: When 'true', the action will attempt to remove any stale/unused entries from the Gradle User Home prior to saving to the GitHub Actions cache.
|
||||
required: false
|
||||
default: false
|
||||
|
||||
outputs:
|
||||
build-scan-url:
|
||||
|
19
actions/dependency-graph-generate/action.yml
Normal file
19
actions/dependency-graph-generate/action.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
name: "Dependency Graph Generate"
|
||||
description: Calculates the complete dependency graph for the repository, saving it as a JSON artifact.
|
||||
|
||||
inputs:
|
||||
gradle-version:
|
||||
description: Gradle version to use. If specified, this Gradle version will be downloaded, added to the PATH and used for invoking Gradle.
|
||||
required: false
|
||||
|
||||
gradle-executable:
|
||||
description: Path to the Gradle executable. If specified, this executable will be added to the PATH and used for invoking Gradle.
|
||||
required: false
|
||||
|
||||
build-root-directory:
|
||||
description: Path to the root directory of the build. Default is the root of the GitHub workspace.
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: '../../dist/dependency-graph-generate/index.js'
|
12
actions/dependency-graph-submit/action.yml
Normal file
12
actions/dependency-graph-submit/action.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
name: "Dependency Graph Submit"
|
||||
description: Retrieves a previously created dependency graph JSON and submits via the GitHub Dependency Submission API.
|
||||
|
||||
inputs:
|
||||
github-token:
|
||||
description: The GitHub token used to authenticate when submitting via the Dependency Submission API.
|
||||
default: ${{ github.token }}
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: '../../dist/dependency-graph-submit/index.js'
|
72829
dist/dependency-graph-generate/index.js
vendored
Normal file
72829
dist/dependency-graph-generate/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/dependency-graph-generate/index.js.map
vendored
Normal file
1
dist/dependency-graph-generate/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
24783
dist/dependency-graph-submit/index.js
vendored
Normal file
24783
dist/dependency-graph-submit/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/dependency-graph-submit/index.js.map
vendored
Normal file
1
dist/dependency-graph-submit/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
15571
dist/main/index.js
vendored
15571
dist/main/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/main/index.js.map
vendored
2
dist/main/index.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/main/sourcemap-register.js
vendored
1
dist/main/sourcemap-register.js
vendored
File diff suppressed because one or more lines are too long
15459
dist/post/index.js
vendored
15459
dist/post/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/post/index.js.map
vendored
2
dist/post/index.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/post/sourcemap-register.js
vendored
1
dist/post/sourcemap-register.js
vendored
File diff suppressed because one or more lines are too long
8056
package-lock.json
generated
8056
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
51
package.json
51
package.json
@@ -8,10 +8,17 @@
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"build": "ncc build src/main.ts --out dist/main --source-map && ncc build src/post.ts --out dist/post --source-map",
|
||||
|
||||
"compile-main": "ncc build src/main.ts --out dist/main --source-map --no-source-map-register",
|
||||
"compile-post": "ncc build src/post.ts --out dist/post --source-map --no-source-map-register",
|
||||
"compile-dependency-graph-generate": "ncc build src/dependency-graph-generate.ts --out dist/dependency-graph-generate --source-map --no-source-map-register",
|
||||
"compile-dependency-graph-submit": "ncc build src/dependency-graph-submit.ts --out dist/dependency-graph-submit --source-map --no-source-map-register",
|
||||
"compile": "npm run compile-main && npm run compile-post && npm run compile-dependency-graph-generate && npm run compile-dependency-graph-submit",
|
||||
|
||||
"test": "jest",
|
||||
"check": "npm run format && npm run lint",
|
||||
"all": "npm run format && npm run lint && npm run build && npm test"
|
||||
"build": "npm run check && npm run compile",
|
||||
"all": "npm run build && npm test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -25,29 +32,31 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/cache": "2.0.5",
|
||||
"@actions/core": "1.8.2",
|
||||
"@actions/artifact": "1.1.1",
|
||||
"@actions/cache": "3.2.1",
|
||||
"@actions/core": "1.10.0",
|
||||
"@actions/exec": "1.1.1",
|
||||
"@actions/github": "5.0.3",
|
||||
"@actions/glob": "0.3.0",
|
||||
"@actions/http-client": "2.0.1",
|
||||
"@actions/github": "5.1.1",
|
||||
"@actions/glob": "0.4.0",
|
||||
"@actions/http-client": "2.1.0",
|
||||
"@actions/tool-cache": "2.0.1",
|
||||
"string-argv": "0.3.1"
|
||||
"@octokit/rest": "19.0.11",
|
||||
"string-argv": "0.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "28.1.0",
|
||||
"@types/node": "16.11.21",
|
||||
"@types/unzipper": "0.10.5",
|
||||
"@typescript-eslint/parser": "5.27.0",
|
||||
"@vercel/ncc": "0.34.0",
|
||||
"eslint": "8.17.0",
|
||||
"eslint-plugin-github": "4.3.6",
|
||||
"eslint-plugin-jest": "26.4.6",
|
||||
"jest": "28.1.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"patch-package": "6.4.7",
|
||||
"prettier": "2.6.2",
|
||||
"ts-jest": "28.0.4",
|
||||
"typescript": "4.7.3"
|
||||
"@types/jest": "29.5.2",
|
||||
"@types/unzipper": "0.10.6",
|
||||
"@typescript-eslint/parser": "5.60.1",
|
||||
"@vercel/ncc": "0.36.1",
|
||||
"eslint": "8.43.0",
|
||||
"eslint-plugin-github": "4.8.0",
|
||||
"eslint-plugin-jest": "27.2.1",
|
||||
"jest": "29.5.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"patch-package": "7.0.0",
|
||||
"prettier": "2.8.8",
|
||||
"ts-jest": "29.1.0",
|
||||
"typescript": "5.1.5"
|
||||
}
|
||||
}
|
||||
|
@@ -1,90 +0,0 @@
|
||||
diff --git a/node_modules/@actions/cache/lib/cache.d.ts b/node_modules/@actions/cache/lib/cache.d.ts
|
||||
index 16b20f7..aea77ba 100644
|
||||
--- a/node_modules/@actions/cache/lib/cache.d.ts
|
||||
+++ b/node_modules/@actions/cache/lib/cache.d.ts
|
||||
@@ -20,7 +20,7 @@ export declare function isFeatureAvailable(): boolean;
|
||||
* @param downloadOptions cache download options
|
||||
* @returns string returns the key for the cache hit, otherwise returns undefined
|
||||
*/
|
||||
-export declare function restoreCache(paths: string[], primaryKey: string, restoreKeys?: string[], options?: DownloadOptions): Promise<string | undefined>;
|
||||
+export declare function restoreCache(paths: string[], primaryKey: string, restoreKeys?: string[], options?: DownloadOptions): Promise<CacheEntry | undefined>;
|
||||
/**
|
||||
* Saves a list of files with the specified key
|
||||
*
|
||||
@@ -29,4 +29,12 @@ export declare function restoreCache(paths: string[], primaryKey: string, restor
|
||||
* @param options cache upload options
|
||||
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
||||
*/
|
||||
-export declare function saveCache(paths: string[], key: string, options?: UploadOptions): Promise<number>;
|
||||
+export declare function saveCache(paths: string[], key: string, options?: UploadOptions): Promise<CacheEntry>;
|
||||
+
|
||||
+// PATCHED: Add `CacheEntry` as return type for save/restore functions
|
||||
+// This allows us to track and report on cache entry sizes.
|
||||
+export declare class CacheEntry {
|
||||
+ key: string;
|
||||
+ size?: number;
|
||||
+ constructor(key: string, size?: number);
|
||||
+}
|
||||
diff --git a/node_modules/@actions/cache/lib/cache.js b/node_modules/@actions/cache/lib/cache.js
|
||||
index 2dd645a..a392352 100644
|
||||
--- a/node_modules/@actions/cache/lib/cache.js
|
||||
+++ b/node_modules/@actions/cache/lib/cache.js
|
||||
@@ -93,6 +93,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
||||
}
|
||||
const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
||||
core.debug(`Archive Path: ${archivePath}`);
|
||||
+ const restoredEntry = new CacheEntry(cacheEntry.cacheKey);
|
||||
try {
|
||||
// Download the cache from the cache entry
|
||||
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
|
||||
@@ -100,6 +101,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
||||
yield tar_1.listTar(archivePath, compressionMethod);
|
||||
}
|
||||
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath);
|
||||
+ restoredEntry.size = archiveFileSize;
|
||||
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
|
||||
yield tar_1.extractTar(archivePath, compressionMethod);
|
||||
core.info('Cache restored successfully');
|
||||
@@ -113,7 +115,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
||||
core.debug(`Failed to delete archive: ${error}`);
|
||||
}
|
||||
}
|
||||
- return cacheEntry.cacheKey;
|
||||
+ return restoredEntry;
|
||||
});
|
||||
}
|
||||
exports.restoreCache = restoreCache;
|
||||
@@ -141,6 +143,7 @@ function saveCache(paths, key, options) {
|
||||
const archiveFolder = yield utils.createTempDirectory();
|
||||
const archivePath = path.join(archiveFolder, utils.getCacheFileName(compressionMethod));
|
||||
core.debug(`Archive Path: ${archivePath}`);
|
||||
+ const savedEntry = new CacheEntry(key);
|
||||
try {
|
||||
yield tar_1.createTar(archiveFolder, cachePaths, compressionMethod);
|
||||
if (core.isDebug()) {
|
||||
@@ -148,6 +151,7 @@ function saveCache(paths, key, options) {
|
||||
}
|
||||
const fileSizeLimit = 10 * 1024 * 1024 * 1024; // 10GB per repo limit
|
||||
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath);
|
||||
+ savedEntry.size = archiveFileSize;
|
||||
core.debug(`File Size: ${archiveFileSize}`);
|
||||
// For GHES, this check will take place in ReserveCache API with enterprise file size limit
|
||||
if (archiveFileSize > fileSizeLimit && !utils.isGhes()) {
|
||||
@@ -179,8 +183,15 @@ function saveCache(paths, key, options) {
|
||||
core.debug(`Failed to delete archive: ${error}`);
|
||||
}
|
||||
}
|
||||
- return cacheId;
|
||||
+ return savedEntry;
|
||||
});
|
||||
}
|
||||
exports.saveCache = saveCache;
|
||||
+class CacheEntry {
|
||||
+ constructor(key, size) {
|
||||
+ this.key = key;
|
||||
+ this.size = size;
|
||||
+ }
|
||||
+}
|
||||
+exports.CacheEntry = CacheEntry;
|
||||
//# sourceMappingURL=cache.js.map
|
||||
\ No newline at end of file
|
113
patches/@actions+cache+3.2.1.patch
Normal file
113
patches/@actions+cache+3.2.1.patch
Normal file
@@ -0,0 +1,113 @@
|
||||
diff --git a/node_modules/@actions/cache/lib/cache.d.ts b/node_modules/@actions/cache/lib/cache.d.ts
|
||||
index 4658366..b796e58 100644
|
||||
--- a/node_modules/@actions/cache/lib/cache.d.ts
|
||||
+++ b/node_modules/@actions/cache/lib/cache.d.ts
|
||||
@@ -21,7 +21,7 @@ export declare function isFeatureAvailable(): boolean;
|
||||
* @param enableCrossOsArchive an optional boolean enabled to restore on windows any cache created on any platform
|
||||
* @returns string returns the key for the cache hit, otherwise returns undefined
|
||||
*/
|
||||
-export declare function restoreCache(paths: string[], primaryKey: string, restoreKeys?: string[], options?: DownloadOptions, enableCrossOsArchive?: boolean): Promise<string | undefined>;
|
||||
+export declare function restoreCache(paths: string[], primaryKey: string, restoreKeys?: string[], options?: DownloadOptions, enableCrossOsArchive?: boolean): Promise<CacheEntry | undefined>;
|
||||
/**
|
||||
* Saves a list of files with the specified key
|
||||
*
|
||||
@@ -31,4 +31,12 @@ export declare function restoreCache(paths: string[], primaryKey: string, restor
|
||||
* @param options cache upload options
|
||||
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
||||
*/
|
||||
-export declare function saveCache(paths: string[], key: string, options?: UploadOptions, enableCrossOsArchive?: boolean): Promise<number>;
|
||||
+export declare function saveCache(paths: string[], key: string, options?: UploadOptions, enableCrossOsArchive?: boolean): Promise<CacheEntry>;
|
||||
+
|
||||
+// PATCHED: Add `CacheEntry` as return type for save/restore functions
|
||||
+// This allows us to track and report on cache entry sizes.
|
||||
+export declare class CacheEntry {
|
||||
+ key: string;
|
||||
+ size?: number;
|
||||
+ constructor(key: string, size?: number);
|
||||
+}
|
||||
diff --git a/node_modules/@actions/cache/lib/cache.js b/node_modules/@actions/cache/lib/cache.js
|
||||
index 9d636aa..a176bd7 100644
|
||||
--- a/node_modules/@actions/cache/lib/cache.js
|
||||
+++ b/node_modules/@actions/cache/lib/cache.js
|
||||
@@ -127,18 +127,21 @@ function restoreCache(paths, primaryKey, restoreKeys, options, enableCrossOsArch
|
||||
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
|
||||
yield (0, tar_1.extractTar)(archivePath, compressionMethod);
|
||||
core.info('Cache restored successfully');
|
||||
- return cacheEntry.cacheKey;
|
||||
- }
|
||||
- catch (error) {
|
||||
- const typedError = error;
|
||||
- if (typedError.name === ValidationError.name) {
|
||||
- throw error;
|
||||
- }
|
||||
- else {
|
||||
- // Supress all non-validation cache related errors because caching should be optional
|
||||
- core.warning(`Failed to restore: ${error.message}`);
|
||||
- }
|
||||
+
|
||||
+ // PATCHED - Return more inforamtion about restored entry
|
||||
+ return new CacheEntry(cacheEntry.cacheKey, archiveFileSize);;
|
||||
}
|
||||
+ // PATCHED - propagate errors
|
||||
+ // catch (error) {
|
||||
+ // const typedError = error;
|
||||
+ // if (typedError.name === ValidationError.name) {
|
||||
+ // throw error;
|
||||
+ // }
|
||||
+ // else {
|
||||
+ // // Supress all non-validation cache related errors because caching should be optional
|
||||
+ // core.warning(`Failed to restore: ${error.message}`);
|
||||
+ // }
|
||||
+ // }
|
||||
finally {
|
||||
// Try to delete the archive to save space
|
||||
try {
|
||||
@@ -206,19 +209,23 @@ function saveCache(paths, key, options, enableCrossOsArchive = false) {
|
||||
}
|
||||
core.debug(`Saving Cache (ID: ${cacheId})`);
|
||||
yield cacheHttpClient.saveCache(cacheId, archivePath, options);
|
||||
+
|
||||
+ // PATCHED - Return more inforamtion about saved entry
|
||||
+ return new CacheEntry(key, archiveFileSize);
|
||||
}
|
||||
- catch (error) {
|
||||
- const typedError = error;
|
||||
- if (typedError.name === ValidationError.name) {
|
||||
- throw error;
|
||||
- }
|
||||
- else if (typedError.name === ReserveCacheError.name) {
|
||||
- core.info(`Failed to save: ${typedError.message}`);
|
||||
- }
|
||||
- else {
|
||||
- core.warning(`Failed to save: ${typedError.message}`);
|
||||
- }
|
||||
- }
|
||||
+ // PATCHED - propagate errors
|
||||
+ // catch (error) {
|
||||
+ // const typedError = error;
|
||||
+ // if (typedError.name === ValidationError.name) {
|
||||
+ // throw error;
|
||||
+ // }
|
||||
+ // else if (typedError.name === ReserveCacheError.name) {
|
||||
+ // core.info(`Failed to save: ${typedError.message}`);
|
||||
+ // }
|
||||
+ // else {
|
||||
+ // core.warning(`Failed to save: ${typedError.message}`);
|
||||
+ // }
|
||||
+ // }
|
||||
finally {
|
||||
// Try to delete the archive to save space
|
||||
try {
|
||||
@@ -232,4 +239,11 @@ function saveCache(paths, key, options, enableCrossOsArchive = false) {
|
||||
});
|
||||
}
|
||||
exports.saveCache = saveCache;
|
||||
+class CacheEntry {
|
||||
+ constructor(key, size) {
|
||||
+ this.key = key;
|
||||
+ this.size = size;
|
||||
+ }
|
||||
+}
|
||||
+exports.CacheEntry = CacheEntry;
|
||||
//# sourceMappingURL=cache.js.map
|
||||
\ No newline at end of file
|
48
patches/@azure+logger+1.0.4.patch
Normal file
48
patches/@azure+logger+1.0.4.patch
Normal file
@@ -0,0 +1,48 @@
|
||||
diff --git a/node_modules/@azure/logger/dist-esm/src/debug.js b/node_modules/@azure/logger/dist-esm/src/debug.js
|
||||
index d202779..30e8313 100644
|
||||
--- a/node_modules/@azure/logger/dist-esm/src/debug.js
|
||||
+++ b/node_modules/@azure/logger/dist-esm/src/debug.js
|
||||
@@ -7,7 +7,7 @@ let enabledNamespaces = [];
|
||||
let skippedNamespaces = [];
|
||||
const debuggers = [];
|
||||
if (debugEnvVariable) {
|
||||
- enable(debugEnvVariable);
|
||||
+ // enable(debugEnvVariable);
|
||||
}
|
||||
const debugObj = Object.assign((namespace) => {
|
||||
return createDebugger(namespace);
|
||||
diff --git a/node_modules/@azure/logger/dist-esm/src/index.js b/node_modules/@azure/logger/dist-esm/src/index.js
|
||||
index cc25720..2925db5 100644
|
||||
--- a/node_modules/@azure/logger/dist-esm/src/index.js
|
||||
+++ b/node_modules/@azure/logger/dist-esm/src/index.js
|
||||
@@ -20,7 +20,7 @@ if (logLevelFromEnv) {
|
||||
setLogLevel(logLevelFromEnv);
|
||||
}
|
||||
else {
|
||||
- console.error(`AZURE_LOG_LEVEL set to unknown log level '${logLevelFromEnv}'; logging is not enabled. Acceptable values: ${AZURE_LOG_LEVELS.join(", ")}.`);
|
||||
+ console.error(`AZURE_LOG_LEVEL set to unknown log level; logging is not enabled. Acceptable values: ${AZURE_LOG_LEVELS.join(", ")}.`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
diff --git a/node_modules/@azure/logger/dist/index.js b/node_modules/@azure/logger/dist/index.js
|
||||
index 81e97c3..a415e2f 100644
|
||||
--- a/node_modules/@azure/logger/dist/index.js
|
||||
+++ b/node_modules/@azure/logger/dist/index.js
|
||||
@@ -21,7 +21,7 @@ let enabledNamespaces = [];
|
||||
let skippedNamespaces = [];
|
||||
const debuggers = [];
|
||||
if (debugEnvVariable) {
|
||||
- enable(debugEnvVariable);
|
||||
+ // enable(debugEnvVariable);
|
||||
}
|
||||
const debugObj = Object.assign((namespace) => {
|
||||
return createDebugger(namespace);
|
||||
@@ -125,7 +125,7 @@ if (logLevelFromEnv) {
|
||||
setLogLevel(logLevelFromEnv);
|
||||
}
|
||||
else {
|
||||
- console.error(`AZURE_LOG_LEVEL set to unknown log level '${logLevelFromEnv}'; logging is not enabled. Acceptable values: ${AZURE_LOG_LEVELS.join(", ")}.`);
|
||||
+ console.error(`AZURE_LOG_LEVEL set to unknown log level; logging is not enabled. Acceptable values: ${AZURE_LOG_LEVELS.join(", ")}.`);
|
||||
}
|
||||
}
|
||||
/**
|
@@ -1 +0,0 @@
|
||||
- [NEW] Use Job Summary to display build scan links, instead of GHA annotations
|
||||
|
27
src/build-results.ts
Normal file
27
src/build-results.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
export interface BuildResult {
|
||||
get rootProjectName(): string
|
||||
get rootProjectDir(): string
|
||||
get requestedTasks(): string
|
||||
get gradleVersion(): string
|
||||
get gradleHomeDir(): string
|
||||
get buildFailed(): boolean
|
||||
get buildScanUri(): string
|
||||
get buildScanFailed(): boolean
|
||||
}
|
||||
|
||||
export function loadBuildResults(): BuildResult[] {
|
||||
const buildResultsDir = path.resolve(process.env['RUNNER_TEMP']!, '.build-results')
|
||||
if (!fs.existsSync(buildResultsDir)) {
|
||||
return []
|
||||
}
|
||||
|
||||
return fs.readdirSync(buildResultsDir).map(file => {
|
||||
// Every file in the .build-results dir should be a BuildResults JSON
|
||||
const filePath = path.join(buildResultsDir, file)
|
||||
const content = fs.readFileSync(filePath, 'utf8')
|
||||
return JSON.parse(content) as BuildResult
|
||||
})
|
||||
}
|
@@ -2,15 +2,14 @@ import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import * as params from './input-params'
|
||||
import {CacheListener} from './cache-reporting'
|
||||
import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete, generateCacheKey} from './cache-utils'
|
||||
import {ConfigurationCacheEntryExtractor, GradleHomeEntryExtractor} from './cache-extract-entries'
|
||||
import {GradleHomeEntryExtractor} from './cache-extract-entries'
|
||||
|
||||
const RESTORED_CACHE_KEY_KEY = 'restored-cache-key'
|
||||
|
||||
export const META_FILE_DIR = '.gradle-build-action'
|
||||
const INCLUDE_PATHS_PARAMETER = 'gradle-home-cache-includes'
|
||||
const EXCLUDE_PATHS_PARAMETER = 'gradle-home-cache-excludes'
|
||||
|
||||
export class GradleStateCache {
|
||||
private cacheName: string
|
||||
@@ -80,7 +79,7 @@ export class GradleStateCache {
|
||||
async afterRestore(listener: CacheListener): Promise<void> {
|
||||
await this.debugReportGradleUserHomeSize('as restored from cache')
|
||||
await new GradleHomeEntryExtractor(this.gradleUserHome).restore(listener)
|
||||
await new ConfigurationCacheEntryExtractor(this.gradleUserHome).restore(listener)
|
||||
// await new ConfigurationCacheEntryExtractor(this.gradleUserHome).restore(listener)
|
||||
await this.debugReportGradleUserHomeSize('after restoring common artifacts')
|
||||
}
|
||||
|
||||
@@ -94,11 +93,18 @@ export class GradleStateCache {
|
||||
async save(listener: CacheListener): Promise<void> {
|
||||
const cacheKey = generateCacheKey(this.cacheName).key
|
||||
const restoredCacheKey = core.getState(RESTORED_CACHE_KEY_KEY)
|
||||
const entryListener = listener.entry(this.cacheDescription)
|
||||
const gradleHomeEntryListener = listener.entry(this.cacheDescription)
|
||||
|
||||
if (restoredCacheKey && cacheKey === restoredCacheKey) {
|
||||
core.info(`Cache hit occurred on the cache key ${cacheKey}, not saving cache.`)
|
||||
entryListener.markUnchanged('cache key not changed')
|
||||
|
||||
for (const entryListener of listener.cacheEntries) {
|
||||
if (entryListener === gradleHomeEntryListener) {
|
||||
entryListener.markNotSaved('cache key not changed')
|
||||
} else {
|
||||
entryListener.markNotSaved(`referencing '${this.cacheDescription}' cache entry not saved`)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -111,7 +117,7 @@ export class GradleStateCache {
|
||||
|
||||
core.info(`Caching ${this.cacheDescription} with cache key: ${cacheKey}`)
|
||||
const cachePath = this.getCachePath()
|
||||
await saveCache(cachePath, cacheKey, entryListener)
|
||||
await saveCache(cachePath, cacheKey, gradleHomeEntryListener)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -123,8 +129,8 @@ export class GradleStateCache {
|
||||
await this.debugReportGradleUserHomeSize('before saving common artifacts')
|
||||
this.deleteExcludedPaths()
|
||||
await Promise.all([
|
||||
new GradleHomeEntryExtractor(this.gradleUserHome).extract(listener),
|
||||
new ConfigurationCacheEntryExtractor(this.gradleUserHome).extract(listener)
|
||||
new GradleHomeEntryExtractor(this.gradleUserHome).extract(listener)
|
||||
// new ConfigurationCacheEntryExtractor(this.gradleUserHome).extract(listener)
|
||||
])
|
||||
await this.debugReportGradleUserHomeSize(
|
||||
"after extracting common artifacts (only 'caches' and 'notifications' will be stored)"
|
||||
@@ -135,7 +141,7 @@ export class GradleStateCache {
|
||||
* Delete any file paths that are excluded by the `gradle-home-cache-excludes` parameter.
|
||||
*/
|
||||
private deleteExcludedPaths(): void {
|
||||
const rawPaths: string[] = core.getMultilineInput(EXCLUDE_PATHS_PARAMETER)
|
||||
const rawPaths: string[] = params.getCacheExcludes()
|
||||
const resolvedPaths = rawPaths.map(x => path.resolve(this.gradleUserHome, x))
|
||||
|
||||
for (const p of resolvedPaths) {
|
||||
@@ -150,7 +156,7 @@ export class GradleStateCache {
|
||||
* but this can be overridden by the `gradle-home-cache-includes` parameter.
|
||||
*/
|
||||
protected getCachePath(): string[] {
|
||||
const rawPaths: string[] = core.getMultilineInput(INCLUDE_PATHS_PARAMETER)
|
||||
const rawPaths: string[] = params.getCacheIncludes()
|
||||
rawPaths.push(META_FILE_DIR)
|
||||
const resolvedPaths = rawPaths.map(x => this.resolveCachePath(x))
|
||||
cacheDebug(`Using cache paths: ${resolvedPaths}`)
|
||||
@@ -168,15 +174,15 @@ export class GradleStateCache {
|
||||
private initializeGradleUserHome(gradleUserHome: string, initScriptsDir: string): void {
|
||||
const initScriptFilenames = ['build-result-capture.init.gradle', 'build-result-capture-service.plugin.groovy']
|
||||
for (const initScriptFilename of initScriptFilenames) {
|
||||
const initScriptContent = this.readResourceAsString(initScriptFilename)
|
||||
const initScriptContent = this.readInitScriptAsString(initScriptFilename)
|
||||
const initScriptPath = path.resolve(initScriptsDir, initScriptFilename)
|
||||
fs.writeFileSync(initScriptPath, initScriptContent)
|
||||
}
|
||||
}
|
||||
|
||||
private readResourceAsString(resource: string): string {
|
||||
private readInitScriptAsString(resource: string): string {
|
||||
// Resolving relative to __dirname will allow node to find the resource at runtime
|
||||
const absolutePath = path.resolve(__dirname, '..', '..', 'src', 'resources', resource)
|
||||
const absolutePath = path.resolve(__dirname, '..', '..', 'src', 'resources', 'init-scripts', resource)
|
||||
return fs.readFileSync(absolutePath, 'utf8')
|
||||
}
|
||||
|
||||
|
68
src/cache-cleaner.ts
Normal file
68
src/cache-cleaner.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
import * as glob from '@actions/glob'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
export class CacheCleaner {
|
||||
private readonly gradleUserHome: string
|
||||
private readonly tmpDir: string
|
||||
|
||||
constructor(gradleUserHome: string, tmpDir: string) {
|
||||
this.gradleUserHome = gradleUserHome
|
||||
this.tmpDir = tmpDir
|
||||
}
|
||||
|
||||
async prepare(): Promise<void> {
|
||||
// Reset the file-access journal so that files appear not to have been used recently
|
||||
fs.rmSync(path.resolve(this.gradleUserHome, 'caches/journal-1'), {recursive: true, force: true})
|
||||
fs.mkdirSync(path.resolve(this.gradleUserHome, 'caches/journal-1'), {recursive: true})
|
||||
fs.writeFileSync(
|
||||
path.resolve(this.gradleUserHome, 'caches/journal-1/file-access.properties'),
|
||||
'inceptionTimestamp=0'
|
||||
)
|
||||
|
||||
// Set the modification time of all files to the past: this timestamp is used when there is no matching entry in the journal
|
||||
await this.ageAllFiles()
|
||||
|
||||
// Touch all 'gc' files so that cache cleanup won't run immediately.
|
||||
await this.touchAllFiles('gc.properties')
|
||||
}
|
||||
|
||||
async forceCleanup(): Promise<void> {
|
||||
// Age all 'gc' files so that cache cleanup will run immediately.
|
||||
await this.ageAllFiles('gc.properties')
|
||||
|
||||
// Run a dummy Gradle build to trigger cache cleanup
|
||||
const cleanupProjectDir = path.resolve(this.tmpDir, 'dummy-cleanup-project')
|
||||
fs.mkdirSync(cleanupProjectDir, {recursive: true})
|
||||
fs.writeFileSync(
|
||||
path.resolve(cleanupProjectDir, 'settings.gradle'),
|
||||
'rootProject.name = "dummy-cleanup-project"'
|
||||
)
|
||||
fs.writeFileSync(path.resolve(cleanupProjectDir, 'build.gradle'), 'task("noop") {}')
|
||||
|
||||
await exec.exec(`gradle -g ${this.gradleUserHome} --no-daemon --build-cache --no-scan --quiet noop`, [], {
|
||||
cwd: cleanupProjectDir
|
||||
})
|
||||
}
|
||||
|
||||
private async ageAllFiles(fileName = '*'): Promise<void> {
|
||||
core.debug(`Aging all files in Gradle User Home with name ${fileName}`)
|
||||
await this.setUtimes(`${this.gradleUserHome}/**/${fileName}`, new Date(0))
|
||||
}
|
||||
|
||||
private async touchAllFiles(fileName = '*'): Promise<void> {
|
||||
core.debug(`Touching all files in Gradle User Home with name ${fileName}`)
|
||||
await this.setUtimes(`${this.gradleUserHome}/**/${fileName}`, new Date())
|
||||
}
|
||||
|
||||
private async setUtimes(pattern: string, timestamp: Date): Promise<void> {
|
||||
const globber = await glob.create(pattern, {
|
||||
implicitDescendants: false
|
||||
})
|
||||
for await (const file of globber.globGenerator()) {
|
||||
fs.utimesSync(file, timestamp, timestamp)
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,18 +3,12 @@ import fs from 'fs'
|
||||
import * as core from '@actions/core'
|
||||
import * as glob from '@actions/glob'
|
||||
|
||||
import * as params from './input-params'
|
||||
|
||||
import {META_FILE_DIR} from './cache-base'
|
||||
import {CacheEntryListener, CacheListener} from './cache-reporting'
|
||||
import {
|
||||
cacheDebug,
|
||||
getCacheKeyPrefix,
|
||||
hashFileNames,
|
||||
isCacheDebuggingEnabled,
|
||||
restoreCache,
|
||||
saveCache,
|
||||
tryDelete
|
||||
} from './cache-utils'
|
||||
import {loadBuildResults} from './job-summary'
|
||||
import {cacheDebug, getCacheKeyPrefix, hashFileNames, restoreCache, saveCache, tryDelete} from './cache-utils'
|
||||
import {loadBuildResults} from './build-results'
|
||||
|
||||
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'
|
||||
|
||||
@@ -150,8 +144,7 @@ abstract class AbstractEntryExtractor {
|
||||
|
||||
// Find all matching files for this cache entry definition
|
||||
const globber = await glob.create(pattern, {
|
||||
implicitDescendants: false,
|
||||
followSymbolicLinks: false
|
||||
implicitDescendants: false
|
||||
})
|
||||
const matchingFiles = await globber.glob()
|
||||
|
||||
@@ -213,7 +206,7 @@ abstract class AbstractEntryExtractor {
|
||||
|
||||
if (previouslyRestoredKey === cacheKey) {
|
||||
cacheDebug(`No change to previously restored ${artifactType}. Not saving.`)
|
||||
entryListener.markUnchanged('contents unchanged')
|
||||
entryListener.markNotSaved('contents unchanged')
|
||||
} else {
|
||||
core.info(`Caching ${artifactType} with path '${pattern}' and cache key: ${cacheKey}`)
|
||||
await saveCache([pattern], cacheKey, entryListener)
|
||||
@@ -247,7 +240,7 @@ abstract class AbstractEntryExtractor {
|
||||
|
||||
// Run actions sequentially if debugging is enabled
|
||||
private async awaitForDebugging(p: Promise<ExtractedCacheEntry>): Promise<ExtractedCacheEntry> {
|
||||
if (isCacheDebuggingEnabled()) {
|
||||
if (params.isCacheDebuggingEnabled()) {
|
||||
await p
|
||||
}
|
||||
return p
|
||||
@@ -308,13 +301,12 @@ export class GradleHomeEntryExtractor extends AbstractEntryExtractor {
|
||||
private async deleteWrapperZips(): Promise<void> {
|
||||
const wrapperZips = path.resolve(this.gradleUserHome, 'wrapper/dists/*/*/*.zip')
|
||||
const globber = await glob.create(wrapperZips, {
|
||||
implicitDescendants: false,
|
||||
followSymbolicLinks: false
|
||||
implicitDescendants: false
|
||||
})
|
||||
|
||||
for (const p of await globber.glob()) {
|
||||
cacheDebug(`Deleting wrapper zip: ${p}`)
|
||||
tryDelete(p)
|
||||
for (const wrapperZip of await globber.glob()) {
|
||||
cacheDebug(`Deleting wrapper zip: ${wrapperZip}`)
|
||||
await tryDelete(wrapperZip)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,8 +332,8 @@ export class GradleHomeEntryExtractor extends AbstractEntryExtractor {
|
||||
|
||||
return [
|
||||
entryDefinition('generated-gradle-jars', ['caches/*/generated-gradle-jars/*.jar'], false),
|
||||
entryDefinition('wrapper-zips', ['wrapper/dists/*/*/'], false), // Entire wrapper directory cached together
|
||||
entryDefinition('java-toolchains', ['jdks/*.zip', 'jdks/*.tar.gz'], false),
|
||||
entryDefinition('wrapper-zips', ['wrapper/dists/*/*/'], false), // Each wrapper directory cached separately
|
||||
entryDefinition('java-toolchains', ['jdks/*/'], false), // Each extracted JDK cached separately
|
||||
entryDefinition('dependencies', ['caches/modules-*/files-*/*/*/*/*'], true),
|
||||
entryDefinition('instrumented-jars', ['caches/jars-*/*'], true),
|
||||
entryDefinition('kotlin-dsl', ['caches/*/kotlin-dsl/*/*'], true)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as cache from '@actions/cache'
|
||||
|
||||
/**
|
||||
* Collects information on what entries were saved and restored during the action.
|
||||
@@ -6,18 +7,19 @@ import * as core from '@actions/core'
|
||||
*/
|
||||
export class CacheListener {
|
||||
cacheEntries: CacheEntryListener[] = []
|
||||
isCacheReadOnly = false
|
||||
isCacheWriteOnly = false
|
||||
isCacheDisabled = false
|
||||
cacheReadOnly = false
|
||||
cacheWriteOnly = false
|
||||
cacheDisabled = false
|
||||
|
||||
get fullyRestored(): boolean {
|
||||
return this.cacheEntries.every(x => !x.wasRequestedButNotRestored())
|
||||
}
|
||||
|
||||
get cacheStatus(): string {
|
||||
if (this.isCacheDisabled) return 'disabled'
|
||||
if (this.isCacheWriteOnly) return 'write-only'
|
||||
if (this.isCacheReadOnly) return 'read-only'
|
||||
if (!cache.isFeatureAvailable()) return 'not available'
|
||||
if (this.cacheDisabled) return 'disabled'
|
||||
if (this.cacheWriteOnly) return 'write-only'
|
||||
if (this.cacheReadOnly) return 'read-only'
|
||||
return 'enabled'
|
||||
}
|
||||
|
||||
@@ -60,11 +62,11 @@ export class CacheEntryListener {
|
||||
requestedRestoreKeys: string[] | undefined
|
||||
restoredKey: string | undefined
|
||||
restoredSize: number | undefined
|
||||
notRestored: string | undefined
|
||||
|
||||
savedKey: string | undefined
|
||||
savedSize: number | undefined
|
||||
|
||||
unchanged: string | undefined
|
||||
notSaved: string | undefined
|
||||
|
||||
constructor(entryName: string) {
|
||||
this.entryName = entryName
|
||||
@@ -86,6 +88,11 @@ export class CacheEntryListener {
|
||||
return this
|
||||
}
|
||||
|
||||
markNotRestored(message: string): CacheEntryListener {
|
||||
this.notRestored = message
|
||||
return this
|
||||
}
|
||||
|
||||
markSaved(key: string, size: number | undefined): CacheEntryListener {
|
||||
this.savedKey = key
|
||||
this.savedSize = size
|
||||
@@ -98,13 +105,13 @@ export class CacheEntryListener {
|
||||
return this
|
||||
}
|
||||
|
||||
markUnchanged(message: string): CacheEntryListener {
|
||||
this.unchanged = message
|
||||
markNotSaved(message: string): CacheEntryListener {
|
||||
this.notSaved = message
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export function logCachingReport(listener: CacheListener): void {
|
||||
export function writeCachingReport(listener: CacheListener): void {
|
||||
const entries = listener.cacheEntries
|
||||
|
||||
core.summary.addRaw(
|
||||
@@ -123,21 +130,7 @@ export function logCachingReport(listener: CacheListener): void {
|
||||
|
||||
core.summary.addHeading('Cache Entry Details', 5)
|
||||
|
||||
const entryDetails = listener.cacheEntries
|
||||
.map(
|
||||
entry =>
|
||||
`Entry: ${entry.entryName}
|
||||
Requested Key : ${entry.requestedKey ?? ''}
|
||||
Restored Key : ${entry.restoredKey ?? ''}
|
||||
Size: ${formatSize(entry.restoredSize)}
|
||||
${getRestoredMessage(entry, listener.isCacheWriteOnly)}
|
||||
Saved Key : ${entry.savedKey ?? ''}
|
||||
Size: ${formatSize(entry.savedSize)}
|
||||
${getSavedMessage(entry, listener.isCacheReadOnly)}
|
||||
`
|
||||
)
|
||||
.join('---\n')
|
||||
|
||||
const entryDetails = renderEntryDetails(listener)
|
||||
core.summary.addRaw(`<pre>
|
||||
${entryDetails}
|
||||
</pre>
|
||||
@@ -145,10 +138,48 @@ ${entryDetails}
|
||||
`)
|
||||
}
|
||||
|
||||
function getRestoredMessage(entry: CacheEntryListener, isCacheWriteOnly: boolean): string {
|
||||
if (isCacheWriteOnly) {
|
||||
export function logCachingReport(listener: CacheListener): void {
|
||||
const entries = listener.cacheEntries
|
||||
|
||||
core.startGroup(`Caching for gradle-build-action was ${listener.cacheStatus} - expand for details`)
|
||||
|
||||
core.info(
|
||||
`Entries Restored: ${getCount(entries, e => e.restoredSize)} (${getSize(entries, e => e.restoredSize)} Mb)`
|
||||
)
|
||||
core.info(`Entries Saved : ${getCount(entries, e => e.savedSize)} (${getSize(entries, e => e.savedSize)} Mb)`)
|
||||
|
||||
core.info(`Cache Entry Details`)
|
||||
core.info(renderEntryDetails(listener))
|
||||
|
||||
core.endGroup()
|
||||
}
|
||||
|
||||
function renderEntryDetails(listener: CacheListener): string {
|
||||
return listener.cacheEntries
|
||||
.map(
|
||||
entry => `Entry: ${entry.entryName}
|
||||
Requested Key : ${entry.requestedKey ?? ''}
|
||||
Restored Key : ${entry.restoredKey ?? ''}
|
||||
Size: ${formatSize(entry.restoredSize)}
|
||||
${getRestoredMessage(entry, listener.cacheWriteOnly)}
|
||||
Saved Key : ${entry.savedKey ?? ''}
|
||||
Size: ${formatSize(entry.savedSize)}
|
||||
${getSavedMessage(entry, listener.cacheReadOnly)}
|
||||
`
|
||||
)
|
||||
.join('---\n')
|
||||
}
|
||||
|
||||
function getRestoredMessage(entry: CacheEntryListener, cacheWriteOnly: boolean): string {
|
||||
if (entry.notRestored) {
|
||||
return `(Entry not restored: ${entry.notRestored})`
|
||||
}
|
||||
if (cacheWriteOnly) {
|
||||
return '(Entry not restored: cache is write-only)'
|
||||
}
|
||||
if (entry.requestedKey === undefined) {
|
||||
return '(Entry not restored: not requested)'
|
||||
}
|
||||
if (entry.restoredKey === undefined) {
|
||||
return '(Entry not restored: no match found)'
|
||||
}
|
||||
@@ -158,12 +189,12 @@ function getRestoredMessage(entry: CacheEntryListener, isCacheWriteOnly: boolean
|
||||
return '(Entry restored: partial match found)'
|
||||
}
|
||||
|
||||
function getSavedMessage(entry: CacheEntryListener, isCacheReadOnly: boolean): string {
|
||||
if (entry.unchanged) {
|
||||
return `(Entry not saved: ${entry.unchanged})`
|
||||
function getSavedMessage(entry: CacheEntryListener, cacheReadOnly: boolean): string {
|
||||
if (entry.notSaved) {
|
||||
return `(Entry not saved: ${entry.notSaved})`
|
||||
}
|
||||
if (entry.savedKey === undefined) {
|
||||
if (isCacheReadOnly) {
|
||||
if (cacheReadOnly) {
|
||||
return '(Entry not saved: cache is read-only)'
|
||||
}
|
||||
return '(Entry not saved: reason unknown)'
|
||||
@@ -178,7 +209,7 @@ function getCount(
|
||||
cacheEntries: CacheEntryListener[],
|
||||
predicate: (value: CacheEntryListener) => number | undefined
|
||||
): number {
|
||||
return cacheEntries.filter(e => predicate(e) !== undefined).length
|
||||
return cacheEntries.filter(e => predicate(e)).length
|
||||
}
|
||||
|
||||
function getSize(
|
||||
@@ -190,11 +221,8 @@ function getSize(
|
||||
}
|
||||
|
||||
function formatSize(bytes: number | undefined): string {
|
||||
if (bytes === undefined) {
|
||||
if (bytes === undefined || bytes === 0) {
|
||||
return ''
|
||||
}
|
||||
if (bytes === 0) {
|
||||
return '0 (Entry already exists)'
|
||||
}
|
||||
return `${Math.round(bytes / (1024 * 1024))} MB (${bytes} B)`
|
||||
}
|
||||
|
@@ -1,20 +1,17 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as cache from '@actions/cache'
|
||||
import * as github from '@actions/github'
|
||||
import * as exec from '@actions/exec'
|
||||
|
||||
import * as crypto from 'crypto'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
|
||||
import * as params from './input-params'
|
||||
|
||||
import {CacheEntryListener} from './cache-reporting'
|
||||
|
||||
const CACHE_PROTOCOL_VERSION = 'v6-'
|
||||
|
||||
const JOB_CONTEXT_PARAMETER = 'workflow-job-context'
|
||||
const CACHE_DISABLED_PARAMETER = 'cache-disabled'
|
||||
const CACHE_READONLY_PARAMETER = 'cache-read-only'
|
||||
const CACHE_WRITEONLY_PARAMETER = 'cache-write-only'
|
||||
const STRICT_CACHE_MATCH_PARAMETER = 'gradle-home-cache-strict-match'
|
||||
const CACHE_DEBUG_VAR = 'GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'
|
||||
const CACHE_PROTOCOL_VERSION = 'v8-'
|
||||
|
||||
const CACHE_KEY_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
|
||||
const CACHE_KEY_OS_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_ENVIRONMENT'
|
||||
@@ -22,20 +19,30 @@ const CACHE_KEY_JOB_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB'
|
||||
const CACHE_KEY_JOB_INSTANCE_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB_INSTANCE'
|
||||
const CACHE_KEY_JOB_EXECUTION_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION'
|
||||
|
||||
const SEGMENT_DOWNLOAD_TIMEOUT_VAR = 'SEGMENT_DOWNLOAD_TIMEOUT_MINS'
|
||||
const SEGMENT_DOWNLOAD_TIMEOUT_DEFAULT = 10 * 60 * 1000 // 10 minutes
|
||||
|
||||
export function isCacheDisabled(): boolean {
|
||||
return core.getBooleanInput(CACHE_DISABLED_PARAMETER)
|
||||
if (!cache.isFeatureAvailable()) {
|
||||
return true
|
||||
}
|
||||
return params.isCacheDisabled()
|
||||
}
|
||||
|
||||
export function isCacheReadOnly(): boolean {
|
||||
return !isCacheWriteOnly() && core.getBooleanInput(CACHE_READONLY_PARAMETER)
|
||||
return !isCacheWriteOnly() && params.isCacheReadOnly()
|
||||
}
|
||||
|
||||
export function isCacheWriteOnly(): boolean {
|
||||
return core.getBooleanInput(CACHE_WRITEONLY_PARAMETER)
|
||||
return params.isCacheWriteOnly()
|
||||
}
|
||||
|
||||
export function isCacheDebuggingEnabled(): boolean {
|
||||
return process.env[CACHE_DEBUG_VAR] ? true : false
|
||||
return params.isCacheDebuggingEnabled()
|
||||
}
|
||||
|
||||
export function isCacheCleanupEnabled(): boolean {
|
||||
return params.isCacheCleanupEnabled()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +91,7 @@ export function generateCacheKey(cacheName: string): CacheKey {
|
||||
// Exact match on Git SHA
|
||||
const cacheKey = `${cacheKeyForJobContext}-${getCacheKeyJobExecution()}`
|
||||
|
||||
if (core.getBooleanInput(STRICT_CACHE_MATCH_PARAMETER)) {
|
||||
if (params.isCacheStrictMatch()) {
|
||||
return new CacheKey(cacheKey, [cacheKeyForJobContext])
|
||||
}
|
||||
|
||||
@@ -102,8 +109,7 @@ function getCacheKeyEnvironment(): string {
|
||||
}
|
||||
|
||||
function getCacheKeyJob(): string {
|
||||
// Prefix can be used to force change all cache keys (defaults to cache protocol version)
|
||||
return process.env[CACHE_KEY_JOB_VAR] || github.context.job
|
||||
return process.env[CACHE_KEY_JOB_VAR] || `${github.context.workflow}-${github.context.job}`
|
||||
}
|
||||
|
||||
function getCacheKeyJobInstance(): string {
|
||||
@@ -114,7 +120,7 @@ function getCacheKeyJobInstance(): string {
|
||||
|
||||
// By default, we hash the full `matrix` data for the run, to uniquely identify this job invocation
|
||||
// The only way we can obtain the `matrix` data is via the `workflow-job-context` parameter in action.yml.
|
||||
const workflowJobContext = core.getInput(JOB_CONTEXT_PARAMETER)
|
||||
const workflowJobContext = params.getJobContext()
|
||||
return hashStrings([workflowJobContext])
|
||||
}
|
||||
|
||||
@@ -143,12 +149,17 @@ export async function restoreCache(
|
||||
): Promise<cache.CacheEntry | undefined> {
|
||||
listener.markRequested(cacheKey, cacheRestoreKeys)
|
||||
try {
|
||||
const restoredEntry = await cache.restoreCache(cachePath, cacheKey, cacheRestoreKeys)
|
||||
// Only override the read timeout if the SEGMENT_DOWNLOAD_TIMEOUT_MINS env var has NOT been set
|
||||
const cacheRestoreOptions = process.env[SEGMENT_DOWNLOAD_TIMEOUT_VAR]
|
||||
? {}
|
||||
: {segmentTimeoutInMs: SEGMENT_DOWNLOAD_TIMEOUT_DEFAULT}
|
||||
const restoredEntry = await cache.restoreCache(cachePath, cacheKey, cacheRestoreKeys, cacheRestoreOptions)
|
||||
if (restoredEntry !== undefined) {
|
||||
listener.markRestored(restoredEntry.key, restoredEntry.size)
|
||||
}
|
||||
return restoredEntry
|
||||
} catch (error) {
|
||||
listener.markNotRestored((error as Error).message)
|
||||
handleCacheFailure(error, `Failed to restore ${cacheKey}`)
|
||||
return undefined
|
||||
}
|
||||
@@ -161,8 +172,10 @@ export async function saveCache(cachePath: string[], cacheKey: string, listener:
|
||||
} catch (error) {
|
||||
if (error instanceof cache.ReserveCacheError) {
|
||||
listener.markAlreadyExists(cacheKey)
|
||||
} else {
|
||||
listener.markNotSaved((error as Error).message)
|
||||
}
|
||||
handleCacheFailure(error, `Failed to save cache entry ${cacheKey}`)
|
||||
handleCacheFailure(error, `Failed to save cache entry with path '${cachePath}' and key: ${cacheKey}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,20 +208,27 @@ export function handleCacheFailure(error: unknown, message: string): void {
|
||||
* Attempt to delete a file or directory, waiting to allow locks to be released
|
||||
*/
|
||||
export async function tryDelete(file: string): Promise<void> {
|
||||
const stat = fs.lstatSync(file)
|
||||
for (let count = 0; count < 3; count++) {
|
||||
const maxAttempts = 5
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
if (!fs.existsSync(file)) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const stat = fs.lstatSync(file)
|
||||
if (stat.isDirectory()) {
|
||||
fs.rmdirSync(file, {recursive: true})
|
||||
fs.rmSync(file, {recursive: true})
|
||||
} else {
|
||||
fs.unlinkSync(file)
|
||||
}
|
||||
return
|
||||
} catch (error) {
|
||||
if (count === 2) {
|
||||
if (attempt === maxAttempts) {
|
||||
core.warning(`Failed to delete ${file}, which will impact caching.
|
||||
It is likely locked by another process. Output of 'jps -ml':
|
||||
${await getJavaProcesses()}`)
|
||||
throw error
|
||||
} else {
|
||||
core.warning(String(error))
|
||||
cacheDebug(`Attempt to delete ${file} failed. Will try again.`)
|
||||
await delay(1000)
|
||||
}
|
||||
}
|
||||
@@ -218,3 +238,8 @@ export async function tryDelete(file: string): Promise<void> {
|
||||
async function delay(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
async function getJavaProcesses(): Promise<string> {
|
||||
const jpsOutput = await exec.getExecOutput('jps', ['-lm'])
|
||||
return jpsOutput.stdout
|
||||
}
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import * as core from '@actions/core'
|
||||
import {isCacheDisabled, isCacheReadOnly, isCacheWriteOnly} from './cache-utils'
|
||||
import {isCacheCleanupEnabled, isCacheDisabled, isCacheReadOnly, isCacheWriteOnly} from './cache-utils'
|
||||
import {CacheListener} from './cache-reporting'
|
||||
import {DaemonController} from './daemon-controller'
|
||||
import {GradleStateCache} from './cache-base'
|
||||
import {CacheCleaner} from './cache-cleaner'
|
||||
|
||||
const CACHE_RESTORED_VAR = 'GRADLE_BUILD_ACTION_CACHE_RESTORED'
|
||||
|
||||
@@ -19,7 +21,7 @@ export async function restore(gradleUserHome: string, cacheListener: CacheListen
|
||||
core.info('Cache is disabled: will not restore state from previous builds.')
|
||||
// Initialize the Gradle User Home even when caching is disabled.
|
||||
gradleStateCache.init()
|
||||
cacheListener.isCacheDisabled = true
|
||||
cacheListener.cacheDisabled = true
|
||||
return
|
||||
}
|
||||
|
||||
@@ -36,41 +38,51 @@ export async function restore(gradleUserHome: string, cacheListener: CacheListen
|
||||
|
||||
if (isCacheWriteOnly()) {
|
||||
core.info('Cache is write-only: will not restore from cache.')
|
||||
cacheListener.isCacheWriteOnly = true
|
||||
cacheListener.cacheWriteOnly = true
|
||||
return
|
||||
}
|
||||
|
||||
await core.group('Restore Gradle state from cache', async () => {
|
||||
await gradleStateCache.restore(cacheListener)
|
||||
})
|
||||
|
||||
if (isCacheCleanupEnabled() && !isCacheReadOnly()) {
|
||||
core.info('Preparing cache for cleanup.')
|
||||
const cacheCleaner = new CacheCleaner(gradleUserHome, process.env['RUNNER_TEMP']!)
|
||||
await cacheCleaner.prepare()
|
||||
}
|
||||
}
|
||||
|
||||
export async function save(gradleUserHome: string, cacheListener: CacheListener): Promise<void> {
|
||||
if (!shouldSaveCaches()) {
|
||||
export async function save(
|
||||
gradleUserHome: string,
|
||||
cacheListener: CacheListener,
|
||||
daemonController: DaemonController
|
||||
): Promise<void> {
|
||||
if (isCacheDisabled()) {
|
||||
core.info('Cache is disabled: will not save state for later builds.')
|
||||
return
|
||||
}
|
||||
|
||||
if (!core.getState(CACHE_RESTORED_VAR)) {
|
||||
core.info('Cache will not be saved: not restored in main action step.')
|
||||
return
|
||||
}
|
||||
|
||||
if (isCacheReadOnly()) {
|
||||
core.info('Cache is read-only: will not save state for use in subsequent builds.')
|
||||
cacheListener.isCacheReadOnly = true
|
||||
cacheListener.cacheReadOnly = true
|
||||
return
|
||||
}
|
||||
|
||||
await daemonController.stopAllDaemons()
|
||||
|
||||
if (isCacheCleanupEnabled()) {
|
||||
core.info('Forcing cache cleanup.')
|
||||
const cacheCleaner = new CacheCleaner(gradleUserHome, process.env['RUNNER_TEMP']!)
|
||||
await cacheCleaner.forceCleanup()
|
||||
}
|
||||
|
||||
await core.group('Caching Gradle state', async () => {
|
||||
return new GradleStateCache(gradleUserHome).save(cacheListener)
|
||||
})
|
||||
}
|
||||
|
||||
function shouldSaveCaches(): boolean {
|
||||
if (isCacheDisabled()) {
|
||||
core.info('Cache is disabled: will not save state for later builds.')
|
||||
return false
|
||||
}
|
||||
|
||||
if (!core.getState(CACHE_RESTORED_VAR)) {
|
||||
core.info('Cache will not be saved: not restored in main action step.')
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
36
src/daemon-controller.ts
Normal file
36
src/daemon-controller.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import {BuildResult} from './build-results'
|
||||
|
||||
export class DaemonController {
|
||||
private readonly gradleHomes
|
||||
|
||||
constructor(buildResults: BuildResult[]) {
|
||||
const allHomes = buildResults.map(buildResult => buildResult.gradleHomeDir)
|
||||
this.gradleHomes = Array.from(new Set(allHomes))
|
||||
}
|
||||
|
||||
async stopAllDaemons(): Promise<void> {
|
||||
core.info('Stopping all Gradle daemons before saving Gradle User Home state')
|
||||
|
||||
const executions: Promise<number>[] = []
|
||||
const args = ['--stop']
|
||||
|
||||
for (const gradleHome of this.gradleHomes) {
|
||||
const executable = path.resolve(gradleHome, 'bin', 'gradle')
|
||||
if (!fs.existsSync(executable)) {
|
||||
core.warning(`Gradle executable not found at ${executable}. Could not stop Gradle daemons.`)
|
||||
continue
|
||||
}
|
||||
core.info(`Stopping Gradle daemons for ${gradleHome}`)
|
||||
executions.push(
|
||||
exec.exec(executable, args, {
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
)
|
||||
}
|
||||
await Promise.all(executions)
|
||||
}
|
||||
}
|
24
src/dependency-graph-generate.ts
Normal file
24
src/dependency-graph-generate.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import * as core from '@actions/core'
|
||||
|
||||
import * as provisioner from './provision'
|
||||
import * as dependencyGraph from './dependency-graph'
|
||||
|
||||
/**
|
||||
* The main entry point for the action, called by Github Actions for the step.
|
||||
*/
|
||||
export async function run(): Promise<void> {
|
||||
try {
|
||||
// Download and install Gradle if required
|
||||
const executable = await provisioner.provisionGradle()
|
||||
|
||||
// Generate and upload dependency graph artifact
|
||||
await dependencyGraph.generateDependencyGraph(executable)
|
||||
} catch (error) {
|
||||
core.setFailed(String(error))
|
||||
if (error instanceof Error && error.stack) {
|
||||
core.info(error.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
16
src/dependency-graph-submit.ts
Normal file
16
src/dependency-graph-submit.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as dependencyGraph from './dependency-graph'
|
||||
|
||||
export async function run(): Promise<void> {
|
||||
try {
|
||||
// Retrieve the dependency graph artifact and submit via Dependency Submission API
|
||||
await dependencyGraph.submitDependencyGraph()
|
||||
} catch (error) {
|
||||
core.setFailed(String(error))
|
||||
if (error instanceof Error && error.stack) {
|
||||
core.info(error.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
155
src/dependency-graph.ts
Normal file
155
src/dependency-graph.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as artifact from '@actions/artifact'
|
||||
import * as github from '@actions/github'
|
||||
import * as glob from '@actions/glob'
|
||||
import * as toolCache from '@actions/tool-cache'
|
||||
import {Octokit} from '@octokit/rest'
|
||||
|
||||
import * as path from 'path'
|
||||
import fs from 'fs'
|
||||
|
||||
import * as execution from './execution'
|
||||
import * as layout from './repository-layout'
|
||||
|
||||
const DEPENDENCY_GRAPH_ARTIFACT = 'dependency-graph'
|
||||
const DEPENDENCY_GRAPH_FILE = 'dependency-graph.json'
|
||||
|
||||
export async function generateDependencyGraph(executable: string | undefined): Promise<void> {
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
const buildRootDirectory = layout.buildRootDirectory()
|
||||
const buildPath = getRelativePathFromWorkspace(buildRootDirectory)
|
||||
|
||||
const initScript = path.resolve(
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'src',
|
||||
'resources',
|
||||
'init-scripts',
|
||||
'github-dependency-graph.init.gradle'
|
||||
)
|
||||
const args = [
|
||||
`-Dorg.gradle.github.env.GRADLE_BUILD_PATH=${buildPath}`,
|
||||
'--init-script',
|
||||
initScript,
|
||||
':GitHubDependencyGraphPlugin_generateDependencyGraph'
|
||||
]
|
||||
|
||||
await execution.executeGradleBuild(executable, buildRootDirectory, args)
|
||||
const dependencyGraphJson = copyDependencyGraphToBuildRoot(buildRootDirectory)
|
||||
|
||||
const artifactClient = artifact.create()
|
||||
artifactClient.uploadArtifact(DEPENDENCY_GRAPH_ARTIFACT, [dependencyGraphJson], workspaceDirectory)
|
||||
}
|
||||
|
||||
function copyDependencyGraphToBuildRoot(buildRootDirectory: string): string {
|
||||
const sourceFile = path.resolve(
|
||||
buildRootDirectory,
|
||||
'build',
|
||||
'reports',
|
||||
'github-dependency-graph-plugin',
|
||||
'github-dependency-snapshot.json'
|
||||
)
|
||||
|
||||
const destFile = path.resolve(buildRootDirectory, DEPENDENCY_GRAPH_FILE)
|
||||
fs.copyFileSync(sourceFile, destFile)
|
||||
return destFile
|
||||
}
|
||||
|
||||
export async function submitDependencyGraph(): Promise<void> {
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
const octokit: Octokit = getOctokit()
|
||||
|
||||
for (const jsonFile of await retrieveDependencyGraphs(octokit, workspaceDirectory)) {
|
||||
const jsonContent = fs.readFileSync(jsonFile, 'utf8')
|
||||
|
||||
const jsonObject = JSON.parse(jsonContent)
|
||||
jsonObject.owner = github.context.repo.owner
|
||||
jsonObject.repo = github.context.repo.repo
|
||||
const response = await octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', jsonObject)
|
||||
|
||||
const relativeJsonFile = getRelativePathFromWorkspace(jsonFile)
|
||||
core.info(`Submitted ${relativeJsonFile}: ${JSON.stringify(response)}`)
|
||||
core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function findDependencyGraphFiles(dir: string): Promise<string[]> {
|
||||
const globber = await glob.create(`${dir}/**/${DEPENDENCY_GRAPH_FILE}`)
|
||||
const graphFiles = globber.glob()
|
||||
core.info(`Found graph files in ${dir}: ${graphFiles}`)
|
||||
return graphFiles
|
||||
}
|
||||
|
||||
async function retrieveDependencyGraphs(octokit: Octokit, workspaceDirectory: string): Promise<string[]> {
|
||||
if (github.context.payload.workflow_run) {
|
||||
return await retrieveDependencyGraphsForWorkflowRun(
|
||||
github.context.payload.workflow_run.id,
|
||||
octokit,
|
||||
workspaceDirectory
|
||||
)
|
||||
}
|
||||
return retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory)
|
||||
}
|
||||
|
||||
async function retrieveDependencyGraphsForWorkflowRun(
|
||||
runId: number,
|
||||
octokit: Octokit,
|
||||
workspaceDirectory: string
|
||||
): Promise<string[]> {
|
||||
// Find the workflow run artifacts named "dependency-graph"
|
||||
const artifacts = await octokit.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: github.context.repo.owner,
|
||||
repo: github.context.repo.repo,
|
||||
run_id: runId
|
||||
})
|
||||
|
||||
const matchArtifact = artifacts.data.artifacts.find(candidate => {
|
||||
return candidate.name === DEPENDENCY_GRAPH_ARTIFACT
|
||||
})
|
||||
|
||||
if (matchArtifact === undefined) {
|
||||
throw new Error(`Dependency graph artifact not found. Has it been generated by workflow run '${runId}'?`)
|
||||
}
|
||||
|
||||
// Download the dependency-graph artifact
|
||||
const download = await octokit.rest.actions.downloadArtifact({
|
||||
owner: github.context.repo.owner,
|
||||
repo: github.context.repo.repo,
|
||||
artifact_id: matchArtifact.id,
|
||||
archive_format: 'zip'
|
||||
})
|
||||
|
||||
const downloadBuffer = download.data as ArrayBuffer
|
||||
const downloadZip = path.resolve(workspaceDirectory, 'dependency-graph.zip')
|
||||
fs.writeFileSync(downloadZip, Buffer.from(downloadBuffer))
|
||||
|
||||
// Expance the dependency-graph zip and locate each dependency-graph JSON file
|
||||
const extractDir = path.resolve(workspaceDirectory, 'dependency-graph')
|
||||
const extracted = await toolCache.extractZip(downloadZip, extractDir)
|
||||
core.info(`Extracted dependency graph artifacts to ${extracted}: ${fs.readdirSync(extracted)}`)
|
||||
|
||||
return findDependencyGraphFiles(extracted)
|
||||
}
|
||||
|
||||
async function retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory: string): Promise<string[]> {
|
||||
const artifactClient = artifact.create()
|
||||
const downloadPath = path.resolve(workspaceDirectory, 'dependency-graph')
|
||||
await artifactClient.downloadArtifact(DEPENDENCY_GRAPH_ARTIFACT, downloadPath)
|
||||
return await findDependencyGraphFiles(downloadPath)
|
||||
}
|
||||
|
||||
function getOctokit(): Octokit {
|
||||
return new Octokit({
|
||||
auth: getGithubToken()
|
||||
})
|
||||
}
|
||||
|
||||
function getGithubToken(): string {
|
||||
return core.getInput('github-token', {required: true})
|
||||
}
|
||||
|
||||
function getRelativePathFromWorkspace(file: string): string {
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
return path.relative(workspaceDirectory, file)
|
||||
}
|
77
src/input-params.ts
Normal file
77
src/input-params.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import * as core from '@actions/core'
|
||||
import {parseArgsStringToArgv} from 'string-argv'
|
||||
|
||||
export function isCacheDisabled(): boolean {
|
||||
return getBooleanInput('cache-disabled')
|
||||
}
|
||||
|
||||
export function isCacheReadOnly(): boolean {
|
||||
return getBooleanInput('cache-read-only')
|
||||
}
|
||||
|
||||
export function isCacheWriteOnly(): boolean {
|
||||
return getBooleanInput('cache-write-only')
|
||||
}
|
||||
|
||||
export function isCacheStrictMatch(): boolean {
|
||||
return getBooleanInput('gradle-home-cache-strict-match')
|
||||
}
|
||||
|
||||
export function isCacheDebuggingEnabled(): boolean {
|
||||
return process.env['GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'] ? true : false
|
||||
}
|
||||
|
||||
export function isCacheCleanupEnabled(): boolean {
|
||||
return getBooleanInput('gradle-home-cache-cleanup')
|
||||
}
|
||||
|
||||
export function getCacheIncludes(): string[] {
|
||||
return core.getMultilineInput('gradle-home-cache-includes')
|
||||
}
|
||||
|
||||
export function getCacheExcludes(): string[] {
|
||||
return core.getMultilineInput('gradle-home-cache-excludes')
|
||||
}
|
||||
|
||||
export function getBuildRootDirectory(): string {
|
||||
return core.getInput('build-root-directory')
|
||||
}
|
||||
|
||||
export function getGradleVersion(): string {
|
||||
return core.getInput('gradle-version')
|
||||
}
|
||||
|
||||
export function getGradleExecutable(): string {
|
||||
return core.getInput('gradle-executable')
|
||||
}
|
||||
|
||||
export function getArguments(): string[] {
|
||||
const input = core.getInput('arguments')
|
||||
return parseArgsStringToArgv(input)
|
||||
}
|
||||
|
||||
// Internal parameters
|
||||
export function getJobContext(): string {
|
||||
return core.getInput('workflow-job-context')
|
||||
}
|
||||
|
||||
export function getGithubToken(): string {
|
||||
return core.getInput('github-token', {required: true})
|
||||
}
|
||||
|
||||
export function isJobSummaryEnabled(): boolean {
|
||||
return getBooleanInput('generate-job-summary', true)
|
||||
}
|
||||
|
||||
function getBooleanInput(paramName: string, paramDefault = false): boolean {
|
||||
const paramValue = core.getInput(paramName)
|
||||
switch (paramValue.toLowerCase().trim()) {
|
||||
case '':
|
||||
return paramDefault
|
||||
case 'false':
|
||||
return false
|
||||
case 'true':
|
||||
return true
|
||||
}
|
||||
throw TypeError(`The value '${paramValue} is not valid for '${paramName}. Valid values are: [true, false]`)
|
||||
}
|
@@ -1,19 +1,8 @@
|
||||
import * as core from '@actions/core'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import {logCachingReport, CacheListener} from './cache-reporting'
|
||||
import {BuildResult} from './build-results'
|
||||
import {writeCachingReport, CacheListener, logCachingReport} from './cache-reporting'
|
||||
|
||||
export interface BuildResult {
|
||||
get rootProjectName(): string
|
||||
get rootProjectDir(): string
|
||||
get requestedTasks(): string
|
||||
get gradleVersion(): string
|
||||
get gradleHomeDir(): string
|
||||
get buildFailed(): boolean
|
||||
get buildScanUri(): string
|
||||
}
|
||||
|
||||
export function writeJobSummary(buildResults: BuildResult[], cacheListener: CacheListener): void {
|
||||
export async function writeJobSummary(buildResults: BuildResult[], cacheListener: CacheListener): Promise<void> {
|
||||
core.info('Writing job summary')
|
||||
|
||||
if (buildResults.length === 0) {
|
||||
@@ -22,49 +11,84 @@ export function writeJobSummary(buildResults: BuildResult[], cacheListener: Cach
|
||||
writeSummaryTable(buildResults)
|
||||
}
|
||||
|
||||
logCachingReport(cacheListener)
|
||||
writeCachingReport(cacheListener)
|
||||
|
||||
core.summary.write()
|
||||
await core.summary.write()
|
||||
}
|
||||
|
||||
export function loadBuildResults(): BuildResult[] {
|
||||
const buildResultsDir = path.resolve(process.env['RUNNER_TEMP']!, '.build-results')
|
||||
if (!fs.existsSync(buildResultsDir)) {
|
||||
return []
|
||||
export async function logJobSummary(buildResults: BuildResult[], cacheListener: CacheListener): Promise<void> {
|
||||
if (buildResults.length === 0) {
|
||||
core.debug('No Gradle build results found. Summary table will not be logged.')
|
||||
} else {
|
||||
logSummaryTable(buildResults)
|
||||
}
|
||||
|
||||
return fs.readdirSync(buildResultsDir).map(file => {
|
||||
// Every file in the .build-results dir should be a BuildResults JSON
|
||||
const filePath = path.join(buildResultsDir, file)
|
||||
const content = fs.readFileSync(filePath, 'utf8')
|
||||
return JSON.parse(content) as BuildResult
|
||||
})
|
||||
logCachingReport(cacheListener)
|
||||
}
|
||||
|
||||
function writeSummaryTable(results: BuildResult[]): void {
|
||||
core.summary.addHeading('Gradle Builds', 3)
|
||||
core.summary.addTable([
|
||||
[
|
||||
{data: 'Root Project', header: true},
|
||||
{data: 'Tasks', header: true},
|
||||
{data: 'Gradle Version', header: true},
|
||||
{data: 'Outcome', header: true}
|
||||
],
|
||||
...results.map(result => [
|
||||
result.rootProjectName,
|
||||
result.requestedTasks,
|
||||
result.gradleVersion,
|
||||
renderOutcome(result)
|
||||
])
|
||||
])
|
||||
core.summary.addRaw('\n')
|
||||
|
||||
core.summary.addRaw(`
|
||||
<table>
|
||||
<tr>
|
||||
<th>Root Project</th>
|
||||
<th>Requested Tasks</th>
|
||||
<th>Gradle Version</th>
|
||||
<th>Build Outcome</th>
|
||||
<th>Build Scan™</th>
|
||||
</tr>${results.map(result => renderBuildResultRow(result)).join('')}
|
||||
</table>
|
||||
`)
|
||||
}
|
||||
|
||||
function renderBuildResultRow(result: BuildResult): string {
|
||||
return `
|
||||
<tr>
|
||||
<td>${result.rootProjectName}</td>
|
||||
<td>${result.requestedTasks}</td>
|
||||
<td align='center'>${result.gradleVersion}</td>
|
||||
<td align='center'>${renderOutcome(result)}</td>
|
||||
<td>${renderBuildScan(result)}</td>
|
||||
</tr>`
|
||||
}
|
||||
|
||||
function renderOutcome(result: BuildResult): string {
|
||||
const labelPart = result.buildScanUri ? 'Build%20Scan%E2%84%A2' : 'Build'
|
||||
const outcomePart = result.buildFailed ? 'FAILED-red' : 'SUCCESS-brightgreen'
|
||||
const badgeUrl = `https://img.shields.io/badge/${labelPart}-${outcomePart}?logo=Gradle`
|
||||
const badgeHtml = `<img src="${badgeUrl}" alt="Gradle Build">`
|
||||
const targetUrl = result.buildScanUri ? result.buildScanUri : '#'
|
||||
return result.buildFailed ? ':x:' : ':white_check_mark:'
|
||||
}
|
||||
|
||||
function renderBuildScan(result: BuildResult): string {
|
||||
if (result.buildScanFailed) {
|
||||
return renderBuildScanBadge(
|
||||
'PUBLISH_FAILED',
|
||||
'orange',
|
||||
'https://docs.gradle.com/enterprise/gradle-plugin/#troubleshooting'
|
||||
)
|
||||
}
|
||||
if (result.buildScanUri) {
|
||||
return renderBuildScanBadge('PUBLISHED', '06A0CE', result.buildScanUri)
|
||||
}
|
||||
return renderBuildScanBadge('NOT_PUBLISHED', 'lightgrey', 'https://scans.gradle.com')
|
||||
}
|
||||
|
||||
function renderBuildScanBadge(outcomeText: string, outcomeColor: string, targetUrl: string): string {
|
||||
const badgeUrl = `https://img.shields.io/badge/Build%20Scan%E2%84%A2-${outcomeText}-${outcomeColor}?logo=Gradle`
|
||||
const badgeHtml = `<img src="${badgeUrl}" alt="Build Scan ${outcomeText}" />`
|
||||
return `<a href="${targetUrl}" rel="nofollow">${badgeHtml}</a>`
|
||||
}
|
||||
|
||||
function logSummaryTable(results: BuildResult[]): void {
|
||||
core.info('============================')
|
||||
core.info('Gradle Builds')
|
||||
core.info('----------------------------')
|
||||
core.info('Root Project | Requested Tasks | Gradle Version | Build Outcome | Build Scan™')
|
||||
core.info('----------------------------')
|
||||
for (const result of results) {
|
||||
core.info(
|
||||
`${result.rootProjectName} | ${result.requestedTasks} | ${result.gradleVersion} | ${
|
||||
result.buildFailed ? 'FAILED' : 'SUCCESS'
|
||||
} | ${result.buildScanFailed ? 'Publish failed' : result.buildScanUri}`
|
||||
)
|
||||
}
|
||||
core.info('============================')
|
||||
}
|
||||
|
48
src/main.ts
48
src/main.ts
@@ -1,30 +1,26 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as path from 'path'
|
||||
import {parseArgsStringToArgv} from 'string-argv'
|
||||
|
||||
import * as setupGradle from './setup-gradle'
|
||||
import * as execution from './execution'
|
||||
import * as provision from './provision'
|
||||
import * as provisioner from './provision'
|
||||
import * as layout from './repository-layout'
|
||||
import * as params from './input-params'
|
||||
|
||||
/**
|
||||
* The main entry point for the action, called by Github Actions for the step.
|
||||
*/
|
||||
export async function run(): Promise<void> {
|
||||
try {
|
||||
const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || ''
|
||||
const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory)
|
||||
// Configure Gradle environment (Gradle User Home)
|
||||
await setupGradle.setup()
|
||||
|
||||
await setupGradle.setup(buildRootDirectory)
|
||||
|
||||
const executable = await provisionGradle(workspaceDirectory)
|
||||
// executable will be undefined if using Gradle wrapper
|
||||
if (executable !== undefined) {
|
||||
core.addPath(path.dirname(executable))
|
||||
}
|
||||
// Download and install Gradle if required
|
||||
const executable = await provisioner.provisionGradle()
|
||||
|
||||
// Only execute if arguments have been provided
|
||||
const args: string[] = parseCommandLineArguments()
|
||||
const args: string[] = params.getArguments()
|
||||
if (args.length > 0) {
|
||||
const buildRootDirectory = layout.buildRootDirectory()
|
||||
await execution.executeGradleBuild(executable, buildRootDirectory, args)
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -36,29 +32,3 @@ export async function run(): Promise<void> {
|
||||
}
|
||||
|
||||
run()
|
||||
|
||||
async function provisionGradle(workspaceDirectory: string): Promise<string | undefined> {
|
||||
const gradleVersion = core.getInput('gradle-version')
|
||||
if (gradleVersion !== '' && gradleVersion !== 'wrapper') {
|
||||
return path.resolve(await provision.gradleVersion(gradleVersion))
|
||||
}
|
||||
|
||||
const gradleExecutable = core.getInput('gradle-executable')
|
||||
if (gradleExecutable !== '') {
|
||||
return path.resolve(workspaceDirectory, gradleExecutable)
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
function resolveBuildRootDirectory(baseDirectory: string): string {
|
||||
const buildRootDirectory = core.getInput('build-root-directory')
|
||||
const resolvedBuildRootDirectory =
|
||||
buildRootDirectory === '' ? path.resolve(baseDirectory) : path.resolve(baseDirectory, buildRootDirectory)
|
||||
return resolvedBuildRootDirectory
|
||||
}
|
||||
|
||||
function parseCommandLineArguments(): string[] {
|
||||
const input = core.getInput('arguments')
|
||||
return parseArgsStringToArgv(input)
|
||||
}
|
||||
|
@@ -7,14 +7,37 @@ import * as cache from '@actions/cache'
|
||||
import * as toolCache from '@actions/tool-cache'
|
||||
|
||||
import * as gradlew from './gradlew'
|
||||
import * as params from './input-params'
|
||||
import * as layout from './repository-layout'
|
||||
import {handleCacheFailure, isCacheDisabled, isCacheReadOnly} from './cache-utils'
|
||||
|
||||
const gradleVersionsBaseUrl = 'https://services.gradle.org/versions'
|
||||
|
||||
/**
|
||||
* @return Gradle executable path
|
||||
* Install any configured version of Gradle, adding the executable to the PATH.
|
||||
* @return Installed Gradle executable or undefined if no version configured.
|
||||
*/
|
||||
export async function gradleVersion(version: string): Promise<string> {
|
||||
export async function provisionGradle(): Promise<string | undefined> {
|
||||
const gradleVersion = params.getGradleVersion()
|
||||
if (gradleVersion !== '' && gradleVersion !== 'wrapper') {
|
||||
return addToPath(path.resolve(await installGradle(gradleVersion)))
|
||||
}
|
||||
|
||||
const gradleExecutable = params.getGradleExecutable()
|
||||
if (gradleExecutable !== '') {
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
return addToPath(path.resolve(workspaceDirectory, gradleExecutable))
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
async function addToPath(executable: string): Promise<string> {
|
||||
core.addPath(path.dirname(executable))
|
||||
return executable
|
||||
}
|
||||
|
||||
async function installGradle(version: string): Promise<string> {
|
||||
switch (version) {
|
||||
case 'current':
|
||||
return gradleCurrent()
|
||||
@@ -34,13 +57,13 @@ export async function gradleVersion(version: string): Promise<string> {
|
||||
|
||||
async function gradleCurrent(): Promise<string> {
|
||||
const versionInfo = await gradleVersionDeclaration(`${gradleVersionsBaseUrl}/current`)
|
||||
return provisionGradle(versionInfo)
|
||||
return installGradleVersion(versionInfo)
|
||||
}
|
||||
|
||||
async function gradleReleaseCandidate(): Promise<string> {
|
||||
const versionInfo = await gradleVersionDeclaration(`${gradleVersionsBaseUrl}/release-candidate`)
|
||||
if (versionInfo && versionInfo.version && versionInfo.downloadUrl) {
|
||||
return provisionGradle(versionInfo)
|
||||
return installGradleVersion(versionInfo)
|
||||
}
|
||||
core.info('No current release-candidate found, will fallback to current')
|
||||
return gradleCurrent()
|
||||
@@ -48,12 +71,12 @@ async function gradleReleaseCandidate(): Promise<string> {
|
||||
|
||||
async function gradleNightly(): Promise<string> {
|
||||
const versionInfo = await gradleVersionDeclaration(`${gradleVersionsBaseUrl}/nightly`)
|
||||
return provisionGradle(versionInfo)
|
||||
return installGradleVersion(versionInfo)
|
||||
}
|
||||
|
||||
async function gradleReleaseNightly(): Promise<string> {
|
||||
const versionInfo = await gradleVersionDeclaration(`${gradleVersionsBaseUrl}/release-nightly`)
|
||||
return provisionGradle(versionInfo)
|
||||
return installGradleVersion(versionInfo)
|
||||
}
|
||||
|
||||
async function gradle(version: string): Promise<string> {
|
||||
@@ -61,7 +84,7 @@ async function gradle(version: string): Promise<string> {
|
||||
if (!versionInfo) {
|
||||
throw new Error(`Gradle version ${version} does not exists`)
|
||||
}
|
||||
return provisionGradle(versionInfo)
|
||||
return installGradleVersion(versionInfo)
|
||||
}
|
||||
|
||||
async function gradleVersionDeclaration(url: string): Promise<GradleVersionInfo> {
|
||||
@@ -75,7 +98,7 @@ async function findGradleVersionDeclaration(version: string): Promise<GradleVers
|
||||
})
|
||||
}
|
||||
|
||||
async function provisionGradle(versionInfo: GradleVersionInfo): Promise<string> {
|
||||
async function installGradleVersion(versionInfo: GradleVersionInfo): Promise<string> {
|
||||
return core.group(`Provision Gradle ${versionInfo.version}`, async () => {
|
||||
return locateGradleAndDownloadIfRequired(versionInfo)
|
||||
})
|
||||
|
16
src/repository-layout.ts
Normal file
16
src/repository-layout.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as params from './input-params'
|
||||
import * as path from 'path'
|
||||
|
||||
export function workspaceDirectory(): string {
|
||||
return process.env[`GITHUB_WORKSPACE`] || ''
|
||||
}
|
||||
|
||||
export function buildRootDirectory(): string {
|
||||
const baseDirectory = workspaceDirectory()
|
||||
const buildRootDirectoryInput = params.getBuildRootDirectory()
|
||||
const resolvedBuildRootDirectory =
|
||||
buildRootDirectoryInput === ''
|
||||
? path.resolve(baseDirectory)
|
||||
: path.resolve(baseDirectory, buildRootDirectoryInput)
|
||||
return resolvedBuildRootDirectory
|
||||
}
|
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Capture information for each executed Gradle build to display in the job summary.
|
||||
*/
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
// Only run against root build. Do not run against included builds.
|
||||
def isTopLevelBuild = gradle.getParent() == null
|
||||
if (isTopLevelBuild) {
|
||||
def version = GradleVersion.current().baseVersion
|
||||
|
||||
def atLeastGradle3 = version >= GradleVersion.version("3.0")
|
||||
def atLeastGradle6 = version >= GradleVersion.version("6.0")
|
||||
|
||||
def invocationId = "-${System.currentTimeMillis()}"
|
||||
|
||||
if (atLeastGradle6) {
|
||||
def useBuildService = version >= GradleVersion.version("6.6")
|
||||
settingsEvaluated { settings ->
|
||||
// The `buildScanPublished` hook is the only way to capture the build scan URI.
|
||||
if (settings.pluginManager.hasPlugin("com.gradle.enterprise")) {
|
||||
captureUsingBuildScanPublished(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject, invocationId)
|
||||
}
|
||||
// We also need to add hooks in case the plugin is applied but no build scan is published
|
||||
if (useBuildService) {
|
||||
captureUsingBuildService(settings, invocationId)
|
||||
} else {
|
||||
captureUsingBuildFinished(gradle, invocationId)
|
||||
}
|
||||
}
|
||||
} else if (atLeastGradle3) {
|
||||
projectsEvaluated { gradle ->
|
||||
if (gradle.rootProject.pluginManager.hasPlugin("com.gradle.build-scan")) {
|
||||
captureUsingBuildScanPublished(gradle.rootProject.extensions["buildScan"], gradle.rootProject, invocationId)
|
||||
}
|
||||
// We need to capture in buildFinished in case the plugin is applied but no build scan is published
|
||||
captureUsingBuildFinished(gradle, invocationId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def captureUsingBuildScanPublished(buildScanExtension, rootProject, invocationId) {
|
||||
buildScanExtension.with {
|
||||
def requestedTasks = gradle.startParameter.taskNames.join(" ")
|
||||
def rootProjectName = rootProject.name
|
||||
def rootProjectDir = rootProject.projectDir.absolutePath
|
||||
def gradleVersion = GradleVersion.current().version
|
||||
def gradleHomeDir = gradle.gradleHomeDir.absolutePath
|
||||
def buildFailed = false
|
||||
|
||||
buildFinished { result ->
|
||||
buildFailed = (result.failure != null)
|
||||
}
|
||||
|
||||
buildScanPublished { buildScan ->
|
||||
|
||||
def buildScanUri = buildScan.buildScanUri.toASCIIString()
|
||||
def buildResults = [
|
||||
rootProjectName: rootProjectName,
|
||||
rootProjectDir: rootProjectDir,
|
||||
requestedTasks: requestedTasks,
|
||||
gradleVersion: gradleVersion,
|
||||
gradleHomeDir: gradleHomeDir,
|
||||
buildFailed: buildFailed,
|
||||
buildScanUri: buildScanUri
|
||||
]
|
||||
|
||||
def buildResultsDir = new File(System.getenv("RUNNER_TEMP"), ".build-results")
|
||||
buildResultsDir.mkdirs()
|
||||
def buildResultsFile = new File(buildResultsDir, System.getenv("GITHUB_ACTION") + invocationId + ".json")
|
||||
|
||||
// Overwrite any contents written by buildFinished or build service, since this result is a superset.
|
||||
if (buildResultsFile.exists()) {
|
||||
buildResultsFile.text = groovy.json.JsonOutput.toJson(buildResults)
|
||||
} else {
|
||||
buildResultsFile << groovy.json.JsonOutput.toJson(buildResults)
|
||||
}
|
||||
|
||||
println("::set-output name=build-scan-url::${buildScan.buildScanUri}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def captureUsingBuildFinished(gradle, invocationId) {
|
||||
gradle.buildFinished { result ->
|
||||
def buildResults = [
|
||||
rootProjectName: gradle.rootProject.name,
|
||||
rootProjectDir: gradle.rootProject.rootDir.absolutePath,
|
||||
requestedTasks: gradle.startParameter.taskNames.join(" "),
|
||||
gradleVersion: GradleVersion.current().version,
|
||||
gradleHomeDir: gradle.gradleHomeDir.absolutePath,
|
||||
buildFailed: result.failure != null,
|
||||
buildScanUri: null
|
||||
]
|
||||
|
||||
def buildResultsDir = new File(System.getenv("RUNNER_TEMP"), ".build-results")
|
||||
buildResultsDir.mkdirs()
|
||||
def buildResultsFile = new File(buildResultsDir, System.getenv("GITHUB_ACTION") + invocationId + ".json")
|
||||
// Don't overwrite file generated by build-scan plugin if present (which has build-scan-uri)
|
||||
if (!buildResultsFile.exists()) {
|
||||
buildResultsFile << groovy.json.JsonOutput.toJson(buildResults)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def captureUsingBuildService(settings, invocationId) {
|
||||
gradle.ext.invocationId = invocationId
|
||||
apply from: 'build-result-capture-service.plugin.groovy'
|
||||
}
|
@@ -41,12 +41,21 @@ abstract class BuildResultsRecorder implements BuildService<BuildResultsRecorder
|
||||
gradleVersion: GradleVersion.current().version,
|
||||
gradleHomeDir: getParameters().getGradleHomeDir().get(),
|
||||
buildFailed: buildFailed,
|
||||
buildScanUri: null
|
||||
buildScanUri: null,
|
||||
buildScanFailed: false
|
||||
]
|
||||
|
||||
def buildResultsDir = new File(System.getenv("RUNNER_TEMP"), ".build-results")
|
||||
def runnerTempDir = System.getenv("RUNNER_TEMP")
|
||||
def githubActionStep = System.getenv("GITHUB_ACTION")
|
||||
if (!runnerTempDir || !githubActionStep) {
|
||||
return
|
||||
}
|
||||
|
||||
def buildResultsDir = new File(runnerTempDir, ".build-results")
|
||||
buildResultsDir.mkdirs()
|
||||
def buildResultsFile = new File(buildResultsDir, System.getenv("GITHUB_ACTION") + getParameters().getInvocationId().get() + ".json")
|
||||
buildResultsFile << groovy.json.JsonOutput.toJson(buildResults)
|
||||
def buildResultsFile = new File(buildResultsDir, githubActionStep + getParameters().getInvocationId().get() + ".json")
|
||||
if (!buildResultsFile.exists()) {
|
||||
buildResultsFile << groovy.json.JsonOutput.toJson(buildResults)
|
||||
}
|
||||
}
|
||||
}
|
138
src/resources/init-scripts/build-result-capture.init.gradle
Normal file
138
src/resources/init-scripts/build-result-capture.init.gradle
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Capture information for each executed Gradle build to display in the job summary.
|
||||
*/
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
// Only run against root build. Do not run against included builds.
|
||||
def isTopLevelBuild = gradle.getParent() == null
|
||||
if (isTopLevelBuild) {
|
||||
def version = GradleVersion.current().baseVersion
|
||||
|
||||
def atLeastGradle3 = version >= GradleVersion.version("3.0")
|
||||
def atLeastGradle6 = version >= GradleVersion.version("6.0")
|
||||
|
||||
def invocationId = "-${System.currentTimeMillis()}"
|
||||
|
||||
if (atLeastGradle6) {
|
||||
def useBuildService = version >= GradleVersion.version("6.6")
|
||||
settingsEvaluated { settings ->
|
||||
// By default, use standard mechanisms to capture build results
|
||||
if (useBuildService) {
|
||||
captureUsingBuildService(settings, invocationId)
|
||||
} else {
|
||||
captureUsingBuildFinished(gradle, invocationId)
|
||||
}
|
||||
|
||||
// The `buildScanPublished` hook allows the capture of the build scan URI.
|
||||
// Results captured this way will overwrite any results from the other mechanism.
|
||||
settings.pluginManager.withPlugin("com.gradle.enterprise") {
|
||||
captureUsingBuildScanPublished(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject, invocationId)
|
||||
}
|
||||
}
|
||||
} else if (atLeastGradle3) {
|
||||
projectsEvaluated { gradle ->
|
||||
// By default, use 'buildFinished' to capture build results
|
||||
captureUsingBuildFinished(gradle, invocationId)
|
||||
|
||||
// The `buildScanPublished` hook allows the capture of the build scan URI.
|
||||
// Results captured this way will overwrite any results from 'buildFinished'.
|
||||
gradle.rootProject.pluginManager.withPlugin("com.gradle.build-scan") {
|
||||
captureUsingBuildScanPublished(gradle.rootProject.extensions["buildScan"], gradle.rootProject, invocationId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def captureUsingBuildScanPublished(buildScanExtension, rootProject, invocationId) {
|
||||
buildScanExtension.with {
|
||||
def buildResults = new BuildResults(invocationId, gradle, rootProject)
|
||||
|
||||
buildFinished { result ->
|
||||
buildResults.setBuildResult(result)
|
||||
}
|
||||
|
||||
buildScanPublished { buildScan ->
|
||||
buildResults.setBuildScanUri(buildScan.buildScanUri.toASCIIString())
|
||||
buildResults.writeToResultsFile(true)
|
||||
|
||||
def githubOutput = System.getenv("GITHUB_OUTPUT")
|
||||
if (githubOutput) {
|
||||
new File(githubOutput) << "build-scan-url=${buildScan.buildScanUri}\n"
|
||||
} else {
|
||||
// Retained for compatibility with older GitHub Enterprise versions
|
||||
println("::set-output name=build-scan-url::${buildScan.buildScanUri}")
|
||||
}
|
||||
}
|
||||
|
||||
onError { error ->
|
||||
buildResults.setBuildScanFailed()
|
||||
buildResults.writeToResultsFile(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def captureUsingBuildFinished(gradle, invocationId) {
|
||||
gradle.buildFinished { result ->
|
||||
println "Got buildFinished: ${result}"
|
||||
def buildResults = new BuildResults(invocationId, gradle, gradle.rootProject)
|
||||
buildResults.setBuildResult(result)
|
||||
buildResults.writeToResultsFile(false)
|
||||
}
|
||||
}
|
||||
|
||||
def captureUsingBuildService(settings, invocationId) {
|
||||
gradle.ext.invocationId = invocationId
|
||||
apply from: 'build-result-capture-service.plugin.groovy'
|
||||
}
|
||||
|
||||
class BuildResults {
|
||||
def invocationId
|
||||
def buildResults
|
||||
|
||||
BuildResults(String invocationId, def gradle, def rootProject) {
|
||||
this.invocationId = invocationId
|
||||
buildResults = [
|
||||
rootProjectName: rootProject.name,
|
||||
rootProjectDir: rootProject.projectDir.absolutePath,
|
||||
requestedTasks: gradle.startParameter.taskNames.join(" "),
|
||||
gradleVersion: GradleVersion.current().version,
|
||||
gradleHomeDir: gradle.gradleHomeDir.absolutePath,
|
||||
buildFailed: false,
|
||||
buildScanUri: null,
|
||||
buildScanFailed: false
|
||||
]
|
||||
}
|
||||
|
||||
def setBuildResult(def result) {
|
||||
buildResults['buildFailed'] = result.failure != null
|
||||
}
|
||||
|
||||
def setBuildScanUri(def buildScanUrl) {
|
||||
buildResults['buildScanUri'] = buildScanUrl
|
||||
}
|
||||
|
||||
def setBuildScanFailed() {
|
||||
buildResults['buildScanFailed'] = true
|
||||
}
|
||||
|
||||
def writeToResultsFile(boolean overwrite) {
|
||||
def runnerTempDir = System.getenv("RUNNER_TEMP")
|
||||
def githubActionStep = System.getenv("GITHUB_ACTION")
|
||||
if (!runnerTempDir || !githubActionStep) {
|
||||
return
|
||||
}
|
||||
|
||||
def buildResultsDir = new File(runnerTempDir, ".build-results")
|
||||
buildResultsDir.mkdirs()
|
||||
def buildResultsFile = new File(buildResultsDir, githubActionStep + invocationId + ".json")
|
||||
|
||||
// Overwrite any contents written by buildFinished or build service, since this result is a superset.
|
||||
if (buildResultsFile.exists()) {
|
||||
if (overwrite) {
|
||||
buildResultsFile.text = groovy.json.JsonOutput.toJson(buildResults)
|
||||
}
|
||||
} else {
|
||||
buildResultsFile << groovy.json.JsonOutput.toJson(buildResults)
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
import org.gradle.github.GitHubDependencyGraphPlugin
|
||||
initscript {
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://plugins.gradle.org/m2/")
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.gradle:github-dependency-graph-gradle-plugin:+")
|
||||
}
|
||||
}
|
||||
apply plugin: GitHubDependencyGraphPlugin
|
@@ -1,24 +1,23 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
import * as fs from 'fs'
|
||||
import {SUMMARY_ENV_VAR} from '@actions/core/lib/summary'
|
||||
import * as path from 'path'
|
||||
import * as os from 'os'
|
||||
import * as caches from './caches'
|
||||
import * as layout from './repository-layout'
|
||||
import * as params from './input-params'
|
||||
|
||||
import {logJobSummary, writeJobSummary} from './job-summary'
|
||||
import {loadBuildResults} from './build-results'
|
||||
import {CacheListener} from './cache-reporting'
|
||||
import {BuildResult, loadBuildResults, writeJobSummary} from './job-summary'
|
||||
import {DaemonController} from './daemon-controller'
|
||||
|
||||
const GRADLE_SETUP_VAR = 'GRADLE_BUILD_ACTION_SETUP_COMPLETED'
|
||||
const GRADLE_USER_HOME = 'GRADLE_USER_HOME'
|
||||
const CACHE_LISTENER = 'CACHE_LISTENER'
|
||||
const JOB_SUMMARY_ENABLED_PARAMETER = 'generate-job-summary'
|
||||
|
||||
function generateJobSummary(): boolean {
|
||||
return core.getBooleanInput(JOB_SUMMARY_ENABLED_PARAMETER)
|
||||
}
|
||||
|
||||
export async function setup(buildRootDirectory: string): Promise<void> {
|
||||
const gradleUserHome = await determineGradleUserHome(buildRootDirectory)
|
||||
export async function setup(): Promise<void> {
|
||||
const gradleUserHome = await determineGradleUserHome()
|
||||
|
||||
// Bypass setup on all but first action step in workflow.
|
||||
if (process.env[GRADLE_SETUP_VAR]) {
|
||||
@@ -44,26 +43,27 @@ export async function complete(): Promise<void> {
|
||||
core.info('Gradle setup post-action only performed for first gradle-build-action step in workflow.')
|
||||
return
|
||||
}
|
||||
core.info('In final post-action step, saving state and writing summary')
|
||||
|
||||
const buildResults = loadBuildResults()
|
||||
|
||||
core.info('Stopping all Gradle daemons')
|
||||
await stopAllDaemons(getUniqueGradleHomes(buildResults))
|
||||
|
||||
core.info('In final post-action step, saving state and writing summary')
|
||||
const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER))
|
||||
|
||||
const gradleUserHome = core.getState(GRADLE_USER_HOME)
|
||||
await caches.save(gradleUserHome, cacheListener)
|
||||
const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER))
|
||||
const daemonController = new DaemonController(buildResults)
|
||||
|
||||
if (generateJobSummary()) {
|
||||
writeJobSummary(buildResults, cacheListener)
|
||||
await caches.save(gradleUserHome, cacheListener, daemonController)
|
||||
|
||||
if (shouldGenerateJobSummary()) {
|
||||
await writeJobSummary(buildResults, cacheListener)
|
||||
} else {
|
||||
logJobSummary(buildResults, cacheListener)
|
||||
}
|
||||
}
|
||||
|
||||
async function determineGradleUserHome(rootDir: string): Promise<string> {
|
||||
async function determineGradleUserHome(): Promise<string> {
|
||||
const customGradleUserHome = process.env['GRADLE_USER_HOME']
|
||||
if (customGradleUserHome) {
|
||||
const rootDir = layout.workspaceDirectory()
|
||||
return path.resolve(rootDir, customGradleUserHome)
|
||||
}
|
||||
|
||||
@@ -87,27 +87,11 @@ async function determineUserHome(): Promise<string> {
|
||||
return userHome
|
||||
}
|
||||
|
||||
function getUniqueGradleHomes(buildResults: BuildResult[]): string[] {
|
||||
const gradleHomes = buildResults.map(buildResult => buildResult.gradleHomeDir)
|
||||
return Array.from(new Set(gradleHomes))
|
||||
}
|
||||
|
||||
async function stopAllDaemons(gradleHomes: string[]): Promise<void> {
|
||||
const executions: Promise<number>[] = []
|
||||
const args = ['--stop']
|
||||
|
||||
for (const gradleHome of gradleHomes) {
|
||||
const executable = path.resolve(gradleHome, 'bin', 'gradle')
|
||||
if (!fs.existsSync(executable)) {
|
||||
core.warning(`Gradle executable not found at ${executable}. Could not stop Gradle daemons.`)
|
||||
continue
|
||||
}
|
||||
core.info(`Stopping Gradle daemons in ${gradleHome}`)
|
||||
executions.push(
|
||||
exec.exec(executable, args, {
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
)
|
||||
function shouldGenerateJobSummary(): boolean {
|
||||
// Check if Job Summary is supported on this platform
|
||||
if (!process.env[SUMMARY_ENV_VAR]) {
|
||||
return false
|
||||
}
|
||||
await Promise.all(executions)
|
||||
|
||||
return params.isJobSummaryEnabled()
|
||||
}
|
||||
|
@@ -14,14 +14,13 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
testImplementation gradleTestKit()
|
||||
testImplementation 'org.spockframework:spock-core:2.1-groovy-3.0'
|
||||
testImplementation('org.spockframework:spock-junit4:2.1-groovy-3.0')
|
||||
testImplementation 'org.spockframework:spock-core:2.3-groovy-3.0'
|
||||
testImplementation('org.spockframework:spock-junit4:2.3-groovy-3.0')
|
||||
|
||||
testImplementation ('io.ratpack:ratpack-groovy-test:1.9.0') {
|
||||
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
|
||||
}
|
||||
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.13.3'
|
||||
|
||||
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.15.2'
|
||||
}
|
||||
|
||||
test {
|
BIN
test/init-scripts/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
test/init-scripts/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
@@ -1,5 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
@@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -80,13 +80,10 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# 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"'
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -143,12 +140,16 @@ fi
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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
|
||||
@@ -205,6 +210,12 @@ set -- \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,8 @@
|
||||
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%
|
||||
|
||||
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
14
test/init-scripts/settings.gradle
Normal file
14
test/init-scripts/settings.gradle
Normal file
@@ -0,0 +1,14 @@
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.13.4"
|
||||
id "com.gradle.common-custom-user-data-gradle-plugin" version "1.11"
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
buildScan {
|
||||
termsOfServiceUrl = "https://gradle.com/terms-of-service"
|
||||
termsOfServiceAgree = "yes"
|
||||
publishAlways()
|
||||
uploadInBackground = false
|
||||
}
|
||||
}
|
||||
rootProject.name = 'test-init-scripts'
|
@@ -17,34 +17,34 @@ import java.util.zip.GZIPOutputStream
|
||||
|
||||
class BaseInitScriptTest extends Specification {
|
||||
|
||||
static final TestGradleVersion GRADLE_3_5 = new TestGradleVersion(GradleVersion.version('3.5.1'), 7, 9)
|
||||
static final TestGradleVersion GRADLE_4_0 = new TestGradleVersion(GradleVersion.version('4.0.2'), 7, 9)
|
||||
static final TestGradleVersion GRADLE_4_10 = new TestGradleVersion(GradleVersion.version('4.10.3'), 7, 10)
|
||||
static final TestGradleVersion GRADLE_5_0 = new TestGradleVersion(GradleVersion.version('5.0'), 8, 11)
|
||||
static final TestGradleVersion GRADLE_5_6 = new TestGradleVersion(GradleVersion.version('5.6.4'), 8, 12)
|
||||
static final TestGradleVersion GRADLE_6_0 = new TestGradleVersion(GradleVersion.version('6.0.1'), 8, 13)
|
||||
static final TestGradleVersion GRADLE_6_7 = new TestGradleVersion(GradleVersion.version('6.7'), 8, 15)
|
||||
static final TestGradleVersion GRADLE_7_0 = new TestGradleVersion(GradleVersion.version('7.0.2'), 8, 16)
|
||||
static final TestGradleVersion GRADLE_7_4 = new TestGradleVersion(GradleVersion.version('7.4.2'), 8, 17)
|
||||
static final TestGradleVersion GRADLE_3_X = new TestGradleVersion(GradleVersion.version('3.5.1'), 7, 9)
|
||||
static final TestGradleVersion GRADLE_4_X = new TestGradleVersion(GradleVersion.version('4.10.3'), 7, 10)
|
||||
static final TestGradleVersion GRADLE_5_X = new TestGradleVersion(GradleVersion.version('5.6.4'), 8, 12)
|
||||
static final TestGradleVersion GRADLE_6_NO_BUILD_SERVICE = new TestGradleVersion(GradleVersion.version('6.5.1'), 8, 14)
|
||||
static final TestGradleVersion GRADLE_6_X = new TestGradleVersion(GradleVersion.version('6.9.4'), 8, 15)
|
||||
static final TestGradleVersion GRADLE_7_X = new TestGradleVersion(GradleVersion.version('7.6.1'), 8, 19)
|
||||
static final TestGradleVersion GRADLE_8_X = new TestGradleVersion(GradleVersion.version('8.0.2'), 8, 19)
|
||||
|
||||
static final List<TestGradleVersion> ALL_VERSIONS = [
|
||||
GRADLE_3_5, // First version where TestKit supports environment variables
|
||||
GRADLE_4_0,
|
||||
GRADLE_4_10,
|
||||
GRADLE_5_0,
|
||||
GRADLE_5_6,
|
||||
GRADLE_6_0,
|
||||
GRADLE_6_7,
|
||||
GRADLE_7_0,
|
||||
GRADLE_7_4,
|
||||
GRADLE_3_X, // First version where TestKit supports environment variables
|
||||
GRADLE_4_X,
|
||||
GRADLE_5_X,
|
||||
GRADLE_6_NO_BUILD_SERVICE, // Last version without build service support
|
||||
GRADLE_6_X,
|
||||
GRADLE_7_X,
|
||||
GRADLE_8_X,
|
||||
]
|
||||
|
||||
static final List<TestGradleVersion> CONFIGURATION_CACHE_VERSIONS =
|
||||
[GRADLE_7_0, GRADLE_7_4]
|
||||
[GRADLE_7_X, GRADLE_8_X]
|
||||
|
||||
static final List<TestGradleVersion> SETTINGS_PLUGIN_VERSIONS =
|
||||
[GRADLE_6_X, GRADLE_7_X, GRADLE_8_X]
|
||||
|
||||
static final String PUBLIC_BUILD_SCAN_ID = 'i2wepy2gr7ovw'
|
||||
static final String DEFAULT_SCAN_UPLOAD_TOKEN = 'scan-upload-token'
|
||||
static final String ROOT_PROJECT_NAME = 'test-init-script'
|
||||
boolean failScanUpload = false
|
||||
|
||||
File settingsFile
|
||||
File buildFile
|
||||
@@ -59,6 +59,10 @@ class BaseInitScriptTest extends Specification {
|
||||
|
||||
handlers {
|
||||
post('in/:gradleVersion/:pluginVersion') {
|
||||
if (failScanUpload) {
|
||||
context.response.status(401).send()
|
||||
return
|
||||
}
|
||||
def scanUrlString = "${mockScansServer.address}s/$PUBLIC_BUILD_SCAN_ID"
|
||||
def body = [
|
||||
id : PUBLIC_BUILD_SCAN_ID,
|
||||
@@ -72,6 +76,10 @@ class BaseInitScriptTest extends Specification {
|
||||
}
|
||||
prefix('scans/publish') {
|
||||
post('gradle/:pluginVersion/token') {
|
||||
if (failScanUpload) {
|
||||
context.response.status(401).send()
|
||||
return
|
||||
}
|
||||
def pluginVersion = context.pathTokens.pluginVersion
|
||||
def scanUrlString = "${mockScansServer.address}s/$PUBLIC_BUILD_SCAN_ID"
|
||||
def body = [
|
||||
@@ -85,6 +93,10 @@ class BaseInitScriptTest extends Specification {
|
||||
.send(jsonWriter.writeValueAsBytes(body))
|
||||
}
|
||||
post('gradle/:pluginVersion/upload') {
|
||||
if (failScanUpload) {
|
||||
context.response.status(401).send()
|
||||
return
|
||||
}
|
||||
context.request.getBody(1024 * 1024 * 10).then {
|
||||
context.response
|
||||
.contentType('application/vnd.gradle.scan-upload-ack+json')
|
||||
@@ -100,7 +112,7 @@ class BaseInitScriptTest extends Specification {
|
||||
settingsFile = new File(testProjectDir, 'settings.gradle')
|
||||
buildFile = new File(testProjectDir, 'build.gradle')
|
||||
|
||||
File srcInitScriptsDir = new File("../../src/resources")
|
||||
File srcInitScriptsDir = new File("../../src/resources/init-scripts")
|
||||
File targetInitScriptsDir = new File(testProjectDir, "initScripts")
|
||||
targetInitScriptsDir.mkdirs()
|
||||
|
||||
@@ -125,7 +137,7 @@ class BaseInitScriptTest extends Specification {
|
||||
} else {
|
||||
"""
|
||||
plugins {
|
||||
id 'com.gradle.enterprise' version '3.4.1'
|
||||
id 'com.gradle.enterprise' version '3.13.4'
|
||||
}
|
||||
gradleEnterprise {
|
||||
server = '$mockScansServer.address'
|
||||
@@ -151,7 +163,7 @@ class BaseInitScriptTest extends Specification {
|
||||
} else if (gradleVersion < GradleVersion.version('6.0')) {
|
||||
"""
|
||||
plugins {
|
||||
id 'com.gradle.build-scan' version '3.4.1'
|
||||
id 'com.gradle.build-scan' version '3.13.4'
|
||||
}
|
||||
gradleEnterprise {
|
||||
server = '$mockScansServer.address'
|
||||
@@ -187,20 +199,17 @@ task expectFailure {
|
||||
File initScriptsDir = new File(testProjectDir, "initScripts")
|
||||
args << '-I' << new File(initScriptsDir, initScript).absolutePath
|
||||
|
||||
envVars['RUNNER_TEMP'] = testProjectDir.absolutePath
|
||||
envVars['GITHUB_ACTION'] = 'github-step-id'
|
||||
envVars.putIfAbsent('RUNNER_TEMP', testProjectDir.absolutePath)
|
||||
envVars.putIfAbsent('GITHUB_ACTION', 'github-step-id')
|
||||
|
||||
def runner = ((DefaultGradleRunner) GradleRunner.create())
|
||||
.withJvmArguments(jvmArgs)
|
||||
.withGradleVersion(gradleVersion.version)
|
||||
.withProjectDir(testProjectDir)
|
||||
.withArguments(args)
|
||||
.withEnvironment(envVars)
|
||||
.forwardOutput()
|
||||
|
||||
if (envVars) {
|
||||
runner.withEnvironment(envVars)
|
||||
}
|
||||
|
||||
runner
|
||||
}
|
||||
|
@@ -118,7 +118,65 @@ class TestBuildResultRecorder extends BaseInitScriptTest {
|
||||
testGradleVersion << CONFIGURATION_CACHE_VERSIONS
|
||||
}
|
||||
|
||||
void assertResults(String task, TestGradleVersion testGradleVersion, boolean hasFailure, boolean hasBuildScan) {
|
||||
def "produces build results file for failing build on #testGradleVersion when build scan publish fails"() {
|
||||
assumeTrue testGradleVersion.compatibleWithCurrentJvm
|
||||
|
||||
when:
|
||||
declareGePluginApplication(testGradleVersion.gradleVersion)
|
||||
addFailingTaskToBuild()
|
||||
failScanUpload = true
|
||||
runAndFail(['expectFailure'], initScript, testGradleVersion.gradleVersion)
|
||||
|
||||
then:
|
||||
assertResults('expectFailure', testGradleVersion, true, false, true)
|
||||
|
||||
where:
|
||||
testGradleVersion << ALL_VERSIONS
|
||||
}
|
||||
|
||||
def "produces no build results file when GitHub env vars not set with #testGradleVersion"() {
|
||||
assumeTrue testGradleVersion.compatibleWithCurrentJvm
|
||||
|
||||
when:
|
||||
run(['help'], initScript, testGradleVersion.gradleVersion, [], [RUNNER_TEMP: '', GITHUB_ACTION: ''])
|
||||
|
||||
then:
|
||||
def buildResultsDir = new File(testProjectDir, '.build-results')
|
||||
assert !buildResultsDir.exists()
|
||||
|
||||
where:
|
||||
testGradleVersion << ALL_VERSIONS
|
||||
}
|
||||
|
||||
def "produces build results file with build scan when GE plugin is applied in settingsEvaluated"() {
|
||||
assumeTrue testGradleVersion.compatibleWithCurrentJvm
|
||||
|
||||
when:
|
||||
settingsFile.text = """
|
||||
plugins {
|
||||
id 'com.gradle.enterprise' version '3.13.4' apply(false)
|
||||
}
|
||||
gradle.settingsEvaluated {
|
||||
apply plugin: 'com.gradle.enterprise'
|
||||
gradleEnterprise {
|
||||
server = '$mockScansServer.address'
|
||||
buildScan {
|
||||
publishAlways()
|
||||
}
|
||||
}
|
||||
}
|
||||
""" + settingsFile.text
|
||||
|
||||
run(['help'], initScript, testGradleVersion.gradleVersion)
|
||||
|
||||
then:
|
||||
assertResults('help', testGradleVersion, false, true)
|
||||
|
||||
where:
|
||||
testGradleVersion << SETTINGS_PLUGIN_VERSIONS
|
||||
}
|
||||
|
||||
void assertResults(String task, TestGradleVersion testGradleVersion, boolean hasFailure, boolean hasBuildScan, boolean scanUploadFailed = false) {
|
||||
def results = new JsonSlurper().parse(buildResultFile)
|
||||
assert results['rootProjectName'] == ROOT_PROJECT_NAME
|
||||
assert results['rootProjectDir'] == testProjectDir.canonicalPath
|
||||
@@ -127,6 +185,7 @@ class TestBuildResultRecorder extends BaseInitScriptTest {
|
||||
assert results['gradleHomeDir'] != null
|
||||
assert results['buildFailed'] == hasFailure
|
||||
assert results['buildScanUri'] == (hasBuildScan ? "${mockScansServer.address}s/${PUBLIC_BUILD_SCAN_ID}" : null)
|
||||
assert results['buildScanFailed'] == scanUploadFailed
|
||||
}
|
||||
|
||||
private File getBuildResultFile() {
|
87
test/jest/cache-cleanup.test.ts
Normal file
87
test/jest/cache-cleanup.test.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import * as exec from '@actions/exec'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import {CacheCleaner} from '../../src/cache-cleaner'
|
||||
|
||||
jest.setTimeout(120000)
|
||||
|
||||
test('will cleanup unused dependency jars and build-cache entries', async () => {
|
||||
const projectRoot = prepareTestProject()
|
||||
const gradleUserHome = path.resolve(projectRoot, 'HOME')
|
||||
const tmpDir = path.resolve(projectRoot, 'tmp')
|
||||
const cacheCleaner = new CacheCleaner(gradleUserHome, tmpDir)
|
||||
|
||||
await runGradleBuild(projectRoot, 'build', '3.1')
|
||||
|
||||
await cacheCleaner.prepare()
|
||||
|
||||
await runGradleBuild(projectRoot, 'build', '3.1.1')
|
||||
|
||||
const commonsMath31 = path.resolve(gradleUserHome, "caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.1")
|
||||
const commonsMath311 = path.resolve(gradleUserHome, "caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.1.1")
|
||||
const buildCacheDir = path.resolve(gradleUserHome, "caches/build-cache-1")
|
||||
|
||||
expect(fs.existsSync(commonsMath31)).toBe(true)
|
||||
expect(fs.existsSync(commonsMath311)).toBe(true)
|
||||
expect(fs.readdirSync(buildCacheDir).length).toBe(4)
|
||||
|
||||
await cacheCleaner.forceCleanup()
|
||||
|
||||
expect(fs.existsSync(commonsMath31)).toBe(false)
|
||||
expect(fs.existsSync(commonsMath311)).toBe(true)
|
||||
expect(fs.readdirSync(buildCacheDir).length).toBe(3)
|
||||
})
|
||||
|
||||
test('will cleanup unused gradle versions', async () => {
|
||||
const projectRoot = prepareTestProject()
|
||||
const gradleUserHome = path.resolve(projectRoot, 'HOME')
|
||||
const tmpDir = path.resolve(projectRoot, 'tmp')
|
||||
const cacheCleaner = new CacheCleaner(gradleUserHome, tmpDir)
|
||||
|
||||
// Initialize HOME with 2 different Gradle versions
|
||||
await runGradleWrapperBuild(projectRoot, 'build')
|
||||
await runGradleBuild(projectRoot, 'build')
|
||||
|
||||
await cacheCleaner.prepare()
|
||||
|
||||
// Run with only one of these versions
|
||||
await runGradleBuild(projectRoot, 'build')
|
||||
|
||||
const gradle802 = path.resolve(gradleUserHome, "caches/8.0.2")
|
||||
const wrapper802 = path.resolve(gradleUserHome, "wrapper/dists/gradle-8.0.2-bin")
|
||||
const gradleCurrent = path.resolve(gradleUserHome, "caches/8.1.1")
|
||||
|
||||
expect(fs.existsSync(gradle802)).toBe(true)
|
||||
expect(fs.existsSync(wrapper802)).toBe(true)
|
||||
expect(fs.existsSync(gradleCurrent)).toBe(true)
|
||||
|
||||
await cacheCleaner.forceCleanup()
|
||||
|
||||
expect(fs.existsSync(gradle802)).toBe(false)
|
||||
expect(fs.existsSync(wrapper802)).toBe(false)
|
||||
expect(fs.existsSync(gradleCurrent)).toBe(true)
|
||||
})
|
||||
|
||||
async function runGradleBuild(projectRoot: string, args: string, version: string = '3.1'): Promise<void> {
|
||||
const status31 = await exec.exec(`gradle -g HOME --no-daemon --build-cache -Dcommons_math3_version="${version}" ${args}`, [], {
|
||||
cwd: projectRoot
|
||||
})
|
||||
console.log(`Gradle User Home initialized with commons_math3_version=${version} ${args}`)
|
||||
}
|
||||
|
||||
async function runGradleWrapperBuild(projectRoot: string, args: string, version: string = '3.1'): Promise<void> {
|
||||
const status31 = await exec.exec(`./gradlew -g HOME --no-daemon --build-cache -Dcommons_math3_version="${version}" ${args}`, [], {
|
||||
cwd: projectRoot
|
||||
})
|
||||
console.log(`Gradle User Home initialized with commons_math3_version="${version}" ${args}`)
|
||||
}
|
||||
|
||||
function prepareTestProject(): string {
|
||||
const projectRoot = 'test/jest/resources/cache-cleanup'
|
||||
fs.rmSync(path.resolve(projectRoot, 'HOME'), { recursive: true, force: true })
|
||||
fs.rmSync(path.resolve(projectRoot, 'tmp'), { recursive: true, force: true })
|
||||
fs.rmSync(path.resolve(projectRoot, 'build'), { recursive: true, force: true })
|
||||
fs.rmSync(path.resolve(projectRoot, '.gradle'), { recursive: true, force: true })
|
||||
return projectRoot
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import {CacheEntryListener, CacheListener} from '../src/cache-reporting'
|
||||
import {CacheEntryListener, CacheListener} from '../../src/cache-reporting'
|
||||
|
||||
describe('caching report', () => {
|
||||
describe('reports not fully restored', () => {
|
@@ -1,4 +1,4 @@
|
||||
import * as cacheUtils from '../src/cache-utils'
|
||||
import * as cacheUtils from '../../src/cache-utils'
|
||||
|
||||
describe('cacheUtils-utils', () => {
|
||||
describe('can hash', () => {
|
@@ -3,3 +3,6 @@
|
||||
|
||||
# Ignore Gradle build output directory
|
||||
build
|
||||
|
||||
HOME
|
||||
tmp
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user