mirror of
https://github.com/gradle/gradle-build-action.git
synced 2025-10-19 22:38:58 +08:00
Compare commits
70 Commits
v1.5.0
...
v2.0-beta.
Author | SHA1 | Date | |
---|---|---|---|
|
c000a0b58f | ||
|
6ff498182a | ||
|
60b1ffac6b | ||
|
9b7c81f8f6 | ||
|
b650771559 | ||
|
17f624cb5b | ||
|
21dee71590 | ||
|
83e2129213 | ||
|
b16787d530 | ||
|
204870af89 | ||
|
0918f5f2a4 | ||
|
1b1a3c48ad | ||
|
a7174b82a2 | ||
|
3de71f2c52 | ||
|
5576baa56b | ||
|
1026c62889 | ||
|
1fb8644035 | ||
|
5a5a5b4387 | ||
|
cc5cdb7fe0 | ||
|
e0d37eb073 | ||
|
bdd89aa34f | ||
|
18cdc8bf28 | ||
|
656ad4b5f2 | ||
|
bebb162342 | ||
|
6084a4eb65 | ||
|
dbb485d80d | ||
|
9bfa003014 | ||
|
fe64d05f86 | ||
|
decca791c5 | ||
|
bd08e7b7cd | ||
|
cca55d0890 | ||
|
a802a3c0ce | ||
|
d06e19f862 | ||
|
bbe1574290 | ||
|
4264cda558 | ||
|
3390540145 | ||
|
1c72a31463 | ||
|
7dfbe33bba | ||
|
e63ddf9c00 | ||
|
d5cd9d86a1 | ||
|
cae99bf6d9 | ||
|
5a90152b1f | ||
|
4b92b8d013 | ||
|
693293c29a | ||
|
ac5d8920dd | ||
|
e833360307 | ||
|
b5a08466b4 | ||
|
4032438d2b | ||
|
9b3abaad52 | ||
|
d20d631365 | ||
|
378bd0b6f8 | ||
|
6d1455a33e | ||
|
c44ebadf6f | ||
|
4d37378696 | ||
|
777a6fc967 | ||
|
d7ed6d7e8d | ||
|
0ecbac99f3 | ||
|
436390bd4e | ||
|
a587e93714 | ||
|
75e00ee3d1 | ||
|
c01af7a6f6 | ||
|
c79d4172e0 | ||
|
b85ac67c9a | ||
|
fa0c026e07 | ||
|
986024f0b7 | ||
|
6fca6b3929 | ||
|
d9cc0aeccf | ||
|
5340f6e816 | ||
|
c211be411e | ||
|
b3afdc78a7 |
3
.github/workflows/dev.yml
vendored
3
.github/workflows/dev.yml
vendored
@@ -1,5 +1,4 @@
|
||||
# make sure the build works and doesn't produce spurious changes
|
||||
name: dev
|
||||
name: Verify generated outputs
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
34
.github/workflows/failure-cases.yml
vendored
Normal file
34
.github/workflows/failure-cases.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Execute failure cases
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||
|
||||
jobs:
|
||||
|
||||
wrapper-missing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Test wrapper missing
|
||||
uses: ./
|
||||
continue-on-error: true
|
||||
with:
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help
|
||||
|
||||
bad-configuration:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Test bad config value
|
||||
uses: ./
|
||||
continue-on-error: true
|
||||
with:
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help
|
||||
cache-disabled: yes
|
84
.github/workflows/integTest-caching.yml
vendored
Normal file
84
.github/workflows/integTest-caching.yml
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
name: Test caching
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||
|
||||
jobs:
|
||||
# Run initial Gradle builds to push initial cache entries
|
||||
# These builds should start fresh without cache hits, due to the seed injected into the cache key above.
|
||||
seed-build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Build using Gradle wrapper
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/groovy-dsl
|
||||
arguments: test
|
||||
- name: Build with configuration-cache enabled
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/groovy-dsl
|
||||
arguments: test --configuration-cache
|
||||
|
||||
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
|
||||
dependencies-cache:
|
||||
needs: seed-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Execute Gradle build with --offline
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/groovy-dsl
|
||||
arguments: test --offline
|
||||
cache-read-only: true
|
||||
|
||||
# Test that the gradle-user-home cache will cache and restore local build-cache
|
||||
build-cache:
|
||||
needs: seed-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Execute Gradle build and verify tasks from cache
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/groovy-dsl
|
||||
arguments: test -DverifyCachedBuild=true
|
||||
cache-read-only: true
|
||||
|
||||
# Test that the project-dot-gradle cache will cache and restore configuration-cache
|
||||
configuration-cache:
|
||||
needs: seed-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Execute Gradle build and verify cached configuration
|
||||
uses: ./
|
||||
env:
|
||||
VERIFY_CACHED_CONFIGURATION: true
|
||||
with:
|
||||
build-root-directory: __tests__/samples/groovy-dsl
|
||||
arguments: test --configuration-cache
|
||||
cache-read-only: true
|
107
.github/workflows/integTest-execution.yml
vendored
Normal file
107
.github/workflows/integTest-execution.yml
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
name: Test Gradle execution
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||
|
||||
jobs:
|
||||
# Tests for executing with different Gradle versions.
|
||||
# Each build verifies that it is executed with the expected Gradle version.
|
||||
gradle-execution:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
include:
|
||||
- os: windows-latest
|
||||
script-suffix: '.bat'
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Test use defined Gradle version
|
||||
uses: ./
|
||||
with:
|
||||
gradle-version: 6.9
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help -DgradleVersionCheck=6.9
|
||||
- name: Test use Gradle version alias
|
||||
uses: ./
|
||||
with:
|
||||
gradle-version: release-candidate
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help -DgradleVersionCheck=7.2
|
||||
- name: Test use defined Gradle executable
|
||||
uses: ./
|
||||
with:
|
||||
gradle-executable: __tests__/samples/groovy-dsl/gradlew${{ matrix.script-suffix }}
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help -DgradleVersionCheck=7.1.1
|
||||
|
||||
gradle-versions:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
include:
|
||||
- os: windows-latest
|
||||
script-suffix: '.bat'
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Test Gradle 7
|
||||
uses: ./
|
||||
id: gradle7
|
||||
with:
|
||||
gradle-version: 7.2
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help -DgradleVersionCheck=7.2
|
||||
- name: Check Gradle 7 scan
|
||||
if: ${{ !steps.gradle7.outputs.build-scan-url }}
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('No build scan detected')
|
||||
- name: Test Gradle 6
|
||||
uses: ./
|
||||
id: gradle6
|
||||
with:
|
||||
gradle-version: 6.9
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help -DgradleVersionCheck=6.9
|
||||
- name: Check Gradle 6 scan
|
||||
if: ${{ !steps.gradle6.outputs.build-scan-url }}
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('No build scan detected')
|
||||
- name: Test Gradle 5
|
||||
uses: ./
|
||||
id: gradle5
|
||||
with:
|
||||
gradle-version: 5.6.4
|
||||
build-root-directory: __tests__/samples/no-wrapper-gradle-5
|
||||
arguments: help -DgradleVersionCheck=5.6.4
|
||||
- name: Check Gradle 5 scan
|
||||
if: ${{ !steps.gradle5.outputs.build-scan-url }}
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('No build scan detected')
|
||||
- name: Test Gradle 4
|
||||
uses: ./
|
||||
id: gradle4
|
||||
with:
|
||||
gradle-version: 4.10.3
|
||||
build-root-directory: __tests__/samples/no-wrapper-gradle-4
|
||||
arguments: help -DgradleVersionCheck=4.10.3
|
||||
- name: Check Gradle 4 scan
|
||||
if: ${{ !steps.gradle4.outputs.build-scan-url }}
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('No build scan detected')
|
||||
|
52
.github/workflows/integTest-gradle-user-home.yml
vendored
Normal file
52
.github/workflows/integTest-gradle-user-home.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: Test caching with a custom GRADLE_USER_HOME
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||
GRADLE_USER_HOME: custom/gradle/home
|
||||
|
||||
jobs:
|
||||
# Run initial Gradle builds to push initial cache entries
|
||||
# These builds should start fresh without cache hits, due to the seed injected into the cache key above.
|
||||
seed-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Build using Gradle wrapper
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/groovy-dsl
|
||||
arguments: test
|
||||
|
||||
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
|
||||
dependencies-cache:
|
||||
needs: seed-build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Execute Gradle build with --offline
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/groovy-dsl
|
||||
arguments: test --offline
|
||||
cache-read-only: true
|
||||
|
||||
# Test that the gradle-user-home cache will cache and restore local build-cache
|
||||
build-cache:
|
||||
needs: seed-build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Execute Gradle build and verify tasks from cache
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/groovy-dsl
|
||||
arguments: test -DverifyCachedBuild=true
|
||||
cache-read-only: true
|
36
.github/workflows/integTest-kotlin-dsl.yml
vendored
Normal file
36
.github/workflows/integTest-kotlin-dsl.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Test caching with Kotlin DSL
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||
CACHE_DEBUG_ENABLED: true
|
||||
|
||||
jobs:
|
||||
# Use kotlin-dsl project to verify caching of generated jars and compiled scripts
|
||||
seed-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Build kotlin-dsl project
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/kotlin-dsl
|
||||
arguments: test
|
||||
|
||||
# Check that the build can run --offline
|
||||
verify-build:
|
||||
needs: seed-build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Build kotlin-dsl project
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/kotlin-dsl
|
||||
arguments: test --offline
|
124
.github/workflows/prod.yml
vendored
124
.github/workflows/prod.yml
vendored
@@ -1,124 +0,0 @@
|
||||
# make sure the action works on a clean machine without building
|
||||
name: prod
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
basic-build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Build using Gradle wrapper
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/basic
|
||||
arguments: test
|
||||
|
||||
gradle-execution:
|
||||
needs: basic-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
include:
|
||||
- os: windows-latest
|
||||
script-suffix: '.bat'
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Test use defined Gradle version
|
||||
uses: ./
|
||||
with:
|
||||
gradle-version: 6.9
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help
|
||||
- name: Test use Gradle version alias
|
||||
uses: ./
|
||||
with:
|
||||
gradle-version: release-candidate
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help
|
||||
- name: Test use defined Gradle executable
|
||||
uses: ./
|
||||
with:
|
||||
gradle-executable: __tests__/samples/basic/gradlew${{ matrix.script-suffix }}
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help
|
||||
- name: Test custom wrapper location (deprecated)
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
wrapper-directory: __tests__/samples/basic
|
||||
arguments: help
|
||||
|
||||
dependencies-cache:
|
||||
needs: basic-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Test dependencies-cache-enabled
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/basic
|
||||
arguments: test --no-daemon
|
||||
dependencies-cache-enabled: true
|
||||
|
||||
configuration-cache:
|
||||
needs: basic-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Test configuration-cache-enabled
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/basic
|
||||
arguments: test --configuration-cache --no-daemon
|
||||
configuration-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
# Configuration cache requires dependencies cache, since it assumes dependencies are already downloaded.
|
||||
|
||||
cache-read-only:
|
||||
needs: basic-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Test cache-read-only
|
||||
uses: ./
|
||||
with:
|
||||
build-root-directory: __tests__/samples/basic
|
||||
arguments: test --no-daemon
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
cache-read-only: true
|
||||
|
||||
failures: # These build invocations are informational only, and are expected to fail
|
||||
needs: basic-build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Test wrapper missing
|
||||
uses: ./
|
||||
continue-on-error: true
|
||||
with:
|
||||
build-root-directory: __tests__/samples/no-wrapper
|
||||
arguments: help
|
160
README.md
160
README.md
@@ -2,9 +2,13 @@
|
||||
|
||||
This GitHub Action can be used to execute a Gradle build on any platform supported by GitHub Actions.
|
||||
|
||||
**Note:** The following documentation is for `gradle/gradle-build-action@v2`, currently in Beta release.
|
||||
You can view the documentation for the latest stable release (v1.5.1) [on the GitHub Marketplace](https://github.com/marketplace/actions/gradle-build-action?version=v1.5.1).
|
||||
|
||||
## Usage
|
||||
|
||||
The following workflow will run `./gradlew build` using the wrapper from the repository on ubuntu, macos and windows. The only prerequisite is to have Java installed: you define the version of Java you need to run the build using the `actions/setup-java` action.
|
||||
The following workflow will run `./gradlew build` on ubuntu, macos and windows.
|
||||
The only prerequisite is to have Java installed: you define the version of Java you need to run the build using the `actions/setup-java` action.
|
||||
|
||||
```yaml
|
||||
# .github/workflows/gradle-build-pr.yml
|
||||
@@ -21,12 +25,26 @@ jobs:
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- uses: gradle/gradle-build-action@v1
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: build
|
||||
```
|
||||
|
||||
## Gradle arguments
|
||||
It is possible to configure multiple Gradle executions to run sequentially in the same job.
|
||||
Each invocation will start its run with the filesystem state remaining from the previous execution.
|
||||
|
||||
```yaml
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: assemble
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: check
|
||||
```
|
||||
|
||||
## Gradle Execution
|
||||
|
||||
### Command-line arguments
|
||||
|
||||
The `arguments` input can used to pass arbitrary arguments to the `gradle` command line.
|
||||
|
||||
@@ -42,44 +60,47 @@ arguments: build -DsystemProperty=bar
|
||||
|
||||
See `gradle --help` for more information.
|
||||
|
||||
If you need to pass environment variables, simply use the GitHub Actions workflow syntax:
|
||||
If you need to pass environment variables, use the GitHub Actions workflow syntax:
|
||||
|
||||
```yaml
|
||||
- uses: gradle/gradle-build-action@v1
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
env:
|
||||
CI: true
|
||||
with:
|
||||
arguments: build
|
||||
```
|
||||
|
||||
## Run a build from a different directory
|
||||
### 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@v1
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
build-root-directory: some/subdirectory
|
||||
```
|
||||
|
||||
## Use a specific `gradle` executable
|
||||
### 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@v1
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
gradle-executable: path/to/gradle
|
||||
gradle-executable: /path/to/installed/gradle
|
||||
```
|
||||
|
||||
## Use a Gradle wrapper from a different directory
|
||||
|
||||
```yaml
|
||||
- uses: gradle/gradle-build-action@v1
|
||||
with:
|
||||
gradle-executable: path/to/gradlew
|
||||
```
|
||||
This mechanism can also be used to target a Gradle wrapper script that is located in a non-default location.
|
||||
|
||||
NOTE: The `wrapper-directory` input has been deprecated. Use `gradle-executable` instead.
|
||||
### Download, install and use a specific Gradle version
|
||||
|
||||
## Setup and use a declared Gradle version
|
||||
The `gradle-build-action` is able to download and install a specific Gradle version to execute.
|
||||
|
||||
```yaml
|
||||
- uses: gradle/gradle-build-action@v1
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
gradle-version: 6.5
|
||||
```
|
||||
@@ -96,7 +117,7 @@ Moreover, you can use the following aliases:
|
||||
| `nightly` | The latest [nightly](https://gradle.org/nightly/), fails if none. |
|
||||
| `release-nightly` | The latest [release nightly](https://gradle.org/release-nightly/), fails if none. |
|
||||
|
||||
This can be handy to, for example, automatically test your build with the next Gradle version once a release candidate is out:
|
||||
This can be handy to automatically verify your build works with the latest release candidate of Gradle:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/test-gradle-rc.yml
|
||||
@@ -112,7 +133,7 @@ jobs:
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- uses: gradle/gradle-build-action@v1
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
gradle-version: release-candidate
|
||||
arguments: build --dry-run # just test build configuration
|
||||
@@ -120,80 +141,42 @@ jobs:
|
||||
|
||||
## Caching
|
||||
|
||||
This action provides 3 levels of caching to help speed up your GitHub Actions:
|
||||
By default, this action aims to cache any and all reusable state that may be speed up a subsequent build invocation.
|
||||
|
||||
- `distributions` caches any downloaded Gradle zips, including any downloaded [wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) versions, saving time downloading Gradle distributions ;
|
||||
- `dependencies` caches the [dependencies](https://docs.gradle.org/current/userguide/dependency_resolution.html#sub:cache_copy), saving time downloading dependencies ;
|
||||
- `configuration` caches the [build configuration](https://docs.gradle.org/nightly/userguide/configuration_cache.html), saving time configuring the build.
|
||||
The state that is cached includes:
|
||||
- Any distributions downloaded to satisfy a `gradle-version` parameter ;
|
||||
- A subset of the Gradle User Home directory, including downloaded dependencies, wrapper distributions, and the local build cache ;
|
||||
- Any [configuration-cache](https://docs.gradle.org/nightly/userguide/configuration_cache.html) data stored in the project `.gradle` directory.
|
||||
|
||||
Only the first one, caching downloaded distributions, is enabled by default.
|
||||
Future versions of this action will enable all caching by default.
|
||||
|
||||
You can control which level is enabled as follows:
|
||||
To reduce the space required for caching, this action makes a best effort to reduce duplication in cache entries.
|
||||
|
||||
Caching is enabled by default. You can disable caching for the action as follows:
|
||||
```yaml
|
||||
distributions-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
cache-disabled: true
|
||||
```
|
||||
|
||||
NOTE: The `wrapper-cache-enabled` flag has been deprecated, replaced by `distributions-cache-enabled` which enables caching for all downloaded distributions, including Gradle wrapper downloads.
|
||||
At this time it is not possible to fine-tune the caching performed by this action.
|
||||
If you have a legitimate use case for fine-grained caching or restricting which files are cached, please raise an issue.
|
||||
|
||||
The distributions cache is simple and can't be configured further.
|
||||
### Cache keys
|
||||
|
||||
The dependencies and configuration cache will compute a cache key in a best effort manner.
|
||||
Keep reading to learn how to better control how they work.
|
||||
For cached distributions, the cache key is unique to the downloaded distribution. This will not change over time.
|
||||
|
||||
Note that enabling configuration cache without the dependencies cache is not permitted, since a hit in the configuration cache assumes that dependencies are already present in the local dependencies cache.
|
||||
The state of the Gradle User Home and configuration-cache are highly dependent on the Gradle execution, so the cache key is composed of the current commit hash and the GitHub actions job id.
|
||||
As such, the cache key is likely to change on each subsequent run of GitHub actions.
|
||||
This allows the most recent state to always be available in the GitHub actions cache.
|
||||
|
||||
### Configuring the dependencies and configuration caches
|
||||
|
||||
Both the dependencies and configuration caches use the same default configuration:
|
||||
|
||||
They use the following inputs to calculate the cache key:
|
||||
|
||||
```text
|
||||
**/*.gradle
|
||||
**/*.gradle.kts
|
||||
**/gradle.properties
|
||||
gradle/**
|
||||
```
|
||||
|
||||
This is a good enough approximation.
|
||||
They restore cached state even if there isn't an exact match.
|
||||
|
||||
If the defaults don't suit your needs you can override them with the following inputs:
|
||||
|
||||
```yaml
|
||||
dependencies-cache-key: |
|
||||
**/gradle.properties
|
||||
gradle/dependency-locks/**
|
||||
dependencies-cache-exact: true
|
||||
configuration-cache-key: |
|
||||
**/gradle.properties
|
||||
gradle/dependency-locks/**
|
||||
configuration-cache-exact: true
|
||||
```
|
||||
|
||||
Coming up with a good cache key isn't trivial and depends on your build.
|
||||
The above example isn't realistic.
|
||||
Stick to the defaults unless you know what you are doing.
|
||||
|
||||
If you happen to use Gradle [dependency locking](https://docs.gradle.org/current/userguide/dependency_locking.html) you can make the dependencies cache more precise with the following configuration:
|
||||
|
||||
```yaml
|
||||
dependencies-cache-enabled: true
|
||||
dependencies-cache-key: gradle/dependency-locks/**
|
||||
dependencies-cache-exact: true
|
||||
```
|
||||
To reduce duplication between cache entries, certain artifacts are cached independently based on their identity.
|
||||
Artifacts that are cached independently include downloaded dependencies, downloaded wrapper distributions and generated Gradle API jars.
|
||||
For example, this means that all jobs executing a particular version of the Gradle wrapper will share common entries for wrapper distributions and for generated Gradle API jars.
|
||||
|
||||
### Using the caches read-only
|
||||
|
||||
Cache storage space is limited for GitHub actions, and writing new cache entries can trigger the deletion of exising entries.
|
||||
In some circumstances, it makes sense for a Gradle invocation to use any existing cache entries but not to write and changes back.
|
||||
In some circumstances, it makes sense for a Gradle invocation to read any existing cache entries but not to write changes back.
|
||||
For example, you may want to write cache entries for builds on your `main` branch, but not for any PR build invocations.
|
||||
|
||||
Use the following configuration to avoid writing cache entries for the action invocation:
|
||||
You can enable read-only caching for any of the caches as follows:
|
||||
|
||||
```yaml
|
||||
cache-read-only: true
|
||||
@@ -201,11 +184,11 @@ cache-read-only: true
|
||||
|
||||
## Build scans
|
||||
|
||||
If your build publishes a [build scan](https://gradle.com/build-scans/) the `gradle-build-action` action will emit the link to the published build scan as an output named `build-scan-url`.
|
||||
If your build publishes a [build scan](https://gradle.com/build-scans/) the `gradle-build-action` action will:
|
||||
- Add a notice with the link to the GitHub Actions user interface
|
||||
- Emit the link to the published build scan as an output named `build-scan-url`.
|
||||
|
||||
You can then use that link in subsequent actions of your workflow.
|
||||
|
||||
For example:
|
||||
You can then use that link in subsequent actions of your workflow. For example:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/gradle-build-pr.yml
|
||||
@@ -213,19 +196,16 @@ name: Run Gradle on PRs
|
||||
on: pull_request
|
||||
jobs:
|
||||
gradle:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- uses: gradle/gradle-build-action@v1
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
id: gradle
|
||||
with:
|
||||
arguments: build
|
||||
id: gradle
|
||||
- name: "Comment build scan url"
|
||||
uses: actions/github-script@v3
|
||||
if: github.event_name == 'pull_request' && failure()
|
||||
|
21
__tests__/cache-utils.test.ts
Normal file
21
__tests__/cache-utils.test.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import * as cacheUtils from '../src/cache-utils'
|
||||
import * as path from 'path'
|
||||
|
||||
describe('cacheUtils-utils', () => {
|
||||
describe('can hash', () => {
|
||||
it('a string', async () => {
|
||||
const hash = cacheUtils.hashStrings(['foo'])
|
||||
expect(hash).toBe('acbd18db4cc2f85cedef654fccc4a4d8')
|
||||
})
|
||||
it('multiple strings', async () => {
|
||||
const hash = cacheUtils.hashStrings(['foo', 'bar', 'baz'])
|
||||
expect(hash).toBe('6df23dc03f9b54cc38a0fc1483df6e21')
|
||||
})
|
||||
it('normalized filenames', async () => {
|
||||
const fileNames = ['/foo/bar/baz.zip', '../boo.html']
|
||||
const posixHash = cacheUtils.hashFileNames(fileNames)
|
||||
const windowsHash = cacheUtils.hashFileNames(fileNames)
|
||||
expect(posixHash).toBe(windowsHash)
|
||||
})
|
||||
})
|
||||
})
|
@@ -1,33 +0,0 @@
|
||||
import * as cacheWrapper from '../src/cache-wrapper'
|
||||
import * as path from 'path'
|
||||
|
||||
describe('cache', () => {
|
||||
describe('can extract gradle wrapper slug', () => {
|
||||
it('from wrapper properties file', async () => {
|
||||
const version = cacheWrapper.extractGradleWrapperSlugFrom(
|
||||
path.resolve(
|
||||
'__tests__/data/cache-wrapper-test/gradle-wrapper.properties'
|
||||
)
|
||||
)
|
||||
expect(version).toBe('6.6.1-bin')
|
||||
})
|
||||
it('for -bin dist', async () => {
|
||||
const version = cacheWrapper.extractGradleWrapperSlugFromDistUri(
|
||||
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.6.1-bin.zip'
|
||||
)
|
||||
expect(version).toBe('6.6.1-bin')
|
||||
})
|
||||
it('for -all dist', async () => {
|
||||
const version = cacheWrapper.extractGradleWrapperSlugFromDistUri(
|
||||
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.6.1-all.zip'
|
||||
)
|
||||
expect(version).toBe('6.6.1-all')
|
||||
})
|
||||
it('for milestone', async () => {
|
||||
const version = cacheWrapper.extractGradleWrapperSlugFromDistUri(
|
||||
'distributionUrl=https\\://services.gradle.org/distributions/gradle-6.6-milestone-1-all.zip'
|
||||
)
|
||||
expect(version).toBe('6.6-milestone-1-all')
|
||||
})
|
||||
})
|
||||
})
|
@@ -1,39 +0,0 @@
|
||||
import * as cryptoUtils from '../src/crypto-utils'
|
||||
import * as path from 'path'
|
||||
|
||||
describe('crypto-utils', () => {
|
||||
describe('can hash', () => {
|
||||
it('a directory', async () => {
|
||||
const hash = await cryptoUtils.hashFiles(
|
||||
path.resolve('__tests__/data/crypto-utils-test/gradle')
|
||||
)
|
||||
expect(hash).toBe(
|
||||
process.platform === 'win32'
|
||||
? '3364336e94e746ce65a31748a6371b7efd7d499e18ad605c74c91cde0edc0a44'
|
||||
: '63b9f14f65d014e585099c9c274b9dcbddf5cfd1a8978e5a24efb89ff9304348'
|
||||
)
|
||||
})
|
||||
it('a directory with a glob', async () => {
|
||||
const hash = await cryptoUtils.hashFiles(
|
||||
path.resolve('__tests__/data/crypto-utils-test/'),
|
||||
['gradle/**']
|
||||
)
|
||||
expect(hash).toBe(
|
||||
process.platform === 'win32'
|
||||
? '3364336e94e746ce65a31748a6371b7efd7d499e18ad605c74c91cde0edc0a44'
|
||||
: '63b9f14f65d014e585099c9c274b9dcbddf5cfd1a8978e5a24efb89ff9304348'
|
||||
)
|
||||
})
|
||||
it('a directory with globs', async () => {
|
||||
const hash = await cryptoUtils.hashFiles(
|
||||
path.resolve('__tests__/data/crypto-utils-test/'),
|
||||
['**/*.gradle', 'gradle/**']
|
||||
)
|
||||
expect(hash).toBe(
|
||||
process.platform === 'win32'
|
||||
? 'd9b66fded38f79f601ce745d64ed726a8df8c0b242b02bcd2c1d331f54742ad6'
|
||||
: 'f42cd10636f09799f4e01cc84e7ae906cc1d9140f1446f8dcd054d19cbc44c2b'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
6
__tests__/samples/basic/.gitattributes
vendored
6
__tests__/samples/basic/.gitattributes
vendored
@@ -1,6 +0,0 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
@@ -1,11 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation('junit:junit:4.12')
|
||||
}
|
23
__tests__/samples/groovy-dsl/build.gradle
Normal file
23
__tests__/samples/groovy-dsl/build.gradle
Normal file
@@ -0,0 +1,23 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation('junit:junit:4.12')
|
||||
}
|
||||
|
||||
tasks.named("test").configure {
|
||||
// Use an environment variable to bypass config-cache checks
|
||||
if (System.getenv('VERIFY_CACHED_CONFIGURATION') != null) {
|
||||
throw new RuntimeException("Configuration was not cached: unexpected configuration of test task")
|
||||
}
|
||||
doLast {
|
||||
if (System.properties.verifyCachedBuild) {
|
||||
throw new RuntimeException("Build was not cached: unexpected execution of test task")
|
||||
}
|
||||
}
|
||||
}
|
1
__tests__/samples/groovy-dsl/gradle.properties
Normal file
1
__tests__/samples/groovy-dsl/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
org.gradle.caching=true
|
18
__tests__/samples/kotlin-dsl/build.gradle.kts
Normal file
18
__tests__/samples/kotlin-dsl/build.gradle.kts
Normal file
@@ -0,0 +1,18 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api("org.apache.commons:commons-math3:3.6.1")
|
||||
implementation("com.google.guava:guava:30.1.1-jre")
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.7.2")
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
1
__tests__/samples/kotlin-dsl/gradle.properties
Normal file
1
__tests__/samples/kotlin-dsl/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
org.gradle.caching=true
|
BIN
__tests__/samples/kotlin-dsl/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
__tests__/samples/kotlin-dsl/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
__tests__/samples/kotlin-dsl/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
__tests__/samples/kotlin-dsl/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
234
__tests__/samples/kotlin-dsl/gradlew
vendored
Executable file
234
__tests__/samples/kotlin-dsl/gradlew
vendored
Executable file
@@ -0,0 +1,234 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
89
__tests__/samples/kotlin-dsl/gradlew.bat
vendored
Normal file
89
__tests__/samples/kotlin-dsl/gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
15
__tests__/samples/kotlin-dsl/settings.gradle.kts
Normal file
15
__tests__/samples/kotlin-dsl/settings.gradle.kts
Normal file
@@ -0,0 +1,15 @@
|
||||
plugins {
|
||||
id("com.gradle.enterprise") version("3.7")
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
buildScan {
|
||||
termsOfServiceUrl = "https://gradle.com/terms-of-service"
|
||||
termsOfServiceAgree = "yes"
|
||||
publishAlways()
|
||||
isUploadInBackground = false
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "kotlin-dsl"
|
||||
|
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* This Java source file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
package com.example;
|
||||
|
||||
public class Library {
|
||||
public boolean someLibraryMethod() {
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* This Java source file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
package com.example;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class LibraryTest {
|
||||
@Test void someLibraryMethodReturnsTrue() {
|
||||
Library classUnderTest = new Library();
|
||||
assertTrue(classUnderTest.someLibraryMethod(), "someLibraryMethod should return 'true'");
|
||||
}
|
||||
}
|
10
__tests__/samples/no-wrapper-gradle-4/build.gradle
Normal file
10
__tests__/samples/no-wrapper-gradle-4/build.gradle
Normal file
@@ -0,0 +1,10 @@
|
||||
plugins {
|
||||
id "com.gradle.build-scan" version "1.16"
|
||||
}
|
||||
|
||||
buildScan {
|
||||
termsOfServiceUrl = "https://gradle.com/terms-of-service"
|
||||
termsOfServiceAgree = "yes"
|
||||
publishAlways()
|
||||
}
|
||||
|
8
__tests__/samples/no-wrapper-gradle-4/settings.gradle
Normal file
8
__tests__/samples/no-wrapper-gradle-4/settings.gradle
Normal file
@@ -0,0 +1,8 @@
|
||||
rootProject.name = 'no-wrapper'
|
||||
|
||||
println "Using Gradle version: ${gradle.gradleVersion}"
|
||||
|
||||
def gradleVersionCheck = System.properties.gradleVersionCheck
|
||||
if (gradleVersionCheck && gradle.gradleVersion != gradleVersionCheck) {
|
||||
throw new RuntimeException("Got the wrong version: expected ${gradleVersionCheck} but was ${gradle.gradleVersion}")
|
||||
}
|
12
__tests__/samples/no-wrapper-gradle-5/build.gradle
Normal file
12
__tests__/samples/no-wrapper-gradle-5/build.gradle
Normal file
@@ -0,0 +1,12 @@
|
||||
plugins {
|
||||
id("com.gradle.build-scan") version("3.7")
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
buildScan {
|
||||
termsOfServiceUrl = "https://gradle.com/terms-of-service"
|
||||
termsOfServiceAgree = "yes"
|
||||
publishAlways()
|
||||
uploadInBackground = false
|
||||
}
|
||||
}
|
8
__tests__/samples/no-wrapper-gradle-5/settings.gradle
Normal file
8
__tests__/samples/no-wrapper-gradle-5/settings.gradle
Normal file
@@ -0,0 +1,8 @@
|
||||
rootProject.name = 'no-wrapper'
|
||||
|
||||
println "Using Gradle version: ${gradle.gradleVersion}"
|
||||
|
||||
def gradleVersionCheck = System.properties.gradleVersionCheck
|
||||
if (gradleVersionCheck && gradle.gradleVersion != gradleVersionCheck) {
|
||||
throw new RuntimeException("Got the wrong version: expected ${gradleVersionCheck} but was ${gradle.gradleVersion}")
|
||||
}
|
6
__tests__/samples/no-wrapper/.gitattributes
vendored
6
__tests__/samples/no-wrapper/.gitattributes
vendored
@@ -1,6 +0,0 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
5
__tests__/samples/no-wrapper/.gitignore
vendored
5
__tests__/samples/no-wrapper/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
# Ignore Gradle project-specific cache directory
|
||||
.gradle
|
||||
|
||||
# Ignore Gradle build output directory
|
||||
build
|
@@ -1,3 +1,21 @@
|
||||
plugins {
|
||||
id("com.gradle.enterprise") version("3.7")
|
||||
}
|
||||
|
||||
gradleEnterprise {
|
||||
buildScan {
|
||||
termsOfServiceUrl = "https://gradle.com/terms-of-service"
|
||||
termsOfServiceAgree = "yes"
|
||||
publishAlways()
|
||||
uploadInBackground = false
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = 'no-wrapper'
|
||||
|
||||
println "Using Gradle version: ${gradle.gradleVersion}"
|
||||
println "Using Gradle version: ${gradle.gradleVersion}"
|
||||
|
||||
def gradleVersionCheck = System.properties.gradleVersionCheck
|
||||
if (gradleVersionCheck && gradle.gradleVersion != gradleVersionCheck) {
|
||||
throw new RuntimeException("Got the wrong version: expected ${gradleVersionCheck} but was ${gradle.gradleVersion}")
|
||||
}
|
43
action.yml
43
action.yml
@@ -4,10 +4,6 @@ description: 'Executes a Gradle build, caching useful state in the GitHub action
|
||||
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
|
||||
|
||||
inputs:
|
||||
wrapper-directory:
|
||||
description: Path to the Gradle Wrapper directory
|
||||
required: false
|
||||
deprecationMessage: Use 'gradle-executable' to point to a gradlew[.bat] file in a non-default location
|
||||
gradle-executable:
|
||||
description: Path to the Gradle executable
|
||||
required: false
|
||||
@@ -20,41 +16,20 @@ inputs:
|
||||
arguments:
|
||||
description: Gradle command line arguments, see gradle --help
|
||||
required: false
|
||||
distributions-cache-enabled:
|
||||
description: Whether caching downloaded Gradle distributions is enabled or not, default to 'true'
|
||||
required: false
|
||||
default: true
|
||||
wrapper-cache-enabled:
|
||||
description: Whether caching wrapper installation is enabled or not, default to 'true'
|
||||
required: false
|
||||
default: true
|
||||
deprecationMessage: Replaced by 'distributions-cache-enabled' which enables caching for all downloaded Gradle distributions
|
||||
dependencies-cache-enabled:
|
||||
description: Whether caching dependencies is enabled or not, default to 'false'
|
||||
required: false
|
||||
default: false
|
||||
dependencies-cache-key:
|
||||
description: Globs of files to hash in the build root directory, separated by new lines, use best-effort if unset
|
||||
required: false
|
||||
dependencies-cache-exact:
|
||||
description: Whether to restore only if exact match, default to 'false'
|
||||
required: false
|
||||
default: false
|
||||
configuration-cache-enabled:
|
||||
description: Whether caching build configuration is enabled or not, default to 'false'
|
||||
required: false
|
||||
default: false
|
||||
configuration-cache-key:
|
||||
description: Globs of files to hash in the build root directory, separated by new lines, use best-effort if unset
|
||||
required: false
|
||||
configuration-cache-exact:
|
||||
description: Whether to restore only if exact match, default to 'false'
|
||||
cache-disabled:
|
||||
description: When 'true', all caching is disabled. No entries will be written to or read from the cache.
|
||||
required: false
|
||||
default: false
|
||||
cache-read-only:
|
||||
description: When 'true', existing entries will be read from the cache but no entries will be written
|
||||
required: false
|
||||
default: false
|
||||
# TODO: It might be useful to default to read-only for PRs, or non-main branch.
|
||||
default: false
|
||||
|
||||
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.
|
||||
required: false
|
||||
default: ${{ toJSON(matrix) }}
|
||||
|
||||
outputs:
|
||||
build-scan-url:
|
||||
|
3
dist/main/index.js
vendored
3
dist/main/index.js
vendored
File diff suppressed because one or more lines are too long
1
dist/main/index.js.map
vendored
Normal file
1
dist/main/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
3912
dist/main/sourcemap-register.js
vendored
Normal file
3912
dist/main/sourcemap-register.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3
dist/post/index.js
vendored
3
dist/post/index.js
vendored
File diff suppressed because one or more lines are too long
1
dist/post/index.js.map
vendored
Normal file
1
dist/post/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
3912
dist/post/sourcemap-register.js
vendored
Normal file
3912
dist/post/sourcemap-register.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
157
package-lock.json
generated
157
package-lock.json
generated
@@ -32,9 +32,9 @@
|
||||
}
|
||||
},
|
||||
"@actions/core": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.4.0.tgz",
|
||||
"integrity": "sha512-CGx2ilGq5i7zSLgiiGUtBCxhRRxibJYU6Fim0Q1Wg2aQL2LTnF27zbqZOrxfvFQ55eSBW0L8uVStgtKMpa0Qlg=="
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.5.0.tgz",
|
||||
"integrity": "sha512-eDOLH1Nq9zh+PJlYLqEMkS/jLQxhksPNmUGNBHfa4G+tQmnIhzpctxmchETtVGyBOvXgOVVpYuE40+eS4cUnwQ=="
|
||||
},
|
||||
"@actions/exec": {
|
||||
"version": "1.1.0",
|
||||
@@ -44,6 +44,17 @@
|
||||
"@actions/io": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"@actions/github": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.0.tgz",
|
||||
"integrity": "sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ==",
|
||||
"requires": {
|
||||
"@actions/http-client": "^1.0.11",
|
||||
"@octokit/core": "^3.4.0",
|
||||
"@octokit/plugin-paginate-rest": "^2.13.3",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"@actions/glob": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.2.0.tgz",
|
||||
@@ -1094,6 +1105,115 @@
|
||||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@octokit/auth-token": {
|
||||
"version": "2.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz",
|
||||
"integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
|
||||
"integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "4.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.4.tgz",
|
||||
"integrity": "sha512-SWTdXsVheRmlotWNjKzPOb6Js6tjSqA2a8z9+glDJng0Aqjzti8MEWOtuT8ZSu6wHnci7LZNuarE87+WJBG4vg==",
|
||||
"requires": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "9.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-9.7.0.tgz",
|
||||
"integrity": "sha512-TUJ16DJU8mekne6+KVcMV5g6g/rJlrnIKn7aALG9QrNpnEipFc1xjoarh0PKaAWf2Hf+HwthRKYt+9mCm5RsRg=="
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.15.1.tgz",
|
||||
"integrity": "sha512-47r52KkhQDkmvUKZqXzA1lKvcyJEfYh3TKAIe5+EzMeyDM3d+/s5v11i2gTk8/n6No6DPi3k5Ind6wtDbo/AEg==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.24.0"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.8.0.tgz",
|
||||
"integrity": "sha512-qeLZZLotNkoq+it6F+xahydkkbnvSK0iDjlXFo3jNTB+Ss0qIbYQb9V/soKLMkgGw8Q2sHjY5YEXiA47IVPp4A==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.25.0",
|
||||
"deprecation": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "5.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.1.tgz",
|
||||
"integrity": "sha512-Ls2cfs1OfXaOKzkcxnqw5MR6drMA/zWX/LIS/p8Yjdz7QKTPQLMsB3R+OvoxE6XnXeXEE2X7xe4G4l4X0gRiKQ==",
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "6.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.25.0.tgz",
|
||||
"integrity": "sha512-bNvyQKfngvAd/08COlYIN54nRgxskmejgywodizQNyiKoXmWRAjKup2/LYwm+T9V0gsKH6tuld1gM0PzmOiB4Q==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^9.5.0"
|
||||
}
|
||||
},
|
||||
"@opencensus/web-types": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@opencensus/web-types/-/web-types-0.0.7.tgz",
|
||||
@@ -1522,9 +1642,9 @@
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
@@ -1807,6 +1927,11 @@
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"before-after-hook": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
|
||||
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@@ -2202,6 +2327,11 @@
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"detect-newline": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
|
||||
@@ -5128,7 +5258,6 @@
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -6327,9 +6456,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"tmpl": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
|
||||
"integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=",
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
||||
"integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
|
||||
"dev": true
|
||||
},
|
||||
"to-fast-properties": {
|
||||
@@ -6554,6 +6683,11 @@
|
||||
"set-value": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
@@ -6778,8 +6912,7 @@
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"write-file-atomic": {
|
||||
"version": "3.0.3",
|
||||
|
@@ -7,7 +7,7 @@
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"build": "ncc build src/main.ts --out dist/main --minify && ncc build src/post.ts --out dist/post --minify",
|
||||
"build": "ncc build src/main.ts --out dist/main --source-map --minify && ncc build src/post.ts --out dist/post --source-map --minify",
|
||||
"test": "jest",
|
||||
"all": "npm run format && npm run lint && npm run build && npm test"
|
||||
},
|
||||
@@ -25,8 +25,9 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/cache": "1.0.7",
|
||||
"@actions/core": "1.4.0",
|
||||
"@actions/core": "1.5.0",
|
||||
"@actions/exec": "1.1.0",
|
||||
"@actions/github": "5.0.0",
|
||||
"@actions/glob": "0.2.0",
|
||||
"@actions/http-client": "1.0.11",
|
||||
"@actions/tool-cache": "1.7.1",
|
||||
|
50
src/build-scan-capture.ts
Normal file
50
src/build-scan-capture.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import * as core from '@actions/core'
|
||||
|
||||
export function writeInitScript(): string {
|
||||
const tmpDir = process.env['RUNNER_TEMP'] || ''
|
||||
const initScript = path.resolve(tmpDir, 'build-scan-capture.init.gradle')
|
||||
core.info(`Writing init script: ${initScript}`)
|
||||
if (fs.existsSync(initScript)) {
|
||||
return initScript
|
||||
}
|
||||
fs.writeFileSync(
|
||||
initScript,
|
||||
`
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
// Don't run against the included builds (if the main build has any).
|
||||
def isTopLevelBuild = gradle.getParent() == null
|
||||
if (isTopLevelBuild) {
|
||||
def version = GradleVersion.current().baseVersion
|
||||
def atLeastGradle4 = version >= GradleVersion.version("4.0")
|
||||
def atLeastGradle6 = version >= GradleVersion.version("6.0")
|
||||
|
||||
if (atLeastGradle6) {
|
||||
settingsEvaluated { settings ->
|
||||
if (settings.pluginManager.hasPlugin("com.gradle.enterprise")) {
|
||||
registerCallbacks(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject.name)
|
||||
}
|
||||
}
|
||||
} else if (atLeastGradle4) {
|
||||
projectsEvaluated { gradle ->
|
||||
if (gradle.rootProject.pluginManager.hasPlugin("com.gradle.build-scan")) {
|
||||
registerCallbacks(gradle.rootProject.extensions["buildScan"], gradle.rootProject.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def registerCallbacks(buildScanExtension, rootProjectName) {
|
||||
buildScanExtension.with {
|
||||
def scanFile = new File("gradle-build-scan.txt")
|
||||
buildScanPublished { buildScan ->
|
||||
scanFile.text = buildScan.buildScanUri
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
)
|
||||
return initScript
|
||||
}
|
@@ -1,112 +0,0 @@
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
|
||||
import * as core from '@actions/core'
|
||||
import * as cache from '@actions/cache'
|
||||
|
||||
import * as crypto from './crypto-utils'
|
||||
|
||||
import {
|
||||
inputCacheKeyGlobs,
|
||||
tryDeleteFiles,
|
||||
isDependenciesCacheDisabled
|
||||
} from './cache-dependencies'
|
||||
|
||||
const CONFIGURATION_CACHE_PATH = 'CONFIGURATION_CACHE_PATH'
|
||||
const CONFIGURATION_CACHE_KEY = 'CONFIGURATION_CACHE_KEY'
|
||||
const CONFIGURATION_CACHE_RESULT = 'CONFIGURATION_CACHE_RESULT'
|
||||
|
||||
export async function restoreCachedConfiguration(
|
||||
rootDir: string
|
||||
): Promise<void> {
|
||||
if (isConfigurationCacheDisabled()) return
|
||||
|
||||
if (isDependenciesCacheDisabled()) {
|
||||
throw new Error(
|
||||
`Must enable dependencies-cache when configuration-cache is enabled`
|
||||
)
|
||||
}
|
||||
|
||||
const cachePath = path.resolve(rootDir, '.gradle/configuration-cache')
|
||||
if (fs.existsSync(cachePath)) return
|
||||
core.saveState(CONFIGURATION_CACHE_PATH, cachePath)
|
||||
|
||||
const inputCacheExact = core.getBooleanInput('configuration-cache-exact')
|
||||
const cacheKeyPrefix = 'configuration|'
|
||||
|
||||
const args = core.getInput('arguments')
|
||||
const cacheKeyWithArgs = `${cacheKeyPrefix}${args}|`
|
||||
|
||||
const cacheKeyGlobs = inputCacheKeyGlobs('configuration-cache-key')
|
||||
const hash = await crypto.hashFiles(rootDir, cacheKeyGlobs)
|
||||
const cacheKey = `${cacheKeyWithArgs}${hash}`
|
||||
|
||||
core.saveState(CONFIGURATION_CACHE_KEY, cacheKey)
|
||||
|
||||
const cacheResult = await cache.restoreCache(
|
||||
[cachePath],
|
||||
cacheKey,
|
||||
inputCacheExact ? [] : [cacheKeyWithArgs, cacheKeyPrefix]
|
||||
)
|
||||
|
||||
if (!cacheResult) {
|
||||
core.info(
|
||||
'Configuration cache not found, expect task graph calculation.'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
core.saveState(CONFIGURATION_CACHE_RESULT, cacheResult)
|
||||
core.info(`Configuration restored from cache key: ${cacheResult}`)
|
||||
return
|
||||
}
|
||||
|
||||
export async function cacheConfiguration(): Promise<void> {
|
||||
if (isConfigurationCacheDisabled()) return
|
||||
|
||||
const cachePath = core.getState(CONFIGURATION_CACHE_PATH)
|
||||
const cacheKey = core.getState(CONFIGURATION_CACHE_KEY)
|
||||
const cacheResult = core.getState(CONFIGURATION_CACHE_RESULT)
|
||||
|
||||
if (!cachePath || !fs.existsSync(cachePath)) {
|
||||
core.debug('No configuration to cache.')
|
||||
return
|
||||
}
|
||||
|
||||
if (cacheResult && cacheKey === cacheResult) {
|
||||
core.info(
|
||||
`Configuration cache hit occurred on the cache key ${cacheKey}, not saving cache.`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const locksDeleted = tryDeleteFiles([
|
||||
path.resolve(cachePath, 'configuration-cache.lock')
|
||||
])
|
||||
if (!locksDeleted) {
|
||||
core.warning(
|
||||
'Unable to delete configuration lock files, try using --no-daemon or stopping the daemon last if you have several Gradle steps, not saving cache.'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
core.info(`Will cache configuration with key ${cacheKey}`)
|
||||
|
||||
try {
|
||||
await cache.saveCache([cachePath], cacheKey)
|
||||
} catch (error) {
|
||||
if (error.name === cache.ValidationError.name) {
|
||||
throw error
|
||||
} else if (error.name === cache.ReserveCacheError.name) {
|
||||
core.info(error.message)
|
||||
} else {
|
||||
core.info(`[warning] ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
function isConfigurationCacheDisabled(): boolean {
|
||||
return !core.getBooleanInput('configuration-cache-enabled')
|
||||
}
|
@@ -1,125 +0,0 @@
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import * as os from 'os'
|
||||
|
||||
import * as core from '@actions/core'
|
||||
import * as cache from '@actions/cache'
|
||||
|
||||
import * as crypto from './crypto-utils'
|
||||
|
||||
const DEPENDENCIES_CACHE_PATH = 'DEPENDENCIES_CACHE_PATH'
|
||||
const DEPENDENCIES_CACHE_KEY = 'DEPENDENCIES_CACHE_KEY'
|
||||
const DEPENDENCIES_CACHE_RESULT = 'DEPENDENCIES_CACHE_RESULT'
|
||||
|
||||
export async function restoreCachedDependencies(
|
||||
rootDir: string
|
||||
): Promise<void> {
|
||||
if (isDependenciesCacheDisabled()) return
|
||||
|
||||
const cachePath = path.resolve(os.homedir(), '.gradle/caches/modules-2')
|
||||
if (fs.existsSync(cachePath)) return
|
||||
core.saveState(DEPENDENCIES_CACHE_PATH, cachePath)
|
||||
|
||||
const inputCacheExact = core.getBooleanInput('dependencies-cache-exact')
|
||||
const cacheKeyPrefix = 'dependencies|'
|
||||
|
||||
const args = core.getInput('arguments')
|
||||
const cacheKeyWithArgs = `${cacheKeyPrefix}${args}|`
|
||||
|
||||
const cacheKeyGlobs = inputCacheKeyGlobs('dependencies-cache-key')
|
||||
const hash = await crypto.hashFiles(rootDir, cacheKeyGlobs)
|
||||
const cacheKey = `${cacheKeyWithArgs}${hash}`
|
||||
|
||||
core.saveState(DEPENDENCIES_CACHE_KEY, cacheKey)
|
||||
|
||||
const cacheResult = await cache.restoreCache(
|
||||
[cachePath],
|
||||
cacheKey,
|
||||
inputCacheExact ? [] : [cacheKeyWithArgs, cacheKeyPrefix]
|
||||
)
|
||||
|
||||
if (!cacheResult) {
|
||||
core.info('Dependencies cache not found, expect dependencies download.')
|
||||
return
|
||||
}
|
||||
|
||||
core.saveState(DEPENDENCIES_CACHE_RESULT, cacheResult)
|
||||
core.info(`Dependencies restored from cache key: ${cacheResult}`)
|
||||
return
|
||||
}
|
||||
|
||||
export async function cacheDependencies(): Promise<void> {
|
||||
if (isDependenciesCacheDisabled()) return
|
||||
|
||||
const cachePath = core.getState(DEPENDENCIES_CACHE_PATH)
|
||||
const cacheKey = core.getState(DEPENDENCIES_CACHE_KEY)
|
||||
const cacheResult = core.getState(DEPENDENCIES_CACHE_RESULT)
|
||||
|
||||
if (!cachePath || !fs.existsSync(cachePath)) {
|
||||
core.debug('No dependencies to cache.')
|
||||
return
|
||||
}
|
||||
|
||||
if (cacheResult && cacheKey === cacheResult) {
|
||||
core.info(
|
||||
`Dependencies cache hit occurred on the cache key ${cacheKey}, not saving cache.`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const locksDeleted = tryDeleteFiles([
|
||||
path.resolve(cachePath, 'modules-2.lock')
|
||||
])
|
||||
if (!locksDeleted) {
|
||||
core.warning(
|
||||
'Unable to delete dependencies lock files, try using --no-daemon or stopping the daemon last if you have several Gradle steps, not saving cache.'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
core.info(`Will cache dependencies with key ${cacheKey}`)
|
||||
|
||||
try {
|
||||
await cache.saveCache([cachePath], cacheKey)
|
||||
} catch (error) {
|
||||
if (error.name === cache.ValidationError.name) {
|
||||
throw error
|
||||
} else if (error.name === cache.ReserveCacheError.name) {
|
||||
core.info(error.message)
|
||||
} else {
|
||||
core.info(`[warning] ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
export function tryDeleteFiles(filePaths: string[]): boolean {
|
||||
let failure = false
|
||||
for (const filePath of filePaths) {
|
||||
if (fs.existsSync(filePath)) {
|
||||
try {
|
||||
fs.unlinkSync(filePath)
|
||||
} catch (error) {
|
||||
failure = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return !failure
|
||||
}
|
||||
|
||||
export function isDependenciesCacheDisabled(): boolean {
|
||||
return !core.getBooleanInput('dependencies-cache-enabled')
|
||||
}
|
||||
|
||||
export function inputCacheKeyGlobs(input: string): string[] {
|
||||
const inputValue = core.getMultilineInput(input)
|
||||
return inputValue.length > 0
|
||||
? inputValue
|
||||
: [
|
||||
'**/*.gradle',
|
||||
'**/*.gradle.kts',
|
||||
'**/gradle.properties',
|
||||
'gradle/**'
|
||||
]
|
||||
}
|
208
src/cache-gradle-user-home.ts
Normal file
208
src/cache-gradle-user-home.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import * as core from '@actions/core'
|
||||
import * as glob from '@actions/glob'
|
||||
import * as exec from '@actions/exec'
|
||||
|
||||
import {AbstractCache, hashFileNames} from './cache-utils'
|
||||
|
||||
// Which paths under Gradle User Home should be cached
|
||||
const CACHE_PATH = ['caches', 'notifications']
|
||||
|
||||
const COMMON_ARTIFACT_CACHES = new Map([
|
||||
['generated-gradle-jars', 'caches/*/generated-gradle-jars/*.jar'],
|
||||
['wrapper-zips', 'wrapper/dists/*/*/*.zip'],
|
||||
['dependency-jars', 'caches/modules-*/files-*/**/*.jar'],
|
||||
['instrumented-jars', 'caches/jars-*/*/*.jar']
|
||||
])
|
||||
|
||||
export class GradleUserHomeCache extends AbstractCache {
|
||||
private gradleUserHome: string
|
||||
|
||||
constructor(rootDir: string) {
|
||||
super('gradle', 'Gradle User Home')
|
||||
this.gradleUserHome = this.determineGradleUserHome(rootDir)
|
||||
}
|
||||
|
||||
async afterRestore(): Promise<void> {
|
||||
await this.reportCacheEntrySize('as restored from cache')
|
||||
await this.restoreCommonArtifacts()
|
||||
await this.reportCacheEntrySize('after restoring common artifacts')
|
||||
}
|
||||
|
||||
private async restoreCommonArtifacts(): Promise<void> {
|
||||
const processes: Promise<void>[] = []
|
||||
for (const [bundle, pattern] of this.getCommonArtifactPaths()) {
|
||||
const p = this.restoreCommonArtifactBundle(bundle, pattern)
|
||||
// Run sequentially when debugging enabled
|
||||
if (this.cacheDebuggingEnabled) {
|
||||
await p
|
||||
}
|
||||
processes.push(p)
|
||||
}
|
||||
|
||||
await Promise.all(processes)
|
||||
}
|
||||
|
||||
private async restoreCommonArtifactBundle(
|
||||
bundle: string,
|
||||
artifactPath: string
|
||||
): Promise<void> {
|
||||
const cacheMetaFile = this.getCacheMetaFile(bundle)
|
||||
if (fs.existsSync(cacheMetaFile)) {
|
||||
const cacheKey = fs.readFileSync(cacheMetaFile, 'utf-8').trim()
|
||||
const restoreKey = await this.restoreCache([artifactPath], cacheKey)
|
||||
if (restoreKey) {
|
||||
core.info(
|
||||
`Restored ${bundle} with key ${cacheKey} to ${artifactPath}`
|
||||
)
|
||||
} else {
|
||||
this.debug(
|
||||
`Failed to restore ${bundle} with key ${cacheKey} to ${artifactPath}`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
this.debug(
|
||||
`No metafile found to restore ${bundle}: ${cacheMetaFile}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private getCacheMetaFile(name: string): string {
|
||||
return path.resolve(
|
||||
this.gradleUserHome,
|
||||
'caches',
|
||||
`.gradle-build-action.${name}.cache`
|
||||
)
|
||||
}
|
||||
|
||||
private async reportCacheEntrySize(label: string): Promise<void> {
|
||||
if (!this.cacheDebuggingEnabled) {
|
||||
return
|
||||
}
|
||||
if (!fs.existsSync(this.gradleUserHome)) {
|
||||
return
|
||||
}
|
||||
const result = await exec.getExecOutput(
|
||||
'du',
|
||||
['-h', '-c', '-t', '5M'],
|
||||
{
|
||||
cwd: this.gradleUserHome,
|
||||
silent: true,
|
||||
ignoreReturnCode: true
|
||||
}
|
||||
)
|
||||
|
||||
core.info(`Gradle User Home cache entry (directories >5M): ${label}`)
|
||||
|
||||
core.info(
|
||||
result.stdout
|
||||
.trimEnd()
|
||||
.replace(/\t/g, ' ')
|
||||
.split('\n')
|
||||
.map(it => {
|
||||
return ` ${it}`
|
||||
})
|
||||
.join('\n')
|
||||
)
|
||||
|
||||
core.info('-----------------------')
|
||||
}
|
||||
|
||||
async beforeSave(): Promise<void> {
|
||||
await this.saveCommonArtifacts()
|
||||
}
|
||||
|
||||
private async saveCommonArtifacts(): Promise<void> {
|
||||
const processes: Promise<void>[] = []
|
||||
for (const [bundle, pattern] of this.getCommonArtifactPaths()) {
|
||||
const p = this.saveCommonArtifactBundle(bundle, pattern)
|
||||
// Run sequentially when debugging enabled
|
||||
if (this.cacheDebuggingEnabled) {
|
||||
await p
|
||||
}
|
||||
processes.push(p)
|
||||
}
|
||||
|
||||
await Promise.all(processes)
|
||||
}
|
||||
|
||||
private async saveCommonArtifactBundle(
|
||||
bundle: string,
|
||||
artifactPath: string
|
||||
): Promise<void> {
|
||||
const cacheMetaFile = this.getCacheMetaFile(bundle)
|
||||
|
||||
const globber = await glob.create(artifactPath)
|
||||
const commonArtifactFiles = await globber.glob()
|
||||
|
||||
// Handle no matching files
|
||||
if (commonArtifactFiles.length === 0) {
|
||||
this.debug(`No files found to cache for ${bundle}`)
|
||||
if (fs.existsSync(cacheMetaFile)) {
|
||||
fs.unlinkSync(cacheMetaFile)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const previouslyRestoredKey = fs.existsSync(cacheMetaFile)
|
||||
? fs.readFileSync(cacheMetaFile, 'utf-8').trim()
|
||||
: ''
|
||||
const cacheKey = this.createCacheKey(bundle, commonArtifactFiles)
|
||||
|
||||
if (previouslyRestoredKey === cacheKey) {
|
||||
this.debug(
|
||||
`No change to previously restored ${bundle}. Not caching.`
|
||||
)
|
||||
} else {
|
||||
core.info(`Caching ${bundle} with cache key: ${cacheKey}`)
|
||||
await this.saveCache([artifactPath], cacheKey)
|
||||
|
||||
this.debug(`Writing cache metafile: ${cacheMetaFile}`)
|
||||
fs.writeFileSync(cacheMetaFile, cacheKey)
|
||||
}
|
||||
|
||||
for (const file of commonArtifactFiles) {
|
||||
fs.unlinkSync(file)
|
||||
}
|
||||
}
|
||||
|
||||
protected createCacheKey(bundle: string, files: string[]): string {
|
||||
const cacheKeyPrefix = process.env['CACHE_KEY_PREFIX'] || ''
|
||||
const relativeFiles = files.map(x =>
|
||||
path.relative(this.gradleUserHome, x)
|
||||
)
|
||||
const key = hashFileNames(relativeFiles)
|
||||
|
||||
return `${cacheKeyPrefix}${bundle}-${key}`
|
||||
}
|
||||
|
||||
protected determineGradleUserHome(rootDir: string): string {
|
||||
const customGradleUserHome = process.env['GRADLE_USER_HOME']
|
||||
if (customGradleUserHome) {
|
||||
return path.resolve(rootDir, customGradleUserHome)
|
||||
}
|
||||
|
||||
return path.resolve(os.homedir(), '.gradle')
|
||||
}
|
||||
|
||||
protected cacheOutputExists(): boolean {
|
||||
// Need to check for 'caches' directory to avoid incorrect detection on MacOS agents
|
||||
const dir = path.resolve(this.gradleUserHome, 'caches')
|
||||
return fs.existsSync(dir)
|
||||
}
|
||||
|
||||
protected getCachePath(): string[] {
|
||||
return CACHE_PATH.map(x => path.resolve(this.gradleUserHome, x))
|
||||
}
|
||||
|
||||
private getCommonArtifactPaths(): Map<string, string> {
|
||||
return new Map(
|
||||
Array.from(COMMON_ARTIFACT_CACHES, ([key, value]) => [
|
||||
key,
|
||||
path.resolve(this.gradleUserHome, value)
|
||||
])
|
||||
)
|
||||
}
|
||||
}
|
30
src/cache-project-dot-gradle.ts
Normal file
30
src/cache-project-dot-gradle.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import {AbstractCache} from './cache-utils'
|
||||
|
||||
// TODO: Maybe allow the user to override / tweak this set
|
||||
const PATHS_TO_CACHE = [
|
||||
'configuration-cache' // Only configuration-cache is stored at present
|
||||
]
|
||||
|
||||
export class ProjectDotGradleCache extends AbstractCache {
|
||||
private rootDir: string
|
||||
constructor(rootDir: string) {
|
||||
super('project', 'Project .gradle directory')
|
||||
this.rootDir = rootDir
|
||||
}
|
||||
|
||||
protected cacheOutputExists(): boolean {
|
||||
const dir = this.getProjectDotGradleDir()
|
||||
return fs.existsSync(dir)
|
||||
}
|
||||
|
||||
protected getCachePath(): string[] {
|
||||
const dir = this.getProjectDotGradleDir()
|
||||
return PATHS_TO_CACHE.map(x => path.resolve(dir, x))
|
||||
}
|
||||
|
||||
private getProjectDotGradleDir(): string {
|
||||
return path.resolve(this.rootDir, '.gradle')
|
||||
}
|
||||
}
|
215
src/cache-utils.ts
Normal file
215
src/cache-utils.ts
Normal file
@@ -0,0 +1,215 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as cache from '@actions/cache'
|
||||
import * as github from '@actions/github'
|
||||
import * as crypto from 'crypto'
|
||||
import * as path from 'path'
|
||||
|
||||
export function isCacheDisabled(): boolean {
|
||||
return core.getBooleanInput('cache-disabled')
|
||||
}
|
||||
|
||||
export function isCacheReadOnly(): boolean {
|
||||
return core.getBooleanInput('cache-read-only')
|
||||
}
|
||||
|
||||
export function isCacheDebuggingEnabled(): boolean {
|
||||
return process.env['CACHE_DEBUG_ENABLED'] ? true : false
|
||||
}
|
||||
|
||||
function generateCacheKey(cacheName: string): CacheKey {
|
||||
// Prefix can be used to force change all cache keys
|
||||
const cacheKeyPrefix = process.env['CACHE_KEY_PREFIX'] || ''
|
||||
|
||||
// At the most general level, share caches for all executions on the same OS
|
||||
const runnerOs = process.env['RUNNER_OS'] || ''
|
||||
const cacheKeyForOs = `${cacheKeyPrefix}${cacheName}|${runnerOs}`
|
||||
|
||||
// Prefer caches that run this job
|
||||
const cacheKeyForJob = `${cacheKeyForOs}|${github.context.job}`
|
||||
|
||||
// Prefer (even more) jobs that run this job with the same context (matrix)
|
||||
const cacheKeyForJobContext = `${cacheKeyForJob}[${determineJobContext()}]`
|
||||
|
||||
// Exact match on Git SHA
|
||||
const cacheKey = `${cacheKeyForJobContext}-${github.context.sha}`
|
||||
|
||||
return new CacheKey(cacheKey, [
|
||||
cacheKeyForJobContext,
|
||||
cacheKeyForJob,
|
||||
cacheKeyForOs
|
||||
])
|
||||
}
|
||||
|
||||
function determineJobContext(): string {
|
||||
// By default, we hash the full `matrix` data for the run, to uniquely identify this job invocation
|
||||
const workflowJobContext = core.getInput('workflow-job-context')
|
||||
return hashStrings([workflowJobContext])
|
||||
}
|
||||
|
||||
export function hashStrings(values: string[]): string {
|
||||
const hash = crypto.createHash('md5')
|
||||
for (const value of values) {
|
||||
hash.update(value)
|
||||
}
|
||||
return hash.digest('hex')
|
||||
}
|
||||
|
||||
export function hashFileNames(fileNames: string[]): string {
|
||||
return hashStrings(
|
||||
fileNames.map(x => x.replace(new RegExp(`\\${path.sep}`, 'g'), '/'))
|
||||
)
|
||||
}
|
||||
|
||||
class CacheKey {
|
||||
key: string
|
||||
restoreKeys: string[]
|
||||
|
||||
constructor(key: string, restoreKeys: string[]) {
|
||||
this.key = key
|
||||
this.restoreKeys = restoreKeys
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class AbstractCache {
|
||||
private cacheName: string
|
||||
private cacheDescription: string
|
||||
private cacheKeyStateKey: string
|
||||
private cacheResultStateKey: string
|
||||
|
||||
protected readonly cacheDebuggingEnabled: boolean
|
||||
|
||||
constructor(cacheName: string, cacheDescription: string) {
|
||||
this.cacheName = cacheName
|
||||
this.cacheDescription = cacheDescription
|
||||
this.cacheKeyStateKey = `CACHE_KEY_${cacheName}`
|
||||
this.cacheResultStateKey = `CACHE_RESULT_${cacheName}`
|
||||
this.cacheDebuggingEnabled = isCacheDebuggingEnabled()
|
||||
}
|
||||
|
||||
async restore(): Promise<void> {
|
||||
if (this.cacheOutputExists()) {
|
||||
core.info(
|
||||
`${this.cacheDescription} already exists. Not restoring from cache.`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const cacheKey = generateCacheKey(this.cacheName)
|
||||
|
||||
core.saveState(this.cacheKeyStateKey, cacheKey.key)
|
||||
|
||||
const cacheResult = await this.restoreCache(
|
||||
this.getCachePath(),
|
||||
cacheKey.key,
|
||||
cacheKey.restoreKeys
|
||||
)
|
||||
|
||||
if (!cacheResult) {
|
||||
core.info(
|
||||
`${this.cacheDescription} cache not found. Will start with empty.`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
core.saveState(this.cacheResultStateKey, cacheResult)
|
||||
|
||||
core.info(
|
||||
`Restored ${this.cacheDescription} from cache key: ${cacheResult}`
|
||||
)
|
||||
|
||||
await this.afterRestore()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
protected async restoreCache(
|
||||
cachePath: string[],
|
||||
cacheKey: string,
|
||||
cacheRestoreKeys: string[] = []
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
return await cache.restoreCache(
|
||||
cachePath,
|
||||
cacheKey,
|
||||
cacheRestoreKeys
|
||||
)
|
||||
} catch (error) {
|
||||
if (error instanceof cache.ValidationError) {
|
||||
// Validation errors should fail the build action
|
||||
throw error
|
||||
}
|
||||
// Warn about any other error and continue
|
||||
core.warning(`Failed to restore ${cacheKey}: ${error}`)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
protected async afterRestore(): Promise<void> {}
|
||||
|
||||
async save(): Promise<void> {
|
||||
if (!this.cacheOutputExists()) {
|
||||
this.debug(`No ${this.cacheDescription} to cache.`)
|
||||
return
|
||||
}
|
||||
|
||||
const cacheKey = core.getState(this.cacheKeyStateKey)
|
||||
const cacheResult = core.getState(this.cacheResultStateKey)
|
||||
|
||||
if (!cacheKey) {
|
||||
this.debug(
|
||||
`${this.cacheDescription} existed prior to cache restore. Not saving.`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (cacheResult && cacheKey === cacheResult) {
|
||||
core.info(
|
||||
`Cache hit occurred on the cache key ${cacheKey}, not saving cache.`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
await this.beforeSave()
|
||||
|
||||
core.info(
|
||||
`Caching ${this.cacheDescription} with cache key: ${cacheKey}`
|
||||
)
|
||||
const cachePath = this.getCachePath()
|
||||
await this.saveCache(cachePath, cacheKey)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
protected async beforeSave(): Promise<void> {}
|
||||
|
||||
protected async saveCache(
|
||||
cachePath: string[],
|
||||
cacheKey: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
await cache.saveCache(cachePath, cacheKey)
|
||||
} catch (error) {
|
||||
if (error instanceof cache.ValidationError) {
|
||||
// Validation errors should fail the build action
|
||||
throw error
|
||||
} else if (error instanceof cache.ReserveCacheError) {
|
||||
// Reserve cache errors are expected if the artifact has been previously cached
|
||||
this.debug(error.message)
|
||||
} else {
|
||||
// Warn about any other error and continue
|
||||
core.warning(String(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected debug(message: string): void {
|
||||
if (this.cacheDebuggingEnabled) {
|
||||
core.info(message)
|
||||
} else {
|
||||
core.debug(message)
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract cacheOutputExists(): boolean
|
||||
protected abstract getCachePath(): string[]
|
||||
}
|
@@ -1,132 +0,0 @@
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import * as os from 'os'
|
||||
|
||||
import * as core from '@actions/core'
|
||||
import * as cache from '@actions/cache'
|
||||
|
||||
const WRAPPER_SLUG = 'WRAPPER_SLUG'
|
||||
|
||||
export async function restoreCachedWrapperDist(
|
||||
gradlewDirectory: string | null
|
||||
): Promise<void> {
|
||||
if (isWrapperCacheDisabled()) return
|
||||
if (gradlewDirectory == null) return
|
||||
|
||||
const wrapperProperties = path.join(
|
||||
path.resolve(gradlewDirectory),
|
||||
'gradle/wrapper/gradle-wrapper.properties'
|
||||
)
|
||||
const wrapperSlug = extractGradleWrapperSlugFrom(wrapperProperties)
|
||||
if (!wrapperSlug) {
|
||||
core.warning(
|
||||
`Could not calculate wrapper version from ${wrapperProperties}`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const wrapperDir = getWrapperDir(wrapperSlug)
|
||||
const cacheKey = getCacheKey(wrapperSlug)
|
||||
const cachePath = getCachePath(wrapperSlug)
|
||||
|
||||
// Check if the wrapper has already been downloaded to Gradle User Home
|
||||
if (fs.existsSync(wrapperDir)) return
|
||||
|
||||
try {
|
||||
const restoredKey = await cache.restoreCache([cachePath], cacheKey)
|
||||
|
||||
if (restoredKey) {
|
||||
core.info(
|
||||
`Wrapper installation restored from cache key: ${restoredKey}`
|
||||
)
|
||||
} else {
|
||||
core.info(
|
||||
`Wrapper installation cache not found. Will download and cache with key: ${cacheKey}.`
|
||||
)
|
||||
// Save the slug to trigger caching of the downloaded wrapper
|
||||
core.saveState(WRAPPER_SLUG, wrapperSlug)
|
||||
}
|
||||
} catch (error) {
|
||||
core.info(
|
||||
`Wrapper installation cache restore failed for key: ${cacheKey}.\n ${error}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function cacheWrapperDist(): Promise<void> {
|
||||
if (isWrapperCacheDisabled()) return
|
||||
|
||||
const wrapperSlug = core.getState(WRAPPER_SLUG)
|
||||
if (!wrapperSlug) return
|
||||
|
||||
const wrapperDir = getWrapperDir(wrapperSlug)
|
||||
const cacheKey = getCacheKey(wrapperSlug)
|
||||
const cachePath = getCachePath(wrapperSlug)
|
||||
|
||||
if (!fs.existsSync(wrapperDir)) {
|
||||
core.warning(`No wrapper installation to cache at ${wrapperDir}`)
|
||||
return
|
||||
}
|
||||
|
||||
core.info(`Will cache wrapper zip ${cachePath} with key ${cacheKey}`)
|
||||
|
||||
try {
|
||||
await cache.saveCache([cachePath], cacheKey)
|
||||
} catch (error) {
|
||||
if (error.name === cache.ValidationError.name) {
|
||||
throw error
|
||||
} else if (error.name === cache.ReserveCacheError.name) {
|
||||
core.info(error.message)
|
||||
} else {
|
||||
core.info(`[warning] ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
export function extractGradleWrapperSlugFrom(
|
||||
wrapperProperties: string
|
||||
): string | null {
|
||||
const props = fs.readFileSync(wrapperProperties, {encoding: 'utf8'})
|
||||
const distUrlLine = props
|
||||
.split('\n')
|
||||
.find(line => line.startsWith('distributionUrl'))
|
||||
if (!distUrlLine) return null
|
||||
return extractGradleWrapperSlugFromDistUri(distUrlLine.substr(16).trim())
|
||||
}
|
||||
|
||||
export function extractGradleWrapperSlugFromDistUri(
|
||||
distUri: string
|
||||
): string | null {
|
||||
const regex = /.*gradle-(.*-(bin|all))\.zip/
|
||||
const match = distUri.match(regex)
|
||||
return match ? match[1] : null
|
||||
}
|
||||
|
||||
function isWrapperCacheDisabled(): boolean {
|
||||
// Check if either 'distributions' or 'wrapper' cache has been disabled
|
||||
const wrapperCacheEnabled = core.getBooleanInput('wrapper-cache-enabled')
|
||||
const distributionsCacheEnabled = core.getBooleanInput(
|
||||
'distributions-cache-enabled'
|
||||
)
|
||||
return !wrapperCacheEnabled || !distributionsCacheEnabled
|
||||
}
|
||||
|
||||
function getCacheKey(wrapperSlug: string): string {
|
||||
return `wrapper-v1-${wrapperSlug}`
|
||||
}
|
||||
|
||||
function getWrapperDir(wrapperSlug: string): string {
|
||||
return path.resolve(
|
||||
os.homedir(),
|
||||
`.gradle/wrapper/dists/gradle-${wrapperSlug}`
|
||||
)
|
||||
}
|
||||
|
||||
function getCachePath(wrapperSlug: string): string {
|
||||
return path.resolve(
|
||||
os.homedir(),
|
||||
`.gradle/wrapper/dists/gradle-${wrapperSlug}/*/gradle-${wrapperSlug}.zip`
|
||||
)
|
||||
}
|
36
src/caches.ts
Normal file
36
src/caches.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import {GradleUserHomeCache} from './cache-gradle-user-home'
|
||||
import {ProjectDotGradleCache} from './cache-project-dot-gradle'
|
||||
import * as core from '@actions/core'
|
||||
import {isCacheDisabled, isCacheReadOnly} from './cache-utils'
|
||||
|
||||
const BUILD_ROOT_DIR = 'BUILD_ROOT_DIR'
|
||||
|
||||
export async function restore(buildRootDirectory: string): Promise<void> {
|
||||
if (isCacheDisabled()) {
|
||||
core.debug('Cache read disabled')
|
||||
return
|
||||
}
|
||||
|
||||
await core.group('Restore Gradle state from cache', async () => {
|
||||
core.saveState(BUILD_ROOT_DIR, buildRootDirectory)
|
||||
return Promise.all([
|
||||
new GradleUserHomeCache(buildRootDirectory).restore(),
|
||||
new ProjectDotGradleCache(buildRootDirectory).restore()
|
||||
])
|
||||
})
|
||||
}
|
||||
|
||||
export async function save(): Promise<void> {
|
||||
if (isCacheReadOnly()) {
|
||||
core.debug('Cache is read-only: not saving cache entry')
|
||||
return
|
||||
}
|
||||
|
||||
await core.group('Caching Gradle state', async () => {
|
||||
const buildRootDirectory = core.getState(BUILD_ROOT_DIR)
|
||||
return Promise.all([
|
||||
new GradleUserHomeCache(buildRootDirectory).save(),
|
||||
new ProjectDotGradleCache(buildRootDirectory).save()
|
||||
])
|
||||
})
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
import * as path from 'path'
|
||||
import * as glob from '@actions/glob'
|
||||
|
||||
export async function hashFiles(
|
||||
baseDir: string,
|
||||
patterns: string[] = ['**'],
|
||||
followSymbolicLinks = false
|
||||
): Promise<string | null> {
|
||||
const combinedPatterns = patterns
|
||||
.map(pattern => `${baseDir}${path.sep}${pattern}`)
|
||||
.join('\n')
|
||||
return glob.hashFiles(combinedPatterns, {followSymbolicLinks})
|
||||
}
|
@@ -1,34 +1,36 @@
|
||||
import * as exec from '@actions/exec'
|
||||
import * as cacheDependencies from './cache-dependencies'
|
||||
import * as cacheConfiguration from './cache-configuration'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import {writeInitScript} from './build-scan-capture'
|
||||
|
||||
export async function execute(
|
||||
executable: string,
|
||||
root: string,
|
||||
argv: string[]
|
||||
args: string[]
|
||||
): Promise<BuildResult> {
|
||||
await cacheDependencies.restoreCachedDependencies(root)
|
||||
await cacheConfiguration.restoreCachedConfiguration(root)
|
||||
|
||||
let publishing = false
|
||||
let buildScanUrl: string | undefined
|
||||
|
||||
const status: number = await exec.exec(executable, argv, {
|
||||
// TODO: instead of running with no-daemon, run `--stop` in post action.
|
||||
args.push('--no-daemon')
|
||||
|
||||
const initScript = writeInitScript()
|
||||
args.push('--init-script')
|
||||
args.push(initScript)
|
||||
|
||||
const buildScanFile = path.resolve(root, 'gradle-build-scan.txt')
|
||||
if (fs.existsSync(buildScanFile)) {
|
||||
fs.unlinkSync(buildScanFile)
|
||||
}
|
||||
|
||||
const status: number = await exec.exec(executable, args, {
|
||||
cwd: root,
|
||||
ignoreReturnCode: true,
|
||||
listeners: {
|
||||
stdline: (line: string) => {
|
||||
if (line.includes('Publishing build scan...')) {
|
||||
publishing = true
|
||||
}
|
||||
if (publishing && line.startsWith('http')) {
|
||||
buildScanUrl = line.trim()
|
||||
publishing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
ignoreReturnCode: true
|
||||
})
|
||||
|
||||
if (fs.existsSync(buildScanFile)) {
|
||||
buildScanUrl = fs.readFileSync(buildScanFile, 'utf-8')
|
||||
}
|
||||
|
||||
return new BuildResultImpl(status, buildScanUrl)
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,7 @@ import fs from 'fs'
|
||||
|
||||
const IS_WINDOWS = process.platform === 'win32'
|
||||
|
||||
export function wrapperFilename(): string {
|
||||
export function wrapperScriptFilename(): string {
|
||||
return IS_WINDOWS ? 'gradlew.bat' : 'gradlew'
|
||||
}
|
||||
|
||||
@@ -11,9 +11,14 @@ export function installScriptFilename(): string {
|
||||
return IS_WINDOWS ? 'gradle.bat' : 'gradle'
|
||||
}
|
||||
|
||||
export function validateGradleWrapper(gradlewDirectory: string): void {
|
||||
export function locateGradleWrapperScript(buildRootDirectory: string): string {
|
||||
validateGradleWrapper(buildRootDirectory)
|
||||
return path.resolve(buildRootDirectory, wrapperScriptFilename())
|
||||
}
|
||||
|
||||
function validateGradleWrapper(buildRootDirectory: string): void {
|
||||
const wrapperProperties = path.resolve(
|
||||
gradlewDirectory,
|
||||
buildRootDirectory,
|
||||
'gradle/wrapper/gradle-wrapper.properties'
|
||||
)
|
||||
if (!fs.existsSync(wrapperProperties)) {
|
||||
|
32
src/main.ts
32
src/main.ts
@@ -2,7 +2,7 @@ import * as core from '@actions/core'
|
||||
import * as path from 'path'
|
||||
import {parseArgsStringToArgv} from 'string-argv'
|
||||
|
||||
import * as cacheWrapper from './cache-wrapper'
|
||||
import * as caches from './caches'
|
||||
import * as execution from './execution'
|
||||
import * as gradlew from './gradlew'
|
||||
import * as provision from './provision'
|
||||
@@ -13,24 +13,34 @@ export async function run(): Promise<void> {
|
||||
const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || ''
|
||||
const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory)
|
||||
|
||||
await caches.restore(buildRootDirectory)
|
||||
|
||||
const args: string[] = parseCommandLineArguments()
|
||||
|
||||
const result = await execution.execute(
|
||||
await resolveGradleExecutable(
|
||||
workspaceDirectory,
|
||||
buildRootDirectory
|
||||
),
|
||||
buildRootDirectory,
|
||||
parseCommandLineArguments()
|
||||
args
|
||||
)
|
||||
|
||||
if (result.buildScanUrl) {
|
||||
core.setOutput('build-scan-url', result.buildScanUrl)
|
||||
// TODO Include context about the invocation (eg step name) in this message
|
||||
// Unfortunately it doesn't seem possible to access the current step name here
|
||||
core.notice(`Gradle build scan: ${result.buildScanUrl}`)
|
||||
}
|
||||
|
||||
if (result.status !== 0) {
|
||||
core.setFailed(`Gradle process exited with status ${result.status}`)
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message)
|
||||
core.setFailed(String(error))
|
||||
if (error instanceof Error && error.stack) {
|
||||
core.info(error.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,24 +57,10 @@ async function resolveGradleExecutable(
|
||||
|
||||
const gradleExecutable = core.getInput('gradle-executable')
|
||||
if (gradleExecutable !== '') {
|
||||
if (gradleExecutable.endsWith(gradlew.wrapperFilename())) {
|
||||
await cacheWrapper.restoreCachedWrapperDist(
|
||||
path.resolve(gradleExecutable, '..')
|
||||
)
|
||||
}
|
||||
return path.resolve(workspaceDirectory, gradleExecutable)
|
||||
}
|
||||
|
||||
const wrapperDirectory = core.getInput('wrapper-directory')
|
||||
const gradlewDirectory =
|
||||
wrapperDirectory !== ''
|
||||
? path.resolve(workspaceDirectory, wrapperDirectory)
|
||||
: buildRootDirectory
|
||||
|
||||
gradlew.validateGradleWrapper(gradlewDirectory)
|
||||
await cacheWrapper.restoreCachedWrapperDist(gradlewDirectory)
|
||||
|
||||
return path.resolve(gradlewDirectory, gradlew.wrapperFilename())
|
||||
return gradlew.locateGradleWrapperScript(buildRootDirectory)
|
||||
}
|
||||
|
||||
function resolveBuildRootDirectory(baseDirectory: string): string {
|
||||
|
22
src/post.ts
22
src/post.ts
@@ -1,20 +1,16 @@
|
||||
import * as core from '@actions/core'
|
||||
|
||||
import * as cacheWrapper from './cache-wrapper'
|
||||
import * as cacheDependencies from './cache-dependencies'
|
||||
import * as cacheConfiguration from './cache-configuration'
|
||||
import * as caches from './caches'
|
||||
|
||||
// Invoked by GitHub Actions
|
||||
export async function run(): Promise<void> {
|
||||
if (isCacheReadOnly()) return
|
||||
|
||||
await cacheWrapper.cacheWrapperDist()
|
||||
await cacheDependencies.cacheDependencies()
|
||||
await cacheConfiguration.cacheConfiguration()
|
||||
}
|
||||
|
||||
function isCacheReadOnly(): boolean {
|
||||
return core.getBooleanInput('cache-read-only')
|
||||
try {
|
||||
await caches.save()
|
||||
} catch (error) {
|
||||
core.setFailed(String(error))
|
||||
if (error instanceof Error && error.stack) {
|
||||
core.info(error.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
||||
|
@@ -7,6 +7,7 @@ import * as cache from '@actions/cache'
|
||||
import * as toolCache from '@actions/tool-cache'
|
||||
|
||||
import * as gradlew from './gradlew'
|
||||
import {isCacheDisabled, isCacheReadOnly} from './cache-utils'
|
||||
|
||||
const gradleVersionsBaseUrl = 'https://services.gradle.org/versions'
|
||||
|
||||
@@ -92,6 +93,14 @@ async function findGradleVersionDeclaration(
|
||||
|
||||
async function provisionGradle(
|
||||
versionInfo: GradleVersionInfo
|
||||
): Promise<string> {
|
||||
return core.group(`Provision Gradle ${versionInfo.version}`, async () => {
|
||||
return locateGradleAndDownloadIfRequired(versionInfo)
|
||||
})
|
||||
}
|
||||
|
||||
async function locateGradleAndDownloadIfRequired(
|
||||
versionInfo: GradleVersionInfo
|
||||
): Promise<string> {
|
||||
const installsDir = path.join(os.homedir(), 'gradle-installations/installs')
|
||||
const installDir = path.join(installsDir, `gradle-${versionInfo.version}`)
|
||||
@@ -119,7 +128,7 @@ async function downloadAndCacheGradleDistribution(
|
||||
`gradle-installations/downloads/gradle-${versionInfo.version}-bin.zip`
|
||||
)
|
||||
|
||||
if (isDistributionsCacheDisabled()) {
|
||||
if (isCacheDisabled()) {
|
||||
await downloadGradleDistribution(versionInfo, downloadPath)
|
||||
return downloadPath
|
||||
}
|
||||
@@ -130,22 +139,25 @@ async function downloadAndCacheGradleDistribution(
|
||||
core.info(
|
||||
`Restored Gradle distribution ${cacheKey} from cache to ${downloadPath}`
|
||||
)
|
||||
} else {
|
||||
core.info(
|
||||
`Gradle distribution ${versionInfo.version} not found in cache. Will download.`
|
||||
)
|
||||
await downloadGradleDistribution(versionInfo, downloadPath)
|
||||
return downloadPath
|
||||
}
|
||||
core.info(
|
||||
`Gradle distribution ${versionInfo.version} not found in cache. Will download.`
|
||||
)
|
||||
await downloadGradleDistribution(versionInfo, downloadPath)
|
||||
|
||||
if (!isCacheReadOnly()) {
|
||||
try {
|
||||
await cache.saveCache([downloadPath], cacheKey)
|
||||
} catch (error) {
|
||||
if (error.name === cache.ValidationError.name) {
|
||||
// Fail on validation errors or non-errors (the latter to keep Typescript happy)
|
||||
if (
|
||||
error instanceof cache.ValidationError ||
|
||||
!(error instanceof Error)
|
||||
) {
|
||||
throw error
|
||||
} else if (error.name === cache.ReserveCacheError.name) {
|
||||
core.info(error.message)
|
||||
} else {
|
||||
core.info(`[warning] ${error.message}`)
|
||||
}
|
||||
core.warning(error.message)
|
||||
}
|
||||
}
|
||||
return downloadPath
|
||||
@@ -183,10 +195,6 @@ async function httpGetString(url: string): Promise<string> {
|
||||
return response.readBody()
|
||||
}
|
||||
|
||||
function isDistributionsCacheDisabled(): boolean {
|
||||
return !core.getBooleanInput('distributions-cache-enabled')
|
||||
}
|
||||
|
||||
interface GradleVersionInfo {
|
||||
version: string
|
||||
downloadUrl: string
|
||||
|
Reference in New Issue
Block a user