mirror of
https://github.com/gradle/gradle-build-action.git
synced 2025-10-21 00:08:55 +08:00
Compare commits
172 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9b814496b5 | ||
|
f2bb19b43a | ||
|
e3ceb00204 | ||
|
116ac10f81 | ||
|
9f1e4d5588 | ||
|
f1c309a163 | ||
|
202e4e0271 | ||
|
c3afc518f5 | ||
|
1072fff97e | ||
|
04df35b994 | ||
|
0fa1a8d680 | ||
|
78039b1f7f | ||
|
b147a594b1 | ||
|
5298cab81e | ||
|
f0a35701c4 | ||
|
477313b699 | ||
|
90fd69fffb | ||
|
7bf980c8dd | ||
|
27c4618d3e | ||
|
9f79f97603 | ||
|
fdce5083a7 | ||
|
f62c9ea5ea | ||
|
52fbfb7d9e | ||
|
9230b19200 | ||
|
503956ef9b | ||
|
3ad927eab1 | ||
|
1b2936fed4 | ||
|
f313ba7cbe | ||
|
191094ccb5 | ||
|
a748ca2efa | ||
|
501cd3b4dc | ||
|
9b724c303e | ||
|
3c3fdfcc0c | ||
|
3317bc450c | ||
|
0e24fa1975 | ||
|
bd717aced6 | ||
|
3b14e1426f | ||
|
cde360986c | ||
|
ff8a687227 | ||
|
f78055c629 | ||
|
72e45fe25b | ||
|
cfe0b72a03 | ||
|
a6bb0f87a3 | ||
|
a1bb3349df | ||
|
aabb2db775 | ||
|
01def677bf | ||
|
73602de30a | ||
|
aeb23a4bdd | ||
|
0a03a96401 | ||
|
3793ab6467 | ||
|
295371713e | ||
|
c616a64390 | ||
|
f9f94e6203 | ||
|
512233d0e6 | ||
|
685c78279d | ||
|
41740501eb | ||
|
6e17ebd67e | ||
|
f2b17e4179 | ||
|
fec4a42eb0 | ||
|
50d833aa5b | ||
|
df274d47a3 | ||
|
0241d94e72 | ||
|
e9f450e1ba | ||
|
ba0737b352 | ||
|
09f46b2da6 | ||
|
d7b4f42aa6 | ||
|
be330a1b19 | ||
|
32663c1b4d | ||
|
0d0b1b386e | ||
|
c75c228a38 | ||
|
cbc83428b4 | ||
|
8a7ba1315b | ||
|
0d13054264 | ||
|
f1d0d15603 | ||
|
857b1415c7 | ||
|
9edc64b62f | ||
|
8ee841e541 | ||
|
fd236b26bd | ||
|
b886042d0a | ||
|
c6a5c06827 | ||
|
92de6969aa | ||
|
4b12eb719d | ||
|
f64fe7765c | ||
|
b64a252d1c | ||
|
d700906a15 | ||
|
e706aba73c | ||
|
53af4d4f57 | ||
|
b10e7caf66 | ||
|
3f03131b48 | ||
|
adcc4faa55 | ||
|
db5c425004 | ||
|
52e5a688fb | ||
|
8827545ceb | ||
|
971ff49395 | ||
|
937999e9cc | ||
|
a0998071eb | ||
|
53e57a851c | ||
|
800e52f373 | ||
|
6dd3b19f8f | ||
|
6f4fa19a5b | ||
|
d97141a29c | ||
|
bc3340afc5 | ||
|
5f1def5815 | ||
|
5a7191522f | ||
|
893f0e10c7 | ||
|
d5e58c8a04 | ||
|
2920a48bbc | ||
|
1904e7e80d | ||
|
702bb97ecb | ||
|
b9c806c75d | ||
|
d2799e6f98 | ||
|
2734714920 | ||
|
f75a3e8436 | ||
|
c349fa5b1f | ||
|
08d5b40ca5 | ||
|
0a5ede19a9 | ||
|
a23ac1d61c | ||
|
a8da4e5ca3 | ||
|
4f616f683a | ||
|
222b714890 | ||
|
7dee0f45c2 | ||
|
50ca2bca83 | ||
|
3aa7bfe163 | ||
|
755aebc7d1 | ||
|
06d64212d3 | ||
|
97a4d7a5fd | ||
|
a7260b277e | ||
|
f4e053dda1 | ||
|
a7c463b44a | ||
|
42faf281e6 | ||
|
13d93c1ca1 | ||
|
3edb3cb004 | ||
|
3609b7787a | ||
|
f804351b51 | ||
|
39e51526fb | ||
|
76ea8a76b2 | ||
|
12fc52a49a | ||
|
c157d0a332 | ||
|
c61f5d87b4 | ||
|
c208b4c1f7 | ||
|
b4e6c2b28a | ||
|
b84b650c31 | ||
|
eda0038770 | ||
|
ed5b4ae5dc | ||
|
d50632cfd1 | ||
|
40c0a12211 | ||
|
e977669c8c | ||
|
0e8b9655a0 | ||
|
367ce74a5f | ||
|
3814d56740 | ||
|
e1f84aa44d | ||
|
1041604f29 | ||
|
253d6427fd | ||
|
69aad1f173 | ||
|
887e1a09ab | ||
|
f344e25b84 | ||
|
574cf0ddce | ||
|
37f2880a8a | ||
|
b88c4086b9 | ||
|
aa9bf7774e | ||
|
ed2ff1a448 | ||
|
ddee3ca933 | ||
|
03d1894080 | ||
|
322805e800 | ||
|
92a1f98d35 | ||
|
fdfc5bf12f | ||
|
a25c0ce6cb | ||
|
76f85a724c | ||
|
45ef022607 | ||
|
a72af0b6a6 | ||
|
b0c29bffb7 | ||
|
996094e8e8 |
@@ -10,7 +10,9 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"eslint-comments/no-use": "off",
|
"eslint-comments/no-use": "off",
|
||||||
"import/no-namespace": "off",
|
"import/no-namespace": "off",
|
||||||
|
"i18n-text/no-en": "off",
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
|
"sort-imports": "off",
|
||||||
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
||||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||||
"@typescript-eslint/no-require-imports": "error",
|
"@typescript-eslint/no-require-imports": "error",
|
||||||
|
3
.github/dco.yml
vendored
Normal file
3
.github/dco.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Disable sign-off checking for members of the Gradle GitHub organization
|
||||||
|
require:
|
||||||
|
members: false
|
51
.github/dependabot.yml
vendored
Normal file
51
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
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: "daily"
|
||||||
|
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"
|
Binary file not shown.
@@ -1,5 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
|
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
60
.github/workflow-samples/gradle-plugin/plugin/build.gradle
vendored
Normal file
60
.github/workflow-samples/gradle-plugin/plugin/build.gradle
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
}
|
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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'"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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"));
|
||||||
|
}
|
||||||
|
}
|
12
.github/workflow-samples/gradle-plugin/settings.gradle
vendored
Normal file
12
.github/workflow-samples/gradle-plugin/settings.gradle
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* This file was generated by the Gradle 'init' task.
|
||||||
|
*
|
||||||
|
* The settings file is used to specify which projects to include in your build.
|
||||||
|
*
|
||||||
|
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||||
|
* in the user manual at https://docs.gradle.org/7.3/userguide/multi_project_builds.html
|
||||||
|
* This project uses @Incubating APIs which are subject to change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rootProject.name = 'gradle-plugin'
|
||||||
|
include('plugin')
|
@@ -7,14 +7,13 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation('junit:junit:4.12')
|
testImplementation('junit:junit:4.13.2')
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named("test").configure {
|
tasks.named("test").configure {
|
||||||
// Use an environment variable to bypass config-cache checks
|
// Echo an output value so we can detect configuration-cache usage
|
||||||
if (System.getenv('VERIFY_CACHED_CONFIGURATION') != null) {
|
println "::set-output name=task_configured::yes"
|
||||||
throw new RuntimeException("Configuration was not cached: unexpected configuration of test task")
|
|
||||||
}
|
|
||||||
doLast {
|
doLast {
|
||||||
if (System.properties.verifyCachedBuild) {
|
if (System.properties.verifyCachedBuild) {
|
||||||
throw new RuntimeException("Build was not cached: unexpected execution of test task")
|
throw new RuntimeException("Build was not cached: unexpected execution of test task")
|
Binary file not shown.
@@ -1,5 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
234
.github/workflow-samples/groovy-dsl/gradlew
vendored
Executable file
234
.github/workflow-samples/groovy-dsl/gradlew
vendored
Executable file
@@ -0,0 +1,234 @@
|
|||||||
|
#!/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 \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# 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" "$@"
|
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
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_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
@@ -64,21 +64,6 @@ echo location of your Java installation.
|
|||||||
|
|
||||||
goto fail
|
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
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
@@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
17
.github/workflow-samples/java-toolchain/build.gradle
vendored
Normal file
17
.github/workflow-samples/java-toolchain/build.gradle
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation('junit:junit:4.13.2')
|
||||||
|
}
|
BIN
.github/workflow-samples/java-toolchain/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
.github/workflow-samples/java-toolchain/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
.github/workflow-samples/java-toolchain/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
.github/workflow-samples/java-toolchain/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
234
.github/workflow-samples/java-toolchain/gradlew
vendored
Executable file
234
.github/workflow-samples/java-toolchain/gradlew
vendored
Executable file
@@ -0,0 +1,234 @@
|
|||||||
|
#!/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 \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# 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" "$@"
|
89
.github/workflow-samples/java-toolchain/gradlew.bat
vendored
Normal file
89
.github/workflow-samples/java-toolchain/gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
@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%" == "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%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
1
.github/workflow-samples/java-toolchain/settings.gradle
vendored
Normal file
1
.github/workflow-samples/java-toolchain/settings.gradle
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'basic'
|
10
.github/workflow-samples/java-toolchain/src/test/java/basic/BasicTest.java
vendored
Normal file
10
.github/workflow-samples/java-toolchain/src/test/java/basic/BasicTest.java
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package basic;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class BasicTest {
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
assert true;
|
||||||
|
}
|
||||||
|
}
|
29
.github/workflow-samples/kotlin-dsl/build.gradle.kts
vendored
Normal file
29
.github/workflow-samples/kotlin-dsl/build.gradle.kts
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
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.8.2")
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
.github/workflow-samples/kotlin-dsl/gradle.properties
vendored
Normal file
1
.github/workflow-samples/kotlin-dsl/gradle.properties
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
org.gradle.caching=true
|
BIN
.github/workflow-samples/kotlin-dsl/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
.github/workflow-samples/kotlin-dsl/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
.github/workflow-samples/kotlin-dsl/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
.github/workflow-samples/kotlin-dsl/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
234
.github/workflow-samples/kotlin-dsl/gradlew
vendored
Executable file
234
.github/workflow-samples/kotlin-dsl/gradlew
vendored
Executable file
@@ -0,0 +1,234 @@
|
|||||||
|
#!/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 \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# 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" "$@"
|
89
.github/workflow-samples/kotlin-dsl/gradlew.bat
vendored
Normal file
89
.github/workflow-samples/kotlin-dsl/gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
@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%" == "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%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.gradle.enterprise") version("3.7")
|
id("com.gradle.enterprise") version "3.10"
|
||||||
}
|
}
|
||||||
|
|
||||||
gradleEnterprise {
|
gradleEnterprise {
|
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.gradle.build-scan") version("3.7")
|
id "com.gradle.build-scan" version "3.10"
|
||||||
}
|
}
|
||||||
|
|
||||||
gradleEnterprise {
|
gradleEnterprise {
|
1
.github/workflow-samples/no-wrapper/build.gradle
vendored
Normal file
1
.github/workflow-samples/no-wrapper/build.gradle
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// Required to keep dependabot happy
|
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.gradle.enterprise") version("3.7")
|
id "com.gradle.enterprise" version "3.10"
|
||||||
}
|
}
|
||||||
|
|
||||||
gradleEnterprise {
|
gradleEnterprise {
|
1
.github/workflows/dev.yml
vendored
1
.github/workflows/dev.yml
vendored
@@ -2,6 +2,7 @@ name: Verify generated outputs
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
push:
|
push:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
6
.github/workflows/failure-cases.yml
vendored
6
.github/workflows/failure-cases.yml
vendored
@@ -4,7 +4,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/no-wrapper
|
build-root-directory: .github/workflow-samples/no-wrapper
|
||||||
arguments: help
|
arguments: help
|
||||||
|
|
||||||
bad-configuration:
|
bad-configuration:
|
||||||
@@ -29,6 +29,6 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/no-wrapper
|
build-root-directory: .github/workflow-samples/no-wrapper
|
||||||
arguments: help
|
arguments: help
|
||||||
cache-disabled: yes
|
cache-disabled: yes
|
||||||
|
13
.github/workflows/integTest-action-inputs.yml
vendored
13
.github/workflows/integTest-action-inputs.yml
vendored
@@ -2,17 +2,24 @@ name: Test different action inputs
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
push:
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
action-inputs:
|
action-inputs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
@@ -20,7 +27,7 @@ jobs:
|
|||||||
- name: Invoke with multi-line arguments
|
- name: Invoke with multi-line arguments
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
build-root-directory: .github/workflow-samples/groovy-dsl
|
||||||
arguments: |
|
arguments: |
|
||||||
--configuration-cache
|
--configuration-cache
|
||||||
--build-cache
|
--build-cache
|
||||||
|
139
.github/workflows/integTest-caching-config.yml
vendored
139
.github/workflows/integTest-caching-config.yml
vendored
@@ -2,74 +2,147 @@ name: Test caching configuration
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
push:
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Run initial Gradle builds to push initial cache entries
|
|
||||||
# These builds should start fresh without cache hits, due to the seed injected into the cache key above.
|
|
||||||
seed-build:
|
seed-build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Build using Gradle wrapper
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
# Add "enterprise" to main cache entry but omit "notifications"
|
||||||
arguments: test
|
|
||||||
# Add "wrapper" to main cache entry and remove 'wrapper-zips' bundle
|
|
||||||
# Exclude build-cache from main cache entry
|
|
||||||
gradle-home-cache-includes: |
|
gradle-home-cache-includes: |
|
||||||
caches
|
caches
|
||||||
notifications
|
enterprise
|
||||||
wrapper
|
# Exclude build-cache from main cache entry
|
||||||
gradle-home-cache-excludes: |
|
gradle-home-cache-excludes: |
|
||||||
caches/build-cache-1
|
caches/build-cache-1
|
||||||
gradle-home-cache-artifact-bundles: |
|
- name: Build using Gradle wrapper
|
||||||
[
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
["generated-gradle-jars", "caches/*/generated-gradle-jars/*.jar"],
|
run: ./gradlew test
|
||||||
["dependencies", "caches/modules-*/files-*/*/*/*/*/"],
|
|
||||||
["instrumented-jars", "caches/jars-*/*/"],
|
|
||||||
["kotlin-dsl", "caches/*/kotlin-dsl/*/*/"]
|
|
||||||
]
|
|
||||||
|
|
||||||
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
|
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
|
||||||
verify-build:
|
verify-build:
|
||||||
needs: seed-build
|
needs: seed-build
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Execute Gradle build with --offline
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
# Use the same configuration as used in the seed build
|
||||||
arguments: test --offline
|
|
||||||
cache-read-only: true
|
|
||||||
# Need the same configuration when restoring state from cache
|
|
||||||
gradle-home-cache-includes: |
|
gradle-home-cache-includes: |
|
||||||
caches
|
caches
|
||||||
notifications
|
enterprise
|
||||||
wrapper
|
|
||||||
gradle-home-cache-excludes: |
|
gradle-home-cache-excludes: |
|
||||||
caches/build-cache-1
|
caches/build-cache-1
|
||||||
gradle-home-cache-artifact-bundles: |
|
cache-read-only: true
|
||||||
[
|
- name: Execute Gradle build with --offline
|
||||||
["generated-gradle-jars", "caches/*/generated-gradle-jars/*.jar"],
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
["dependencies", "caches/modules-*/files-*/*/*/*/*/"],
|
run: ./gradlew test --offline
|
||||||
["instrumented-jars", "caches/jars-*/*/"],
|
|
||||||
["kotlin-dsl", "caches/*/kotlin-dsl/*/*/"]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
# Test that build scans are captured when caching is explicitly disabled
|
||||||
|
cache-disabled:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- 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@v3
|
||||||
|
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@v2
|
||||||
|
- 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@v3
|
||||||
|
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: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-write-only-
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- 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: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-write-only-
|
||||||
|
needs: seed-build-write-only
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- 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
|
||||||
|
|
||||||
|
@@ -2,64 +2,143 @@ name: Test save/restore configuration-cache state
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
push:
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
|
||||||
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Run initial Gradle builds to push initial cache entries
|
# Run initial Gradle builds to push initial cache entries
|
||||||
# These builds should start fresh without cache hits, due to the seed injected into the cache key above.
|
# These builds should start fresh without cache hits, due to the seed injected into the cache key above.
|
||||||
seed-build:
|
seed-build-groovy:
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-groovy-
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Build with configuration-cache enabled
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Groovy build with configuration-cache enabled
|
||||||
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
|
run: ./gradlew test --configuration-cache
|
||||||
|
|
||||||
|
configuration-cache-groovy:
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-groovy-
|
||||||
|
needs: seed-build-groovy
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
cache-read-only: true
|
||||||
arguments: test --configuration-cache
|
- 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@v5
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.setFailed('Configuration cache was not used - task was configured unexpectedly')
|
||||||
|
|
||||||
# Test that the project-dot-gradle cache will cache and restore configuration-cache
|
# Check that the build can run when no extracted cache entries are restored
|
||||||
configuration-cache:
|
no-extracted-cache-entries-restored:
|
||||||
needs: seed-build
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-groovy-
|
||||||
|
needs: seed-build-groovy
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Execute Gradle build and verify cached configuration
|
- name: Setup Gradle with no extracted cache entries restored
|
||||||
uses: ./
|
uses: ./
|
||||||
env:
|
env:
|
||||||
VERIFY_CACHED_CONFIGURATION: true
|
GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl"
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
|
||||||
arguments: test --configuration-cache
|
|
||||||
cache-read-only: true
|
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
|
||||||
|
|
||||||
# Check that the build can run when no bundles are restored
|
seed-build-kotlin:
|
||||||
no-bundles-restored:
|
env:
|
||||||
needs: seed-build
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-kotlin-
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Execute Gradle build with no cache artifact bundles restored
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- 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_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-kotlin-
|
||||||
|
needs: seed-build-kotlin
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- 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
|
||||||
|
configuration-cache-kotlin:
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-kotlin-
|
||||||
|
needs: modify-build-kotlin
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
|
||||||
arguments: test --configuration-cache
|
|
||||||
cache-read-only: true
|
cache-read-only: true
|
||||||
gradle-home-cache-artifact-bundles: '[]'
|
- 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@v5
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.setFailed('Configuration cache was not used - task was configured unexpectedly')
|
||||||
|
|
||||||
|
@@ -2,78 +2,87 @@ name: Test save/restore Gradle Home directory
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
push:
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Run initial Gradle builds to push initial cache entries
|
|
||||||
# These builds should start fresh without cache hits, due to the seed injected into the cache key above.
|
|
||||||
seed-build:
|
seed-build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Build using Gradle wrapper
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
- name: Build using Gradle wrapper
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
arguments: test
|
run: ./gradlew test
|
||||||
|
|
||||||
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
|
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
|
||||||
dependencies-cache:
|
dependencies-cache:
|
||||||
needs: seed-build
|
needs: seed-build
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Execute Gradle build with --offline
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
|
||||||
arguments: test --offline
|
|
||||||
cache-read-only: true
|
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
|
# Test that the gradle-user-home cache will cache and restore local build-cache
|
||||||
build-cache:
|
build-cache:
|
||||||
needs: seed-build
|
needs: seed-build
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Execute Gradle build and verify tasks from cache
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
|
||||||
arguments: test -DverifyCachedBuild=true
|
|
||||||
cache-read-only: true
|
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 no bundles are restored
|
# Check that the build can run when Gradle User Home is not fully restored
|
||||||
no-bundles-restored:
|
no-extracted-cache-entries-restored:
|
||||||
needs: seed-build
|
needs: seed-build
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Execute Gradle build with no cache artifact bundles restored
|
- name: Setup Gradle with no extracted cache entries restored
|
||||||
uses: ./
|
uses: ./
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl"
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
|
||||||
arguments: test
|
|
||||||
cache-read-only: true
|
cache-read-only: true
|
||||||
gradle-home-cache-artifact-bundles: '[]'
|
- name: Check executee Gradle build
|
||||||
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
|
run: ./gradlew test
|
||||||
|
|
||||||
|
49
.github/workflows/integTest-caching-java-toolchain.yml
vendored
Normal file
49
.github/workflows/integTest-caching-java-toolchain.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
name: Test save/restore java toolchains
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
seed-build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- 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: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- 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
|
49
.github/workflows/integTest-execution-with-caching.yml
vendored
Normal file
49
.github/workflows/integTest-execution-with-caching.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
name: Test save/restore Gradle state with direct execution
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
seed-build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Execute Gradle build
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
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: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Execute Gradle build
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
build-root-directory: .github/workflow-samples/groovy-dsl
|
||||||
|
arguments: test --offline -DverifyCachedBuild=true
|
||||||
|
|
84
.github/workflows/integTest-execution.yml
vendored
84
.github/workflows/integTest-execution.yml
vendored
@@ -2,11 +2,18 @@ name: Test Gradle execution
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
push:
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Tests for executing with different Gradle versions.
|
# Tests for executing with different Gradle versions.
|
||||||
@@ -14,7 +21,7 @@ jobs:
|
|||||||
gradle-execution:
|
gradle-execution:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
include:
|
include:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
script-suffix: '.bat'
|
script-suffix: '.bat'
|
||||||
@@ -26,82 +33,47 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
gradle-version: 6.9
|
gradle-version: 6.9
|
||||||
build-root-directory: __tests__/samples/no-wrapper
|
build-root-directory: .github/workflow-samples/no-wrapper
|
||||||
arguments: help -DgradleVersionCheck=6.9
|
arguments: help -DgradleVersionCheck=6.9
|
||||||
- name: Test use Gradle version alias
|
- name: Test use Gradle version alias
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
gradle-version: release-candidate
|
gradle-version: release-candidate
|
||||||
build-root-directory: __tests__/samples/no-wrapper
|
build-root-directory: .github/workflow-samples/no-wrapper
|
||||||
arguments: help
|
arguments: help
|
||||||
- name: Test use defined Gradle executable
|
- name: Test use defined Gradle executable
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
gradle-executable: __tests__/samples/groovy-dsl/gradlew${{ matrix.script-suffix }}
|
gradle-executable: .github/workflow-samples/groovy-dsl/gradlew${{ matrix.script-suffix }}
|
||||||
build-root-directory: __tests__/samples/no-wrapper
|
build-root-directory: .github/workflow-samples/no-wrapper
|
||||||
arguments: help -DgradleVersionCheck=7.1.1
|
arguments: help -DgradleVersionCheck=7.4.2
|
||||||
|
|
||||||
gradle-versions:
|
gradle-versions:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
gradle: [7.3, 6.9, 5.6.4, 4.10.3]
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
include:
|
include:
|
||||||
- os: windows-latest
|
- gradle: 5.6.4
|
||||||
script-suffix: '.bat'
|
build-root-suffix: -gradle-5
|
||||||
|
- gradle: 4.10.3
|
||||||
|
build-root-suffix: -gradle-4
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Test Gradle 7
|
- name: Run Gradle build
|
||||||
uses: ./
|
uses: ./
|
||||||
id: gradle7
|
id: gradle
|
||||||
with:
|
with:
|
||||||
gradle-version: 7.2
|
gradle-version: ${{matrix.gradle}}
|
||||||
build-root-directory: __tests__/samples/no-wrapper
|
build-root-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
|
||||||
arguments: help -DgradleVersionCheck=7.2
|
arguments: help -DgradleVersionCheck=${{matrix.gradle}}
|
||||||
- name: Check Gradle 7 scan
|
- name: Check build scan url
|
||||||
if: ${{ !steps.gradle7.outputs.build-scan-url }}
|
if: ${{ !steps.gradle.outputs.build-scan-url }}
|
||||||
uses: actions/github-script@v3
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
core.setFailed('No build scan detected')
|
|
||||||
- name: Test Gradle 6
|
|
||||||
uses: ./
|
|
||||||
id: gradle6
|
|
||||||
with:
|
|
||||||
gradle-version: 6.9
|
|
||||||
build-root-directory: __tests__/samples/no-wrapper
|
|
||||||
arguments: help -DgradleVersionCheck=6.9
|
|
||||||
- name: Check Gradle 6 scan
|
|
||||||
if: ${{ !steps.gradle6.outputs.build-scan-url }}
|
|
||||||
uses: actions/github-script@v3
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
core.setFailed('No build scan detected')
|
|
||||||
- name: Test Gradle 5
|
|
||||||
uses: ./
|
|
||||||
id: gradle5
|
|
||||||
with:
|
|
||||||
gradle-version: 5.6.4
|
|
||||||
build-root-directory: __tests__/samples/no-wrapper-gradle-5
|
|
||||||
arguments: help -DgradleVersionCheck=5.6.4
|
|
||||||
- name: Check Gradle 5 scan
|
|
||||||
if: ${{ !steps.gradle5.outputs.build-scan-url }}
|
|
||||||
uses: actions/github-script@v3
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
core.setFailed('No build scan detected')
|
|
||||||
- name: Test Gradle 4
|
|
||||||
uses: ./
|
|
||||||
id: gradle4
|
|
||||||
with:
|
|
||||||
gradle-version: 4.10.3
|
|
||||||
build-root-directory: __tests__/samples/no-wrapper-gradle-4
|
|
||||||
arguments: help -DgradleVersionCheck=4.10.3
|
|
||||||
- name: Check Gradle 4 scan
|
|
||||||
if: ${{ !steps.gradle4.outputs.build-scan-url }}
|
|
||||||
uses: actions/github-script@v3
|
uses: actions/github-script@v3
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
core.setFailed('No build scan detected')
|
core.setFailed('No build scan detected')
|
||||||
|
|
||||||
|
|
||||||
|
39
.github/workflows/integTest-gradle-user-home.yml
vendored
39
.github/workflows/integTest-gradle-user-home.yml
vendored
@@ -2,12 +2,19 @@ name: Test caching with a custom GRADLE_USER_HOME
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
push:
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
GRADLE_USER_HOME: custom/gradle/home
|
GRADLE_USER_HOME: ${{github.workspace}}/custom/gradle/home
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Run initial Gradle builds to push initial cache entries
|
# Run initial Gradle builds to push initial cache entries
|
||||||
@@ -15,47 +22,49 @@ jobs:
|
|||||||
seed-build:
|
seed-build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Build using Gradle wrapper
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
- name: Build using Gradle wrapper
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
arguments: test
|
run: ./gradlew test --info
|
||||||
|
|
||||||
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
|
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
|
||||||
dependencies-cache:
|
dependencies-cache:
|
||||||
needs: seed-build
|
needs: seed-build
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Execute Gradle build with --offline
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
|
||||||
arguments: test --offline
|
|
||||||
cache-read-only: true
|
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
|
# Test that the gradle-user-home cache will cache and restore local build-cache
|
||||||
build-cache:
|
build-cache:
|
||||||
needs: seed-build
|
needs: seed-build
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Execute Gradle build and verify tasks from cache
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
build-root-directory: __tests__/samples/groovy-dsl
|
|
||||||
arguments: test -DverifyCachedBuild=true
|
|
||||||
cache-read-only: true
|
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
|
||||||
|
83
.github/workflows/integTest-gradle-versions.yml
vendored
Normal file
83
.github/workflows/integTest-gradle-versions.yml
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
name: Test provision different Gradle versions
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
|
|
||||||
|
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: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
script-suffix: '.bat'
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle with v6.9
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
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]
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
include:
|
||||||
|
- gradle: 5.6.4
|
||||||
|
build-root-suffix: -gradle-5
|
||||||
|
- gradle: 4.10.3
|
||||||
|
build-root-suffix: -gradle-4
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
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@v3
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.setFailed('No build scan detected')
|
||||||
|
|
||||||
|
|
47
.github/workflows/integTest-sample-gradle-plugin.yml
vendored
Normal file
47
.github/workflows/integTest-sample-gradle-plugin.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Test caching with Gradle Plugin project using TestKit
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
seed-build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Build gradle-plugin project
|
||||||
|
working-directory: .github/workflow-samples/gradle-plugin
|
||||||
|
run: ./gradlew build
|
||||||
|
|
||||||
|
verify-build:
|
||||||
|
needs: seed-build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Build gradle-plugin project
|
||||||
|
working-directory: .github/workflow-samples/gradle-plugin
|
||||||
|
run: ./gradlew build --offline
|
@@ -2,41 +2,46 @@ name: Test caching with Kotlin DSL
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
push:
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/**'
|
||||||
|
- 'dist/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}:${{github.run_attempt}}-
|
||||||
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Use kotlin-dsl project to verify caching of generated jars and compiled scripts
|
|
||||||
seed-build:
|
seed-build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Build kotlin-dsl project
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
- name: Build kotlin-dsl project
|
||||||
build-root-directory: __tests__/samples/kotlin-dsl
|
working-directory: .github/workflow-samples/kotlin-dsl
|
||||||
arguments: test
|
run: ./gradlew build
|
||||||
|
|
||||||
# Check that the build can run --offline
|
|
||||||
verify-build:
|
verify-build:
|
||||||
needs: seed-build
|
needs: seed-build
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Build kotlin-dsl project
|
- name: Setup Gradle
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
- name: Build kotlin-dsl project
|
||||||
build-root-directory: __tests__/samples/kotlin-dsl
|
working-directory: .github/workflow-samples/kotlin-dsl
|
||||||
arguments: test --offline
|
run: ./gradlew build --offline
|
27
.github/workflows/pr-build-scan-comment.yml
vendored
Normal file
27
.github/workflows/pr-build-scan-comment.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
name: Add a 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@v2
|
||||||
|
- 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@v5
|
||||||
|
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 }}'
|
||||||
|
})
|
224
README.md
224
README.md
@@ -1,14 +1,15 @@
|
|||||||
# Execute Gradle builds in GitHub Actions workflows
|
# Execute Gradle builds in GitHub Actions workflows
|
||||||
|
|
||||||
This GitHub Action can be used to execute a Gradle build on any platform supported by GitHub Actions.
|
This GitHub Action can be used to configure Gradle and optionally execute a Gradle build on any platform supported by GitHub Actions.
|
||||||
|
|
||||||
## Usage
|
## Use the action to setup Gradle
|
||||||
|
|
||||||
The following workflow will run `./gradlew build` on ubuntu, macos and windows.
|
If you have an existing workflow invoking Gradle, you can add an initial "Setup Gradle" Step to benefit from caching,
|
||||||
The only prerequisite is to have Java installed: you define the version of Java you need to run the build using the `actions/setup-java` action.
|
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
|
```yaml
|
||||||
# .github/workflows/gradle-build-pr.yml
|
|
||||||
name: Run Gradle on PRs
|
name: Run Gradle on PRs
|
||||||
on: pull_request
|
on: pull_request
|
||||||
jobs:
|
jobs:
|
||||||
@@ -19,16 +20,109 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 11
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/gradle-build-action@v2
|
||||||
|
|
||||||
|
- name: Execute Gradle build
|
||||||
|
run: ./gradlew build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why use the `gradle-build-action`?
|
||||||
|
|
||||||
|
It is possible to directly invoke Gradle in your workflow, and the `actions/setup-java@v2` action provides a simple way to cache Gradle dependencies.
|
||||||
|
|
||||||
|
However, the `gradle-build-action` offers a number of advantages over this approach:
|
||||||
|
|
||||||
|
- Easily [run the build with different versions of Gradle](#download-install-and-use-a-specific-gradle-version) using the `gradle-version` parameter. Gradle distributions are automatically downloaded and cached.
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
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@v2` 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.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: gradle/gradle-build-action@v2
|
||||||
|
with:
|
||||||
|
gradle-version: 6.5
|
||||||
|
```
|
||||||
|
|
||||||
|
The `gradle-version` parameter 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. |
|
||||||
|
|
||||||
|
This can be handy to automatically verify your build works with the latest release candidate of Gradle:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Test latest Gradle RC
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: 0 0 * * * # daily
|
||||||
|
jobs:
|
||||||
|
gradle-rc:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: gradle/gradle-build-action@v2
|
- uses: gradle/gradle-build-action@v2
|
||||||
with:
|
with:
|
||||||
arguments: build
|
gradle-version: release-candidate
|
||||||
|
- run: gradle build --dry-run # just test build configuration
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Gradle Execution
|
||||||
|
|
||||||
|
If the action is configured with an `arguments` input, then Gradle will execute a Gradle build with the arguments provided.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Run Gradle on PRs
|
||||||
|
on: pull_request
|
||||||
|
jobs:
|
||||||
|
gradle:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
|
||||||
|
- name: Setup and execute Gradle 'test' task
|
||||||
|
uses: gradle/gradle-build-action@v2
|
||||||
|
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.
|
It is possible to configure multiple Gradle executions to run sequentially in the same job.
|
||||||
Each invocation will start its run with the filesystem state remaining from the previous execution.
|
The initial Action step will perform the Gradle setup.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: gradle/gradle-build-action@v2
|
- uses: gradle/gradle-build-action@v2
|
||||||
@@ -39,22 +133,7 @@ Each invocation will start its run with the filesystem state remaining from the
|
|||||||
arguments: check
|
arguments: check
|
||||||
```
|
```
|
||||||
|
|
||||||
### Why is this better than running Gradle directly?
|
### Gradle command-line arguments
|
||||||
|
|
||||||
It is possible to directly invoke Gradle in your workflow, and the `setup-java` action provides a simple way to cache Gradle dependencies.
|
|
||||||
|
|
||||||
However, the `gradle-build-action` offers a number of advantages over this approach:
|
|
||||||
|
|
||||||
- Easily [run the build with different versions of Gradle](#download-install-and-use-a-specific-gradle-version) using the `gradle-version` parameter. Gradle distributions are automatically downloaded and cached.
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
The `gradle-build-action` is designed to provide these benefits with minimal configuration.
|
|
||||||
|
|
||||||
## Gradle Execution
|
|
||||||
|
|
||||||
### Command-line arguments
|
|
||||||
|
|
||||||
The `arguments` input can used to pass arbitrary arguments to the `gradle` command line.
|
The `arguments` input can used to pass arbitrary arguments to the `gradle` command line.
|
||||||
Arguments can be supplied in a single line, or as a multi-line input.
|
Arguments can be supplied in a single line, or as a multi-line input.
|
||||||
@@ -72,8 +151,6 @@ arguments: |
|
|||||||
-DsystemProperty=bar
|
-DsystemProperty=bar
|
||||||
```
|
```
|
||||||
|
|
||||||
See `gradle --help` for more information.
|
|
||||||
|
|
||||||
If you need to pass environment variables, use the GitHub Actions workflow syntax:
|
If you need to pass environment variables, use the GitHub Actions workflow syntax:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -92,6 +169,7 @@ Use the `build-root-directory` input to target a Gradle build in a subdirectory.
|
|||||||
```yaml
|
```yaml
|
||||||
- uses: gradle/gradle-build-action@v2
|
- uses: gradle/gradle-build-action@v2
|
||||||
with:
|
with:
|
||||||
|
arguments: build
|
||||||
build-root-directory: some/subdirectory
|
build-root-directory: some/subdirectory
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -104,55 +182,12 @@ Use the `gradle-executable` input to execute using a specific Gradle installatio
|
|||||||
```yaml
|
```yaml
|
||||||
- uses: gradle/gradle-build-action@v2
|
- uses: gradle/gradle-build-action@v2
|
||||||
with:
|
with:
|
||||||
|
arguments: build
|
||||||
gradle-executable: /path/to/installed/gradle
|
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.
|
This mechanism can also be used to target a Gradle wrapper script that is located in a non-default location.
|
||||||
|
|
||||||
### Download, install and use a specific Gradle version
|
|
||||||
|
|
||||||
The `gradle-build-action` is able to download and install a specific Gradle version to execute.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: gradle/gradle-build-action@v2
|
|
||||||
with:
|
|
||||||
gradle-version: 6.5
|
|
||||||
```
|
|
||||||
|
|
||||||
`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. |
|
|
||||||
|
|
||||||
This can be handy to automatically verify your build works with the latest release candidate of Gradle:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# .github/workflows/test-gradle-rc.yml
|
|
||||||
name: Test latest Gradle RC
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: 0 0 * * * # daily
|
|
||||||
jobs:
|
|
||||||
gradle-rc:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-java@v1
|
|
||||||
with:
|
|
||||||
java-version: 11
|
|
||||||
- uses: gradle/gradle-build-action@v2
|
|
||||||
with:
|
|
||||||
gradle-version: release-candidate
|
|
||||||
arguments: build --dry-run # just test build configuration
|
|
||||||
```
|
|
||||||
|
|
||||||
## Caching
|
## Caching
|
||||||
|
|
||||||
By default, this action aims to cache any and all reusable state that may be speed up a subsequent build invocation.
|
By default, this action aims to cache any and all reusable state that may be speed up a subsequent build invocation.
|
||||||
@@ -171,7 +206,7 @@ cache-disabled: true
|
|||||||
|
|
||||||
### Cache keys
|
### Cache keys
|
||||||
|
|
||||||
For distributions downloaded to satisfy a `gradle-version` parametere 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.
|
Distributions downloaded to satisfy a `gradle-version` parameter are stored outside of Gradle User Home and cached separately. The cache key is unique to the downloaded distribution and will not change over time.
|
||||||
|
|
||||||
The state of the Gradle User Home and configuration-cache are highly dependent on the Gradle execution, so the cache key is composed of the current commit hash and the GitHub actions job id.
|
The state of the Gradle User Home 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.
|
As such, the cache key is likely to change on each subsequent run of GitHub actions.
|
||||||
@@ -253,11 +288,37 @@ Each build is different, and some builds produce more Gradle User Home content t
|
|||||||
[Cache debugging ](#cache-debugging-and-analysis) can provide insight into which cache entries are the largest,
|
[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).
|
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@v2
|
||||||
|
- 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
|
## Build scans
|
||||||
|
|
||||||
If your build publishes a [build scan](https://gradle.com/build-scans/) the `gradle-build-action` action will:
|
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
|
- Add a notice with the link to the GitHub Actions user interface
|
||||||
- Emit the link to the published build scan as an output named `build-scan-url`.
|
- 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:
|
You can then use that link in subsequent actions of your workflow. For example:
|
||||||
|
|
||||||
@@ -269,21 +330,20 @@ jobs:
|
|||||||
gradle:
|
gradle:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Checkout project sources
|
||||||
- uses: actions/setup-java@v1
|
uses: actions/checkout@v2
|
||||||
with:
|
- name: Setup Gradle
|
||||||
java-version: 11
|
uses: gradle/gradle-build-action@v2
|
||||||
- uses: gradle/gradle-build-action@v2
|
- name: Run build with Gradle wrapper
|
||||||
id: gradle
|
id: gradle
|
||||||
with:
|
run: ./gradlew build --scan
|
||||||
arguments: build
|
- name: "Add build scan URL as PR comment"
|
||||||
- name: "Comment build scan url"
|
uses: actions/github-script@v5
|
||||||
uses: actions/github-script@v3
|
|
||||||
if: github.event_name == 'pull_request' && failure()
|
if: github.event_name == 'pull_request' && failure()
|
||||||
with:
|
with:
|
||||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
script: |
|
script: |
|
||||||
github.issues.createComment({
|
github.rest.issues.createComment({
|
||||||
issue_number: context.issue.number,
|
issue_number: context.issue.number,
|
||||||
owner: context.repo.owner,
|
owner: context.repo.owner,
|
||||||
repo: context.repo.repo,
|
repo: context.repo.repo,
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import {CacheEntryListener, CacheListener} from '../src/cache-base'
|
import {CacheEntryListener, CacheListener} from '../src/cache-reporting'
|
||||||
|
|
||||||
describe('caching report', () => {
|
describe('caching report', () => {
|
||||||
describe('reports not fully restored', () => {
|
describe('reports not fully restored', () => {
|
185
__tests__/samples/groovy-dsl/gradlew
vendored
185
__tests__/samples/groovy-dsl/gradlew
vendored
@@ -1,185 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright 2015 the original author or authors.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
##
|
|
||||||
## Gradle start up script for UN*X
|
|
||||||
##
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD="maximum"
|
|
||||||
|
|
||||||
warn () {
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die () {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
nonstop=false
|
|
||||||
case "`uname`" in
|
|
||||||
CYGWIN* )
|
|
||||||
cygwin=true
|
|
||||||
;;
|
|
||||||
Darwin* )
|
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
NONSTOP* )
|
|
||||||
nonstop=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
|
||||||
else
|
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD="java"
|
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
|
||||||
if [ $? -eq 0 ] ; then
|
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
ulimit -n $MAX_FD
|
|
||||||
if [ $? -ne 0 ] ; then
|
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=`expr $i + 1`
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
0) set -- ;;
|
|
||||||
1) set -- "$args0" ;;
|
|
||||||
2) set -- "$args0" "$args1" ;;
|
|
||||||
3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Escape application args
|
|
||||||
save () {
|
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
|
||||||
echo " "
|
|
||||||
}
|
|
||||||
APP_ARGS=`save "$@"`
|
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
|
@@ -1,18 +0,0 @@
|
|||||||
plugins {
|
|
||||||
`java-library`
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
api("org.apache.commons:commons-math3:3.6.1")
|
|
||||||
implementation("com.google.guava:guava:30.1.1-jre")
|
|
||||||
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter:5.7.2")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
55
action.yml
55
action.yml
@@ -1,25 +1,13 @@
|
|||||||
name: "Gradle Build Action"
|
name: "Gradle Build Action"
|
||||||
description: 'Executes a Gradle build, caching useful state in the GitHub actions cache'
|
description: 'Configures Gradle for use in GitHub actions, caching useful state in the GitHub actions cache'
|
||||||
|
|
||||||
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
|
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
gradle-executable:
|
|
||||||
description: Path to the Gradle executable
|
|
||||||
required: false
|
|
||||||
|
|
||||||
gradle-version:
|
gradle-version:
|
||||||
description: Gradle version to use
|
description: Gradle version to use
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
build-root-directory:
|
|
||||||
description: Path to the root directory of the build
|
|
||||||
required: false
|
|
||||||
|
|
||||||
arguments:
|
|
||||||
description: Gradle command line arguments (supports multi-line input)
|
|
||||||
required: false
|
|
||||||
|
|
||||||
cache-disabled:
|
cache-disabled:
|
||||||
description: When 'true', all caching is disabled. No entries will be written to or read from the cache.
|
description: When 'true', all caching is disabled. No entries will be written to or read from the cache.
|
||||||
required: false
|
required: false
|
||||||
@@ -42,40 +30,47 @@ inputs:
|
|||||||
gradle-home-cache-excludes:
|
gradle-home-cache-excludes:
|
||||||
description: Paths within Gradle User Home to exclude from cache.
|
description: Paths within Gradle User Home to exclude from cache.
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
# e.g. Use the following setting to prevent the local build cache from being saved/restored
|
# e.g. Use the following setting to prevent the local build cache from being saved/restored
|
||||||
# gradle-home-cache-excludes: |
|
# gradle-home-cache-excludes: |
|
||||||
# ["caches/build-cache-1"]
|
# caches/build-cache-1
|
||||||
|
|
||||||
# EXPERIMENTAL & INTERNAL CONFIGURATION PROPERTIES
|
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
|
||||||
|
|
||||||
|
# EXPERIMENTAL & INTERNAL ACTION INPUTS
|
||||||
# The following action properties allow fine-grained tweaking of the action caching behaviour.
|
# The following action properties allow fine-grained tweaking of the action caching behaviour.
|
||||||
# These properties are not designed for production use, and may change without notice in a subsequent release of `gradle-build-action`.
|
# 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!
|
# Use at your own risk!
|
||||||
|
cache-write-only:
|
||||||
|
description: When 'true', entries will not be restored from the cache but will be saved at the end of the Job. This allows a 'clean' cache entry to be written.
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
gradle-home-cache-strict-match:
|
||||||
|
description: When 'true', the action will not attempt to restore the Gradle User Home entries from other Jobs.
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
workflow-job-context:
|
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).
|
description: Used to uniquely identify the current job invocation. Defaults to the matrix values for this job; this should not be overridden by users (INTERNAL).
|
||||||
required: false
|
required: false
|
||||||
default: ${{ toJSON(matrix) }}
|
default: ${{ toJSON(matrix) }}
|
||||||
gradle-home-cache-artifact-bundles:
|
|
||||||
description: Names and patterns of artifact bundles to cache separately. (EXPERIMENTAL - may be changed/removed without notice)
|
|
||||||
required: false
|
|
||||||
default: |
|
|
||||||
[
|
|
||||||
["generated-gradle-jars", "caches/*/generated-gradle-jars/*.jar"],
|
|
||||||
["wrapper-zips", "wrapper/dists/*/*/*.zip"],
|
|
||||||
["dependencies", "caches/modules-*/files-*/*/*/*/*/"],
|
|
||||||
["instrumented-jars", "caches/jars-*/*/"],
|
|
||||||
["kotlin-dsl", "caches/*/kotlin-dsl/*/*/"]
|
|
||||||
]
|
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
build-scan-url:
|
build-scan-url:
|
||||||
description: Link to the build scan if any
|
description: Link to the build scan if any
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node16'
|
||||||
main: 'dist/main/index.js'
|
main: 'dist/main/index.js'
|
||||||
post: 'dist/post/index.js'
|
post: 'dist/post/index.js'
|
||||||
post-if: success()
|
|
||||||
|
|
||||||
branding:
|
branding:
|
||||||
icon: 'box'
|
icon: 'box'
|
||||||
|
262
dist/main/index.js
vendored
262
dist/main/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/main/index.js.map
vendored
2
dist/main/index.js.map
vendored
File diff suppressed because one or more lines are too long
3913
dist/main/sourcemap-register.js
vendored
3913
dist/main/sourcemap-register.js
vendored
File diff suppressed because one or more lines are too long
262
dist/post/index.js
vendored
262
dist/post/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/post/index.js.map
vendored
2
dist/post/index.js.map
vendored
File diff suppressed because one or more lines are too long
3913
dist/post/sourcemap-register.js
vendored
3913
dist/post/sourcemap-register.js
vendored
File diff suppressed because one or more lines are too long
@@ -3,10 +3,8 @@ module.exports = {
|
|||||||
moduleFileExtensions: ['js', 'ts', 'json'],
|
moduleFileExtensions: ['js', 'ts', 'json'],
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
testMatch: ['**/*.test.ts'],
|
testMatch: ['**/*.test.ts'],
|
||||||
testRunner: 'jest-circus/runner',
|
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.ts$': 'ts-jest'
|
'^.+\\.ts$': 'ts-jest'
|
||||||
},
|
},
|
||||||
verbose: true,
|
verbose: true
|
||||||
setupFilesAfterEnv: ['./jest.setup.js']
|
|
||||||
}
|
}
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
jest.setTimeout(10000) // in milliseconds
|
|
16855
package-lock.json
generated
16855
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
42
package.json
42
package.json
@@ -24,30 +24,28 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "1.0.7",
|
"@actions/cache": "2.0.4",
|
||||||
"@actions/core": "1.5.0",
|
"@actions/core": "1.8.2",
|
||||||
"@actions/exec": "1.1.0",
|
"@actions/exec": "1.1.1",
|
||||||
"@actions/github": "5.0.0",
|
"@actions/github": "5.0.3",
|
||||||
"@actions/glob": "0.2.0",
|
"@actions/glob": "0.3.0",
|
||||||
"@actions/http-client": "1.0.11",
|
"@actions/http-client": "2.0.1",
|
||||||
"@actions/tool-cache": "1.7.1",
|
"@actions/tool-cache": "2.0.1",
|
||||||
"patch-package": "6.4.7",
|
|
||||||
"string-argv": "0.3.1"
|
"string-argv": "0.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "27.0.2",
|
"@types/node": "16.11.21",
|
||||||
"@types/node": "14.17.3",
|
"@types/unzipper": "0.10.5",
|
||||||
"@types/unzipper": "0.10.4",
|
"@typescript-eslint/parser": "5.23.0",
|
||||||
"@typescript-eslint/parser": "4.28.2",
|
"@vercel/ncc": "0.33.4",
|
||||||
"@zeit/ncc": "0.22.3",
|
"eslint": "8.15.0",
|
||||||
"eslint": "7.30.0",
|
"eslint-plugin-github": "4.3.6",
|
||||||
"eslint-plugin-github": "4.1.3",
|
"eslint-plugin-jest": "26.2.2",
|
||||||
"eslint-plugin-jest": "24.3.6",
|
"jest": "28.1.0",
|
||||||
"jest": "27.3.1",
|
"js-yaml": "4.1.0",
|
||||||
"jest-circus": "27.3.1",
|
"patch-package": "6.4.7",
|
||||||
"js-yaml": "3.14.1",
|
"prettier": "2.6.2",
|
||||||
"prettier": "2.3.2",
|
"ts-jest": "28.0.2",
|
||||||
"ts-jest": "27.0.7",
|
"typescript": "4.6.4"
|
||||||
"typescript": "4.3.5"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,92 +0,0 @@
|
|||||||
diff --git a/node_modules/@actions/cache/lib/cache.d.ts b/node_modules/@actions/cache/lib/cache.d.ts
|
|
||||||
index 805a8e5..d3ab419 100644
|
|
||||||
--- a/node_modules/@actions/cache/lib/cache.d.ts
|
|
||||||
+++ b/node_modules/@actions/cache/lib/cache.d.ts
|
|
||||||
@@ -5,6 +5,11 @@ export declare class ValidationError extends Error {
|
|
||||||
export declare class ReserveCacheError extends Error {
|
|
||||||
constructor(message: string);
|
|
||||||
}
|
|
||||||
+export declare class CacheEntry {
|
|
||||||
+ key: string;
|
|
||||||
+ size?: number;
|
|
||||||
+ constructor(key: string, size?: number);
|
|
||||||
+}
|
|
||||||
/**
|
|
||||||
* Restores cache from keys
|
|
||||||
*
|
|
||||||
@@ -14,7 +19,7 @@ export declare class ReserveCacheError extends Error {
|
|
||||||
* @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
|
|
||||||
*
|
|
||||||
@@ -23,4 +28,4 @@ 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>;
|
|
||||||
diff --git a/node_modules/@actions/cache/lib/cache.js b/node_modules/@actions/cache/lib/cache.js
|
|
||||||
index df78fe0..540114f 100644
|
|
||||||
--- a/node_modules/@actions/cache/lib/cache.js
|
|
||||||
+++ b/node_modules/@actions/cache/lib/cache.js
|
|
||||||
@@ -37,6 +37,13 @@ class ReserveCacheError extends Error {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.ReserveCacheError = ReserveCacheError;
|
|
||||||
+class CacheEntry {
|
|
||||||
+ constructor(key, size) {
|
|
||||||
+ this.key = key;
|
|
||||||
+ this.size = size;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+exports.CacheEntry = CacheEntry;
|
|
||||||
function checkPaths(paths) {
|
|
||||||
if (!paths || paths.length === 0) {
|
|
||||||
throw new ValidationError(`Path Validation Error: At least one directory or file path is required`);
|
|
||||||
@@ -84,6 +91,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
|
||||||
}
|
|
||||||
const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
|
||||||
core.debug(`Archive Path: ${archivePath}`);
|
|
||||||
+ const restoredEntry = new CacheEntry(cacheEntry.cacheKey);
|
|
||||||
try {
|
|
||||||
// Download the cache from the cache entry
|
|
||||||
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
|
|
||||||
@@ -91,6 +99,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
|
||||||
yield tar_1.listTar(archivePath, compressionMethod);
|
|
||||||
}
|
|
||||||
const archiveFileSize = utils.getArchiveFileSizeIsBytes(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');
|
|
||||||
@@ -104,7 +113,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
|
||||||
core.debug(`Failed to delete archive: ${error}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- return cacheEntry.cacheKey;
|
|
||||||
+ return restoredEntry;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.restoreCache = restoreCache;
|
|
||||||
@@ -147,7 +156,7 @@ function saveCache(paths, key, options) {
|
|
||||||
}
|
|
||||||
core.debug(`Saving Cache (ID: ${cacheId})`);
|
|
||||||
yield cacheHttpClient.saveCache(cacheId, archivePath, options);
|
|
||||||
- return cacheId;
|
|
||||||
+ return new CacheEntry(key, archiveFileSize);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.saveCache = saveCache;
|
|
||||||
diff --git a/node_modules/@actions/cache/lib/cache.js.map b/node_modules/@actions/cache/lib/cache.js.map
|
|
||||||
index 05fc369..41b9189 100644
|
|
||||||
--- a/node_modules/@actions/cache/lib/cache.js.map
|
|
||||||
+++ b/node_modules/@actions/cache/lib/cache.js.map
|
|
||||||
@@ -1 +1 @@
|
|
||||||
-{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,oDAAqC;AACrC,2CAA4B;AAC5B,6DAA8C;AAC9C,4EAA6D;AAC7D,wCAA6D;AAG7D,MAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACxD,CAAC;CACF;AAND,0CAMC;AAED,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;QAC/B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAA;IAC1D,CAAC;CACF;AAND,8CAMC;AAED,SAAS,UAAU,CAAC,KAAe;IACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QAChC,MAAM,IAAI,eAAe,CACvB,wEAAwE,CACzE,CAAA;KACF;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE;QACpB,MAAM,IAAI,eAAe,CACvB,yBAAyB,GAAG,wCAAwC,CACrE,CAAA;KACF;IACD,MAAM,KAAK,GAAG,SAAS,CAAA;IACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACpB,MAAM,IAAI,eAAe,CACvB,yBAAyB,GAAG,yBAAyB,CACtD,CAAA;KACF;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAsB,YAAY,CAChC,KAAe,EACf,UAAkB,EAClB,WAAsB,EACtB,OAAyB;;QAEzB,UAAU,CAAC,KAAK,CAAC,CAAA;QAEjB,WAAW,GAAG,WAAW,IAAI,EAAE,CAAA;QAC/B,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,GAAG,WAAW,CAAC,CAAA;QAEzC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;QAC5B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;QAEhC,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE;YACpB,MAAM,IAAI,eAAe,CACvB,4DAA4D,CAC7D,CAAA;SACF;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;YACtB,QAAQ,CAAC,GAAG,CAAC,CAAA;SACd;QAED,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAE5D,qCAAqC;QACrC,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE;YAClE,iBAAiB;SAClB,CAAC,CAAA;QACF,IAAI,EAAC,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,eAAe,CAAA,EAAE;YAChC,kBAAkB;YAClB,OAAO,SAAS,CAAA;SACjB;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,MAAM,KAAK,CAAC,mBAAmB,EAAE,EACjC,KAAK,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAC1C,CAAA;QACD,IAAI,CAAC,KAAK,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAA;QAE1C,IAAI;YACF,0CAA0C;YAC1C,MAAM,eAAe,CAAC,aAAa,CACjC,UAAU,CAAC,eAAe,EAC1B,WAAW,EACX,OAAO,CACR,CAAA;YAED,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;gBAClB,MAAM,aAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;aAC9C;YAED,MAAM,eAAe,GAAG,KAAK,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;YACpE,IAAI,CAAC,IAAI,CACP,gBAAgB,IAAI,CAAC,KAAK,CACxB,eAAe,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAChC,QAAQ,eAAe,KAAK,CAC9B,CAAA;YAED,MAAM,gBAAU,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;YAChD,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;SACzC;gBAAS;YACR,0CAA0C;YAC1C,IAAI;gBACF,MAAM,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;aACpC;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAA;aACjD;SACF;QAED,OAAO,UAAU,CAAC,QAAQ,CAAA;IAC5B,CAAC;CAAA;AAvED,oCAuEC;AAED;;;;;;;GAOG;AACH,SAAsB,SAAS,CAC7B,KAAe,EACf,GAAW,EACX,OAAuB;;QAEvB,UAAU,CAAC,KAAK,CAAC,CAAA;QACjB,QAAQ,CAAC,GAAG,CAAC,CAAA;QAEb,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAE5D,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;QAC7B,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE;YAC7D,iBAAiB;SAClB,CAAC,CAAA;QACF,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE;YAClB,MAAM,IAAI,iBAAiB,CACzB,oCAAoC,GAAG,2CAA2C,CACnF,CAAA;SACF;QACD,IAAI,CAAC,KAAK,CAAC,aAAa,OAAO,EAAE,CAAC,CAAA;QAElC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QAClD,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;QAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAE3C,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,mBAAmB,EAAE,CAAA;QACvD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,aAAa,EACb,KAAK,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAC1C,CAAA;QAED,IAAI,CAAC,KAAK,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAA;QAE1C,MAAM,eAAS,CAAC,aAAa,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAA;QAC7D,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;YAClB,MAAM,aAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;SAC9C;QAED,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA,CAAC,qBAAqB;QAClE,MAAM,eAAe,GAAG,KAAK,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;QACpE,IAAI,CAAC,KAAK,CAAC,cAAc,eAAe,EAAE,CAAC,CAAA;QAC3C,IAAI,eAAe,GAAG,aAAa,EAAE;YACnC,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,KAAK,CAC1B,eAAe,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAChC,QAAQ,eAAe,8CAA8C,CACvE,CAAA;SACF;QAED,IAAI,CAAC,KAAK,CAAC,qBAAqB,OAAO,GAAG,CAAC,CAAA;QAC3C,MAAM,eAAe,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;QAE9D,OAAO,OAAO,CAAA;IAChB,CAAC;CAAA;AArDD,8BAqDC"}
|
|
||||||
\ No newline at end of file
|
|
||||||
+{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,oDAAqC;AACrC,2CAA4B;AAC5B,6DAA8C;AAC9C,4EAA6D;AAC7D,wCAA6D;AAG7D,MAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACxD,CAAC;CACF;AAND,0CAMC;AAED,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;QAC/B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAA;IAC1D,CAAC;CACF;AAND,8CAMC;AAED,MAAa,UAAU;IAIrB,YAAY,GAAW,EAAE,IAAa;QACpC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF;AARD,gCAQC;AAED,SAAS,UAAU,CAAC,KAAe;IACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QAChC,MAAM,IAAI,eAAe,CACvB,wEAAwE,CACzE,CAAA;KACF;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE;QACpB,MAAM,IAAI,eAAe,CACvB,yBAAyB,GAAG,wCAAwC,CACrE,CAAA;KACF;IACD,MAAM,KAAK,GAAG,SAAS,CAAA;IACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACpB,MAAM,IAAI,eAAe,CACvB,yBAAyB,GAAG,yBAAyB,CACtD,CAAA;KACF;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAsB,YAAY,CAChC,KAAe,EACf,UAAkB,EAClB,WAAsB,EACtB,OAAyB;;QAEzB,UAAU,CAAC,KAAK,CAAC,CAAA;QAEjB,WAAW,GAAG,WAAW,IAAI,EAAE,CAAA;QAC/B,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,GAAG,WAAW,CAAC,CAAA;QAEzC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;QAC5B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;QAEhC,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE;YACpB,MAAM,IAAI,eAAe,CACvB,4DAA4D,CAC7D,CAAA;SACF;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;YACtB,QAAQ,CAAC,GAAG,CAAC,CAAA;SACd;QAED,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAE5D,qCAAqC;QACrC,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE;YAClE,iBAAiB;SAClB,CAAC,CAAA;QACF,IAAI,EAAC,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,eAAe,CAAA,EAAE;YAChC,kBAAkB;YAClB,OAAO,SAAS,CAAA;SACjB;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,MAAM,KAAK,CAAC,mBAAmB,EAAE,EACjC,KAAK,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAC1C,CAAA;QACD,IAAI,CAAC,KAAK,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAA;QAE1C,MAAM,aAAa,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,QAAS,CAAC,CAAA;QAC1D,IAAI;YACF,0CAA0C;YAC1C,MAAM,eAAe,CAAC,aAAa,CACjC,UAAU,CAAC,eAAe,EAC1B,WAAW,EACX,OAAO,CACR,CAAA;YAED,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;gBAClB,MAAM,aAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;aAC9C;YAED,MAAM,eAAe,GAAG,KAAK,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;YACpE,aAAa,CAAC,IAAI,GAAG,eAAe,CAAA;YACpC,IAAI,CAAC,IAAI,CACP,gBAAgB,IAAI,CAAC,KAAK,CACxB,eAAe,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAChC,QAAQ,eAAe,KAAK,CAC9B,CAAA;YAED,MAAM,gBAAU,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;YAChD,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;SACzC;gBAAS;YACR,0CAA0C;YAC1C,IAAI;gBACF,MAAM,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;aACpC;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAA;aACjD;SACF;QAED,OAAO,aAAa,CAAA;IACtB,CAAC;CAAA;AAzED,oCAyEC;AAED;;;;;;;GAOG;AACH,SAAsB,SAAS,CAC7B,KAAe,EACf,GAAW,EACX,OAAuB;;QAEvB,UAAU,CAAC,KAAK,CAAC,CAAA;QACjB,QAAQ,CAAC,GAAG,CAAC,CAAA;QAEb,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAE5D,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;QAC7B,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE;YAC7D,iBAAiB;SAClB,CAAC,CAAA;QACF,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE;YAClB,MAAM,IAAI,iBAAiB,CACzB,oCAAoC,GAAG,2CAA2C,CACnF,CAAA;SACF;QACD,IAAI,CAAC,KAAK,CAAC,aAAa,OAAO,EAAE,CAAC,CAAA;QAElC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QAClD,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;QAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAE3C,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,mBAAmB,EAAE,CAAA;QACvD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,aAAa,EACb,KAAK,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAC1C,CAAA;QAED,IAAI,CAAC,KAAK,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAA;QAE1C,MAAM,eAAS,CAAC,aAAa,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAA;QAC7D,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;YAClB,MAAM,aAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;SAC9C;QAED,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA,CAAC,qBAAqB;QAClE,MAAM,eAAe,GAAG,KAAK,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;QACpE,IAAI,CAAC,KAAK,CAAC,cAAc,eAAe,EAAE,CAAC,CAAA;QAC3C,IAAI,eAAe,GAAG,aAAa,EAAE;YACnC,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,KAAK,CAC1B,eAAe,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAChC,QAAQ,eAAe,8CAA8C,CACvE,CAAA;SACF;QAED,IAAI,CAAC,KAAK,CAAC,qBAAqB,OAAO,GAAG,CAAC,CAAA;QAC3C,MAAM,eAAe,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;QAE9D,OAAO,IAAI,UAAU,CAAC,GAAG,EAAE,eAAe,CAAC,CAAA;IAC7C,CAAC;CAAA;AArDD,8BAqDC"}
|
|
||||||
\ No newline at end of file
|
|
90
patches/@actions+cache+2.0.4.patch
Normal file
90
patches/@actions+cache+2.0.4.patch
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
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 0b5a2a8..757ad88 100644
|
||||||
|
--- a/node_modules/@actions/cache/lib/cache.js
|
||||||
|
+++ b/node_modules/@actions/cache/lib/cache.js
|
||||||
|
@@ -93,6 +93,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
||||||
|
}
|
||||||
|
const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
||||||
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
|
+ const restoredEntry = new CacheEntry(cacheEntry.cacheKey);
|
||||||
|
try {
|
||||||
|
// Download the cache from the cache entry
|
||||||
|
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
|
||||||
|
@@ -100,6 +101,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
||||||
|
yield tar_1.listTar(archivePath, compressionMethod);
|
||||||
|
}
|
||||||
|
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath);
|
||||||
|
+ restoredEntry.size = archiveFileSize;
|
||||||
|
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
|
||||||
|
yield tar_1.extractTar(archivePath, compressionMethod);
|
||||||
|
core.info('Cache restored successfully');
|
||||||
|
@@ -113,7 +115,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
||||||
|
core.debug(`Failed to delete archive: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- return cacheEntry.cacheKey;
|
||||||
|
+ return restoredEntry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.restoreCache = restoreCache;
|
||||||
|
@@ -138,6 +140,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()) {
|
||||||
|
@@ -145,6 +148,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()) {
|
||||||
|
@@ -176,8 +180,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
|
1
release/changes.md
Normal file
1
release/changes.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[FIX] Save/restore exploded Gradle dist rather than zip
|
@@ -1,50 +0,0 @@
|
|||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
import * as core from '@actions/core'
|
|
||||||
|
|
||||||
export function writeInitScript(): string {
|
|
||||||
const tmpDir = process.env['RUNNER_TEMP'] || ''
|
|
||||||
const initScript = path.resolve(tmpDir, 'build-scan-capture.init.gradle')
|
|
||||||
core.info(`Writing init script: ${initScript}`)
|
|
||||||
if (fs.existsSync(initScript)) {
|
|
||||||
return initScript
|
|
||||||
}
|
|
||||||
fs.writeFileSync(
|
|
||||||
initScript,
|
|
||||||
`
|
|
||||||
import org.gradle.util.GradleVersion
|
|
||||||
|
|
||||||
// Don't run against the included builds (if the main build has any).
|
|
||||||
def isTopLevelBuild = gradle.getParent() == null
|
|
||||||
if (isTopLevelBuild) {
|
|
||||||
def version = GradleVersion.current().baseVersion
|
|
||||||
def atLeastGradle4 = version >= GradleVersion.version("4.0")
|
|
||||||
def atLeastGradle6 = version >= GradleVersion.version("6.0")
|
|
||||||
|
|
||||||
if (atLeastGradle6) {
|
|
||||||
settingsEvaluated { settings ->
|
|
||||||
if (settings.pluginManager.hasPlugin("com.gradle.enterprise")) {
|
|
||||||
registerCallbacks(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (atLeastGradle4) {
|
|
||||||
projectsEvaluated { gradle ->
|
|
||||||
if (gradle.rootProject.pluginManager.hasPlugin("com.gradle.build-scan")) {
|
|
||||||
registerCallbacks(gradle.rootProject.extensions["buildScan"], gradle.rootProject.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def registerCallbacks(buildScanExtension, rootProjectName) {
|
|
||||||
buildScanExtension.with {
|
|
||||||
def scanFile = new File("gradle-build-scan.txt")
|
|
||||||
buildScanPublished { buildScan ->
|
|
||||||
scanFile.text = buildScan.buildScanUri
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
)
|
|
||||||
return initScript
|
|
||||||
}
|
|
@@ -1,35 +1,34 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as cache from '@actions/cache'
|
import * as exec from '@actions/exec'
|
||||||
import * as github from '@actions/github'
|
import * as github from '@actions/github'
|
||||||
import {isCacheDebuggingEnabled, getCacheKeyPrefix, hashStrings, handleCacheFailure} from './cache-utils'
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
|
import {CacheListener} from './cache-reporting'
|
||||||
|
import {
|
||||||
|
getCacheKeyPrefix,
|
||||||
|
determineJobContext,
|
||||||
|
saveCache,
|
||||||
|
restoreCache,
|
||||||
|
cacheDebug,
|
||||||
|
isCacheDebuggingEnabled,
|
||||||
|
tryDelete
|
||||||
|
} from './cache-utils'
|
||||||
|
import {ConfigurationCacheEntryExtractor, GradleHomeEntryExtractor} from './cache-extract-entries'
|
||||||
|
|
||||||
const JOB_CONTEXT_PARAMETER = 'workflow-job-context'
|
const CACHE_PROTOCOL_VERSION = 'v6-'
|
||||||
|
const RESTORED_CACHE_KEY_KEY = 'restored-cache-key'
|
||||||
|
|
||||||
function generateCacheKey(cacheName: string): CacheKey {
|
export const META_FILE_DIR = '.gradle-build-action'
|
||||||
const cacheKeyPrefix = getCacheKeyPrefix()
|
export const PROJECT_ROOTS_FILE = 'project-roots.txt'
|
||||||
|
const INCLUDE_PATHS_PARAMETER = 'gradle-home-cache-includes'
|
||||||
// At the most general level, share caches for all executions on the same OS
|
const EXCLUDE_PATHS_PARAMETER = 'gradle-home-cache-excludes'
|
||||||
const runnerOs = process.env['RUNNER_OS'] || ''
|
const STRICT_CACHE_MATCH_PARAMETER = 'gradle-home-cache-strict-match'
|
||||||
const cacheKeyForOs = `${cacheKeyPrefix}${cacheName}|${runnerOs}`
|
|
||||||
|
|
||||||
// Prefer caches that run this job
|
|
||||||
const cacheKeyForJob = `${cacheKeyForOs}|${github.context.job}`
|
|
||||||
|
|
||||||
// Prefer (even more) jobs that run this job with the same context (matrix)
|
|
||||||
const cacheKeyForJobContext = `${cacheKeyForJob}[${determineJobContext()}]`
|
|
||||||
|
|
||||||
// Exact match on Git SHA
|
|
||||||
const cacheKey = `${cacheKeyForJobContext}-${github.context.sha}`
|
|
||||||
|
|
||||||
return new CacheKey(cacheKey, [cacheKeyForJobContext, cacheKeyForJob, cacheKeyForOs])
|
|
||||||
}
|
|
||||||
|
|
||||||
function determineJobContext(): string {
|
|
||||||
// By default, we hash the full `matrix` data for the run, to uniquely identify this job invocation
|
|
||||||
const workflowJobContext = core.getInput(JOB_CONTEXT_PARAMETER)
|
|
||||||
return hashStrings([workflowJobContext])
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
class CacheKey {
|
class CacheKey {
|
||||||
key: string
|
key: string
|
||||||
restoreKeys: string[]
|
restoreKeys: string[]
|
||||||
@@ -40,118 +39,99 @@ class CacheKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CacheListener {
|
/**
|
||||||
cacheEntries: CacheEntryListener[] = []
|
* Generates a cache key specific to the current job execution.
|
||||||
|
* The key is constructed from the following inputs:
|
||||||
|
* - A user-defined prefix (optional)
|
||||||
|
* - 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
|
||||||
|
*/
|
||||||
|
function generateCacheKey(cacheName: string): CacheKey {
|
||||||
|
const cacheKeyBase = `${getCacheKeyPrefix()}${CACHE_PROTOCOL_VERSION}${cacheName}`
|
||||||
|
|
||||||
get fullyRestored(): boolean {
|
// At the most general level, share caches for all executions on the same OS
|
||||||
return this.cacheEntries.every(x => !x.wasRequestedButNotRestored())
|
const runnerOs = process.env['RUNNER_OS'] || ''
|
||||||
|
const cacheKeyForOs = `${cacheKeyBase}|${runnerOs}`
|
||||||
|
|
||||||
|
// Prefer caches that run this job
|
||||||
|
const cacheKeyForJob = `${cacheKeyForOs}|${github.context.job}`
|
||||||
|
|
||||||
|
// Prefer (even more) jobs that run this job with the same context (matrix)
|
||||||
|
const cacheKeyForJobContext = `${cacheKeyForJob}[${determineJobContext()}]`
|
||||||
|
|
||||||
|
// Exact match on Git SHA
|
||||||
|
const cacheKey = `${cacheKeyForJobContext}-${github.context.sha}`
|
||||||
|
|
||||||
|
if (core.getBooleanInput(STRICT_CACHE_MATCH_PARAMETER)) {
|
||||||
|
return new CacheKey(cacheKey, [cacheKeyForJobContext])
|
||||||
}
|
}
|
||||||
|
|
||||||
entry(name: string): CacheEntryListener {
|
return new CacheKey(cacheKey, [cacheKeyForJobContext, cacheKeyForJob, cacheKeyForOs])
|
||||||
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 {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CacheEntryListener {
|
export class GradleStateCache {
|
||||||
entryName: string
|
|
||||||
requestedKey: string | undefined
|
|
||||||
requestedRestoreKeys: string[] | undefined
|
|
||||||
restoredKey: string | undefined
|
|
||||||
restoredSize: number | undefined
|
|
||||||
|
|
||||||
savedKey: string | undefined
|
|
||||||
savedSize: number | 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
|
|
||||||
}
|
|
||||||
|
|
||||||
markSaved(key: string, size: number | undefined): CacheEntryListener {
|
|
||||||
this.savedKey = key
|
|
||||||
this.savedSize = size
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class AbstractCache {
|
|
||||||
private cacheName: string
|
private cacheName: string
|
||||||
private cacheDescription: string
|
private cacheDescription: string
|
||||||
private cacheKeyStateKey: string
|
|
||||||
private cacheResultStateKey: string
|
|
||||||
|
|
||||||
protected readonly cacheDebuggingEnabled: boolean
|
protected readonly gradleUserHome: string
|
||||||
|
|
||||||
constructor(cacheName: string, cacheDescription: string) {
|
constructor(gradleUserHome: string) {
|
||||||
this.cacheName = cacheName
|
this.gradleUserHome = gradleUserHome
|
||||||
this.cacheDescription = cacheDescription
|
this.cacheName = 'gradle'
|
||||||
this.cacheKeyStateKey = `CACHE_KEY_${cacheName}`
|
this.cacheDescription = 'Gradle User Home'
|
||||||
this.cacheResultStateKey = `CACHE_RESULT_${cacheName}`
|
|
||||||
this.cacheDebuggingEnabled = isCacheDebuggingEnabled()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async restore(listener: CacheListener): Promise<void> {
|
init(): void {
|
||||||
if (this.cacheOutputExists()) {
|
const actionCacheDir = path.resolve(this.gradleUserHome, '.gradle-build-action')
|
||||||
core.info(`${this.cacheDescription} already exists. Not restoring from cache.`)
|
fs.mkdirSync(actionCacheDir, {recursive: true})
|
||||||
return
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
const cacheKey = this.prepareCacheKey()
|
/**
|
||||||
const entryReport = listener.entry(this.cacheDescription)
|
* Restores the cache entry, finding the closest match to the currently running job.
|
||||||
entryReport.markRequested(cacheKey.key, cacheKey.restoreKeys)
|
*/
|
||||||
|
async restore(listener: CacheListener): Promise<void> {
|
||||||
|
const entryListener = listener.entry(this.cacheDescription)
|
||||||
|
|
||||||
this.debug(
|
const cacheKey = generateCacheKey(this.cacheName)
|
||||||
|
|
||||||
|
cacheDebug(
|
||||||
`Requesting ${this.cacheDescription} with
|
`Requesting ${this.cacheDescription} with
|
||||||
key:${cacheKey.key}
|
key:${cacheKey.key}
|
||||||
restoreKeys:[${cacheKey.restoreKeys}]`
|
restoreKeys:[${cacheKey.restoreKeys}]`
|
||||||
)
|
)
|
||||||
|
|
||||||
const cacheResult = await this.restoreCache(this.getCachePath(), cacheKey.key, cacheKey.restoreKeys)
|
const cacheResult = await restoreCache(this.getCachePath(), cacheKey.key, cacheKey.restoreKeys, entryListener)
|
||||||
|
|
||||||
if (!cacheResult) {
|
if (!cacheResult) {
|
||||||
core.info(`${this.cacheDescription} cache not found. Will start with empty.`)
|
core.info(`${this.cacheDescription} cache not found. Will initialize empty.`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
core.saveState(this.cacheResultStateKey, cacheResult.key)
|
core.saveState(RESTORED_CACHE_KEY_KEY, cacheResult.key)
|
||||||
entryReport.markRestored(cacheResult.key, cacheResult.size)
|
|
||||||
core.info(`Restored ${this.cacheDescription} from cache key: ${cacheResult.key}`)
|
core.info(`Restored ${this.cacheDescription} from cache key: ${cacheResult.key}`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -161,43 +141,28 @@ export abstract class AbstractCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareCacheKey(): CacheKey {
|
/**
|
||||||
const cacheKey = generateCacheKey(this.cacheName)
|
* Restore any extracted cache entries after the main Gradle User Home entry is restored.
|
||||||
|
*/
|
||||||
core.saveState(this.cacheKeyStateKey, cacheKey.key)
|
async afterRestore(listener: CacheListener): Promise<void> {
|
||||||
return cacheKey
|
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')
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async restoreCache(
|
/**
|
||||||
cachePath: string[],
|
* Saves the cache entry based on the current cache key unless the cache was restored with the exact key,
|
||||||
cacheKey: string,
|
* in which case we cannot overwrite it.
|
||||||
cacheRestoreKeys: string[] = []
|
*
|
||||||
): Promise<cache.CacheEntry | undefined> {
|
* If the cache entry was restored with a partial match on a restore key, then
|
||||||
try {
|
* it is saved with the exact key.
|
||||||
return await cache.restoreCache(cachePath, cacheKey, cacheRestoreKeys)
|
*/
|
||||||
} catch (error) {
|
|
||||||
handleCacheFailure(error, `Failed to restore ${cacheKey}`)
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async afterRestore(_listener: CacheListener): Promise<void> {}
|
|
||||||
|
|
||||||
async save(listener: CacheListener): Promise<void> {
|
async save(listener: CacheListener): Promise<void> {
|
||||||
if (!this.cacheOutputExists()) {
|
const cacheKey = generateCacheKey(this.cacheName).key
|
||||||
core.info(`No ${this.cacheDescription} to cache.`)
|
const restoredCacheKey = core.getState(RESTORED_CACHE_KEY_KEY)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const cacheKey = core.getState(this.cacheKeyStateKey)
|
if (restoredCacheKey && cacheKey === restoredCacheKey) {
|
||||||
const cacheResult = core.getState(this.cacheResultStateKey)
|
|
||||||
|
|
||||||
if (!cacheKey) {
|
|
||||||
core.info(`${this.cacheDescription} existed prior to cache restore. Not saving.`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cacheResult && cacheKey === cacheResult) {
|
|
||||||
core.info(`Cache hit occurred on the cache key ${cacheKey}, not saving cache.`)
|
core.info(`Cache hit occurred on the cache key ${cacheKey}, not saving cache.`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -211,34 +176,165 @@ export abstract class AbstractCache {
|
|||||||
|
|
||||||
core.info(`Caching ${this.cacheDescription} with cache key: ${cacheKey}`)
|
core.info(`Caching ${this.cacheDescription} with cache key: ${cacheKey}`)
|
||||||
const cachePath = this.getCachePath()
|
const cachePath = this.getCachePath()
|
||||||
const savedEntry = await this.saveCache(cachePath, cacheKey)
|
const entryListener = listener.entry(this.cacheDescription)
|
||||||
|
await saveCache(cachePath, cacheKey, entryListener)
|
||||||
if (savedEntry) {
|
|
||||||
listener.entry(this.cacheDescription).markSaved(savedEntry.key, savedEntry.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async beforeSave(_listener: CacheListener): Promise<void> {}
|
/**
|
||||||
|
* Extract and save any defined extracted cache entries prior to the main Gradle User Home entry being saved.
|
||||||
protected async saveCache(cachePath: string[], cacheKey: string): Promise<cache.CacheEntry | undefined> {
|
*/
|
||||||
try {
|
async beforeSave(listener: CacheListener): Promise<void> {
|
||||||
return await cache.saveCache(cachePath, cacheKey)
|
await this.debugReportGradleUserHomeSize('before saving common artifacts')
|
||||||
} catch (error) {
|
this.deleteExcludedPaths()
|
||||||
handleCacheFailure(error, `Failed to save cache entry ${cacheKey}`)
|
await Promise.all([
|
||||||
}
|
new GradleHomeEntryExtractor(this.gradleUserHome).extract(listener),
|
||||||
return undefined
|
new ConfigurationCacheEntryExtractor(this.gradleUserHome).extract(listener)
|
||||||
|
])
|
||||||
|
await this.debugReportGradleUserHomeSize(
|
||||||
|
"after extracting common artifacts (only 'caches' and 'notifications' will be stored)"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected debug(message: string): void {
|
/**
|
||||||
if (this.cacheDebuggingEnabled) {
|
* Delete any file paths that are excluded by the `gradle-home-cache-excludes` parameter.
|
||||||
core.info(message)
|
*/
|
||||||
} else {
|
private deleteExcludedPaths(): void {
|
||||||
core.debug(message)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract cacheOutputExists(): boolean
|
/**
|
||||||
protected abstract getCachePath(): string[]
|
* 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 propertiesFile = path.resolve(gradleUserHome, 'gradle.properties')
|
||||||
|
fs.appendFileSync(propertiesFile, 'org.gradle.daemon=false')
|
||||||
|
|
||||||
|
const buildScanCapture = path.resolve(initScriptsDir, 'build-scan-capture.init.gradle')
|
||||||
|
fs.writeFileSync(
|
||||||
|
buildScanCapture,
|
||||||
|
`import org.gradle.util.GradleVersion
|
||||||
|
|
||||||
|
// Only run against root build. Do not run against included builds.
|
||||||
|
def isTopLevelBuild = gradle.getParent() == null
|
||||||
|
if (isTopLevelBuild) {
|
||||||
|
def version = GradleVersion.current().baseVersion
|
||||||
|
def atLeastGradle4 = version >= GradleVersion.version("4.0")
|
||||||
|
def atLeastGradle6 = version >= GradleVersion.version("6.0")
|
||||||
|
|
||||||
|
if (atLeastGradle6) {
|
||||||
|
settingsEvaluated { settings ->
|
||||||
|
if (settings.pluginManager.hasPlugin("com.gradle.enterprise")) {
|
||||||
|
registerCallbacks(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (atLeastGradle4) {
|
||||||
|
projectsEvaluated { gradle ->
|
||||||
|
if (gradle.rootProject.pluginManager.hasPlugin("com.gradle.build-scan")) {
|
||||||
|
registerCallbacks(gradle.rootProject.extensions["buildScan"], gradle.rootProject.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def registerCallbacks(buildScanExtension, rootProjectName) {
|
||||||
|
buildScanExtension.with {
|
||||||
|
def scanFile = new File("gradle-build-scan.txt")
|
||||||
|
def buildFailed = false
|
||||||
|
|
||||||
|
buildFinished { result ->
|
||||||
|
buildFailed = (result.failure != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildScanPublished { buildScan ->
|
||||||
|
scanFile.text = buildScan.buildScanUri
|
||||||
|
|
||||||
|
// Send commands directly to GitHub Actions via STDOUT.
|
||||||
|
def gradleCommand = rootProjectName + " " + gradle.startParameter.taskNames.join(" ")
|
||||||
|
if (buildFailed) {
|
||||||
|
println("::warning ::Gradle build '\${gradleCommand}' FAILED - \${buildScan.buildScanUri}")
|
||||||
|
} else {
|
||||||
|
println("::notice ::Gradle build '\${gradleCommand}' - \${buildScan.buildScanUri}")
|
||||||
|
}
|
||||||
|
println("::set-output name=build-scan-url::\${buildScan.buildScanUri}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
|
const projectRootCapture = path.resolve(initScriptsDir, 'project-root-capture.init.gradle')
|
||||||
|
fs.writeFileSync(
|
||||||
|
projectRootCapture,
|
||||||
|
`
|
||||||
|
// Only run against root build. Do not run against included builds.
|
||||||
|
def isTopLevelBuild = gradle.getParent() == null
|
||||||
|
if (isTopLevelBuild) {
|
||||||
|
settingsEvaluated { settings ->
|
||||||
|
def projectRootEntry = settings.rootDir.absolutePath + "\\n"
|
||||||
|
def projectRootList = new File(settings.gradle.gradleUserHomeDir, "${PROJECT_ROOTS_FILE}")
|
||||||
|
if (!projectRootList.exists() || !projectRootList.text.contains(projectRootEntry)) {
|
||||||
|
projectRootList << projectRootEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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('-----------------------')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
398
src/cache-extract-entries.ts
Normal file
398
src/cache-extract-entries.ts
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as glob from '@actions/glob'
|
||||||
|
|
||||||
|
import {META_FILE_DIR, PROJECT_ROOTS_FILE} from './cache-base'
|
||||||
|
import {CacheEntryListener, CacheListener} from './cache-reporting'
|
||||||
|
import {
|
||||||
|
cacheDebug,
|
||||||
|
getCacheKeyPrefix,
|
||||||
|
hashFileNames,
|
||||||
|
isCacheDebuggingEnabled,
|
||||||
|
restoreCache,
|
||||||
|
saveCache,
|
||||||
|
tryDelete
|
||||||
|
} from './cache-utils'
|
||||||
|
|
||||||
|
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.`)
|
||||||
|
} 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 p of await globber.glob()) {
|
||||||
|
cacheDebug(`Deleting wrapper zip: ${p}`)
|
||||||
|
tryDelete(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 projectList = path.resolve(this.gradleUserHome, PROJECT_ROOTS_FILE)
|
||||||
|
if (!fs.existsSync(projectList)) {
|
||||||
|
core.info(`Missing project list file ${projectList}`)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const projectRoots = fs.readFileSync(projectList, 'utf-8')
|
||||||
|
core.info(`Found project roots '${projectRoots}' in ${projectList}`)
|
||||||
|
return projectRoots.trim().split('\n')
|
||||||
|
}
|
||||||
|
}
|
@@ -1,256 +0,0 @@
|
|||||||
import path from 'path'
|
|
||||||
import fs from 'fs'
|
|
||||||
import os from 'os'
|
|
||||||
import * as core from '@actions/core'
|
|
||||||
import * as glob from '@actions/glob'
|
|
||||||
import * as exec from '@actions/exec'
|
|
||||||
|
|
||||||
import {AbstractCache, CacheEntryListener, CacheListener} from './cache-base'
|
|
||||||
import {getCacheKeyPrefix, hashFileNames, tryDelete} from './cache-utils'
|
|
||||||
|
|
||||||
const META_FILE_DIR = '.gradle-build-action'
|
|
||||||
|
|
||||||
const INCLUDE_PATHS_PARAMETER = 'gradle-home-cache-includes'
|
|
||||||
const EXCLUDE_PATHS_PARAMETER = 'gradle-home-cache-excludes'
|
|
||||||
const ARTIFACT_BUNDLES_PARAMETER = 'gradle-home-cache-artifact-bundles'
|
|
||||||
|
|
||||||
export class GradleUserHomeCache extends AbstractCache {
|
|
||||||
private gradleUserHome: string
|
|
||||||
|
|
||||||
constructor(rootDir: string) {
|
|
||||||
super('gradle', 'Gradle User Home')
|
|
||||||
this.gradleUserHome = this.determineGradleUserHome(rootDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
async afterRestore(listener: CacheListener): Promise<void> {
|
|
||||||
await this.reportGradleUserHomeSize('as restored from cache')
|
|
||||||
await this.restoreArtifactBundles(listener)
|
|
||||||
await this.reportGradleUserHomeSize('after restoring common artifacts')
|
|
||||||
}
|
|
||||||
|
|
||||||
private async restoreArtifactBundles(listener: CacheListener): Promise<void> {
|
|
||||||
const processes: Promise<void>[] = []
|
|
||||||
|
|
||||||
const bundleMetaFiles = await this.getBundleMetaFiles()
|
|
||||||
const bundlePatterns = this.getArtifactBundles()
|
|
||||||
|
|
||||||
// Iterate over all bundle meta files and try to restore
|
|
||||||
for (const bundleMetaFile of bundleMetaFiles) {
|
|
||||||
const bundle = path.basename(bundleMetaFile, '.cache')
|
|
||||||
const entryListener = listener.entry(bundle)
|
|
||||||
const bundlePattern = bundlePatterns.get(bundle)
|
|
||||||
|
|
||||||
// Handle case where the 'artifactBundlePatterns' have been changed
|
|
||||||
if (bundlePattern === undefined) {
|
|
||||||
core.info(`Found bundle metafile for ${bundle} but no such bundle defined`)
|
|
||||||
entryListener.markRequested('BUNDLE_NOT_CONFIGURED')
|
|
||||||
tryDelete(bundleMetaFile)
|
|
||||||
} else {
|
|
||||||
const p = this.restoreArtifactBundle(bundle, bundlePattern, bundleMetaFile, entryListener)
|
|
||||||
// Run sequentially when debugging enabled
|
|
||||||
if (this.cacheDebuggingEnabled) {
|
|
||||||
await p
|
|
||||||
}
|
|
||||||
processes.push(p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all(processes)
|
|
||||||
}
|
|
||||||
|
|
||||||
private async restoreArtifactBundle(
|
|
||||||
bundle: string,
|
|
||||||
bundlePattern: string,
|
|
||||||
bundleMetaFile: string,
|
|
||||||
listener: CacheEntryListener
|
|
||||||
): Promise<void> {
|
|
||||||
const cacheKey = fs.readFileSync(bundleMetaFile, 'utf-8').trim()
|
|
||||||
listener.markRequested(cacheKey)
|
|
||||||
|
|
||||||
const restoredEntry = await this.restoreCache([bundlePattern], cacheKey)
|
|
||||||
if (restoredEntry) {
|
|
||||||
core.info(`Restored ${bundle} with key ${cacheKey} to ${bundlePattern}`)
|
|
||||||
listener.markRestored(restoredEntry.key, restoredEntry.size)
|
|
||||||
} else {
|
|
||||||
core.info(`Did not restore ${bundle} with key ${cacheKey} to ${bundlePattern}`)
|
|
||||||
tryDelete(bundleMetaFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getBundleMetaFile(name: string): string {
|
|
||||||
return path.resolve(this.gradleUserHome, META_FILE_DIR, `${name}.cache`)
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getBundleMetaFiles(): Promise<string[]> {
|
|
||||||
const metaFiles = path.resolve(this.gradleUserHome, META_FILE_DIR, '*.cache')
|
|
||||||
const globber = await glob.create(metaFiles)
|
|
||||||
const bundleFiles = await globber.glob()
|
|
||||||
return bundleFiles
|
|
||||||
}
|
|
||||||
|
|
||||||
async beforeSave(listener: CacheListener): Promise<void> {
|
|
||||||
await this.reportGradleUserHomeSize('before saving common artifacts')
|
|
||||||
this.removeExcludedPaths()
|
|
||||||
await this.saveArtifactBundles(listener)
|
|
||||||
await this.reportGradleUserHomeSize(
|
|
||||||
"after saving common artifacts (only 'caches' and 'notifications' will be stored)"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private removeExcludedPaths(): void {
|
|
||||||
const rawPaths: string[] = core.getMultilineInput(EXCLUDE_PATHS_PARAMETER)
|
|
||||||
const resolvedPaths = rawPaths.map(x => path.resolve(this.gradleUserHome, x))
|
|
||||||
|
|
||||||
for (const p of resolvedPaths) {
|
|
||||||
this.debug(`Deleting excluded path: ${p}`)
|
|
||||||
tryDelete(p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async saveArtifactBundles(listener: CacheListener): Promise<void> {
|
|
||||||
const processes: Promise<void>[] = []
|
|
||||||
for (const [bundle, pattern] of this.getArtifactBundles()) {
|
|
||||||
const entryListener = listener.entry(bundle)
|
|
||||||
|
|
||||||
const p = this.saveArtifactBundle(bundle, pattern, entryListener)
|
|
||||||
// Run sequentially when debugging enabled
|
|
||||||
if (this.cacheDebuggingEnabled) {
|
|
||||||
await p
|
|
||||||
}
|
|
||||||
processes.push(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all(processes)
|
|
||||||
}
|
|
||||||
|
|
||||||
private async saveArtifactBundle(
|
|
||||||
bundle: string,
|
|
||||||
artifactPath: string,
|
|
||||||
listener: CacheEntryListener
|
|
||||||
): Promise<void> {
|
|
||||||
const bundleMetaFile = this.getBundleMetaFile(bundle)
|
|
||||||
|
|
||||||
const globber = await glob.create(artifactPath, {
|
|
||||||
implicitDescendants: false,
|
|
||||||
followSymbolicLinks: false
|
|
||||||
})
|
|
||||||
const bundleFiles = await globber.glob()
|
|
||||||
|
|
||||||
// Handle no matching files
|
|
||||||
if (bundleFiles.length === 0) {
|
|
||||||
this.debug(`No files found to cache for ${bundle}`)
|
|
||||||
if (fs.existsSync(bundleMetaFile)) {
|
|
||||||
tryDelete(bundleMetaFile)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const previouslyRestoredKey = fs.existsSync(bundleMetaFile)
|
|
||||||
? fs.readFileSync(bundleMetaFile, 'utf-8').trim()
|
|
||||||
: ''
|
|
||||||
const cacheKey = this.createCacheKey(bundle, bundleFiles)
|
|
||||||
|
|
||||||
if (previouslyRestoredKey === cacheKey) {
|
|
||||||
this.debug(`No change to previously restored ${bundle}. Not caching.`)
|
|
||||||
} else {
|
|
||||||
core.info(`Caching ${bundle} with cache key: ${cacheKey}`)
|
|
||||||
const savedEntry = await this.saveCache([artifactPath], cacheKey)
|
|
||||||
if (savedEntry !== undefined) {
|
|
||||||
this.writeBundleMetaFile(bundleMetaFile, cacheKey)
|
|
||||||
listener.markSaved(savedEntry.key, savedEntry.size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const file of bundleFiles) {
|
|
||||||
tryDelete(file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected createCacheKey(bundle: string, files: string[]): string {
|
|
||||||
const cacheKeyPrefix = getCacheKeyPrefix()
|
|
||||||
const relativeFiles = files.map(x => path.relative(this.gradleUserHome, x))
|
|
||||||
const key = hashFileNames(relativeFiles)
|
|
||||||
|
|
||||||
this.debug(`Generating cache key for ${bundle} from files: ${relativeFiles}`)
|
|
||||||
|
|
||||||
return `${cacheKeyPrefix}${bundle}-${key}`
|
|
||||||
}
|
|
||||||
|
|
||||||
private writeBundleMetaFile(metaFile: string, cacheKey: string): void {
|
|
||||||
this.debug(`Writing bundle metafile: ${metaFile}`)
|
|
||||||
|
|
||||||
const dirName = path.dirname(metaFile)
|
|
||||||
if (!fs.existsSync(dirName)) {
|
|
||||||
fs.mkdirSync(dirName)
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync(metaFile, cacheKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected determineGradleUserHome(rootDir: string): string {
|
|
||||||
const customGradleUserHome = process.env['GRADLE_USER_HOME']
|
|
||||||
if (customGradleUserHome) {
|
|
||||||
return path.resolve(rootDir, customGradleUserHome)
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.resolve(os.homedir(), '.gradle')
|
|
||||||
}
|
|
||||||
|
|
||||||
protected cacheOutputExists(): boolean {
|
|
||||||
// Need to check for 'caches' directory to avoid incorrect detection on MacOS agents
|
|
||||||
const dir = path.resolve(this.gradleUserHome, 'caches')
|
|
||||||
return fs.existsSync(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getCachePath(): string[] {
|
|
||||||
const rawPaths: string[] = core.getMultilineInput(INCLUDE_PATHS_PARAMETER)
|
|
||||||
rawPaths.push(META_FILE_DIR)
|
|
||||||
const resolvedPaths = rawPaths.map(x => this.resolveCachePath(x))
|
|
||||||
this.debug(`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 getArtifactBundles(): Map<string, string> {
|
|
||||||
const artifactBundleDefinition = core.getInput(ARTIFACT_BUNDLES_PARAMETER)
|
|
||||||
this.debug(`Using artifact bundle definition: ${artifactBundleDefinition}`)
|
|
||||||
const artifactBundles = JSON.parse(artifactBundleDefinition)
|
|
||||||
return new Map(Array.from(artifactBundles, ([key, value]) => [key, path.resolve(this.gradleUserHome, value)]))
|
|
||||||
}
|
|
||||||
|
|
||||||
private async reportGradleUserHomeSize(label: string): Promise<void> {
|
|
||||||
if (!this.cacheDebuggingEnabled) {
|
|
||||||
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('-----------------------')
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,30 +0,0 @@
|
|||||||
import path from 'path'
|
|
||||||
import fs from 'fs'
|
|
||||||
import {AbstractCache} from './cache-base'
|
|
||||||
|
|
||||||
// TODO: Maybe allow the user to override / tweak this set
|
|
||||||
const PATHS_TO_CACHE = [
|
|
||||||
'configuration-cache' // Only configuration-cache is stored at present
|
|
||||||
]
|
|
||||||
|
|
||||||
export class ProjectDotGradleCache extends AbstractCache {
|
|
||||||
private rootDir: string
|
|
||||||
constructor(rootDir: string) {
|
|
||||||
super('project', 'Project configuration cache')
|
|
||||||
this.rootDir = rootDir
|
|
||||||
}
|
|
||||||
|
|
||||||
protected cacheOutputExists(): boolean {
|
|
||||||
const dir = this.getProjectDotGradleDir()
|
|
||||||
return fs.existsSync(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getCachePath(): string[] {
|
|
||||||
const dir = this.getProjectDotGradleDir()
|
|
||||||
return PATHS_TO_CACHE.map(x => path.resolve(dir, x))
|
|
||||||
}
|
|
||||||
|
|
||||||
private getProjectDotGradleDir(): string {
|
|
||||||
return path.resolve(this.rootDir, '.gradle')
|
|
||||||
}
|
|
||||||
}
|
|
138
src/cache-reporting.ts
Normal file
138
src/cache-reporting.ts
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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[] = []
|
||||||
|
|
||||||
|
get fullyRestored(): boolean {
|
||||||
|
return this.cacheEntries.every(x => !x.wasRequestedButNotRestored())
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
savedKey: string | undefined
|
||||||
|
savedSize: number | 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logCachingReport(listener: CacheListener): void {
|
||||||
|
if (listener.cacheEntries.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`---------- Caching Summary -------------
|
||||||
|
Restored Entries Count: ${getCount(listener.cacheEntries, e => e.restoredSize)}
|
||||||
|
Size: ${getSum(listener.cacheEntries, e => e.restoredSize)}
|
||||||
|
Saved Entries Count: ${getCount(listener.cacheEntries, e => e.savedSize)}
|
||||||
|
Size: ${getSum(listener.cacheEntries, e => e.savedSize)}`)
|
||||||
|
|
||||||
|
core.startGroup('Cache Entry details')
|
||||||
|
for (const entry of listener.cacheEntries) {
|
||||||
|
core.info(`Entry: ${entry.entryName}
|
||||||
|
Requested Key : ${entry.requestedKey ?? ''}
|
||||||
|
Restored Key : ${entry.restoredKey ?? ''}
|
||||||
|
Size: ${formatSize(entry.restoredSize)}
|
||||||
|
Saved Key : ${entry.savedKey ?? ''}
|
||||||
|
Size: ${formatSize(entry.savedSize)}`)
|
||||||
|
}
|
||||||
|
core.endGroup()
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCount(
|
||||||
|
cacheEntries: CacheEntryListener[],
|
||||||
|
predicate: (value: CacheEntryListener) => number | undefined
|
||||||
|
): number {
|
||||||
|
return cacheEntries.filter(e => predicate(e) !== undefined).length
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSum(
|
||||||
|
cacheEntries: CacheEntryListener[],
|
||||||
|
predicate: (value: CacheEntryListener) => number | undefined
|
||||||
|
): string {
|
||||||
|
if (cacheEntries.length === 0) {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
return formatSize(cacheEntries.map(e => predicate(e) ?? 0).reduce((p, v) => p + v, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSize(bytes: number | undefined): string {
|
||||||
|
if (bytes === undefined) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if (bytes === 0) {
|
||||||
|
return '0 (Entry already exists)'
|
||||||
|
}
|
||||||
|
return `${Math.round(bytes / (1024 * 1024))} MB (${bytes} B)`
|
||||||
|
}
|
@@ -4,10 +4,12 @@ import * as crypto from 'crypto'
|
|||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
|
|
||||||
const CACHE_PROTOCOL_VERSION = 'v4-'
|
import {CacheEntryListener} from './cache-reporting'
|
||||||
|
|
||||||
|
const JOB_CONTEXT_PARAMETER = 'workflow-job-context'
|
||||||
const CACHE_DISABLED_PARAMETER = 'cache-disabled'
|
const CACHE_DISABLED_PARAMETER = 'cache-disabled'
|
||||||
const CACHE_READONLY_PARAMETER = 'cache-read-only'
|
const CACHE_READONLY_PARAMETER = 'cache-read-only'
|
||||||
|
const CACHE_WRITEONLY_PARAMETER = 'cache-write-only'
|
||||||
const CACHE_DEBUG_VAR = 'GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'
|
const CACHE_DEBUG_VAR = 'GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'
|
||||||
const CACHE_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
|
const CACHE_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
|
||||||
|
|
||||||
@@ -19,13 +21,28 @@ export function isCacheReadOnly(): boolean {
|
|||||||
return core.getBooleanInput(CACHE_READONLY_PARAMETER)
|
return core.getBooleanInput(CACHE_READONLY_PARAMETER)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isCacheWriteOnly(): boolean {
|
||||||
|
return core.getBooleanInput(CACHE_WRITEONLY_PARAMETER)
|
||||||
|
}
|
||||||
|
|
||||||
export function isCacheDebuggingEnabled(): boolean {
|
export function isCacheDebuggingEnabled(): boolean {
|
||||||
return process.env[CACHE_DEBUG_VAR] ? true : false
|
return process.env[CACHE_DEBUG_VAR] ? true : false
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCacheKeyPrefix(): string {
|
export function getCacheKeyPrefix(): string {
|
||||||
// Prefix can be used to force change all cache keys (defaults to cache protocol version)
|
// Prefix can be used to force change all cache keys (defaults to cache protocol version)
|
||||||
return process.env[CACHE_PREFIX_VAR] || CACHE_PROTOCOL_VERSION
|
return process.env[CACHE_PREFIX_VAR] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export function determineJobContext(): string {
|
||||||
|
// By default, we hash the full `matrix` data for the run, to uniquely identify this job invocation
|
||||||
|
// The only way we can obtain the `matrix` data is via the `workflow-job-context` parameter in action.yml.
|
||||||
|
const workflowJobContext = core.getInput(JOB_CONTEXT_PARAMETER)
|
||||||
|
return hashStrings([workflowJobContext])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hashFileNames(fileNames: string[]): string {
|
||||||
|
return hashStrings(fileNames.map(x => x.replace(new RegExp(`\\${path.sep}`, 'g'), '/')))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hashStrings(values: string[]): string {
|
export function hashStrings(values: string[]): string {
|
||||||
@@ -36,8 +53,43 @@ export function hashStrings(values: string[]): string {
|
|||||||
return hash.digest('hex')
|
return hash.digest('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hashFileNames(fileNames: string[]): string {
|
export async function restoreCache(
|
||||||
return hashStrings(fileNames.map(x => x.replace(new RegExp(`\\${path.sep}`, 'g'), '/')))
|
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)
|
||||||
|
if (restoredEntry !== undefined) {
|
||||||
|
listener.markRestored(restoredEntry.key, restoredEntry.size)
|
||||||
|
}
|
||||||
|
return restoredEntry
|
||||||
|
} catch (error) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
handleCacheFailure(error, `Failed to save cache entry ${cacheKey}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cacheDebug(message: string): void {
|
||||||
|
if (isCacheDebuggingEnabled()) {
|
||||||
|
core.info(message)
|
||||||
|
} else {
|
||||||
|
core.debug(message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleCacheFailure(error: unknown, message: string): void {
|
export function handleCacheFailure(error: unknown, message: string): void {
|
||||||
@@ -47,14 +99,13 @@ export function handleCacheFailure(error: unknown, message: string): void {
|
|||||||
}
|
}
|
||||||
if (error instanceof cache.ReserveCacheError) {
|
if (error instanceof cache.ReserveCacheError) {
|
||||||
// Reserve cache errors are expected if the artifact has been previously cached
|
// Reserve cache errors are expected if the artifact has been previously cached
|
||||||
if (isCacheDebuggingEnabled()) {
|
core.info(`${message}: ${error}`)
|
||||||
core.info(message)
|
|
||||||
} else {
|
|
||||||
core.debug(message)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Warn on all other errors
|
// Warn on all other errors
|
||||||
core.warning(`${message}: ${error}`)
|
core.warning(`${message}: ${error}`)
|
||||||
|
if (error instanceof Error && error.stack) {
|
||||||
|
cacheDebug(error.stack)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
112
src/caches.ts
112
src/caches.ts
@@ -1,39 +1,60 @@
|
|||||||
import {GradleUserHomeCache} from './cache-gradle-user-home'
|
|
||||||
import {ProjectDotGradleCache} from './cache-project-dot-gradle'
|
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {isCacheDisabled, isCacheReadOnly} from './cache-utils'
|
import {isCacheDisabled, isCacheReadOnly, isCacheWriteOnly} from './cache-utils'
|
||||||
import {CacheEntryListener, CacheListener} from './cache-base'
|
import {logCachingReport, CacheListener} from './cache-reporting'
|
||||||
|
import {GradleStateCache} from './cache-base'
|
||||||
|
|
||||||
const BUILD_ROOT_DIR = 'BUILD_ROOT_DIR'
|
const CACHE_RESTORED_VAR = 'GRADLE_BUILD_ACTION_CACHE_RESTORED'
|
||||||
|
const GRADLE_USER_HOME = 'GRADLE_USER_HOME'
|
||||||
const CACHE_LISTENER = 'CACHE_LISTENER'
|
const CACHE_LISTENER = 'CACHE_LISTENER'
|
||||||
|
|
||||||
export async function restore(buildRootDirectory: string): Promise<void> {
|
export async function restore(gradleUserHome: string): 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()) {
|
if (isCacheDisabled()) {
|
||||||
core.info('Cache is disabled: will not restore state from previous builds.')
|
core.info('Cache is disabled: will not restore state from previous builds.')
|
||||||
|
// Initialize the Gradle User Home even when caching is disabled.
|
||||||
|
gradleStateCache.init()
|
||||||
|
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)
|
||||||
|
// Save the Gradle User Home for the post-action step.
|
||||||
|
core.saveState(GRADLE_USER_HOME, gradleUserHome)
|
||||||
|
|
||||||
|
if (isCacheWriteOnly()) {
|
||||||
|
core.info('Cache is write-only: will not restore from cache.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await core.group('Restore Gradle state from cache', async () => {
|
await core.group('Restore Gradle state from cache', async () => {
|
||||||
core.saveState(BUILD_ROOT_DIR, buildRootDirectory)
|
|
||||||
|
|
||||||
const cacheListener = new CacheListener()
|
const cacheListener = new CacheListener()
|
||||||
await new GradleUserHomeCache(buildRootDirectory).restore(cacheListener)
|
await gradleStateCache.restore(cacheListener)
|
||||||
|
|
||||||
const projectDotGradleCache = new ProjectDotGradleCache(buildRootDirectory)
|
|
||||||
if (cacheListener.fullyRestored) {
|
|
||||||
// Only restore the configuration-cache if the Gradle Home is fully restored
|
|
||||||
await projectDotGradleCache.restore(cacheListener)
|
|
||||||
} else {
|
|
||||||
// Otherwise, prepare the cache key for later save()
|
|
||||||
core.info('Gradle Home cache not fully restored: not restoring configuration-cache state')
|
|
||||||
projectDotGradleCache.prepareCacheKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
core.saveState(CACHE_LISTENER, cacheListener.stringify())
|
core.saveState(CACHE_LISTENER, cacheListener.stringify())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function save(): Promise<void> {
|
export async function save(): Promise<void> {
|
||||||
|
if (!shouldSaveCaches()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER))
|
const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER))
|
||||||
|
|
||||||
if (isCacheReadOnly()) {
|
if (isCacheReadOnly()) {
|
||||||
@@ -43,56 +64,23 @@ export async function save(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await core.group('Caching Gradle state', async () => {
|
await core.group('Caching Gradle state', async () => {
|
||||||
const buildRootDirectory = core.getState(BUILD_ROOT_DIR)
|
const gradleUserHome = core.getState(GRADLE_USER_HOME)
|
||||||
return Promise.all([
|
return new GradleStateCache(gradleUserHome).save(cacheListener)
|
||||||
new GradleUserHomeCache(buildRootDirectory).save(cacheListener),
|
|
||||||
new ProjectDotGradleCache(buildRootDirectory).save(cacheListener)
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
logCachingReport(cacheListener)
|
logCachingReport(cacheListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
function logCachingReport(listener: CacheListener): void {
|
function shouldSaveCaches(): boolean {
|
||||||
if (listener.cacheEntries.length === 0) {
|
if (isCacheDisabled()) {
|
||||||
return
|
core.info('Cache is disabled: will not save state for later builds.')
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info(`---------- Caching Summary -------------
|
if (!core.getState(CACHE_RESTORED_VAR)) {
|
||||||
Restored Entries Count: ${getCount(listener.cacheEntries, e => e.restoredSize)}
|
core.info('Cache will not be saved: not restored in main action step.')
|
||||||
Size: ${getSum(listener.cacheEntries, e => e.restoredSize)}
|
return false
|
||||||
Saved Entries Count: ${getCount(listener.cacheEntries, e => e.savedSize)}
|
|
||||||
Size: ${getSum(listener.cacheEntries, e => e.savedSize)}`)
|
|
||||||
|
|
||||||
core.startGroup('Cache Entry details')
|
|
||||||
for (const entry of listener.cacheEntries) {
|
|
||||||
core.info(`Entry: ${entry.entryName}
|
|
||||||
Requested Key : ${entry.requestedKey ?? ''}
|
|
||||||
Restored Key : ${entry.restoredKey ?? ''}
|
|
||||||
Size: ${formatSize(entry.restoredSize)}
|
|
||||||
Saved Key : ${entry.savedKey ?? ''}
|
|
||||||
Size: ${formatSize(entry.savedSize)}`)
|
|
||||||
}
|
}
|
||||||
core.endGroup()
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCount(
|
return true
|
||||||
cacheEntries: CacheEntryListener[],
|
|
||||||
predicate: (value: CacheEntryListener) => number | undefined
|
|
||||||
): number {
|
|
||||||
return cacheEntries.filter(e => predicate(e) !== undefined).length
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSum(
|
|
||||||
cacheEntries: CacheEntryListener[],
|
|
||||||
predicate: (value: CacheEntryListener) => number | undefined
|
|
||||||
): string {
|
|
||||||
return formatSize(cacheEntries.map(e => predicate(e) ?? 0).reduce((p, v) => p + v, 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatSize(bytes: number | undefined): string {
|
|
||||||
if (bytes === undefined || bytes === 0) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
return `${Math.round(bytes / (1024 * 1024))} MB (${bytes} B)`
|
|
||||||
}
|
}
|
||||||
|
@@ -1,24 +1,21 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import {writeInitScript} from './build-scan-capture'
|
import * as gradlew from './gradlew'
|
||||||
|
|
||||||
export async function execute(executable: string, root: string, args: string[]): Promise<BuildResult> {
|
export async function executeGradleBuild(executable: string | undefined, root: string, args: string[]): Promise<void> {
|
||||||
let buildScanUrl: string | undefined
|
let buildScanUrl: string | undefined
|
||||||
|
|
||||||
// TODO: instead of running with no-daemon, run `--stop` in post action.
|
|
||||||
args.push('--no-daemon')
|
|
||||||
|
|
||||||
const initScript = writeInitScript()
|
|
||||||
args.push('--init-script')
|
|
||||||
args.push(initScript)
|
|
||||||
|
|
||||||
const buildScanFile = path.resolve(root, 'gradle-build-scan.txt')
|
const buildScanFile = path.resolve(root, 'gradle-build-scan.txt')
|
||||||
if (fs.existsSync(buildScanFile)) {
|
if (fs.existsSync(buildScanFile)) {
|
||||||
fs.unlinkSync(buildScanFile)
|
fs.unlinkSync(buildScanFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
const status: number = await exec.exec(executable, args, {
|
// Use the provided executable, or look for a Gradle wrapper script to run
|
||||||
|
const toExecute = executable ?? gradlew.locateGradleWrapperScript(root)
|
||||||
|
verifyIsExecutableScript(toExecute)
|
||||||
|
const status: number = await exec.exec(toExecute, args, {
|
||||||
cwd: root,
|
cwd: root,
|
||||||
ignoreReturnCode: true
|
ignoreReturnCode: true
|
||||||
})
|
})
|
||||||
@@ -27,14 +24,19 @@ export async function execute(executable: string, root: string, args: string[]):
|
|||||||
buildScanUrl = fs.readFileSync(buildScanFile, 'utf-8')
|
buildScanUrl = fs.readFileSync(buildScanFile, 'utf-8')
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BuildResultImpl(status, buildScanUrl)
|
if (status !== 0) {
|
||||||
|
if (buildScanUrl) {
|
||||||
|
core.setFailed(`Gradle build failed: ${buildScanUrl}`)
|
||||||
|
} else {
|
||||||
|
core.setFailed(`Gradle build failed: process exited with status ${status}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BuildResult {
|
function verifyIsExecutableScript(toExecute: string): void {
|
||||||
readonly status: number
|
try {
|
||||||
readonly buildScanUrl?: string
|
fs.accessSync(toExecute, fs.constants.X_OK)
|
||||||
}
|
} catch (err) {
|
||||||
|
throw new Error(`Gradle script '${toExecute}' is not executable.`)
|
||||||
class BuildResultImpl implements BuildResult {
|
}
|
||||||
constructor(readonly status: number, readonly buildScanUrl?: string) {}
|
|
||||||
}
|
}
|
||||||
|
50
src/main.ts
50
src/main.ts
@@ -1,42 +1,33 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
import * as os from 'os'
|
||||||
import {parseArgsStringToArgv} from 'string-argv'
|
import {parseArgsStringToArgv} from 'string-argv'
|
||||||
|
|
||||||
import * as caches from './caches'
|
import * as caches from './caches'
|
||||||
import * as execution from './execution'
|
import * as execution from './execution'
|
||||||
import * as gradlew from './gradlew'
|
|
||||||
import * as provision from './provision'
|
import * as provision from './provision'
|
||||||
|
|
||||||
// Invoked by GitHub Actions
|
/**
|
||||||
|
* The main entry point for the action, called by Github Actions for the step.
|
||||||
|
*/
|
||||||
export async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || ''
|
const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || ''
|
||||||
const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory)
|
const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory)
|
||||||
|
const gradleUserHome = determineGradleUserHome(buildRootDirectory)
|
||||||
|
|
||||||
await caches.restore(buildRootDirectory)
|
await caches.restore(gradleUserHome)
|
||||||
|
|
||||||
const args: string[] = parseCommandLineArguments()
|
const executable = await provisionGradle(workspaceDirectory)
|
||||||
|
// executable will be undefined if using Gradle wrapper
|
||||||
const result = await execution.execute(
|
if (executable !== undefined) {
|
||||||
await resolveGradleExecutable(workspaceDirectory, buildRootDirectory),
|
core.addPath(path.dirname(executable))
|
||||||
buildRootDirectory,
|
|
||||||
args
|
|
||||||
)
|
|
||||||
|
|
||||||
if (result.buildScanUrl) {
|
|
||||||
core.setOutput('build-scan-url', result.buildScanUrl)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.status !== 0) {
|
// Only execute if arguments have been provided
|
||||||
if (result.buildScanUrl) {
|
const args: string[] = parseCommandLineArguments()
|
||||||
core.setFailed(`Gradle build failed: ${result.buildScanUrl}`)
|
if (args.length > 0) {
|
||||||
} else {
|
await execution.executeGradleBuild(executable, buildRootDirectory, args)
|
||||||
core.setFailed(`Gradle build failed: process exited with status ${result.status}`)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (result.buildScanUrl) {
|
|
||||||
core.notice(`Gradle build succeeded: ${result.buildScanUrl}`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(String(error))
|
core.setFailed(String(error))
|
||||||
@@ -48,7 +39,7 @@ export async function run(): Promise<void> {
|
|||||||
|
|
||||||
run()
|
run()
|
||||||
|
|
||||||
async function resolveGradleExecutable(workspaceDirectory: string, buildRootDirectory: string): Promise<string> {
|
async function provisionGradle(workspaceDirectory: string): Promise<string | undefined> {
|
||||||
const gradleVersion = core.getInput('gradle-version')
|
const gradleVersion = core.getInput('gradle-version')
|
||||||
if (gradleVersion !== '' && gradleVersion !== 'wrapper') {
|
if (gradleVersion !== '' && gradleVersion !== 'wrapper') {
|
||||||
return path.resolve(await provision.gradleVersion(gradleVersion))
|
return path.resolve(await provision.gradleVersion(gradleVersion))
|
||||||
@@ -59,7 +50,7 @@ async function resolveGradleExecutable(workspaceDirectory: string, buildRootDire
|
|||||||
return path.resolve(workspaceDirectory, gradleExecutable)
|
return path.resolve(workspaceDirectory, gradleExecutable)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gradlew.locateGradleWrapperScript(buildRootDirectory)
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveBuildRootDirectory(baseDirectory: string): string {
|
function resolveBuildRootDirectory(baseDirectory: string): string {
|
||||||
@@ -69,6 +60,15 @@ function resolveBuildRootDirectory(baseDirectory: string): string {
|
|||||||
return resolvedBuildRootDirectory
|
return resolvedBuildRootDirectory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function determineGradleUserHome(rootDir: string): string {
|
||||||
|
const customGradleUserHome = process.env['GRADLE_USER_HOME']
|
||||||
|
if (customGradleUserHome) {
|
||||||
|
return path.resolve(rootDir, customGradleUserHome)
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.resolve(os.homedir(), '.gradle')
|
||||||
|
}
|
||||||
|
|
||||||
function parseCommandLineArguments(): string[] {
|
function parseCommandLineArguments(): string[] {
|
||||||
const input = core.getInput('arguments')
|
const input = core.getInput('arguments')
|
||||||
return parseArgsStringToArgv(input)
|
return parseArgsStringToArgv(input)
|
||||||
|
21
src/post.ts
21
src/post.ts
@@ -1,15 +1,26 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as caches from './caches'
|
import * as caches from './caches'
|
||||||
|
|
||||||
// Invoked by GitHub Actions
|
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||||
|
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
||||||
|
// throw an uncaught exception. Instead of failing this action, just warn.
|
||||||
|
process.on('uncaughtException', e => handleFailure(e))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The post-execution entry point for the action, called by Github Actions after completing all steps for the Job.
|
||||||
|
*/
|
||||||
export async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await caches.save()
|
await caches.save()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(String(error))
|
handleFailure(error)
|
||||||
if (error instanceof Error && error.stack) {
|
}
|
||||||
core.info(error.stack)
|
}
|
||||||
}
|
|
||||||
|
function handleFailure(error: unknown): void {
|
||||||
|
core.warning(`Unhandled error saving cache - job will continue: ${error}`)
|
||||||
|
if (error instanceof Error && error.stack) {
|
||||||
|
core.info(error.stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user