Compare commits

..

60 Commits
v3.3.2 ... v3

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
70 changed files with 8558 additions and 1034 deletions

View File

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

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (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. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

View File

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

View File

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

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (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. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

View File

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

View File

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

View File

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

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (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. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

View File

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

View File

@@ -8,9 +8,9 @@ repositories {
dependencies { dependencies {
api("org.apache.commons:commons-math3:3.6.1") 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 { tasks.test {

View File

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

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (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. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (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. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

View File

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

View File

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

View File

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

View File

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

View File

@@ -35,7 +35,7 @@ jobs:
cache-read-only: false # For testing, allow writing cache entries on non-default branches cache-read-only: false # For testing, allow writing cache entries on non-default branches
- name: Build with 3.1 - name: Build with 3.1
working-directory: sources/test/jest/resources/cache-cleanup 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 # Second build will use the cache from the first build, but cleanup should remove unused artifacts
assemble-build: assemble-build:
@@ -58,7 +58,7 @@ jobs:
gradle-home-cache-cleanup: true gradle-home-cache-cleanup: true
- name: Build with 3.1.1 - name: Build with 3.1.1
working-directory: sources/test/jest/resources/cache-cleanup 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: check-clean-cache:
needs: assemble-build needs: assemble-build
@@ -78,7 +78,9 @@ jobs:
with: with:
cache-read-only: true cache-read-only: true
- name: Report Gradle User Home - 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 - name: Verify cleaned cache
shell: bash shell: bash
run: | run: |
@@ -90,3 +92,7 @@ jobs:
echo "::error ::Should NOT find commons-math3 3.1 in cache" echo "::error ::Should NOT find commons-math3 3.1 in cache"
exit 1 exit 1
fi 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

@@ -26,14 +26,19 @@ jobs:
DEVELOCITY_URL: https://ge.solutions-team.gradle.com DEVELOCITY_URL: https://ge.solutions-team.gradle.com
DEVELOCITY_PLUGIN_VERSION: ${{ matrix.plugin-version }} DEVELOCITY_PLUGIN_VERSION: ${{ matrix.plugin-version }}
DEVELOCITY_CCUD_PLUGIN_VERSION: '2.0' DEVELOCITY_CCUD_PLUGIN_VERSION: '2.0'
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} # required to test against GE plugin 3.16.2 ${{matrix.accessKeyEnv}}: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
gradle: [current, 7.6.2, 6.9.4, 5.6.4] gradle: [current, 7.6.2, 6.9.4, 5.6.4]
os: ${{fromJSON(inputs.runner-os)}} os: ${{fromJSON(inputs.runner-os)}}
plugin-version: [3.16.2, 3.17.2] 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 }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -61,4 +66,136 @@ jobs:
uses: actions/github-script@v7 uses: actions/github-script@v7
with: with:
script: | 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

@@ -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 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) 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 ## Using `act` to run integ-test workflows locally
It's possible to run GitHub Actions workflows locally with https://nektosact.com/. 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` `./build act -W .github/workflows/integ-test-caching-config.yml -j cache-disabled-pre-existing-gradle-home`
Known issues: 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. - `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) - `act` is not yet compatible with `actions/upload-artifact@v4` (or related toolkit functions)
- See https://github.com/nektos/act/pull/2224 - See https://github.com/nektos/act/pull/2224
@@ -46,4 +30,4 @@ Tips:
- Add the following lines to `~/.actrc`: - 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 - `--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 - `--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.

8
build
View File

@@ -16,12 +16,18 @@ case "$1" in
# Run act # Run act
$@ $@
# Revert the changes to the dist directory # Revert the changes to the dist directory
git co -- dist git checkout -- dist
;; ;;
init-scripts) init-scripts)
cd test/init-scripts cd test/init-scripts
./gradlew check ./gradlew check
;; ;;
dist)
npm install
npm run build
cd ..
cp -r sources/dist .
;;
*) *)
npm install npm install
npm run build npm run build

View File

@@ -15,13 +15,13 @@ inputs:
dependency-resolution-task: dependency-resolution-task:
description: | 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. By default, the built-in `:ForceDependencyResolutionPlugin_resolveAllDependencies` task is executed.
required: false required: false
additional-arguments: additional-arguments:
description: | 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`. For example, `--no-configuration-cache --stacktrace`.
required: false required: false
@@ -40,7 +40,7 @@ inputs:
cache-write-only: cache-write-only:
description: | 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'. Setting this to 'true' implies cache-read-only will be 'false'.
required: false required: false
default: false default: false
@@ -52,7 +52,7 @@ inputs:
cache-encryption-key: cache-encryption-key:
description: | 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`. 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. Configuration-cache data will not be saved/restored without an encryption key being provided.
required: false 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-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. '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. '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, 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 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. required to submit via the Dependency Submission API.
@@ -120,11 +120,19 @@ inputs:
build-scan-terms-of-use-url: 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'. 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 required: false
build-scan-terms-of-use-agree: build-scan-terms-of-use-agree:
description: Indicate that you agree to the Build Scan® terms of use. This input value must be "yes". description: Indicate that you agree to the Build Scan® terms of use. This input value must be "yes".
required: false 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 # DEPRECATED ACTION INPUTS
build-scan-terms-of-service-url: 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'. 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. description: When 'true', the action will not attempt to restore the Gradle User Home entries from other Jobs.
required: false required: false
default: false default: false
# INTERNAL ACTION INPUTS # INTERNAL ACTION INPUTS
# These inputs should not be configured directly, and are only used to pass environmental information to the action # These inputs should not be configured directly, and are only used to pass environmental information to the action
workflow-job-context: 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 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). [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 ## General usage
@@ -95,7 +95,7 @@ In some cases, the default action configuration will not be sufficient, and addi
dependency-resolution-task: myDependencyResolutionTask dependency-resolution-task: myDependencyResolutionTask
# Additional arguments that should be passed to execute Gradle # 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. # Enable configuration-cache reuse for this build.
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
@@ -367,6 +367,7 @@ on:
types: [completed] types: [completed]
permissions: permissions:
actions: read
contents: write contents: write
jobs: jobs:

View File

@@ -1,9 +1,9 @@
# Deprecation upgrade guide # 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 Deprecated functionality will be fully supported during the current major release, and will be
removed in the next major release. removed in the next major release.
Users will receive a deprecation warning when they rely on deprecated functionality, Users will receive a deprecation warning when they rely on deprecated functionality,
prompting them to update their workflows. prompting them to update their workflows.
## The action `gradle/gradle-build-action` has been replaced by `gradle/actions/setup-gradle` ## 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` ## 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. 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. 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`: 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 - name: Setup Gradle for a non-wrapper project
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:
gradle-version: 8.7 gradle-version: 8.9
- name: Assemble the project - name: Assemble the project
run: gradle assemble run: gradle assemble
@@ -143,3 +143,8 @@ to this:
build-scan-terms-of-use-agree: "yes" 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`. 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? ## 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: 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). - 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). - 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. - [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. - [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. These features work both when Gradle is executed via `setup-gradle` and for any Gradle execution in subsequent steps.
## General usage ## 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. 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. 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.
@@ -46,7 +46,7 @@ jobs:
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
- name: Execute Gradle build - name: Execute Gradle build
run: ./gradlew build run: ./gradlew build
``` ```
@@ -126,7 +126,7 @@ cache-disabled: true
### Using the cache read-only ### 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. 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. 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. 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.
@@ -158,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. 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. 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 > 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`: 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`:
@@ -198,13 +198,13 @@ jobs:
``` ```
> [!IMPORTANT] > [!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 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. > This prevents a malicious PR from reading the configuration-cache data, which may encode secrets read by Gradle.
### Incompatibility with other caching mechanisms ### 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: 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). - 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).
@@ -218,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. 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. - 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 - 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. Each of these properties has influenced the design and implementation of the caching in `setup-gradle`, as described below.
@@ -256,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}` 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. This allows the most recent state to always be available in the GitHub actions cache.
### Finding a matching cache entry ### Finding a matching cache entry
@@ -271,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. 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). 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).
@@ -289,7 +289,7 @@ For example, this means that all jobs executing a particular version of the Grad
### Stopping the Gradle daemon ### 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. 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. 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.
@@ -316,23 +316,23 @@ Some techniques can be used to avoid/mitigate this issue:
### Select which branches should write to the cache ### Select which branches should write to the cache
GitHub cache entries are not shared between builds on different branches. GitHub cache entries are not shared between builds on different branches or tags.
Workflow runs can restore caches created in either the current branch or the default branch (usually main). 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. 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. 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. 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`, 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. 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, 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. 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. 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): 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 `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. - 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 ### 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. As well as any wrapper distributions, the action will attempt to save and restore the `caches` and `notifications` directories from Gradle User Home.
@@ -353,7 +353,7 @@ gradle-home-cache-excludes: |
caches/keyrings 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. 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 ### Remove unused files from Gradle User Home before saving to the cache
@@ -362,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 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. 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. 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: Gradle Home cache cleanup is considered experimental and is disabled by default. You can enable this feature for the action as follows:
@@ -376,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 - 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 - 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. 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. Local builds can then benefit from the remote cache.
@@ -389,8 +389,8 @@ You can enable debug logging either by:
### Increased logging from Gradle builds ### Increased logging from Gradle builds
When debug logging is enabled, this action will cause all builds to run with the `--info` and `--stacktrace` options. 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) 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. 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: 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:
@@ -403,7 +403,7 @@ org.gradle.logging.stacktrace=internal
### Cache debugging and analysis ### 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. 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. When debug logging is enabled, more detailed logging of cache operations is included in the GitHub actions log.
@@ -461,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, 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 `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 ### 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. 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. To save selected files from your build execution, you can use the core [Upload-Artifact](https://github.com/actions/upload-artifact) action.
For example: For example:
```yaml ```yaml
jobs: jobs:
gradle: gradle:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -506,7 +506,7 @@ Since Gradle applies init scripts in alphabetical order, one way to ensure this
## Gradle Wrapper validation ## 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. wrapper validation directly in your Setup Gradle step.
```yaml ```yaml
@@ -530,7 +530,7 @@ You can use the `setup-gradle` action on GitHub Enterprise Server, and benefit f
## GitHub Dependency Graph support ## GitHub Dependency Graph support
> [!IMPORTANT] > [!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 > using `gradle/actions/dependency-submission`. This action will attempt to detect all dependencies used by your build
> without building and testing the project itself. > without building and testing the project itself.
> >
@@ -544,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). 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 ### Basic usage
You enable GitHub Dependency Graph support by setting the `dependency-graph` action parameter. Valid values are: You enable GitHub Dependency Graph support by setting the `dependency-graph` action parameter. Valid values are:
| Option | Behaviour | | Option | Behaviour |
@@ -560,7 +560,7 @@ Example of a CI workflow that generates and submits a dependency graph:
name: CI build name: CI build
on: on:
push: push:
permissions: permissions:
contents: write contents: write
@@ -582,13 +582,13 @@ jobs:
run: ./gradlew build 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). 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] > [!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. > 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 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). > 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).
@@ -610,7 +610,7 @@ graph cannot be generated or submitted. You can enable this behavior with the `d
### Using a custom plugin repository ### 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. 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. The `GRADLE_PLUGIN_REPOSITORY_USERNAME` and `GRADLE_PLUGIN_REPOSITORY_PASSWORD` can be used when the plugin repository requires authentication.
@@ -670,7 +670,7 @@ jobs:
### Filtering which Gradle Configurations contribute to the dependency graph ### 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. you can limit the dependency extraction to a subset of these.
See the documentation for [dependency-submission](dependency-submission.md) and the See the documentation for [dependency-submission](dependency-submission.md) and the
@@ -678,7 +678,7 @@ See the documentation for [dependency-submission](dependency-submission.md) and
### Gradle version compatibility ### 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. 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. A known exception to this is that Gradle `7.0`, `7.0.1`, and `7.0.2` are not supported.
@@ -687,7 +687,7 @@ See [here](https://github.com/gradle/github-dependency-graph-gradle-plugin?tab=r
### Reducing storage costs for saved dependency graph artifacts ### 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). 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. To reduce storage costs for these artifacts, you can set the `artifact-retention-days` value to a lower number.
@@ -708,27 +708,49 @@ The same auto-injection behavior is available for the Common Custom User Data Gr
## Enabling Develocity injection ## 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: Here's a minimal example:
```yaml ```yaml
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v3 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 - name: Run a Gradle build with Develocity injection enabled
run: ./gradlew build run: ./gradlew build
env: env:
DEVELOCITY_INJECTION_ENABLED: true DEVELOCITY_INJECTION_ENABLED: true
DEVELOCITY_URL: https://develocity.your-server.com DEVELOCITY_URL: https://develocity.your-server.com
DEVELOCITY_PLUGIN_VERSION: 3.17.2 DEVELOCITY_PLUGIN_VERSION: 3.17
``` ```
This configuration will automatically apply `v3.17.2` 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. ### Short-lived access tokens
In the likely scenario that your Develocity server requires authentication, you will also need to configure an additional environment variable 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.
with a valid [Develocity access key](https://docs.gradle.com/develocity/gradle-plugin/#via_environment_variable). 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 ## Configuring Develocity injection
@@ -736,16 +758,46 @@ The `init-script` supports several additional configuration parameters that you
| Variable | Required | Description | | Variable | Required | Description |
|--------------------------------------| --- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |--------------------------------------| --- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| DEVELOCITY_INJECTION_ENABLED | :white_check_mark: | enables Develocity injection | | develocity-injection-enabled | :white_check_mark: | enables Develocity injection |
| DEVELOCITY_URL | :white_check_mark: | the URL of the Develocity server | | 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-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-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-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-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 | | 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-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-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 | | 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 ## Publishing to scans.gradle.com

View File

@@ -23,7 +23,7 @@ inputs:
cache-write-only: cache-write-only:
description: | 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'. Setting this to 'true' implies cache-read-only will be 'false'.
required: false required: false
default: false default: false
@@ -35,7 +35,7 @@ inputs:
cache-encryption-key: cache-encryption-key:
description: | 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`. 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. Configuration-cache data will not be saved/restored without an encryption key being provided.
required: false required: false
@@ -70,7 +70,7 @@ inputs:
# Dependency Graph configuration # Dependency Graph configuration
dependency-graph: dependency-graph:
description: | 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'. Valid values are 'disabled' (default), 'generate', 'generate-and-submit', 'generate-and-upload', 'download-and-submit' and 'clear'.
required: false required: false
default: 'disabled' default: 'disabled'
@@ -95,11 +95,59 @@ inputs:
build-scan-terms-of-use-url: 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'. 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 required: false
build-scan-terms-of-use-agree: build-scan-terms-of-use-agree:
description: Indicate that you agree to the Build Scan® terms of use. This input value must be "yes". description: Indicate that you agree to the Build Scan® terms of use. This input value must be "yes".
required: false 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 # Wrapper validation configuration
validate-wrappers: validate-wrappers:
description: | description: |
@@ -143,7 +191,7 @@ inputs:
description: When 'true', the action will not attempt to restore the Gradle User Home entries from other Jobs. description: When 'true', the action will not attempt to restore the Gradle User Home entries from other Jobs.
required: false required: false
default: false default: false
# INTERNAL ACTION INPUTS # INTERNAL ACTION INPUTS
# These inputs should not be configured directly, and are only used to pass environmental information to the action # These inputs should not be configured directly, and are only used to pass environmental information to the action
workflow-job-context: workflow-job-context:

View File

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

View File

@@ -3316,12 +3316,12 @@
} }
}, },
"node_modules/braces": { "node_modules/braces": {
"version": "3.0.2", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"fill-range": "^7.0.1" "fill-range": "^7.1.1"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@@ -4736,9 +4736,9 @@
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.0.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
@@ -11628,12 +11628,12 @@
} }
}, },
"braces": { "braces": {
"version": "3.0.2", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true, "dev": true,
"requires": { "requires": {
"fill-range": "^7.0.1" "fill-range": "^7.1.1"
} }
}, },
"browserslist": { "browserslist": {
@@ -12659,9 +12659,9 @@
} }
}, },
"fill-range": { "fill-range": {
"version": "7.0.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true, "dev": true,
"requires": { "requires": {
"to-regex-range": "^5.0.1" "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.2')
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 core from '@actions/core'
import * as exec from '@actions/exec'
import * as glob from '@actions/glob'
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import {provisionAndMaybeExecute} from '../execution/gradle'
export class CacheCleaner { export class CacheCleaner {
private readonly gradleUserHome: string private readonly gradleUserHome: string
@@ -13,25 +12,20 @@ export class CacheCleaner {
this.tmpDir = tmpDir this.tmpDir = tmpDir
} }
async prepare(): Promise<void> { async prepare(): Promise<string> {
// Reset the file-access journal so that files appear not to have been used recently // Save the current timestamp
fs.rmSync(path.resolve(this.gradleUserHome, 'caches/journal-1'), {recursive: true, force: true}) const timestamp = Date.now().toString()
fs.mkdirSync(path.resolve(this.gradleUserHome, 'caches/journal-1'), {recursive: true}) core.saveState('clean-timestamp', timestamp)
fs.writeFileSync( return timestamp
path.resolve(this.gradleUserHome, 'caches/journal-1/file-access.properties'),
'inceptionTimestamp=0'
)
// Set the modification time of all files to the past: this timestamp is used when there is no matching entry in the journal
await this.ageAllFiles()
// Touch all 'gc' files so that cache cleanup won't run immediately.
await this.touchAllFiles('gc.properties')
} }
async forceCleanup(): Promise<void> { async forceCleanup(): Promise<void> {
// Age all 'gc' files so that cache cleanup will run immediately. const cleanTimestamp = core.getState('clean-timestamp')
await this.ageAllFiles('gc.properties') 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 // Run a dummy Gradle build to trigger cache cleanup
const cleanupProjectDir = path.resolve(this.tmpDir, 'dummy-cleanup-project') const cleanupProjectDir = path.resolve(this.tmpDir, 'dummy-cleanup-project')
@@ -40,30 +34,37 @@ export class CacheCleaner {
path.resolve(cleanupProjectDir, 'settings.gradle'), path.resolve(cleanupProjectDir, 'settings.gradle'),
'rootProject.name = "dummy-cleanup-project"' '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") {}') 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 provisionAndMaybeExecute('current', cleanupProjectDir, [
await exec.exec(gradleCommand, [], { '-g',
cwd: cleanupProjectDir this.gradleUserHome,
}) '-I',
} 'init.gradle',
'--info',
private async ageAllFiles(fileName = '*'): Promise<void> { '--no-daemon',
core.debug(`Aging all files in Gradle User Home with name ${fileName}`) '--no-scan',
await this.setUtimes(`${this.gradleUserHome}/**/${fileName}`, new Date(0)) '--build-cache',
} '-DGITHUB_DEPENDENCY_GRAPH_ENABLED=false',
'noop'
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)
}
} }
} }

View File

@@ -188,6 +188,9 @@ export enum JobSummaryOption {
} }
export class BuildScanConfig { export class BuildScanConfig {
static DevelocityAccessKeyEnvVar = 'DEVELOCITY_ACCESS_KEY'
static GradleEnterpriseAccessKeyEnvVar = 'GRADLE_ENTERPRISE_ACCESS_KEY'
getBuildScanPublishEnabled(): boolean { getBuildScanPublishEnabled(): boolean {
return getBooleanInput('build-scan-publish') && this.verifyTermsOfUseAgreement() return getBooleanInput('build-scan-publish') && this.verifyTermsOfUseAgreement()
} }
@@ -200,6 +203,59 @@ export class BuildScanConfig {
return this.getTermsOfUseProp('build-scan-terms-of-use-agree', 'build-scan-terms-of-service-agree') 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 { private verifyTermsOfUseAgreement(): boolean {
if ( if (
(this.getBuildScanTermsOfUseUrl() !== 'https://gradle.com/terms-of-service' && (this.getBuildScanTermsOfUseUrl() !== 'https://gradle.com/terms-of-service' &&
@@ -313,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]`) 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

@@ -60,44 +60,19 @@ export async function complete(config: DependencyGraphConfig): Promise<void> {
return return
case DependencyGraphOption.GenerateAndSubmit: case DependencyGraphOption.GenerateAndSubmit:
case DependencyGraphOption.Clear: // Submit the empty dependency graph case DependencyGraphOption.Clear: // Submit the empty dependency graph
await submitDependencyGraphs(await findDependencyGraphFiles()) await findAndSubmitDependencyGraphs(config)
return return
case DependencyGraphOption.GenerateAndUpload: case DependencyGraphOption.GenerateAndUpload:
await uploadDependencyGraphs(await findDependencyGraphFiles(), config) await findAndUploadDependencyGraphs(config)
} }
} catch (e) { } catch (e) {
warnOrFail(config, option, e) warnOrFail(config, option, e)
} }
} }
async function uploadDependencyGraphs(dependencyGraphFiles: string[], config: DependencyGraphConfig): Promise<void> {
if (dependencyGraphFiles.length === 0) {
core.info('No dependency graph files found to upload.')
return
}
if (isRunningInActEnvironment()) {
core.info('Dependency graph upload not supported in the ACT environment.')
core.info(`Would upload: ${dependencyGraphFiles.join(', ')}`)
return
}
const workspaceDirectory = getWorkspaceDirectory()
const artifactClient = new DefaultArtifactClient()
for (const dependencyGraphFile of dependencyGraphFiles) {
const relativePath = getRelativePathFromWorkspace(dependencyGraphFile)
core.info(`Uploading dependency graph file: ${relativePath}`)
const artifactName = `${DEPENDENCY_GRAPH_PREFIX}${path.basename(dependencyGraphFile)}`
await artifactClient.uploadArtifact(artifactName, [dependencyGraphFile], workspaceDirectory, {
retentionDays: config.getArtifactRetentionDays()
})
}
}
async function downloadAndSubmitDependencyGraphs(config: DependencyGraphConfig): Promise<void> { async function downloadAndSubmitDependencyGraphs(config: DependencyGraphConfig): Promise<void> {
if (isRunningInActEnvironment()) { if (isRunningInActEnvironment()) {
core.info('Dependency graph download and submit not supported in the ACT environment.') core.info('Dependency graph not supported in the ACT environment.')
return return
} }
@@ -108,53 +83,32 @@ async function downloadAndSubmitDependencyGraphs(config: DependencyGraphConfig):
} }
} }
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> { async function findAndSubmitDependencyGraphs(config: DependencyGraphConfig): Promise<void> {
if (dependencyGraphFiles.length === 0) {
core.info('No dependency graph files found to submit.')
return
}
if (isRunningInActEnvironment()) { if (isRunningInActEnvironment()) {
core.info('Dependency graph submit not supported in the ACT environment.') core.info('Dependency graph not supported in the ACT environment.')
core.info(`Would submit: ${dependencyGraphFiles.join(', ')}`)
return return
} }
for (const dependencyGraphFile of dependencyGraphFiles) { const dependencyGraphFiles = await findDependencyGraphFiles()
try {
await submitDependencyGraphs(dependencyGraphFiles)
} catch (e) {
try { try {
await submitDependencyGraphFile(dependencyGraphFile) await uploadDependencyGraphs(dependencyGraphFiles, config)
} catch (error) { } catch (uploadError) {
if (error instanceof RequestError) { core.info(String(uploadError))
error.message = translateErrorMessage(dependencyGraphFile, error)
}
throw error
} }
throw e
} }
} }
function translateErrorMessage(jsonFile: string, error: RequestError): string { async function findAndUploadDependencyGraphs(config: DependencyGraphConfig): Promise<void> {
const relativeJsonFile = getRelativePathFromWorkspace(jsonFile) if (isRunningInActEnvironment()) {
const mainWarning = `Dependency submission failed for ${relativeJsonFile}.\n${error.message}` core.info('Dependency graph not supported in the ACT environment.')
if (error.message === 'Resource not accessible by integration') { return
return `${mainWarning}
Please ensure that the 'contents: write' permission is available for the workflow job.
Note that this permission is never available for a 'pull_request' trigger from a repository fork.
`
} }
return mainWarning
}
async function submitDependencyGraphFile(jsonFile: string): Promise<void> { await uploadDependencyGraphs(await findDependencyGraphFiles(), config)
const octokit = getOctokit()
const jsonContent = fs.readFileSync(jsonFile, 'utf8')
const jsonObject = JSON.parse(jsonContent)
jsonObject.owner = github.context.repo.owner
jsonObject.repo = github.context.repo.repo
const response = await octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', jsonObject)
const relativeJsonFile = getRelativePathFromWorkspace(jsonFile)
core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
} }
async function downloadDependencyGraphs(): Promise<string[]> { async function downloadDependencyGraphs(): Promise<string[]> {
@@ -195,6 +149,67 @@ async function findDependencyGraphFiles(): Promise<string[]> {
return unprocessedFiles return unprocessedFiles
} }
async function uploadDependencyGraphs(dependencyGraphFiles: string[], config: DependencyGraphConfig): Promise<void> {
if (dependencyGraphFiles.length === 0) {
core.info('No dependency graph files found to upload.')
return
}
const workspaceDirectory = getWorkspaceDirectory()
const artifactClient = new DefaultArtifactClient()
for (const dependencyGraphFile of dependencyGraphFiles) {
const relativePath = getRelativePathFromWorkspace(dependencyGraphFile)
core.info(`Uploading dependency graph file: ${relativePath}`)
const artifactName = `${DEPENDENCY_GRAPH_PREFIX}${path.basename(dependencyGraphFile)}`
await artifactClient.uploadArtifact(artifactName, [dependencyGraphFile], workspaceDirectory, {
retentionDays: config.getArtifactRetentionDays()
})
}
}
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
if (dependencyGraphFiles.length === 0) {
core.info('No dependency graph files found to submit.')
return
}
for (const dependencyGraphFile of dependencyGraphFiles) {
try {
await submitDependencyGraphFile(dependencyGraphFile)
} catch (error) {
if (error instanceof RequestError) {
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${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.
Note that this permission is never available for a 'pull_request' trigger from a repository fork.
`
}
return mainWarning
}
async function submitDependencyGraphFile(jsonFile: string): Promise<void> {
const octokit = getOctokit()
const jsonContent = fs.readFileSync(jsonFile, 'utf8')
const jsonObject = JSON.parse(jsonContent)
jsonObject.owner = github.context.repo.owner
jsonObject.repo = github.context.repo.repo
const response = await octokit.request('POST /repos/{owner}/{repo}/dependency-graph/snapshots', jsonObject)
const relativeJsonFile = getRelativePathFromWorkspace(jsonFile)
core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
}
function getReportDirectory(): string { function getReportDirectory(): string {
return process.env.DEPENDENCY_GRAPH_REPORT_DIR! return process.env.DEPENDENCY_GRAPH_REPORT_DIR!
} }

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

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

View File

@@ -1,16 +1,20 @@
/*
* Initscript for injection of Develocity into Gradle builds.
* Version: v1.0
*/
import org.gradle.util.GradleVersion 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 { 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 def isTopLevelBuild = !gradle.parent
if (!isTopLevelBuild) { if (!isTopLevelBuild) {
return return
} }
def getInputParam = { String name -> 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) return System.getProperty(name) ?: System.getenv(envVarName)
} }
@@ -20,9 +24,9 @@ initscript {
return return
} }
// finish early if injection is disabled // Plugin loading is only required for Develocity injection. Abort early if not enabled.
def gradleInjectionEnabled = getInputParam("develocity.injection-enabled") def develocityInjectionEnabled = Boolean.parseBoolean(getInputParam("develocity.injection-enabled"))
if (gradleInjectionEnabled != "true") { if (!develocityInjectionEnabled) {
return return
} }
@@ -75,29 +79,17 @@ initscript {
} }
} }
def BUILD_SCAN_PLUGIN_ID = 'com.gradle.build-scan' static getInputParam(String name) {
def BUILD_SCAN_PLUGIN_CLASS = 'com.gradle.scan.plugin.BuildScanPlugin' def ENV_VAR_PREFIX = ''
def envVarName = ENV_VAR_PREFIX + name.toUpperCase().replace('.', '_').replace('-', '_')
def GRADLE_ENTERPRISE_PLUGIN_ID = 'com.gradle.enterprise' return System.getProperty(name) ?: System.getenv(envVarName)
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 isTopLevelBuild = !gradle.parent def isTopLevelBuild = !gradle.parent
if (!isTopLevelBuild) { if (!isTopLevelBuild) {
return 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 requestedInitScriptName = getInputParam('develocity.injection.init-script-name')
def initScriptName = buildscript.sourceFile.name def initScriptName = buildscript.sourceFile.name
if (requestedInitScriptName != initScriptName) { if (requestedInitScriptName != initScriptName) {
@@ -105,205 +97,226 @@ if (requestedInitScriptName != initScriptName) {
return return
} }
// finish early if injection is disabled def develocityInjectionEnabled = Boolean.parseBoolean(getInputParam("develocity.injection-enabled"))
def gradleInjectionEnabled = getInputParam("develocity.injection-enabled") if (develocityInjectionEnabled) {
if (gradleInjectionEnabled != "true") { enableDevelocityInjection()
return
} }
def develocityUrl = getInputParam('develocity.url') // To enable build-scan capture, a `captureBuildScanLink(String)` method must be added to `BuildScanCollector`.
def develocityAllowUntrustedServer = Boolean.parseBoolean(getInputParam('develocity.allow-untrusted-server')) def buildScanCollector = new BuildScanCollector()
def develocityEnforceUrl = Boolean.parseBoolean(getInputParam('develocity.enforce-url')) def buildScanCaptureEnabled = buildScanCollector.metaClass.respondsTo(buildScanCollector, 'captureBuildScanLink', String)
def buildScanUploadInBackground = Boolean.parseBoolean(getInputParam('develocity.build-scan.upload-in-background')) if (buildScanCaptureEnabled) {
def develocityCaptureFileFingerprints = getInputParam('develocity.capture-file-fingerprints') ? Boolean.parseBoolean(getInputParam('develocity.capture-file-fingerprints')) : true enableBuildScanLinkCapture(buildScanCollector)
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') void enableDevelocityInjection() {
def atLeastGradle4 = GradleVersion.current() >= GradleVersion.version('4.0') def BUILD_SCAN_PLUGIN_ID = 'com.gradle.build-scan'
def shouldApplyDevelocityPlugin = atLeastGradle5 && develocityPluginVersion && isAtLeast(develocityPluginVersion, '3.17') def BUILD_SCAN_PLUGIN_CLASS = 'com.gradle.scan.plugin.BuildScanPlugin'
def dvOrGe = { def dvValue, def geValue -> def GRADLE_ENTERPRISE_PLUGIN_ID = 'com.gradle.enterprise'
if (shouldApplyDevelocityPlugin) { def GRADLE_ENTERPRISE_PLUGIN_CLASS = 'com.gradle.enterprise.gradleplugin.GradleEnterprisePlugin'
return dvValue instanceof Closure<?> ? dvValue() : dvValue
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 // finish early if configuration parameters passed in via system properties are not valid/supported
if (ccudPluginVersion && isNotAtLeast(ccudPluginVersion, '1.7')) { if (ccudPluginVersion && isNotAtLeast(ccudPluginVersion, '1.7')) {
logger.warn("Common Custom User Data Gradle plugin must be at least 1.7. Configured version is $ccudPluginVersion.") logger.warn("Common Custom User Data Gradle plugin must be at least 1.7. Configured version is $ccudPluginVersion.")
return return
} }
// register buildScanPublished listener and optionally apply the Develocity plugin // Conditionally apply and configure the Develocity plugin
if (GradleVersion.current() < GradleVersion.version('6.0')) { if (GradleVersion.current() < GradleVersion.version('6.0')) {
rootProject { rootProject {
buildscript.configurations.getByName("classpath").incoming.afterResolve { ResolvableDependencies incoming -> buildscript.configurations.getByName("classpath").incoming.afterResolve { ResolvableDependencies incoming ->
def resolutionResult = incoming.resolutionResult def resolutionResult = incoming.resolutionResult
if (develocityPluginVersion) { if (develocityPluginVersion) {
def scanPluginComponent = resolutionResult.allComponents.find { def scanPluginComponent = resolutionResult.allComponents.find {
it.moduleVersion.with { group == "com.gradle" && ['build-scan-plugin', 'gradle-enterprise-gradle-plugin', 'develocity-gradle-plugin'].contains(name) } it.moduleVersion.with { group == "com.gradle" && ['build-scan-plugin', 'gradle-enterprise-gradle-plugin', 'develocity-gradle-plugin'].contains(name) }
} }
if (!scanPluginComponent) { if (!scanPluginComponent) {
def pluginClass = dvOrGe(DEVELOCITY_PLUGIN_CLASS, BUILD_SCAN_PLUGIN_CLASS) def pluginClass = dvOrGe(DEVELOCITY_PLUGIN_CLASS, BUILD_SCAN_PLUGIN_CLASS)
logger.lifecycle("Applying $pluginClass via init script") logger.lifecycle("Applying $pluginClass via init script")
applyPluginExternally(pluginManager, pluginClass) applyPluginExternally(pluginManager, pluginClass)
def rootExtension = dvOrGe( def rootExtension = dvOrGe(
{ develocity }, { develocity },
{ buildScan } { buildScan }
) )
def buildScanExtension = dvOrGe( def buildScanExtension = dvOrGe(
{ rootExtension.buildScan }, { rootExtension.buildScan },
{ rootExtension } { rootExtension }
) )
if (develocityUrl) { if (develocityUrl) {
logger.lifecycle("Connection to Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints") logger.lifecycle("Connection to Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints")
rootExtension.server = develocityUrl rootExtension.server = develocityUrl
rootExtension.allowUntrustedServer = develocityAllowUntrustedServer rootExtension.allowUntrustedServer = develocityAllowUntrustedServer
} }
if (!shouldApplyDevelocityPlugin) { if (!shouldApplyDevelocityPlugin) {
// Develocity plugin publishes scans by default // Develocity plugin publishes scans by default
buildScanExtension.publishAlways() buildScanExtension.publishAlways()
} }
// uploadInBackground not available for build-scan-plugin 1.16 // uploadInBackground not available for build-scan-plugin 1.16
if (buildScanExtension.metaClass.respondsTo(buildScanExtension, 'setUploadInBackground', Boolean)) buildScanExtension.uploadInBackground = buildScanUploadInBackground if (buildScanExtension.metaClass.respondsTo(buildScanExtension, 'setUploadInBackground', Boolean)) buildScanExtension.uploadInBackground = buildScanUploadInBackground
buildScanExtension.value CI_AUTO_INJECTION_CUSTOM_VALUE_NAME, ciAutoInjectionCustomValueValue buildScanExtension.value CI_AUTO_INJECTION_CUSTOM_VALUE_NAME, ciAutoInjectionCustomValueValue
if (isAtLeast(develocityPluginVersion, '2.1') && atLeastGradle5) { if (isAtLeast(develocityPluginVersion, '2.1') && atLeastGradle5) {
logger.lifecycle("Setting captureFileFingerprints: $develocityCaptureFileFingerprints") logger.lifecycle("Setting captureFileFingerprints: $develocityCaptureFileFingerprints")
if (isAtLeast(develocityPluginVersion, '3.17')) { if (isAtLeast(develocityPluginVersion, '3.17')) {
buildScanExtension.capture.fileFingerprints.set(develocityCaptureFileFingerprints) buildScanExtension.capture.fileFingerprints.set(develocityCaptureFileFingerprints)
} else if (isAtLeast(develocityPluginVersion, '3.7')) { } else if (isAtLeast(develocityPluginVersion, '3.7')) {
buildScanExtension.capture.taskInputFiles = develocityCaptureFileFingerprints buildScanExtension.capture.taskInputFiles = develocityCaptureFileFingerprints
} else { } else {
buildScanExtension.captureTaskInputFiles = develocityCaptureFileFingerprints 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) { if (develocityUrl && develocityEnforceUrl) {
logger.lifecycle("Enforcing Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints") logger.lifecycle("Enforcing Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints")
} }
pluginManager.withPlugin(BUILD_SCAN_PLUGIN_ID) { eachDevelocitySettingsExtension(settings,
// Only execute if develocity plugin isn't applied. { develocity ->
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) { if (develocityUrl && develocityEnforceUrl) {
develocity.server = develocityUrl develocity.server = develocityUrl
develocity.allowUntrustedServer = develocityAllowUntrustedServer develocity.allowUntrustedServer = develocityAllowUntrustedServer
} }
}
if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) { if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
develocity.buildScan.termsOfUseUrl = buildScanTermsOfUseUrl develocity.buildScan.termsOfUseUrl = buildScanTermsOfUseUrl
develocity.buildScan.termsOfUseAgree = buildScanTermsOfUseAgree 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 ->
gradleEnterprise.buildScan.publishAlways() if (develocityUrl && develocityEnforceUrl) {
if (isAtLeast(develocityPluginVersion, '2.1')) { gradleEnterprise.server = develocityUrl
logger.lifecycle("Setting captureFileFingerprints: $develocityCaptureFileFingerprints") gradleEnterprise.allowUntrustedServer = develocityAllowUntrustedServer
if (isAtLeast(develocityPluginVersion, '3.7')) { }
gradleEnterprise.buildScan.capture.taskInputFiles = develocityCaptureFileFingerprints
} else { if (buildScanTermsOfUseUrl && buildScanTermsOfUseAgree) {
gradleEnterprise.buildScan.captureTaskInputFiles = develocityCaptureFileFingerprints gradleEnterprise.buildScan.termsOfServiceUrl = buildScanTermsOfUseUrl
} gradleEnterprise.buildScan.termsOfServiceAgree = buildScanTermsOfUseAgree
} }
} }
) )
} }
if (develocityUrl && develocityEnforceUrl) { if (ccudPluginVersion) {
logger.lifecycle("Enforcing Develocity: $develocityUrl, allowUntrustedServer: $develocityAllowUntrustedServer, captureFileFingerprints: $develocityCaptureFileFingerprints") 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))
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))
} }
} }
} }
@@ -360,4 +373,42 @@ static boolean isAtLeast(String versionUnderTest, String referenceVersion) {
static boolean isNotAtLeast(String versionUnderTest, String referenceVersion) { static boolean isNotAtLeast(String versionUnderTest, String referenceVersion) {
!isAtLeast(versionUnderTest, 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 os from 'os'
import * as caches from './caching/caches' import * as caches from './caching/caches'
import * as jobSummary from './job-summary' 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 {loadBuildResults, markBuildResultsProcessed} from './build-results'
import {CacheListener, generateCachingReport} from './caching/cache-reporting' 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()) core.saveState(CACHE_LISTENER, cacheListener.stringify())
buildScan.setup(buildScanConfig) await buildScan.setup(buildScanConfig)
return true 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", "version": "8.7",
"checksum": "cb0da6751c2b753a16ac168bb354870ebb1e162e9083f116729cec9c781156b8" "checksum": "cb0da6751c2b753a16ac168bb354870ebb1e162e9083f116729cec9c781156b8"

View File

@@ -20,7 +20,7 @@ dependencies {
testImplementation ('io.ratpack:ratpack-groovy-test:1.9.0') { testImplementation ('io.ratpack:ratpack-groovy-test:1.9.0') {
exclude group: 'org.codehaus.groovy', module: 'groovy-all' 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 { test {

View File

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

View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (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. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

View File

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

View File

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

View File

@@ -16,7 +16,7 @@ import java.nio.file.Files
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
class BaseInitScriptTest extends Specification { class BaseInitScriptTest extends Specification {
static final String DEVELOCITY_PLUGIN_VERSION = '3.17.2' static final String DEVELOCITY_PLUGIN_VERSION = '3.17.5'
static final String CCUD_PLUGIN_VERSION = '2.0.1' 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_3_X = new TestGradleVersion(GradleVersion.version('3.5.1'), 7, 9)
@@ -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_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_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_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 = [ static final List<TestGradleVersion> ALL_VERSIONS = [
GRADLE_3_X, // First version where TestKit supports environment variables GRADLE_3_X, // First version where TestKit supports environment variables

View File

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

View File

@@ -146,7 +146,7 @@ class TestDependencyGraph extends BaseInitScriptTest {
then: then:
assert reportFile.exists() 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: where:
testGradleVersion << DEPENDENCY_GRAPH_VERSIONS testGradleVersion << DEPENDENCY_GRAPH_VERSIONS
@@ -170,7 +170,7 @@ class TestDependencyGraph extends BaseInitScriptTest {
then: then:
assert reportFile.exists() 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") assert result.output.contains("Applying credentials for plugin repository: https://plugins.grdev.net/m2")
where: where:

View File

@@ -1,4 +1,6 @@
import * as exec from '@actions/exec' import * as exec from '@actions/exec'
import * as core from '@actions/core'
import * as glob from '@actions/glob'
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import {CacheCleaner} from '../../src/caching/cache-cleaner' 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 runGradleBuild(projectRoot, 'build', '3.1')
await cacheCleaner.prepare() const timestamp = await cacheCleaner.prepare()
await runGradleBuild(projectRoot, 'build', '3.1.1') 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(commonsMath31)).toBe(true)
expect(fs.existsSync(commonsMath311)).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(commonsMath31)).toBe(false)
expect(fs.existsSync(commonsMath311)).toBe(true) 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 () => { 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 // Initialize HOME with 2 different Gradle versions
await runGradleWrapperBuild(projectRoot, 'build') await runGradleWrapperBuild(projectRoot, 'build')
await runGradleBuild(projectRoot, 'build') await runGradleBuild(projectRoot, 'build')
await cacheCleaner.prepare() const timestamp = await cacheCleaner.prepare()
// Run with only one of these versions // Run with only one of these versions
await runGradleBuild(projectRoot, 'build') await runGradleBuild(projectRoot, 'build')
const gradle802 = path.resolve(gradleUserHome, "caches/8.0.2") 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 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(gradle802)).toBe(true)
expect(fs.existsSync(transforms3)).toBe(true)
expect(fs.existsSync(metadata100)).toBe(true)
expect(fs.existsSync(wrapper802)).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(gradle802)).toBe(false)
expect(fs.existsSync(transforms3)).toBe(false)
expect(fs.existsSync(metadata100)).toBe(false)
expect(fs.existsSync(wrapper802)).toBe(false) expect(fs.existsSync(wrapper802)).toBe(false)
expect(fs.existsSync(gradleCurrent)).toBe(true) 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> { async function runGradleBuild(projectRoot: string, args: string, version: string = '3.1'): Promise<void> {
@@ -85,3 +101,9 @@ function prepareTestProject(): string {
return projectRoot 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,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()
})
})