mirror of
https://github.com/gradle/gradle-build-action.git
synced 2024-11-22 09:02:50 +00:00
Merge pull request #968 : Prepare for version 3.x
Contains all functionality planned for the initial 3.x release. - Fixes #726 - Fixes #946 - Fixes #966 - Fixes #996
This commit is contained in:
commit
a7b743845f
19 changed files with 18101 additions and 5972 deletions
2
.github/workflows/ci-full-check.yml
vendored
2
.github/workflows/ci-full-check.yml
vendored
|
@ -25,7 +25,7 @@ jobs:
|
||||||
cache-key-prefix: ${{github.run_number}}-
|
cache-key-prefix: ${{github.run_number}}-
|
||||||
|
|
||||||
caching-config:
|
caching-config:
|
||||||
uses: ./.github/workflows/integ-test-action-inputs-caching.yml
|
uses: ./.github/workflows/integ-test-caching-config.yml
|
||||||
with:
|
with:
|
||||||
cache-key-prefix: ${{github.run_number}}-
|
cache-key-prefix: ${{github.run_number}}-
|
||||||
|
|
||||||
|
|
14
.github/workflows/ci-quick-check.yml
vendored
14
.github/workflows/ci-quick-check.yml
vendored
|
@ -45,7 +45,7 @@ jobs:
|
||||||
|
|
||||||
caching-config:
|
caching-config:
|
||||||
needs: build-distribution
|
needs: build-distribution
|
||||||
uses: ./.github/workflows/integ-test-action-inputs-caching.yml
|
uses: ./.github/workflows/integ-test-caching-config.yml
|
||||||
with:
|
with:
|
||||||
runner-os: '["ubuntu-latest"]'
|
runner-os: '["ubuntu-latest"]'
|
||||||
download-dist: true
|
download-dist: true
|
||||||
|
@ -87,12 +87,12 @@ jobs:
|
||||||
runner-os: '["ubuntu-latest"]'
|
runner-os: '["ubuntu-latest"]'
|
||||||
download-dist: true
|
download-dist: true
|
||||||
|
|
||||||
# restore-configuration-cache:
|
restore-configuration-cache:
|
||||||
# needs: build-distribution
|
needs: build-distribution
|
||||||
# uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
|
uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
|
||||||
# with:
|
with:
|
||||||
# runner-os: '["ubuntu-latest"]'
|
runner-os: '["ubuntu-latest"]'
|
||||||
# download-dist: true
|
download-dist: true
|
||||||
|
|
||||||
restore-containerized-gradle-home:
|
restore-containerized-gradle-home:
|
||||||
needs: build-distribution
|
needs: build-distribution
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name: Test action inputs for caching
|
name: Test caching configuration
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
@ -38,7 +38,8 @@ jobs:
|
||||||
enterprise
|
enterprise
|
||||||
# Exclude build-cache from main cache entry
|
# Exclude build-cache from main cache entry
|
||||||
gradle-home-cache-excludes: |
|
gradle-home-cache-excludes: |
|
||||||
caches/build-cache-1
|
caches/build-cache-*
|
||||||
|
caches/*/executionHistory
|
||||||
- name: Build using Gradle wrapper
|
- name: Build using Gradle wrapper
|
||||||
working-directory: .github/workflow-samples/groovy-dsl
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
run: ./gradlew test
|
run: ./gradlew test
|
||||||
|
@ -63,7 +64,8 @@ jobs:
|
||||||
caches
|
caches
|
||||||
enterprise
|
enterprise
|
||||||
gradle-home-cache-excludes: |
|
gradle-home-cache-excludes: |
|
||||||
caches/build-cache-1
|
caches/build-cache-*
|
||||||
|
caches/*/executionHistory
|
||||||
cache-read-only: true
|
cache-read-only: true
|
||||||
- name: Execute Gradle build with --offline
|
- name: Execute Gradle build with --offline
|
||||||
working-directory: .github/workflow-samples/groovy-dsl
|
working-directory: .github/workflow-samples/groovy-dsl
|
|
@ -34,9 +34,11 @@ jobs:
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
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
|
||||||
|
cache-encryption-key: Da25KUVSE5jbGds2zXmfXw==
|
||||||
|
gradle-version: release-nightly
|
||||||
- name: Groovy build with configuration-cache enabled
|
- name: Groovy build with configuration-cache enabled
|
||||||
working-directory: .github/workflow-samples/groovy-dsl
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
run: ./gradlew test --configuration-cache
|
run: gradle test --configuration-cache
|
||||||
|
|
||||||
verify-build-groovy:
|
verify-build-groovy:
|
||||||
env:
|
env:
|
||||||
|
@ -55,10 +57,12 @@ jobs:
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
cache-read-only: true
|
cache-read-only: true
|
||||||
|
cache-encryption-key: Da25KUVSE5jbGds2zXmfXw==
|
||||||
|
gradle-version: release-nightly
|
||||||
- name: Groovy build with configuration-cache enabled
|
- name: Groovy build with configuration-cache enabled
|
||||||
id: execute
|
id: execute
|
||||||
working-directory: .github/workflow-samples/groovy-dsl
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
run: ./gradlew test --configuration-cache
|
run: gradle test --configuration-cache
|
||||||
- name: Check that configuration-cache was used
|
- name: Check that configuration-cache was used
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
|
@ -88,9 +92,11 @@ jobs:
|
||||||
GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl"
|
GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl"
|
||||||
with:
|
with:
|
||||||
cache-read-only: true
|
cache-read-only: true
|
||||||
|
cache-encryption-key: Da25KUVSE5jbGds2zXmfXw==
|
||||||
|
gradle-version: release-nightly
|
||||||
- name: Check execute Gradle build with configuration cache enabled (but not restored)
|
- name: Check execute Gradle build with configuration cache enabled (but not restored)
|
||||||
working-directory: .github/workflow-samples/groovy-dsl
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
run: ./gradlew test --configuration-cache
|
run: gradle test --configuration-cache
|
||||||
|
|
||||||
seed-build-kotlin:
|
seed-build-kotlin:
|
||||||
env:
|
env:
|
||||||
|
@ -108,9 +114,11 @@ jobs:
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
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
|
||||||
|
cache-encryption-key: Da25KUVSE5jbGds2zXmfXw==
|
||||||
|
gradle-version: release-nightly
|
||||||
- name: Execute 'help' with configuration-cache enabled
|
- name: Execute 'help' with configuration-cache enabled
|
||||||
working-directory: .github/workflow-samples/kotlin-dsl
|
working-directory: .github/workflow-samples/kotlin-dsl
|
||||||
run: ./gradlew help --configuration-cache
|
run: gradle help --configuration-cache
|
||||||
|
|
||||||
modify-build-kotlin:
|
modify-build-kotlin:
|
||||||
env:
|
env:
|
||||||
|
@ -129,9 +137,11 @@ jobs:
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
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
|
||||||
|
cache-encryption-key: Da25KUVSE5jbGds2zXmfXw==
|
||||||
|
gradle-version: release-nightly
|
||||||
- name: Execute 'test' with configuration-cache enabled
|
- name: Execute 'test' with configuration-cache enabled
|
||||||
working-directory: .github/workflow-samples/kotlin-dsl
|
working-directory: .github/workflow-samples/kotlin-dsl
|
||||||
run: ./gradlew test --configuration-cache
|
run: gradle test --configuration-cache
|
||||||
|
|
||||||
# Test restore configuration-cache from the third build invocation
|
# Test restore configuration-cache from the third build invocation
|
||||||
verify-build-kotlin:
|
verify-build-kotlin:
|
||||||
|
@ -151,10 +161,12 @@ jobs:
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
cache-read-only: true
|
cache-read-only: true
|
||||||
|
cache-encryption-key: Da25KUVSE5jbGds2zXmfXw==
|
||||||
|
gradle-version: release-nightly
|
||||||
- name: Execute 'test' again with configuration-cache enabled
|
- name: Execute 'test' again with configuration-cache enabled
|
||||||
id: execute
|
id: execute
|
||||||
working-directory: .github/workflow-samples/kotlin-dsl
|
working-directory: .github/workflow-samples/kotlin-dsl
|
||||||
run: ./gradlew test --configuration-cache
|
run: gradle test --configuration-cache
|
||||||
- name: Check that configuration-cache was used
|
- name: Check that configuration-cache was used
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
# Configuration file for asdf version manager
|
# Configuration file for asdf version manager
|
||||||
nodejs 16.18.1
|
nodejs 20.10.0
|
||||||
gradle 8.5
|
gradle 8.5
|
||||||
|
|
98
README.md
98
README.md
|
@ -97,7 +97,6 @@ jobs:
|
||||||
- run: echo "The release-candidate version was ${{ steps.setup-gradle.outputs.gradle-version }}"
|
- run: echo "The release-candidate version was ${{ steps.setup-gradle.outputs.gradle-version }}"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Caching build state between Jobs
|
## Caching build state between Jobs
|
||||||
|
|
||||||
The `gradle-build-action` will use the GitHub Actions cache to save and restore reusable state that may be speed up a subsequent build invocation. This includes most content that is downloaded from the internet as part of a build, as well as expensive to create content like compiled build scripts, transformed Jar files, etc.
|
The `gradle-build-action` will use the GitHub Actions cache to save and restore reusable state that may be speed up a subsequent build invocation. This includes most content that is downloaded from the internet as part of a build, as well as expensive to create content like compiled build scripts, transformed Jar files, etc.
|
||||||
|
@ -423,103 +422,6 @@ jobs:
|
||||||
path: build/reports/
|
path: build/reports/
|
||||||
```
|
```
|
||||||
|
|
||||||
## Use the action to invoke Gradle
|
|
||||||
|
|
||||||
If the `gradle-build-action` is configured with an `arguments` input, then Gradle will execute a Gradle build with the arguments provided. NOTE: We recommend using the `gradle-build-action` as a "Setup Gradle" step as described above, with Gradle being invoked via a regular `run` command.
|
|
||||||
|
|
||||||
If no `arguments` are provided, the action will not execute Gradle, but will still cache Gradle state and configure build-scan capture for all subsequent Gradle executions.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: Run Gradle on PRs
|
|
||||||
on: pull_request
|
|
||||||
jobs:
|
|
||||||
gradle:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-java@v3
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: 11
|
|
||||||
|
|
||||||
- name: Setup and execute Gradle 'test' task
|
|
||||||
uses: gradle/gradle-build-action@v2
|
|
||||||
with:
|
|
||||||
arguments: test
|
|
||||||
```
|
|
||||||
|
|
||||||
### Multiple Gradle executions in the same Job
|
|
||||||
|
|
||||||
It is possible to configure multiple Gradle executions to run sequentially in the same job.
|
|
||||||
The initial Action step will perform the Gradle setup.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: gradle/gradle-build-action@v2
|
|
||||||
with:
|
|
||||||
arguments: assemble
|
|
||||||
- uses: gradle/gradle-build-action@v2
|
|
||||||
with:
|
|
||||||
arguments: check
|
|
||||||
```
|
|
||||||
|
|
||||||
### Gradle command-line arguments
|
|
||||||
|
|
||||||
The `arguments` input can be used to pass arbitrary arguments to the `gradle` command line.
|
|
||||||
Arguments can be supplied in a single line, or as a multi-line input.
|
|
||||||
|
|
||||||
Here are some valid examples:
|
|
||||||
```yaml
|
|
||||||
arguments: build
|
|
||||||
arguments: check --scan
|
|
||||||
arguments: some arbitrary tasks
|
|
||||||
arguments: build -PgradleProperty=foo
|
|
||||||
arguments: |
|
|
||||||
build
|
|
||||||
--scan
|
|
||||||
-PgradleProperty=foo
|
|
||||||
-DsystemProperty=bar
|
|
||||||
```
|
|
||||||
|
|
||||||
If you need to pass environment variables, use the GitHub Actions workflow syntax:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: gradle/gradle-build-action@v2
|
|
||||||
env:
|
|
||||||
CI: true
|
|
||||||
with:
|
|
||||||
arguments: build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Gradle build located in a subdirectory
|
|
||||||
|
|
||||||
By default, the action will execute Gradle in the root directory of your project.
|
|
||||||
Use the `build-root-directory` input to target a Gradle build in a subdirectory.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: gradle/gradle-build-action@v2
|
|
||||||
with:
|
|
||||||
arguments: build
|
|
||||||
build-root-directory: some/subdirectory
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using a specific Gradle executable
|
|
||||||
|
|
||||||
The action will first look for a Gradle wrapper script in the root directory of your project.
|
|
||||||
If not found, `gradle` will be executed from the PATH.
|
|
||||||
Use the `gradle-executable` input to execute using a specific Gradle installation.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: gradle/gradle-build-action@v2
|
|
||||||
with:
|
|
||||||
arguments: build
|
|
||||||
gradle-executable: /path/to/installed/gradle
|
|
||||||
```
|
|
||||||
|
|
||||||
This mechanism can also be used to target a Gradle wrapper script that is located in a non-default location.
|
|
||||||
|
|
||||||
## Support for GitHub Enterprise Server (GHES)
|
## Support for GitHub Enterprise Server (GHES)
|
||||||
|
|
||||||
You can use the `gradle-build-action` on GitHub Enterprise Server, and benefit from the improved integration with Gradle. Depending on the version of GHES you are running, certain features may be limited:
|
You can use the `gradle-build-action` on GitHub Enterprise Server, and benefit from the improved integration with Gradle. Depending on the version of GHES you are running, certain features may be limited:
|
||||||
|
|
38
action.yml
38
action.yml
|
@ -8,14 +8,6 @@ inputs:
|
||||||
description: Gradle version to use. If specified, this Gradle version will be downloaded, added to the PATH and used for invoking Gradle.
|
description: Gradle version to use. If specified, this Gradle version will be downloaded, added to the PATH and used for invoking Gradle.
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
gradle-executable:
|
|
||||||
description: Path to the Gradle executable. If specified, this executable will be added to the PATH and used for invoking Gradle.
|
|
||||||
required: false
|
|
||||||
|
|
||||||
build-root-directory:
|
|
||||||
description: Path to the root directory of the build. Default is the root of the GitHub workspace.
|
|
||||||
required: false
|
|
||||||
|
|
||||||
cache-disabled:
|
cache-disabled:
|
||||||
description: When 'true', all caching is disabled. No entries will be written to or read from the cache.
|
description: When 'true', all caching is disabled. No entries will be written to or read from the cache.
|
||||||
required: false
|
required: false
|
||||||
|
@ -40,6 +32,13 @@ inputs:
|
||||||
required: false
|
required: false
|
||||||
default: false
|
default: false
|
||||||
|
|
||||||
|
cache-encryption-key:
|
||||||
|
description: |
|
||||||
|
A base64 encoded AES key used to encrypt the configuration-cache data. The key is exported as 'GRADLE_ENCRYPTION_KEY' for later steps.
|
||||||
|
A suitable key can be generated with `openssl rand -base64 16`.
|
||||||
|
Configuration-cache data will not be saved/restored without an encryption key being provided.
|
||||||
|
required: false
|
||||||
|
|
||||||
gradle-home-cache-includes:
|
gradle-home-cache-includes:
|
||||||
description: Paths within Gradle User Home to cache.
|
description: Paths within Gradle User Home to cache.
|
||||||
required: false
|
required: false
|
||||||
|
@ -59,10 +58,6 @@ inputs:
|
||||||
required: false
|
required: false
|
||||||
default: false
|
default: false
|
||||||
|
|
||||||
arguments:
|
|
||||||
description: Gradle command line arguments (supports multi-line input)
|
|
||||||
required: false
|
|
||||||
|
|
||||||
generate-job-summary:
|
generate-job-summary:
|
||||||
description: When 'false', no Job Summary will be generated for the Job.
|
description: When 'false', no Job Summary will be generated for the Job.
|
||||||
required: false
|
required: false
|
||||||
|
@ -77,6 +72,22 @@ inputs:
|
||||||
description: Specifies the number of days to retain any artifacts generated by the action. If not set, the default retention settings for the repository will apply.
|
description: Specifies the number of days to retain any artifacts generated by the action. If not set, the default retention settings for the repository will apply.
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
|
# DEPRECATED ACTION INPUTS
|
||||||
|
arguments:
|
||||||
|
description: Gradle command line arguments (supports multi-line input)
|
||||||
|
required: false
|
||||||
|
deprecation-message: Using the action to execute Gradle directly is deprecated in favor of using the action to setup Gradle, and executing Gradle in a subsequent Step. See https://github.com/gradle/gradle-build-action?tab=readme-ov-file#use-the-action-to-setup-gradle.
|
||||||
|
|
||||||
|
build-root-directory:
|
||||||
|
description: Path to the root directory of the build. Default is the root of the GitHub workspace.
|
||||||
|
required: false
|
||||||
|
deprecation-message: Using the action to execute Gradle directly is deprecated in favor of using the action to setup Gradle, and executing Gradle in a subsequent Step. See https://github.com/gradle/gradle-build-action?tab=readme-ov-file#use-the-action-to-setup-gradle.
|
||||||
|
|
||||||
|
gradle-executable:
|
||||||
|
description: Path to the Gradle executable. If specified, this executable will be added to the PATH and used for invoking Gradle.
|
||||||
|
required: false
|
||||||
|
deprecation-message: Using the action to execute Gradle directly is deprecated in favor of using the action to setup Gradle, and executing Gradle in a subsequent Step. See https://github.com/gradle/gradle-build-action?tab=readme-ov-file#use-the-action-to-setup-gradle.
|
||||||
|
|
||||||
# EXPERIMENTAL & INTERNAL ACTION INPUTS
|
# EXPERIMENTAL & INTERNAL ACTION INPUTS
|
||||||
# The following action properties allow fine-grained tweaking of the action caching behaviour.
|
# The following action properties allow fine-grained tweaking of the action caching behaviour.
|
||||||
# These properties are experimental and not (yet) designed for production use, and may change without notice in a subsequent release of `gradle-build-action`.
|
# These properties are experimental and not (yet) designed for production use, and may change without notice in a subsequent release of `gradle-build-action`.
|
||||||
|
@ -85,6 +96,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
|
||||||
|
|
||||||
workflow-job-context:
|
workflow-job-context:
|
||||||
description: Used to uniquely identify the current job invocation. Defaults to the matrix values for this job; this should not be overridden by users (INTERNAL).
|
description: Used to uniquely identify the current job invocation. Defaults to the matrix values for this job; this should not be overridden by users (INTERNAL).
|
||||||
required: false
|
required: false
|
||||||
|
@ -104,7 +116,7 @@ outputs:
|
||||||
description: Version of Gradle that was setup by the action
|
description: Version of Gradle that was setup by the action
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node20'
|
||||||
main: 'dist/main/index.js'
|
main: 'dist/main/index.js'
|
||||||
post: 'dist/post/index.js'
|
post: 'dist/post/index.js'
|
||||||
|
|
||||||
|
|
11344
dist/main/index.js
vendored
11344
dist/main/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/main/index.js.map
vendored
2
dist/main/index.js.map
vendored
File diff suppressed because one or more lines are too long
11344
dist/post/index.js
vendored
11344
dist/post/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/post/index.js.map
vendored
2
dist/post/index.js.map
vendored
File diff suppressed because one or more lines are too long
1020
package-lock.json
generated
1020
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -8,11 +8,9 @@
|
||||||
"format": "prettier --write **/*.ts",
|
"format": "prettier --write **/*.ts",
|
||||||
"format-check": "prettier --check **/*.ts",
|
"format-check": "prettier --check **/*.ts",
|
||||||
"lint": "eslint src/**/*.ts",
|
"lint": "eslint src/**/*.ts",
|
||||||
|
|
||||||
"compile-main": "ncc build src/main.ts --out dist/main --source-map --no-source-map-register",
|
"compile-main": "ncc build src/main.ts --out dist/main --source-map --no-source-map-register",
|
||||||
"compile-post": "ncc build src/post.ts --out dist/post --source-map --no-source-map-register",
|
"compile-post": "ncc build src/post.ts --out dist/post --source-map --no-source-map-register",
|
||||||
"compile": "npm run compile-main && npm run compile-post",
|
"compile": "npm run compile-main && npm run compile-post",
|
||||||
|
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"check": "npm run format && npm run lint",
|
"check": "npm run format && npm run lint",
|
||||||
"build": "npm run check && npm run compile",
|
"build": "npm run check && npm run compile",
|
||||||
|
@ -34,17 +32,18 @@
|
||||||
"@actions/cache": "3.2.2",
|
"@actions/cache": "3.2.2",
|
||||||
"@actions/core": "1.10.1",
|
"@actions/core": "1.10.1",
|
||||||
"@actions/exec": "1.1.1",
|
"@actions/exec": "1.1.1",
|
||||||
"@actions/github": "5.1.1",
|
"@actions/github": "6.0.0",
|
||||||
"@actions/glob": "0.4.0",
|
"@actions/glob": "0.4.0",
|
||||||
"@actions/http-client": "2.2.0",
|
"@actions/http-client": "2.2.0",
|
||||||
"@actions/tool-cache": "2.0.1",
|
"@actions/tool-cache": "2.0.1",
|
||||||
"@octokit/rest": "19.0.13",
|
"@octokit/rest": "19.0.13",
|
||||||
"@octokit/webhooks-types": "7.3.1",
|
"@octokit/webhooks-types": "7.3.1",
|
||||||
|
"semver": "^7.5.4",
|
||||||
"string-argv": "0.3.2"
|
"string-argv": "0.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "16.18.38",
|
|
||||||
"@types/jest": "29.5.11",
|
"@types/jest": "29.5.11",
|
||||||
|
"@types/node": "20.10.0",
|
||||||
"@types/unzipper": "0.10.9",
|
"@types/unzipper": "0.10.9",
|
||||||
"@typescript-eslint/parser": "6.14.0",
|
"@typescript-eslint/parser": "6.14.0",
|
||||||
"@vercel/ncc": "0.38.1",
|
"@vercel/ncc": "0.38.1",
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
|
import * as glob from '@actions/glob'
|
||||||
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import * as params from './input-params'
|
import * as params from './input-params'
|
||||||
import {CacheListener} from './cache-reporting'
|
import {CacheListener} from './cache-reporting'
|
||||||
import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete, generateCacheKey} from './cache-utils'
|
import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete, generateCacheKey} from './cache-utils'
|
||||||
import {GradleHomeEntryExtractor} from './cache-extract-entries'
|
import {GradleHomeEntryExtractor, ConfigurationCacheEntryExtractor} from './cache-extract-entries'
|
||||||
|
|
||||||
const RESTORED_CACHE_KEY_KEY = 'restored-cache-key'
|
const RESTORED_CACHE_KEY_KEY = 'restored-cache-key'
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@ export class GradleStateCache {
|
||||||
async afterRestore(listener: CacheListener): Promise<void> {
|
async afterRestore(listener: CacheListener): Promise<void> {
|
||||||
await this.debugReportGradleUserHomeSize('as restored from cache')
|
await this.debugReportGradleUserHomeSize('as restored from cache')
|
||||||
await new GradleHomeEntryExtractor(this.gradleUserHome).restore(listener)
|
await new GradleHomeEntryExtractor(this.gradleUserHome).restore(listener)
|
||||||
// await new ConfigurationCacheEntryExtractor(this.gradleUserHome).restore(listener)
|
await new ConfigurationCacheEntryExtractor(this.gradleUserHome).restore(listener)
|
||||||
await this.debugReportGradleUserHomeSize('after restoring common artifacts')
|
await this.debugReportGradleUserHomeSize('after restoring common artifacts')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,10 +129,10 @@ export class GradleStateCache {
|
||||||
*/
|
*/
|
||||||
async beforeSave(listener: CacheListener): Promise<void> {
|
async beforeSave(listener: CacheListener): Promise<void> {
|
||||||
await this.debugReportGradleUserHomeSize('before saving common artifacts')
|
await this.debugReportGradleUserHomeSize('before saving common artifacts')
|
||||||
this.deleteExcludedPaths()
|
await this.deleteExcludedPaths()
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
new GradleHomeEntryExtractor(this.gradleUserHome).extract(listener)
|
new GradleHomeEntryExtractor(this.gradleUserHome).extract(listener),
|
||||||
// new ConfigurationCacheEntryExtractor(this.gradleUserHome).extract(listener)
|
new ConfigurationCacheEntryExtractor(this.gradleUserHome).extract(listener)
|
||||||
])
|
])
|
||||||
await this.debugReportGradleUserHomeSize(
|
await this.debugReportGradleUserHomeSize(
|
||||||
"after extracting common artifacts (only 'caches' and 'notifications' will be stored)"
|
"after extracting common artifacts (only 'caches' and 'notifications' will be stored)"
|
||||||
|
@ -140,13 +142,21 @@ export class GradleStateCache {
|
||||||
/**
|
/**
|
||||||
* Delete any file paths that are excluded by the `gradle-home-cache-excludes` parameter.
|
* Delete any file paths that are excluded by the `gradle-home-cache-excludes` parameter.
|
||||||
*/
|
*/
|
||||||
private deleteExcludedPaths(): void {
|
private async deleteExcludedPaths(): Promise<void> {
|
||||||
const rawPaths: string[] = params.getCacheExcludes()
|
const rawPaths: string[] = params.getCacheExcludes()
|
||||||
|
rawPaths.push('caches/*/cc-keystore')
|
||||||
const resolvedPaths = rawPaths.map(x => path.resolve(this.gradleUserHome, x))
|
const resolvedPaths = rawPaths.map(x => path.resolve(this.gradleUserHome, x))
|
||||||
|
|
||||||
for (const p of resolvedPaths) {
|
for (const p of resolvedPaths) {
|
||||||
cacheDebug(`Deleting excluded path: ${p}`)
|
cacheDebug(`Removing excluded path: ${p}`)
|
||||||
tryDelete(p)
|
const globber = await glob.create(p, {
|
||||||
|
implicitDescendants: false
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const toDelete of await globber.glob()) {
|
||||||
|
cacheDebug(`Removing excluded file: ${toDelete}`)
|
||||||
|
await tryDelete(toDelete)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
import crypto from 'crypto'
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as glob from '@actions/glob'
|
import * as glob from '@actions/glob'
|
||||||
|
import * as semver from 'semver'
|
||||||
|
|
||||||
import * as params from './input-params'
|
import * as params from './input-params'
|
||||||
|
|
||||||
import {META_FILE_DIR} from './cache-base'
|
import {META_FILE_DIR} from './cache-base'
|
||||||
import {CacheEntryListener, CacheListener} from './cache-reporting'
|
import {CacheEntryListener, CacheListener} from './cache-reporting'
|
||||||
import {cacheDebug, getCacheKeyPrefix, hashFileNames, restoreCache, saveCache, tryDelete} from './cache-utils'
|
import {cacheDebug, getCacheKeyPrefix, hashFileNames, restoreCache, saveCache, tryDelete} from './cache-utils'
|
||||||
import {loadBuildResults} from './build-results'
|
import {BuildResult, loadBuildResults} from './build-results'
|
||||||
|
|
||||||
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'
|
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ class ExtractedCacheEntryDefinition {
|
||||||
pattern: string
|
pattern: string
|
||||||
bundle: boolean
|
bundle: boolean
|
||||||
uniqueFileNames = true
|
uniqueFileNames = true
|
||||||
|
notCacheableReason: string | undefined
|
||||||
|
|
||||||
constructor(artifactType: string, pattern: string, bundle: boolean) {
|
constructor(artifactType: string, pattern: string, bundle: boolean) {
|
||||||
this.artifactType = artifactType
|
this.artifactType = artifactType
|
||||||
|
@ -53,10 +56,24 @@ class ExtractedCacheEntryDefinition {
|
||||||
this.bundle = bundle
|
this.bundle = bundle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate that the file names matching the cache entry pattern are NOT sufficient to uniquely identify the contents.
|
||||||
|
* If the file names are sufficient, then we use a hash of the file names to identify the entry.
|
||||||
|
* With non-unique-file-names, we hash the file contents to identify the cache entry.
|
||||||
|
*/
|
||||||
withNonUniqueFileNames(): ExtractedCacheEntryDefinition {
|
withNonUniqueFileNames(): ExtractedCacheEntryDefinition {
|
||||||
this.uniqueFileNames = false
|
this.uniqueFileNames = false
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify that the cache entry, should not be saved for some reason, even though the contents exist.
|
||||||
|
* This is used to prevent configuration-cache entries being cached when they were generated by Gradle < 8.6,
|
||||||
|
*/
|
||||||
|
notCacheableBecause(reason: string): ExtractedCacheEntryDefinition {
|
||||||
|
this.notCacheableReason = reason
|
||||||
|
return this
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,6 +159,11 @@ abstract class AbstractEntryExtractor {
|
||||||
const artifactType = cacheEntryDefinition.artifactType
|
const artifactType = cacheEntryDefinition.artifactType
|
||||||
const pattern = cacheEntryDefinition.pattern
|
const pattern = cacheEntryDefinition.pattern
|
||||||
|
|
||||||
|
if (cacheEntryDefinition.notCacheableReason) {
|
||||||
|
listener.entry(pattern).markNotSaved(cacheEntryDefinition.notCacheableReason)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Find all matching files for this cache entry definition
|
// Find all matching files for this cache entry definition
|
||||||
const globber = await glob.create(pattern, {
|
const globber = await glob.create(pattern, {
|
||||||
implicitDescendants: false
|
implicitDescendants: false
|
||||||
|
@ -256,7 +278,7 @@ abstract class AbstractEntryExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
const filedata = fs.readFileSync(cacheMetadataFile, 'utf-8')
|
const filedata = fs.readFileSync(cacheMetadataFile, 'utf-8')
|
||||||
cacheDebug(`Loaded cache metadata: ${filedata}`)
|
cacheDebug(`Loaded cache metadata for ${this.extractorName}: ${filedata}`)
|
||||||
const extractedCacheEntryMetadata = JSON.parse(filedata) as ExtractedCacheEntryMetadata
|
const extractedCacheEntryMetadata = JSON.parse(filedata) as ExtractedCacheEntryMetadata
|
||||||
return extractedCacheEntryMetadata.entries
|
return extractedCacheEntryMetadata.entries
|
||||||
}
|
}
|
||||||
|
@ -264,12 +286,12 @@ abstract class AbstractEntryExtractor {
|
||||||
/**
|
/**
|
||||||
* Saves information about the extracted cache entries into the 'cache-metadata.json' file.
|
* Saves information about the extracted cache entries into the 'cache-metadata.json' file.
|
||||||
*/
|
*/
|
||||||
private saveMetadataForCacheResults(results: ExtractedCacheEntry[]): void {
|
protected saveMetadataForCacheResults(results: ExtractedCacheEntry[]): void {
|
||||||
const extractedCacheEntryMetadata = new ExtractedCacheEntryMetadata()
|
const extractedCacheEntryMetadata = new ExtractedCacheEntryMetadata()
|
||||||
extractedCacheEntryMetadata.entries = results.filter(x => x.cacheKey !== undefined)
|
extractedCacheEntryMetadata.entries = results.filter(x => x.cacheKey !== undefined)
|
||||||
|
|
||||||
const filedata = JSON.stringify(extractedCacheEntryMetadata)
|
const filedata = JSON.stringify(extractedCacheEntryMetadata)
|
||||||
cacheDebug(`Saving cache metadata: ${filedata}`)
|
cacheDebug(`Saving cache metadata for ${this.extractorName}: ${filedata}`)
|
||||||
|
|
||||||
fs.writeFileSync(this.getCacheMetadataFile(), filedata, 'utf-8')
|
fs.writeFileSync(this.getCacheMetadataFile(), filedata, 'utf-8')
|
||||||
}
|
}
|
||||||
|
@ -351,37 +373,104 @@ export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor {
|
||||||
* entry is not reusable.
|
* entry is not reusable.
|
||||||
*/
|
*/
|
||||||
async restore(listener: CacheListener): Promise<void> {
|
async restore(listener: CacheListener): Promise<void> {
|
||||||
if (listener.fullyRestored) {
|
if (!listener.fullyRestored) {
|
||||||
return super.restore(listener)
|
this.markNotRestored(listener, 'Gradle User Home was not fully restored')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info('Not restoring configuration-cache state, as Gradle User Home was not fully restored')
|
if (!params.getCacheEncryptionKey()) {
|
||||||
for (const cacheEntry of this.loadExtractedCacheEntries()) {
|
this.markNotRestored(listener, 'Encryption Key was not provided')
|
||||||
listener.entry(cacheEntry.pattern).markRequested('NOT_RESTORED')
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const encryptionKey = this.getAESEncryptionKey()
|
||||||
|
core.exportVariable('GRADLE_ENCRYPTION_KEY', encryptionKey)
|
||||||
|
return await super.restore(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
private markNotRestored(listener: CacheListener, reason: string): void {
|
||||||
|
const cacheEntries = this.loadExtractedCacheEntries()
|
||||||
|
if (cacheEntries.length > 0) {
|
||||||
|
core.info(`Not restoring configuration-cache state, as ${reason}`)
|
||||||
|
for (const cacheEntry of cacheEntries) {
|
||||||
|
listener.entry(cacheEntry.pattern).markNotRestored(reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the results file based on no entries restored
|
||||||
|
this.saveMetadataForCacheResults([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async extract(listener: CacheListener): Promise<void> {
|
||||||
|
if (!params.getCacheEncryptionKey()) {
|
||||||
|
const cacheEntryDefinitions = this.getExtractedCacheEntryDefinitions()
|
||||||
|
if (cacheEntryDefinitions.length > 0) {
|
||||||
|
core.info('Not saving configuration-cache state, as no encryption key was provided')
|
||||||
|
for (const cacheEntry of cacheEntryDefinitions) {
|
||||||
|
listener.entry(cacheEntry.pattern).markNotSaved('No encryption key provided')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await super.extract(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAESEncryptionKey(): string | undefined {
|
||||||
|
const secret = params.getCacheEncryptionKey()
|
||||||
|
const key = crypto.pbkdf2Sync(secret, '', 1000, 16, 'sha256')
|
||||||
|
return key.toString('base64')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract cache entries for the configuration cache in each project.
|
* Extract cache entries for the configuration cache in each project.
|
||||||
*/
|
*/
|
||||||
protected getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[] {
|
protected getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[] {
|
||||||
return this.getProjectRoots().map(projectRoot => {
|
// Group BuildResult by existing configCacheDir
|
||||||
const configCachePath = path.resolve(projectRoot, '.gradle/configuration-cache')
|
const groupedResults = this.getConfigCacheDirectoriesWithAssociatedBuildResults()
|
||||||
return new ExtractedCacheEntryDefinition(
|
|
||||||
|
return Object.entries(groupedResults).map(([configCachePath, pathResults]) => {
|
||||||
|
// Create a entry definition for each unique configuration cache directory
|
||||||
|
const definition = new ExtractedCacheEntryDefinition(
|
||||||
'configuration-cache',
|
'configuration-cache',
|
||||||
configCachePath,
|
configCachePath,
|
||||||
true
|
true
|
||||||
).withNonUniqueFileNames()
|
).withNonUniqueFileNames()
|
||||||
|
|
||||||
|
// If any associated build result used Gradle < 8.6, then mark it as not cacheable
|
||||||
|
if (
|
||||||
|
pathResults.find(result => {
|
||||||
|
const gradleVersion = semver.coerce(result.gradleVersion)
|
||||||
|
return gradleVersion && semver.lt(gradleVersion, '8.6.0')
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
core.info(
|
||||||
|
`Not saving config-cache data for ${configCachePath}. Configuration cache data is only saved for Gradle 8.6+`
|
||||||
|
)
|
||||||
|
definition.notCacheableBecause('Configuration cache data only saved for Gradle 8.6+')
|
||||||
|
}
|
||||||
|
return definition
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private getConfigCacheDirectoriesWithAssociatedBuildResults(): Record<string, BuildResult[]> {
|
||||||
* For every Gradle invocation, we record the project root directory. This method returns the entire
|
return loadBuildResults().reduce(
|
||||||
* set of project roots, to allow saving of configuration-cache entries for each.
|
(acc, buildResult) => {
|
||||||
*/
|
// For each build result, find the config-cache dir
|
||||||
private getProjectRoots(): string[] {
|
const configCachePath = path.resolve(buildResult.rootProjectDir, '.gradle/configuration-cache')
|
||||||
const buildResults = loadBuildResults()
|
// Ignore case where config-cache dir doesn't exist
|
||||||
const projectRootDirs = buildResults.map(x => x.rootProjectDir)
|
if (!fs.existsSync(configCachePath)) {
|
||||||
return [...new Set(projectRootDirs)] // Remove duplicates
|
return acc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group by unique config cache directories and collect associated build results
|
||||||
|
if (!acc[configCachePath]) {
|
||||||
|
acc[configCachePath] = []
|
||||||
|
}
|
||||||
|
acc[configCachePath].push(buildResult)
|
||||||
|
return acc
|
||||||
|
},
|
||||||
|
{} as Record<string, BuildResult[]>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,6 +198,9 @@ function getSavedMessage(entry: CacheEntryListener, cacheReadOnly: boolean): str
|
||||||
if (cacheReadOnly) {
|
if (cacheReadOnly) {
|
||||||
return '(Entry not saved: cache is read-only)'
|
return '(Entry not saved: cache is read-only)'
|
||||||
}
|
}
|
||||||
|
if (entry.notRestored) {
|
||||||
|
return '(Entry not saved: not restored)'
|
||||||
|
}
|
||||||
return '(Entry not saved: reason unknown)'
|
return '(Entry not saved: reason unknown)'
|
||||||
}
|
}
|
||||||
if (entry.savedSize === 0) {
|
if (entry.savedSize === 0) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import * as params from './input-params'
|
||||||
|
|
||||||
import {CacheEntryListener} from './cache-reporting'
|
import {CacheEntryListener} from './cache-reporting'
|
||||||
|
|
||||||
const CACHE_PROTOCOL_VERSION = 'v8-'
|
const CACHE_PROTOCOL_VERSION = 'v9-'
|
||||||
|
|
||||||
const CACHE_KEY_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
|
const CACHE_KEY_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
|
||||||
const CACHE_KEY_OS_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_ENVIRONMENT'
|
const CACHE_KEY_OS_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_ENVIRONMENT'
|
||||||
|
|
|
@ -29,6 +29,10 @@ export function isCacheCleanupEnabled(): boolean {
|
||||||
return getBooleanInput('gradle-home-cache-cleanup')
|
return getBooleanInput('gradle-home-cache-cleanup')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCacheEncryptionKey(): string {
|
||||||
|
return core.getInput('cache-encryption-key')
|
||||||
|
}
|
||||||
|
|
||||||
export function getCacheIncludes(): string[] {
|
export function getCacheIncludes(): string[] {
|
||||||
return core.getMultilineInput('gradle-home-cache-includes')
|
return core.getMultilineInput('gradle-home-cache-includes')
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ export async function complete(): Promise<void> {
|
||||||
core.info('Gradle setup post-action only performed for first gradle-build-action step in workflow.')
|
core.info('Gradle setup post-action only performed for first gradle-build-action step in workflow.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
core.info('In final post-action step, saving state and writing summary')
|
core.info('In post-action step')
|
||||||
|
|
||||||
const buildResults = loadBuildResults()
|
const buildResults = loadBuildResults()
|
||||||
|
|
||||||
|
@ -63,6 +63,8 @@ export async function complete(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
await dependencyGraph.complete(params.getDependencyGraphOption())
|
await dependencyGraph.complete(params.getDependencyGraphOption())
|
||||||
|
|
||||||
|
core.info('Completed post-action step')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function determineGradleUserHome(): Promise<string> {
|
async function determineGradleUserHome(): Promise<string> {
|
||||||
|
|
Loading…
Reference in a new issue