Compare commits

...

81 Commits

Author SHA1 Message Date
bigdaz
d9c87d481d [bot] Update dist directory 2024-07-15 19:00:43 +00:00
Daz DeBoer
ff865cb801 Upload dependency graph on submission failure (#291) 2024-07-15 12:47:06 -06:00
daz
c3acd19a4a Update to Gradle 8.9 2024-07-14 08:12:33 -06:00
bigdaz
e5bbd4c742 [bot] Update dist directory 2024-07-12 17:38:55 +00:00
dependabot[bot]
d7cd9fc65c Bump com.fasterxml.jackson.dataformat:jackson-dataformat-smile
Bumps [com.fasterxml.jackson.dataformat:jackson-dataformat-smile](https://github.com/FasterXML/jackson-dataformats-binary) from 2.17.1 to 2.17.2.
- [Commits](https://github.com/FasterXML/jackson-dataformats-binary/compare/jackson-dataformats-binary-2.17.1...jackson-dataformats-binary-2.17.2)

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson.dataformat:jackson-dataformat-smile
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-12 11:30:33 -06:00
github-actions[bot]
6407986e96 Update known wrapper checksums (#278)
Automatically generated pull request to update the known wrapper
checksums.

Co-authored-by: bigdaz <179734+bigdaz@users.noreply.github.com>
2024-07-12 11:29:43 -06:00
daz
87bf5ca2ea Update DV plugin versions that were missed by automation 2024-07-05 11:33:00 -06:00
Daz DeBoer
81b4ece56a Clarify that tags are isolated in cache entries 2024-07-02 12:15:24 -06:00
bigdaz
cdbbabd09c [bot] Update dist directory 2024-06-28 19:47:07 +00:00
Daz DeBoer
dad038d88d Use Gradle 8.8 features for Gradle Home cleanup (#272)
Fixes #33
Fixes #24
Fixes #46 
Fixes #169
2024-06-28 13:46:10 -06:00
daz
621f3b3f79 Run cache-cleanup build with --info
Resolves #169
2024-06-28 13:25:56 -06:00
daz
4022faad7e Fix integ-test-cache-cleanup.yml for running on act 2024-06-28 13:21:54 -06:00
daz
95ef72241e Use Gradle 8.8 features for cleanup
Gradle 8.8 introduces new features that allow us to avoid using
timestamp manipulation to force the cleanup of the Gradle User Home directory.

This solution is simpler and more robust, but relies on Gradle 8.8+ always being
used for the cache cleanup operation.

Fixes #24
2024-06-28 13:06:23 -06:00
daz
169bec5d8b Provision latest Gradle for cache-cleanup
To cleanup Gradle User Home, a Gradle build must be executed.
Newer Gradle versions are able to cleanup the home directories of older versions,
but not vice-versa.

With this change, the latest version of Gradle is automatically provisioned
in order to run Gradle User Home cleanup. This ensures a consistent version of
Gradle is used for cleanup, and fixes #33 where Gradle is not pre-installed on
a custom runner.
2024-06-28 12:39:09 -06:00
Daz DeBoer
b9abb7b195 Use latest dependency graph plugin (#269) 2024-06-27 19:42:01 -06:00
Daz DeBoer
c04155e2ca Remove instructions for merging Dependabot PRs
These are no longer required, since the bot will update the `dist` directory.
2024-06-27 19:32:31 -06:00
daz
1da1cc97d5 Rename Develocity secret 2024-06-27 18:49:52 -06:00
dependabot[bot]
c401249391 Bump org.junit.jupiter:junit-jupiter
Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.10.2 to 5.10.3.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.10.2...r5.10.3)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-27 18:05:07 -06:00
bigdaz
a6a0c7dcef [bot] Update dist directory 2024-06-27 20:12:25 +00:00
bigdaz
3f3913eed0 Update known wrapper checksums 2024-06-27 14:11:23 -06:00
Eric Haag
2cd2a6e951 Fix grammar in docs 2024-06-20 07:58:28 -05:00
cdsap
dbbdc275be [bot] Update dist directory 2024-06-17 17:45:00 +00:00
Iñaki Villar
ae74429826 Fix race condition with fetching short lived token (#260)
This somehow worked before (and in our integ test) because the setup
action gave enough time to let the request short-lived token return in
time 🤷.
2024-06-17 10:44:01 -07:00
Alexis Tual
bdc7162ff9 Forward the setup short-lived token Promise
This caused a race condition not allowing the short-lived token to be returned in time before the setup finished.
2024-06-17 19:03:10 +02:00
bigdaz
31ae3562f6 [bot] Update dist directory 2024-06-15 03:19:11 +00:00
Daz DeBoer
719985db3d Simplify requesting short-lived Develocity access tokens (#259)
- Always fetch a token for every hostname in the access key
- Use any tokens that are successfully fetched
- Retain access key if no tokens can be fetched
2024-06-14 21:18:08 -06:00
bigdaz
b53238971c [bot] Update dist directory 2024-06-14 22:45:05 +00:00
Inaki Villar
5f1c5827bf handle missing access token 2024-06-14 16:44:06 -06:00
bigdaz
d9336dac04 [bot] Update dist directory 2024-06-13 19:36:18 +00:00
daz
8dbe9a3802 Update DV access key regex to be more selective
This should address the code-scanning alert
  https://github.com/gradle/actions/security/code-scanning/1
2024-06-13 13:35:19 -06:00
bigdaz
9c3430720d [bot] Update dist directory 2024-06-13 19:32:23 +00:00
daz
30c82f0068 Fail on invalid boolean for Develocity inputs 2024-06-13 13:31:25 -06:00
daz
e3bc05f224 Run CodeQL on PRs 2024-06-13 13:15:23 -06:00
daz
485ea107b7 Run CodeQL on dev/* branches 2024-06-13 13:01:56 -06:00
bigdaz
c1091c9c8e [bot] Update dist directory 2024-06-13 18:43:53 +00:00
Iñaki Villar
d0a116fff5 Adding Develocity input actions (#244)
Adding Develocity input actions. 

If an input is configured in the action, it will generate the environment variable, example:

```yaml
    - name: Setup Gradle
      uses: gradle/actions/setup-gradle@v3
      with:
        develocity-injection-enabled: true
        develocity-url: https://develocity.your-server.com
        develocity-plugin-version: 3.17.4

    - name: Run a Gradle build with Develocity injection enabled from input actions
      run: ./gradlew build
```

This configuration will create the environment variables:
```
DEVELOCITY_INJECTION_ENABLED=true
DEVELOCITY_URL=https://develocity.your-server.com
DEVELOCITY_PLUGIN_VERSION=3.17.4
```

Relation variable-input available:

| Variable | Input |

|--------------------------------------|--------------------------------------|
| DEVELOCITY_INJECTION_ENABLED | develocity-injection-enabled |
| DEVELOCITY_URL | develocity-url |
| DEVELOCITY_ALLOW_UNTRUSTED_SERVER | develocity-allow-untrusted-server
|
| DEVELOCITY_CAPTURE_FILE_FINGERPRINTS |
develocity-capture-file-fingerprints |
| DEVELOCITY_ENFORCE_URL | develocity-enforce-url |
| DEVELOCITY_PLUGIN_VERSION | develocity-plugin-version |
| DEVELOCITY_CCUD_PLUGIN_VERSION | develocity-ccud-plugin-version |
| GRADLE_PLUGIN_REPOSITORY_URL | gradle-plugin-repository-url |
| GRADLE_PLUGIN_REPOSITORY_USERNAME | gradle-plugin-repository-username
|
| GRADLE_PLUGIN_REPOSITORY_PASSWORD | gradle-plugin-repository-password
|
2024-06-13 12:42:47 -06:00
bigdaz
e238a7ad22 [bot] Update dist directory 2024-06-13 16:01:59 +00:00
bot-githubaction
1d2ea6e5a8 Bump references to Develocity Gradle plugin from 3.17.4 to 3.17.5 2024-06-13 10:01:04 -06:00
dependabot[bot]
114c1c234e Bump braces from 3.0.2 to 3.0.3 in /sources
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-13 09:10:17 -06:00
daz
2db3ae936e Update to Gradle 8.8 2024-06-13 09:03:40 -06:00
dependabot[bot]
a68381d359 Bump com.google.guava:guava in /.github/workflow-samples/kotlin-dsl
Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.2.0-jre to 33.2.1-jre.
- [Release notes](https://github.com/google/guava/releases)
- [Commits](https://github.com/google/guava/commits)

---
updated-dependencies:
- dependency-name: com.google.guava:guava
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-13 07:41:41 -06:00
bigdaz
52ae27f7bb [bot] Update dist directory 2024-06-13 13:41:01 +00:00
bigdaz
d1cd62d80a Update known wrapper checksums 2024-06-13 07:40:03 -06:00
Anton Mostovoy
af6e576724 add missing permission for downloading dependency graph artifact
per https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts, `actions: read` is required. Without it the action fails after logging `Fetching artifact list for workflow ` due to `Error: HttpError: Resource not accessible by integration`
2024-05-23 09:09:36 -06:00
bigdaz
775b4d10d7 [bot] Update dist directory 2024-05-23 14:57:08 +00:00
Bot Githubaction
30610bc983 Bump references to Develocity Gradle plugin from 3.17.3 to 3.17.4 (#236)
This PR bumps references to Develocity Gradle plugin from 3.17.3 to 3.17.4.

---------

Co-authored-by: Eric Haag <ehaag@gradle.com>
2024-05-23 08:56:09 -06:00
bigdaz
d4d72c9934 [bot] Update dist directory 2024-05-17 21:08:44 +00:00
Alexis Tual
96b9cb4988 Set both DEVELOCITY_ACCESS_KEY and GRADLE_ENTERPRISE_ACCESS_KEY env vars (#225)
Follow up of https://github.com/gradle/actions/pull/224, we now attempt to set both old and new access key env variables to a short lived token.
If a short-lived token cannot be obtained, then:
- DEVELOCITY_ACCESS_KEY is set to an empty string, preventing this from being used.
- GRADLE_ENTERPRISE_ACCESS_KEY is left intact, with a deprecation warning being issued.
2024-05-17 15:07:50 -06:00
Bot Githubaction
db270b9337 Update develocity-injection init script to v1.0
Updates the develocity-injection init script to the latest reference script content
from https://github.com/gradle/develocity-ci-injection.
2024-05-17 14:18:19 -06:00
Bot Githubaction
d91e2960eb Update develocity-injection init script to v0.5.1
Updates the develocity-injection init script to the latest reference script content
from https://github.com/gradle/develocity-ci-injection.
2024-05-17 11:10:27 -06:00
bigdaz
0498421560 Update develocity-injection init script to v0.5.0 2024-05-17 07:27:33 -06:00
bigdaz
edb13383f3 Update develocity-injection init script to v0.4.0 2024-05-15 16:56:41 -06:00
bigdaz
cd560aa3ad [bot] Update dist directory 2024-05-15 22:50:56 +00:00
Alexis Tual
500e0ee5b3 Add support for short-lived tokens (#224)
The setup-gradle action tries to get a short-lived access token given the supplied Develocity access key.
This key can be passed either with the `DEVELOCITY_ACCESS_KEY` env var or via the  `develocity-access-key` input parameter.
If a token can be retrieved, then the `DEVELOCITY_ACCESS_KEY` env var will be set to the token. 
Otherwise the `DEVELOCITY_ACCESS_KEY` will be set to a blank string, to avoid a leak.

---------

Co-authored-by: daz <daz@gradle.com>
2024-05-15 16:49:55 -06:00
bigdaz
eb13cf7170 [bot] Update dist directory 2024-05-11 13:46:41 +00:00
Daz DeBoer
ea14aa9caf Dependency updates (#222)
- Bump to com.gradle.develocity plugin v3.17.3
- Bump JVM dependencies in sample projects
2024-05-11 07:45:47 -06:00
lokalpage-safe
063cfaf0eb Update dependency-submission.md
fix: Fixed document typo (additonal -> additional)
2024-05-09 15:54:39 -06:00
Maxim Mironyuk
35f9242e22 Update setup-gradle.md
repsitory -> repository
2024-05-09 15:54:08 -06:00
bigdaz
90f1de0556 [bot] Update dist directory 2024-04-28 14:50:56 +00:00
bigdaz
da512b52a5 Update known wrapper checksums 2024-04-28 15:49:59 +01:00
bigdaz
db19848a5f [bot] Update dist directory 2024-04-25 20:24:26 +00:00
daz
941b289d84 Avoid running Gradle 3.5.1 on MacOS where Java 8 is not available 2024-04-25 21:23:15 +01:00
Daz DeBoer
bce7daca54 Improve build scan badge readability with long tasks (#200)
Improve readability of build scan when requested tasks is very long, as
agreed in #175. HTML diff for each case of job summary is clearer in
cd62d9c9ef.

- Ensure a minimum size for the badge, at least the size of "Build
scan®", by preventing a line break with `&nbsp;`
- Reduce the size of the badge by tweaking the inner text

Also fix a typo in the build shell script.
2024-04-25 21:22:36 +01:00
daz
11eaed9738 Avoid Java 8 since it is not available on MacOS runners 2024-04-25 20:17:16 +01:00
Gabriel Feo
cd62d9c9ef Improve job summary readability with long tasks
Change tests for nbsp and concise badge

Make tests pass

Signed-off-by: Gabriel Feo <gabriel@gabrielfeo.com>
2024-04-25 19:40:04 +01:00
Gabriel Feo
a54fb6a5bb Add tests on current job-summary behavior
Signed-off-by: Gabriel Feo <gabriel@gabrielfeo.com>
2024-04-25 17:44:41 +01:00
Gabriel Feo
ef36f81b41 Fix typo in build shell script
Signed-off-by: Gabriel Feo <gabriel@gabrielfeo.com>
2024-04-25 17:42:29 +01:00
bigdaz
18998bc43e [bot] Update dist directory 2024-04-25 10:20:39 +00:00
daz
a772c14b33 Avoid updating real dependency graph in tests 2024-04-25 11:19:43 +01:00
daz
7763d71170 Set the report dir for download-and-submit
Fixes #196
2024-04-25 11:19:43 +01:00
bigdaz
9ab93ee864 [bot] Update dist directory 2024-04-19 16:25:39 +00:00
daz
d124ec149f Retain and log stacktrace for submission errors 2024-04-19 10:24:45 -06:00
Alex Serbin
6ccde15122 Use logger in dependency graph init script (#191)
Dependency graph init script now uses Gradle logger to emit warning/info messages.
This allows these messages to be suppressed using `--quiet`.
2024-04-19 07:03:17 -06:00
bigdaz
750cdda3ed [bot] Update dist directory 2024-04-18 19:41:35 +00:00
Daz DeBoer
c198d84863 Support custom report dir for dependency-submission (#189)
If the `DEPENDENCY_GRAPH_REPORT_DIR` var is set, use this value when locating dependency-graph files to upload/submit.

Fixes #188
2024-04-18 13:40:41 -06:00
Daz DeBoer
d211a39090 Documentation updates (#187)
* Use consistent YAML syntax in example workflows
* Add link to plugin env vars
2024-04-18 09:39:15 -06:00
bigdaz
439ed0a0ac [bot] Update dist directory 2024-04-18 01:09:48 +00:00
daz
eef9b10930 Bump Develocity and CCUD plugin versions 2024-04-17 19:08:51 -06:00
Marcono1234
8be796e9fa Update link to 'update checksums' workflow 2024-04-16 10:06:09 -06:00
daz
3c2d3b6f2a Include VS code workspace file
This workspace sets things up so that source code navigation works
propertly in VS code.
2024-04-12 15:39:30 -06:00
daz
0fa10b26b8 Update releasing guide 2024-04-12 14:01:48 -06:00
90 changed files with 9157 additions and 1146 deletions

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

View File

@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ 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.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

View File

@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ 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.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

View File

@@ -1,6 +1,6 @@
plugins {
id "com.gradle.develocity" version "3.17.1"
id "com.gradle.common-custom-user-data-gradle-plugin" version "2.0"
id "com.gradle.develocity" version "3.17.5"
id "com.gradle.common-custom-user-data-gradle-plugin" version "2.0.1"
}
develocity {

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

View File

@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ 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.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

View File

@@ -8,9 +8,9 @@ repositories {
dependencies {
api("org.apache.commons:commons-math3:3.6.1")
implementation("com.google.guava:guava:33.1.0-jre")
implementation("com.google.guava:guava:33.2.1-jre")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.3")
}
tasks.test {

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

View File

@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ 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.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

View File

@@ -1,6 +1,6 @@
plugins {
id("com.gradle.develocity") version "3.17.1"
id("com.gradle.common-custom-user-data-gradle-plugin") version "2.0"
id("com.gradle.develocity") version "3.17.5"
id("com.gradle.common-custom-user-data-gradle-plugin") version "2.0.1"
}
develocity {

View File

@@ -1,5 +1,5 @@
plugins {
id "com.gradle.develocity" version "3.17.1"
id "com.gradle.develocity" version "3.17.5"
}
develocity {

View File

@@ -1,5 +1,5 @@
plugins {
id "com.gradle.develocity" version "3.17.1"
id "com.gradle.develocity" version "3.17.5"
}
develocity {

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

View File

@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ 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.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

View File

@@ -1,5 +1,5 @@
plugins {
id "com.gradle.develocity" version "3.17"
id "com.gradle.develocity" version "3.17.5"
}
develocity {

View File

@@ -5,6 +5,12 @@ on:
branches:
- 'main'
- 'release/**'
- 'dev/**' # Allow running Code QL on dev branches without a PR
paths-ignore:
- 'dist/**'
pull_request:
branches:
- 'main'
paths-ignore:
- 'dist/**'
schedule:

View File

@@ -24,7 +24,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
java-version: 11
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3 # Use a released version to avoid breakages
- name: Run integration tests

View File

@@ -143,7 +143,7 @@ jobs:
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
secrets:
DEVELOCITY_ACCESS_KEY: ${{ secrets.GE_SOLUTIONS_ACCESS_TOKEN }}
DEVELOCITY_ACCESS_KEY: ${{ secrets.DV_SOLUTIONS_ACCESS_KEY }}
provision-gradle-versions:
needs: [determine-suite, build-distribution]

View File

@@ -34,7 +34,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
java-version: 11
- name: Setup Gradle
id: setup-gradle
uses: ./setup-gradle

View File

@@ -35,7 +35,7 @@ jobs:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
- name: Build with 3.1
working-directory: sources/test/jest/resources/cache-cleanup
run: gradle --no-daemon --build-cache -Dcommons_math3_version="3.1" build
run: ./gradlew --no-daemon --build-cache -Dcommons_math3_version="3.1" build
# Second build will use the cache from the first build, but cleanup should remove unused artifacts
assemble-build:
@@ -58,7 +58,7 @@ jobs:
gradle-home-cache-cleanup: true
- name: Build with 3.1.1
working-directory: sources/test/jest/resources/cache-cleanup
run: gradle --no-daemon --build-cache -Dcommons_math3_version="3.1.1" build
run: ./gradlew --no-daemon --build-cache -Dcommons_math3_version="3.1.1" build
check-clean-cache:
needs: assemble-build
@@ -78,7 +78,9 @@ jobs:
with:
cache-read-only: true
- name: Report Gradle User Home
run: du -hc ~/.gradle/caches/modules-2
run: |
du -hc ~/.gradle/caches/modules-2
du -hc ~/.gradle/wrapper/dists
- name: Verify cleaned cache
shell: bash
run: |
@@ -90,3 +92,7 @@ jobs:
echo "::error ::Should NOT find commons-math3 3.1 in cache"
exit 1
fi
if [ ! -e ~/.gradle/wrapper/dists/gradle-8.0.2-bin ]; then
echo "::error ::Should find gradle-8.0.2 in wrapper/dists"
exit 1
fi

View File

@@ -18,6 +18,7 @@ permissions:
env:
SKIP_DIST: ${{ inputs.skip-dist }}
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: dependency-graph-${{ inputs.cache-key-prefix }}
GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository
jobs:
groovy-generate:

View File

@@ -1,4 +1,4 @@
name: Test dependency graph
name: Test dependency submission failures
on:
workflow_call:
@@ -15,6 +15,7 @@ on:
env:
SKIP_DIST: ${{ inputs.skip-dist }}
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: dependency-submission-failures-${{ inputs.cache-key-prefix }}
GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository
jobs:
failing-build:

View File

@@ -1,4 +1,4 @@
name: Test dependency graph
name: Test dependency submission
on:
workflow_call:
@@ -18,6 +18,7 @@ permissions:
env:
SKIP_DIST: ${{ inputs.skip-dist }}
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: dependency-submission-${{ inputs.cache-key-prefix }}
GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository
jobs:
groovy-generate-and-upload:
@@ -223,8 +224,6 @@ jobs:
with:
gradle-version: ${{ matrix.gradle }}
build-root-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
env:
GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository
after-setup-gradle:
strategy:
@@ -245,3 +244,79 @@ jobs:
uses: ./dependency-submission
with:
build-root-directory: .github/workflow-samples/groovy-dsl
custom-report-dir-submit:
strategy:
fail-fast: false
matrix:
os: ${{fromJSON(inputs.runner-os)}}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- name: Generate dependency graph
id: dependency-graph
uses: ./dependency-submission
with:
dependency-graph: generate-and-submit
build-root-directory: .github/workflow-samples/groovy-dsl
env:
DEPENDENCY_GRAPH_REPORT_DIR: '${{ github.workspace }}/custom/report-dir'
- name: Check generated dependency graphs
shell: bash
run: |
echo "report file: ${{ steps.dependency-graph.outputs.dependency-graph-file }}"
if [ ! -e "${{ steps.dependency-graph.outputs.dependency-graph-file }}" ]; then
echo "Did not find dependency graph file"
exit 1
fi
if [ -z "$(ls -A "${{ github.workspace }}/custom/report-dir")" ]; then
echo "No dependency graph files found in custom directory"
exit 1
fi
custom-report-dir-upload:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- name: Generate and upload dependency graph
id: dependency-graph
uses: ./dependency-submission
with:
dependency-graph: generate-and-upload
build-root-directory: .github/workflow-samples/groovy-dsl
env:
DEPENDENCY_GRAPH_REPORT_DIR: '${{ github.workspace }}/custom/report-dir'
custom-report-dir-download-and-submit:
needs: custom-report-dir-upload
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- name: Download and submit dependency graph
uses: ./dependency-submission
with:
dependency-graph: download-and-submit
build-root-directory: .github/workflow-samples/groovy-dsl
env:
DEPENDENCY_GRAPH_REPORT_DIR: '${{ github.workspace }}/custom/report-dir'
- name: Check downloaded dependency graph
shell: bash
run: |
if [ -z "$(ls -A "${{ github.workspace }}/custom/report-dir")" ]; then
echo "No dependency graph files found in custom directory"
exit 1
fi

View File

@@ -61,12 +61,17 @@ jobs:
gradle: [7.5.1, 6.9.2, 5.6.4, 4.10.3, 3.5.1]
os: ${{fromJSON(inputs.runner-os)}}
include:
- java-version: 11
- gradle: 5.6.4
build-root-suffix: -gradle-5
- gradle: 4.10.3
build-root-suffix: -gradle-4
- gradle: 3.5.1
build-root-suffix: -gradle-4
java-version: 8
exclude:
- os: macos-latest # Java 8 is not supported on macos-latest, so we cannot test Gradle 3.5.1
gradle: 3.5.1
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
@@ -78,7 +83,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
java-version: ${{ matrix.java-version }}
- name: Run Gradle build
uses: ./setup-gradle
id: gradle

View File

@@ -26,14 +26,19 @@ jobs:
DEVELOCITY_URL: https://ge.solutions-team.gradle.com
DEVELOCITY_PLUGIN_VERSION: ${{ matrix.plugin-version }}
DEVELOCITY_CCUD_PLUGIN_VERSION: '2.0'
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} # required to test against GE plugin 3.16.2
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
${{matrix.accessKeyEnv}}: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
strategy:
fail-fast: false
matrix:
gradle: [current, 7.6.2, 6.9.4, 5.6.4]
os: ${{fromJSON(inputs.runner-os)}}
plugin-version: [3.16.2, 3.17]
plugin-version: [3.16.2, 3.17.5]
include:
- plugin-version: 3.16.2
accessKeyEnv: GRADLE_ENTERPRISE_ACCESS_KEY
- plugin-version: 3.17.5
accessKeyEnv: DEVELOCITY_ACCESS_KEY
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
@@ -45,7 +50,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
java-version: 11
- name: Setup Gradle
id: setup-gradle
uses: ./setup-gradle
@@ -61,4 +66,136 @@ jobs:
uses: actions/github-script@v7
with:
script: |
core.setFailed('No Build Scan detected')
core.setFailed('No Build Scan detected')
- name: Check short lived token (DEVELOCITY_ACCESS_KEY)
run: "[ ${#DEVELOCITY_ACCESS_KEY} -gt 500 ] || (echo 'DEVELOCITY_ACCESS_KEY does not look like a short lived token'; exit 1)"
- name: Check short lived token (GRADLE_ENTERPRISE_ACCESS_KEY)
run: "[ ${#GRADLE_ENTERPRISE_ACCESS_KEY} -gt 500 ] || (echo 'GRADLE_ENTERPRISE_ACCESS_KEY does not look like a short lived token'; exit 1)"
inject-develocity-with-access-key:
env:
DEVELOCITY_INJECTION_ENABLED: true
DEVELOCITY_URL: 'https://ge.solutions-team.gradle.com'
DEVELOCITY_PLUGIN_VERSION: ${{ matrix.plugin-version }}
DEVELOCITY_CCUD_PLUGIN_VERSION: '2.0'
strategy:
fail-fast: false
matrix:
gradle: [current, 7.6.2, 6.9.4, 5.6.4]
os: ${{fromJSON(inputs.runner-os)}}
plugin-version: [3.16.2, 3.17.5]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
- name: Setup Gradle
id: setup-gradle
uses: ./setup-gradle
with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
gradle-version: ${{ matrix.gradle }}
develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
develocity-token-expiry: 1
- name: Run Gradle build
id: gradle
working-directory: .github/workflow-samples/no-ge
run: gradle help
- name: Check short lived token (DEVELOCITY_ACCESS_KEY)
run: "[ ${#DEVELOCITY_ACCESS_KEY} -gt 500 ] || (echo 'DEVELOCITY_ACCESS_KEY does not look like a short lived token'; exit 1)"
- name: Check short lived token (GRADLE_ENTERPRISE_ACCESS_KEY)
run: "[ ${#GRADLE_ENTERPRISE_ACCESS_KEY} -gt 500 ] || (echo 'GRADLE_ENTERPRISE_ACCESS_KEY does not look like a short lived token'; exit 1)"
- name: Check Build Scan url
if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v7
with:
script: |
core.setFailed('No Build Scan detected')
inject-develocity-short-lived-token-failed:
env:
DEVELOCITY_INJECTION_ENABLED: true
DEVELOCITY_URL: 'https://localhost:3333/'
DEVELOCITY_PLUGIN_VERSION: ${{ matrix.plugin-version }}
DEVELOCITY_CCUD_PLUGIN_VERSION: '2.0'
# Access key also set as an env var, we want to check it does not leak
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
strategy:
fail-fast: false
matrix:
gradle: [ current, 7.6.2, 6.9.4, 5.6.4 ]
os: ${{fromJSON(inputs.runner-os)}}
plugin-version: [ 3.16.2, 3.17.5 ]
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
- name: Setup Gradle
id: setup-gradle
uses: ./setup-gradle
with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
- name: Run Gradle build
id: gradle
working-directory: .github/workflow-samples/no-ge
run: gradle help
- name: Check access key is not blank (DEVELOCITY_ACCESS_KEY)
run: "[ \"${DEVELOCITY_ACCESS_KEY}\" != \"\" ] || (echo 'using DEVELOCITY_ACCESS_KEY!'; exit 1)"
- name: Check access key is not blank (GRADLE_ENTERPRISE_ACCESS_KEY)
run: "[ \"${GRADLE_ENTERPRISE_ACCESS_KEY}\" != \"\" ] || (echo 'GRADLE_ENTERPRISE_ACCESS_KEY is still supported in v3!'; exit 1)"
inject-develocity-with-access-key-from-input-actions:
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
strategy:
fail-fast: false
matrix:
gradle: [ current, 7.6.2, 6.9.4, 5.6.4 ]
os: ${{fromJSON(inputs.runner-os)}}
plugin-version: [ 3.16.2, 3.17.5 ]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
- name: Setup Gradle
id: setup-gradle
uses: ./setup-gradle
with:
cache-read-only: false # For testing, allow writing cache entries on non-default branches
gradle-version: ${{ matrix.gradle }}
develocity-injection-enabled: true
develocity-url: 'https://ge.solutions-team.gradle.com'
develocity-plugin-version: ${{ matrix.plugin-version }}
- name: Run Gradle build
id: gradle
working-directory: .github/workflow-samples/no-ge
run: gradle help
- name: Check Build Scan url
if: ${{ !steps.gradle.outputs.build-scan-url }}
uses: actions/github-script@v7
with:
script: |
core.setFailed('No Build Scan detected')

View File

@@ -76,12 +76,17 @@ jobs:
gradle: [7.3, 6.9, 5.6.4, 4.10.3, 3.5.1]
os: ${{fromJSON(inputs.runner-os)}}
include:
- java-version: 11
- gradle: 5.6.4
build-root-suffix: -gradle-5
- gradle: 4.10.3
build-root-suffix: -gradle-4
- gradle: 3.5.1
build-root-suffix: -gradle-4
java-version: 8
exclude:
- os: macos-latest # Java 8 is not supported on macos-latest, so we cannot test Gradle 3.5.1
gradle: 3.5.1
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
@@ -93,7 +98,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
java-version: ${{ matrix.java-version }}
- name: Setup Gradle
id: setup-gradle
uses: ./setup-gradle

View File

@@ -48,7 +48,7 @@ jobs:
body: |
Automatically generated pull request to update the known wrapper checksums.
In case of conflicts, manually run the workflow from the [Actions tab](https://github.com/gradle/wrapper-validation-action/actions/workflows/update-checksums-file.yml), the changes will then be force-pushed onto this pull request branch.
In case of conflicts, manually run the workflow from the [Actions tab](https://github.com/gradle/actions/actions/workflows/update-checksums-file.yml), the changes will then be force-pushed onto this pull request branch.
Do not manually update the pull request branch; those changes might get overwritten.
> [!IMPORTANT]

1
.gitignore vendored
View File

@@ -1,3 +1,2 @@
.git
.vscode
actions.code-workspace

View File

@@ -6,21 +6,6 @@ The `build` script in the project root provides a convenient way to perform many
3. `./build init-scripts` will run the init-script integration tests
4. `./build act <act-commands>` will run `act` after building local changes (see below)
## How to merge a Dependabot PR
The "distribution" for a GitHub Action is checked into the repository itself.
In the case of these actions, the transpiled sources are committed to the `dist` directory.
Any production dependencies are inlined into the distribution.
So if a Dependabot PR updates a production dependency (or a dev dependency that changes the distribution, like the Typescript compiler),
then a manual step is required to rebuild the dist and commit.
The simplest process to follow is:
1. Checkout the dependabot branch locally eg: `git checkout dependabot/npm_and_yarn/actions/github-5.1.0`
2. In the `sources` directory, run `npm install` to download NPM dependencies
3. In the `sources` directory, run `npm run build` to regenerate the distribution
4. Push the changes to the dependabot branch
5. If/when the checks pass, you can merge the dependabot PR
## Using `act` to run integ-test workflows locally
It's possible to run GitHub Actions workflows locally with https://nektosact.com/.
@@ -36,7 +21,6 @@ Example running a single job:
`./build act -W .github/workflows/integ-test-caching-config.yml -j cache-disabled-pre-existing-gradle-home`
Known issues:
- `integ-test-cache-cleanup.yml` fails because `gradle` is not installed on the runner. Should be fixed by #33.
- `integ-test-detect-java-toolchains.yml` fails when running on a `linux/amd64` container, since the expected pre-installed JDKs are not present. Should be fixed by #89.
- `act` is not yet compatible with `actions/upload-artifact@v4` (or related toolkit functions)
- See https://github.com/nektos/act/pull/2224
@@ -46,4 +30,4 @@ Tips:
- Add the following lines to `~/.actrc`:
- `--container-daemon-socket -` : Prevents "error while creating mount source path", and yes that's a solitary dash at the end
- `--matrix os:ubuntu-latest` : Avoids a lot of logging about unsupported runners being skipped
- Runners don't have `java` installed by default, so all workflows that run Gradle require a `setup-java` step.
- Runners don't have `java` installed by default, so all workflows that run Gradle require a `setup-java` step.

View File

@@ -15,7 +15,8 @@ The recommended way to execute any Gradle build is with the help of the [Gradle
```yaml
name: Build
on: [ push ]
on:
push:
jobs:
build:
@@ -48,7 +49,9 @@ Simply add this as a new workflow file to your repository (eg `.github/workflows
```yaml
name: Dependency Submission
on: [ push ]
on:
push:
branches: [ 'main' ]
permissions:
contents: write
@@ -80,7 +83,10 @@ The action should be run in the root of the repository, as it will recursively s
```yaml
name: "Validate Gradle Wrapper"
on: [push, pull_request]
on:
push:
pull_request:
jobs:
validation:

View File

@@ -1,8 +1,9 @@
# Gradle GitHub Actions release process
## Preparation
- Push any outstanding changes to branch main. For any change that impacts the released action, you must run npm via `./build all` and commit the various files generated into the dist directory.
- Push any outstanding changes to branch main.
- Check that https://github.com/gradle/actions/actions is green for all workflows for the main branch.
- This should include any workflows triggered by `[bot] Update dist directory`
- Decide on the version number to use for the release. The action releases should follow semantic versioning.
- By default, a patch release is assumed (eg. `3.0.0``3.0.1`)
- If new features have been added, bump the minor version (eg `3.1.1``3.2.0`)
@@ -11,14 +12,12 @@
## Release gradle/actions
- Create a tag for the release. The tag should have the format `v3.1.0`
- From CLI: `git tag v3.1.0`
- Push the commit and tag
- From CLI: `git push --tags`
- From CLI: `git tag v3.1.0 && git push --tags`
- Go to https://github.com/gradle/actions/releases and "Draft new release"
- Use the newly created tag and copy the tag name exactly as the release title.
- Craft release notes content based on issues closed, PRs merged and commits
- Include a Full changelog link in the format https://github.com/gradle/actions/compare/v2.12.0...v3.0.0
- Publish the release. Before using "Publish release", check that [action workflows](https://github.com/gradle/actions/actions) are green for the version tag. eg https://github.com/gradle/actions/actions?query=branch%3Av3.0.0
- Publish the release.
- Force push the `v3` tag (or current major version) to point to the new release. It is conventional for users to bind to a major release version using this tag.
- From CLI: `git tag -f -a -m "v3.0.0" v3 v3.0.0 && git push -f --tags`
- Note that we set the commit message for the tag to the newly released version.
@@ -38,6 +37,21 @@ During the 3.x release series, we will continue to publish parallel releases of
- Force push the `v3` tag (or current major version) to point to the new release.
- From CLI: `git tag -f -a -m "v3.0.0" v3 v3.0.0 && git push -f --tags`
## Release gradle/wrapper-validation-action
During the 3.x release series, we will continue to publish parallel releases of `gradle/wrapper-validation-action`. These releases will simply delegate to `gradle/actions/wrapper-validation` with the same version.
- Update the [wrapper-validation-action action.yml](https://github.com/gradle/wrapper-validation-action/blob/main/action.yml#L162) file to point to the newly released version of `gradle/actions/wrapper-validation`.
- Ensure that any parameters that have been added to the `wrapper-validation` action (if any) are added to the action definition, and that these are passed on to setup-gradle.
- Create and push a tag for the release.
- From CLI: `git tag v3.1.0 && git push --tags`
- Go to https://github.com/gradle/wrapper-validation-action/releases and "Draft new release"
- Use the newly created tag and copy the tag name exactly as the release title.
- In the release notes, point users to the gradle/actions release. Include a header informing users to switch to `gradle/actions/wrapper-validation`.
- Publish the release.
- Force push the `v3` tag (or current major version) to point to the new release.
- From CLI: `git tag -f -a -m "v3.0.0" v3 v3.0.0 && git push -f --tags`
## Post release steps
Submit PRs to update the GitHub starter workflow. Starter workflows contain content that should reference the Git hash of the current gradle/actions release:

11
actions.code-workspace Normal file
View File

@@ -0,0 +1,11 @@
{
"folders": [
{
"path": "."
},
{
"path": "sources"
}
],
"settings": {}
}

12
build
View File

@@ -5,7 +5,7 @@ cd sources
case "$1" in
all)
npm clean-install
nprm run all
npm run all
;;
act)
# Build and copy outputs to the dist directory
@@ -16,14 +16,20 @@ case "$1" in
# Run act
$@
# Revert the changes to the dist directory
git co -- dist
git checkout -- dist
;;
init-scripts)
cd test/init-scripts
./gradlew check
;;
dist)
npm install
npm run build
cd ..
cp -r sources/dist .
;;
*)
npm install
npm run build
;;
esac
esac

View File

@@ -10,7 +10,9 @@ Simply add this as a new workflow file to your repository (eg `.github/workflows
```yaml
name: Dependency Submission
on: [ push ]
on:
push:
branches: ['main']
permissions:
contents: write

View File

@@ -15,13 +15,13 @@ inputs:
dependency-resolution-task:
description: |
Task(s) that should be executed in order to resolve all project dependencies.
Task(s) that should be executed in order to resolve all project dependencies.
By default, the built-in `:ForceDependencyResolutionPlugin_resolveAllDependencies` task is executed.
required: false
additional-arguments:
description: |
Additional arguments to pass to Gradle when generating the dependency graph.
Additional arguments to pass to Gradle when generating the dependency graph.
For example, `--no-configuration-cache --stacktrace`.
required: false
@@ -40,7 +40,7 @@ inputs:
cache-write-only:
description: |
When 'true', entries will not be restored from the cache but will be saved at the end of the Job.
When 'true', entries will not be restored from the cache but will be saved at the end of the Job.
Setting this to 'true' implies cache-read-only will be 'false'.
required: false
default: false
@@ -52,7 +52,7 @@ inputs:
cache-encryption-key:
description: |
A base64 encoded AES key used to encrypt the configuration-cache data. The key is exported as 'GRADLE_ENCRYPTION_KEY' for later steps.
A base64 encoded AES key used to encrypt the configuration-cache data. The key is exported as 'GRADLE_ENCRYPTION_KEY' for later steps.
A suitable key can be generated with `openssl rand -base64 16`.
Configuration-cache data will not be saved/restored without an encryption key being provided.
required: false
@@ -92,7 +92,7 @@ inputs:
'generate-and-submit' (default): Generates a dependency graph for the project and submits it in the same Job.
'generate-and-upload': Generates a dependency graph for the project and saves it as a workflow artifact.
'download-and-submit': Retrieves a previously saved dependency-graph and submits it to the repository.
The `generate-and-upload` and `download-and-submit` options are designed to be used in an untrusted workflow scenario,
where the workflow generating the dependency-graph cannot (or should not) be given the `contents: write` permissions
required to submit via the Dependency Submission API.
@@ -120,11 +120,19 @@ inputs:
build-scan-terms-of-use-url:
description: The URL to the Build Scan® terms of use. This input must be set to 'https://gradle.com/terms-of-service' or 'https://gradle.com/help/legal-terms-of-use'.
required: false
build-scan-terms-of-use-agree:
description: Indicate that you agree to the Build Scan® terms of use. This input value must be "yes".
required: false
develocity-access-key:
description: Develocity access key. Should be set to a secret containing the Develocity Access key.
required: false
develocity-token-expiry:
description: The Develocity short-lived access tokens expiry in hours. Default is 2 hours.
required: false
# DEPRECATED ACTION INPUTS
build-scan-terms-of-service-url:
description: The URL to the Build Scan® terms of use. This input must be set to 'https://gradle.com/terms-of-service'.
@@ -150,7 +158,7 @@ inputs:
description: When 'true', the action will not attempt to restore the Gradle User Home entries from other Jobs.
required: false
default: false
# INTERNAL ACTION INPUTS
# These inputs should not be configured directly, and are only used to pass environmental information to the action
workflow-job-context:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@ The generated dependency graph includes all of the dependencies in your build, a
for vulnerable dependencies, as well as to populate the
[Dependency Graph insights view](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/exploring-the-dependencies-of-a-repository#viewing-the-dependency-graph).
If your confused by the behaviour you're seeing or have specific questions, please check out [the FAQ](dependency-submission-faq.md) before raising an issue.
If you're confused by the behaviour you're seeing or have specific questions, please check out [the FAQ](dependency-submission-faq.md) before raising an issue.
## General usage
@@ -25,7 +25,9 @@ Simply add this as a new workflow file to your repository (eg `.github/workflows
```yaml
name: Dependency Submission
on: [ push ]
on:
push:
branches: [ 'main' ]
permissions:
contents: write
@@ -93,7 +95,7 @@ In some cases, the default action configuration will not be sufficient, and addi
dependency-resolution-task: myDependencyResolutionTask
# Additional arguments that should be passed to execute Gradle
additonal-arguments: --no-configuration-cache
additional-arguments: --no-configuration-cache
# Enable configuration-cache reuse for this build.
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
@@ -104,6 +106,11 @@ In some cases, the default action configuration will not be sufficient, and addi
See the [Action Metadata file](../dependency-submission/action.yml) for a more detailed description of each input parameter.
The `GitHub Dependency Graph Gradle Plugin` can be further
[configured via a number of environment variables](https://github.com/gradle/github-dependency-graph-gradle-plugin?#required-environment-variables).
These will be automatically set by the `dependency-submission` action, but you may override these values
by setting them explicitly in your workflow file.
# Resolving a dependency vulnerability
## Finding the source of a dependency vulnerability
@@ -292,7 +299,8 @@ Example of a pull request workflow that executes a build for a pull request and
```yaml
name: Dependency review for pull requests
on: [ pull_request ]
on:
pull_request:
permissions:
contents: write
@@ -327,7 +335,8 @@ Because of this restriction, we require 2 separate workflows in order to generat
```yaml
name: Generate and save dependency graph
on: [ pull_request ]
on:
pull_request:
permissions:
contents: read # 'write' permission is not available
@@ -358,6 +367,7 @@ on:
types: [completed]
permissions:
actions: read
contents: write
jobs:
@@ -381,7 +391,8 @@ Here's an example of a separate "Dependency Review" workflow that will wait for
```yaml
name: dependency-review
on: [ pull_request ]
on:
pull_request:
permissions:
contents: read

View File

@@ -1,9 +1,9 @@
# Deprecation upgrade guide
As these actions evolve, certain inputs, behaviour and usages are deprecated for removal.
As these actions evolve, certain inputs, behaviour and usages are deprecated for removal.
Deprecated functionality will be fully supported during the current major release, and will be
removed in the next major release.
Users will receive a deprecation warning when they rely on deprecated functionality,
removed in the next major release.
Users will receive a deprecation warning when they rely on deprecated functionality,
prompting them to update their workflows.
## The action `gradle/gradle-build-action` has been replaced by `gradle/actions/setup-gradle`
@@ -25,10 +25,10 @@ with
## The action `gradle/wrapper-validation-action` has been replaced by `gradle/actions/wrapper-validation`
To facilitate ongoing development, the `wrapper-validation-action` action implementation has been merged into
To facilitate ongoing development, the `wrapper-validation-action` action implementation has been merged into
the https://github.com/gradle/actions repository, and the `gradle/wrapper-validation-action` has been replaced by the `gradle/actions/wrapper-validation` action.
As of `v3.x`, the `gradle/wrapper-validation-action` and `gradle/actions/wrappper-validation` actions are
As of `v3.x`, the `gradle/wrapper-validation-action` and `gradle/actions/wrappper-validation` actions are
functionally identical, and are released with the same versions.
In a future major version (likely `v4.x`) we will stop releasing new versions of `gradle/wrapper-validation-action`:
@@ -101,7 +101,7 @@ The exact syntax depends on whether or not your project is configured with the [
- name: Setup Gradle for a non-wrapper project
uses: gradle/actions/setup-gradle@v3
with:
gradle-version: 8.7
gradle-version: 8.9
- name: Assemble the project
run: gradle assemble
@@ -143,3 +143,8 @@ to this:
build-scan-terms-of-use-agree: "yes"
```
These deprecated build-scan parameters are scheduled to be removed in `setup-gradle@v4` and `dependency-submission@v4`.
## The GRADLE_ENTERPRISE_ACCESS_KEY env var is deprecated
Gradle Enterprise has been renamed to Develocity starting from Gradle plugin 3.17 and Develocity server 2024.1.
In v4 release of the action, it will require setting the access key with the `develocity-access-key` input and Develocity 2024.1 at least to generate short-lived tokens.
If those requirements are not met, the `GRADLE_ENTERPRISE_ACCESS_KEY` env var will be cleared out and build scan publication or other authenticated Develocity operations won't be possible.

View File

@@ -4,22 +4,22 @@ This GitHub Action can be used to configure Gradle for optimal execution on any
## Why use the `setup-gradle` action?
It is possible to directly invoke Gradle in your workflow, and the `actions/setup-java@v4` action provides a simple way to cache Gradle dependencies.
It is possible to directly invoke Gradle in your workflow, and the `actions/setup-java@v4` action provides a simple way to cache Gradle dependencies.
However, the `setup-gradle` action offers a several advantages over this approach:
- Easily [configure your workflow to use a specific version of Gradle](#build-with-a-specific-gradle-version) using the `gradle-version` parameter. Gradle distributions are automatically downloaded and cached.
- Easily [configure your workflow to use a specific version of Gradle](#build-with-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-build-state-between-jobs).
- Detailed reporting of cache usage and cache configuration options allow you to [optimize the use of the GitHub actions cache](#optimizing-cache-effectiveness).
- [Generate and Submit a GitHub Dependency Graph](#github-dependency-graph-support) for your project, enabling Dependabot security alerts.
- [Automatic capture of Build Scan® links](#build-reporting) from the build, making them easier to locate in workflow runs.
The `setup-gradle` action is designed to provide these benefits with minimal configuration.
The `setup-gradle` action is designed to provide these benefits with minimal configuration.
These features work both when Gradle is executed via `setup-gradle` and for any Gradle execution in subsequent steps.
## General usage
The `setup-gradle` action works by configuring environment variables and by adding a set of Gradle init-scripts to the Gradle User Home. These will apply to all Gradle executions on the runner, no matter how Gradle is invoked.
The `setup-gradle` action works by configuring environment variables and by adding a set of Gradle init-scripts to the Gradle User Home. These will apply to all Gradle executions on the runner, no matter how Gradle is invoked.
This means that if you have an existing workflow that executes Gradle with a `run` step, you can add an initial "Setup Gradle" Step to benefit from caching, build-scan capture, and other features of this action.
The recommended way to execute any Gradle build is with the help of the [Gradle Wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html), and the following examples assume that the Gradle Wrapper has been configured for the project. See [this example](#build-with-a-specific-gradle-version) if your project doesn't use the Gradle Wrapper.
@@ -28,7 +28,8 @@ The recommended way to execute any Gradle build is with the help of the [Gradle
```yaml
name: Run Gradle on every push
on: push
on:
push:
jobs:
gradle:
@@ -45,7 +46,7 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
- name: Execute Gradle build
run: ./gradlew build
```
@@ -125,7 +126,7 @@ cache-disabled: true
### Using the cache read-only
By default, The `setup-gradle` action will only write to the cache from Jobs on the default (`main`/`master`) branch.
Jobs on other branches will read entries from the cache but will not write updated entries.
Jobs on other branches will read entries from the cache but will not write updated entries.
See [Optimizing cache effectiveness](#select-which-branches-should-write-to-the-cache) for a more detailed explanation.
In some circumstances, it makes sense to change this default and configure a workflow Job to read existing cache entries but not to write changes back.
@@ -157,7 +158,7 @@ cache-write-only: true
When the action detects that the Gradle User Home caches directory already exists (`~/.gradle/caches`), then by default it will not overwrite the existing content of this directory.
This can occur when a prior action initializes this directory, or when using a self-hosted runner that retains this directory between uses.
In this case, the Job Summary will display a message like:
In this case, the Job Summary will display a message like:
> Caching for Gradle actions was disabled due to pre-existing Gradle User Home
If you want to override the default and have the caches of the `setup-gradle` action overwrite existing content in the Gradle User Home, you can set the `cache-overwrite-existing` parameter to `true`:
@@ -197,13 +198,13 @@ jobs:
```
> [!IMPORTANT]
> The configuration cache cannot be saved or restored in workflows triggered by a pull requests from a repsitory fork.
> The configuration cache cannot be saved or restored in workflows triggered by a pull requests from a repository fork.
> This is because [GitHub secrets are not passed to workflows triggered by PRs from forks](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#using-secrets-in-a-workflow).
> This prevents a malicious PR from reading the configuration-cache data, which may encode secrets read by Gradle.
### Incompatibility with other caching mechanisms
When using `setup-gradle` we recommend that you avoid using other mechanisms to save and restore the Gradle User Home.
When using `setup-gradle` we recommend that you avoid using other mechanisms to save and restore the Gradle User Home.
Specifically:
- Avoid using `actions/cache` configured to cache the Gradle User Home, [as described in this example](https://github.com/actions/cache/blob/main/examples.md#java---gradle).
@@ -217,7 +218,7 @@ Using either of these mechanisms may interfere with the caching provided by this
The GitHub Actions cache has some properties that present problems for efficient caching of the Gradle User Home.
- Immutable entries: once a cache entry is written for a key, it cannot be overwritten or changed.
- Branch scope: cache entries written for a Git branch are not visible from actions running against different branches. Entries written for the default branch are visible to all. https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache
- Branch scope: cache entries written for a Git branch are not visible from actions running against different branches or tags. Entries written for the default branch are visible to all. https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache
- Restore keys: if no exact match is found, a set of partial keys can be provided that will match by cache key prefix. https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key
Each of these properties has influenced the design and implementation of the caching in `setup-gradle`, as described below.
@@ -255,7 +256,7 @@ The Gradle User Home cache key is composed of:
Specifically, the cache key is: `${cache-protocol}-gradle|${runner-os}|${job-id}[${hash-of-job-matrix-and-workflow-name}]-${git-sha}`
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.
This allows the most recent state to always be available in the GitHub actions cache.
### Finding a matching cache entry
@@ -270,7 +271,7 @@ Due to branch scoping of cache entries, the above match will be first performed
After the Job is complete, the current Gradle User Home state will be collected and written as a new cache entry with the complete cache key. Old entries will be expunged from the GitHub Actions cache on a least recently used basis.
Note that while effective, this mechanism is not inherently efficient. It requires the entire Gradle User Home directory to be stored separately for each branch, for every OS+Job+Matrix combination. In addition, it writes a new cache entry on every GitHub Actions run.
Note that while effective, this mechanism is not inherently efficient. It requires the entire Gradle User Home directory to be stored separately for each branch, for every OS+Job+Matrix combination. In addition, it writes a new cache entry on every GitHub Actions run.
This inefficiency is effectively mitigated by [Deduplication of Gradle User Home cache entries](#deduplication-of-gradle-user-home-cache-entries) and can be further optimized for a workflow using the techniques described in [Optimizing cache effectiveness](#optimizing-cache-effectiveness).
@@ -288,7 +289,7 @@ For example, this means that all jobs executing a particular version of the Grad
### Stopping the Gradle daemon
By default, the action will stop all running Gradle daemons in the post-action step, before saving the Gradle User Home state.
By default, the action will stop all running Gradle daemons in the post-action step, before saving the Gradle User Home state.
This allows for any Gradle User Home cleanup to occur, and avoid file-locking issues on Windows.
If caching is disabled or the cache is in read-only mode, the daemon will not be stopped and will continue running after the job is completed.
@@ -315,23 +316,23 @@ Some techniques can be used to avoid/mitigate this issue:
### Select which branches should write to the cache
GitHub cache entries are not shared between builds on different branches.
Workflow runs can restore caches created in either the current branch or the default branch (usually main).
GitHub cache entries are not shared between builds on different branches or tags.
Workflow runs can _only_ restore caches created in either the same branch or the default branch (usually `main`).
This means that each branch will have its own Gradle User Home cache scope, and will not benefit from cache entries written for other (non-default) branches.
By default, The `setup-gradle` action will only _write_ to the cache for builds run on the default (`master`/`main`) branch.
Jobs running on other branches will only read from the cache. In most cases, this is the desired behavior.
This is because Jobs running on other branches will benefit from the cached Gradle User Home from `main`,
By default, The `setup-gradle` action will only _write_ to the cache for builds run on the default (`master`/`main`) branch.
Jobs running on other branches will only read from the cache. In most cases, this is the desired behavior.
This is because Jobs running on other branches will benefit from the cached Gradle User Home from `main`,
without writing private cache entries which could lead to evicting these shared entries.
If you have other long-lived development branches that would benefit from writing to the cache,
you can configure this by disabling the `cache-read-only` action parameter for these branches.
If you have other long-lived development branches that would benefit from writing to the cache,
you can configure this by disabling the `cache-read-only` action parameter for these branches.
See [Using the cache read-only](#using-the-cache-read-only) for more details.
Note there are some cases where writing cache entries is typically unhelpful (these are disabled by default):
- For `pull_request` triggered runs, the cache scope is limited to the merge ref (`refs/pull/.../merge`) and can only be restored by re-runs of the same pull request.
- For `merge_group` triggered runs, the cache scope is limited to a temporary branch with a special prefix created to validate pull request changes, and won't be available on subsequent Merge Queue executions.
### Exclude content from Gradle User Home cache
As well as any wrapper distributions, the action will attempt to save and restore the `caches` and `notifications` directories from Gradle User Home.
@@ -352,7 +353,7 @@ gradle-home-cache-excludes: |
caches/keyrings
```
You can specify any number of fixed paths or patterns to include or exclude.
You can specify any number of fixed paths or patterns to include or exclude.
File pattern support is documented at https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#patterns-to-match-file-paths.
### Remove unused files from Gradle User Home before saving to the cache
@@ -361,7 +362,7 @@ The Gradle User Home directory tends to grow over time. When you switch to a new
the old files are not automatically and immediately removed. While this can make sense in a local environment, in a GitHub Actions environment
it can lead to ever-larger Gradle User Home cache entries being saved and restored.
To avoid this situation, The `setup-gradle` action supports the `gradle-home-cache-cleanup` parameter.
To avoid this situation, The `setup-gradle` action supports the `gradle-home-cache-cleanup` parameter.
When enabled, this feature will attempt to delete any files in the Gradle User Home that were not used by Gradle during the GitHub Actions Workflow, before saving the Gradle User Home to the GitHub Actions cache.
Gradle Home cache cleanup is considered experimental and is disabled by default. You can enable this feature for the action as follows:
@@ -375,7 +376,7 @@ If you have a remote build-cache available for your build, then it is recommende
- Enable [remote build-cache push](https://docs.gradle.org/current/userguide/build_cache.html#sec:build_cache_configure_use_cases) for your GitHub Actions builds
- Disable [local build-cache]() for your GitHub Actions build
As well as reducing the content that needs to be saved to the GitHub Actions cache,
As well as reducing the content that needs to be saved to the GitHub Actions cache,
this setup will ensure that your CI builds populate the remote cache and keep the cache entries fresh by reading these entries.
Local builds can then benefit from the remote cache.
@@ -388,8 +389,8 @@ You can enable debug logging either by:
### Increased logging from Gradle builds
When debug logging is enabled, this action will cause all builds to run with the `--info` and `--stacktrace` options.
This is done by inserting the relevant [Gradle properties](https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties)
When debug logging is enabled, this action will cause all builds to run with the `--info` and `--stacktrace` options.
This is done by inserting the relevant [Gradle properties](https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties)
at the top of the `${GRADLE_USER_HOME}/gradle.properties` file.
If the additional Gradle logging produced is problematic, you may opt out of this behavior by setting these properties manually in your project `gradle.properties` file:
@@ -402,7 +403,7 @@ org.gradle.logging.stacktrace=internal
### Cache debugging and analysis
A report of all cache entries restored and saved is printed to the Job Summary when saving the cache entries.
A report of all cache entries restored and saved is printed to the Job Summary when saving the cache entries.
This report can provide valuable insight into how much cache space is being used.
When debug logging is enabled, more detailed logging of cache operations is included in the GitHub actions log.
@@ -460,18 +461,18 @@ Note that to add a Pull Request comment, the workflow must be configured with th
As well as reporting all [Build Scan](https://gradle.com/build-scans/) links in the Job Summary,
The `setup-gradle` action makes this link available as an output of any Step that executes Gradle.
The output name is `build-scan-url`. You can then use the build scan link in subsequent actions of your workflow.
The output name is `build-scan-url`. You can then use the build scan link in subsequent actions of your workflow.
### Saving arbitrary build outputs
By default, a GitHub Actions workflow using `setup-gradle` will record the log output and any Build Scan
By default, a GitHub Actions workflow using `setup-gradle` 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:
jobs:
gradle:
runs-on: ubuntu-latest
steps:
@@ -505,7 +506,7 @@ Since Gradle applies init scripts in alphabetical order, one way to ensure this
## Gradle Wrapper validation
Instead of using the [wrapper-validation action](./wrapper-validation.md) separately, you can enable
Instead of using the [wrapper-validation action](./wrapper-validation.md) separately, you can enable
wrapper validation directly in your Setup Gradle step.
```yaml
@@ -529,7 +530,7 @@ You can use the `setup-gradle` action on GitHub Enterprise Server, and benefit f
## GitHub Dependency Graph support
> [!IMPORTANT]
> The simplest (and recommended) way to generate a dependency graph is via a separate workflow
> The simplest (and recommended) way to generate a dependency graph is via a separate workflow
> using `gradle/actions/dependency-submission`. This action will attempt to detect all dependencies used by your build
> without building and testing the project itself.
>
@@ -543,7 +544,7 @@ The dependency graph snapshot is generated via integration with the [GitHub Depe
The generated dependency graph snapshot reports all of the dependencies that were resolved during a build execution, and is used by GitHub to generate [Dependabot Alerts](https://docs.github.com/en/code-security/dependabot/dependabot-alerts/about-dependabot-alerts) for vulnerable dependencies, as well as to populate the [Dependency Graph insights view](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/exploring-the-dependencies-of-a-repository#viewing-the-dependency-graph).
### Basic usage
You enable GitHub Dependency Graph support by setting the `dependency-graph` action parameter. Valid values are:
| Option | Behaviour |
@@ -559,7 +560,7 @@ Example of a CI workflow that generates and submits a dependency graph:
name: CI build
on:
push:
permissions:
contents: write
@@ -581,13 +582,13 @@ jobs:
run: ./gradlew build
```
The `contents: write` permission is required to submit (but not generate) the dependency graph file.
The `contents: write` permission is required to submit (but not generate) the dependency graph file.
Depending on [repository settings](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token), this permission may be available by default or may need to be explicitly enabled in the workflow file (as above).
> [!IMPORTANT]
> The above configuration will work for workflows that run as a result of commits to a repository branch,
> The above configuration will work for workflows that run as a result of commits to a repository branch,
> but not when a workflow is triggered by a PR from a repository fork.
> This is because the `contents: write` permission is not available when executing a workflow
> This is because the `contents: write` permission is not available when executing a workflow
> for a PR submitted from a forked repository.
> For a configuration that supports this setup, see [Dependency Graphs for pull request workflows](dependency-submission.md#usage-with-pull-requests-from-public-forked-repositories).
@@ -609,7 +610,7 @@ graph cannot be generated or submitted. You can enable this behavior with the `d
### Using a custom plugin repository
By default, the action downloads the `github-dependency-graph-gradle-plugin` from the Gradle Plugin Portal (https://plugins.gradle.org). If your GitHub Actions environment does not have access to this URL, you can specify a custom plugin repository to use.
By default, the action downloads the `github-dependency-graph-gradle-plugin` from the Gradle Plugin Portal (https://plugins.gradle.org). If your GitHub Actions environment does not have access to this URL, you can specify a custom plugin repository to use.
Do so by setting the `GRADLE_PLUGIN_REPOSITORY_URL` environment variable with your Gradle invocation.
The `GRADLE_PLUGIN_REPOSITORY_USERNAME` and `GRADLE_PLUGIN_REPOSITORY_PASSWORD` can be used when the plugin repository requires authentication.
@@ -669,7 +670,7 @@ jobs:
### Filtering which Gradle Configurations contribute to the dependency graph
If you do not want the dependency graph to include every dependency configuration in every project in your build,
If you do not want the dependency graph to include every dependency configuration in every project in your build,
you can limit the dependency extraction to a subset of these.
See the documentation for [dependency-submission](dependency-submission.md) and the
@@ -677,7 +678,7 @@ See the documentation for [dependency-submission](dependency-submission.md) and
### Gradle version compatibility
Dependency-graph generation is compatible with most versions of Gradle >= `5.2`, and is tested regularly against
Dependency-graph generation is compatible with most versions of Gradle >= `5.2`, and is tested regularly against
Gradle versions `5.2.1`, `5.6.4`, `6.0.1`, `6.9.4`, `7.1.1` and `7.6.3`, as well as all patched versions of Gradle 8.x.
A known exception to this is that Gradle `7.0`, `7.0.1`, and `7.0.2` are not supported.
@@ -686,7 +687,7 @@ See [here](https://github.com/gradle/github-dependency-graph-gradle-plugin?tab=r
### Reducing storage costs for saved dependency graph artifacts
When `generate` or `generate-and-submit` is used with the action, the dependency graph that is generated is stored as a workflow artifact.
When `generate` or `generate-and-submit` is used with the action, the dependency graph that is generated is stored as a workflow artifact.
By default, these artifacts are retained for 30 days (or as configured for the repository).
To reduce storage costs for these artifacts, you can set the `artifact-retention-days` value to a lower number.
@@ -707,13 +708,32 @@ The same auto-injection behavior is available for the Common Custom User Data Gr
## Enabling Develocity injection
To enable Develocity injection for your build, you must provide the required configuration via environment variables.
To enable Develocity injection for your build, you must provide the required configuration via inputs.
Here's a minimal example:
```yaml
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
develocity-injection-enabled: true
develocity-url: https://develocity.your-server.com
develocity-plugin-version: 3.17.5
- name: Run a Gradle build with Develocity injection enabled
run: ./gradlew build
```
This configuration will automatically apply `v3.17.5` of the [Develocity Gradle plugin](https://docs.gradle.com/develocity/gradle-plugin/), and publish build scans to https://develocity.your-server.com.
This example assumes that the `develocity.your-server.com` server allows anonymous publishing of build scans.
In the likely scenario that your Develocity server requires authentication, you will also need to pass a valid [Develocity access key](https://docs.gradle.com/develocity/gradle-plugin/#via_environment_variable) taken from a secret:
```yaml
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
develocity-access-key: ${{ secrets.MY_DEVELOCITY_ACCESS_KEY }}
- name: Run a Gradle build with Develocity injection enabled
run: ./gradlew build
@@ -723,11 +743,14 @@ Here's a minimal example:
DEVELOCITY_PLUGIN_VERSION: 3.17
```
This configuration will automatically apply `v3.17` of the [Develocity Gradle plugin](https://docs.gradle.com/develocity/gradle-plugin/), and publish build scans to https://develocity.your-server.com.
This access key will be used during the action execution to get a short-lived token and set it to the DEVELOCITY_ACCESS_KEY environment variable.
This example assumes that the `develocity.your-server.com` server allows anonymous publishing of build scans.
In the likely scenario that your Develocity server requires authentication, you will also need to configure an additional environment variable
with a valid [Develocity access key](https://docs.gradle.com/develocity/gradle-plugin/#via_environment_variable).
### Short-lived access tokens
Develocity access keys are long-lived, creating risks if they are leaked. To avoid this, users can use short-lived access tokens to authenticate with Develocity. Access tokens can be used wherever an access key would be used. Access tokens are only valid for the Develocity instance that created them.
If a short-lived token fails to be retrieved (for example, if the Develocity server version is lower than `2024.1`):
- if a `GRADLE_ENTERPRISE_ACCESS_KEY` env var has been set, we're falling back to it with a deprecation warning
- otherwise no access key env var will be set. In that case Develocity authenticated operations like build cache read/write and build scan publication will fail without failing the build.
For more information on short-lived tokens, see [Develocity API documentation](https://docs.gradle.com/develocity/api-manual/#short_lived_access_tokens).
## Configuring Develocity injection
@@ -735,16 +758,46 @@ The `init-script` supports several additional configuration parameters that you
| Variable | Required | Description |
|--------------------------------------| --- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| DEVELOCITY_INJECTION_ENABLED | :white_check_mark: | enables Develocity injection |
| DEVELOCITY_URL | :white_check_mark: | the URL of the Develocity server |
| DEVELOCITY_ALLOW_UNTRUSTED_SERVER | | allow communication with an untrusted server; set to _true_ if your Develocity instance is using a self-signed certificate |
| DEVELOCITY_CAPTURE_FILE_FINGERPRINTS | | enables capturing the paths and content hashes of each individual input file |
| DEVELOCITY_ENFORCE_URL | | enforce the configured Develocity URL over a URL configured in the project's build; set to _true_ to enforce publication of build scans to the configured Develocity URL |
| DEVELOCITY_PLUGIN_VERSION | :white_check_mark: | the version of the [Develocity Gradle plugin](https://docs.gradle.com/develocity/gradle-plugin/) to apply |
| DEVELOCITY_CCUD_PLUGIN_VERSION | | the version of the [Common Custom User Data Gradle plugin](https://github.com/gradle/common-custom-user-data-gradle-plugin) to apply, if any |
| GRADLE_PLUGIN_REPOSITORY_URL | | the URL of the repository to use when resolving the Develocity and CCUD plugins; the Gradle Plugin Portal is used by default |
| GRADLE_PLUGIN_REPOSITORY_USERNAME | | the username for the repository URL to use when resolving the Develocity and CCUD plugins |
| GRADLE_PLUGIN_REPOSITORY_PASSWORD | | the password for the repository URL to use when resolving the Develocity and CCUD plugins; Consider using secrets to pass the value to this variable |
| develocity-injection-enabled | :white_check_mark: | enables Develocity injection |
| develocity-url | :white_check_mark: | the URL of the Develocity server |
| develocity-allow-untrusted-server | | allow communication with an untrusted server; set to _true_ if your Develocity instance is using a self-signed certificate |
| develocity-capture-file-fingerprints | | enables capturing the paths and content hashes of each individual input file |
| develocity-enforce-url | | enforce the configured Develocity URL over a URL configured in the project's build; set to _true_ to enforce publication of build scans to the configured Develocity URL |
| develocity-plugin-version | :white_check_mark: | the version of the [Develocity Gradle plugin](https://docs.gradle.com/develocity/gradle-plugin/) to apply |
| develocity-ccud-plugin-version | | the version of the [Common Custom User Data Gradle plugin](https://github.com/gradle/common-custom-user-data-gradle-plugin) to apply, if any |
| gradle-plugin-repository-url | | the URL of the repository to use when resolving the Develocity and CCUD plugins; the Gradle Plugin Portal is used by default |
| gradle-plugin-repository-username | | the username for the repository URL to use when resolving the Develocity and CCUD plugins |
| gradle-plugin-repository-password | | the password for the repository URL to use when resolving the Develocity and CCUD plugins; Consider using secrets to pass the value to this variable |
The input parameters can be expressed as environment variables following the relationships outlined in the table below:
| Input | Environment Variable |
|--------------------------------------|--------------------------------------|
| develocity-injection-enabled | DEVELOCITY_INJECTION_ENABLED |
| develocity-url | DEVELOCITY_URL |
| develocity-allow-untrusted-server | DEVELOCITY_ALLOW_UNTRUSTED_SERVER |
| develocity-capture-file-fingerprints | DEVELOCITY_CAPTURE_FILE_FINGERPRINTS |
| develocity-enforce-url | DEVELOCITY_ENFORCE_URL |
| develocity-plugin-version | DEVELOCITY_PLUGIN_VERSION |
| develocity-ccud-plugin-version | DEVELOCITY_CCUD_PLUGIN_VERSION |
| gradle-plugin-repository-url | GRADLE_PLUGIN_REPOSITORY_URL |
| gradle-plugin-repository-username | GRADLE_PLUGIN_REPOSITORY_USERNAME |
| gradle-plugin-repository-password | GRADLE_PLUGIN_REPOSITORY_PASSWORD |
Here's an example using the env vars:
```yaml
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
- name: Run a Gradle build with Develocity injection enabled with environment variables
run: ./gradlew build
env:
DEVELOCITY_INJECTION_ENABLED: true
DEVELOCITY_URL: https://develocity.your-server.com
DEVELOCITY_PLUGIN_VERSION: 3.17.5
```
## Publishing to scans.gradle.com

View File

@@ -56,7 +56,10 @@ Here's a sample complete workflow you can add to your repositories:
**`.github/workflows/gradle-wrapper-validation.yml`**
```yaml
name: "Validate Gradle Wrapper"
on: [push, pull_request]
on:
push:
pull_request:
jobs:
validation:

View File

@@ -11,7 +11,8 @@ The recommended way to execute any Gradle build is with the help of the [Gradle
```yaml
name: Build
on: [ push ]
on:
push:
jobs:
build:

View File

@@ -23,7 +23,7 @@ inputs:
cache-write-only:
description: |
When 'true', entries will not be restored from the cache but will be saved at the end of the Job.
When 'true', entries will not be restored from the cache but will be saved at the end of the Job.
Setting this to 'true' implies cache-read-only will be 'false'.
required: false
default: false
@@ -35,7 +35,7 @@ inputs:
cache-encryption-key:
description: |
A base64 encoded AES key used to encrypt the configuration-cache data. The key is exported as 'GRADLE_ENCRYPTION_KEY' for later steps.
A base64 encoded AES key used to encrypt the configuration-cache data. The key is exported as 'GRADLE_ENCRYPTION_KEY' for later steps.
A suitable key can be generated with `openssl rand -base64 16`.
Configuration-cache data will not be saved/restored without an encryption key being provided.
required: false
@@ -70,7 +70,7 @@ inputs:
# Dependency Graph configuration
dependency-graph:
description: |
Specifies if a GitHub dependency snapshot should be generated for each Gradle build, and if so, how.
Specifies if a GitHub dependency snapshot should be generated for each Gradle build, and if so, how.
Valid values are 'disabled' (default), 'generate', 'generate-and-submit', 'generate-and-upload', 'download-and-submit' and 'clear'.
required: false
default: 'disabled'
@@ -95,11 +95,59 @@ inputs:
build-scan-terms-of-use-url:
description: The URL to the Build Scan® terms of use. This input must be set to 'https://gradle.com/terms-of-service' or 'https://gradle.com/help/legal-terms-of-use'.
required: false
build-scan-terms-of-use-agree:
description: Indicate that you agree to the Build Scan® terms of use. This input value must be "yes".
required: false
develocity-access-key:
description: Develocity access key. Should be set to a secret containing the Develocity Access key.
required: false
develocity-token-expiry:
description: The Develocity short-lived access tokens expiry in hours. Default is 2 hours.
required: false
develocity-injection-enabled:
description: Enables Develocity injection.
required: false
develocity-url:
description: The URL for the Develocity server.
required: false
develocity-allow-untrusted-server:
description: Allow communication with an untrusted server; set to _true_ if your Develocity instance is using a self-signed.
required: false
develocity-capture-file-fingerprints:
description: Enables capturing the paths and content hashes of each individual input file.
required: false
develocity-enforce-url:
description: Enforce the configured Develocity URL over a URL configured in the project's build; set to _true_ to enforce publication of build scans to the configured Develocity URL.
required: false
develocity-plugin-version:
description: The version of the Develocity Gradle plugin to apply.
required: false
develocity-ccud-plugin-version:
description: The version of the Common Custom User Data Gradle plugin to apply, if any.
required: false
gradle-plugin-repository-url:
description: The URL of the repository to use when resolving the Develocity and CCUD plugins; the Gradle Plugin Portal is used by default.
required: false
gradle-plugin-repository-username:
description: The username for the repository URL to use when resolving the Develocity and CCUD.
required: false
gradle-plugin-repository-password:
description: The password for the repository URL to use when resolving the Develocity and CCUD plugins; Consider using secrets to pass the value to this variable.
required: false
# Wrapper validation configuration
validate-wrappers:
description: |
@@ -143,7 +191,7 @@ inputs:
description: When 'true', the action will not attempt to restore the Gradle User Home entries from other Jobs.
required: false
default: false
# INTERNAL ACTION INPUTS
# These inputs should not be configured directly, and are only used to pass environmental information to the action
workflow-job-context:

View File

@@ -1,3 +1,3 @@
# Configuration file for asdf version manager
nodejs 20.10.0
gradle 8.7
gradle 8.9

View File

@@ -3316,12 +3316,12 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -4736,9 +4736,9 @@
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -11628,12 +11628,12 @@
}
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
}
},
"browserslist": {
@@ -12659,9 +12659,9 @@
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"

View File

@@ -1,20 +0,0 @@
import * as core from '@actions/core'
import {BuildScanConfig} from './configuration'
export function setup(config: BuildScanConfig): void {
maybeExportVariable('DEVELOCITY_INJECTION_INIT_SCRIPT_NAME', 'gradle-actions.inject-develocity.init.gradle')
maybeExportVariable('DEVELOCITY_AUTO_INJECTION_CUSTOM_VALUE', 'gradle-actions')
if (config.getBuildScanPublishEnabled()) {
maybeExportVariable('DEVELOCITY_INJECTION_ENABLED', 'true')
maybeExportVariable('DEVELOCITY_PLUGIN_VERSION', '3.17')
maybeExportVariable('DEVELOCITY_CCUD_PLUGIN_VERSION', '2.0')
maybeExportVariable('DEVELOCITY_TERMS_OF_USE_URL', config.getBuildScanTermsOfUseUrl())
maybeExportVariable('DEVELOCITY_TERMS_OF_USE_AGREE', config.getBuildScanTermsOfUseAgree())
}
}
function maybeExportVariable(variableName: string, value: unknown): void {
if (!process.env[variableName]) {
core.exportVariable(variableName, value)
}
}

View File

@@ -1,8 +1,7 @@
import * as core from '@actions/core'
import * as exec from '@actions/exec'
import * as glob from '@actions/glob'
import fs from 'fs'
import path from 'path'
import {provisionAndMaybeExecute} from '../execution/gradle'
export class CacheCleaner {
private readonly gradleUserHome: string
@@ -13,25 +12,20 @@ export class CacheCleaner {
this.tmpDir = tmpDir
}
async prepare(): Promise<void> {
// Reset the file-access journal so that files appear not to have been used recently
fs.rmSync(path.resolve(this.gradleUserHome, 'caches/journal-1'), {recursive: true, force: true})
fs.mkdirSync(path.resolve(this.gradleUserHome, 'caches/journal-1'), {recursive: true})
fs.writeFileSync(
path.resolve(this.gradleUserHome, 'caches/journal-1/file-access.properties'),
'inceptionTimestamp=0'
)
// Set the modification time of all files to the past: this timestamp is used when there is no matching entry in the journal
await this.ageAllFiles()
// Touch all 'gc' files so that cache cleanup won't run immediately.
await this.touchAllFiles('gc.properties')
async prepare(): Promise<string> {
// Save the current timestamp
const timestamp = Date.now().toString()
core.saveState('clean-timestamp', timestamp)
return timestamp
}
async forceCleanup(): Promise<void> {
// Age all 'gc' files so that cache cleanup will run immediately.
await this.ageAllFiles('gc.properties')
const cleanTimestamp = core.getState('clean-timestamp')
await this.forceCleanupFilesOlderThan(cleanTimestamp)
}
async forceCleanupFilesOlderThan(cleanTimestamp: string): Promise<void> {
core.info(`Cleaning up caches before ${cleanTimestamp}`)
// Run a dummy Gradle build to trigger cache cleanup
const cleanupProjectDir = path.resolve(this.tmpDir, 'dummy-cleanup-project')
@@ -40,30 +34,37 @@ export class CacheCleaner {
path.resolve(cleanupProjectDir, 'settings.gradle'),
'rootProject.name = "dummy-cleanup-project"'
)
fs.writeFileSync(
path.resolve(cleanupProjectDir, 'init.gradle'),
`
beforeSettings { settings ->
def cleanupTime = ${cleanTimestamp}
settings.caches {
cleanup = Cleanup.ALWAYS
releasedWrappers.removeUnusedEntriesOlderThan.set(cleanupTime)
snapshotWrappers.removeUnusedEntriesOlderThan.set(cleanupTime)
downloadedResources.removeUnusedEntriesOlderThan.set(cleanupTime)
createdResources.removeUnusedEntriesOlderThan.set(cleanupTime)
buildCache.removeUnusedEntriesOlderThan.set(cleanupTime)
}
}
`
)
fs.writeFileSync(path.resolve(cleanupProjectDir, 'build.gradle'), 'task("noop") {}')
const gradleCommand = `gradle -g ${this.gradleUserHome} --no-daemon --build-cache --no-scan --quiet -DGITHUB_DEPENDENCY_GRAPH_ENABLED=false noop`
await exec.exec(gradleCommand, [], {
cwd: cleanupProjectDir
})
}
private async ageAllFiles(fileName = '*'): Promise<void> {
core.debug(`Aging all files in Gradle User Home with name ${fileName}`)
await this.setUtimes(`${this.gradleUserHome}/**/${fileName}`, new Date(0))
}
private async touchAllFiles(fileName = '*'): Promise<void> {
core.debug(`Touching all files in Gradle User Home with name ${fileName}`)
await this.setUtimes(`${this.gradleUserHome}/**/${fileName}`, new Date())
}
private async setUtimes(pattern: string, timestamp: Date): Promise<void> {
const globber = await glob.create(pattern, {
implicitDescendants: false
})
for await (const file of globber.globGenerator()) {
fs.utimesSync(file, timestamp, timestamp)
}
await provisionAndMaybeExecute('current', cleanupProjectDir, [
'-g',
this.gradleUserHome,
'-I',
'init.gradle',
'--info',
'--no-daemon',
'--no-scan',
'--build-cache',
'-DGITHUB_DEPENDENCY_GRAPH_ENABLED=false',
'noop'
])
}
}

View File

@@ -45,6 +45,10 @@ export class DependencyGraphConfig {
return DependencyGraphConfig.constructJobCorrelator(github.context.workflow, github.context.job, getJobMatrix())
}
getReportDirectory(): string {
return path.resolve(getWorkspaceDirectory(), 'dependency-graph-reports')
}
static constructJobCorrelator(workflow: string, jobId: string, matrixJson: string): string {
const matrixString = this.describeMatrix(matrixJson)
const label = matrixString ? `${workflow}-${jobId}-${matrixString}` : `${workflow}-${jobId}`
@@ -184,6 +188,9 @@ export enum JobSummaryOption {
}
export class BuildScanConfig {
static DevelocityAccessKeyEnvVar = 'DEVELOCITY_ACCESS_KEY'
static GradleEnterpriseAccessKeyEnvVar = 'GRADLE_ENTERPRISE_ACCESS_KEY'
getBuildScanPublishEnabled(): boolean {
return getBooleanInput('build-scan-publish') && this.verifyTermsOfUseAgreement()
}
@@ -196,6 +203,59 @@ export class BuildScanConfig {
return this.getTermsOfUseProp('build-scan-terms-of-use-agree', 'build-scan-terms-of-service-agree')
}
getDevelocityAccessKey(): string {
return (
core.getInput('develocity-access-key') ||
process.env[BuildScanConfig.DevelocityAccessKeyEnvVar] ||
process.env[BuildScanConfig.GradleEnterpriseAccessKeyEnvVar] ||
''
)
}
getDevelocityTokenExpiry(): string {
return core.getInput('develocity-token-expiry')
}
getDevelocityInjectionEnabled(): boolean | undefined {
return getOptionalBooleanInput('develocity-injection-enabled')
}
getDevelocityUrl(): string {
return core.getInput('develocity-url')
}
getDevelocityAllowUntrustedServer(): boolean | undefined {
return getOptionalBooleanInput('develocity-allow-untrusted-server')
}
getDevelocityCaptureFileFingerprints(): boolean | undefined {
return getOptionalBooleanInput('develocity-capture-file-fingerprints')
}
getDevelocityEnforceUrl(): boolean | undefined {
return getOptionalBooleanInput('develocity-enforce-url')
}
getDevelocityPluginVersion(): string {
return core.getInput('develocity-plugin-version')
}
getDevelocityCcudPluginVersion(): string {
return core.getInput('develocity-ccud-plugin-version')
}
getGradlePluginRepositoryUrl(): string {
return core.getInput('gradle-plugin-repository-url')
}
getGradlePluginRepositoryUsername(): string {
return core.getInput('gradle-plugin-repository-username')
}
getGradlePluginRepositoryPassword(): string {
return core.getInput('gradle-plugin-repository-password')
}
private verifyTermsOfUseAgreement(): boolean {
if (
(this.getBuildScanTermsOfUseUrl() !== 'https://gradle.com/terms-of-service' &&
@@ -309,3 +369,11 @@ function getBooleanInput(paramName: string, paramDefault = false): boolean {
}
throw TypeError(`The value '${paramValue} is not valid for '${paramName}. Valid values are: [true, false]`)
}
function getOptionalBooleanInput(paramName: string): boolean | undefined {
const paramValue = core.getInput(paramName)
if (paramValue === '') {
return undefined
}
return getBooleanInput(paramName)
}

View File

@@ -22,6 +22,7 @@ export async function setup(config: DependencyGraphConfig): Promise<void> {
}
// Download and submit early, for compatability with dependency review.
if (option === DependencyGraphOption.DownloadAndSubmit) {
maybeExportVariable('DEPENDENCY_GRAPH_REPORT_DIR', config.getReportDirectory())
await downloadAndSubmitDependencyGraphs(config)
return
}
@@ -34,10 +35,7 @@ export async function setup(config: DependencyGraphConfig): Promise<void> {
maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_REF', github.context.ref)
maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_SHA', getShaFromContext())
maybeExportVariable('GITHUB_DEPENDENCY_GRAPH_WORKSPACE', getWorkspaceDirectory())
maybeExportVariable(
'DEPENDENCY_GRAPH_REPORT_DIR',
path.resolve(getWorkspaceDirectory(), 'dependency-graph-reports')
)
maybeExportVariable('DEPENDENCY_GRAPH_REPORT_DIR', config.getReportDirectory())
// To clear the dependency graph, we generate an empty graph by excluding all projects and configurations
if (option === DependencyGraphOption.Clear) {
@@ -62,25 +60,98 @@ export async function complete(config: DependencyGraphConfig): Promise<void> {
return
case DependencyGraphOption.GenerateAndSubmit:
case DependencyGraphOption.Clear: // Submit the empty dependency graph
await submitDependencyGraphs(await findGeneratedDependencyGraphFiles())
await findAndSubmitDependencyGraphs(config)
return
case DependencyGraphOption.GenerateAndUpload:
await uploadDependencyGraphs(await findGeneratedDependencyGraphFiles(), config)
await findAndUploadDependencyGraphs(config)
}
} catch (e) {
warnOrFail(config, option, e)
}
}
async function findGeneratedDependencyGraphFiles(): Promise<string[]> {
const workspaceDirectory = getWorkspaceDirectory()
return await findDependencyGraphFiles(workspaceDirectory)
async function downloadAndSubmitDependencyGraphs(config: DependencyGraphConfig): Promise<void> {
if (isRunningInActEnvironment()) {
core.info('Dependency graph not supported in the ACT environment.')
return
}
try {
await submitDependencyGraphs(await downloadDependencyGraphs())
} catch (e) {
warnOrFail(config, DependencyGraphOption.DownloadAndSubmit, e)
}
}
async function findAndSubmitDependencyGraphs(config: DependencyGraphConfig): Promise<void> {
if (isRunningInActEnvironment()) {
core.info('Dependency graph not supported in the ACT environment.')
return
}
const dependencyGraphFiles = await findDependencyGraphFiles()
try {
await submitDependencyGraphs(dependencyGraphFiles)
} catch (e) {
try {
await uploadDependencyGraphs(dependencyGraphFiles, config)
} catch (uploadError) {
core.info(String(uploadError))
}
throw e
}
}
async function findAndUploadDependencyGraphs(config: DependencyGraphConfig): Promise<void> {
if (isRunningInActEnvironment()) {
core.info('Dependency graph not supported in the ACT environment.')
return
}
await uploadDependencyGraphs(await findDependencyGraphFiles(), config)
}
async function downloadDependencyGraphs(): Promise<string[]> {
const findBy = github.context.payload.workflow_run
? {
token: getGithubToken(),
workflowRunId: github.context.payload.workflow_run.id,
repositoryName: github.context.repo.repo,
repositoryOwner: github.context.repo.owner
}
: undefined
const artifactClient = new DefaultArtifactClient()
const dependencyGraphArtifacts = (
await artifactClient.listArtifacts({
latest: true,
findBy
})
).artifacts.filter(artifact => artifact.name.startsWith(DEPENDENCY_GRAPH_PREFIX))
for (const artifact of dependencyGraphArtifacts) {
const downloadedArtifact = await artifactClient.downloadArtifact(artifact.id, {
findBy
})
core.info(`Downloading dependency-graph artifact ${artifact.name} to ${downloadedArtifact.downloadPath}`)
}
return findDependencyGraphFiles()
}
async function findDependencyGraphFiles(): Promise<string[]> {
const globber = await glob.create(`${getReportDirectory()}/**/*.json`)
const allFiles = await globber.glob()
const unprocessedFiles = allFiles.filter(file => !isProcessed(file))
unprocessedFiles.forEach(markProcessed)
core.info(`Found dependency graph files: ${unprocessedFiles.join(', ')}`)
return unprocessedFiles
}
async function uploadDependencyGraphs(dependencyGraphFiles: string[], config: DependencyGraphConfig): Promise<void> {
if (isRunningInActEnvironment()) {
core.info('Dependency graph upload not supported in the ACT environment.')
core.info(`Would upload: ${dependencyGraphFiles.join(', ')}`)
if (dependencyGraphFiles.length === 0) {
core.info('No dependency graph files found to upload.')
return
}
@@ -97,23 +168,9 @@ async function uploadDependencyGraphs(dependencyGraphFiles: string[], config: De
}
}
async function downloadAndSubmitDependencyGraphs(config: DependencyGraphConfig): Promise<void> {
if (isRunningInActEnvironment()) {
core.info('Dependency graph download and submit not supported in the ACT environment.')
return
}
try {
await submitDependencyGraphs(await downloadDependencyGraphs())
} catch (e) {
warnOrFail(config, DependencyGraphOption.DownloadAndSubmit, e)
}
}
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
if (isRunningInActEnvironment()) {
core.info('Dependency graph submit not supported in the ACT environment.')
core.info(`Would submit: ${dependencyGraphFiles.join(', ')}`)
if (dependencyGraphFiles.length === 0) {
core.info('No dependency graph files found to submit.')
return
}
@@ -122,17 +179,16 @@ async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<v
await submitDependencyGraphFile(dependencyGraphFile)
} catch (error) {
if (error instanceof RequestError) {
throw new Error(translateErrorMessage(dependencyGraphFile, error))
} else {
throw error
error.message = translateErrorMessage(dependencyGraphFile, error)
}
throw error
}
}
}
function translateErrorMessage(jsonFile: string, error: RequestError): string {
const relativeJsonFile = getRelativePathFromWorkspace(jsonFile)
const mainWarning = `Dependency submission failed for ${relativeJsonFile}.\n${String(error)}`
const mainWarning = `Dependency submission failed for ${relativeJsonFile}.\n${error.message}`
if (error.message === 'Resource not accessible by integration') {
return `${mainWarning}
Please ensure that the 'contents: write' permission is available for the workflow job.
@@ -154,46 +210,8 @@ async function submitDependencyGraphFile(jsonFile: string): Promise<void> {
const relativeJsonFile = getRelativePathFromWorkspace(jsonFile)
core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
}
async function downloadDependencyGraphs(): Promise<string[]> {
const workspaceDirectory = getWorkspaceDirectory()
const findBy = github.context.payload.workflow_run
? {
token: getGithubToken(),
workflowRunId: github.context.payload.workflow_run.id,
repositoryName: github.context.repo.repo,
repositoryOwner: github.context.repo.owner
}
: undefined
const artifactClient = new DefaultArtifactClient()
const downloadPath = path.resolve(workspaceDirectory, 'dependency-graph')
const dependencyGraphArtifacts = (
await artifactClient.listArtifacts({
latest: true,
findBy
})
).artifacts.filter(candidate => candidate.name.startsWith(DEPENDENCY_GRAPH_PREFIX))
for (const artifact of dependencyGraphArtifacts) {
const downloadedArtifact = await artifactClient.downloadArtifact(artifact.id, {
path: downloadPath,
findBy
})
core.info(`Downloading dependency-graph artifact ${artifact.name} to ${downloadedArtifact.downloadPath}`)
}
return findDependencyGraphFiles(downloadPath)
}
async function findDependencyGraphFiles(dir: string): Promise<string[]> {
const globber = await glob.create(`${dir}/dependency-graph-reports/*.json`)
const allFiles = await globber.glob()
const unprocessedFiles = allFiles.filter(file => !isProcessed(file))
unprocessedFiles.forEach(markProcessed)
return unprocessedFiles
function getReportDirectory(): string {
return process.env.DEPENDENCY_GRAPH_REPORT_DIR!
}
function isProcessed(dependencyGraphFile: string): boolean {

View File

@@ -0,0 +1,39 @@
import * as core from '@actions/core'
import {BuildScanConfig} from '../configuration'
import {setupToken} from './short-lived-token'
export async function setup(config: BuildScanConfig): Promise<void> {
maybeExportVariable('DEVELOCITY_INJECTION_INIT_SCRIPT_NAME', 'gradle-actions.inject-develocity.init.gradle')
maybeExportVariable('DEVELOCITY_AUTO_INJECTION_CUSTOM_VALUE', 'gradle-actions')
if (config.getBuildScanPublishEnabled()) {
maybeExportVariable('DEVELOCITY_INJECTION_ENABLED', 'true')
maybeExportVariable('DEVELOCITY_PLUGIN_VERSION', '3.17.5')
maybeExportVariable('DEVELOCITY_CCUD_PLUGIN_VERSION', '2.0')
maybeExportVariable('DEVELOCITY_TERMS_OF_USE_URL', config.getBuildScanTermsOfUseUrl())
maybeExportVariable('DEVELOCITY_TERMS_OF_USE_AGREE', config.getBuildScanTermsOfUseAgree())
}
maybeExportVariableNotEmpty('DEVELOCITY_INJECTION_ENABLED', config.getDevelocityInjectionEnabled())
maybeExportVariableNotEmpty('DEVELOCITY_URL', config.getDevelocityUrl())
maybeExportVariableNotEmpty('DEVELOCITY_ALLOW_UNTRUSTED_SERVER', config.getDevelocityAllowUntrustedServer())
maybeExportVariableNotEmpty('DEVELOCITY_CAPTURE_FILE_FINGERPRINTS', config.getDevelocityCaptureFileFingerprints())
maybeExportVariableNotEmpty('DEVELOCITY_ENFORCE_URL', config.getDevelocityEnforceUrl())
maybeExportVariableNotEmpty('DEVELOCITY_PLUGIN_VERSION', config.getDevelocityPluginVersion())
maybeExportVariableNotEmpty('GRADLE_PLUGIN_REPOSITORY_URL', config.getGradlePluginRepositoryUrl())
maybeExportVariableNotEmpty('GRADLE_PLUGIN_REPOSITORY_USERNAME', config.getGradlePluginRepositoryUsername())
maybeExportVariableNotEmpty('GRADLE_PLUGIN_REPOSITORY_PASSWORD', config.getGradlePluginRepositoryPassword())
return setupToken(config.getDevelocityAccessKey(), config.getDevelocityTokenExpiry())
}
function maybeExportVariable(variableName: string, value: unknown): void {
if (!process.env[variableName]) {
core.exportVariable(variableName, value)
}
}
function maybeExportVariableNotEmpty(variableName: string, value: unknown): void {
if (value !== null && value !== undefined && value !== '') {
maybeExportVariable(variableName, value)
}
}

View File

@@ -0,0 +1,160 @@
import * as httpm from 'typed-rest-client/HttpClient'
import * as core from '@actions/core'
import {BuildScanConfig} from '../configuration'
import {recordDeprecation} from '../deprecation-collector'
export async function setupToken(develocityAccessKey: string, develocityTokenExpiry: string): Promise<void> {
if (develocityAccessKey) {
try {
core.debug('Fetching short-lived token...')
const tokens = await getToken(develocityAccessKey, develocityTokenExpiry)
if (tokens != null && !tokens.isEmpty()) {
core.debug(`Got token(s), setting the access key env vars`)
const token = tokens.raw()
core.setSecret(token)
exportAccessKeyEnvVars(token)
} else {
handleMissingAccessToken()
}
} catch (e) {
handleMissingAccessToken()
core.warning(`Failed to fetch short-lived token, reason: ${e}`)
}
}
}
function exportAccessKeyEnvVars(value: string): void {
;[BuildScanConfig.DevelocityAccessKeyEnvVar, BuildScanConfig.GradleEnterpriseAccessKeyEnvVar].forEach(key =>
core.exportVariable(key, value)
)
}
function handleMissingAccessToken(): void {
core.warning(`Failed to fetch short-lived token for Develocity`)
if (process.env[BuildScanConfig.GradleEnterpriseAccessKeyEnvVar]) {
// We do not clear the GRADLE_ENTERPRISE_ACCESS_KEY env var in v3, to let the users upgrade to DV 2024.1
recordDeprecation(`The ${BuildScanConfig.GradleEnterpriseAccessKeyEnvVar} env var is deprecated`)
}
if (process.env[BuildScanConfig.DevelocityAccessKeyEnvVar]) {
core.warning(`The ${BuildScanConfig.DevelocityAccessKeyEnvVar} env var should be mapped to a short-lived token`)
}
}
export async function getToken(accessKey: string, expiry: string): Promise<DevelocityAccessCredentials | null> {
const empty: Promise<DevelocityAccessCredentials | null> = new Promise(r => r(null))
const develocityAccessKey = DevelocityAccessCredentials.parse(accessKey)
const shortLivedTokenClient = new ShortLivedTokenClient()
if (develocityAccessKey == null) {
return empty
}
const tokens = new Array<HostnameAccessKey>()
for (const k of develocityAccessKey.keys) {
try {
core.info(`Requesting short-lived Develocity access token for ${k.hostname}`)
const token = await shortLivedTokenClient.fetchToken(`https://${k.hostname}`, k, expiry)
tokens.push(token)
} catch (e) {
// Ignore failure to obtain token
core.info(`Failed to obtain short-lived Develocity access token for ${k.hostname}: ${e}`)
}
}
if (tokens.length > 0) {
return DevelocityAccessCredentials.of(tokens)
}
return empty
}
class ShortLivedTokenClient {
httpc = new httpm.HttpClient('gradle/actions/setup-gradle')
maxRetries = 3
retryInterval = 1000
async fetchToken(serverUrl: string, accessKey: HostnameAccessKey, expiry: string): Promise<HostnameAccessKey> {
const queryParams = expiry ? `?expiresInHours${expiry}` : ''
const sanitizedServerUrl = !serverUrl.endsWith('/') ? `${serverUrl}/` : serverUrl
const headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessKey.key}`
}
let attempts = 0
while (attempts < this.maxRetries) {
try {
const requestUrl = `${sanitizedServerUrl}api/auth/token${queryParams}`
core.debug(`Attempt ${attempts} to fetch short lived token at ${requestUrl}`)
const response = await this.httpc.post(requestUrl, '', headers)
if (response.message.statusCode === 200) {
const text = await response.readBody()
return new Promise<HostnameAccessKey>(resolve => resolve({hostname: accessKey.hostname, key: text}))
}
// This should be only 404
attempts++
if (attempts === this.maxRetries) {
return new Promise((resolve, reject) =>
reject(
new Error(
`Develocity short lived token request failed ${serverUrl} with status code ${response.message.statusCode}`
)
)
)
}
} catch (error) {
attempts++
if (attempts === this.maxRetries) {
return new Promise((resolve, reject) => reject(error))
}
}
await new Promise(resolve => setTimeout(resolve, this.retryInterval))
}
return new Promise((resolve, reject) => reject(new Error('Illegal state')))
}
}
type HostnameAccessKey = {
hostname: string
key: string
}
export class DevelocityAccessCredentials {
static readonly accessKeyRegexp = /^([^;=\s]+=\w+)(;[^;=\s]+=\w+)*$/
readonly keys: HostnameAccessKey[]
private constructor(allKeys: HostnameAccessKey[]) {
this.keys = allKeys
}
static of(allKeys: HostnameAccessKey[]): DevelocityAccessCredentials {
return new DevelocityAccessCredentials(allKeys)
}
private static readonly keyDelimiter = ';'
private static readonly hostDelimiter = '='
static parse(rawKey: string): DevelocityAccessCredentials | null {
if (!this.isValid(rawKey)) {
return null
}
return new DevelocityAccessCredentials(
rawKey.split(this.keyDelimiter).map(hostKey => {
const pair = hostKey.split(this.hostDelimiter)
return {hostname: pair[0], key: pair[1]}
})
)
}
isEmpty(): boolean {
return this.keys.length === 0
}
raw(): string {
return this.keys
.map(k => `${k.hostname}${DevelocityAccessCredentials.hostDelimiter}${k.key}`)
.join(DevelocityAccessCredentials.keyDelimiter)
}
private static isValid(allKeys: string): boolean {
return this.accessKeyRegexp.test(allKeys)
}
}

View File

@@ -22,7 +22,10 @@ export function handleMainActionError(error: unknown): void {
}
}
} else if (error instanceof JobFailure) {
core.setFailed(String(error)) // No stack trace for JobFailure: these are known errors
core.setFailed(String(error))
if (error.stack) {
core.info(error.stack)
}
} else {
core.setFailed(String(error))
if (error instanceof Error && error.stack) {
@@ -34,6 +37,9 @@ export function handleMainActionError(error: unknown): void {
export function handlePostActionError(error: unknown): void {
if (error instanceof JobFailure) {
core.setFailed(String(error))
if (error.stack) {
core.info(error.stack)
}
} else {
core.warning(`Unhandled error in Gradle post-action - job will continue: ${error}`)
if (error instanceof Error && error.stack) {

View File

@@ -78,7 +78,7 @@ Note that this permission is never available for a workflow triggered from a rep
return mainWarning
}
function renderSummaryTable(results: BuildResult[]): string {
export function renderSummaryTable(results: BuildResult[]): string {
return `${renderDeprecations()}\n${renderBuildResults(results)}`
}
@@ -113,7 +113,7 @@ function renderBuildResults(results: BuildResult[]): string {
<th>Requested Tasks</th>
<th>Gradle Version</th>
<th>Build Outcome</th>
<th>Build Scan®</th>
<th>Build&nbsp;Scan®</th>
</tr>${results.map(result => renderBuildResultRow(result)).join('')}
</table>
`
@@ -134,23 +134,46 @@ function renderOutcome(result: BuildResult): string {
return result.buildFailed ? ':x:' : ':white_check_mark:'
}
function renderBuildScan(result: BuildResult): string {
if (result.buildScanFailed) {
return renderBuildScanBadge(
'PUBLISH_FAILED',
'orange',
'https://docs.gradle.com/develocity/gradle-plugin/#troubleshooting'
)
}
if (result.buildScanUri) {
return renderBuildScanBadge('PUBLISHED', '06A0CE', result.buildScanUri)
}
return renderBuildScanBadge('NOT_PUBLISHED', 'lightgrey', 'https://scans.gradle.com')
interface BadgeSpec {
text: string
alt: string
color: string
logo: boolean
targetUrl: string
}
function renderBuildScanBadge(outcomeText: string, outcomeColor: string, targetUrl: string): string {
const badgeUrl = `https://img.shields.io/badge/Build%20Scan%C2%AE-${outcomeText}-${outcomeColor}?logo=Gradle`
const badgeHtml = `<img src="${badgeUrl}" alt="Build Scan ${outcomeText}" />`
function renderBuildScan(result: BuildResult): string {
if (result.buildScanFailed) {
return renderBuildScanBadge({
text: 'Publish failed',
alt: 'Build Scan publish failed',
color: 'orange',
logo: false,
targetUrl: 'https://docs.gradle.com/develocity/gradle-plugin/#troubleshooting'
})
}
if (result.buildScanUri) {
return renderBuildScanBadge({
text: 'Build Scan®',
alt: 'Build Scan published',
color: '06A0CE',
logo: true,
targetUrl: result.buildScanUri
})
}
return renderBuildScanBadge({
text: 'Not published',
alt: 'Build Scan not published',
color: 'lightgrey',
logo: false,
targetUrl: 'https://scans.gradle.com'
})
}
function renderBuildScanBadge({text, alt, color, logo, targetUrl}: BadgeSpec): string {
const encodedText = encodeURIComponent(text)
const badgeUrl = `https://img.shields.io/badge/${encodedText}-${color}${logo ? '?logo=Gradle' : ''}`
const badgeHtml = `<img src="${badgeUrl}" alt="${alt}" />`
return `<a href="${targetUrl}" rel="nofollow" target="_blank">${badgeHtml}</a>`
}

View File

@@ -6,7 +6,7 @@ buildscript {
def pluginRepositoryUrl = getInputParam('gradle.plugin-repository.url') ?: 'https://plugins.gradle.org/m2'
def pluginRepositoryUsername = getInputParam('gradle.plugin-repository.username')
def pluginRepositoryPassword = getInputParam('gradle.plugin-repository.password')
def dependencyGraphPluginVersion = getInputParam('dependency-graph-plugin.version') ?: '1.3.0'
def dependencyGraphPluginVersion = getInputParam('dependency-graph-plugin.version') ?: '1.3.1'
logger.lifecycle("Resolving dependency graph plugin ${dependencyGraphPluginVersion} from plugin repository: ${pluginRepositoryUrl}")
repositories {

View File

@@ -12,7 +12,7 @@ if (gradleVersion < GradleVersion.version("5.2") ||
if (getVariable('GITHUB_DEPENDENCY_GRAPH_CONTINUE_ON_FAILURE') != "true") {
throw new GradleException("Dependency Graph is not supported for ${gradleVersion}. No dependency snapshot will be generated.")
}
println "::warning::Dependency Graph is not supported for ${gradleVersion}. No dependency snapshot will be generated."
logger.warn("::warning::Dependency Graph is not supported for ${gradleVersion}. No dependency snapshot will be generated.")
return
}
@@ -23,11 +23,11 @@ if (isTopLevelBuild) {
def reportFile = getUniqueReportFile(getVariable('GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR'))
if (reportFile == null) {
println "::warning::No dependency snapshot generated for step. Could not determine unique job correlator - specify GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR var for this step."
logger.warn("::warning::No dependency snapshot generated for step. Could not determine unique job correlator - specify GITHUB_DEPENDENCY_GRAPH_JOB_CORRELATOR var for this step.")
return
}
println "Generating dependency graph into '${reportFile}'"
logger.lifecycle("Generating dependency graph into '${reportFile}'")
}
apply from: 'gradle-actions.github-dependency-graph-gradle-plugin-apply.groovy'

View File

@@ -1,16 +1,20 @@
/*
* Initscript for injection of Develocity into Gradle builds.
* Version: v1.0
*/
import org.gradle.util.GradleVersion
// note that there is no mechanism to share code between the initscript{} block and the main script, so some logic is duplicated
// conditionally apply the Develocity plugin to the classpath so it can be applied to the build further down in this script
initscript {
// NOTE: there is no mechanism to share code between the initscript{} block and the main script, so some logic is duplicated
def isTopLevelBuild = !gradle.parent
if (!isTopLevelBuild) {
return
}
def getInputParam = { String name ->
def envVarName = name.toUpperCase().replace('.', '_').replace('-', '_')
def ENV_VAR_PREFIX = ''
def envVarName = ENV_VAR_PREFIX + name.toUpperCase().replace('.', '_').replace('-', '_')
return System.getProperty(name) ?: System.getenv(envVarName)
}
@@ -20,9 +24,9 @@ initscript {
return
}
// finish early if injection is disabled
def gradleInjectionEnabled = getInputParam("develocity.injection-enabled")
if (gradleInjectionEnabled != "true") {
// Plugin loading is only required for Develocity injection. Abort early if not enabled.
def develocityInjectionEnabled = Boolean.parseBoolean(getInputParam("develocity.injection-enabled"))
if (!develocityInjectionEnabled) {
return
}
@@ -75,29 +79,17 @@ initscript {
}
}
def BUILD_SCAN_PLUGIN_ID = 'com.gradle.build-scan'
def BUILD_SCAN_PLUGIN_CLASS = 'com.gradle.scan.plugin.BuildScanPlugin'
def GRADLE_ENTERPRISE_PLUGIN_ID = 'com.gradle.enterprise'
def GRADLE_ENTERPRISE_PLUGIN_CLASS = 'com.gradle.enterprise.gradleplugin.GradleEnterprisePlugin'
def DEVELOCITY_PLUGIN_ID = 'com.gradle.develocity'
def DEVELOCITY_PLUGIN_CLASS = 'com.gradle.develocity.agent.gradle.DevelocityPlugin'
def CI_AUTO_INJECTION_CUSTOM_VALUE_NAME = 'CI auto injection'
def CCUD_PLUGIN_ID = 'com.gradle.common-custom-user-data-gradle-plugin'
def CCUD_PLUGIN_CLASS = 'com.gradle.CommonCustomUserDataGradlePlugin'
static getInputParam(String name) {
def ENV_VAR_PREFIX = ''
def envVarName = ENV_VAR_PREFIX + name.toUpperCase().replace('.', '_').replace('-', '_')
return System.getProperty(name) ?: System.getenv(envVarName)
}
def isTopLevelBuild = !gradle.parent
if (!isTopLevelBuild) {
return
}
def getInputParam = { String name ->
def envVarName = name.toUpperCase().replace('.', '_').replace('-', '_')
return System.getProperty(name) ?: System.getenv(envVarName)
}
def requestedInitScriptName = getInputParam('develocity.injection.init-script-name')
def initScriptName = buildscript.sourceFile.name
if (requestedInitScriptName != initScriptName) {
@@ -105,205 +97,226 @@ if (requestedInitScriptName != initScriptName) {
return
}
// finish early if injection is disabled
def gradleInjectionEnabled = getInputParam("develocity.injection-enabled")
if (gradleInjectionEnabled != "true") {
return
def develocityInjectionEnabled = Boolean.parseBoolean(getInputParam("develocity.injection-enabled"))
if (develocityInjectionEnabled) {
enableDevelocityInjection()
}
def develocityUrl = getInputParam('develocity.url')
def develocityAllowUntrustedServer = Boolean.parseBoolean(getInputParam('develocity.allow-untrusted-server'))
def develocityEnforceUrl = Boolean.parseBoolean(getInputParam('develocity.enforce-url'))
def buildScanUploadInBackground = Boolean.parseBoolean(getInputParam('develocity.build-scan.upload-in-background'))
def develocityCaptureFileFingerprints = getInputParam('develocity.capture-file-fingerprints') ? Boolean.parseBoolean(getInputParam('develocity.capture-file-fingerprints')) : true
def develocityPluginVersion = getInputParam('develocity.plugin.version')
def ccudPluginVersion = getInputParam('develocity.ccud-plugin.version')
def buildScanTermsOfUseUrl = getInputParam('develocity.terms-of-use.url')
def buildScanTermsOfUseAgree = getInputParam('develocity.terms-of-use.agree')
def ciAutoInjectionCustomValueValue = getInputParam('develocity.auto-injection.custom-value')
// To enable build-scan capture, a `captureBuildScanLink(String)` method must be added to `BuildScanCollector`.
def buildScanCollector = new BuildScanCollector()
def buildScanCaptureEnabled = buildScanCollector.metaClass.respondsTo(buildScanCollector, 'captureBuildScanLink', String)
if (buildScanCaptureEnabled) {
enableBuildScanLinkCapture(buildScanCollector)
}
def atLeastGradle5 = GradleVersion.current() >= GradleVersion.version('5.0')
def atLeastGradle4 = GradleVersion.current() >= GradleVersion.version('4.0')
def shouldApplyDevelocityPlugin = atLeastGradle5 && develocityPluginVersion && isAtLeast(develocityPluginVersion, '3.17')
void enableDevelocityInjection() {
def BUILD_SCAN_PLUGIN_ID = 'com.gradle.build-scan'
def BUILD_SCAN_PLUGIN_CLASS = 'com.gradle.scan.plugin.BuildScanPlugin'
def dvOrGe = { def dvValue, def geValue ->
if (shouldApplyDevelocityPlugin) {
return dvValue instanceof Closure<?> ? dvValue() : dvValue
def GRADLE_ENTERPRISE_PLUGIN_ID = 'com.gradle.enterprise'
def GRADLE_ENTERPRISE_PLUGIN_CLASS = 'com.gradle.enterprise.gradleplugin.GradleEnterprisePlugin'
def DEVELOCITY_PLUGIN_ID = 'com.gradle.develocity'
def DEVELOCITY_PLUGIN_CLASS = 'com.gradle.develocity.agent.gradle.DevelocityPlugin'
def CI_AUTO_INJECTION_CUSTOM_VALUE_NAME = 'CI auto injection'
def CCUD_PLUGIN_ID = 'com.gradle.common-custom-user-data-gradle-plugin'
def CCUD_PLUGIN_CLASS = 'com.gradle.CommonCustomUserDataGradlePlugin'
def develocityUrl = getInputParam('develocity.url')
def develocityAllowUntrustedServer = Boolean.parseBoolean(getInputParam('develocity.allow-untrusted-server'))
def develocityEnforceUrl = Boolean.parseBoolean(getInputParam('develocity.enforce-url'))
def buildScanUploadInBackground = Boolean.parseBoolean(getInputParam('develocity.build-scan.upload-in-background'))
def develocityCaptureFileFingerprints = getInputParam('develocity.capture-file-fingerprints') ? Boolean.parseBoolean(getInputParam('develocity.capture-file-fingerprints')) : true
def develocityPluginVersion = getInputParam('develocity.plugin.version')
def ccudPluginVersion = getInputParam('develocity.ccud-plugin.version')
def buildScanTermsOfUseUrl = getInputParam('develocity.terms-of-use.url')
def buildScanTermsOfUseAgree = getInputParam('develocity.terms-of-use.agree')
def ciAutoInjectionCustomValueValue = getInputParam('develocity.auto-injection.custom-value')
def atLeastGradle5 = GradleVersion.current() >= GradleVersion.version('5.0')
def atLeastGradle4 = GradleVersion.current() >= GradleVersion.version('4.0')
def shouldApplyDevelocityPlugin = atLeastGradle5 && develocityPluginVersion && isAtLeast(develocityPluginVersion, '3.17')
def dvOrGe = { def dvValue, def geValue ->
if (shouldApplyDevelocityPlugin) {
return dvValue instanceof Closure<?> ? dvValue() : dvValue
}
return geValue instanceof Closure<?> ? geValue() : geValue
}
return geValue instanceof Closure<?> ? geValue() : geValue
}
// finish early if configuration parameters passed in via system properties are not valid/supported
if (ccudPluginVersion && isNotAtLeast(ccudPluginVersion, '1.7')) {
logger.warn("Common Custom User Data Gradle plugin must be at least 1.7. Configured version is $ccudPluginVersion.")
return
}
// finish early if configuration parameters passed in via system properties are not valid/supported
if (ccudPluginVersion && isNotAtLeast(ccudPluginVersion, '1.7')) {
logger.warn("Common Custom User Data Gradle plugin must be at least 1.7. Configured version is $ccudPluginVersion.")
return
}
// register buildScanPublished listener and optionally apply the Develocity plugin
if (GradleVersion.current() < GradleVersion.version('6.0')) {
rootProject {
buildscript.configurations.getByName("classpath").incoming.afterResolve { ResolvableDependencies incoming ->
def resolutionResult = incoming.resolutionResult
// Conditionally apply and configure the Develocity plugin
if (GradleVersion.current() < GradleVersion.version('6.0')) {
rootProject {
buildscript.configurations.getByName("classpath").incoming.afterResolve { ResolvableDependencies incoming ->
def resolutionResult = incoming.resolutionResult
if (develocityPluginVersion) {
def scanPluginComponent = resolutionResult.allComponents.find {
it.moduleVersion.with { group == "com.gradle" && ['build-scan-plugin', 'gradle-enterprise-gradle-plugin', 'develocity-gradle-plugin'].contains(name) }
}
if (!scanPluginComponent) {
def pluginClass = dvOrGe(DEVELOCITY_PLUGIN_CLASS, BUILD_SCAN_PLUGIN_CLASS)
logger.lifecycle("Applying $pluginClass via init script")
applyPluginExternally(pluginManager, pluginClass)
def rootExtension = dvOrGe(
if (develocityPluginVersion) {
def scanPluginComponent = resolutionResult.allComponents.find {
it.moduleVersion.with { group == "com.gradle" && ['build-scan-plugin', 'gradle-enterprise-gradle-plugin', 'develocity-gradle-plugin'].contains(name) }
}
if (!scanPluginComponent) {
def pluginClass = dvOrGe(DEVELOCITY_PLUGIN_CLASS, BUILD_SCAN_PLUGIN_CLASS)
logger.lifecycle("Applying $pluginClass via init script")
applyPluginExternally(pluginManager, pluginClass)
def rootExtension = dvOrGe(
{ develocity },
{ buildScan }
)
def buildScanExtension = dvOrGe(
)
def buildScanExtension = dvOrGe(
{ rootExtension.buildScan },
{ rootExtension }
)
if (develocityUrl) {
logger.lifecycle("Connection to Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints")
rootExtension.server = develocityUrl
rootExtension.allowUntrustedServer = develocityAllowUntrustedServer
}
if (!shouldApplyDevelocityPlugin) {
// Develocity plugin publishes scans by default
buildScanExtension.publishAlways()
}
// uploadInBackground not available for build-scan-plugin 1.16
if (buildScanExtension.metaClass.respondsTo(buildScanExtension, 'setUploadInBackground', Boolean)) buildScanExtension.uploadInBackground = buildScanUploadInBackground
buildScanExtension.value CI_AUTO_INJECTION_CUSTOM_VALUE_NAME, ciAutoInjectionCustomValueValue
if (isAtLeast(develocityPluginVersion, '2.1') && atLeastGradle5) {
logger.lifecycle("Setting captureFileFingerprints: $develocityCaptureFileFingerprints")
if (isAtLeast(develocityPluginVersion, '3.17')) {
buildScanExtension.capture.fileFingerprints.set(develocityCaptureFileFingerprints)
} else if (isAtLeast(develocityPluginVersion, '3.7')) {
buildScanExtension.capture.taskInputFiles = develocityCaptureFileFingerprints
} else {
buildScanExtension.captureTaskInputFiles = develocityCaptureFileFingerprints
)
if (develocityUrl) {
logger.lifecycle("Connection to Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints")
rootExtension.server = develocityUrl
rootExtension.allowUntrustedServer = develocityAllowUntrustedServer
}
if (!shouldApplyDevelocityPlugin) {
// Develocity plugin publishes scans by default
buildScanExtension.publishAlways()
}
// uploadInBackground not available for build-scan-plugin 1.16
if (buildScanExtension.metaClass.respondsTo(buildScanExtension, 'setUploadInBackground', Boolean)) buildScanExtension.uploadInBackground = buildScanUploadInBackground
buildScanExtension.value CI_AUTO_INJECTION_CUSTOM_VALUE_NAME, ciAutoInjectionCustomValueValue
if (isAtLeast(develocityPluginVersion, '2.1') && atLeastGradle5) {
logger.lifecycle("Setting captureFileFingerprints: $develocityCaptureFileFingerprints")
if (isAtLeast(develocityPluginVersion, '3.17')) {
buildScanExtension.capture.fileFingerprints.set(develocityCaptureFileFingerprints)
} else if (isAtLeast(develocityPluginVersion, '3.7')) {
buildScanExtension.capture.taskInputFiles = develocityCaptureFileFingerprints
} else {
buildScanExtension.captureTaskInputFiles = develocityCaptureFileFingerprints
}
}
}
if (develocityUrl && develocityEnforceUrl) {
logger.lifecycle("Enforcing Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints")
}
pluginManager.withPlugin(BUILD_SCAN_PLUGIN_ID) {
// Only execute if develocity plugin isn't applied.
if (gradle.rootProject.extensions.findByName("develocity")) return
afterEvaluate {
if (develocityUrl && develocityEnforceUrl) {
buildScan.server = develocityUrl
buildScan.allowUntrustedServer = develocityAllowUntrustedServer
}
}
if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
buildScan.termsOfServiceUrl = buildScanTermsOfUseUrl
buildScan.termsOfServiceAgree = buildScanTermsOfUseAgree
}
}
pluginManager.withPlugin(DEVELOCITY_PLUGIN_ID) {
afterEvaluate {
if (develocityUrl && develocityEnforceUrl) {
develocity.server = develocityUrl
develocity.allowUntrustedServer = develocityAllowUntrustedServer
}
}
if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
develocity.buildScan.termsOfUseUrl = buildScanTermsOfUseUrl
develocity.buildScan.termsOfUseAgree = buildScanTermsOfUseAgree
}
}
}
if (ccudPluginVersion && atLeastGradle4) {
def ccudPluginComponent = resolutionResult.allComponents.find {
it.moduleVersion.with { group == "com.gradle" && name == "common-custom-user-data-gradle-plugin" }
}
if (!ccudPluginComponent) {
logger.lifecycle("Applying $CCUD_PLUGIN_CLASS via init script")
pluginManager.apply(initscript.classLoader.loadClass(CCUD_PLUGIN_CLASS))
}
}
}
}
} else {
gradle.settingsEvaluated { settings ->
if (develocityPluginVersion) {
if (!settings.pluginManager.hasPlugin(GRADLE_ENTERPRISE_PLUGIN_ID) && !settings.pluginManager.hasPlugin(DEVELOCITY_PLUGIN_ID)) {
def pluginClass = dvOrGe(DEVELOCITY_PLUGIN_CLASS, GRADLE_ENTERPRISE_PLUGIN_CLASS)
logger.lifecycle("Applying $pluginClass via init script")
applyPluginExternally(settings.pluginManager, pluginClass)
if (develocityUrl) {
logger.lifecycle("Connection to Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints")
eachDevelocitySettingsExtension(settings) { ext ->
ext.server = develocityUrl
ext.allowUntrustedServer = develocityAllowUntrustedServer
}
}
eachDevelocitySettingsExtension(settings) { ext ->
ext.buildScan.uploadInBackground = buildScanUploadInBackground
ext.buildScan.value CI_AUTO_INJECTION_CUSTOM_VALUE_NAME, ciAutoInjectionCustomValueValue
}
eachDevelocitySettingsExtension(settings,
{ develocity ->
logger.lifecycle("Setting captureFileFingerprints: $develocityCaptureFileFingerprints")
develocity.buildScan.capture.fileFingerprints = develocityCaptureFileFingerprints
},
{ gradleEnterprise ->
gradleEnterprise.buildScan.publishAlways()
if (isAtLeast(develocityPluginVersion, '2.1')) {
logger.lifecycle("Setting captureFileFingerprints: $develocityCaptureFileFingerprints")
if (isAtLeast(develocityPluginVersion, '3.7')) {
gradleEnterprise.buildScan.capture.taskInputFiles = develocityCaptureFileFingerprints
} else {
gradleEnterprise.buildScan.captureTaskInputFiles = develocityCaptureFileFingerprints
}
}
}
)
}
if (develocityUrl && develocityEnforceUrl) {
logger.lifecycle("Enforcing Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints")
}
pluginManager.withPlugin(BUILD_SCAN_PLUGIN_ID) {
// Only execute if develocity plugin isn't applied.
if (gradle.rootProject.extensions.findByName("develocity")) return
afterEvaluate {
if (develocityUrl && develocityEnforceUrl) {
buildScan.server = develocityUrl
buildScan.allowUntrustedServer = develocityAllowUntrustedServer
}
}
if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
buildScan.termsOfServiceUrl = buildScanTermsOfUseUrl
buildScan.termsOfServiceAgree = buildScanTermsOfUseAgree
}
}
pluginManager.withPlugin(DEVELOCITY_PLUGIN_ID) {
afterEvaluate {
eachDevelocitySettingsExtension(settings,
{ develocity ->
if (develocityUrl && develocityEnforceUrl) {
develocity.server = develocityUrl
develocity.allowUntrustedServer = develocityAllowUntrustedServer
}
}
if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
develocity.buildScan.termsOfUseUrl = buildScanTermsOfUseUrl
develocity.buildScan.termsOfUseAgree = buildScanTermsOfUseAgree
}
}
}
if (ccudPluginVersion && atLeastGradle4) {
def ccudPluginComponent = resolutionResult.allComponents.find {
it.moduleVersion.with { group == "com.gradle" && name == "common-custom-user-data-gradle-plugin" }
}
if (!ccudPluginComponent) {
logger.lifecycle("Applying $CCUD_PLUGIN_CLASS via init script")
pluginManager.apply(initscript.classLoader.loadClass(CCUD_PLUGIN_CLASS))
}
}
}
}
} else {
gradle.settingsEvaluated { settings ->
if (develocityPluginVersion) {
if (!settings.pluginManager.hasPlugin(GRADLE_ENTERPRISE_PLUGIN_ID) && !settings.pluginManager.hasPlugin(DEVELOCITY_PLUGIN_ID)) {
def pluginClass = dvOrGe(DEVELOCITY_PLUGIN_CLASS, GRADLE_ENTERPRISE_PLUGIN_CLASS)
logger.lifecycle("Applying $pluginClass via init script")
applyPluginExternally(settings.pluginManager, pluginClass)
if (develocityUrl) {
logger.lifecycle("Connection to Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints")
eachDevelocitySettingsExtension(settings) { ext ->
ext.server = develocityUrl
ext.allowUntrustedServer = develocityAllowUntrustedServer
}
}
eachDevelocitySettingsExtension(settings) { ext ->
ext.buildScan.uploadInBackground = buildScanUploadInBackground
ext.buildScan.value CI_AUTO_INJECTION_CUSTOM_VALUE_NAME, ciAutoInjectionCustomValueValue
}
eachDevelocitySettingsExtension(settings,
{ develocity ->
logger.lifecycle("Setting captureFileFingerprints: $develocityCaptureFileFingerprints")
develocity.buildScan.capture.fileFingerprints = develocityCaptureFileFingerprints
if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
develocity.buildScan.termsOfUseUrl = buildScanTermsOfUseUrl
develocity.buildScan.termsOfUseAgree = buildScanTermsOfUseAgree
}
},
{ gradleEnterprise ->
gradleEnterprise.buildScan.publishAlways()
if (isAtLeast(develocityPluginVersion, '2.1')) {
logger.lifecycle("Setting captureFileFingerprints: $develocityCaptureFileFingerprints")
if (isAtLeast(develocityPluginVersion, '3.7')) {
gradleEnterprise.buildScan.capture.taskInputFiles = develocityCaptureFileFingerprints
} else {
gradleEnterprise.buildScan.captureTaskInputFiles = develocityCaptureFileFingerprints
}
if (develocityUrl && develocityEnforceUrl) {
gradleEnterprise.server = develocityUrl
gradleEnterprise.allowUntrustedServer = develocityAllowUntrustedServer
}
if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
gradleEnterprise.buildScan.termsOfServiceUrl = buildScanTermsOfUseUrl
gradleEnterprise.buildScan.termsOfServiceAgree = buildScanTermsOfUseAgree
}
}
)
}
if (develocityUrl && develocityEnforceUrl) {
logger.lifecycle("Enforcing Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints")
}
eachDevelocitySettingsExtension(settings,
{ develocity ->
if (develocityUrl && develocityEnforceUrl) {
develocity.server = develocityUrl
develocity.allowUntrustedServer = develocityAllowUntrustedServer
}
if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
develocity.buildScan.termsOfUseUrl = buildScanTermsOfUseUrl
develocity.buildScan.termsOfUseAgree = buildScanTermsOfUseAgree
}
},
{ gradleEnterprise ->
if (develocityUrl && develocityEnforceUrl) {
gradleEnterprise.server = develocityUrl
gradleEnterprise.allowUntrustedServer = develocityAllowUntrustedServer
}
if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
gradleEnterprise.buildScan.termsOfServiceUrl = buildScanTermsOfUseUrl
gradleEnterprise.buildScan.termsOfServiceAgree = buildScanTermsOfUseAgree
}
if (ccudPluginVersion) {
if (!settings.pluginManager.hasPlugin(CCUD_PLUGIN_ID)) {
logger.lifecycle("Applying $CCUD_PLUGIN_CLASS via init script")
settings.pluginManager.apply(initscript.classLoader.loadClass(CCUD_PLUGIN_CLASS))
}
)
}
if (ccudPluginVersion) {
if (!settings.pluginManager.hasPlugin(CCUD_PLUGIN_ID)) {
logger.lifecycle("Applying $CCUD_PLUGIN_CLASS via init script")
settings.pluginManager.apply(initscript.classLoader.loadClass(CCUD_PLUGIN_CLASS))
}
}
}
@@ -360,4 +373,42 @@ static boolean isAtLeast(String versionUnderTest, String referenceVersion) {
static boolean isNotAtLeast(String versionUnderTest, String referenceVersion) {
!isAtLeast(versionUnderTest, referenceVersion)
}
}
void enableBuildScanLinkCapture(BuildScanCollector collector) {
def BUILD_SCAN_PLUGIN_ID = 'com.gradle.build-scan'
def DEVELOCITY_PLUGIN_ID = 'com.gradle.develocity'
// Conditionally apply and configure the Develocity plugin
if (GradleVersion.current() < GradleVersion.version('6.0')) {
rootProject {
pluginManager.withPlugin(BUILD_SCAN_PLUGIN_ID) {
// Only execute if develocity plugin isn't applied.
if (gradle.rootProject.extensions.findByName("develocity")) return
buildScanPublishedAction(buildScan, collector)
}
pluginManager.withPlugin(DEVELOCITY_PLUGIN_ID) {
buildScanPublishedAction(develocity.buildScan, collector)
}
}
} else {
gradle.settingsEvaluated { settings ->
eachDevelocitySettingsExtension(settings) { ext ->
buildScanPublishedAction(ext.buildScan, collector)
}
}
}
}
// Action will only be called if a `BuildScanCollector.captureBuildScanLink` method is present.
// Add `void captureBuildScanLink(String) {}` to the `BuildScanCollector` class to respond to buildScanPublished events
static buildScanPublishedAction(def buildScanExtension, BuildScanCollector collector) {
if (buildScanExtension.metaClass.respondsTo(buildScanExtension, 'buildScanPublished', Action)) {
buildScanExtension.buildScanPublished { scan ->
collector.captureBuildScanLink(scan.buildScanUri.toString())
}
}
}
class BuildScanCollector {}

View File

@@ -4,7 +4,7 @@ import * as path from 'path'
import * as os from 'os'
import * as caches from './caching/caches'
import * as jobSummary from './job-summary'
import * as buildScan from './build-scan'
import * as buildScan from './develocity/build-scan'
import {loadBuildResults, markBuildResultsProcessed} from './build-results'
import {CacheListener, generateCachingReport} from './caching/cache-reporting'
@@ -41,7 +41,7 @@ export async function setup(cacheConfig: CacheConfig, buildScanConfig: BuildScan
core.saveState(CACHE_LISTENER, cacheListener.stringify())
buildScan.setup(buildScanConfig)
await buildScan.setup(buildScanConfig)
return true
}

View File

@@ -1,4 +1,28 @@
[
{
"version": "8.9",
"checksum": "498495120a03b9a6ab5d155f5de3c8f0d986a449153702fb80fc80e134484f17"
},
{
"version": "8.9-rc-2",
"checksum": "498495120a03b9a6ab5d155f5de3c8f0d986a449153702fb80fc80e134484f17"
},
{
"version": "8.9-rc-1",
"checksum": "498495120a03b9a6ab5d155f5de3c8f0d986a449153702fb80fc80e134484f17"
},
{
"version": "8.8",
"checksum": "cb0da6751c2b753a16ac168bb354870ebb1e162e9083f116729cec9c781156b8"
},
{
"version": "8.8-rc-2",
"checksum": "cb0da6751c2b753a16ac168bb354870ebb1e162e9083f116729cec9c781156b8"
},
{
"version": "8.8-rc-1",
"checksum": "cb0da6751c2b753a16ac168bb354870ebb1e162e9083f116729cec9c781156b8"
},
{
"version": "8.7",
"checksum": "cb0da6751c2b753a16ac168bb354870ebb1e162e9083f116729cec9c781156b8"

View File

@@ -20,7 +20,7 @@ dependencies {
testImplementation ('io.ratpack:ratpack-groovy-test:1.9.0') {
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
}
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.17.0'
testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.17.2'
}
test {

View File

@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

View File

@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################

View File

@@ -1,6 +1,6 @@
plugins {
id "com.gradle.develocity" version "3.17.1"
id "com.gradle.common-custom-user-data-gradle-plugin" version "2.0"
id "com.gradle.develocity" version "3.17.5"
id "com.gradle.common-custom-user-data-gradle-plugin" version "2.0.1"
}
develocity {

View File

@@ -16,8 +16,8 @@ import java.nio.file.Files
import java.util.zip.GZIPOutputStream
class BaseInitScriptTest extends Specification {
static final String DEVELOCITY_PLUGIN_VERSION = '3.17'
static final String CCUD_PLUGIN_VERSION = '2.0'
static final String DEVELOCITY_PLUGIN_VERSION = '3.17.5'
static final String CCUD_PLUGIN_VERSION = '2.0.1'
static final TestGradleVersion GRADLE_3_X = new TestGradleVersion(GradleVersion.version('3.5.1'), 7, 9)
static final TestGradleVersion GRADLE_4_X = new TestGradleVersion(GradleVersion.version('4.10.3'), 7, 10)
@@ -27,7 +27,7 @@ class BaseInitScriptTest extends Specification {
static final TestGradleVersion GRADLE_7_1 = new TestGradleVersion(GradleVersion.version('7.6.2'), 8, 19)
static final TestGradleVersion GRADLE_7_X = new TestGradleVersion(GradleVersion.version('7.6.2'), 8, 19)
static final TestGradleVersion GRADLE_8_0 = new TestGradleVersion(GradleVersion.version('8.0.2'), 8, 19)
static final TestGradleVersion GRADLE_8_X = new TestGradleVersion(GradleVersion.version('8.5'), 8, 19)
static final TestGradleVersion GRADLE_8_X = new TestGradleVersion(GradleVersion.version('8.9'), 8, 22)
static final List<TestGradleVersion> ALL_VERSIONS = [
GRADLE_3_X, // First version where TestKit supports environment variables

View File

@@ -190,7 +190,7 @@ class TestBuildResultRecorder extends BaseInitScriptTest {
when:
settingsFile.text = """
plugins {
id 'com.gradle.develocity' version '3.17' apply(false)
id 'com.gradle.develocity' version '3.17.5' apply(false)
}
gradle.settingsEvaluated {
apply plugin: 'com.gradle.develocity'

View File

@@ -146,7 +146,7 @@ class TestDependencyGraph extends BaseInitScriptTest {
then:
assert reportFile.exists()
assert result.output.contains("Resolving dependency graph plugin 1.3.0 from plugin repository: https://plugins.grdev.net/m2")
assert result.output.find("Resolving dependency graph plugin [\\d\\.]+ from plugin repository: https://plugins.grdev.net/m2")
where:
testGradleVersion << DEPENDENCY_GRAPH_VERSIONS
@@ -170,7 +170,7 @@ class TestDependencyGraph extends BaseInitScriptTest {
then:
assert reportFile.exists()
assert result.output.contains("Resolving dependency graph plugin 1.3.0 from plugin repository: https://plugins.grdev.net/m2")
assert result.output.find("Resolving dependency graph plugin [\\d\\.]+ from plugin repository: https://plugins.grdev.net/m2")
assert result.output.contains("Applying credentials for plugin repository: https://plugins.grdev.net/m2")
where:

View File

@@ -1,4 +1,6 @@
import * as exec from '@actions/exec'
import * as core from '@actions/core'
import * as glob from '@actions/glob'
import fs from 'fs'
import path from 'path'
import {CacheCleaner} from '../../src/caching/cache-cleaner'
@@ -13,7 +15,7 @@ test('will cleanup unused dependency jars and build-cache entries', async () =>
await runGradleBuild(projectRoot, 'build', '3.1')
await cacheCleaner.prepare()
const timestamp = await cacheCleaner.prepare()
await runGradleBuild(projectRoot, 'build', '3.1.1')
@@ -23,13 +25,13 @@ test('will cleanup unused dependency jars and build-cache entries', async () =>
expect(fs.existsSync(commonsMath31)).toBe(true)
expect(fs.existsSync(commonsMath311)).toBe(true)
expect(fs.readdirSync(buildCacheDir).length).toBe(6)
expect(fs.readdirSync(buildCacheDir).length).toBe(4) // gc.properties, build-cache-1.lock, and 2 task entries
await cacheCleaner.forceCleanup()
await cacheCleaner.forceCleanupFilesOlderThan(timestamp)
expect(fs.existsSync(commonsMath31)).toBe(false)
expect(fs.existsSync(commonsMath311)).toBe(true)
expect(fs.readdirSync(buildCacheDir).length).toBe(5)
expect(fs.readdirSync(buildCacheDir).length).toBe(3) // 1 task entry has been cleaned up
})
test('will cleanup unused gradle versions', async () => {
@@ -41,25 +43,39 @@ test('will cleanup unused gradle versions', async () => {
// Initialize HOME with 2 different Gradle versions
await runGradleWrapperBuild(projectRoot, 'build')
await runGradleBuild(projectRoot, 'build')
await cacheCleaner.prepare()
const timestamp = await cacheCleaner.prepare()
// Run with only one of these versions
await runGradleBuild(projectRoot, 'build')
const gradle802 = path.resolve(gradleUserHome, "caches/8.0.2")
const transforms3 = path.resolve(gradleUserHome, "caches/transforms-3")
const metadata100 = path.resolve(gradleUserHome, "caches/modules-2/metadata-2.100")
const wrapper802 = path.resolve(gradleUserHome, "wrapper/dists/gradle-8.0.2-bin")
const gradleCurrent = path.resolve(gradleUserHome, "caches/8.7")
const gradleCurrent = path.resolve(gradleUserHome, "caches/8.9")
const metadataCurrent = path.resolve(gradleUserHome, "caches/modules-2/metadata-2.106")
expect(fs.existsSync(gradle802)).toBe(true)
expect(fs.existsSync(transforms3)).toBe(true)
expect(fs.existsSync(metadata100)).toBe(true)
expect(fs.existsSync(wrapper802)).toBe(true)
expect(fs.existsSync(gradleCurrent)).toBe(true)
await cacheCleaner.forceCleanup()
expect(fs.existsSync(gradleCurrent)).toBe(true)
expect(fs.existsSync(metadataCurrent)).toBe(true)
// The wrapper won't be removed if it was recently downloaded. Age it.
setUtimes(wrapper802, new Date(Date.now() - 48 * 60 * 60 * 1000))
await cacheCleaner.forceCleanupFilesOlderThan(timestamp)
expect(fs.existsSync(gradle802)).toBe(false)
expect(fs.existsSync(transforms3)).toBe(false)
expect(fs.existsSync(metadata100)).toBe(false)
expect(fs.existsSync(wrapper802)).toBe(false)
expect(fs.existsSync(gradleCurrent)).toBe(true)
expect(fs.existsSync(metadataCurrent)).toBe(true)
})
async function runGradleBuild(projectRoot: string, args: string, version: string = '3.1'): Promise<void> {
@@ -85,3 +101,9 @@ function prepareTestProject(): string {
return projectRoot
}
async function setUtimes(pattern: string, timestamp: Date): Promise<void> {
const globber = await glob.create(pattern)
for await (const file of globber.globGenerator()) {
fs.utimesSync(file, timestamp, timestamp)
}
}

View File

@@ -0,0 +1,177 @@
import { BuildResult } from '../../src/build-results'
import { renderSummaryTable } from '../../src/job-summary'
import dedent from 'dedent'
const successfulHelpBuild: BuildResult = {
rootProjectName: 'root',
rootProjectDir: '/',
requestedTasks: 'help',
gradleVersion: '8.0',
gradleHomeDir: '/opt/gradle',
buildFailed: false,
buildScanUri: 'https://scans.gradle.com/s/abc123',
buildScanFailed: false
}
const failedHelpBuild: BuildResult = {
...successfulHelpBuild,
buildFailed: true
}
const longArgsBuild: BuildResult = {
...successfulHelpBuild,
requestedTasks: 'check publishMyLongNamePluginPublicationToMavenCentral publishMyLongNamePluginPublicationToPluginPortal',
}
const scanPublishDisabledBuild: BuildResult = {
...successfulHelpBuild,
buildScanUri: '',
buildScanFailed: false,
}
const scanPublishFailedBuild: BuildResult = {
...successfulHelpBuild,
buildScanUri: '',
buildScanFailed: true,
}
describe('renderSummaryTable', () => {
describe('renders', () => {
it('successful build', () => {
const table = renderSummaryTable([successfulHelpBuild])
expect(table.trim()).toBe(dedent`
<table>
<tr>
<th>Gradle Root Project</th>
<th>Requested Tasks</th>
<th>Gradle Version</th>
<th>Build Outcome</th>
<th>Build&nbsp;Scan®</th>
</tr>
<tr>
<td>root</td>
<td>help</td>
<td align='center'>8.0</td>
<td align='center'>:white_check_mark:</td>
<td><a href="https://scans.gradle.com/s/abc123" rel="nofollow" target="_blank"><img src="https://img.shields.io/badge/Build%20Scan%C2%AE-06A0CE?logo=Gradle" alt="Build Scan published" /></a></td>
</tr>
</table>
`);
})
it('failed build', () => {
const table = renderSummaryTable([failedHelpBuild])
expect(table.trim()).toBe(dedent`
<table>
<tr>
<th>Gradle Root Project</th>
<th>Requested Tasks</th>
<th>Gradle Version</th>
<th>Build Outcome</th>
<th>Build&nbsp;Scan®</th>
</tr>
<tr>
<td>root</td>
<td>help</td>
<td align='center'>8.0</td>
<td align='center'>:x:</td>
<td><a href="https://scans.gradle.com/s/abc123" rel="nofollow" target="_blank"><img src="https://img.shields.io/badge/Build%20Scan%C2%AE-06A0CE?logo=Gradle" alt="Build Scan published" /></a></td>
</tr>
</table>
`);
})
describe('when build scan', () => {
it('publishing disabled', () => {
const table = renderSummaryTable([scanPublishDisabledBuild])
expect(table.trim()).toBe(dedent`
<table>
<tr>
<th>Gradle Root Project</th>
<th>Requested Tasks</th>
<th>Gradle Version</th>
<th>Build Outcome</th>
<th>Build&nbsp;Scan®</th>
</tr>
<tr>
<td>root</td>
<td>help</td>
<td align='center'>8.0</td>
<td align='center'>:white_check_mark:</td>
<td><a href="https://scans.gradle.com" rel="nofollow" target="_blank"><img src="https://img.shields.io/badge/Not%20published-lightgrey" alt="Build Scan not published" /></a></td>
</tr>
</table>
`);
})
it('publishing failed', () => {
const table = renderSummaryTable([scanPublishFailedBuild])
expect(table.trim()).toBe(dedent`
<table>
<tr>
<th>Gradle Root Project</th>
<th>Requested Tasks</th>
<th>Gradle Version</th>
<th>Build Outcome</th>
<th>Build&nbsp;Scan®</th>
</tr>
<tr>
<td>root</td>
<td>help</td>
<td align='center'>8.0</td>
<td align='center'>:white_check_mark:</td>
<td><a href="https://docs.gradle.com/develocity/gradle-plugin/#troubleshooting" rel="nofollow" target="_blank"><img src="https://img.shields.io/badge/Publish%20failed-orange" alt="Build Scan publish failed" /></a></td>
</tr>
</table>
`);
})
})
it('multiple builds', () => {
const table = renderSummaryTable([successfulHelpBuild, failedHelpBuild])
expect(table.trim()).toBe(dedent`
<table>
<tr>
<th>Gradle Root Project</th>
<th>Requested Tasks</th>
<th>Gradle Version</th>
<th>Build Outcome</th>
<th>Build&nbsp;Scan®</th>
</tr>
<tr>
<td>root</td>
<td>help</td>
<td align='center'>8.0</td>
<td align='center'>:white_check_mark:</td>
<td><a href="https://scans.gradle.com/s/abc123" rel="nofollow" target="_blank"><img src="https://img.shields.io/badge/Build%20Scan%C2%AE-06A0CE?logo=Gradle" alt="Build Scan published" /></a></td>
</tr>
<tr>
<td>root</td>
<td>help</td>
<td align='center'>8.0</td>
<td align='center'>:x:</td>
<td><a href="https://scans.gradle.com/s/abc123" rel="nofollow" target="_blank"><img src="https://img.shields.io/badge/Build%20Scan%C2%AE-06A0CE?logo=Gradle" alt="Build Scan published" /></a></td>
</tr>
</table>
`);
})
it('truncating long requested tasks', () => {
const table = renderSummaryTable([longArgsBuild])
expect(table.trim()).toBe(dedent`
<table>
<tr>
<th>Gradle Root Project</th>
<th>Requested Tasks</th>
<th>Gradle Version</th>
<th>Build Outcome</th>
<th>Build&nbsp;Scan®</th>
</tr>
<tr>
<td>root</td>
<td><div title='check publishMyLongNamePluginPublicationToMavenCentral publishMyLongNamePluginPublicationToPluginPortal'>check publishMyLongNamePluginPublicationToMavenCentral publ…</div></td>
<td align='center'>8.0</td>
<td align='center'>:white_check_mark:</td>
<td><a href="https://scans.gradle.com/s/abc123" rel="nofollow" target="_blank"><img src="https://img.shields.io/badge/Build%20Scan%C2%AE-06A0CE?logo=Gradle" alt="Build Scan published" /></a></td>
</tr>
</table>
`);
})
})
})

View File

@@ -0,0 +1,117 @@
import {DevelocityAccessCredentials, getToken} from "../../src/develocity/short-lived-token";
import nock from "nock";
describe('short lived tokens', () => {
it('parse valid access key should return an object', async () => {
let develocityAccessCredentials = DevelocityAccessCredentials.parse('some-host.local=key1;host2=key2');
expect(develocityAccessCredentials).toStrictEqual(DevelocityAccessCredentials.of([
{hostname: 'some-host.local', key: 'key1'},
{hostname: 'host2', key: 'key2'}])
)
})
it('parse wrong access key should return null', async () => {
let develocityAccessCredentials = DevelocityAccessCredentials.parse('random;foo');
expect(develocityAccessCredentials).toBeNull()
})
it('parse empty access key should return null', async () => {
let develocityAccessCredentials = DevelocityAccessCredentials.parse('');
expect(develocityAccessCredentials).toBeNull()
})
it('access key as raw string', async () => {
let develocityAccessCredentials = DevelocityAccessCredentials.parse('host1=key1;host2=key2');
expect(develocityAccessCredentials?.raw()).toBe('host1=key1;host2=key2')
})
it('get short lived token fails when cannot connect', async () => {
nock('http://localhost:3333')
.post('/api/auth/token')
.times(3)
.replyWithError({
message: 'connect ECONNREFUSED 127.0.0.1:3333',
code: 'ECONNREFUSED'
})
await expect(getToken('localhost=key0', ''))
.resolves
.toBeNull()
})
it('get short lived token is null when request fails', async () => {
nock('http://dev:3333')
.post('/api/auth/token')
.times(3)
.reply(500, 'Internal error')
expect.assertions(1)
await expect(getToken('dev=xyz', ''))
.resolves
.toBeNull()
})
it('get short lived token returns null when access key is empty', async () => {
expect.assertions(1)
await expect(getToken('', ''))
.resolves
.toBeNull()
})
it('get short lived token succeeds when single key is set', async () => {
nock('https://dev')
.post('/api/auth/token')
.reply(200, 'token')
expect.assertions(1)
await expect(getToken('dev=key1', ''))
.resolves
.toEqual({"keys": [{"hostname": "dev", "key": "token"}]})
})
it('get short lived token succeeds when multiple keys are set', async () => {
nock('https://dev')
.post('/api/auth/token')
.reply(200, 'token1')
nock('https://prod')
.post('/api/auth/token')
.reply(200, 'token2')
expect.assertions(1)
await expect(getToken('dev=key1;prod=key2', ''))
.resolves
.toEqual({"keys": [{"hostname": "dev", "key": "token1"}, {"hostname": "prod", "key": "token2"}]})
})
it('get short lived token succeeds when multiple keys are set and one is failing', async () => {
nock('https://dev')
.post('/api/auth/token')
.reply(200, 'token1')
nock('https://bogus')
.post('/api/auth/token')
.times(3)
.reply(500, 'Internal Error')
nock('https://prod')
.post('/api/auth/token')
.reply(200, 'token2')
expect.assertions(1)
await expect(getToken('dev=key1;bogus=key0;prod=key2', ''))
.resolves
.toEqual({"keys": [{"hostname": "dev", "key": "token1"}, {"hostname": "prod", "key": "token2"}]})
})
it('get short lived token is null when multiple keys are set and all are failing', async () => {
nock('https://dev')
.post('/api/auth/token')
.times(3)
.reply(500, 'Internal Error')
nock('https://bogus')
.post('/api/auth/token')
.times(3)
.reply(500, 'Internal Error')
expect.assertions(1)
await expect(getToken('dev=key1;bogus=key0', ''))
.resolves
.toBeNull()
})
})

View File

@@ -8,7 +8,10 @@ The action should be run in the root of the repository, as it will recursively s
```yaml
name: "Validate Gradle Wrapper"
on: [push, pull_request]
on:
push:
pull_request:
jobs:
validation: