Compare commits

..

11 Commits

Author SHA1 Message Date
Paul Merlin
e220e54c83 Merge branch 'master' into releases/v1 2020-06-14 12:41:26 +02:00
Paul Merlin
720051268d Cleanup 2020-06-13 16:37:23 +02:00
Paul Merlin
36d51a403a Merge branch 'master' into releases/v1 2020-06-13 16:33:57 +02:00
Paul Merlin
d0c5f7955e build 2019-12-09 15:22:02 +01:00
Paul Merlin
a2ba194e38 Merge branch 'master' into releases/v1 2019-12-09 15:20:11 +01:00
Paul Merlin
064f85c156 build 2019-10-28 13:31:49 +01:00
Paul Merlin
580b26a94c Merge branch 'master' into releases/v1 2019-10-28 13:30:49 +01:00
Paul Merlin
c61d0fe2b5 Merge branch 'master' into releases/v1 2019-10-28 13:27:16 +01:00
Paul Merlin
6170f06e8d build 2019-09-23 12:20:06 +02:00
Paul Merlin
e561eefa28 Merge branch 'master' into releases/v1 2019-09-23 12:17:48 +02:00
Paul Merlin
2d5ca45eab publishing v1 of action 2019-09-21 16:11:55 +02:00
118 changed files with 6017 additions and 150463 deletions

View File

@@ -10,10 +10,8 @@
"rules": {
"eslint-comments/no-use": "off",
"import/no-namespace": "off",
"i18n-text/no-en": "off",
"no-unused-vars": "off",
"sort-imports": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
@@ -39,7 +37,7 @@
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": ["error", {"ignoreStringArrays": true}],
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"semi": "off",
"@typescript-eslint/semi": ["error", "never"],

View File

@@ -1,16 +0,0 @@
name: 'Build and upload distribution'
# Builds the action distribution an uploads as an artifact for later download
runs:
using: "composite"
steps:
- name: Build distribution
shell: bash
run: |
npm install
npm run all
- name: Upload distribution
uses: actions/upload-artifact@v3
with:
name: dist
path: dist/

View File

@@ -1,12 +0,0 @@
name: 'Download dist'
# Downloads a 'dist' directory artifact that was uploaded in an earlier step
# We control this with an environment variable to allow for easier global configuration.
runs:
using: "composite"
steps:
- name: Download dist
if: ${{ env.DOWNLOAD_DIST == 'true' }}
uses: actions/download-artifact@v3
with:
name: dist
path: dist/

3
.github/dco.yml vendored
View File

@@ -1,3 +0,0 @@
# Disable sign-off checking for members of the Gradle GitHub organization
require:
members: false

View File

@@ -1,51 +0,0 @@
version: 2
registries:
gradle-plugin-portal:
type: maven-repository
url: https://plugins.gradle.org/m2
username: dummy # Required by dependabot
password: dummy # Required by dependabot
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
ignore:
- dependency-name: "@types/node"
- package-ecosystem: "gradle"
directory: ".github/workflow-samples/gradle-plugin"
registries:
- gradle-plugin-portal
schedule:
interval: "daily"
- package-ecosystem: "gradle"
directory: ".github/workflow-samples/groovy-dsl"
registries:
- gradle-plugin-portal
schedule:
interval: "daily"
- package-ecosystem: "gradle"
directory: ".github/workflow-samples/java-toolchain"
registries:
- gradle-plugin-portal
schedule:
interval: "daily"
- package-ecosystem: "gradle"
directory: ".github/workflow-samples/kotlin-dsl"
registries:
- gradle-plugin-portal
schedule:
interval: "daily"
- package-ecosystem: "gradle"
directory: ".github/workflow-samples/no-wrapper"
registries:
- gradle-plugin-portal
schedule:
interval: "daily"
- package-ecosystem: "gradle"
directory: ".github/workflow-samples/no-wrapper-gradle-5"
registries:
- gradle-plugin-portal
schedule:
interval: "daily"

View File

@@ -1,6 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,240 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# 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" "$@"

View File

@@ -1,91 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% 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

View File

@@ -1,60 +0,0 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Gradle plugin project to get you started.
* For more details take a look at the Writing Custom Plugins chapter in the Gradle
* User Manual available at https://docs.gradle.org/7.3/userguide/custom_plugins.html
* This project uses @Incubating APIs which are subject to change.
*/
plugins {
// Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
id 'java-gradle-plugin'
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
testing {
suites {
// Configure the built-in test suite
test {
// Use JUnit Jupiter test framework
useJUnitJupiter('5.7.2')
}
// Create a new test suite
functionalTest(JvmTestSuite) {
dependencies {
// functionalTest test suite depends on the production code in tests
implementation project
}
targets {
all {
// This test suite should run after the built-in test suite has run its tests
testTask.configure { shouldRunAfter(test) }
}
}
}
}
}
gradlePlugin {
// Define the plugin
plugins {
greeting {
id = 'org.example.gradle.plugin.greeting'
implementationClass = 'org.example.gradle.plugin.GradlePluginPlugin'
}
}
}
gradlePlugin.testSourceSets(sourceSets.functionalTest)
tasks.named('check') {
// Include functionalTest as part of the check lifecycle
dependsOn(testing.suites.functionalTest)
}

View File

@@ -1,57 +0,0 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package org.example.gradle.plugin;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.io.FileWriter;
import java.nio.file.Files;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.BuildResult;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import static org.junit.jupiter.api.Assertions.*;
/**
* A simple functional test for the 'org.example.gradle.plugin.greeting' plugin.
*/
class GradlePluginPluginFunctionalTest {
@TempDir
File projectDir;
private File getBuildFile() {
return new File(projectDir, "build.gradle");
}
private File getSettingsFile() {
return new File(projectDir, "settings.gradle");
}
@Test void canRunTaskWithGradle691() throws IOException {
writeString(getSettingsFile(), "");
writeString(getBuildFile(),
"plugins {" +
" id('org.example.gradle.plugin.greeting')" +
"}");
// Run the build
GradleRunner runner = GradleRunner.create();
runner.forwardOutput();
runner.withGradleVersion("6.9.1");
runner.withPluginClasspath();
runner.withArguments("greeting");
runner.withProjectDir(projectDir);
BuildResult result = runner.build();
// Verify the result
assertTrue(result.getOutput().contains("Hello from plugin 'org.example.gradle.plugin.greeting'"));
}
private void writeString(File file, String string) throws IOException {
try (Writer writer = new FileWriter(file)) {
writer.write(string);
}
}
}

View File

@@ -1,19 +0,0 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package org.example.gradle.plugin;
import org.gradle.api.Project;
import org.gradle.api.Plugin;
/**
* A simple 'hello world' plugin.
*/
public class GradlePluginPlugin implements Plugin<Project> {
public void apply(Project project) {
// Register a task
project.getTasks().register("greeting", task -> {
task.doLast(s -> System.out.println("Hello from plugin 'org.example.gradle.plugin.greeting'"));
});
}
}

View File

@@ -1,23 +0,0 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package org.example.gradle.plugin;
import org.gradle.testfixtures.ProjectBuilder;
import org.gradle.api.Project;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* A simple unit test for the 'org.example.gradle.plugin.greeting' plugin.
*/
class GradlePluginPluginTest {
@Test void pluginRegistersATask() {
// Create a test project and apply the plugin
Project project = ProjectBuilder.builder().build();
project.getPlugins().apply("org.example.gradle.plugin.greeting");
// Verify the result
assertNotNull(project.getTasks().findByName("greeting"));
}
}

View File

@@ -1,22 +0,0 @@
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
testImplementation('junit:junit:4.13.2')
}
tasks.named("test").configure {
// Echo an output value so we can detect configuration-cache usage
println "::set-output name=task_configured::yes"
doLast {
if (System.properties.verifyCachedBuild) {
throw new RuntimeException("Build was not cached: unexpected execution of test task")
}
}
}

View File

@@ -1 +0,0 @@
org.gradle.caching=true

View File

@@ -1,6 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,240 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# 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" "$@"

View File

@@ -1,91 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% 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

View File

@@ -1,14 +0,0 @@
plugins {
id "com.gradle.enterprise" version "3.11.1"
id "com.gradle.common-custom-user-data-gradle-plugin" version "1.8.0"
}
gradleEnterprise {
buildScan {
termsOfServiceUrl = "https://gradle.com/terms-of-service"
termsOfServiceAgree = "yes"
publishAlways()
uploadInBackground = false
}
}
rootProject.name = 'groovy-dsl'

View File

@@ -1,10 +0,0 @@
package basic;
import org.junit.Test;
public class BasicTest {
@Test
public void test() {
assert true;
}
}

View File

@@ -1,17 +0,0 @@
plugins {
id 'java'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(16)
}
}
repositories {
mavenCentral()
}
dependencies {
testImplementation('junit:junit:4.13.2')
}

View File

@@ -1 +0,0 @@
org.gradle.caching=true

View File

@@ -1,6 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,240 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# 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" "$@"

View File

@@ -1,91 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% 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

View File

@@ -1 +0,0 @@
rootProject.name = 'basic'

View File

@@ -1,10 +0,0 @@
package basic;
import org.junit.Test;
public class BasicTest {
@Test
public void test() {
assert true;
}
}

View File

@@ -1,29 +0,0 @@
plugins {
`java-library`
}
repositories {
mavenCentral()
}
dependencies {
api("org.apache.commons:commons-math3:3.6.1")
implementation("com.google.guava:guava:31.1-jre")
testImplementation("org.junit.jupiter:junit-jupiter:5.9.0")
}
tasks.test {
useJUnitPlatform()
}
tasks.named("test").configure {
// Echo an output value so we can detect configuration-cache usage
println("::set-output name=task_configured::yes")
doLast {
if (System.getProperties().containsKey("verifyCachedBuild")) {
throw RuntimeException("Build was not cached: unexpected execution of test task")
}
}
}

View File

@@ -1 +0,0 @@
org.gradle.caching=true

View File

@@ -1,6 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,240 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# 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" "$@"

View File

@@ -1,91 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% 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

View File

@@ -1,16 +0,0 @@
plugins {
id("com.gradle.enterprise") version "3.11.1"
id("com.gradle.common-custom-user-data-gradle-plugin") version "1.8.0"
}
gradleEnterprise {
buildScan {
termsOfServiceUrl = "https://gradle.com/terms-of-service"
termsOfServiceAgree = "yes"
publishAlways()
isUploadInBackground = false
}
}
rootProject.name = "kotlin-dsl"

View File

@@ -1,10 +0,0 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package com.example;
public class Library {
public boolean someLibraryMethod() {
return true;
}
}

View File

@@ -1,14 +0,0 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package com.example;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class LibraryTest {
@Test void someLibraryMethodReturnsTrue() {
Library classUnderTest = new Library();
assertTrue(classUnderTest.someLibraryMethod(), "someLibraryMethod should return 'true'");
}
}

View File

@@ -1,10 +0,0 @@
plugins {
id "com.gradle.build-scan" version "1.16"
}
buildScan {
termsOfServiceUrl = "https://gradle.com/terms-of-service"
termsOfServiceAgree = "yes"
publishAlways()
}

View File

@@ -1,8 +0,0 @@
rootProject.name = 'no-wrapper'
println "Using Gradle version: ${gradle.gradleVersion}"
def gradleVersionCheck = System.properties.gradleVersionCheck
if (gradleVersionCheck && gradle.gradleVersion != gradleVersionCheck) {
throw new RuntimeException("Got the wrong version: expected ${gradleVersionCheck} but was ${gradle.gradleVersion}")
}

View File

@@ -1,12 +0,0 @@
plugins {
id "com.gradle.build-scan" version "3.11.1"
}
gradleEnterprise {
buildScan {
termsOfServiceUrl = "https://gradle.com/terms-of-service"
termsOfServiceAgree = "yes"
publishAlways()
uploadInBackground = false
}
}

View File

@@ -1,8 +0,0 @@
rootProject.name = 'no-wrapper'
println "Using Gradle version: ${gradle.gradleVersion}"
def gradleVersionCheck = System.properties.gradleVersionCheck
if (gradleVersionCheck && gradle.gradleVersion != gradleVersionCheck) {
throw new RuntimeException("Got the wrong version: expected ${gradleVersionCheck} but was ${gradle.gradleVersion}")
}

View File

@@ -1 +0,0 @@
// Required to keep dependabot happy

View File

@@ -1,21 +0,0 @@
plugins {
id "com.gradle.enterprise" version "3.11.1"
}
gradleEnterprise {
buildScan {
termsOfServiceUrl = "https://gradle.com/terms-of-service"
termsOfServiceAgree = "yes"
publishAlways()
uploadInBackground = false
}
}
rootProject.name = 'no-wrapper'
println "Using Gradle version: ${gradle.gradleVersion}"
def gradleVersionCheck = System.properties.gradleVersionCheck
if (gradleVersionCheck && gradle.gradleVersion != gradleVersionCheck) {
throw new RuntimeException("Got the wrong version: expected ${gradleVersionCheck} but was ${gradle.gradleVersion}")
}

View File

@@ -1,70 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: CI-codeql
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '25 23 * * 2'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

View File

@@ -1,74 +0,0 @@
name: CI-full-check
on:
pull_request:
types:
- assigned
- review_requested
push:
branches:
- main
paths:
- '.github/workflows/**'
- 'dist/**'
jobs:
action-inputs:
uses: ./.github/workflows/integ-test-action-inputs.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}}-
execution-with-caching:
uses: ./.github/workflows/integ-test-execution-with-caching.yml
with:
cache-key-prefix: ${{github.run_number}}-
execution:
uses: ./.github/workflows/integ-test-execution.yml
with:
cache-key-prefix: ${{github.run_number}}-
provision-gradle-versions:
uses: ./.github/workflows/integ-test-provision-gradle-versions.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
with:
cache-key-prefix: ${{github.run_number}}-
restore-containerized-gradle-home:
uses: ./.github/workflows/integ-test-restore-containerized-gradle-home.yml
with:
cache-key-prefix: ${{github.run_number}}-
restore-gradle-home:
uses: ./.github/workflows/integ-test-restore-gradle-home.yml
with:
cache-key-prefix: ${{github.run_number}}-
restore-java-toolchain:
uses: ./.github/workflows/integ-test-restore-java-toolchain.yml
with:
cache-key-prefix: ${{github.run_number}}-
sample-kotlin-dsl:
uses: ./.github/workflows/integ-test-sample-kotlin-dsl.yml
with:
cache-key-prefix: ${{github.run_number}}-
sample-gradle-plugin:
uses: ./.github/workflows/integ-test-sample-gradle-plugin.yml
with:
cache-key-prefix: ${{github.run_number}}-

View File

@@ -1,26 +0,0 @@
name: CI-init-script-check
on:
push:
paths:
- '.github/workflows/**'
- 'src/resources/init-scripts/**'
- 'test/init-script-check/**'
workflow_dispatch:
jobs:
test-init-scripts:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 8
- name: Setup Gradle
uses: gradle/gradle-build-action@v2 # Use a released version to avoid breakages
- name: Run integration tests
working-directory: test/init-scripts
run: ./gradlew check

View File

@@ -1,96 +0,0 @@
name: CI-quick-check
on:
push:
branches-ignore: main
jobs:
build-distribution:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Build and upload distribution
uses: ./.github/actions/build-dist
action-inputs:
needs: build-distribution
uses: ./.github/workflows/integ-test-action-inputs.yml
with:
runner-os: '["ubuntu-latest"]'
download-dist: true
caching-config:
needs: build-distribution
uses: ./.github/workflows/integ-test-action-inputs-caching.yml
with:
runner-os: '["ubuntu-latest"]'
download-dist: true
execution-with-caching:
needs: build-distribution
uses: ./.github/workflows/integ-test-execution-with-caching.yml
with:
runner-os: '["ubuntu-latest"]'
download-dist: true
execution:
needs: build-distribution
uses: ./.github/workflows/integ-test-execution.yml
with:
runner-os: '["ubuntu-latest"]'
download-dist: true
provision-gradle-versions:
needs: build-distribution
uses: ./.github/workflows/integ-test-provision-gradle-versions.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
uses: ./.github/workflows/integ-test-restore-containerized-gradle-home.yml
with:
download-dist: true
restore-custom-gradle-home:
needs: build-distribution
uses: ./.github/workflows/integ-test-restore-custom-gradle-home.yml
with:
download-dist: true
restore-gradle-home:
needs: build-distribution
uses: ./.github/workflows/integ-test-restore-gradle-home.yml
with:
runner-os: '["ubuntu-latest"]'
download-dist: true
restore-java-toolchain:
needs: build-distribution
uses: ./.github/workflows/integ-test-restore-java-toolchain.yml
with:
runner-os: '["ubuntu-latest"]'
download-dist: true
sample-kotlin-dsl:
needs: build-distribution
uses: ./.github/workflows/integ-test-sample-kotlin-dsl.yml
with:
runner-os: '["ubuntu-latest"]'
download-dist: true
sample-gradle-plugin:
needs: build-distribution
uses: ./.github/workflows/integ-test-sample-gradle-plugin.yml
with:
runner-os: '["ubuntu-latest"]'
download-dist: true

View File

