mirror of
https://github.com/gradle/gradle-build-action.git
synced 2025-10-19 22:38:58 +08:00
Compare commits
358 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
bd57605957 | ||
|
f464d5c9e5 | ||
|
cef72ff9e4 | ||
|
7a67f395d2 | ||
|
bc190ca89a | ||
|
f01b48d89d | ||
|
1e71bceb3f | ||
|
9a4d99b236 | ||
|
33f9bc031c | ||
|
437bff62b6 | ||
|
c0186c5832 | ||
|
ee7ca6ac9b | ||
|
063cc1c708 | ||
|
820b228f28 | ||
|
d0ffeaa089 | ||
|
4c9c435d2f | ||
|
a6ad1901be | ||
|
d7761f188f | ||
|
92c37aaab7 | ||
|
1a6aca96f3 | ||
|
90c9cfa90d | ||
|
35af09efd8 | ||
|
00309f16a9 | ||
|
3273b6ada1 | ||
|
f807993b34 | ||
|
bde650d6f1 | ||
|
40b6781dcd | ||
|
626d937994 | ||
|
6c3f1eadfe | ||
|
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 |
@@ -12,6 +12,7 @@
|
||||
"import/no-namespace": "off",
|
||||
"i18n-text/no-en": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-shadow": "off",
|
||||
"sort-imports": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||
@@ -28,8 +29,9 @@
|
||||
"@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-shadow": "error",
|
||||
"@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:
|
||||
|
26
.github/dependabot.yml
vendored
26
.github/dependabot.yml
vendored
@@ -6,13 +6,31 @@ registries:
|
||||
username: dummy # Required by dependabot
|
||||
password: dummy # Required by dependabot
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
- dependency-name: "@types/node"
|
||||
groups:
|
||||
runtime-dependencies:
|
||||
patterns:
|
||||
- "@actions/*"
|
||||
- "@octokit/rest"
|
||||
- "string-argv"
|
||||
dev-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: "gradle"
|
||||
directory: ".github/workflow-samples/gradle-plugin"
|
||||
registries:
|
||||
@@ -49,3 +67,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,8 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=38f66cd6eef217b4c35855bb11ea4e9fbc53594ccccb5fb82dfd317ef8c2c5a3
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
30
.github/workflow-samples/gradle-plugin/gradlew
vendored
30
.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
|
||||
@@ -133,22 +130,29 @@ 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.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
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
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
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 +197,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 +213,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,8 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=38f66cd6eef217b4c35855bb11ea4e9fbc53594ccccb5fb82dfd317ef8c2c5a3
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
30
.github/workflow-samples/groovy-dsl/gradlew
vendored
30
.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
|
||||
@@ -133,22 +130,29 @@ 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.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
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
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
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 +197,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 +213,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,6 +1,6 @@
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.10.2"
|
||||
id "com.gradle.common-custom-user-data-gradle-plugin" version "1.7.2"
|
||||
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,8 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=38f66cd6eef217b4c35855bb11ea4e9fbc53594ccccb5fb82dfd317ef8c2c5a3
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
30
.github/workflow-samples/java-toolchain/gradlew
vendored
30
.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
|
||||
@@ -133,22 +130,29 @@ 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.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
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
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
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 +197,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 +213,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,8 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=38f66cd6eef217b4c35855bb11ea4e9fbc53594ccccb5fb82dfd317ef8c2c5a3
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
30
.github/workflow-samples/kotlin-dsl/gradlew
vendored
30
.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
|
||||
@@ -133,22 +130,29 @@ 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.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
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
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
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 +197,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 +213,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,6 +1,6 @@
|
||||
plugins {
|
||||
id("com.gradle.enterprise") version "3.10.2"
|
||||
id("com.gradle.common-custom-user-data-gradle-plugin") version "1.7.2"
|
||||
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.2"
|
||||
id "com.gradle.build-scan" version "3.13.4"
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id "com.gradle.enterprise" version "3.10.2"
|
||||
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
|
21
.github/workflows/ci-full-check.yml
vendored
21
.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,11 +19,21 @@ 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:
|
||||
cache-key-prefix: ${{github.run_number}}-
|
||||
|
||||
dependency-graph:
|
||||
uses: ./.github/workflows/integ-test-dependency-graph.yml
|
||||
with:
|
||||
cache-key-prefix: ${{github.run_number}}-
|
||||
|
||||
execution-with-caching:
|
||||
uses: ./.github/workflows/integ-test-execution-with-caching.yml
|
||||
with:
|
||||
@@ -38,10 +49,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
|
||||
|
6
.github/workflows/ci-init-script-check.yml
vendored
6
.github/workflows/ci-init-script-check.yml
vendored
@@ -3,9 +3,9 @@ name: CI-init-script-check
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/**'
|
||||
- '.github/workflows/ci-init-script-check.yml'
|
||||
- 'src/resources/init-scripts/**'
|
||||
- 'test/init-script-check/**'
|
||||
- 'test/init-scripts/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -20,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.5.1 # Use a released version to avoid breakages
|
||||
- name: Run integration tests
|
||||
working-directory: test/init-scripts
|
||||
run: ./gradlew check
|
||||
|
42
.github/workflows/ci-quick-check.yml
vendored
42
.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.2
|
||||
- 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
|
||||
@@ -27,6 +50,13 @@ jobs:
|
||||
runner-os: '["ubuntu-latest"]'
|
||||
download-dist: true
|
||||
|
||||
dependency-graph:
|
||||
needs: build-distribution
|
||||
uses: ./.github/workflows/integ-test-dependency-graph.yml
|
||||
with:
|
||||
runner-os: '["ubuntu-latest"]'
|
||||
download-dist: true
|
||||
|
||||
execution-with-caching:
|
||||
needs: build-distribution
|
||||
uses: ./.github/workflows/integ-test-execution-with-caching.yml
|
||||
@@ -48,12 +78,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
|
||||
|
5
.github/workflows/ci-verify-outputs.yml
vendored
5
.github/workflows/ci-verify-outputs.yml
vendored
@@ -8,6 +8,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dependabot/**
|
||||
|
||||
jobs:
|
||||
check:
|
||||
@@ -17,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: |
|
||||
|
2
.github/workflows/demo-job-summary.yml
vendored
2
.github/workflows/demo-job-summary.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Demo Job Summary for Gradle builds
|
||||
name: Demo Job Summary, for Gradle builds
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
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
|
68
.github/workflows/integ-test-dependency-graph.yml
vendored
Normal file
68
.github/workflows/integ-test-dependency-graph.yml
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
name: Test execution with caching
|
||||
|
||||
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: dependency-graph-${{ inputs.cache-key-prefix }}
|
||||
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||
|
||||
jobs:
|
||||
groovy-generate:
|
||||
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 for dependency-graph generate
|
||||
uses: ./
|
||||
with:
|
||||
dependency-graph: generate
|
||||
- name: Run gradle build
|
||||
run: ./gradlew build
|
||||
working-directory: .github/workflow-samples/groovy-dsl
|
||||
|
||||
kotlin-generate:
|
||||
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 for dependency-graph generate
|
||||
uses: ./
|
||||
with:
|
||||
dependency-graph: generate-and-submit
|
||||
- name: Run gradle build
|
||||
run: ./gradlew build
|
||||
working-directory: .github/workflow-samples/kotlin-dsl
|
||||
|
||||
submit:
|
||||
needs: [groovy-generate, kotlin-generate]
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Download distribution if required
|
||||
uses: ./.github/actions/download-dist
|
||||
- name: Submit dependency graphs
|
||||
uses: ./
|
||||
with:
|
||||
dependency-graph: download-and-submit
|
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.2
|
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
|
2
LICENSE
2
LICENSE
@@ -1,7 +1,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 GitHub, Inc. and contributors
|
||||
Copyright (c) 2023 Gradle Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
235
README.md
235
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.
|
||||
@@ -197,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.
|
||||
|
||||
@@ -205,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.
|
||||
|
||||
@@ -234,6 +232,13 @@ You can configure read-only caching for the `gradle-build-action` as follows:
|
||||
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.
|
||||
@@ -246,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.
|
||||
@@ -258,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:
|
||||
@@ -272,17 +278,18 @@ 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.
|
||||
|
||||
#### 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.
|
||||
An exception to this is that 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.
|
||||
|
||||
By default, the `gradle-build-action` will only _write_ to the cache for builds run on the default branch.
|
||||
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.
|
||||
@@ -299,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:
|
||||
|
||||
@@ -361,3 +374,157 @@ 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.
|
||||
|
||||
# GitHub Dependency Graph support
|
||||
**EXPERIMENTAL**
|
||||
|
||||
The `gradle-build-action` has experimental support for submitting a [GitHub Dependency Graph](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-the-dependency-graph) snapshot via the [GitHub Dependency Submission API](https://docs.github.com/en/rest/dependency-graph/dependency-submission?apiVersion=2022-11-28).
|
||||
|
||||
The dependency graph snapshot is generated via integration with the [GitHub Dependency Graph Gradle Plugin](https://plugins.gradle.org/plugin/org.gradle.github-dependency-graph-gradle-plugin), and saved as a workflow artifact. The generated snapshot files can be submitted either in the same job, or in a subsequent job (in the same or a dependent workflow).
|
||||
|
||||
The generated dependency graph snapshot reports all of the dependencies that were resolved during a bulid execution, and is used by GitHub to generate [Dependabot Alerts](https://docs.github.com/en/code-security/dependabot/dependabot-alerts/about-dependabot-alerts) for vulnerable dependencies, as well as to populate the [Dependency Graph insights view](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/exploring-the-dependencies-of-a-repository#viewing-the-dependency-graph).
|
||||
|
||||
You enable GitHub Dependency Graph support by setting the `dependency-graph` action parameter. Valid values are:
|
||||
|
||||
|<div style="width:290px">Option</div> | Behaviour |
|
||||
| --- |---|
|
||||
| `disabled` | Do not generate a dependency graph for any build invocations.<p>This is the default. |
|
||||
| `generate` | Generate a dependency graph snapshot for each build invocation, saving as a workflow artifact. |
|
||||
| `generate-and-submit` | As per `generate`, but any generated dependency graph snapshots will be submitted at the end of the job. |
|
||||
| `download-and-submit` | Download any previously saved dependency graph snapshots, submitting them via the Dependency Submission API. This can be useful to collect all snapshots in a matrix of builds and submit them in one step. |
|
||||
|
||||
- 'disabled': Do not generate a dependency graph for any build invocations. This is the default.
|
||||
- 'generate': Generate a dependency graph snapshot for each build invocation, saving as a workflow artifact.
|
||||
- 'generate-and-submit': As per 'generate', but any generated dependency graph snapshots will be submitted at the end of the job.
|
||||
- 'download-and-submit': Download any previously saved dependency graph snapshots, submitting them via the Dependency Submission API. This can be useful to collect all snapshots in a matrix of builds and submit them in one step.
|
||||
|
||||
Dependency Graph _submission_ (but not generation) requires the `contents: write` permission, which may need to be explicitly enabled in the workflow file.
|
||||
|
||||
Example of a simple workflow that generates and submits a dependency graph:
|
||||
```yaml
|
||||
name: Submit dependency graph
|
||||
on:
|
||||
push:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Gradle to generate and submit dependency graphs
|
||||
uses: gradle/gradle-build-action@dependency-graph
|
||||
with:
|
||||
dependency-graph: generate-and-submit
|
||||
- name: Run a build, generating the dependency graph snapshot which will be submitted
|
||||
run: ./gradlew build
|
||||
```
|
||||
|
||||
### Running multiple builds in a single Job
|
||||
|
||||
GitHub tracks dependency snapshots based on the `job.correlator` value that is embedded in the snapshot. When a newer snapshot for an existing correlator is submitted, the previous snapshot is replaced. Snapshots with different `job.correlator` values are additive to the overall dependency graph for the repository.
|
||||
|
||||
The `gradle-build-action` will generate a `job.correlator` value based on the workflow name, job id and matrix values. However, if your job steps contains multiple Gradle invocations, then a unique correlator value must be assigned to each. You assign a correlator by setting the `GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR` environment variable.
|
||||
|
||||
```yaml
|
||||
name: dependency-graph
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Gradle to generate and submit dependency graphs
|
||||
uses: gradle/gradle-build-action@dependency-graph
|
||||
with:
|
||||
dependency-graph: generate-and-submit
|
||||
- name: Run first build using the default job correlator 'dependency-graph-build'
|
||||
run: ./gradlew build
|
||||
- name: Run second build providing a unique job correlator
|
||||
run: ./gradlew test
|
||||
env:
|
||||
GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR: dependency-graph-test
|
||||
|
||||
```
|
||||
|
||||
### Dependency snapshots generated for pull requests
|
||||
|
||||
This `contents: write` permission is not available for any workflow that is triggered by a pull request submitted from a forked repository, since it would permit a malicious pull request to make repository changes.
|
||||
|
||||
Because of this restriction, it is not possible to `generate-and-submit` a dependency graph generated for a pull-request that comes from a repository fork. In order to do so, 2 workflows will be required:
|
||||
1. The first workflow runs directly against the pull request sources and will generate the dependency graph snapshot.
|
||||
2. The second workflow is triggered on `workflow_run` of the first workflow, and will submit the previously saved dependency snapshots.
|
||||
|
||||
Note: when `download-and-submit` is used in a workflow triggered via [workflow_run](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run), the action will download snapshots saved in the triggering workflow.
|
||||
|
||||
***Main workflow file***
|
||||
```yaml
|
||||
name: run-build-and-generate-dependency-snapshot
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Gradle to generate and submit dependency graphs
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
dependency-graph: generate # Only generate in this job
|
||||
- name: Run a build, generating the dependency graph snapshot which will be submitted
|
||||
run: ./gradlew build
|
||||
```
|
||||
|
||||
***Dependent workflow file***
|
||||
```yaml
|
||||
name: submit-dependency-snapshot
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['run-build-and-generate-dependency-snapshot']
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
submit-snapshots:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Retrieve dependency graph artifact and submit
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
dependency-graph: download-and-submit
|
||||
```
|
||||
|
||||
|
34
action.yml
34
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,19 +53,16 @@ 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
|
||||
default: true
|
||||
|
||||
dependency-graph:
|
||||
description: Specifies if a GitHub dependency snapshot should be generated for each Gradle build, and if so, how. Valid values are 'disabled' (default), 'generate', 'generate-and-submit' and 'download-and-submit'.
|
||||
required: false
|
||||
default: 'disabled'
|
||||
|
||||
# EXPERIMENTAL & INTERNAL ACTION INPUTS
|
||||
# The following action properties allow fine-grained tweaking of the action caching behaviour.
|
||||
# These properties are experimental and not (yet) designed for production use, and may change without notice in a subsequent release of `gradle-build-action`.
|
||||
@@ -70,6 +75,15 @@ 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
|
||||
|
||||
github-token:
|
||||
description: The GitHub token used to authenticate when submitting via the Dependency Submission API.
|
||||
default: ${{ github.token }}
|
||||
required: false
|
||||
|
||||
outputs:
|
||||
build-scan-url:
|
||||
|
24
actions/clear-dependency-graph/action.yml
Normal file
24
actions/clear-dependency-graph/action.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
name: 'Clear dependency graph for a correlator'
|
||||
|
||||
inputs:
|
||||
job-correlator:
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set current timestamp as env variable
|
||||
shell: bash
|
||||
run: echo "NOW=$(date -Iseconds)" >> $GITHUB_ENV
|
||||
- name: Submit empty dependency graph
|
||||
shell: bash
|
||||
run: |
|
||||
curl -L \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ github.token }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/${{ github.repository }}/dependency-graph/snapshots \
|
||||
-d '{ "version" : 0, "job" : { "id" : "${{ github.run_id }}", "correlator" : "${{ inputs.job-correlator }} " }, "sha" : "${{ github.sha }}", "ref" : "${{ github.ref }}", "detector" : { "name" : "GitHub Dependency Graph Gradle Plugin", "version" : "0.0.3", "url" : "https://github.com/gradle/github-dependency-graph-gradle-plugin" }, "manifests" : {}, "scanned" : "${{ env.NOW }}" }'
|
||||
- run: echo "::notice ::Cleared dependency graph for job correlator '${{ inputs.job-correlator }}'"
|
||||
shell: bash
|
72938
dist/dependency-graph-generate/index.js
vendored
Normal file
72938
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
23812
dist/main/index.js
vendored
23812
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
24601
dist/post/index.js
vendored
24601
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
8646
package-lock.json
generated
8646
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
49
package.json
49
package.json
@@ -8,10 +8,15 @@
|
||||
"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": "npm run compile-main && npm run compile-post",
|
||||
|
||||
"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 +30,31 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/cache": "2.0.6",
|
||||
"@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.13",
|
||||
"string-argv": "0.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "28.1.1",
|
||||
"@types/node": "16.11.21",
|
||||
"@types/unzipper": "0.10.5",
|
||||
"@typescript-eslint/parser": "5.28.0",
|
||||
"@vercel/ncc": "0.34.0",
|
||||
"eslint": "8.17.0",
|
||||
"eslint-plugin-github": "4.3.6",
|
||||
"eslint-plugin-jest": "26.5.3",
|
||||
"jest": "28.1.1",
|
||||
"js-yaml": "4.1.0",
|
||||
"patch-package": "6.4.7",
|
||||
"prettier": "2.7.0",
|
||||
"ts-jest": "28.0.5",
|
||||
"typescript": "4.7.3"
|
||||
"@types/jest": "29.5.2",
|
||||
"@types/unzipper": "0.10.6",
|
||||
"@typescript-eslint/parser": "5.61.0",
|
||||
"@vercel/ncc": "0.36.1",
|
||||
"eslint": "8.44.0",
|
||||
"eslint-plugin-github": "4.8.0",
|
||||
"eslint-plugin-jest": "27.2.2",
|
||||
"jest": "29.6.1",
|
||||
"js-yaml": "4.1.0",
|
||||
"patch-package": "7.0.0",
|
||||
"prettier": "3.0.0",
|
||||
"ts-jest": "29.1.1",
|
||||
"typescript": "5.1.6"
|
||||
}
|
||||
}
|
||||
|
@@ -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')
|
||||
}
|
||||
|
||||
@@ -101,9 +100,9 @@ export class GradleStateCache {
|
||||
|
||||
for (const entryListener of listener.cacheEntries) {
|
||||
if (entryListener === gradleHomeEntryListener) {
|
||||
entryListener.markUnsaved('cache key not changed')
|
||||
entryListener.markNotSaved('cache key not changed')
|
||||
} else {
|
||||
entryListener.markUnsaved(`referencing '${this.cacheDescription}' cache entry not saved`)
|
||||
entryListener.markNotSaved(`referencing '${this.cacheDescription}' cache entry not saved`)
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -130,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)"
|
||||
@@ -142,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) {
|
||||
@@ -157,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}`)
|
||||
@@ -173,7 +172,12 @@ export class GradleStateCache {
|
||||
}
|
||||
|
||||
private initializeGradleUserHome(gradleUserHome: string, initScriptsDir: string): void {
|
||||
const initScriptFilenames = ['build-result-capture.init.gradle', 'build-result-capture-service.plugin.groovy']
|
||||
const initScriptFilenames = [
|
||||
'build-result-capture.init.gradle',
|
||||
'build-result-capture-service.plugin.groovy',
|
||||
'github-dependency-graph.init.gradle',
|
||||
'github-dependency-graph-gradle-plugin-apply.groovy'
|
||||
]
|
||||
for (const initScriptFilename of initScriptFilenames) {
|
||||
const initScriptContent = this.readInitScriptAsString(initScriptFilename)
|
||||
const initScriptPath = path.resolve(initScriptsDir, initScriptFilename)
|
||||
|
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.markUnsaved('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,8 +301,7 @@ 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 wrapperZip of await globber.glob()) {
|
||||
@@ -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
|
||||
|
||||
unsaved: 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
|
||||
}
|
||||
|
||||
markUnsaved(message: string): CacheEntryListener {
|
||||
this.unsaved = 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.unsaved) {
|
||||
return `(Entry not saved: ${entry.unsaved})`
|
||||
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(
|
||||
|
@@ -7,16 +7,11 @@ 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'
|
||||
@@ -24,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()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,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])
|
||||
}
|
||||
|
||||
@@ -104,8 +109,12 @@ 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] || getCacheKeyForJob(github.context.workflow, github.context.job)
|
||||
}
|
||||
|
||||
export function getCacheKeyForJob(workflowName: string, jobId: string): string {
|
||||
const sanitizedWorkflow = workflowName.replace(/,/g, '').toLowerCase()
|
||||
return `${sanitizedWorkflow}-${jobId}`
|
||||
}
|
||||
|
||||
function getCacheKeyJobInstance(): string {
|
||||
@@ -116,10 +125,25 @@ 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.getJobMatrix()
|
||||
return hashStrings([workflowJobContext])
|
||||
}
|
||||
|
||||
export function getUniqueLabelForJobInstance(): string {
|
||||
return getUniqueLabelForJobInstanceValues(github.context.workflow, github.context.job, params.getJobMatrix())
|
||||
}
|
||||
|
||||
export function getUniqueLabelForJobInstanceValues(workflow: string, jobId: string, matrixJson: string): string {
|
||||
const matrix = JSON.parse(matrixJson)
|
||||
const matrixString = Object.values(matrix).join('-')
|
||||
const label = matrixString ? `${workflow}-${jobId}-${matrixString}` : `${workflow}-${jobId}`
|
||||
return sanitize(label)
|
||||
}
|
||||
|
||||
function sanitize(value: string): string {
|
||||
return value.replace(/[^a-zA-Z0-9_-]/g, '').toLowerCase()
|
||||
}
|
||||
|
||||
function getCacheKeyJobExecution(): string {
|
||||
// Used to associate a cache key with a particular execution (default is bound to the git commit sha)
|
||||
return process.env[CACHE_KEY_JOB_EXECUTION_VAR] || github.context.sha
|
||||
@@ -145,12 +169,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
|
||||
}
|
||||
@@ -163,6 +192,8 @@ 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 with path '${cachePath}' and key: ${cacheKey}`)
|
||||
}
|
||||
@@ -205,7 +236,7 @@ export async function tryDelete(file: string): Promise<void> {
|
||||
try {
|
||||
const stat = fs.lstatSync(file)
|
||||
if (stat.isDirectory()) {
|
||||
fs.rmdirSync(file, {recursive: true})
|
||||
fs.rmSync(file, {recursive: true})
|
||||
} else {
|
||||
fs.unlinkSync(file)
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
178
src/dependency-graph.ts
Normal file
178
src/dependency-graph.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
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 layout from './repository-layout'
|
||||
import {DependencyGraphOption, getJobMatrix} from './input-params'
|
||||
|
||||
const DEPENDENCY_GRAPH_ARTIFACT = 'dependency-graph'
|
||||
|
||||
export function setup(option: DependencyGraphOption): void {
|
||||
if (option === DependencyGraphOption.Disabled || option === DependencyGraphOption.DownloadAndSubmit) {
|
||||
return
|
||||
}
|
||||
|
||||
core.info('Enabling dependency graph generation')
|
||||
const jobCorrelator = getJobCorrelator()
|
||||
core.exportVariable('GITHUB_DEPENDENCY_GRAPH_ENABLED', 'true')
|
||||
core.exportVariable('GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR', jobCorrelator)
|
||||
core.exportVariable('GITHUB_DEPENDENCY_GRAPH_JOB_ID', github.context.runId)
|
||||
core.exportVariable(
|
||||
'GITHUB_DEPENDENCY_GRAPH_REPORT_DIR',
|
||||
path.resolve(layout.workspaceDirectory(), 'dependency-graph-reports')
|
||||
)
|
||||
}
|
||||
|
||||
export async function complete(option: DependencyGraphOption): Promise<void> {
|
||||
switch (option) {
|
||||
case DependencyGraphOption.Disabled:
|
||||
return
|
||||
case DependencyGraphOption.Generate:
|
||||
await uploadDependencyGraphs()
|
||||
return
|
||||
case DependencyGraphOption.GenerateAndSubmit:
|
||||
await submitDependencyGraphs(await uploadDependencyGraphs())
|
||||
return
|
||||
case DependencyGraphOption.DownloadAndSubmit:
|
||||
await downloadAndSubmitDependencyGraphs()
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadDependencyGraphs(): Promise<string[]> {
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
const graphFiles = await findDependencyGraphFiles(workspaceDirectory)
|
||||
|
||||
const relativeGraphFiles = graphFiles.map(x => getRelativePathFromWorkspace(x))
|
||||
core.info(`Uploading dependency graph files: ${relativeGraphFiles}`)
|
||||
|
||||
const artifactClient = artifact.create()
|
||||
artifactClient.uploadArtifact(DEPENDENCY_GRAPH_ARTIFACT, graphFiles, workspaceDirectory)
|
||||
|
||||
return graphFiles
|
||||
}
|
||||
|
||||
async function downloadAndSubmitDependencyGraphs(): Promise<void> {
|
||||
const workspaceDirectory = layout.workspaceDirectory()
|
||||
submitDependencyGraphs(await retrieveDependencyGraphs(workspaceDirectory))
|
||||
}
|
||||
|
||||
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
|
||||
const octokit: Octokit = getOctokit()
|
||||
|
||||
for (const jsonFile of dependencyGraphFiles) {
|
||||
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.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function retrieveDependencyGraphs(workspaceDirectory: string): Promise<string[]> {
|
||||
if (github.context.payload.workflow_run) {
|
||||
return await retrieveDependencyGraphsForWorkflowRun(github.context.payload.workflow_run.id, workspaceDirectory)
|
||||
}
|
||||
return retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory)
|
||||
}
|
||||
|
||||
async function retrieveDependencyGraphsForWorkflowRun(runId: number, workspaceDirectory: string): Promise<string[]> {
|
||||
const octokit: Octokit = getOctokit()
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
async function findDependencyGraphFiles(dir: string): Promise<string[]> {
|
||||
const globber = await glob.create(`${dir}/dependency-graph-reports/*.json`)
|
||||
const graphFiles = globber.glob()
|
||||
return graphFiles
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
export function getJobCorrelator(): string {
|
||||
return constructJobCorrelator(github.context.workflow, github.context.job, getJobMatrix())
|
||||
}
|
||||
|
||||
export function constructJobCorrelator(workflow: string, jobId: string, matrixJson: string): string {
|
||||
const matrixString = describeMatrix(matrixJson)
|
||||
const label = matrixString ? `${workflow}-${jobId}-${matrixString}` : `${workflow}-${jobId}`
|
||||
return sanitize(label)
|
||||
}
|
||||
|
||||
function describeMatrix(matrixJson: string): string {
|
||||
core.debug(`Got matrix json: ${matrixJson}`)
|
||||
const matrix = JSON.parse(matrixJson)
|
||||
if (matrix) {
|
||||
return Object.values(matrix).join('-')
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function sanitize(value: string): string {
|
||||
return value
|
||||
.replace(/[^a-zA-Z0-9_-\s]/g, '')
|
||||
.replace(/\s+/g, '_')
|
||||
.toLowerCase()
|
||||
}
|
105
src/input-params.ts
Normal file
105
src/input-params.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
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 getJobMatrix(): 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)
|
||||
}
|
||||
|
||||
export function isDependencyGraphEnabled(): boolean {
|
||||
return getBooleanInput('generate-dependency-graph', true)
|
||||
}
|
||||
|
||||
export function getDependencyGraphOption(): DependencyGraphOption {
|
||||
const val = core.getInput('dependency-graph')
|
||||
switch (val.toLowerCase().trim()) {
|
||||
case 'disabled':
|
||||
return DependencyGraphOption.Disabled
|
||||
case 'generate':
|
||||
return DependencyGraphOption.Generate
|
||||
case 'generate-and-submit':
|
||||
return DependencyGraphOption.GenerateAndSubmit
|
||||
case 'download-and-submit':
|
||||
return DependencyGraphOption.DownloadAndSubmit
|
||||
}
|
||||
throw TypeError(
|
||||
`The value '${val} is not valid for 'dependency-graph. Valid values are: [disabled, generate-and-upload, generate-and-submit, download-and-submit]. The default value is 'disabled'.`
|
||||
)
|
||||
}
|
||||
|
||||
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]`)
|
||||
}
|
||||
|
||||
export enum DependencyGraphOption {
|
||||
Disabled,
|
||||
Generate,
|
||||
GenerateAndSubmit,
|
||||
DownloadAndSubmit
|
||||
}
|
@@ -1,18 +1,6 @@
|
||||
import * as core from '@actions/core'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import {logCachingReport, CacheListener} 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
|
||||
get buildScanFailed(): boolean
|
||||
}
|
||||
import {BuildResult} from './build-results'
|
||||
import {writeCachingReport, CacheListener, logCachingReport} from './cache-reporting'
|
||||
|
||||
export async function writeJobSummary(buildResults: BuildResult[], cacheListener: CacheListener): Promise<void> {
|
||||
core.info('Writing job summary')
|
||||
@@ -23,23 +11,19 @@ export async function writeJobSummary(buildResults: BuildResult[], cacheListener
|
||||
writeSummaryTable(buildResults)
|
||||
}
|
||||
|
||||
logCachingReport(cacheListener)
|
||||
writeCachingReport(cacheListener)
|
||||
|
||||
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 {
|
||||
@@ -92,3 +76,19 @@ function renderBuildScanBadge(outcomeText: string, outcomeColor: string, targetU
|
||||
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
|
||||
}
|
@@ -45,9 +45,17 @@ abstract class BuildResultsRecorder implements BuildService<BuildResultsRecorder
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,24 +16,29 @@ if (isTopLevelBuild) {
|
||||
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
|
||||
// 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 ->
|
||||
if (gradle.rootProject.pluginManager.hasPlugin("com.gradle.build-scan")) {
|
||||
// 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)
|
||||
}
|
||||
// We need to capture in buildFinished in case the plugin is applied but no build scan is published
|
||||
captureUsingBuildFinished(gradle, invocationId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +55,13 @@ def captureUsingBuildScanPublished(buildScanExtension, rootProject, invocationId
|
||||
buildResults.setBuildScanUri(buildScan.buildScanUri.toASCIIString())
|
||||
buildResults.writeToResultsFile(true)
|
||||
|
||||
println("::set-output name=build-scan-url::${buildScan.buildScanUri}")
|
||||
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 ->
|
||||
@@ -62,11 +73,10 @@ def captureUsingBuildScanPublished(buildScanExtension, rootProject, invocationId
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,9 +116,15 @@ class BuildResults {
|
||||
}
|
||||
|
||||
def writeToResultsFile(boolean overwrite) {
|
||||
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") + invocationId + ".json")
|
||||
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()) {
|
||||
|
@@ -0,0 +1,9 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.gradle:github-dependency-graph-gradle-plugin:0.0.5"
|
||||
}
|
||||
}
|
||||
apply plugin: org.gradle.github.GitHubDependencyGraphPlugin
|
@@ -0,0 +1,24 @@
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
if (System.env.GITHUB_DEPENDENCY_GRAPH_ENABLED != "true") {
|
||||
return
|
||||
}
|
||||
|
||||
if (GradleVersion.current().baseVersion < GradleVersion.version("5.0")) {
|
||||
println "::warning::Dependency Graph is not supported for Gradle versions < 5.0. No dependency snapshot will be generated."
|
||||
return
|
||||
}
|
||||
|
||||
def reportDir = System.env.GITHUB_DEPENDENCY_GRAPH_REPORT_DIR
|
||||
def jobCorrelator = System.env.GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR
|
||||
def reportFile = new File(reportDir, jobCorrelator + ".json")
|
||||
|
||||
if (reportFile.exists()) {
|
||||
println "::warning::No dependency snapshot generated for step: report file for '${jobCorrelator}' created in earlier step. Each build invocation requires a unique job correlator: specify GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR var for this step."
|
||||
return
|
||||
}
|
||||
|
||||
println "Generating dependency graph for '${jobCorrelator}'"
|
||||
|
||||
// TODO:DAZ This should be conditionally applied, since the script may be present when not required.
|
||||
apply from: 'github-dependency-graph-gradle-plugin-apply.groovy'
|
@@ -1,30 +1,24 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as exec from '@actions/exec'
|
||||
import {SUMMARY_ENV_VAR} from '@actions/core/lib/summary'
|
||||
import * as fs from 'fs'
|
||||
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 * as dependencyGraph from './dependency-graph'
|
||||
|
||||
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 shouldGenerateJobSummary(): boolean {
|
||||
// Check if Job Summary is supported on this platform
|
||||
if (!process.env[SUMMARY_ENV_VAR]) {
|
||||
return false
|
||||
}
|
||||
|
||||
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]) {
|
||||
@@ -43,6 +37,8 @@ export async function setup(buildRootDirectory: string): Promise<void> {
|
||||
await caches.restore(gradleUserHome, cacheListener)
|
||||
|
||||
core.saveState(CACHE_LISTENER, cacheListener.stringify())
|
||||
|
||||
dependencyGraph.setup(params.getDependencyGraphOption())
|
||||
}
|
||||
|
||||
export async function complete(): Promise<void> {
|
||||
@@ -50,26 +46,29 @@ 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)
|
||||
|
||||
await caches.save(gradleUserHome, cacheListener, daemonController)
|
||||
|
||||
if (shouldGenerateJobSummary()) {
|
||||
writeJobSummary(buildResults, cacheListener)
|
||||
await writeJobSummary(buildResults, cacheListener)
|
||||
} else {
|
||||
logJobSummary(buildResults, cacheListener)
|
||||
}
|
||||
|
||||
dependencyGraph.complete(params.getDependencyGraphOption())
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -93,27 +92,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
BIN
test/init-scripts/gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
@@ -1,5 +1,8 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionSha256Sum=38f66cd6eef217b4c35855bb11ea4e9fbc53594ccccb5fb82dfd317ef8c2c5a3
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
30
test/init-scripts/gradlew
vendored
30
test/init-scripts/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
|
||||
@@ -133,22 +130,29 @@ 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.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
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
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
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 +197,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 +213,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
test/init-scripts/gradlew.bat
vendored
15
test/init-scripts/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 +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,30 +17,31 @@ 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.2'), 8, 19)
|
||||
static final TestGradleVersion GRADLE_8_0 = new TestGradleVersion(GradleVersion.version('8.0.2'), 8, 19)
|
||||
static final TestGradleVersion GRADLE_8_X = new TestGradleVersion(GradleVersion.version('8.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_0,
|
||||
GRADLE_8_X,
|
||||
]
|
||||
|
||||
static final List<TestGradleVersion> CONFIGURATION_CACHE_VERSIONS =
|
||||
[GRADLE_7_0, GRADLE_7_4]
|
||||
[GRADLE_7_X, GRADLE_8_0, GRADLE_8_X]
|
||||
|
||||
static final List<TestGradleVersion> SETTINGS_PLUGIN_VERSIONS =
|
||||
[GRADLE_6_X, GRADLE_7_X, GRADLE_8_0, GRADLE_8_X]
|
||||
|
||||
static final String PUBLIC_BUILD_SCAN_ID = 'i2wepy2gr7ovw'
|
||||
static final String DEFAULT_SCAN_UPLOAD_TOKEN = 'scan-upload-token'
|
||||
@@ -138,7 +139,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'
|
||||
@@ -164,7 +165,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'
|
||||
@@ -200,20 +201,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
|
||||
}
|
||||
|
||||
|
@@ -134,6 +134,48 @@ class TestBuildResultRecorder extends BaseInitScriptTest {
|
||||
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
|
||||
|
@@ -0,0 +1,87 @@
|
||||
package com.gradle.gradlebuildaction
|
||||
|
||||
import static org.junit.Assume.assumeTrue
|
||||
|
||||
class TestDependencyGraph extends BaseInitScriptTest {
|
||||
def initScript = 'github-dependency-graph.init.gradle'
|
||||
|
||||
static final List<TestGradleVersion> NO_DEPENDENCY_GRAPH_VERSIONS = [GRADLE_3_X, GRADLE_4_X]
|
||||
static final List<TestGradleVersion> DEPENDENCY_GRAPH_VERSIONS = ALL_VERSIONS - NO_DEPENDENCY_GRAPH_VERSIONS
|
||||
|
||||
|
||||
def "does not produce dependency graph when not enabled"() {
|
||||
assumeTrue testGradleVersion.compatibleWithCurrentJvm
|
||||
|
||||
when:
|
||||
run(['help'], initScript, testGradleVersion.gradleVersion)
|
||||
|
||||
then:
|
||||
assert !reportsDir.exists()
|
||||
|
||||
where:
|
||||
testGradleVersion << ALL_VERSIONS
|
||||
}
|
||||
|
||||
def "produces dependency graph when enabled"() {
|
||||
assumeTrue testGradleVersion.compatibleWithCurrentJvm
|
||||
|
||||
when:
|
||||
run(['help'], initScript, testGradleVersion.gradleVersion, [], envVars)
|
||||
|
||||
then:
|
||||
assert reportFile.exists()
|
||||
|
||||
where:
|
||||
testGradleVersion << DEPENDENCY_GRAPH_VERSIONS
|
||||
}
|
||||
|
||||
def "warns and produces no dependency graph when enabled for older Gradle versions"() {
|
||||
assumeTrue testGradleVersion.compatibleWithCurrentJvm
|
||||
|
||||
when:
|
||||
def result = run(['help'], initScript, testGradleVersion.gradleVersion, [], envVars)
|
||||
|
||||
then:
|
||||
assert !reportsDir.exists()
|
||||
assert result.output.contains("::warning::Dependency Graph is not supported")
|
||||
|
||||
where:
|
||||
testGradleVersion << NO_DEPENDENCY_GRAPH_VERSIONS
|
||||
}
|
||||
|
||||
def "warns and does not overwrite existing report file"() {
|
||||
assumeTrue testGradleVersion.compatibleWithCurrentJvm
|
||||
|
||||
when:
|
||||
reportsDir.mkdirs()
|
||||
reportFile << "DUMMY CONTENT"
|
||||
def result = run(['help'], initScript, testGradleVersion.gradleVersion, [], envVars)
|
||||
|
||||
then:
|
||||
assert reportFile.text == "DUMMY CONTENT"
|
||||
assert result.output.contains("::warning::No dependency snapshot generated for step")
|
||||
|
||||
where:
|
||||
testGradleVersion << DEPENDENCY_GRAPH_VERSIONS
|
||||
}
|
||||
|
||||
def getEnvVars() {
|
||||
return [
|
||||
GITHUB_DEPENDENCY_GRAPH_ENABLED: "true",
|
||||
GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR: "CORRELATOR",
|
||||
GITHUB_DEPENDENCY_GRAPH_JOB_ID: "1",
|
||||
GITHUB_DEPENDENCY_GRAPH_REPORT_DIR: reportsDir.absolutePath,
|
||||
GITHUB_REF: "main",
|
||||
GITHUB_SHA: "123456",
|
||||
GITHUB_WORKSPACE: testProjectDir.absolutePath
|
||||
]
|
||||
}
|
||||
|
||||
def getReportsDir() {
|
||||
return new File(testProjectDir, 'build/reports/github-dependency-graph-snapshots')
|
||||
}
|
||||
|
||||
def getReportFile() {
|
||||
return new File(reportsDir, "CORRELATOR.json")
|
||||
}
|
||||
}
|
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.2")
|
||||
|
||||
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
|
||||
}
|
||||
|
@@ -17,4 +17,10 @@ describe('cacheUtils-utils', () => {
|
||||
expect(posixHash).toBe(windowsHash)
|
||||
})
|
||||
})
|
||||
describe('sanitizes workflow name in cache key', () => {
|
||||
it('with comma', () => {
|
||||
const cacheKey = cacheUtils.getCacheKeyForJob("Workflow, with,commas", "JOB_ID")
|
||||
expect(cacheKey).toBe('workflow withcommas-JOB_ID')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
34
test/jest/dependency-graph.test.ts
Normal file
34
test/jest/dependency-graph.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import * as dependencyGraph from '../../src/dependency-graph'
|
||||
|
||||
describe('dependency-graph', () => {
|
||||
describe('constructs job correlator', () => {
|
||||
it('removes commas from workflow name', () => {
|
||||
const id = dependencyGraph.constructJobCorrelator('Workflow, with,commas', 'jobid', '{}')
|
||||
expect(id).toBe('workflow_withcommas-jobid')
|
||||
})
|
||||
it('removes non word characters', () => {
|
||||
const id = dependencyGraph.constructJobCorrelator('Workflow!_with()characters', 'job-*id', '{"foo": "bar!@#$%^&*("}')
|
||||
expect(id).toBe('workflow_withcharacters-job-id-bar')
|
||||
})
|
||||
it('replaces spaces', () => {
|
||||
const id = dependencyGraph.constructJobCorrelator('Workflow !_ with () characters, and spaces', 'job-*id', '{"foo": "bar!@#$%^&*("}')
|
||||
expect(id).toBe('workflow___with_characters_and_spaces-job-id-bar')
|
||||
})
|
||||
it('without matrix', () => {
|
||||
const id = dependencyGraph.constructJobCorrelator('workflow', 'jobid', 'null')
|
||||
expect(id).toBe('workflow-jobid')
|
||||
})
|
||||
it('with dashes in values', () => {
|
||||
const id = dependencyGraph.constructJobCorrelator('workflow-name', 'job-id', '{"os": "ubuntu-latest"}')
|
||||
expect(id).toBe('workflow-name-job-id-ubuntu-latest')
|
||||
})
|
||||
it('with single matrix value', () => {
|
||||
const id = dependencyGraph.constructJobCorrelator('workflow', 'jobid', '{"os": "windows"}')
|
||||
expect(id).toBe('workflow-jobid-windows')
|
||||
})
|
||||
it('with composite matrix value', () => {
|
||||
const id = dependencyGraph.constructJobCorrelator('workflow', 'jobid', '{"os": "windows", "java-version": "21.1", "other": "Value, with COMMA"}')
|
||||
expect(id).toBe('workflow-jobid-windows-211-value_with_comma')
|
||||
})
|
||||
})
|
||||
})
|
6
test/jest/resources/cache-cleanup/.gitattributes
vendored
Normal file
6
test/jest/resources/cache-cleanup/.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
8
test/jest/resources/cache-cleanup/.gitignore
vendored
Normal file
8
test/jest/resources/cache-cleanup/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Ignore Gradle project-specific cache directory
|
||||
.gradle
|
||||
|
||||
# Ignore Gradle build output directory
|
||||
build
|
||||
|
||||
HOME
|
||||
tmp
|
11
test/jest/resources/cache-cleanup/build.gradle
Normal file
11
test/jest/resources/cache-cleanup/build.gradle
Normal file
@@ -0,0 +1,11 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api "org.apache.commons:commons-math3:${System.properties['commons_math3_version']}"
|
||||
}
|
BIN
test/jest/resources/cache-cleanup/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
test/jest/resources/cache-cleanup/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
test/jest/resources/cache-cleanup/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
test/jest/resources/cache-cleanup/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
# Deliberately not using the latest Gradle version for cache cleanup testing
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
245
test/jest/resources/cache-cleanup/gradlew
vendored
Executable file
245
test/jest/resources/cache-cleanup/gradlew
vendored
Executable file
@@ -0,0 +1,245 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
92
test/jest/resources/cache-cleanup/gradlew.bat
vendored
Normal file
92
test/jest/resources/cache-cleanup/gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% 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!
|
||||
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
|
||||
|
||||
:omega
|
1
test/jest/resources/cache-cleanup/settings.gradle
Normal file
1
test/jest/resources/cache-cleanup/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'unused-dependencies'
|
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* This Java source file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
package unused.dependencies;
|
||||
|
||||
public class Library {
|
||||
public boolean someLibraryMethod() {
|
||||
return true;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user