@@ -1,38 +0,0 @@
name: CI-verify-outputs
on:
pull_request:
types:
- assigned
- review_requested
push:
branches:
- main
- dependabot/**
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Build
run: |
npm install
npm run all
- name: Compare the expected and actual dist/ directories
run: |
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build. See status below:"
git diff
exit 1
fi
id: diff
# If index.js was different than expected, upload the expected version as an artifact
- uses: actions/upload-artifact@v3
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with:
name: dist
path: dist/

View File

@@ -1,43 +0,0 @@
name: demo-failure-cases
on:
workflow_dispatch:
jobs:
failing-build:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Test build failure
uses: ./
continue-on-error: true
with:
build-root-directory: .github/workflow-samples/kotlin-dsl
arguments: not-a-valid-task
wrapper-missing:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Test wrapper missing
uses: ./
continue-on-error: true
with:
build-root-directory: .github/workflow-samples/no-wrapper
arguments: help
bad-configuration:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Test bad config value
uses: ./
continue-on-error: true
with:
build-root-directory: .github/workflow-samples/no-wrapper
arguments: help
cache-disabled: yes

View File

@@ -1,43 +0,0 @@
name: Demo Job Summary for Gradle builds
on:
workflow_dispatch:
push:
env:
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
run-gradle-builds:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Build distribution
shell: bash
run: |
npm install
npm run build
- name: Setup Gradle
uses: ./
- name: Build kotlin-dsl project
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew assemble
- name: Build kotlin-dsl project without build scan
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew assemble check --no-scan
- name: Build kotlin-dsl project with build scan publish failure
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew check -Dgradle.enterprise.url=https://not.valid.server
- name: Build groovy-dsl project
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew assemble
- name: Build kotlin-dsl project with multiple gradle invocations
working-directory: .github/workflow-samples/kotlin-dsl
run: |
./gradlew tasks --no-daemon
./gradlew help check
- name: Fail groovy-dsl project
working-directory: .github/workflow-samples/groovy-dsl
continue-on-error: true
run: ./gradlew not-a-real-task

View File

@@ -1,27 +0,0 @@
name: Demo adding build scan comment to PR
on:
pull_request:
types: [assigned, review_requested]
jobs:
gradle:
runs-on: ubuntu-latest
steps:
- name: Checkout project sources
uses: actions/checkout@v3
- name: Setup Gradle
uses: ./
- name: Run build with Gradle wrapper
id: gradle
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew build --scan
- name: "Add build scan URL as PR comment"
uses: actions/github-script@v6
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'PR ready for review: ${{ steps.gradle.outputs.build-scan-url }}'
})

31
.github/workflows/dev.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: dev
on:
pull_request:
push:
jobs:
check:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Build
run: |
npm install
npm run all
- name: Test wrapper
uses: ./
with:
wrapper-directory: __tests__/data/basic
build-root-directory: __tests__/data/basic
arguments: help
- name: Test dist download
uses: ./
with:
gradle-version: 6.5
build-root-directory: __tests__/data/basic
arguments: help

View File

@@ -1,162 +0,0 @@
name: Test action inputs for 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: action-inputs-caching-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
seed-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
# Add "enterprise" to main cache entry but omit "notifications"
gradle-home-cache-includes: |
caches
enterprise
# Exclude build-cache from main cache entry
gradle-home-cache-excludes: |
caches/build-cache-1
- name: Build using Gradle wrapper
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
verify-build:
needs: seed-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:
# Use the same configuration as used in the seed build
gradle-home-cache-includes: |
caches
enterprise
gradle-home-cache-excludes: |
caches/build-cache-1
cache-read-only: true
- name: Execute Gradle build with --offline
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --offline
# Test that build scans are captured when caching is explicitly disabled
cache-disabled:
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-disabled: true
- name: Run Gradle build
id: gradle
working-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}"
- name: Check build scan url is captured
if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v6
with:
script: |
core.setFailed('No build scan detected')
# Test that build scans are captured when caching is disabled because Gradle User Home already exists
cache-disabled-pre-existing-gradle-home:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download distribution if required
uses: ./.github/actions/download-dist
- name: Create dummy Gradle User Home
run: mkdir -p ~/.gradle/caches
- name: Setup Gradle
uses: ./
- name: Run Gradle build
id: gradle
working-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}"
- name: Check build scan url is captured
if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v6
with:
script: |
core.setFailed('No build scan detected')
# Test seed the cache with cache-write-only and verify with cache-read-only
seed-build-write-only:
env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{ inputs.cache-key-prefix }}-write-only-
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-write-only: true
- name: Build using Gradle wrapper
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test
verify-write-only-build:
env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{ inputs.cache-key-prefix }}-write-only-
needs: seed-build-write-only
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: Execute Gradle build with --offline
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --offline

View File

@@ -1,41 +0,0 @@
name: Test action inputs
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: action-inputs-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
action-inputs:
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: Invoke with multi-line arguments
uses: ./
with:
build-root-directory: .github/workflow-samples/groovy-dsl
arguments: |
--configuration-cache
--build-cache
-DsystemProperty=FOO
-PgradleProperty=BAR
test
jar

View File

@@ -1,56 +0,0 @@
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: execution-with-caching-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
seed-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: Execute Gradle build
uses: ./
with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
build-root-directory: .github/workflow-samples/groovy-dsl
arguments: test
# Test that the gradle-user-home is restored
verify-build:
needs: seed-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: Execute Gradle build
uses: ./
with:
cache-read-only: true
build-root-directory: .github/workflow-samples/groovy-dsl
arguments: test --offline -DverifyCachedBuild=true

View File

@@ -1,94 +0,0 @@
name: Test execution
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: execution-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
# Tests for executing with different Gradle versions.
# Each build verifies that it is executed with the expected Gradle version.
gradle-execution:
strategy:
matrix:
os: ${{fromJSON(inputs.runner-os)}}
include:
- os: windows-latest
script-suffix: '.bat'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download distribution if required
uses: ./.github/actions/download-dist
- name: Test use defined Gradle version
uses: ./
with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
gradle-version: 6.9
build-root-directory: .github/workflow-samples/no-wrapper
arguments: help -DgradleVersionCheck=6.9
- name: Test use Gradle version alias
uses: ./
with:
gradle-version: release-candidate
build-root-directory: .github/workflow-samples/no-wrapper
arguments: help
- name: Test use defined Gradle executable
uses: ./
with:
gradle-executable: .github/workflow-samples/groovy-dsl/gradlew${{ matrix.script-suffix }}
build-root-directory: .github/workflow-samples/no-wrapper
arguments: help
gradle-versions:
strategy:
matrix:
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
build-root-suffix: -gradle-5
- gradle: 4.10.3
build-root-suffix: -gradle-4
- gradle: 3.5.1
build-root-suffix: -gradle-4
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download distribution if required
uses: ./.github/actions/download-dist
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 8
- name: Run Gradle build
uses: ./
id: gradle
with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
gradle-version: ${{matrix.gradle}}
build-root-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
arguments: help -DgradleVersionCheck=${{matrix.gradle}}
- name: Check build scan url
if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v6
with:
script: |
core.setFailed('No build scan detected')

View File

@@ -1,98 +0,0 @@
name: Test provision Gradle versions
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: provision-gradle-versions-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
# Tests for executing with different Gradle versions.
# Each build verifies that it is executed with the expected Gradle version.
provision-gradle:
strategy:
matrix:
os: ${{fromJSON(inputs.runner-os)}}
include:
- os: windows-latest
script-suffix: '.bat'
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 with v6.9
uses: ./
with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
gradle-version: 6.9
- name: Test uses Gradle v6.9
working-directory: .github/workflow-samples/no-wrapper
run: gradle help "-DgradleVersionCheck=6.9"
- name: Setup Gradle with v7.1.1
uses: ./
with:
gradle-version: 7.1.1
- name: Test uses Gradle v7.1.1
working-directory: .github/workflow-samples/no-wrapper
run: gradle help "-DgradleVersionCheck=7.1.1"
- name: Setup Gradle with release-candidate
uses: ./
with:
gradle-version: release-candidate
- name: Test use release-candidate
working-directory: .github/workflow-samples/no-wrapper
run: gradle help
gradle-versions:
strategy:
matrix:
gradle: [7.3, 6.9, 5.6.4, 4.10.3, 3.5.1]
os: ${{fromJSON(inputs.runner-os)}}
include:
- gradle: 5.6.4
build-root-suffix: -gradle-5
- gradle: 4.10.3
build-root-suffix: -gradle-4
- gradle: 3.5.1
build-root-suffix: -gradle-4
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download distribution if required
uses: ./.github/actions/download-dist
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 8
- name: Setup Gradle
uses: ./
with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
gradle-version: ${{ matrix.gradle }}
- name: Run Gradle build
id: gradle
working-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}"
- name: Check build scan url
if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v6
with:
script: |
core.setFailed('No build scan detected')

View File

@@ -1,162 +0,0 @@
name: Test restore configuration-cache
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: restore-configuration-cache-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
seed-build-groovy:
env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy
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: Groovy build with configuration-cache enabled
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --configuration-cache
verify-build-groovy:
env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy
needs: seed-build-groovy
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: Groovy build with configuration-cache enabled
id: execute
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')
# Check that the build can run when no extracted cache entries are restored
gradle-user-home-not-fully-restored:
env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy
needs: seed-build-groovy
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 with no extracted cache entries restored
uses: ./
env:
GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl"
with:
cache-read-only: true
- name: Check execute Gradle build with configuration cache enabled (but not restored)
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --configuration-cache
seed-build-kotlin:
env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-kotlin
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: Execute 'help' with configuration-cache enabled
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew help --configuration-cache
modify-build-kotlin:
env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-kotlin-modified
needs: seed-build-kotlin
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: Execute 'test' with configuration-cache enabled
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew test --configuration-cache
# Test restore configuration-cache from the third build invocation
verify-build-kotlin:
env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-kotlin-modified
needs: modify-build-kotlin
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: Execute 'test' again with configuration-cache enabled
id: execute
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')

View File

@@ -1,60 +0,0 @@
name: Test restore custom Gradle Home
on:
workflow_call:
inputs:
cache-key-prefix:
type: string
download-dist:
type: boolean
default: false
env:
DOWNLOAD_DIST: ${{ inputs.download-dist }}
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-custom-gradle-home-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
seed-build:
runs-on: ubuntu-latest
container: fedora:latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download distribution if required
uses: ./.github/actions/download-dist
- name: Setup Java
uses: actions/setup-java@v3
with:
java-version: 11
distribution: temurin
- name: Setup Gradle
uses: ./
with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
- name: Build using Gradle wrapper
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
dependencies-cache:
needs: seed-build
runs-on: ubuntu-latest
container: fedora:latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Download distribution if required
uses: ./.github/actions/download-dist
- name: Setup Java
uses: actions/setup-java@v3
with:
java-version: 11
distribution: temurin
- name: Setup Gradle
uses: ./
with:
cache-read-only: true
- name: Execute Gradle build with --offline
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --offline

View File

@@ -1,77 +0,0 @@
name: Test restore custom Gradle Home
on:
workflow_call:
inputs:
cache-key-prefix:
type: string
download-dist:
type: boolean
default: false
env:
DOWNLOAD_DIST: ${{ inputs.download-dist }}
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-custom-gradle-home-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
seed-build:
runs-on: ubuntu-latest
steps:
- name: Set Gradle User Home
run: |
mkdir -p $GITHUB_WORKSPACE/gradle-user-home
echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/gradle-user-home" >> $GITHUB_ENV
- 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 using Gradle wrapper
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --info
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
dependencies-cache:
needs: seed-build
runs-on: ubuntu-latest
steps:
- name: Set Gradle User Home
run: |
mkdir -p $GITHUB_WORKSPACE/gradle-user-home
echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/gradle-user-home" >> $GITHUB_ENV
- 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: Execute Gradle build with --offline
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --offline --info
# Test that the gradle-user-home cache will cache and restore local build-cache
build-cache:
needs: seed-build
runs-on: ubuntu-latest
steps:
- name: Set Gradle User Home
run: |
mkdir -p $GITHUB_WORKSPACE/gradle-user-home
echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/gradle-user-home" >> $GITHUB_ENV
- 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: Execute Gradle build and verify tasks from cache
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test -DverifyCachedBuild=true --info

View File

@@ -1,101 +0,0 @@
name: Test restore Gradle Home
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: restore-gradle-home-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-gradle-home
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
seed-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 using Gradle wrapper
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
dependencies-cache:
needs: seed-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: Execute Gradle build with --offline
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test --offline
# Test that the gradle-user-home cache will cache and restore local build-cache
build-cache:
needs: seed-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: Execute Gradle build and verify tasks from cache
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test -DverifyCachedBuild=true
# Check that the build can run when Gradle User Home is not fully restored
no-extracted-cache-entries-restored:
needs: seed-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 with no extracted cache entries restored
uses: ./
env:
GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl"
with:
cache-read-only: true
- name: Check executee Gradle build
working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test

View File

@@ -1,57 +0,0 @@
name: Test restore java toolchains
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: restore-java-toolchain-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
seed-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 using Gradle wrapper
working-directory: .github/workflow-samples/java-toolchain
run: ./gradlew test --info
# Test that the gradle-user-home cache will cache the toolchain, by running build with --offline
toolchain-cache:
needs: seed-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: Execute Gradle build with --offline
working-directory: .github/workflow-samples/java-toolchain
run: ./gradlew test --info --offline

View File

@@ -1,56 +0,0 @@
name: Test sample Gradle Plugin project
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: sample-gradle-plugin-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
seed-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 gradle-plugin project
working-directory: .github/workflow-samples/gradle-plugin
run: ./gradlew build
verify-build:
needs: seed-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: Build gradle-plugin project
working-directory: .github/workflow-samples/gradle-plugin
run: ./gradlew build --offline

View File

@@ -1,56 +0,0 @@
name: Test sample Kotlin DSL project
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: sample-kotlin-dsl-${{ inputs.cache-key-prefix }}
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
jobs:
seed-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 kotlin-dsl project
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew build
verify-build:
needs: seed-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: Build kotlin-dsl project
working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew build --offline

30
.github/workflows/prod.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
# make sure the action works on a clean machine without building
name: prod
on:
push:
branches:
- master
- 'releases/*'
jobs:
check:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Test wrapper
uses: ./
with:
wrapper-directory: __tests__/data/basic
build-root-directory: __tests__/data/basic
arguments: help
- name: Test dist download
uses: ./
with:
gradle-version: 6.5
build-root-directory: __tests__/data/basic
arguments: help

View File

@@ -1,28 +0,0 @@
name: Purge old workflow runs
on:
workflow_dispatch:
inputs:
days:
description: 'Purge runs older than days'
required: true
default: 30
minimum_runs:
description: 'The minimum runs to keep for each workflow.'
required: true
default: 6
delete_workflow_pattern:
description: 'The name of the workflow. if not set then it will target all workflows.'
required: false
jobs:
del_runs:
runs-on: ubuntu-latest
steps:
- name: Purge workflow runs
uses: Mattraks/delete-workflow-runs@v2
with:
token: ${{ github.token }}
repository: ${{ github.repository }}
retain_days: ${{ github.event.inputs.days }}
keep_minimum_runs: ${{ github.event.inputs.minimum_runs }}
delete_workflow_pattern: ${{ github.event.inputs.delete_workflow_pattern }}

4
.gitignore vendored
View File

@@ -98,9 +98,5 @@ Thumbs.db
__tests__/runner/*
# lib/**/*
# IntelliJ IDEA config files
.idea/
*.iml
# ASDF tool configuration
.tool-versions

1
.nvmrc
View File

@@ -1 +0,0 @@
v16

View File

@@ -1,5 +1,5 @@
{
"printWidth": 120,
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"semi": false,

398
README.md
View File

@@ -1,15 +1,17 @@
# Execute Gradle builds in GitHub Actions workflows
# Execute Gradle commands in GitHub Actions workflows
This GitHub Action can be used to configure Gradle and optionally execute a Gradle build on any platform supported by GitHub Actions.
This GitHub Action can be used to run arbitrary Gradle commands on any platform supported by GitHub Actions.
## Use the action to setup Gradle
You might also be interested by the related [Gradle Plugin](https://github.com/eskatos/gradle-github-actions-plugin) that allows your build to easily get GitHub Actions environment and tag Gradle Build Scans accordingly.
## Usage
The following workflow will run `./gradlew build` using the wrapper from the repository on ubuntu, macos and windows. The only prerequisite is to have Java installed, you can define the version you need to run the build using the `actions/setup-java` action.
If you have an existing workflow invoking Gradle, you can add an initial "Setup Gradle" Step to benefit from caching,
build-scan capture and other features of the gradle-build-action.
All subsequent Gradle invocations will benefit from this initial setup, via `init` scripts added to the Gradle User Home.
```yaml
# .github/workflows/gradle-build-pr.yml
name: Run Gradle on PRs
on: pull_request
jobs:
@@ -19,61 +21,87 @@ jobs:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
distribution: temurin
java-version: 11
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Execute Gradle build
run: ./gradlew build
- uses: eskatos/gradle-command-action@v1
with:
arguments: build
```
## Why use the `gradle-build-action`?
## Gradle arguments
It is possible to directly invoke Gradle in your workflow, and the `actions/setup-java@v3` action provides a simple way to cache Gradle dependencies.
The `arguments` input can used to pass arbitrary arguments to the `gradle` command line.
However, the `gradle-build-action` offers a number of advantages over this approach:
Here are some valid examples:
```yaml
arguments: build
arguments: check --scan
arguments: some arbitrary tasks
arguments: build -PgradleProperty=foo
arguments: build -DsystemProperty=bar
....
```
- 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.
- 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.
See `gradle --help` for more information.
The `gradle-build-action` is designed to provide these benefits with minimal configuration.
These features work both when Gradle is executed via the `gradle-build-action` and for any Gradle execution in subsequent steps.
When using `gradle-build-action` we recommend that you _not_ use `actions/cache` or `actions/setup-java@v3` to explicitly cache the Gradle User Home. Doing so may interfere with the caching provided by this action.
## Use a specific Gradle version
The `gradle-build-action` can download and install a specified Gradle version, adding this installed version to the PATH.
Downloaded Gradle versions are stored in the GitHub Actions cache, to avoid requiring downloading again later.
If you need to pass environment variables, simply use the GitHub Actions workflow syntax:
```yaml
- uses: gradle/gradle-build-action@v2
with:
gradle-version: 6.5
- uses: eskatos/gradle-command-action@v1
env:
CI: true
```
The `gradle-version` parameter can be set to any valid Gradle version.
## Run a build from a different directory
```yaml
- uses: eskatos/gradle-command-action@v1
with:
build-root-directory: some/subdirectory
```
## Use a Gradle wrapper from a different directory
```yaml
- uses: eskatos/gradle-command-action@v1
with:
wrapper-directory: path/to/wrapper-directory
```
## Use a specific `gradle` executable
```yaml
- uses: eskatos/gradle-command-action@v1
with:
gradle-executable: path/to/gradle
```
## Setup and use a declared Gradle version
```yaml
- uses: eskatos/gradle-command-action@v1
with:
gradle-version: 5.6.2
```
`gradle-version` can be set to any valid Gradle version.
Moreover, you can use the following aliases:
| Alias | Selects |
| --- |---|
| `wrapper` | The Gradle wrapper's version (default, useful for matrix builds) |
| `current` | The current [stable release](https://gradle.org/install/) |
| `release-candidate` | The current [release candidate](https://gradle.org/release-candidate/) if any, otherwise fallback to `current` |
| `nightly` | The latest [nightly](https://gradle.org/nightly/), fails if none. |
| `release-nightly` | The latest [release nightly](https://gradle.org/release-nightly/), fails if none. |
| `wrapper` | The Gradle wrapper's version (default, useful for matrix builds) |
| `current` | The current [stable release](https://gradle.org/install/) |
| `rc` | The current [release candidate](https://gradle.org/release-candidate/) if any, otherwise fallback to `current` |
| `nightly` | The latest [nightly](https://gradle.org/nightly/), fails if none. |
| `release-nightly` | The latest [release nightly](https://gradle.org/release-nightly/), fails if none. |
This can be handy to automatically verify your build works with the latest release candidate of Gradle:
This can be handy to, for example, automatically test your build with the next Gradle version once a release candidate is out:
```yaml
# .github/workflows/test-gradle-rc.yml
name: Test latest Gradle RC
on:
schedule:
@@ -82,24 +110,26 @@ jobs:
gradle-rc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
distribution: temurin
java-version: 11
- uses: gradle/gradle-build-action@v2
- uses: eskatos/gradle-command-action@v1
with:
gradle-version: release-candidate
- run: gradle build --dry-run # just test build configuration
gradle-version: rc
arguments: build --dry-run # just test build configuration
```
## Gradle Execution
# Build scans
If the action is configured with an `arguments` input, then Gradle will execute a Gradle build with the arguments provided.
If your build publishes a [build scan](https://gradle.com/build-scans/) the `gradle-command-action` action will emit the link to the published build scan as an output named `build-scan-url`.
If no `arguments` are provided, the action will not execute Gradle, but will still cache Gradle state and configure build-scan capture for all subsequent Gradle executions.
You can then use that link in subsequent actions of your workflow.
For example:
```yaml
# .github/workflows/gradle-build-pr.yml
name: Run Gradle on PRs
on: pull_request
jobs:
@@ -109,270 +139,16 @@ jobs:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
distribution: temurin
java-version: 11
- name: Setup and execute Gradle 'test' task
uses: gradle/gradle-build-action@v2
- uses: eskatos/gradle-command-action@v1
with:
arguments: test
```
### Multiple Gradle executions in the same Job
It is possible to configure multiple Gradle executions to run sequentially in the same job.
The initial Action step will perform the Gradle setup.
```yaml
- uses: gradle/gradle-build-action@v2
with:
arguments: assemble
- uses: gradle/gradle-build-action@v2
with:
arguments: check
```
### Gradle command-line arguments
The `arguments` input can be used to pass arbitrary arguments to the `gradle` command line.
Arguments can be supplied in a single line, or as a multi-line input.
Here are some valid examples:
```yaml
arguments: build
arguments: check --scan
arguments: some arbitrary tasks
arguments: build -PgradleProperty=foo
arguments: |
build
--scan
-PgradleProperty=foo
-DsystemProperty=bar
```
If you need to pass environment variables, use the GitHub Actions workflow syntax:
```yaml
- uses: gradle/gradle-build-action@v2
env:
CI: true
with:
arguments: build
```
### Gradle build located in a subdirectory
By default, the action will execute Gradle in the root directory of your project.
Use the `build-root-directory` input to target a Gradle build in a subdirectory.
```yaml
- uses: gradle/gradle-build-action@v2
with:
arguments: build
build-root-directory: some/subdirectory
```
### Using a specific Gradle executable
The action will first look for a Gradle wrapper script in the root directory of your project.
If not found, `gradle` will be executed from the PATH.
Use the `gradle-executable` input to execute using a specific Gradle installation.
```yaml
- uses: gradle/gradle-build-action@v2
with:
arguments: build
gradle-executable: /path/to/installed/gradle
```
This mechanism can also be used to target a Gradle wrapper script that is located in a non-default location.
## Caching
By default, this action aims to cache any and all reusable state that may be speed up a subsequent build invocation.
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.
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.
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.
To reduce duplication between cache entries, certain artifacts are cached independently based on their identity.
Artifacts that are cached independently include downloaded dependencies, downloaded wrapper distributions and generated Gradle API jars.
For example, this means that all jobs executing a particular version of the Gradle wrapper will share common entries for wrapper distributions and for generated Gradle API jars.
### Using the caches read-only
By default, the `gradle-build-action` will only write to the cache from Jobs on the default (`main`/`master`) branch.
Jobs on other branches will read entries from the cache but will not write updated entries.
See [Optimizing cache effectiveness](#optimizing-cache-effectiveness) for a more detailed explanation.
In some circumstances it makes sense to change this default, and to configure a workflow Job to read existing cache entries but not to write changes back.
You can configure read-only caching for the `gradle-build-action` as follows:
```yaml
# Only write to the cache for builds on the 'main' and 'release' branches. (Default is 'main' only.)
# Builds on other branches will only read existing entries from the cache.
cache-read-only: ${{ github.ref != 'refs/heads/main' && 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.
The contents to be cached can be fine tuned by including and excluding certain paths with Gradle User Home.
```yaml
# Cache downloaded JDKs in addition to the default directories.
gradle-home-cache-includes: |
caches
notifications
jdks
# Exclude the local build-cache from the directories cached.
gradle-home-cache-excludes: |
caches/build-cache-1
```
You can specify any number of fixed paths or patterns to include or exclude.
File pattern support is documented at https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#patterns-to-match-file-paths.
### Cache debugging and analysis
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 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:
```yaml
env:
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
```
Note that this setting will also prevent certain cache operations from running in parallel, further assisting with debugging.
### Optimizing cache effectiveness
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 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 (`master`/`main`) branch.
Jobs run on other branches will only read from the cache. In most cases, this is the desired behaviour,
because Jobs run against other branches will benefit from the cache Gradle User Home from `main`,
without writing private cache entries that could lead to evicting shared entries.
If you have other long-lived development branches that would benefit from writing to the cache,
you can configure these by overriding the `cache-read-only` action parameter.
See [Using the caches read-only](#using-the-caches-read-only) for more details.
Similarly, you could use `cache-read-only` for certain jobs in the workflow, and instead have these jobs reuse the cache content from upstream jobs.
#### Exclude content from Gradle User Home cache
Each build is different, and some builds produce more Gradle User Home content than others.
[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
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/
```
## Build scans
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`.
You can then use that link in subsequent actions of your workflow. For example:
```yaml
# .github/workflows/gradle-build-pr.yml
name: Run Gradle on PRs
on: pull_request
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
arguments: build
id: gradle
run: ./gradlew build --scan
- name: "Add build scan URL as PR comment"
uses: actions/github-script@v5
if: github.event_name == 'pull_request' && failure()
- uses: example/action-that-comments-on-the-pr@v0
if: failure()
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '❌ ${{ github.workflow }} failed: ${{ steps.gradle.outputs.build-scan-url }}'
})
comment: Build failed ${{ steps.gradle.outputs.build-scan-url }}
```
## 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 is not yet available in any version of GHES. Instead of producing a Job Summary, the build-results summary and caching report will be written to the workflow log, as part of the post-action step.

33
__tests__/cache.test.ts Normal file
View File

@@ -0,0 +1,33 @@
import * as cache from '../src/cache'
import * as path from 'path'
describe('cache', () => {
describe('can extract gradle wrapper slug', () => {
it('from wrapper properties file', async () => {
const version = cache.extractGradleWrapperSlugFrom(
path.resolve(
'__tests__/data/basic/gradle/wrapper/gradle-wrapper.properties'
)
)
expect(version).toBe('6.5-bin')
})
it('for -bin dist', async () => {
const version = cache.extractGradleWrapperSlugFromDistUri(
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-bin.zip'
)
expect(version).toBe('6.5-bin')
})
it('for -all dist', async () => {
const version = cache.extractGradleWrapperSlugFromDistUri(
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-all.zip'
)
expect(version).toBe('6.5-all')
})
it('for milestone', async () => {
const version = cache.extractGradleWrapperSlugFromDistUri(
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.6-milestone-1-all.zip'
)
expect(version).toBe('6.6-milestone-1-all')
})
})
})

6
__tests__/data/basic/.gitattributes vendored Normal file
View 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

View File

@@ -0,0 +1,6 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This is a general purpose Gradle build.
* Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds
*/

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
__tests__/data/basic/gradlew vendored Executable file
View File

@@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

View File

@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,6 +64,21 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
@@ -71,7 +86,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell

View File

@@ -4,9 +4,7 @@
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/7.3/userguide/multi_project_builds.html
* This project uses @Incubating APIs which are subject to change.
* in the user manual at https://docs.gradle.org/6.5/userguide/multi_project_builds.html
*/
rootProject.name = 'gradle-plugin'
include('plugin')
rootProject.name = 'basic'

View File

@@ -1,88 +1,35 @@
name: "Gradle Build Action"
description: 'Configures Gradle for use in GitHub actions, caching useful state in the GitHub actions cache'
name: "Gradle Command"
description: 'Execute Gradle Command Line'
author: 'Paul Merlin <paul@nospere.org>'
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
inputs:
gradle-version:
description: Gradle version to use
wrapper-directory:
description: Path to the Gradle Wrapper directory
required: false
cache-disabled:
description: When 'true', all caching is disabled. No entries will be written to or read from the cache.
required: false
default: false
cache-read-only:
description: |
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.event.repository && github.ref_name != github.event.repository.default_branch }}
cache-write-only:
description: |
When 'true', entries will not be restored from the cache but will be saved at the end of the Job.
Setting this to 'true' implies cache-read-only will be 'false'.
required: false
default: false
gradle-home-cache-includes:
description: Paths within Gradle User Home to cache.
required: false
default: |
caches
notifications
gradle-home-cache-excludes:
description: Paths within Gradle User Home to exclude from cache.
required: false
# e.g. Use the following setting to prevent the local build cache from being saved/restored
# gradle-home-cache-excludes: |
# caches/build-cache-1
arguments:
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.
gradle-version:
description: Gradle version to use
required: false
default: true
# 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`.
# Use at your own risk!
gradle-home-cache-strict-match:
description: When 'true', the action will not attempt to restore the Gradle User Home entries from other Jobs.
build-root-directory:
description: Path to the root directory of the build
required: false
default: false
cache-read-timeout:
description: A timeout value in seconds for cache reads. Requests taking longer that this will be aborted.
required: true
default: 600
workflow-job-context:
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).
arguments:
description: Gradle command line arguments, see gradle --help
required: false
default: ${{ toJSON(matrix) }}
outputs:
build-scan-url:
description: Link to the build scan if any
runs:
using: 'node16'
using: 'node12'
main: 'dist/main/index.js'
post: 'dist/post/index.js'
post-if: success()
branding:
icon: 'box'

67655
dist/main/index.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

66339
dist/post/index.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -3,8 +3,10 @@ module.exports = {
moduleFileExtensions: ['js', 'ts', 'json'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
verbose: true,
setupFilesAfterEnv: ['./jest.setup.js']
}

1
jest.setup.js Normal file
View File

@@ -0,0 +1 @@
jest.setTimeout(10000) // in milliseconds

15401
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,19 @@
{
"name": "gradle-build-action",
"name": "gradle-command-action",
"version": "1.0.0",
"private": true,
"description": "Execute Gradle Build",
"description": "Execute Gradle Command Line",
"scripts": {
"postinstall": "patch-package",
"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",
"build": "ncc build src/main.ts --out dist/main --minify && ncc build src/post.ts --out dist/post --minify",
"test": "jest",
"check": "npm run format && npm run lint",
"all": "npm run format && npm run lint && npm run build && npm test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/gradle/gradle-build-action.git"
"url": "git+https://github.com/eskatos/gradle-command-action.git"
},
"keywords": [
"github",
@@ -23,31 +21,32 @@
"github-actions",
"gradle"
],
"author": "Paul Merlin <paul@nosphere.org>",
"license": "MIT",
"dependencies": {
"@actions/cache": "3.0.3",
"@actions/core": "1.9.1",
"@actions/exec": "1.1.1",
"@actions/github": "5.0.3",
"@actions/glob": "0.3.0",
"@actions/http-client": "2.0.1",
"@actions/tool-cache": "2.0.1",
"string-argv": "0.3.1"
"@actions/core": "1.2.4",
"@actions/exec": "1.0.4",
"@actions/io": "1.0.2",
"@actions/tool-cache": "1.5.5",
"@actions/cache": "0.2.1",
"string-argv": "0.3.1",
"typed-rest-client": "1.7.3",
"unzipper": "0.10.11"
},
"devDependencies": {
"@types/jest": "28.1.7",
"@types/node": "16.11.21",
"@types/unzipper": "0.10.5",
"@typescript-eslint/parser": "5.33.1",
"@vercel/ncc": "0.34.0",
"eslint": "8.22.0",
"eslint-plugin-github": "4.3.7",
"eslint-plugin-jest": "26.8.3",
"jest": "28.1.3",
"js-yaml": "4.1.0",
"patch-package": "6.4.7",
"prettier": "2.7.1",
"ts-jest": "28.0.8",
"typescript": "4.7.4"
"@types/jest": "26.0.0",
"@types/node": "12.12.6",
"@types/unzipper": "0.10.3",
"@typescript-eslint/parser": "3.2.0",
"@zeit/ncc": "0.22.3",
"eslint": "7.2.0",
"eslint-plugin-github": "4.0.1",
"eslint-plugin-jest": "23.13.2",
"jest": "26.0.1",
"jest-circus": "26.0.1",
"js-yaml": "3.14.0",
"prettier": "2.0.5",
"ts-jest": "26.1.0",
"typescript": "3.8.3"
}
}

View File

@@ -1,114 +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 4dc5e88..92d99d5 100644
--- a/node_modules/@actions/cache/lib/cache.js
+++ b/node_modules/@actions/cache/lib/cache.js
@@ -95,26 +95,18 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
}
archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
core.debug(`Archive Path: ${archivePath}`);
+ const restoredEntry = new CacheEntry(cacheEntry.cacheKey);
// Download the cache from the cache entry
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
if (core.isDebug()) {
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');
- 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}`);
- }
+ return restoredEntry;
}
finally {
// Try to delete the archive to save space
@@ -153,6 +145,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()) {
@@ -160,6 +153,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()) {
@@ -182,18 +176,6 @@ function saveCache(paths, key, options) {
core.debug(`Saving Cache (ID: ${cacheId})`);
yield cacheHttpClient.saveCache(cacheId, archivePath, options);
}
- 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 {
@@ -203,8 +185,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

View File

View File

@@ -1,27 +0,0 @@
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
})
}

View File

@@ -1,222 +0,0 @@
import * as core from '@actions/core'
import * as exec from '@actions/exec'
import path from 'path'
import fs from 'fs'
import {CacheListener} from './cache-reporting'
import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete, generateCacheKey} from './cache-utils'
import {ConfigurationCacheEntryExtractor, 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
private cacheDescription: string
protected readonly gradleUserHome: string
constructor(gradleUserHome: string) {
this.gradleUserHome = gradleUserHome
this.cacheName = 'gradle'
this.cacheDescription = 'Gradle User Home'
}
init(): void {
const actionCacheDir = path.resolve(this.gradleUserHome, '.gradle-build-action')
fs.mkdirSync(actionCacheDir, {recursive: true})
const initScriptsDir = path.resolve(this.gradleUserHome, 'init.d')
fs.mkdirSync(initScriptsDir, {recursive: true})
this.initializeGradleUserHome(this.gradleUserHome, initScriptsDir)
}
cacheOutputExists(): boolean {
const cachesDir = path.resolve(this.gradleUserHome, 'caches')
if (fs.existsSync(cachesDir)) {
cacheDebug(`Cache output exists at ${cachesDir}`)
return true
}
return false
}
/**
* Restores the cache entry, finding the closest match to the currently running job.
*/
async restore(listener: CacheListener): Promise<void> {
const entryListener = listener.entry(this.cacheDescription)
const cacheKey = generateCacheKey(this.cacheName)
cacheDebug(
`Requesting ${this.cacheDescription} with
key:${cacheKey.key}
restoreKeys:[${cacheKey.restoreKeys}]`
)
const cacheResult = await restoreCache(this.getCachePath(), cacheKey.key, cacheKey.restoreKeys, entryListener)
if (!cacheResult) {
core.info(`${this.cacheDescription} cache not found. Will initialize empty.`)
return
}
core.saveState(RESTORED_CACHE_KEY_KEY, cacheResult.key)
core.info(`Restored ${this.cacheDescription} from cache key: ${cacheResult.key}`)
try {
await this.afterRestore(listener)
} catch (error) {
core.warning(`Restore ${this.cacheDescription} failed in 'afterRestore': ${error}`)
}
}
/**
* Restore any extracted cache entries after the main Gradle User Home entry is restored.
*/
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 this.debugReportGradleUserHomeSize('after restoring common artifacts')
}
/**
* Saves the cache entry based on the current cache key unless the cache was restored with the exact key,
* in which case we cannot overwrite it.
*
* If the cache entry was restored with a partial match on a restore key, then
* it is saved with the exact key.
*/
async save(listener: CacheListener): Promise<void> {
const cacheKey = generateCacheKey(this.cacheName).key
const restoredCacheKey = core.getState(RESTORED_CACHE_KEY_KEY)
const gradleHomeEntryListener = listener.entry(this.cacheDescription)
if (restoredCacheKey && cacheKey === restoredCacheKey) {
core.info(`Cache hit occurred on the cache key ${cacheKey}, not saving cache.`)
for (const entryListener of listener.cacheEntries) {
if (entryListener === gradleHomeEntryListener) {
entryListener.markNotSaved('cache key not changed')
} else {
entryListener.markNotSaved(`referencing '${this.cacheDescription}' cache entry not saved`)
}
}
return
}
try {
await this.beforeSave(listener)
} catch (error) {
core.warning(`Save ${this.cacheDescription} failed in 'beforeSave': ${error}`)
return
}
core.info(`Caching ${this.cacheDescription} with cache key: ${cacheKey}`)
const cachePath = this.getCachePath()
await saveCache(cachePath, cacheKey, gradleHomeEntryListener)
return
}
/**
* Extract and save any defined extracted cache entries prior to the main Gradle User Home entry being saved.
*/
async beforeSave(listener: CacheListener): Promise<void> {
await this.debugReportGradleUserHomeSize('before saving common artifacts')
this.deleteExcludedPaths()
await Promise.all([
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)"
)
}
/**
* 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 resolvedPaths = rawPaths.map(x => path.resolve(this.gradleUserHome, x))
for (const p of resolvedPaths) {
cacheDebug(`Deleting excluded path: ${p}`)
tryDelete(p)
}
}
/**
* Determines the paths within Gradle User Home to cache.
* By default, this is the 'caches' and 'notifications' directories,
* but this can be overridden by the `gradle-home-cache-includes` parameter.
*/
protected getCachePath(): string[] {
const rawPaths: string[] = core.getMultilineInput(INCLUDE_PATHS_PARAMETER)
rawPaths.push(META_FILE_DIR)
const resolvedPaths = rawPaths.map(x => this.resolveCachePath(x))
cacheDebug(`Using cache paths: ${resolvedPaths}`)
return resolvedPaths
}
private resolveCachePath(rawPath: string): string {
if (rawPath.startsWith('!')) {
const resolved = this.resolveCachePath(rawPath.substring(1))
return `!${resolved}`
}
return path.resolve(this.gradleUserHome, rawPath)
}
private initializeGradleUserHome(gradleUserHome: string, initScriptsDir: string): void {
const initScriptFilenames = ['build-result-capture.init.gradle', 'build-result-capture-service.plugin.groovy']
for (const initScriptFilename of initScriptFilenames) {
const initScriptContent = this.readInitScriptAsString(initScriptFilename)
const initScriptPath = path.resolve(initScriptsDir, initScriptFilename)
fs.writeFileSync(initScriptPath, initScriptContent)
}
}
private readInitScriptAsString(resource: string): string {
// Resolving relative to __dirname will allow node to find the resource at runtime
const absolutePath = path.resolve(__dirname, '..', '..', 'src', 'resources', 'init-scripts', resource)
return fs.readFileSync(absolutePath, 'utf8')
}
/**
* When cache debugging is enabled, this method will give a detailed report
* of the Gradle User Home contents.
*/
private async debugReportGradleUserHomeSize(label: string): Promise<void> {
if (!isCacheDebuggingEnabled()) {
return
}
if (!fs.existsSync(this.gradleUserHome)) {
return
}
const result = await exec.getExecOutput('du', ['-h', '-c', '-t', '5M'], {
cwd: this.gradleUserHome,
silent: true,
ignoreReturnCode: true
})
core.info(`Gradle User Home (directories >5M): ${label}`)
core.info(
result.stdout
.trimEnd()
.replace(/\t/g, ' ')
.split('\n')
.map(it => {
return ` ${it}`
})
.join('\n')
)
core.info('-----------------------')
}
}

View File

@@ -1,395 +0,0 @@
import path from 'path'
import fs from 'fs'
import * as core from '@actions/core'
import * as glob from '@actions/glob'
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 './build-results'
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'
/**
* Represents the result of attempting to load or store an extracted cache entry.
* An undefined cacheKey indicates that the operation did not succeed.
* The collected results are then used to populate the `cache-metadata.json` file for later use.
*/
class ExtractedCacheEntry {
artifactType: string
pattern: string
cacheKey: string | undefined
constructor(artifactType: string, pattern: string, cacheKey: string | undefined) {
this.artifactType = artifactType
this.pattern = pattern
this.cacheKey = cacheKey
}
}
/**
* Representation of all of the extracted cache entries for this Gradle User Home.
* This object is persisted to JSON file in the Gradle User Home directory for storing,
* and subsequently used to restore the Gradle User Home.
*/
class ExtractedCacheEntryMetadata {
entries: ExtractedCacheEntry[] = []
}
/**
* The specification for a type of extracted cache entry.
*/
class ExtractedCacheEntryDefinition {
artifactType: string
pattern: string
bundle: boolean
uniqueFileNames = true
constructor(artifactType: string, pattern: string, bundle: boolean) {
this.artifactType = artifactType
this.pattern = pattern
this.bundle = bundle
}
withNonUniqueFileNames(): ExtractedCacheEntryDefinition {
this.uniqueFileNames = false
return this
}
}
/**
* Caches and restores the entire Gradle User Home directory, extracting entries containing common artifacts
* for more efficient storage.
*/
abstract class AbstractEntryExtractor {
protected readonly gradleUserHome: string
private extractorName: string
constructor(gradleUserHome: string, extractorName: string) {
this.gradleUserHome = gradleUserHome
this.extractorName = extractorName
}
/**
* Restores any artifacts that were cached separately, based on the information in the `cache-metadata.json` file.
* Each extracted cache entry is restored in parallel, except when debugging is enabled.
*/
async restore(listener: CacheListener): Promise<void> {
const previouslyExtractedCacheEntries = this.loadExtractedCacheEntries()
const processes: Promise<ExtractedCacheEntry>[] = []
for (const cacheEntry of previouslyExtractedCacheEntries) {
const artifactType = cacheEntry.artifactType
const entryListener = listener.entry(cacheEntry.pattern)
// Handle case where the extracted-cache-entry definitions have been changed
const skipRestore = process.env[SKIP_RESTORE_VAR] || ''
if (skipRestore.includes(artifactType)) {
core.info(`Not restoring extracted cache entry for ${artifactType}`)
entryListener.markRequested('SKIP_RESTORE')
} else {
processes.push(
this.awaitForDebugging(
this.restoreExtractedCacheEntry(
artifactType,
cacheEntry.cacheKey!,
cacheEntry.pattern,
entryListener
)
)
)
}
}
this.saveMetadataForCacheResults(await Promise.all(processes))
}
private async restoreExtractedCacheEntry(
artifactType: string,
cacheKey: string,
pattern: string,
listener: CacheEntryListener
): Promise<ExtractedCacheEntry> {
const restoredEntry = await restoreCache([pattern], cacheKey, [], listener)
if (restoredEntry) {
core.info(`Restored ${artifactType} with key ${cacheKey} to ${pattern}`)
return new ExtractedCacheEntry(artifactType, pattern, cacheKey)
} else {
core.info(`Did not restore ${artifactType} with key ${cacheKey} to ${pattern}`)
return new ExtractedCacheEntry(artifactType, pattern, undefined)
}
}
/**
* Saves any artifacts that are configured to be cached separately, based on the extracted cache entry definitions.
* Each entry is extracted and saved in parallel, except when debugging is enabled.
*/
async extract(listener: CacheListener): Promise<void> {
// Load the cache entry definitions (from config) and the previously restored entries (from persisted metadata file)
const cacheEntryDefinitions = this.getExtractedCacheEntryDefinitions()
cacheDebug(
`Extracting cache entries for ${this.extractorName}: ${JSON.stringify(cacheEntryDefinitions, null, 2)}`
)
const previouslyRestoredEntries = this.loadExtractedCacheEntries()
const cacheActions: Promise<ExtractedCacheEntry>[] = []
// For each cache entry definition, determine if it has already been restored, and if not, extract it
for (const cacheEntryDefinition of cacheEntryDefinitions) {
const artifactType = cacheEntryDefinition.artifactType
const pattern = cacheEntryDefinition.pattern
// Find all matching files for this cache entry definition
const globber = await glob.create(pattern, {
implicitDescendants: false,
followSymbolicLinks: false
})
const matchingFiles = await globber.glob()
if (matchingFiles.length === 0) {
cacheDebug(`No files found to cache for ${artifactType}`)
continue
}
if (cacheEntryDefinition.bundle) {
// For an extracted "bundle", use the defined pattern and cache all matching files in a single entry.
cacheActions.push(
this.awaitForDebugging(
this.saveExtractedCacheEntry(
matchingFiles,
artifactType,
pattern,
cacheEntryDefinition.uniqueFileNames,
previouslyRestoredEntries,
listener.entry(pattern)
)
)
)
} else {
// Otherwise cache each matching file in a separate entry, using the complete file path as the cache pattern.
for (const cacheFile of matchingFiles) {
cacheActions.push(
this.awaitForDebugging(
this.saveExtractedCacheEntry(
[cacheFile],
artifactType,
cacheFile,
cacheEntryDefinition.uniqueFileNames,
previouslyRestoredEntries,
listener.entry(cacheFile)
)
)
)
}
}
}
this.saveMetadataForCacheResults(await Promise.all(cacheActions))
}
private async saveExtractedCacheEntry(
matchingFiles: string[],
artifactType: string,
pattern: string,
uniqueFileNames: boolean,
previouslyRestoredEntries: ExtractedCacheEntry[],
entryListener: CacheEntryListener
): Promise<ExtractedCacheEntry> {
const cacheKey = uniqueFileNames
? this.createCacheKeyFromFileNames(artifactType, matchingFiles)
: await this.createCacheKeyFromFileContents(artifactType, pattern)
const previouslyRestoredKey = previouslyRestoredEntries.find(
x => x.artifactType === artifactType && x.pattern === pattern
)?.cacheKey
if (previouslyRestoredKey === cacheKey) {
cacheDebug(`No change to previously restored ${artifactType}. Not saving.`)
entryListener.markNotSaved('contents unchanged')
} else {
core.info(`Caching ${artifactType} with path '${pattern}' and cache key: ${cacheKey}`)
await saveCache([pattern], cacheKey, entryListener)
}
for (const file of matchingFiles) {
tryDelete(file)
}
return new ExtractedCacheEntry(artifactType, pattern, cacheKey)
}
protected createCacheKeyFromFileNames(artifactType: string, files: string[]): string {
const cacheKeyPrefix = getCacheKeyPrefix()
const relativeFiles = files.map(x => path.relative(this.gradleUserHome, x))
const key = hashFileNames(relativeFiles)
cacheDebug(`Generating cache key for ${artifactType} from file names: ${relativeFiles}`)
return `${cacheKeyPrefix}${artifactType}-${key}`
}
protected async createCacheKeyFromFileContents(artifactType: string, pattern: string): Promise<string> {
const cacheKeyPrefix = getCacheKeyPrefix()
const key = await glob.hashFiles(pattern)
cacheDebug(`Generating cache key for ${artifactType} from files matching: ${pattern}`)
return `${cacheKeyPrefix}${artifactType}-${key}`
}
// Run actions sequentially if debugging is enabled
private async awaitForDebugging(p: Promise<ExtractedCacheEntry>): Promise<ExtractedCacheEntry> {
if (isCacheDebuggingEnabled()) {
await p
}
return p
}
/**
* Load information about the extracted cache entries previously restored/saved. This is loaded from the 'cache-metadata.json' file.
*/
protected loadExtractedCacheEntries(): ExtractedCacheEntry[] {
const cacheMetadataFile = this.getCacheMetadataFile()
if (!fs.existsSync(cacheMetadataFile)) {
return []
}
const filedata = fs.readFileSync(cacheMetadataFile, 'utf-8')
cacheDebug(`Loaded cache metadata: ${filedata}`)
const extractedCacheEntryMetadata = JSON.parse(filedata) as ExtractedCacheEntryMetadata
return extractedCacheEntryMetadata.entries
}
/**
* Saves information about the extracted cache entries into the 'cache-metadata.json' file.
*/
private saveMetadataForCacheResults(results: ExtractedCacheEntry[]): void {
const extractedCacheEntryMetadata = new ExtractedCacheEntryMetadata()
extractedCacheEntryMetadata.entries = results.filter(x => x.cacheKey !== undefined)
const filedata = JSON.stringify(extractedCacheEntryMetadata)
cacheDebug(`Saving cache metadata: ${filedata}`)
fs.writeFileSync(this.getCacheMetadataFile(), filedata, 'utf-8')
}
private getCacheMetadataFile(): string {
const actionMetadataDirectory = path.resolve(this.gradleUserHome, META_FILE_DIR)
fs.mkdirSync(actionMetadataDirectory, {recursive: true})
return path.resolve(actionMetadataDirectory, `${this.extractorName}-entry-metadata.json`)
}
protected abstract getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[]
}
export class GradleHomeEntryExtractor extends AbstractEntryExtractor {
constructor(gradleUserHome: string) {
super(gradleUserHome, 'gradle-home')
}
async extract(listener: CacheListener): Promise<void> {
await this.deleteWrapperZips()
return super.extract(listener)
}
/**
* Delete any downloaded wrapper zip files that are not needed after extraction.
* These files are cleaned up by Gradle >= 7.5, but for older versions we remove them manually.
*/
private async deleteWrapperZips(): Promise<void> {
const wrapperZips = path.resolve(this.gradleUserHome, 'wrapper/dists/*/*/*.zip')
const globber = await glob.create(wrapperZips, {
implicitDescendants: false,
followSymbolicLinks: false
})
for (const wrapperZip of await globber.glob()) {
cacheDebug(`Deleting wrapper zip: ${wrapperZip}`)
await tryDelete(wrapperZip)
}
}
/**
* Return the extracted cache entry definitions, which determine which artifacts will be cached
* separately from the rest of the Gradle User Home cache entry.
*/
protected getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[] {
const entryDefinition = (
artifactType: string,
patterns: string[],
bundle: boolean
): ExtractedCacheEntryDefinition => {
const resolvedPatterns = patterns
.map(x => {
const isDir = x.endsWith('/')
const resolved = path.resolve(this.gradleUserHome, x)
return isDir ? `${resolved}/` : resolved // Restore trailing '/' removed by path.resolve()
})
.join('\n')
return new ExtractedCacheEntryDefinition(artifactType, resolvedPatterns, bundle)
}
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('dependencies', ['caches/modules-*/files-*/*/*/*/*'], true),
entryDefinition('instrumented-jars', ['caches/jars-*/*'], true),
entryDefinition('kotlin-dsl', ['caches/*/kotlin-dsl/*/*'], true)
]
}
}
export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor {
constructor(gradleUserHome: string) {
super(gradleUserHome, 'configuration-cache')
}
/**
* Handle the case where Gradle User Home has not been fully restored, so that the configuration-cache
* entry is not reusable.
*/
async restore(listener: CacheListener): Promise<void> {
if (listener.fullyRestored) {
return super.restore(listener)
}
core.info('Not restoring configuration-cache state, as Gradle User Home was not fully restored')
for (const cacheEntry of this.loadExtractedCacheEntries()) {
listener.entry(cacheEntry.pattern).markRequested('NOT_RESTORED')
}
}
/**
* Extract cache entries for the configuration cache in each project.
*/
protected getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[] {
return this.getProjectRoots().map(projectRoot => {
const configCachePath = path.resolve(projectRoot, '.gradle/configuration-cache')
return new ExtractedCacheEntryDefinition(
'configuration-cache',
configCachePath,
true
).withNonUniqueFileNames()
})
}
/**
* For every Gradle invocation, we record the project root directory. This method returns the entire
* set of project roots, to allow saving of configuration-cache entries for each.
*/
private getProjectRoots(): string[] {
const buildResults = loadBuildResults()
const projectRootDirs = buildResults.map(x => x.rootProjectDir)
return [...new Set(projectRootDirs)] // Remove duplicates
}
}

View File

@@ -1,228 +0,0 @@
import * as core from '@actions/core'
import * as cache from '@actions/cache'
/**
* Collects information on what entries were saved and restored during the action.
* This information is used to generate a summary of the cache usage.
*/
export class CacheListener {
cacheEntries: CacheEntryListener[] = []
cacheReadOnly = false
cacheWriteOnly = false
cacheDisabled = false
get fullyRestored(): boolean {
return this.cacheEntries.every(x => !x.wasRequestedButNotRestored())
}
get cacheStatus(): string {
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'
}
entry(name: string): CacheEntryListener {
for (const entry of this.cacheEntries) {
if (entry.entryName === name) {
return entry
}
}
const newEntry = new CacheEntryListener(name)
this.cacheEntries.push(newEntry)
return newEntry
}
stringify(): string {
return JSON.stringify(this)
}
static rehydrate(stringRep: string): CacheListener {
if (stringRep === '') {
return new CacheListener()
}
const rehydrated: CacheListener = Object.assign(new CacheListener(), JSON.parse(stringRep))
const entries = rehydrated.cacheEntries
for (let index = 0; index < entries.length; index++) {
const rawEntry = entries[index]
entries[index] = Object.assign(new CacheEntryListener(rawEntry.entryName), rawEntry)
}
return rehydrated
}
}
/**
* Collects information on the state of a single cache entry.
*/
export class CacheEntryListener {
entryName: string
requestedKey: string | undefined
requestedRestoreKeys: string[] | undefined
restoredKey: string | undefined
restoredSize: number | undefined
notRestored: string | undefined
savedKey: string | undefined
savedSize: number | undefined
notSaved: string | undefined
constructor(entryName: string) {
this.entryName = entryName
}
wasRequestedButNotRestored(): boolean {
return this.requestedKey !== undefined && this.restoredKey === undefined
}
markRequested(key: string, restoreKeys: string[] = []): CacheEntryListener {
this.requestedKey = key
this.requestedRestoreKeys = restoreKeys
return this
}
markRestored(key: string, size: number | undefined): CacheEntryListener {
this.restoredKey = key
this.restoredSize = size
return this
}
markNotRestored(message: string): CacheEntryListener {
this.notRestored = message
return this
}
markSaved(key: string, size: number | undefined): CacheEntryListener {
this.savedKey = key
this.savedSize = size
return this
}
markAlreadyExists(key: string): CacheEntryListener {
this.savedKey = key
this.savedSize = 0
return this
}
markNotSaved(message: string): CacheEntryListener {
this.notSaved = message
return this
}
}
export function writeCachingReport(listener: CacheListener): void {
const entries = listener.cacheEntries
core.summary.addRaw(
`\n<details><summary><h4>Caching for gradle-build-action was ${listener.cacheStatus} - expand for details</h4></summary>\n`
)
core.summary.addTable([
[
{data: '', header: true},
{data: 'Count', header: true},
{data: 'Total Size (Mb)', header: true}
],
['Entries Restored', `${getCount(entries, e => e.restoredSize)}`, `${getSize(entries, e => e.restoredSize)}`],
['Entries Saved', `${getCount(entries, e => e.savedSize)}`, `${getSize(entries, e => e.savedSize)}`]
])
core.summary.addHeading('Cache Entry Details', 5)
const entryDetails = renderEntryDetails(listener)
core.summary.addRaw(`<pre>
${entryDetails}
</pre>
</details>
`)
}
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)'
}
if (entry.restoredKey === entry.requestedKey) {
return '(Entry restored: exact match found)'
}
return '(Entry restored: partial match found)'
}
function getSavedMessage(entry: CacheEntryListener, cacheReadOnly: boolean): string {
if (entry.notSaved) {
return `(Entry not saved: ${entry.notSaved})`
}
if (entry.savedKey === undefined) {
if (cacheReadOnly) {
return '(Entry not saved: cache is read-only)'
}
return '(Entry not saved: reason unknown)'
}
if (entry.savedSize === 0) {
return '(Entry not saved: entry with key already exists)'
}
return '(Entry saved)'
}
function getCount(
cacheEntries: CacheEntryListener[],
predicate: (value: CacheEntryListener) => number | undefined
): number {
return cacheEntries.filter(e => predicate(e)).length
}
function getSize(
cacheEntries: CacheEntryListener[],
predicate: (value: CacheEntryListener) => number | undefined
): number {
const bytes = cacheEntries.map(e => predicate(e) ?? 0).reduce((p, v) => p + v, 0)
return Math.round(bytes / (1024 * 1024))
}
function formatSize(bytes: number | undefined): string {
if (bytes === undefined || bytes === 0) {
return ''
}
return `${Math.round(bytes / (1024 * 1024))} MB (${bytes} B)`
}

View File

@@ -1,247 +0,0 @@
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import * as github from '@actions/github'
import * as exec from '@actions/exec'
import * as crypto from 'crypto'
import * as path from 'path'
import * as fs from 'fs'
import {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 CACHE_TIMEOUT_PARAMETER = 'cache-read-timeout'
const STRICT_CACHE_MATCH_PARAMETER = 'gradle-home-cache-strict-match'
const CACHE_DEBUG_VAR = 'GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'
const CACHE_KEY_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
const CACHE_KEY_OS_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_ENVIRONMENT'
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'
export function isCacheDisabled(): boolean {
if (!cache.isFeatureAvailable()) {
return true
}
return core.getBooleanInput(CACHE_DISABLED_PARAMETER)
}
export function isCacheReadOnly(): boolean {
return !isCacheWriteOnly() && core.getBooleanInput(CACHE_READONLY_PARAMETER)
}
export function isCacheWriteOnly(): boolean {
return core.getBooleanInput(CACHE_WRITEONLY_PARAMETER)
}
export function isCacheDebuggingEnabled(): boolean {
return process.env[CACHE_DEBUG_VAR] ? true : false
}
function getCacheReadTimeoutMs(): number {
return parseInt(core.getInput(CACHE_TIMEOUT_PARAMETER)) * 1000
}
/**
* Represents a key used to restore a cache entry.
* The Github Actions cache will first try for an exact match on the key.
* If that fails, it will try for a prefix match on any of the restoreKeys.
*/
export class CacheKey {
key: string
restoreKeys: string[]
constructor(key: string, restoreKeys: string[]) {
this.key = key
this.restoreKeys = restoreKeys
}
}
/**
* Generates a cache key specific to the current job execution.
* The key is constructed from the following inputs (with some user overrides):
* - The cache protocol version
* - The name of the cache
* - The runner operating system
* - The name of the Job being executed
* - The matrix values for the Job being executed (job context)
* - The SHA of the commit being executed
*
* Caches are restored by trying to match the these key prefixes in order:
* - The full key with SHA
* - A previous key for this Job + matrix
* - Any previous key for this Job (any matrix)
* - Any previous key for this cache on the current OS
*/
export function generateCacheKey(cacheName: string): CacheKey {
const cacheKeyBase = `${getCacheKeyPrefix()}${CACHE_PROTOCOL_VERSION}${cacheName}`
// At the most general level, share caches for all executions on the same OS
const cacheKeyForEnvironment = `${cacheKeyBase}|${getCacheKeyEnvironment()}`
// Prefer caches that run this job
const cacheKeyForJob = `${cacheKeyForEnvironment}|${getCacheKeyJob()}`
// Prefer (even more) jobs that run this job with the same context (matrix)
const cacheKeyForJobContext = `${cacheKeyForJob}[${getCacheKeyJobInstance()}]`
// Exact match on Git SHA
const cacheKey = `${cacheKeyForJobContext}-${getCacheKeyJobExecution()}`
if (core.getBooleanInput(STRICT_CACHE_MATCH_PARAMETER)) {
return new CacheKey(cacheKey, [cacheKeyForJobContext])
}
return new CacheKey(cacheKey, [cacheKeyForJobContext, cacheKeyForJob, cacheKeyForEnvironment])
}
export function getCacheKeyPrefix(): string {
// Prefix can be used to force change all cache keys (defaults to cache protocol version)
return process.env[CACHE_KEY_PREFIX_VAR] || ''
}
function getCacheKeyEnvironment(): string {
const runnerOs = process.env['RUNNER_OS'] || ''
return process.env[CACHE_KEY_OS_VAR] || runnerOs
}
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
}
function getCacheKeyJobInstance(): string {
const override = process.env[CACHE_KEY_JOB_INSTANCE_VAR]
if (override) {
return override
}
// 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)
return hashStrings([workflowJobContext])
}
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
}
export function hashFileNames(fileNames: string[]): string {
return hashStrings(fileNames.map(x => x.replace(new RegExp(`\\${path.sep}`, 'g'), '/')))
}
export function hashStrings(values: string[]): string {
const hash = crypto.createHash('md5')
for (const value of values) {
hash.update(value)
}
return hash.digest('hex')
}
export async function restoreCache(
cachePath: string[],
cacheKey: string,
cacheRestoreKeys: string[],
listener: CacheEntryListener
): Promise<cache.CacheEntry | undefined> {
listener.markRequested(cacheKey, cacheRestoreKeys)
try {
const restoredEntry = await cache.restoreCache(cachePath, cacheKey, cacheRestoreKeys, {
segmentTimeoutInMs: getCacheReadTimeoutMs()
})
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
}
}
export async function saveCache(cachePath: string[], cacheKey: string, listener: CacheEntryListener): Promise<void> {
try {
const savedEntry = await cache.saveCache(cachePath, cacheKey)
listener.markSaved(savedEntry.key, savedEntry.size)
} 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}`)
}
}
export function cacheDebug(message: string): void {
if (isCacheDebuggingEnabled()) {
core.info(message)
} else {
core.debug(message)
}
}
export function handleCacheFailure(error: unknown, message: string): void {
if (error instanceof cache.ValidationError) {
// Fail on cache validation errors
throw error
}
if (error instanceof cache.ReserveCacheError) {
// Reserve cache errors are expected if the artifact has been previously cached
core.info(`${message}: ${error}`)
} else {
// Warn on all other errors
core.warning(`${message}: ${error}`)
if (error instanceof Error && error.stack) {
cacheDebug(error.stack)
}
}
}
/**
* Attempt to delete a file or directory, waiting to allow locks to be released
*/
export async function tryDelete(file: string): Promise<void> {
const maxAttempts = 5
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
if (!fs.existsSync(file)) {
return
}
try {
const stat = fs.lstatSync(file)
if (stat.isDirectory()) {
fs.rmdirSync(file, {recursive: true})
} else {
fs.unlinkSync(file)
}
return
} catch (error) {
if (attempt === maxAttempts) {
core.warning(`Failed to delete ${file}, which will impact caching.
It is likely locked by another process. Output of 'jps -ml':
${await getJavaProcesses()}`)
throw error
} else {
cacheDebug(`Attempt to delete ${file} failed. Will try again.`)
await delay(1000)
}
}
}
}
async function delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function getJavaProcesses(): Promise<string> {
const jpsOutput = await exec.getExecOutput('jps', ['-lm'])
return jpsOutput.stdout
}

97
src/cache.ts Normal file
View File

@@ -0,0 +1,97 @@
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import * as path from 'path'
import * as fs from 'fs'
import * as os from 'os'
const WRAPPER_CACHE_KEY = 'WRAPPER_CACHE_KEY'
const WRAPPER_CACHE_PATH = 'WRAPPER_CACHE_PATH'
const WRAPPER_CACHE_RESULT = 'WRAPPER_CACHE_RESULT'
export async function restoreCachedWrapperDist(
executableDirectory: string
): Promise<void> {
const wrapperSlug = extractGradleWrapperSlugFrom(
path.join(
path.resolve(executableDirectory),
'gradle/wrapper/gradle-wrapper.properties'
)
)
if (!wrapperSlug) return
const wrapperCacheKey = `wrapper-${wrapperSlug}`
const wrapperCachePath = path.join(
os.homedir(),
`.gradle/wrapper/dists/gradle-${wrapperSlug}`
)
core.saveState(WRAPPER_CACHE_KEY, wrapperCacheKey)
core.saveState(WRAPPER_CACHE_PATH, wrapperCachePath)
const restoredKey = await cache.restoreCache(
[wrapperCachePath],
wrapperCacheKey
)
if (!restoredKey) {
core.info(
'Wrapper installation cache not found, expect a Gradle distribution download.'
)
return
}
core.saveState(WRAPPER_CACHE_RESULT, restoredKey)
core.info(`Wrapper installation restored from cache key: ${restoredKey}`)
return
}
export async function cacheWrapperDist(): Promise<void> {
const cacheKey = core.getState(WRAPPER_CACHE_KEY)
const cachePath = core.getState(WRAPPER_CACHE_PATH)
const cacheResult = core.getState(WRAPPER_CACHE_RESULT)
if (!cachePath) {
core.debug('No wrapper installation to cache.')
return
}
if (cacheResult && cacheKey === cacheResult) {
core.info(
`Wrapper installation cache hit occurred on the cache key ${cacheKey}, not saving cache.`
)
return
}
try {
await cache.saveCache([cachePath], cacheKey)
} catch (error) {
if (error.name === cache.ValidationError.name) {
throw error
} else if (error.name === cache.ReserveCacheError.name) {
core.info(error.message)
} else {
core.info(`[warning] ${error.message}`)
}
}
return
}
export function extractGradleWrapperSlugFrom(
wrapperProperties: string
): string | null {
const props = fs.readFileSync(wrapperProperties, {encoding: 'utf8'})
const distUrlLine = props
.split('\n')
.find(line => line.startsWith('distributionUrl'))
if (!distUrlLine) return null
return extractGradleWrapperSlugFromDistUri(distUrlLine.substr(16).trim())
}
export function extractGradleWrapperSlugFromDistUri(
distUri: string
): string | null {
const regex = /.*gradle-(.*-(bin|all))\.zip/
const match = distUri.match(regex)
return match ? match[1] : null
}

View File

@@ -1,75 +0,0 @@
import * as core from '@actions/core'
import {isCacheDisabled, isCacheReadOnly, isCacheWriteOnly} from './cache-utils'
import {CacheListener} from './cache-reporting'
import {DaemonController} from './daemon-controller'
import {GradleStateCache} from './cache-base'
const CACHE_RESTORED_VAR = 'GRADLE_BUILD_ACTION_CACHE_RESTORED'
export async function restore(gradleUserHome: string, cacheListener: CacheListener): Promise<void> {
// Bypass restore cache on all but first action step in workflow.
if (process.env[CACHE_RESTORED_VAR]) {
core.info('Cache only restored on first action step.')
return
}
core.exportVariable(CACHE_RESTORED_VAR, true)
const gradleStateCache = new GradleStateCache(gradleUserHome)
if (isCacheDisabled()) {
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.cacheDisabled = true
return
}
if (gradleStateCache.cacheOutputExists()) {
core.info('Gradle User Home already exists: will not restore from cache.')
// Initialize pre-existing Gradle User Home.
gradleStateCache.init()
return
}
gradleStateCache.init()
// Mark the state as restored so that post-action will perform save.
core.saveState(CACHE_RESTORED_VAR, true)
if (isCacheWriteOnly()) {
core.info('Cache is write-only: will not restore from cache.')
cacheListener.cacheWriteOnly = true
return
}
await core.group('Restore Gradle state from cache', async () => {
await gradleStateCache.restore(cacheListener)
})
}
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.cacheReadOnly = true
return
}
await daemonController.stopAllDaemons()
await core.group('Caching Gradle state', async () => {
return new GradleStateCache(gradleUserHome).save(cacheListener)
})
}

Some files were not shown because too many files have changed in this diff Show More