mirror of
https://github.com/gradle/gradle-build-action.git
synced 2025-10-20 15:18:56 +08:00
Compare commits
186 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3edb3cb004 | ||
|
3609b7787a | ||
|
f804351b51 | ||
|
39e51526fb | ||
|
76ea8a76b2 | ||
|
12fc52a49a | ||
|
c157d0a332 | ||
|
c61f5d87b4 | ||
|
c208b4c1f7 | ||
|
b4e6c2b28a | ||
|
b84b650c31 | ||
|
eda0038770 | ||
|
ed5b4ae5dc | ||
|
d50632cfd1 | ||
|
40c0a12211 | ||
|
e977669c8c | ||
|
0e8b9655a0 | ||
|
367ce74a5f | ||
|
3814d56740 | ||
|
e1f84aa44d | ||
|
1041604f29 | ||
|
253d6427fd | ||
|
69aad1f173 | ||
|
887e1a09ab | ||
|
f344e25b84 | ||
|
574cf0ddce | ||
|
37f2880a8a | ||
|
b88c4086b9 | ||
|
aa9bf7774e | ||
|
ed2ff1a448 | ||
|
ddee3ca933 | ||
|
03d1894080 | ||
|
322805e800 | ||
|
92a1f98d35 | ||
|
fdfc5bf12f | ||
|
a25c0ce6cb | ||
|
76f85a724c | ||
|
45ef022607 | ||
|
a72af0b6a6 | ||
|
b0c29bffb7 | ||
|
996094e8e8 | ||
|
4137be6a8b | ||
|
4e899835b3 | ||
|
3812292b26 | ||
|
c12283ec57 | ||
|
f2dc0d8256 | ||
|
717db318c1 | ||
|
2a57ddf74a | ||
|
230fd6b47f | ||
|
472ac8a356 | ||
|
3ba05ede1f | ||
|
d785346c8c | ||
|
6ca4d4ade2 | ||
|
75cec40e58 | ||
|
c317ccac62 | ||
|
a74bb0fad6 | ||
|
6ff2065a12 | ||
|
727b4612ba | ||
|
613f4ec588 | ||
|
db6202adcd | ||
|
f0f68e07c3 | ||
|
8ba5a0033b | ||
|
9edc2a11bd | ||
|
079e4844d6 | ||
|
4ebd000afd | ||
|
063fc6a872 | ||
|
e3ada7e5c2 | ||
|
d61e5be06a | ||
|
db2b34260f | ||
|
c031dc946b | ||
|
0eb881f067 | ||
|
27f2dc276c | ||
|
cba1833dde | ||
|
39db90e99b | ||
|
947a893558 | ||
|
b99e9f0bc3 | ||
|
4cf255df10 | ||
|
614d8770a4 | ||
|
69453dbfc5 | ||
|
1113cb87cb | ||
|
9c95294209 | ||
|
f901ec9c20 | ||
|
a94b9252d5 | ||
|
25672bf196 | ||
|
cb6a0acca4 | ||
|
aa2ed2e033 | ||
|
263f84178a | ||
|
0eb5996567 | ||
|
fe55bf4667 | ||
|
709ded51a5 | ||
|
8b1f1a3817 | ||
|
7abf13ee48 | ||
|
da64595ccc | ||
|
29b14c7fca | ||
|
d1ab42cddf | ||
|
422726cec5 | ||
|
4bc52c85c3 | ||
|
e7b5fd0b28 | ||
|
53ccc3e0d7 | ||
|
8ab7c9d8dd | ||
|
0cf00ed767 | ||
|
aedc5fc8f9 | ||
|
78e25cd233 | ||
|
29894757f3 | ||
|
5328161026 | ||
|
4968d2280b | ||
|
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 | ||
|
e0c2736e35 | ||
|
a63892c289 | ||
|
d432f2086c | ||
|
eaad2cd2bb | ||
|
a148b21183 | ||
|
e7422f245c | ||
|
c86093d76a | ||
|
a693ccda4b | ||
|
543cacb256 | ||
|
3f3947669a |
@@ -10,8 +10,10 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"eslint-comments/no-use": "off",
|
"eslint-comments/no-use": "off",
|
||||||
"import/no-namespace": "off",
|
"import/no-namespace": "off",
|
||||||
|
"i18n-text/no-en": "off",
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "error",
|
"sort-imports": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
||||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||||
"@typescript-eslint/no-require-imports": "error",
|
"@typescript-eslint/no-require-imports": "error",
|
||||||
"@typescript-eslint/array-type": "error",
|
"@typescript-eslint/array-type": "error",
|
||||||
|
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ main ]
|
||||||
|
schedule:
|
||||||
|
- cron: '25 23 * * 2'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'javascript' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
|
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
4
.github/workflows/dev.yml
vendored
4
.github/workflows/dev.yml
vendored
@@ -1,8 +1,8 @@
|
|||||||
# make sure the build works and doesn't produce spurious changes
|
name: Verify generated outputs
|
||||||
name: dev
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
push:
|
push:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
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:
|
||||||
|
GRADLE_BUILD_ACTION_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
|
31
.github/workflows/integTest-action-inputs.yml
vendored
Normal file
31
.github/workflows/integTest-action-inputs.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
name: Test different action inputs
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
action-inputs:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Invoke with multi-line arguments
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
build-root-directory: __tests__/samples/groovy-dsl
|
||||||
|
arguments: |
|
||||||
|
--configuration-cache
|
||||||
|
--build-cache
|
||||||
|
-DsystemProperty=FOO
|
||||||
|
-PgradleProperty=BAR
|
||||||
|
test
|
||||||
|
jar
|
60
.github/workflows/integTest-caching-config.yml
vendored
Normal file
60
.github/workflows/integTest-caching-config.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
name: Test caching configuration
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
seed-build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
# Add "enterprise" to main cache entry but omit "notifications"
|
||||||
|
gradle-home-cache-includes: |
|
||||||
|
caches
|
||||||
|
enterprise
|
||||||
|
# Exclude build-cache from main cache entry
|
||||||
|
gradle-home-cache-excludes: |
|
||||||
|
caches/build-cache-1
|
||||||
|
- name: Build using Gradle wrapper
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test
|
||||||
|
|
||||||
|
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline
|
||||||
|
verify-build:
|
||||||
|
needs: seed-build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
# Use the same configuration when restoring state from cache
|
||||||
|
gradle-home-cache-includes: |
|
||||||
|
caches
|
||||||
|
enterprise
|
||||||
|
gradle-home-cache-excludes: |
|
||||||
|
caches/build-cache-1
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Execute Gradle build with --offline
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test --offline
|
||||||
|
|
||||||
|
|
127
.github/workflows/integTest-caching-configuration-cache.yml
vendored
Normal file
127
.github/workflows/integTest-caching-configuration-cache.yml
vendored
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
name: Test save/restore configuration-cache state
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||||
|
|
||||||
|
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-groovy:
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-groovy-
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Groovy build with configuration-cache enabled
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test --configuration-cache
|
||||||
|
|
||||||
|
configuration-cache-groovy:
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-groovy-
|
||||||
|
needs: seed-build-groovy
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Execute Gradle build and verify cached configuration
|
||||||
|
env:
|
||||||
|
VERIFY_CACHED_CONFIGURATION: true
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test --configuration-cache
|
||||||
|
|
||||||
|
# Check that the build can run when no extracted cache entries are restored
|
||||||
|
no-extracted-cache-entries-restored:
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-groovy-
|
||||||
|
needs: seed-build-groovy
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle with no extracted cache entries restored
|
||||||
|
uses: ./
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl"
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Check execute Gradle build with configuration cache enabled (but not restored)
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test --configuration-cache
|
||||||
|
|
||||||
|
seed-build-kotlin:
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-kotlin-
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Kotlin build with configuration-cache enabled
|
||||||
|
working-directory: __tests__/samples/kotlin-dsl
|
||||||
|
run: ./gradlew help --configuration-cache
|
||||||
|
|
||||||
|
modify-build-kotlin:
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-kotlin-
|
||||||
|
needs: seed-build-kotlin
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Kotlin build with configuration-cache enabled
|
||||||
|
working-directory: __tests__/samples/kotlin-dsl
|
||||||
|
run: ./gradlew test --configuration-cache
|
||||||
|
|
||||||
|
# Test restore configuration-cache from the third build invocation
|
||||||
|
configuration-cache-kotlin:
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-kotlin-
|
||||||
|
needs: modify-build-kotlin
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Execute Gradle build and verify cached configuration
|
||||||
|
env:
|
||||||
|
VERIFY_CACHED_CONFIGURATION: true
|
||||||
|
working-directory: __tests__/samples/kotlin-dsl
|
||||||
|
run: ./gradlew test --configuration-cache
|
82
.github/workflows/integTest-caching-gradle-home.yml
vendored
Normal file
82
.github/workflows/integTest-caching-gradle-home.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
name: Test save/restore Gradle Home directory
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
seed-build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Build using Gradle wrapper
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test
|
||||||
|
|
||||||
|
# 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, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Execute Gradle build with --offline
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test --offline
|
||||||
|
|
||||||
|
# Test that the gradle-user-home cache will cache and restore local build-cache
|
||||||
|
build-cache:
|
||||||
|
needs: seed-build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Execute Gradle build and verify tasks from cache
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test -DverifyCachedBuild=true
|
||||||
|
|
||||||
|
# Check that the build can run when Gradle User Home is not fully restored
|
||||||
|
no-extracted-cache-entries-restored:
|
||||||
|
needs: seed-build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle with no extracted cache entries restored
|
||||||
|
uses: ./
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_SKIP_RESTORE: "generated-gradle-jars|wrapper-zips|java-toolchains|instrumented-jars|dependencies|kotlin-dsl"
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Check executee Gradle build
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test
|
||||||
|
|
43
.github/workflows/integTest-caching-java-toolchain.yml
vendored
Normal file
43
.github/workflows/integTest-caching-java-toolchain.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
name: Test save/restore java toolchains
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
seed-build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Build using Gradle wrapper
|
||||||
|
working-directory: __tests__/samples/java-toolchain
|
||||||
|
run: ./gradlew test --info
|
||||||
|
|
||||||
|
# Test that the gradle-user-home cache will cache the toolchain, by running build with --offline
|
||||||
|
toolchain-cache:
|
||||||
|
needs: seed-build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Execute Gradle build with --offline
|
||||||
|
working-directory: __tests__/samples/java-toolchain
|
||||||
|
run: ./gradlew test --info --offline
|
43
.github/workflows/integTest-execution-with-caching.yml
vendored
Normal file
43
.github/workflows/integTest-execution-with-caching.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
name: Test save/restore Gradle state with direct execution
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
seed-build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Exucute Gradle build
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
build-root-directory: __tests__/samples/groovy-dsl
|
||||||
|
arguments: test
|
||||||
|
|
||||||
|
# Test that the gradle-user-home is restored
|
||||||
|
verify-build:
|
||||||
|
needs: seed-build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Execute Gradle build
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
build-root-directory: __tests__/samples/groovy-dsl
|
||||||
|
arguments: test --offline -DverifyCachedBuild=true
|
||||||
|
|
73
.github/workflows/integTest-execution.yml
vendored
Normal file
73
.github/workflows/integTest-execution.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: Test Gradle execution
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_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, 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
|
||||||
|
- 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:
|
||||||
|
gradle: [7.3, 6.9, 5.6.4, 4.10.3]
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
include:
|
||||||
|
- gradle: 5.6.4
|
||||||
|
build-root-suffix: -gradle-5
|
||||||
|
- gradle: 4.10.3
|
||||||
|
build-root-suffix: -gradle-4
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Run Gradle build
|
||||||
|
uses: ./
|
||||||
|
id: gradle
|
||||||
|
with:
|
||||||
|
gradle-version: ${{matrix.gradle}}
|
||||||
|
build-root-directory: __tests__/samples/no-wrapper${{ matrix.build-root-suffix }}
|
||||||
|
arguments: help -DgradleVersionCheck=${{matrix.gradle}}
|
||||||
|
- name: Check build scan url
|
||||||
|
if: ${{ !steps.gradle.outputs.build-scan-url }}
|
||||||
|
uses: actions/github-script@v3
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.setFailed('No build scan detected')
|
||||||
|
|
||||||
|
|
64
.github/workflows/integTest-gradle-user-home.yml
vendored
Normal file
64
.github/workflows/integTest-gradle-user-home.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
name: Test caching with a custom GRADLE_USER_HOME
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||||
|
GRADLE_USER_HOME: ${{github.workspace}}/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:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Build using Gradle wrapper
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test --info
|
||||||
|
|
||||||
|
# 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, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Execute Gradle build with --offline
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test --offline --info
|
||||||
|
|
||||||
|
# Test that the gradle-user-home cache will cache and restore local build-cache
|
||||||
|
build-cache:
|
||||||
|
needs: seed-build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
cache-read-only: true
|
||||||
|
- name: Execute Gradle build and verify tasks from cache
|
||||||
|
working-directory: __tests__/samples/groovy-dsl
|
||||||
|
run: ./gradlew test -DverifyCachedBuild=true --info
|
77
.github/workflows/integTest-gradle-versions.yml
vendored
Normal file
77
.github/workflows/integTest-gradle-versions.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
name: Test provision different Gradle versions
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_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.
|
||||||
|
provision-gradle:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
script-suffix: '.bat'
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle with v6.9
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
gradle-version: 6.9
|
||||||
|
- name: Test uses Gradle v6.9
|
||||||
|
working-directory: __tests__/samples/no-wrapper
|
||||||
|
run: gradle help "-DgradleVersionCheck=6.9"
|
||||||
|
- name: Setup Gradle with v7.1.1
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
gradle-version: 7.1.1
|
||||||
|
- name: Test uses Gradle v7.1.1
|
||||||
|
working-directory: __tests__/samples/no-wrapper
|
||||||
|
run: gradle help "-DgradleVersionCheck=7.1.1"
|
||||||
|
- name: Setup Gradle with release-candidate
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
gradle-version: release-candidate
|
||||||
|
- name: Test use release-candidate
|
||||||
|
working-directory: __tests__/samples/no-wrapper
|
||||||
|
run: gradle help
|
||||||
|
|
||||||
|
gradle-versions:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
gradle: [7.3, 6.9, 5.6.4, 4.10.3]
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
include:
|
||||||
|
- gradle: 5.6.4
|
||||||
|
build-root-suffix: -gradle-5
|
||||||
|
- gradle: 4.10.3
|
||||||
|
build-root-suffix: -gradle-4
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
gradle-version: ${{ matrix.gradle }}
|
||||||
|
- name: Run Gradle build
|
||||||
|
id: gradle
|
||||||
|
working-directory: __tests__/samples/no-wrapper${{ matrix.build-root-suffix }}
|
||||||
|
run: gradle help "-DgradleVersionCheck=${{matrix.gradle}}"
|
||||||
|
- name: Check build scan url
|
||||||
|
if: ${{ !steps.gradle.outputs.build-scan-url }}
|
||||||
|
uses: actions/github-script@v3
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.setFailed('No build scan detected')
|
||||||
|
|
||||||
|
|
41
.github/workflows/integTest-sample-gradle-plugin.yml
vendored
Normal file
41
.github/workflows/integTest-sample-gradle-plugin.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
name: Test caching with Gradle Plugin project using TestKit
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
seed-build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Build gradle-plugin project
|
||||||
|
working-directory: __tests__/samples/gradle-plugin
|
||||||
|
run: ./gradlew build
|
||||||
|
|
||||||
|
verify-build:
|
||||||
|
needs: seed-build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Build gradle-plugin project
|
||||||
|
working-directory: __tests__/samples/gradle-plugin
|
||||||
|
run: ./gradlew build --offline
|
41
.github/workflows/integTest-sample-kotlin-dsl.yml
vendored
Normal file
41
.github/workflows/integTest-sample-kotlin-dsl.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
name: Test caching with Kotlin DSL
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{github.workflow}}#${{github.run_number}}-
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
seed-build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Build kotlin-dsl project
|
||||||
|
working-directory: __tests__/samples/kotlin-dsl
|
||||||
|
run: ./gradlew build
|
||||||
|
|
||||||
|
verify-build:
|
||||||
|
needs: seed-build
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: ./
|
||||||
|
- name: Build kotlin-dsl project
|
||||||
|
working-directory: __tests__/samples/kotlin-dsl
|
||||||
|
run: ./gradlew build --offline
|
27
.github/workflows/pr-build-scan-comment.yml
vendored
Normal file
27
.github/workflows/pr-build-scan-comment.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
name: Add a build scan comment to PR
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [assigned, review_requested]
|
||||||
|
jobs:
|
||||||
|
gradle:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
- uses: ./
|
||||||
|
- id: gradle
|
||||||
|
working-directory: __tests__/samples/kotlin-dsl
|
||||||
|
run: ./gradlew help
|
||||||
|
- name: "Comment build scan url"
|
||||||
|
uses: actions/github-script@v3
|
||||||
|
with:
|
||||||
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
script: |
|
||||||
|
github.issues.createComment({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: 'PR ready for review: ${{ steps.gradle.outputs.build-scan-url }}'
|
||||||
|
})
|
93
.github/workflows/prod.yml
vendored
93
.github/workflows/prod.yml
vendored
@@ -1,93 +0,0 @@
|
|||||||
# make sure the action works on a clean machine without building
|
|
||||||
name: prod
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
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 Gradle wrapper
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
build-root-directory: __tests__/samples/basic
|
|
||||||
arguments: test
|
|
||||||
- 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:
|
|
||||||
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:
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
failures: # These build invocations are informational only, and are expected to fail
|
|
||||||
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
|
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 80,
|
"printWidth": 120,
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"useTabs": false,
|
"useTabs": false,
|
||||||
"semi": false,
|
"semi": false,
|
||||||
|
370
README.md
370
README.md
@@ -1,13 +1,15 @@
|
|||||||
# Execute Gradle builds in GitHub Actions workflows
|
# Execute Gradle builds in GitHub Actions workflows
|
||||||
|
|
||||||
This GitHub Action can be used to execute a Gradle build on any platform supported by GitHub Actions.
|
This GitHub Action can be used to configure Gradle and optionally execute a Gradle build on any platform supported by GitHub Actions.
|
||||||
|
|
||||||
## Usage
|
## Use the action to setup Gradle
|
||||||
|
|
||||||
The following workflow will run `./gradlew build` 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.
|
If you have an existing workflow invoking Gradle, you can add an initial "Setup Gradle" Step to benefit from caching,
|
||||||
|
build-scan capture and other features of the gradle-build-action.
|
||||||
|
|
||||||
|
All subsequent Gradle invocations will benefit from this initial setup, via `init` scripts added to the Gradle User Home.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# .github/workflows/gradle-build-pr.yml
|
|
||||||
name: Run Gradle on PRs
|
name: Run Gradle on PRs
|
||||||
on: pull_request
|
on: pull_request
|
||||||
jobs:
|
jobs:
|
||||||
@@ -21,70 +23,40 @@ jobs:
|
|||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: gradle/gradle-build-action@v1
|
|
||||||
with:
|
- name: Setup Gradle
|
||||||
arguments: build
|
uses: gradle/gradle-build-action@v2
|
||||||
|
|
||||||
|
- name: Execute Gradle build
|
||||||
|
run: ./gradlew build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Gradle arguments
|
## Why use the `gradle-build-action`?
|
||||||
|
|
||||||
The `arguments` input can used to pass arbitrary arguments to the `gradle` command line.
|
It is possible to directly invoke Gradle in your workflow, and the `setup-java` action provides a simple way to cache Gradle dependencies.
|
||||||
|
|
||||||
Here are some valid examples:
|
However, the `gradle-build-action` offers a number of advantages over this approach:
|
||||||
```yaml
|
|
||||||
arguments: build
|
|
||||||
arguments: check --scan
|
|
||||||
arguments: some arbitrary tasks
|
|
||||||
arguments: build -PgradleProperty=foo
|
|
||||||
arguments: build -DsystemProperty=bar
|
|
||||||
....
|
|
||||||
```
|
|
||||||
|
|
||||||
See `gradle --help` for more information.
|
- Easily [run the build with different versions of Gradle](#download-install-and-use-a-specific-gradle-version) using the `gradle-version` parameter. Gradle distributions are automatically downloaded and cached.
|
||||||
|
- More sophisticated and more efficient caching of Gradle User Home between invocations, compared to `setup-java` and most custom configurations using `actions/cache`. [More details below](#caching).
|
||||||
|
- Detailed reporting of cache usage and cache configuration options allow you to [optimize the use of the GitHub actions cache](#optimizing-cache-effectiveness).
|
||||||
|
- [Automatic capture of build scan links](#build-scans) from the build, making these easier to locate for workflow run.
|
||||||
|
|
||||||
If you need to pass environment variables, simply use the GitHub Actions workflow syntax:
|
The `gradle-build-action` is designed to provide these benefits with minimal configuration.
|
||||||
|
These features work both when Gradle is executed via the `gradle-build-action` and for any Gradle execution in subsequent steps.
|
||||||
|
|
||||||
|
## Use a specific Gradle version
|
||||||
|
|
||||||
|
The `gradle-build-action` can download and install a specified Gradle version, adding this installed version to the PATH.
|
||||||
|
Downloaded Gradle versions are stored in the GitHub Actions cache, to avoid requiring downloading again later.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: gradle/gradle-build-action@v1
|
- uses: gradle/gradle-build-action@v2
|
||||||
env:
|
|
||||||
CI: true
|
|
||||||
```
|
|
||||||
|
|
||||||
## Run a build from a different directory
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: gradle/gradle-build-action@v1
|
|
||||||
with:
|
|
||||||
build-root-directory: some/subdirectory
|
|
||||||
```
|
|
||||||
|
|
||||||
## Use a specific `gradle` executable
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: gradle/gradle-build-action@v1
|
|
||||||
with:
|
|
||||||
gradle-executable: path/to/gradle
|
|
||||||
```
|
|
||||||
|
|
||||||
## Use a Gradle wrapper from a different directory
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: gradle/gradle-build-action@v1
|
|
||||||
with:
|
|
||||||
gradle-executable: path/to/gradlew
|
|
||||||
```
|
|
||||||
|
|
||||||
NOTE: The `wrapper-directory` input has been deprecated. Use `gradle-executable` instead.
|
|
||||||
|
|
||||||
## Setup and use a declared Gradle version
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: gradle/gradle-build-action@v1
|
|
||||||
with:
|
with:
|
||||||
gradle-version: 6.5
|
gradle-version: 6.5
|
||||||
```
|
```
|
||||||
|
|
||||||
`gradle-version` can be set to any valid Gradle version.
|
The `gradle-version` parameter can be set to any valid Gradle version.
|
||||||
|
|
||||||
Moreover, you can use the following aliases:
|
Moreover, you can use the following aliases:
|
||||||
|
|
||||||
@@ -96,10 +68,9 @@ Moreover, you can use the following aliases:
|
|||||||
| `nightly` | The latest [nightly](https://gradle.org/nightly/), fails if none. |
|
| `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. |
|
| `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
|
```yaml
|
||||||
# .github/workflows/test-gradle-rc.yml
|
|
||||||
name: Test latest Gradle RC
|
name: Test latest Gradle RC
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
@@ -112,91 +83,19 @@ jobs:
|
|||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: gradle/gradle-build-action@v1
|
- uses: gradle/gradle-build-action@v2
|
||||||
with:
|
with:
|
||||||
gradle-version: release-candidate
|
gradle-version: release-candidate
|
||||||
arguments: build --dry-run # just test build configuration
|
- run: gradle build --dry-run # just test build configuration
|
||||||
```
|
```
|
||||||
|
|
||||||
## Caching
|
## Gradle Execution
|
||||||
|
|
||||||
This action provides 3 levels of caching to help speed up your GitHub Actions:
|
If the action is configured with an `arguments` input, then Gradle will execute a Gradle build with the arguments provided.
|
||||||
|
|
||||||
- `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 ;
|
If no `arguments` are provided, the action will not execute Gradle, but will still cache Gradle state and configure build-scan capture for all subsequent Gradle executions.
|
||||||
- `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.
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
distributions-cache-enabled: true
|
|
||||||
dependencies-cache-enabled: true
|
|
||||||
configuration-cache-enabled: 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.
|
|
||||||
|
|
||||||
The distributions cache is simple and can't be configured further.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Note that enabling configuration cache without thee dependencies cache is not permitted, since a hit in the configuration cache assumes that dependencies are already present in the local dependencies 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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`.
|
|
||||||
|
|
||||||
You can then use that link in subsequent actions of your workflow.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# .github/workflows/gradle-build-pr.yml
|
|
||||||
name: Run Gradle on PRs
|
name: Run Gradle on PRs
|
||||||
on: pull_request
|
on: pull_request
|
||||||
jobs:
|
jobs:
|
||||||
@@ -210,10 +109,205 @@ jobs:
|
|||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 11
|
java-version: 11
|
||||||
- uses: gradle/gradle-build-action@v1
|
|
||||||
|
- name: Setup and execute Gradle 'test' task
|
||||||
|
uses: gradle/gradle-build-action@v2
|
||||||
with:
|
with:
|
||||||
arguments: build
|
arguments: test
|
||||||
id: gradle
|
```
|
||||||
|
|
||||||
|
### Multiple Gradle executions in the same Job
|
||||||
|
|
||||||
|
It is possible to configure multiple Gradle executions to run sequentially in the same job.
|
||||||
|
The initial Action step will perform the Gradle setup.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: gradle/gradle-build-action@v2
|
||||||
|
with:
|
||||||
|
arguments: assemble
|
||||||
|
- uses: gradle/gradle-build-action@v2
|
||||||
|
with:
|
||||||
|
arguments: check
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gradle command-line arguments
|
||||||
|
|
||||||
|
The `arguments` input can used to pass arbitrary arguments to the `gradle` command line.
|
||||||
|
Arguments can be supplied in a single line, or as a multi-line input.
|
||||||
|
|
||||||
|
Here are some valid examples:
|
||||||
|
```yaml
|
||||||
|
arguments: build
|
||||||
|
arguments: check --scan
|
||||||
|
arguments: some arbitrary tasks
|
||||||
|
arguments: build -PgradleProperty=foo
|
||||||
|
arguments: |
|
||||||
|
build
|
||||||
|
--scan
|
||||||
|
-PgradleProperty=foo
|
||||||
|
-DsystemProperty=bar
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to pass environment variables, use the GitHub Actions workflow syntax:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: gradle/gradle-build-action@v2
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
|
with:
|
||||||
|
arguments: build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gradle build located in a subdirectory
|
||||||
|
|
||||||
|
By default, the action will execute Gradle in the root directory of your project.
|
||||||
|
Use the `build-root-directory` input to target a Gradle build in a subdirectory.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: gradle/gradle-build-action@v2
|
||||||
|
with:
|
||||||
|
arguments: build
|
||||||
|
build-root-directory: some/subdirectory
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using a specific Gradle executable
|
||||||
|
|
||||||
|
The action will first look for a Gradle wrapper script in the root directory of your project.
|
||||||
|
If not found, `gradle` will be executed from the PATH.
|
||||||
|
Use the `gradle-executable` input to execute using a specific Gradle installation.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: gradle/gradle-build-action@v2
|
||||||
|
with:
|
||||||
|
arguments: build
|
||||||
|
gradle-executable: /path/to/installed/gradle
|
||||||
|
```
|
||||||
|
|
||||||
|
This mechanism can also be used to target a Gradle wrapper script that is located in a non-default location.
|
||||||
|
|
||||||
|
## Caching
|
||||||
|
|
||||||
|
By default, this action aims to cache any and all reusable state that may be speed up a subsequent build invocation.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
cache-disabled: true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cache keys
|
||||||
|
|
||||||
|
For distributions downloaded to satisfy a `gradle-version` parametere are stored outside of Gradle User Home and cached separately. The cache key is unique to the downloaded distribution and will not change over time.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
You can enable read-only caching for any of the caches as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Only write to the cache for builds on the 'main' branch.
|
||||||
|
# Builds on other branches will only read existing entries from the cache.
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gradle User Home cache tuning
|
||||||
|
|
||||||
|
As well as any wrapper distributions, the action will attempt to save and restore the `caches` and `notifications` directories from Gradle User Home.
|
||||||
|
|
||||||
|
The contents to be cached can be fine tuned by including and excluding certain paths with Gradle User Home.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Cache downloaded JDKs in addition to the default directories.
|
||||||
|
gradle-home-cache-includes: |
|
||||||
|
caches
|
||||||
|
notifications
|
||||||
|
jdks
|
||||||
|
# Exclude the local build-cache from the directories cached.
|
||||||
|
gradle-home-cache-excludes: |
|
||||||
|
caches/build-cache-1
|
||||||
|
```
|
||||||
|
|
||||||
|
You can specify any number of fixed paths or patterns to include or exclude.
|
||||||
|
File pattern support is documented at https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#patterns-to-match-file-paths.
|
||||||
|
|
||||||
|
### Cache debugging and analysis
|
||||||
|
|
||||||
|
Gradle User Home state will be restored from the cache during the first `gradle-build-action` step for any workflow job.
|
||||||
|
This state will be saved back to the cache at the end of the job, after all Gradle executions have completed.
|
||||||
|
A report of all cache entries restored and saved is printed to the action log when saving the cache entries.
|
||||||
|
This report can provide valuable insignt into how much cache space is being used.
|
||||||
|
|
||||||
|
It is possible to enable additional debug logging for cache operations. You do via the `GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED` environment variable:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
env:
|
||||||
|
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that this setting will also prevent certain cache operations from running in parallel, further assisting with debugging.
|
||||||
|
|
||||||
|
### Optimizing cache effectiveness
|
||||||
|
|
||||||
|
Cache storage space for GitHub actions is limited, and writing new cache entries can trigger the deletion of exising entries.
|
||||||
|
Eviction of shared cache entries can reduce cache effectiveness, slowing down your `gradle-build-action` steps.
|
||||||
|
|
||||||
|
There are a number of actions you can take if your cache use is less effective due to entry eviction.
|
||||||
|
|
||||||
|
#### Only write to the cache from the default branch
|
||||||
|
|
||||||
|
GitHub cache entries are not shared between builds on different branches. This means that identical cache entries will be stored separately for different branches.
|
||||||
|
The exception to the is cache entries for the default (`master`/`main`) branch can be read by actions invoked for other branches.
|
||||||
|
|
||||||
|
An easy way to reduce cache usage when you run builds on many different branches is to only permit your default branch to write to the cache,
|
||||||
|
with all other branch builds using `cache-read-only`. See [Using the caches read-only](#using-the-caches-read-only) for more details.
|
||||||
|
|
||||||
|
Similarly, you could use `cache-read-only` for certain jobs in the workflow, and instead have these jobs reuse the cache content from upstream jobs.
|
||||||
|
|
||||||
|
#### Exclude content from Gradle User Home cache
|
||||||
|
|
||||||
|
Each build is different, and some builds produce more Gradle User Home content than others.
|
||||||
|
[Cache debugging ](#cache-debugging-and-analysis) can provide insight into which cache entries are the largest,
|
||||||
|
and you can selectively [exclude content using `gradle-home-cache-exclude`](#gradle-user-home-cache-tuning).
|
||||||
|
|
||||||
|
## Build scans
|
||||||
|
|
||||||
|
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
|
||||||
|
- For each step that executes Gradle, adds the link to the published build scan as a Step output named `build-scan-url`.
|
||||||
|
|
||||||
|
You can then use that link in subsequent actions of your workflow. For example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# .github/workflows/gradle-build-pr.yml
|
||||||
|
name: Run Gradle on PRs
|
||||||
|
on: pull_request
|
||||||
|
jobs:
|
||||||
|
gradle:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
- uses: gradle/gradle-build-action@v2
|
||||||
|
- id: gradle
|
||||||
|
run: ./gradlew build
|
||||||
- name: "Comment build scan url"
|
- name: "Comment build scan url"
|
||||||
uses: actions/github-script@v3
|
uses: actions/github-script@v3
|
||||||
if: github.event_name == 'pull_request' && failure()
|
if: github.event_name == 'pull_request' && failure()
|
||||||
|
95
__tests__/cache-reporting.test.ts
Normal file
95
__tests__/cache-reporting.test.ts
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import {CacheEntryListener, CacheListener} from '../src/cache-reporting'
|
||||||
|
|
||||||
|
describe('caching report', () => {
|
||||||
|
describe('reports not fully restored', () => {
|
||||||
|
it('with one requested entry report', async () => {
|
||||||
|
const report = new CacheListener()
|
||||||
|
report.entry('foo').markRequested('1', ['2'])
|
||||||
|
report.entry('bar').markRequested('3').markRestored('4', 500)
|
||||||
|
expect(report.fullyRestored).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('reports fully restored', () => {
|
||||||
|
it('when empty', async () => {
|
||||||
|
const report = new CacheListener()
|
||||||
|
expect(report.fullyRestored).toBe(true)
|
||||||
|
})
|
||||||
|
it('with empty entry reports', async () => {
|
||||||
|
const report = new CacheListener()
|
||||||
|
report.entry('foo')
|
||||||
|
report.entry('bar')
|
||||||
|
expect(report.fullyRestored).toBe(true)
|
||||||
|
})
|
||||||
|
it('with restored entry report', async () => {
|
||||||
|
const report = new CacheListener()
|
||||||
|
report.entry('bar').markRequested('3').markRestored('4', 300)
|
||||||
|
expect(report.fullyRestored).toBe(true)
|
||||||
|
})
|
||||||
|
it('with multiple restored entry reportss', async () => {
|
||||||
|
const report = new CacheListener()
|
||||||
|
report.entry('foo').markRestored('4', 3300)
|
||||||
|
report.entry('bar').markRequested('3').markRestored('4', 333)
|
||||||
|
expect(report.fullyRestored).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('can be stringified and rehydrated', () => {
|
||||||
|
it('when empty', async () => {
|
||||||
|
const report = new CacheListener()
|
||||||
|
|
||||||
|
const stringRep = report.stringify()
|
||||||
|
const reportClone: CacheListener = CacheListener.rehydrate(stringRep)
|
||||||
|
|
||||||
|
expect(reportClone.cacheEntries).toEqual([])
|
||||||
|
|
||||||
|
// Can call methods on rehydrated
|
||||||
|
expect(reportClone.entry('foo')).toBeInstanceOf(CacheEntryListener)
|
||||||
|
})
|
||||||
|
it('with entry reports', async () => {
|
||||||
|
const report = new CacheListener()
|
||||||
|
report.entry('foo')
|
||||||
|
report.entry('bar')
|
||||||
|
report.entry('baz')
|
||||||
|
|
||||||
|
const stringRep = report.stringify()
|
||||||
|
const reportClone: CacheListener = CacheListener.rehydrate(stringRep)
|
||||||
|
|
||||||
|
expect(reportClone.cacheEntries.length).toBe(3)
|
||||||
|
expect(reportClone.cacheEntries[0].entryName).toBe('foo')
|
||||||
|
expect(reportClone.cacheEntries[1].entryName).toBe('bar')
|
||||||
|
expect(reportClone.cacheEntries[2].entryName).toBe('baz')
|
||||||
|
|
||||||
|
expect(reportClone.entry('foo')).toBe(reportClone.cacheEntries[0])
|
||||||
|
})
|
||||||
|
it('with rehydrated entry report', async () => {
|
||||||
|
const report = new CacheListener()
|
||||||
|
const entryReport = report.entry('foo')
|
||||||
|
entryReport.markRequested('1', ['2', '3'])
|
||||||
|
entryReport.markSaved('4', 100)
|
||||||
|
|
||||||
|
const stringRep = report.stringify()
|
||||||
|
const reportClone: CacheListener = CacheListener.rehydrate(stringRep)
|
||||||
|
const entryClone = reportClone.entry('foo')
|
||||||
|
|
||||||
|
expect(entryClone.requestedKey).toBe('1')
|
||||||
|
expect(entryClone.requestedRestoreKeys).toEqual(['2', '3'])
|
||||||
|
expect(entryClone.savedKey).toBe('4')
|
||||||
|
})
|
||||||
|
it('with live entry report', async () => {
|
||||||
|
const report = new CacheListener()
|
||||||
|
const entryReport = report.entry('foo')
|
||||||
|
entryReport.markRequested('1', ['2', '3'])
|
||||||
|
|
||||||
|
const stringRep = report.stringify()
|
||||||
|
const reportClone: CacheListener = CacheListener.rehydrate(stringRep)
|
||||||
|
const entryClone = reportClone.entry('foo')
|
||||||
|
|
||||||
|
// Check type and call method on rehydrated entry report
|
||||||
|
expect(entryClone).toBeInstanceOf(CacheEntryListener)
|
||||||
|
entryClone.markSaved('4', 100)
|
||||||
|
|
||||||
|
expect(entryClone.requestedKey).toBe('1')
|
||||||
|
expect(entryClone.requestedRestoreKeys).toEqual(['2', '3'])
|
||||||
|
expect(entryClone.savedKey).toBe('4')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
20
__tests__/cache-utils.test.ts
Normal file
20
__tests__/cache-utils.test.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import * as cacheUtils from '../src/cache-utils'
|
||||||
|
|
||||||
|
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
|
|
||||||
|
|
BIN
__tests__/samples/gradle-plugin/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
__tests__/samples/gradle-plugin/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
__tests__/samples/gradle-plugin/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
__tests__/samples/gradle-plugin/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.3-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
234
__tests__/samples/gradle-plugin/gradlew
vendored
Executable file
234
__tests__/samples/gradle-plugin/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/gradle-plugin/gradlew.bat
vendored
Normal file
89
__tests__/samples/gradle-plugin/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
|
60
__tests__/samples/gradle-plugin/plugin/build.gradle
Normal file
60
__tests__/samples/gradle-plugin/plugin/build.gradle
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* This file was generated by the Gradle 'init' task.
|
||||||
|
*
|
||||||
|
* This generated file contains a sample Gradle plugin project to get you started.
|
||||||
|
* For more details take a look at the Writing Custom Plugins chapter in the Gradle
|
||||||
|
* User Manual available at https://docs.gradle.org/7.3/userguide/custom_plugins.html
|
||||||
|
* This project uses @Incubating APIs which are subject to change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
// Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
|
||||||
|
id 'java-gradle-plugin'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
// Use Maven Central for resolving dependencies.
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
testing {
|
||||||
|
suites {
|
||||||
|
// Configure the built-in test suite
|
||||||
|
test {
|
||||||
|
// Use JUnit Jupiter test framework
|
||||||
|
useJUnitJupiter('5.7.2')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new test suite
|
||||||
|
functionalTest(JvmTestSuite) {
|
||||||
|
dependencies {
|
||||||
|
// functionalTest test suite depends on the production code in tests
|
||||||
|
implementation project
|
||||||
|
}
|
||||||
|
|
||||||
|
targets {
|
||||||
|
all {
|
||||||
|
// This test suite should run after the built-in test suite has run its tests
|
||||||
|
testTask.configure { shouldRunAfter(test) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gradlePlugin {
|
||||||
|
// Define the plugin
|
||||||
|
plugins {
|
||||||
|
greeting {
|
||||||
|
id = 'org.example.gradle.plugin.greeting'
|
||||||
|
implementationClass = 'org.example.gradle.plugin.GradlePluginPlugin'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gradlePlugin.testSourceSets(sourceSets.functionalTest)
|
||||||
|
|
||||||
|
tasks.named('check') {
|
||||||
|
// Include functionalTest as part of the check lifecycle
|
||||||
|
dependsOn(testing.suites.functionalTest)
|
||||||
|
}
|
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* This Java source file was generated by the Gradle 'init' task.
|
||||||
|
*/
|
||||||
|
package org.example.gradle.plugin;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import org.gradle.testkit.runner.GradleRunner;
|
||||||
|
import org.gradle.testkit.runner.BuildResult;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple functional test for the 'org.example.gradle.plugin.greeting' plugin.
|
||||||
|
*/
|
||||||
|
class GradlePluginPluginFunctionalTest {
|
||||||
|
@TempDir
|
||||||
|
File projectDir;
|
||||||
|
|
||||||
|
private File getBuildFile() {
|
||||||
|
return new File(projectDir, "build.gradle");
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getSettingsFile() {
|
||||||
|
return new File(projectDir, "settings.gradle");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test void canRunTaskWithGradle691() throws IOException {
|
||||||
|
writeString(getSettingsFile(), "");
|
||||||
|
writeString(getBuildFile(),
|
||||||
|
"plugins {" +
|
||||||
|
" id('org.example.gradle.plugin.greeting')" +
|
||||||
|
"}");
|
||||||
|
|
||||||
|
// Run the build
|
||||||
|
GradleRunner runner = GradleRunner.create();
|
||||||
|
runner.forwardOutput();
|
||||||
|
runner.withGradleVersion("6.9.1");
|
||||||
|
runner.withPluginClasspath();
|
||||||
|
runner.withArguments("greeting");
|
||||||
|
runner.withProjectDir(projectDir);
|
||||||
|
BuildResult result = runner.build();
|
||||||
|
|
||||||
|
// Verify the result
|
||||||
|
assertTrue(result.getOutput().contains("Hello from plugin 'org.example.gradle.plugin.greeting'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeString(File file, String string) throws IOException {
|
||||||
|
try (Writer writer = new FileWriter(file)) {
|
||||||
|
writer.write(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* This Java source file was generated by the Gradle 'init' task.
|
||||||
|
*/
|
||||||
|
package org.example.gradle.plugin;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.Plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple 'hello world' plugin.
|
||||||
|
*/
|
||||||
|
public class GradlePluginPlugin implements Plugin<Project> {
|
||||||
|
public void apply(Project project) {
|
||||||
|
// Register a task
|
||||||
|
project.getTasks().register("greeting", task -> {
|
||||||
|
task.doLast(s -> System.out.println("Hello from plugin 'org.example.gradle.plugin.greeting'"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* This Java source file was generated by the Gradle 'init' task.
|
||||||
|
*/
|
||||||
|
package org.example.gradle.plugin;
|
||||||
|
|
||||||
|
import org.gradle.testfixtures.ProjectBuilder;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple unit test for the 'org.example.gradle.plugin.greeting' plugin.
|
||||||
|
*/
|
||||||
|
class GradlePluginPluginTest {
|
||||||
|
@Test void pluginRegistersATask() {
|
||||||
|
// Create a test project and apply the plugin
|
||||||
|
Project project = ProjectBuilder.builder().build();
|
||||||
|
project.getPlugins().apply("org.example.gradle.plugin.greeting");
|
||||||
|
|
||||||
|
// Verify the result
|
||||||
|
assertNotNull(project.getTasks().findByName("greeting"));
|
||||||
|
}
|
||||||
|
}
|
12
__tests__/samples/gradle-plugin/settings.gradle
Normal file
12
__tests__/samples/gradle-plugin/settings.gradle
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* This file was generated by the Gradle 'init' task.
|
||||||
|
*
|
||||||
|
* The settings file is used to specify which projects to include in your build.
|
||||||
|
*
|
||||||
|
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||||
|
* in the user manual at https://docs.gradle.org/7.3/userguide/multi_project_builds.html
|
||||||
|
* This project uses @Incubating APIs which are subject to change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rootProject.name = 'gradle-plugin'
|
||||||
|
include('plugin')
|
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
|
@@ -2,6 +2,12 @@ plugins {
|
|||||||
id 'java'
|
id 'java'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
1
__tests__/samples/java-toolchain/gradle.properties
Normal file
1
__tests__/samples/java-toolchain/gradle.properties
Normal file
@@ -0,0 +1 @@
|
|||||||
|
org.gradle.caching=true
|
BIN
__tests__/samples/java-toolchain/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
__tests__/samples/java-toolchain/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
__tests__/samples/java-toolchain/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
__tests__/samples/java-toolchain/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.3.1-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
185
__tests__/samples/java-toolchain/gradlew
vendored
Executable file
185
__tests__/samples/java-toolchain/gradlew
vendored
Executable file
@@ -0,0 +1,185 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2015 the original author or authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=`expr $i + 1`
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
0) set -- ;;
|
||||||
|
1) set -- "$args0" ;;
|
||||||
|
2) set -- "$args0" "$args1" ;;
|
||||||
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
104
__tests__/samples/java-toolchain/gradlew.bat
vendored
Normal file
104
__tests__/samples/java-toolchain/gradlew.bat
vendored
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
@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 init
|
||||||
|
|
||||||
|
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 init
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@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 %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
1
__tests__/samples/java-toolchain/settings.gradle
Normal file
1
__tests__/samples/java-toolchain/settings.gradle
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'basic'
|
@@ -0,0 +1,10 @@
|
|||||||
|
package basic;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class BasicTest {
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
assert true;
|
||||||
|
}
|
||||||
|
}
|
30
__tests__/samples/kotlin-dsl/build.gradle.kts
Normal file
30
__tests__/samples/kotlin-dsl/build.gradle.kts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("test").configure {
|
||||||
|
// Use an environment variable to bypass config-cache checks
|
||||||
|
if (System.getenv("VERIFY_CACHED_CONFIGURATION") != null) {
|
||||||
|
throw RuntimeException("Configuration was not cached: unexpected configuration of test task")
|
||||||
|
}
|
||||||
|
doLast {
|
||||||
|
if (System.getProperties().containsKey("verifyCachedBuild")) {
|
||||||
|
throw RuntimeException("Build was not cached: unexpected execution of test task")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
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'
|
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}")
|
||||||
|
}
|
86
action.yml
86
action.yml
@@ -1,56 +1,59 @@
|
|||||||
name: "Gradle Command"
|
name: "Gradle Build Action"
|
||||||
description: 'Execute Gradle Build'
|
description: 'Configures Gradle for use in GitHub actions, caching useful state in the GitHub actions cache'
|
||||||
|
|
||||||
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
|
# https://help.github.com/en/articles/metadata-syntax-for-github-actions
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
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
|
|
||||||
gradle-version:
|
gradle-version:
|
||||||
description: Gradle version to use
|
description: Gradle version to use
|
||||||
required: false
|
required: 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
|
||||||
|
# e.g. Use the following setting to only write cache entries from your 'main' branch
|
||||||
|
# cache-read-only: ${{ github.ref != 'refs/heads/main' }}
|
||||||
|
|
||||||
|
gradle-home-cache-includes:
|
||||||
|
description: Paths within Gradle User Home to cache.
|
||||||
|
required: false
|
||||||
|
default: |
|
||||||
|
caches
|
||||||
|
notifications
|
||||||
|
|
||||||
|
gradle-home-cache-excludes:
|
||||||
|
description: Paths within Gradle User Home to exclude from cache.
|
||||||
|
required: false
|
||||||
|
# e.g. Use the following setting to prevent the local build cache from being saved/restored
|
||||||
|
# gradle-home-cache-excludes: |
|
||||||
|
# ["caches/build-cache-1"]
|
||||||
|
|
||||||
|
arguments:
|
||||||
|
description: Gradle command line arguments (supports multi-line input)
|
||||||
|
required: false
|
||||||
|
|
||||||
build-root-directory:
|
build-root-directory:
|
||||||
description: Path to the root directory of the build
|
description: Path to the root directory of the build
|
||||||
required: false
|
required: false
|
||||||
arguments:
|
|
||||||
description: Gradle command line arguments, see gradle --help
|
gradle-executable:
|
||||||
|
description: Path to the Gradle executable
|
||||||
required: false
|
required: false
|
||||||
distributions-cache-enabled:
|
|
||||||
description: Whether caching downloaded Gradle distributions is enabled or not, default to 'true'
|
# EXPERIMENTAL & INTERNAL ACTION INPUTS
|
||||||
|
# The following action properties allow fine-grained tweaking of the action caching behaviour.
|
||||||
|
# These properties are not designed for production use, and may change without notice in a subsequent release of `gradle-build-action`.
|
||||||
|
# Use at your own risk!
|
||||||
|
workflow-job-context:
|
||||||
|
description: Used to uniquely identify the current job invocation. Defaults to the matrix values for this job; this should not be overridden by users (INTERNAL).
|
||||||
required: false
|
required: false
|
||||||
default: true
|
default: ${{ toJSON(matrix) }}
|
||||||
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'
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
build-scan-url:
|
build-scan-url:
|
||||||
@@ -60,7 +63,6 @@ runs:
|
|||||||
using: 'node12'
|
using: 'node12'
|
||||||
main: 'dist/main/index.js'
|
main: 'dist/main/index.js'
|
||||||
post: 'dist/post/index.js'
|
post: 'dist/post/index.js'
|
||||||
post-if: success()
|
|
||||||
|
|
||||||
branding:
|
branding:
|
||||||
icon: 'box'
|
icon: 'box'
|
||||||
|
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
12400
package-lock.json
generated
12400
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
@@ -4,10 +4,11 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"description": "Execute Gradle Build",
|
"description": "Execute Gradle Build",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"postinstall": "patch-package",
|
||||||
"format": "prettier --write **/*.ts",
|
"format": "prettier --write **/*.ts",
|
||||||
"format-check": "prettier --check **/*.ts",
|
"format-check": "prettier --check **/*.ts",
|
||||||
"lint": "eslint src/**/*.ts",
|
"lint": "eslint src/**/*.ts",
|
||||||
"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",
|
"test": "jest",
|
||||||
"all": "npm run format && npm run lint && npm run build && npm test"
|
"all": "npm run format && npm run lint && npm run build && npm test"
|
||||||
},
|
},
|
||||||
@@ -21,31 +22,32 @@
|
|||||||
"github-actions",
|
"github-actions",
|
||||||
"gradle"
|
"gradle"
|
||||||
],
|
],
|
||||||
"author": "Paul Merlin <paul@nosphere.org>",
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "1.0.7",
|
"@actions/cache": "1.0.8",
|
||||||
"@actions/core": "1.4.0",
|
"@actions/core": "1.6.0",
|
||||||
"@actions/exec": "1.1.0",
|
"@actions/exec": "1.1.0",
|
||||||
|
"@actions/github": "5.0.0",
|
||||||
"@actions/glob": "0.2.0",
|
"@actions/glob": "0.2.0",
|
||||||
"@actions/http-client": "1.0.11",
|
"@actions/http-client": "1.0.11",
|
||||||
"@actions/tool-cache": "1.7.1",
|
"@actions/tool-cache": "1.7.1",
|
||||||
|
"patch-package": "6.4.7",
|
||||||
"string-argv": "0.3.1"
|
"string-argv": "0.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "26.0.23",
|
"@types/jest": "27.0.3",
|
||||||
"@types/node": "14.17.3",
|
"@types/node": "16.11.11",
|
||||||
"@types/unzipper": "0.10.4",
|
"@types/unzipper": "0.10.4",
|
||||||
"@typescript-eslint/parser": "4.28.2",
|
"@typescript-eslint/parser": "5.5.0",
|
||||||
"@zeit/ncc": "0.22.3",
|
"@zeit/ncc": "0.22.3",
|
||||||
"eslint": "7.30.0",
|
"eslint": "8.3.0",
|
||||||
"eslint-plugin-github": "4.1.3",
|
"eslint-plugin-github": "4.3.5",
|
||||||
"eslint-plugin-jest": "24.3.6",
|
"eslint-plugin-jest": "25.3.0",
|
||||||
"jest": "26.6.3",
|
"jest": "27.4.3",
|
||||||
"jest-circus": "26.6.3",
|
"jest-circus": "27.4.2",
|
||||||
"js-yaml": "3.14.1",
|
"js-yaml": "4.1.0",
|
||||||
"prettier": "2.3.2",
|
"prettier": "2.5.0",
|
||||||
"ts-jest": "26.5.6",
|
"ts-jest": "27.0.7",
|
||||||
"typescript": "4.3.5"
|
"typescript": "4.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
108
patches/@actions+cache+1.0.8.patch
Normal file
108
patches/@actions+cache+1.0.8.patch
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
diff --git a/node_modules/@actions/cache/lib/cache.d.ts b/node_modules/@actions/cache/lib/cache.d.ts
|
||||||
|
index 805a8e5..d3ab419 100644
|
||||||
|
--- a/node_modules/@actions/cache/lib/cache.d.ts
|
||||||
|
+++ b/node_modules/@actions/cache/lib/cache.d.ts
|
||||||
|
@@ -5,6 +5,11 @@ export declare class ValidationError extends Error {
|
||||||
|
export declare class ReserveCacheError extends Error {
|
||||||
|
constructor(message: string);
|
||||||
|
}
|
||||||
|
+export declare class CacheEntry {
|
||||||
|
+ key: string;
|
||||||
|
+ size?: number;
|
||||||
|
+ constructor(key: string, size?: number);
|
||||||
|
+}
|
||||||
|
/**
|
||||||
|
* Restores cache from keys
|
||||||
|
*
|
||||||
|
@@ -14,7 +19,7 @@ export declare class ReserveCacheError extends Error {
|
||||||
|
* @param downloadOptions cache download options
|
||||||
|
* @returns string returns the key for the cache hit, otherwise returns undefined
|
||||||
|
*/
|
||||||
|
-export declare function restoreCache(paths: string[], primaryKey: string, restoreKeys?: string[], options?: DownloadOptions): Promise<string | undefined>;
|
||||||
|
+export declare function restoreCache(paths: string[], primaryKey: string, restoreKeys?: string[], options?: DownloadOptions): Promise<CacheEntry | undefined>;
|
||||||
|
/**
|
||||||
|
* Saves a list of files with the specified key
|
||||||
|
*
|
||||||
|
@@ -23,4 +28,4 @@ export declare function restoreCache(paths: string[], primaryKey: string, restor
|
||||||
|
* @param options cache upload options
|
||||||
|
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
||||||
|
*/
|
||||||
|
-export declare function saveCache(paths: string[], key: string, options?: UploadOptions): Promise<number>;
|
||||||
|
+export declare function saveCache(paths: string[], key: string, options?: UploadOptions): Promise<CacheEntry>;
|
||||||
|
diff --git a/node_modules/@actions/cache/lib/cache.js b/node_modules/@actions/cache/lib/cache.js
|
||||||
|
index e3c43e6..c947d02 100644
|
||||||
|
--- a/node_modules/@actions/cache/lib/cache.js
|
||||||
|
+++ b/node_modules/@actions/cache/lib/cache.js
|
||||||
|
@@ -37,6 +37,13 @@ class ReserveCacheError extends Error {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.ReserveCacheError = ReserveCacheError;
|
||||||
|
+class CacheEntry {
|
||||||
|
+ constructor(key, size) {
|
||||||
|
+ this.key = key;
|
||||||
|
+ this.size = size;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+exports.CacheEntry = CacheEntry;
|
||||||
|
function checkPaths(paths) {
|
||||||
|
if (!paths || paths.length === 0) {
|
||||||
|
throw new ValidationError(`Path Validation Error: At least one directory or file path is required`);
|
||||||
|
@@ -84,6 +91,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
||||||
|
}
|
||||||
|
const archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
||||||
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
|
+ const restoredEntry = new CacheEntry(cacheEntry.cacheKey);
|
||||||
|
try {
|
||||||
|
// Download the cache from the cache entry
|
||||||
|
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath, options);
|
||||||
|
@@ -91,6 +99,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
||||||
|
yield tar_1.listTar(archivePath, compressionMethod);
|
||||||
|
}
|
||||||
|
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath);
|
||||||
|
+ restoredEntry.size = archiveFileSize;
|
||||||
|
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
|
||||||
|
yield tar_1.extractTar(archivePath, compressionMethod);
|
||||||
|
core.info('Cache restored successfully');
|
||||||
|
@@ -104,7 +113,7 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
||||||
|
core.debug(`Failed to delete archive: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- return cacheEntry.cacheKey;
|
||||||
|
+ return restoredEntry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.restoreCache = restoreCache;
|
||||||
|
@@ -135,6 +144,7 @@ function saveCache(paths, key, options) {
|
||||||
|
const archiveFolder = yield utils.createTempDirectory();
|
||||||
|
const archivePath = path.join(archiveFolder, utils.getCacheFileName(compressionMethod));
|
||||||
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
|
+ const savedEntry = new CacheEntry(key);
|
||||||
|
try {
|
||||||
|
yield tar_1.createTar(archiveFolder, cachePaths, compressionMethod);
|
||||||
|
if (core.isDebug()) {
|
||||||
|
@@ -142,6 +152,7 @@ function saveCache(paths, key, options) {
|
||||||
|
}
|
||||||
|
const fileSizeLimit = 10 * 1024 * 1024 * 1024; // 10GB per repo limit
|
||||||
|
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath);
|
||||||
|
+ savedEntry.size = archiveFileSize;
|
||||||
|
core.debug(`File Size: ${archiveFileSize}`);
|
||||||
|
if (archiveFileSize > fileSizeLimit) {
|
||||||
|
throw new Error(`Cache size of ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B) is over the 10GB limit, not saving cache.`);
|
||||||
|
@@ -158,7 +169,7 @@ function saveCache(paths, key, options) {
|
||||||
|
core.debug(`Failed to delete archive: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- return cacheId;
|
||||||
|
+ return savedEntry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.saveCache = saveCache;
|
||||||
|
diff --git a/node_modules/@actions/cache/lib/cache.js.map b/node_modules/@actions/cache/lib/cache.js.map
|
||||||
|
index ec474b2..7e09719 100644
|
||||||
|
--- a/node_modules/@actions/cache/lib/cache.js.map
|
||||||
|
+++ b/node_modules/@actions/cache/lib/cache.js.map
|
||||||
|
@@ -1 +1 @@
|
||||||
|
-{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,oDAAqC;AACrC,2CAA4B;AAC5B,6DAA8C;AAC9C,4EAA6D;AAC7D,wCAA6D;AAG7D,MAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACxD,CAAC;CACF;AAND,0CAMC;AAED,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;QAC/B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAA;IAC1D,CAAC;CACF;AAND,8CAMC;AAED,SAAS,UAAU,CAAC,KAAe;IACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QAChC,MAAM,IAAI,eAAe,CACvB,wEAAwE,CACzE,CAAA;KACF;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE;QACpB,MAAM,IAAI,eAAe,CACvB,yBAAyB,GAAG,wCAAwC,CACrE,CAAA;KACF;IACD,MAAM,KAAK,GAAG,SAAS,CAAA;IACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACpB,MAAM,IAAI,eAAe,CACvB,yBAAyB,GAAG,yBAAyB,CACtD,CAAA;KACF;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAsB,YAAY,CAChC,KAAe,EACf,UAAkB,EAClB,WAAsB,EACtB,OAAyB;;QAEzB,UAAU,CAAC,KAAK,CAAC,CAAA;QAEjB,WAAW,GAAG,WAAW,IAAI,EAAE,CAAA;QAC/B,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,GAAG,WAAW,CAAC,CAAA;QAEzC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;QAC5B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;QAEhC,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE;YACpB,MAAM,IAAI,eAAe,CACvB,4DAA4D,CAC7D,CAAA;SACF;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;YACtB,QAAQ,CAAC,GAAG,CAAC,CAAA;SACd;QAED,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAE5D,qCAAqC;QACrC,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE;YAClE,iBAAiB;SAClB,CAAC,CAAA;QACF,IAAI,EAAC,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,eAAe,CAAA,EAAE;YAChC,kBAAkB;YAClB,OAAO,SAAS,CAAA;SACjB;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,MAAM,KAAK,CAAC,mBAAmB,EAAE,EACjC,KAAK,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAC1C,CAAA;QACD,IAAI,CAAC,KAAK,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAA;QAE1C,IAAI;YACF,0CAA0C;YAC1C,MAAM,eAAe,CAAC,aAAa,CACjC,UAAU,CAAC,eAAe,EAC1B,WAAW,EACX,OAAO,CACR,CAAA;YAED,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;gBAClB,MAAM,aAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;aAC9C;YAED,MAAM,eAAe,GAAG,KAAK,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;YACpE,IAAI,CAAC,IAAI,CACP,gBAAgB,IAAI,CAAC,KAAK,CACxB,eAAe,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAChC,QAAQ,eAAe,KAAK,CAC9B,CAAA;YAED,MAAM,gBAAU,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;YAChD,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;SACzC;gBAAS;YACR,0CAA0C;YAC1C,IAAI;gBACF,MAAM,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;aACpC;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAA;aACjD;SACF;QAED,OAAO,UAAU,CAAC,QAAQ,CAAA;IAC5B,CAAC;CAAA;AAvED,oCAuEC;AAED;;;;;;;GAOG;AACH,SAAsB,SAAS,CAC7B,KAAe,EACf,GAAW,EACX,OAAuB;;QAEvB,UAAU,CAAC,KAAK,CAAC,CAAA;QACjB,QAAQ,CAAC,GAAG,CAAC,CAAA;QAEb,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAE5D,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;QAC7B,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE;YAC7D,iBAAiB;SAClB,CAAC,CAAA;QACF,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE;YAClB,MAAM,IAAI,iBAAiB,CACzB,oCAAoC,GAAG,2CAA2C,CACnF,CAAA;SACF;QACD,IAAI,CAAC,KAAK,CAAC,aAAa,OAAO,EAAE,CAAC,CAAA;QAElC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QAClD,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;QAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAE3C,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,mBAAmB,EAAE,CAAA;QACvD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,aAAa,EACb,KAAK,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAC1C,CAAA;QAED,IAAI,CAAC,KAAK,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAA;QAE1C,IAAI;YACF,MAAM,eAAS,CAAC,aAAa,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAA;YAC7D,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;gBAClB,MAAM,aAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;aAC9C;YAED,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA,CAAC,sBAAsB;YACpE,MAAM,eAAe,GAAG,KAAK,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;YACpE,IAAI,CAAC,KAAK,CAAC,cAAc,eAAe,EAAE,CAAC,CAAA;YAC3C,IAAI,eAAe,GAAG,aAAa,EAAE;gBACnC,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,KAAK,CAC1B,eAAe,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAChC,QAAQ,eAAe,+CAA+C,CACxE,CAAA;aACF;YAED,IAAI,CAAC,KAAK,CAAC,qBAAqB,OAAO,GAAG,CAAC,CAAA;YAC3C,MAAM,eAAe,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;SAC/D;gBAAS;YACR,0CAA0C;YAC1C,IAAI;gBACF,MAAM,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;aACpC;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAA;aACjD;SACF;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;CAAA;AA9DD,8BA8DC"}
|
||||||
|
\ No newline at end of file
|
||||||
|
+{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,oDAAqC;AACrC,2CAA4B;AAC5B,6DAA8C;AAC9C,4EAA6D;AAC7D,wCAA6D;AAG7D,MAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAA;IACxD,CAAC;CACF;AAND,0CAMC;AAED,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;QAC/B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAA;IAC1D,CAAC;CACF;AAND,8CAMC;AAED,MAAa,UAAU;IAIrB,YAAY,GAAW,EAAE,IAAa;QACpC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF;AARD,gCAQC;AAED,SAAS,UAAU,CAAC,KAAe;IACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QAChC,MAAM,IAAI,eAAe,CACvB,wEAAwE,CACzE,CAAA;KACF;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE;QACpB,MAAM,IAAI,eAAe,CACvB,yBAAyB,GAAG,wCAAwC,CACrE,CAAA;KACF;IACD,MAAM,KAAK,GAAG,SAAS,CAAA;IACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACpB,MAAM,IAAI,eAAe,CACvB,yBAAyB,GAAG,yBAAyB,CACtD,CAAA;KACF;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAsB,YAAY,CAChC,KAAe,EACf,UAAkB,EAClB,WAAsB,EACtB,OAAyB;;QAEzB,UAAU,CAAC,KAAK,CAAC,CAAA;QAEjB,WAAW,GAAG,WAAW,IAAI,EAAE,CAAA;QAC/B,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,GAAG,WAAW,CAAC,CAAA;QAEzC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;QAC5B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;QAEhC,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE;YACpB,MAAM,IAAI,eAAe,CACvB,4DAA4D,CAC7D,CAAA;SACF;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;YACtB,QAAQ,CAAC,GAAG,CAAC,CAAA;SACd;QAED,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAE5D,qCAAqC;QACrC,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE;YAClE,iBAAiB;SAClB,CAAC,CAAA;QACF,IAAI,EAAC,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,eAAe,CAAA,EAAE;YAChC,kBAAkB;YAClB,OAAO,SAAS,CAAA;SACjB;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,MAAM,KAAK,CAAC,mBAAmB,EAAE,EACjC,KAAK,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAC1C,CAAA;QACD,IAAI,CAAC,KAAK,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAA;QAE1C,MAAM,aAAa,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,QAAS,CAAC,CAAA;QAC1D,IAAI;YACF,0CAA0C;YAC1C,MAAM,eAAe,CAAC,aAAa,CACjC,UAAU,CAAC,eAAe,EAC1B,WAAW,EACX,OAAO,CACR,CAAA;YAED,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;gBAClB,MAAM,aAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;aAC9C;YAED,MAAM,eAAe,GAAG,KAAK,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;YACpE,aAAa,CAAC,IAAI,GAAG,eAAe,CAAA;YACpC,IAAI,CAAC,IAAI,CACP,gBAAgB,IAAI,CAAC,KAAK,CACxB,eAAe,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAChC,QAAQ,eAAe,KAAK,CAC9B,CAAA;YAED,MAAM,gBAAU,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;YAChD,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;SACzC;gBAAS;YACR,0CAA0C;YAC1C,IAAI;gBACF,MAAM,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;aACpC;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAA;aACjD;SACF;QAED,OAAO,aAAa,CAAA;IACtB,CAAC;CAAA;AAzED,oCAyEC;AAED;;;;;;;GAOG;AACH,SAAsB,SAAS,CAC7B,KAAe,EACf,GAAW,EACX,OAAuB;;QAEvB,UAAU,CAAC,KAAK,CAAC,CAAA;QACjB,QAAQ,CAAC,GAAG,CAAC,CAAA;QAEb,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAE5D,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;QAC7B,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE;YAC7D,iBAAiB;SAClB,CAAC,CAAA;QACF,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE;YAClB,MAAM,IAAI,iBAAiB,CACzB,oCAAoC,GAAG,2CAA2C,CACnF,CAAA;SACF;QACD,IAAI,CAAC,KAAK,CAAC,aAAa,OAAO,EAAE,CAAC,CAAA;QAElC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QAClD,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;QAC1B,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAE3C,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,mBAAmB,EAAE,CAAA;QACvD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,aAAa,EACb,KAAK,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAC1C,CAAA;QAED,IAAI,CAAC,KAAK,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAA;QAE1C,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAA;QACtC,IAAI;YACF,MAAM,eAAS,CAAC,aAAa,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAA;YAC7D,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;gBAClB,MAAM,aAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;aAC9C;YAED,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA,CAAC,sBAAsB;YACpE,MAAM,eAAe,GAAG,KAAK,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAA;YACpE,UAAU,CAAC,IAAI,GAAG,eAAe,CAAA;YACjC,IAAI,CAAC,KAAK,CAAC,cAAc,eAAe,EAAE,CAAC,CAAA;YAC3C,IAAI,eAAe,GAAG,aAAa,EAAE;gBACnC,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,KAAK,CAC1B,eAAe,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAChC,QAAQ,eAAe,+CAA+C,CACxE,CAAA;aACF;YAED,IAAI,CAAC,KAAK,CAAC,qBAAqB,OAAO,GAAG,CAAC,CAAA;YAC3C,MAAM,eAAe,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;SAC/D;gBAAS;YACR,0CAA0C;YAC1C,IAAI;gBACF,MAAM,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;aACpC;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAA;aACjD;SACF;QACD,OAAO,UAAU,CAAA;IACnB,CAAC;CAAA;AA/DD,8BA+DC"}
|
||||||
|
\ No newline at end of file
|
333
src/cache-base.ts
Normal file
333
src/cache-base.ts
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as exec from '@actions/exec'
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
|
import {CacheListener} from './cache-reporting'
|
||||||
|
import {
|
||||||
|
getCacheKeyPrefix,
|
||||||
|
determineJobContext,
|
||||||
|
saveCache,
|
||||||
|
restoreCache,
|
||||||
|
cacheDebug,
|
||||||
|
isCacheDebuggingEnabled,
|
||||||
|
tryDelete
|
||||||
|
} from './cache-utils'
|
||||||
|
import {ConfigurationCacheEntryExtractor, GradleHomeEntryExtractor} from './cache-extract-entries'
|
||||||
|
|
||||||
|
const CACHE_PROTOCOL_VERSION = 'v5-'
|
||||||
|
|
||||||
|
export const META_FILE_DIR = '.gradle-build-action'
|
||||||
|
export const PROJECT_ROOTS_FILE = 'project-roots.txt'
|
||||||
|
const INCLUDE_PATHS_PARAMETER = 'gradle-home-cache-includes'
|
||||||
|
const EXCLUDE_PATHS_PARAMETER = 'gradle-home-cache-excludes'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a key used to restore a cache entry.
|
||||||
|
* The Github Actions cache will first try for an exact match on the key.
|
||||||
|
* If that fails, it will try for a prefix match on any of the restoreKeys.
|
||||||
|
*/
|
||||||
|
class CacheKey {
|
||||||
|
key: string
|
||||||
|
restoreKeys: string[]
|
||||||
|
|
||||||
|
constructor(key: string, restoreKeys: string[]) {
|
||||||
|
this.key = key
|
||||||
|
this.restoreKeys = restoreKeys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a cache key specific to the current job execution.
|
||||||
|
* The key is constructed from the following inputs:
|
||||||
|
* - A user-defined prefix (optional)
|
||||||
|
* - The cache protocol version
|
||||||
|
* - The name of the cache
|
||||||
|
* - The runner operating system
|
||||||
|
* - The name of the Job being executed
|
||||||
|
* - The matrix values for the Job being executed (job context)
|
||||||
|
* - The SHA of the commit being executed
|
||||||
|
*
|
||||||
|
* Caches are restored by trying to match the these key prefixes in order:
|
||||||
|
* - The full key with SHA
|
||||||
|
* - A previous key for this Job + matrix
|
||||||
|
* - Any previous key for this Job (any matrix)
|
||||||
|
* - Any previous key for this cache on the current OS
|
||||||
|
*/
|
||||||
|
function generateCacheKey(cacheName: string): CacheKey {
|
||||||
|
const cacheKeyBase = `${getCacheKeyPrefix()}${CACHE_PROTOCOL_VERSION}${cacheName}`
|
||||||
|
|
||||||
|
// At the most general level, share caches for all executions on the same OS
|
||||||
|
const runnerOs = process.env['RUNNER_OS'] || ''
|
||||||
|
const cacheKeyForOs = `${cacheKeyBase}|${runnerOs}`
|
||||||
|
|
||||||
|
// Prefer caches that run this job
|
||||||
|
const cacheKeyForJob = `${cacheKeyForOs}|${github.context.job}`
|
||||||
|
|
||||||
|
// Prefer (even more) jobs that run this job with the same context (matrix)
|
||||||
|
const cacheKeyForJobContext = `${cacheKeyForJob}[${determineJobContext()}]`
|
||||||
|
|
||||||
|
// Exact match on Git SHA
|
||||||
|
const cacheKey = `${cacheKeyForJobContext}-${github.context.sha}`
|
||||||
|
|
||||||
|
return new CacheKey(cacheKey, [cacheKeyForJobContext, cacheKeyForJob, cacheKeyForOs])
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GradleStateCache {
|
||||||
|
private cacheName: string
|
||||||
|
private cacheDescription: string
|
||||||
|
private cacheKeyStateKey: string
|
||||||
|
private cacheResultStateKey: string
|
||||||
|
|
||||||
|
protected readonly gradleUserHome: string
|
||||||
|
|
||||||
|
constructor(gradleUserHome: string) {
|
||||||
|
this.gradleUserHome = gradleUserHome
|
||||||
|
this.cacheName = 'gradle'
|
||||||
|
this.cacheDescription = 'Gradle User Home'
|
||||||
|
this.cacheKeyStateKey = `CACHE_KEY_gradle`
|
||||||
|
this.cacheResultStateKey = `CACHE_RESULT_gradle`
|
||||||
|
}
|
||||||
|
|
||||||
|
init(): void {
|
||||||
|
const actionCacheDir = path.resolve(this.gradleUserHome, '.gradle-build-action')
|
||||||
|
fs.mkdirSync(actionCacheDir, {recursive: true})
|
||||||
|
|
||||||
|
const initScriptsDir = path.resolve(this.gradleUserHome, 'init.d')
|
||||||
|
fs.mkdirSync(initScriptsDir, {recursive: true})
|
||||||
|
|
||||||
|
this.initializeGradleUserHome(this.gradleUserHome, initScriptsDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the cache entry, finding the closest match to the currently running job.
|
||||||
|
*/
|
||||||
|
async restore(listener: CacheListener): Promise<void> {
|
||||||
|
const entryListener = listener.entry(this.cacheDescription)
|
||||||
|
|
||||||
|
const cacheKey = generateCacheKey(this.cacheName)
|
||||||
|
core.saveState(this.cacheKeyStateKey, cacheKey.key)
|
||||||
|
|
||||||
|
cacheDebug(
|
||||||
|
`Requesting ${this.cacheDescription} with
|
||||||
|
key:${cacheKey.key}
|
||||||
|
restoreKeys:[${cacheKey.restoreKeys}]`
|
||||||
|
)
|
||||||
|
|
||||||
|
const cacheResult = await restoreCache(this.getCachePath(), cacheKey.key, cacheKey.restoreKeys)
|
||||||
|
entryListener.markRequested(cacheKey.key, cacheKey.restoreKeys)
|
||||||
|
|
||||||
|
if (!cacheResult) {
|
||||||
|
core.info(`${this.cacheDescription} cache not found. Will initialize empty.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
core.saveState(this.cacheResultStateKey, cacheResult.key)
|
||||||
|
entryListener.markRestored(cacheResult.key, cacheResult.size)
|
||||||
|
|
||||||
|
core.info(`Restored ${this.cacheDescription} from cache key: ${cacheResult.key}`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.afterRestore(listener)
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(`Restore ${this.cacheDescription} failed in 'afterRestore': ${error}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore any extracted cache entries after the main Gradle User Home entry is restored.
|
||||||
|
*/
|
||||||
|
async afterRestore(listener: CacheListener): Promise<void> {
|
||||||
|
await this.debugReportGradleUserHomeSize('as restored from cache')
|
||||||
|
await new GradleHomeEntryExtractor(this.gradleUserHome).restore(listener)
|
||||||
|
await new ConfigurationCacheEntryExtractor(this.gradleUserHome).restore(listener)
|
||||||
|
await this.debugReportGradleUserHomeSize('after restoring common artifacts')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the cache entry based on the current cache key unless the cache was restored with the exact key,
|
||||||
|
* in which case we cannot overwrite it.
|
||||||
|
*
|
||||||
|
* If the cache entry was restored with a partial match on a restore key, then
|
||||||
|
* it is saved with the exact key.
|
||||||
|
*/
|
||||||
|
async save(listener: CacheListener): Promise<void> {
|
||||||
|
// Retrieve the state set in the previous 'restore' step.
|
||||||
|
const cacheKeyFromRestore = core.getState(this.cacheKeyStateKey)
|
||||||
|
const cacheResultFromRestore = core.getState(this.cacheResultStateKey)
|
||||||
|
|
||||||
|
if (cacheResultFromRestore && cacheKeyFromRestore === cacheResultFromRestore) {
|
||||||
|
core.info(`Cache hit occurred on the cache key ${cacheKeyFromRestore}, not saving cache.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.beforeSave(listener)
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(`Save ${this.cacheDescription} failed in 'beforeSave': ${error}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`Caching ${this.cacheDescription} with cache key: ${cacheKeyFromRestore}`)
|
||||||
|
const cachePath = this.getCachePath()
|
||||||
|
const savedEntry = await saveCache(cachePath, cacheKeyFromRestore)
|
||||||
|
|
||||||
|
if (savedEntry) {
|
||||||
|
listener.entry(this.cacheDescription).markSaved(savedEntry.key, savedEntry.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract and save any defined extracted cache entries prior to the main Gradle User Home entry being saved.
|
||||||
|
*/
|
||||||
|
async beforeSave(listener: CacheListener): Promise<void> {
|
||||||
|
await this.debugReportGradleUserHomeSize('before saving common artifacts')
|
||||||
|
this.deleteExcludedPaths()
|
||||||
|
await Promise.all([
|
||||||
|
new GradleHomeEntryExtractor(this.gradleUserHome).extract(listener),
|
||||||
|
new ConfigurationCacheEntryExtractor(this.gradleUserHome).extract(listener)
|
||||||
|
])
|
||||||
|
await this.debugReportGradleUserHomeSize(
|
||||||
|
"after extracting common artifacts (only 'caches' and 'notifications' will be stored)"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete any file paths that are excluded by the `gradle-home-cache-excludes` parameter.
|
||||||
|
*/
|
||||||
|
private deleteExcludedPaths(): void {
|
||||||
|
const rawPaths: string[] = core.getMultilineInput(EXCLUDE_PATHS_PARAMETER)
|
||||||
|
const resolvedPaths = rawPaths.map(x => path.resolve(this.gradleUserHome, x))
|
||||||
|
|
||||||
|
for (const p of resolvedPaths) {
|
||||||
|
cacheDebug(`Deleting excluded path: ${p}`)
|
||||||
|
tryDelete(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the paths within Gradle User Home to cache.
|
||||||
|
* By default, this is the 'caches' and 'notifications' directories,
|
||||||
|
* but this can be overridden by the `gradle-home-cache-includes` parameter.
|
||||||
|
*/
|
||||||
|
protected getCachePath(): string[] {
|
||||||
|
const rawPaths: string[] = core.getMultilineInput(INCLUDE_PATHS_PARAMETER)
|
||||||
|
rawPaths.push(META_FILE_DIR)
|
||||||
|
const resolvedPaths = rawPaths.map(x => this.resolveCachePath(x))
|
||||||
|
cacheDebug(`Using cache paths: ${resolvedPaths}`)
|
||||||
|
return resolvedPaths
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolveCachePath(rawPath: string): string {
|
||||||
|
if (rawPath.startsWith('!')) {
|
||||||
|
const resolved = this.resolveCachePath(rawPath.substring(1))
|
||||||
|
return `!${resolved}`
|
||||||
|
}
|
||||||
|
return path.resolve(this.gradleUserHome, rawPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeGradleUserHome(gradleUserHome: string, initScriptsDir: string): void {
|
||||||
|
const propertiesFile = path.resolve(gradleUserHome, 'gradle.properties')
|
||||||
|
fs.writeFileSync(propertiesFile, 'org.gradle.daemon=false')
|
||||||
|
|
||||||
|
const buildScanCapture = path.resolve(initScriptsDir, 'build-scan-capture.init.gradle')
|
||||||
|
fs.writeFileSync(
|
||||||
|
buildScanCapture,
|
||||||
|
`import org.gradle.util.GradleVersion
|
||||||
|
|
||||||
|
// Only run again root build. Do not run against included builds.
|
||||||
|
def isTopLevelBuild = gradle.getParent() == null
|
||||||
|
if (isTopLevelBuild) {
|
||||||
|
def version = GradleVersion.current().baseVersion
|
||||||
|
def atLeastGradle4 = version >= GradleVersion.version("4.0")
|
||||||
|
def atLeastGradle6 = version >= GradleVersion.version("6.0")
|
||||||
|
|
||||||
|
if (atLeastGradle6) {
|
||||||
|
settingsEvaluated { settings ->
|
||||||
|
if (settings.pluginManager.hasPlugin("com.gradle.enterprise")) {
|
||||||
|
registerCallbacks(settings.extensions["gradleEnterprise"].buildScan, settings.rootProject.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (atLeastGradle4) {
|
||||||
|
projectsEvaluated { gradle ->
|
||||||
|
if (gradle.rootProject.pluginManager.hasPlugin("com.gradle.build-scan")) {
|
||||||
|
registerCallbacks(gradle.rootProject.extensions["buildScan"], gradle.rootProject.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def registerCallbacks(buildScanExtension, rootProjectName) {
|
||||||
|
buildScanExtension.with {
|
||||||
|
def buildOutcome = ""
|
||||||
|
def scanFile = new File("gradle-build-scan.txt")
|
||||||
|
|
||||||
|
buildFinished { result ->
|
||||||
|
buildOutcome = result.failure == null ? " succeeded" : " failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildScanPublished { buildScan ->
|
||||||
|
scanFile.text = buildScan.buildScanUri
|
||||||
|
|
||||||
|
// Send commands directly to GitHub Actions via STDOUT.
|
||||||
|
def message = "Build '\${rootProjectName}'\${buildOutcome} - \${buildScan.buildScanUri}"
|
||||||
|
println("::notice ::\${message}")
|
||||||
|
println("::set-output name=build-scan-url::\${buildScan.buildScanUri}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
|
const projectRootCapture = path.resolve(initScriptsDir, 'project-root-capture.init.gradle')
|
||||||
|
fs.writeFileSync(
|
||||||
|
projectRootCapture,
|
||||||
|
`
|
||||||
|
// Only run again root build. Do not run against included builds.
|
||||||
|
def isTopLevelBuild = gradle.getParent() == null
|
||||||
|
if (isTopLevelBuild) {
|
||||||
|
settingsEvaluated { settings ->
|
||||||
|
def projectRootEntry = settings.rootDir.absolutePath + "\\n"
|
||||||
|
def projectRootList = new File(settings.gradle.gradleUserHomeDir, "${PROJECT_ROOTS_FILE}")
|
||||||
|
if (!projectRootList.exists() || !projectRootList.text.contains(projectRootEntry)) {
|
||||||
|
projectRootList << projectRootEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When cache debugging is enabled, this method will give a detailed report
|
||||||
|
* of the Gradle User Home contents.
|
||||||
|
*/
|
||||||
|
private async debugReportGradleUserHomeSize(label: string): Promise<void> {
|
||||||
|
if (!isCacheDebuggingEnabled()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(this.gradleUserHome)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const result = await exec.getExecOutput('du', ['-h', '-c', '-t', '5M'], {
|
||||||
|
cwd: this.gradleUserHome,
|
||||||
|
silent: true,
|
||||||
|
ignoreReturnCode: true
|
||||||
|
})
|
||||||
|
|
||||||
|
core.info(`Gradle User Home (directories >5M): ${label}`)
|
||||||
|
|
||||||
|
core.info(
|
||||||
|
result.stdout
|
||||||
|
.trimEnd()
|
||||||
|
.replace(/\t/g, ' ')
|
||||||
|
.split('\n')
|
||||||
|
.map(it => {
|
||||||
|
return ` ${it}`
|
||||||
|
})
|
||||||
|
.join('\n')
|
||||||
|
)
|
||||||
|
|
||||||
|
core.info('-----------------------')
|
||||||
|
}
|
||||||
|
}
|
@@ -1,106 +0,0 @@
|
|||||||
import path from 'path'
|
|
||||||
import 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 cacheKeyGlobs = inputCacheKeyGlobs('configuration-cache-key')
|
|
||||||
|
|
||||||
const hash = await crypto.hashFiles(rootDir, cacheKeyGlobs)
|
|
||||||
const cacheKeyPrefix = 'configuration-'
|
|
||||||
const cacheKey = `${cacheKeyPrefix}${hash}`
|
|
||||||
core.saveState(CONFIGURATION_CACHE_KEY, cacheKey)
|
|
||||||
|
|
||||||
const cacheResult = await cache.restoreCache(
|
|
||||||
[cachePath],
|
|
||||||
cacheKey,
|
|
||||||
inputCacheExact ? [] : [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
|
|
||||||
}
|
|
||||||
|
|
||||||
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,119 +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 cacheKeyGlobs = inputCacheKeyGlobs('dependencies-cache-key')
|
|
||||||
|
|
||||||
const hash = await crypto.hashFiles(rootDir, cacheKeyGlobs)
|
|
||||||
const cacheKeyPrefix = 'dependencies-'
|
|
||||||
const cacheKey = `${cacheKeyPrefix}${hash}`
|
|
||||||
core.saveState(DEPENDENCIES_CACHE_KEY, cacheKey)
|
|
||||||
|
|
||||||
const cacheResult = await cache.restoreCache(
|
|
||||||
[cachePath],
|
|
||||||
cacheKey,
|
|
||||||
inputCacheExact ? [] : [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
|
|
||||||
}
|
|
||||||
|
|
||||||
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/**'
|
|
||||||
]
|
|
||||||
}
|
|
376
src/cache-extract-entries.ts
Normal file
376
src/cache-extract-entries.ts
Normal file
@@ -0,0 +1,376 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as glob from '@actions/glob'
|
||||||
|
|
||||||
|
import {META_FILE_DIR, PROJECT_ROOTS_FILE} from './cache-base'
|
||||||
|
import {CacheEntryListener, CacheListener} from './cache-reporting'
|
||||||
|
import {
|
||||||
|
cacheDebug,
|
||||||
|
getCacheKeyPrefix,
|
||||||
|
hashFileNames,
|
||||||
|
isCacheDebuggingEnabled,
|
||||||
|
restoreCache,
|
||||||
|
saveCache,
|
||||||
|
tryDelete
|
||||||
|
} from './cache-utils'
|
||||||
|
|
||||||
|
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the result of attempting to load or store an extracted cache entry.
|
||||||
|
* An undefined cacheKey indicates that the operation did not succeed.
|
||||||
|
* The collected results are then used to populate the `cache-metadata.json` file for later use.
|
||||||
|
*/
|
||||||
|
class ExtractedCacheEntry {
|
||||||
|
artifactType: string
|
||||||
|
pattern: string
|
||||||
|
cacheKey: string | undefined
|
||||||
|
|
||||||
|
constructor(artifactType: string, pattern: string, cacheKey: string | undefined) {
|
||||||
|
this.artifactType = artifactType
|
||||||
|
this.pattern = pattern
|
||||||
|
this.cacheKey = cacheKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of all of the extracted cache entries for this Gradle User Home.
|
||||||
|
* This object is persisted to JSON file in the Gradle User Home directory for storing,
|
||||||
|
* and subsequently used to restore the Gradle User Home.
|
||||||
|
*/
|
||||||
|
class ExtractedCacheEntryMetadata {
|
||||||
|
entries: ExtractedCacheEntry[] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The specification for a type of extracted cache entry.
|
||||||
|
*/
|
||||||
|
class ExtractedCacheEntryDefinition {
|
||||||
|
artifactType: string
|
||||||
|
pattern: string
|
||||||
|
bundle: boolean
|
||||||
|
uniqueFileNames = true
|
||||||
|
|
||||||
|
constructor(artifactType: string, pattern: string, bundle: boolean) {
|
||||||
|
this.artifactType = artifactType
|
||||||
|
this.pattern = pattern
|
||||||
|
this.bundle = bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
withNonUniqueFileNames(): ExtractedCacheEntryDefinition {
|
||||||
|
this.uniqueFileNames = false
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caches and restores the entire Gradle User Home directory, extracting entries containing common artifacts
|
||||||
|
* for more efficient storage.
|
||||||
|
*/
|
||||||
|
abstract class AbstractEntryExtractor {
|
||||||
|
protected readonly gradleUserHome: string
|
||||||
|
private extractorName: string
|
||||||
|
|
||||||
|
constructor(gradleUserHome: string, extractorName: string) {
|
||||||
|
this.gradleUserHome = gradleUserHome
|
||||||
|
this.extractorName = extractorName
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores any artifacts that were cached separately, based on the information in the `cache-metadata.json` file.
|
||||||
|
* Each extracted cache entry is restored in parallel, except when debugging is enabled.
|
||||||
|
*/
|
||||||
|
async restore(listener: CacheListener): Promise<void> {
|
||||||
|
const previouslyExtractedCacheEntries = this.loadExtractedCacheEntries()
|
||||||
|
|
||||||
|
const processes: Promise<ExtractedCacheEntry>[] = []
|
||||||
|
|
||||||
|
for (const cacheEntry of previouslyExtractedCacheEntries) {
|
||||||
|
const artifactType = cacheEntry.artifactType
|
||||||
|
const entryListener = listener.entry(cacheEntry.pattern)
|
||||||
|
|
||||||
|
// Handle case where the extracted-cache-entry definitions have been changed
|
||||||
|
const skipRestore = process.env[SKIP_RESTORE_VAR] || ''
|
||||||
|
if (skipRestore.includes(artifactType)) {
|
||||||
|
core.info(`Not restoring extracted cache entry for ${artifactType}`)
|
||||||
|
entryListener.markRequested('SKIP_RESTORE')
|
||||||
|
} else {
|
||||||
|
processes.push(
|
||||||
|
this.awaitForDebugging(
|
||||||
|
this.restoreExtractedCacheEntry(
|
||||||
|
artifactType,
|
||||||
|
cacheEntry.cacheKey!,
|
||||||
|
cacheEntry.pattern,
|
||||||
|
entryListener
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveMetadataForCacheResults(await Promise.all(processes))
|
||||||
|
}
|
||||||
|
|
||||||
|
private async restoreExtractedCacheEntry(
|
||||||
|
artifactType: string,
|
||||||
|
cacheKey: string,
|
||||||
|
pattern: string,
|
||||||
|
listener: CacheEntryListener
|
||||||
|
): Promise<ExtractedCacheEntry> {
|
||||||
|
listener.markRequested(cacheKey)
|
||||||
|
|
||||||
|
const restoredEntry = await restoreCache([pattern], cacheKey)
|
||||||
|
if (restoredEntry) {
|
||||||
|
core.info(`Restored ${artifactType} with key ${cacheKey} to ${pattern}`)
|
||||||
|
listener.markRestored(restoredEntry.key, restoredEntry.size)
|
||||||
|
return new ExtractedCacheEntry(artifactType, pattern, cacheKey)
|
||||||
|
} else {
|
||||||
|
core.info(`Did not restore ${artifactType} with key ${cacheKey} to ${pattern}`)
|
||||||
|
return new ExtractedCacheEntry(artifactType, pattern, undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves any artifacts that are configured to be cached separately, based on the extracted cache entry definitions.
|
||||||
|
* Each entry is extracted and saved in parallel, except when debugging is enabled.
|
||||||
|
*/
|
||||||
|
async extract(listener: CacheListener): Promise<void> {
|
||||||
|
// Load the cache entry definitions (from config) and the previously restored entries (from persisted metadata file)
|
||||||
|
const cacheEntryDefinitions = this.getExtractedCacheEntryDefinitions()
|
||||||
|
cacheDebug(
|
||||||
|
`Extracting cache entries for ${this.extractorName}: ${JSON.stringify(cacheEntryDefinitions, null, 2)}`
|
||||||
|
)
|
||||||
|
|
||||||
|
const previouslyRestoredEntries = this.loadExtractedCacheEntries()
|
||||||
|
const cacheActions: Promise<ExtractedCacheEntry>[] = []
|
||||||
|
|
||||||
|
// For each cache entry definition, determine if it has already been restored, and if not, extract it
|
||||||
|
for (const cacheEntryDefinition of cacheEntryDefinitions) {
|
||||||
|
const artifactType = cacheEntryDefinition.artifactType
|
||||||
|
const pattern = cacheEntryDefinition.pattern
|
||||||
|
|
||||||
|
// Find all matching files for this cache entry definition
|
||||||
|
const globber = await glob.create(pattern, {
|
||||||
|
implicitDescendants: false,
|
||||||
|
followSymbolicLinks: false
|
||||||
|
})
|
||||||
|
const matchingFiles = await globber.glob()
|
||||||
|
|
||||||
|
if (matchingFiles.length === 0) {
|
||||||
|
cacheDebug(`No files found to cache for ${artifactType}`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cacheEntryDefinition.bundle) {
|
||||||
|
// For an extracted "bundle", use the defined pattern and cache all matching files in a single entry.
|
||||||
|
cacheActions.push(
|
||||||
|
this.awaitForDebugging(
|
||||||
|
this.saveExtractedCacheEntry(
|
||||||
|
matchingFiles,
|
||||||
|
artifactType,
|
||||||
|
pattern,
|
||||||
|
cacheEntryDefinition.uniqueFileNames,
|
||||||
|
previouslyRestoredEntries,
|
||||||
|
listener.entry(pattern)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Otherwise cache each matching file in a separate entry, using the complete file path as the cache pattern.
|
||||||
|
for (const cacheFile of matchingFiles) {
|
||||||
|
cacheActions.push(
|
||||||
|
this.awaitForDebugging(
|
||||||
|
this.saveExtractedCacheEntry(
|
||||||
|
[cacheFile],
|
||||||
|
artifactType,
|
||||||
|
cacheFile,
|
||||||
|
cacheEntryDefinition.uniqueFileNames,
|
||||||
|
previouslyRestoredEntries,
|
||||||
|
listener.entry(cacheFile)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveMetadataForCacheResults(await Promise.all(cacheActions))
|
||||||
|
}
|
||||||
|
|
||||||
|
private async saveExtractedCacheEntry(
|
||||||
|
matchingFiles: string[],
|
||||||
|
artifactType: string,
|
||||||
|
pattern: string,
|
||||||
|
uniqueFileNames: boolean,
|
||||||
|
previouslyRestoredEntries: ExtractedCacheEntry[],
|
||||||
|
entryListener: CacheEntryListener
|
||||||
|
): Promise<ExtractedCacheEntry> {
|
||||||
|
const cacheKey = uniqueFileNames
|
||||||
|
? this.createCacheKeyFromFileNames(artifactType, matchingFiles)
|
||||||
|
: await this.createCacheKeyFromFileContents(artifactType, pattern)
|
||||||
|
const previouslyRestoredKey = previouslyRestoredEntries.find(
|
||||||
|
x => x.artifactType === artifactType && x.pattern === pattern
|
||||||
|
)?.cacheKey
|
||||||
|
|
||||||
|
if (previouslyRestoredKey === cacheKey) {
|
||||||
|
cacheDebug(`No change to previously restored ${artifactType}. Not saving.`)
|
||||||
|
} else {
|
||||||
|
core.info(`Caching ${artifactType} with path '${pattern}' and cache key: ${cacheKey}`)
|
||||||
|
const savedEntry = await saveCache([pattern], cacheKey)
|
||||||
|
if (savedEntry !== undefined) {
|
||||||
|
entryListener.markSaved(savedEntry.key, savedEntry.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const file of matchingFiles) {
|
||||||
|
tryDelete(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ExtractedCacheEntry(artifactType, pattern, cacheKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createCacheKeyFromFileNames(artifactType: string, files: string[]): string {
|
||||||
|
const cacheKeyPrefix = getCacheKeyPrefix()
|
||||||
|
const relativeFiles = files.map(x => path.relative(this.gradleUserHome, x))
|
||||||
|
const key = hashFileNames(relativeFiles)
|
||||||
|
|
||||||
|
cacheDebug(`Generating cache key for ${artifactType} from file names: ${relativeFiles}`)
|
||||||
|
|
||||||
|
return `${cacheKeyPrefix}${artifactType}-${key}`
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async createCacheKeyFromFileContents(artifactType: string, pattern: string): Promise<string> {
|
||||||
|
const cacheKeyPrefix = getCacheKeyPrefix()
|
||||||
|
const key = await glob.hashFiles(pattern)
|
||||||
|
|
||||||
|
cacheDebug(`Generating cache key for ${artifactType} from files matching: ${pattern}`)
|
||||||
|
|
||||||
|
return `${cacheKeyPrefix}${artifactType}-${key}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run actions sequentially if debugging is enabled
|
||||||
|
private async awaitForDebugging(p: Promise<ExtractedCacheEntry>): Promise<ExtractedCacheEntry> {
|
||||||
|
if (isCacheDebuggingEnabled()) {
|
||||||
|
await p
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load information about the extracted cache entries previously restored/saved. This is loaded from the 'cache-metadata.json' file.
|
||||||
|
*/
|
||||||
|
protected loadExtractedCacheEntries(): ExtractedCacheEntry[] {
|
||||||
|
const cacheMetadataFile = this.getCacheMetadataFile()
|
||||||
|
if (!fs.existsSync(cacheMetadataFile)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const filedata = fs.readFileSync(cacheMetadataFile, 'utf-8')
|
||||||
|
cacheDebug(`Loaded cache metadata: ${filedata}`)
|
||||||
|
const extractedCacheEntryMetadata = JSON.parse(filedata) as ExtractedCacheEntryMetadata
|
||||||
|
return extractedCacheEntryMetadata.entries
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves information about the extracted cache entries into the 'cache-metadata.json' file.
|
||||||
|
*/
|
||||||
|
private saveMetadataForCacheResults(results: ExtractedCacheEntry[]): void {
|
||||||
|
const extractedCacheEntryMetadata = new ExtractedCacheEntryMetadata()
|
||||||
|
extractedCacheEntryMetadata.entries = results.filter(x => x.cacheKey !== undefined)
|
||||||
|
|
||||||
|
const filedata = JSON.stringify(extractedCacheEntryMetadata)
|
||||||
|
cacheDebug(`Saving cache metadata: ${filedata}`)
|
||||||
|
|
||||||
|
fs.writeFileSync(this.getCacheMetadataFile(), filedata, 'utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCacheMetadataFile(): string {
|
||||||
|
const actionMetadataDirectory = path.resolve(this.gradleUserHome, META_FILE_DIR)
|
||||||
|
fs.mkdirSync(actionMetadataDirectory, {recursive: true})
|
||||||
|
|
||||||
|
return path.resolve(actionMetadataDirectory, `${this.extractorName}-entry-metadata.json`)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GradleHomeEntryExtractor extends AbstractEntryExtractor {
|
||||||
|
constructor(gradleUserHome: string) {
|
||||||
|
super(gradleUserHome, 'gradle-home')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the extracted cache entry definitions, which determine which artifacts will be cached
|
||||||
|
* separately from the rest of the Gradle User Home cache entry.
|
||||||
|
*/
|
||||||
|
protected getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[] {
|
||||||
|
const entryDefinition = (
|
||||||
|
artifactType: string,
|
||||||
|
patterns: string[],
|
||||||
|
bundle: boolean
|
||||||
|
): ExtractedCacheEntryDefinition => {
|
||||||
|
const resolvedPattern = patterns.map(x => path.resolve(this.gradleUserHome, x)).join('\n')
|
||||||
|
return new ExtractedCacheEntryDefinition(artifactType, resolvedPattern, bundle)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
entryDefinition('generated-gradle-jars', ['caches/*/generated-gradle-jars/*.jar'], false),
|
||||||
|
entryDefinition('wrapper-zips', ['wrapper/dists/*/*/*.zip'], false),
|
||||||
|
entryDefinition('java-toolchains', ['jdks/*.zip', 'jdks/*.tar.gz'], false),
|
||||||
|
entryDefinition('dependencies', ['caches/modules-*/files-*/*/*/*/*'], true),
|
||||||
|
entryDefinition('instrumented-jars', ['caches/jars-*/*'], true),
|
||||||
|
entryDefinition('kotlin-dsl', ['caches/*/kotlin-dsl/*/*'], true)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ConfigurationCacheEntryExtractor extends AbstractEntryExtractor {
|
||||||
|
constructor(gradleUserHome: string) {
|
||||||
|
super(gradleUserHome, 'configuration-cache')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the case where Gradle User Home has not been fully restored, so that the configuration-cache
|
||||||
|
* entry is not reusable.
|
||||||
|
*/
|
||||||
|
async restore(listener: CacheListener): Promise<void> {
|
||||||
|
if (listener.fullyRestored) {
|
||||||
|
return super.restore(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info('Not restoring configuration-cache state, as Gradle User Home was not fully restored')
|
||||||
|
for (const cacheEntry of this.loadExtractedCacheEntries()) {
|
||||||
|
listener.entry(cacheEntry.pattern).markRequested('NOT_RESTORED')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract cache entries for the configuration cache in each project.
|
||||||
|
*/
|
||||||
|
protected getExtractedCacheEntryDefinitions(): ExtractedCacheEntryDefinition[] {
|
||||||
|
return this.getProjectRoots().map(projectRoot => {
|
||||||
|
const configCachePath = path.resolve(projectRoot, '.gradle/configuration-cache')
|
||||||
|
return new ExtractedCacheEntryDefinition(
|
||||||
|
'configuration-cache',
|
||||||
|
configCachePath,
|
||||||
|
true
|
||||||
|
).withNonUniqueFileNames()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For every Gradle invocation, we record the project root directory. This method returns the entire
|
||||||
|
* set of project roots, to allow saving of configuration-cache entries for each.
|
||||||
|
*/
|
||||||
|
private getProjectRoots(): string[] {
|
||||||
|
const projectList = path.resolve(this.gradleUserHome, PROJECT_ROOTS_FILE)
|
||||||
|
if (!fs.existsSync(projectList)) {
|
||||||
|
core.info(`Missing project list file ${projectList}`)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const projectRoots = fs.readFileSync(projectList, 'utf-8')
|
||||||
|
core.info(`Found project roots '${projectRoots}' in ${projectList}`)
|
||||||
|
return projectRoots.trim().split('\n')
|
||||||
|
}
|
||||||
|
}
|
123
src/cache-reporting.ts
Normal file
123
src/cache-reporting.ts
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects information on what entries were saved and restored during the action.
|
||||||
|
* This information is used to generate a summary of the cache usage.
|
||||||
|
*/
|
||||||
|
export class CacheListener {
|
||||||
|
cacheEntries: CacheEntryListener[] = []
|
||||||
|
|
||||||
|
get fullyRestored(): boolean {
|
||||||
|
return this.cacheEntries.every(x => !x.wasRequestedButNotRestored())
|
||||||
|
}
|
||||||
|
|
||||||
|
entry(name: string): CacheEntryListener {
|
||||||
|
for (const entry of this.cacheEntries) {
|
||||||
|
if (entry.entryName === name) {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newEntry = new CacheEntryListener(name)
|
||||||
|
this.cacheEntries.push(newEntry)
|
||||||
|
return newEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
stringify(): string {
|
||||||
|
return JSON.stringify(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
static rehydrate(stringRep: string): CacheListener {
|
||||||
|
const rehydrated: CacheListener = Object.assign(new CacheListener(), JSON.parse(stringRep))
|
||||||
|
const entries = rehydrated.cacheEntries
|
||||||
|
for (let index = 0; index < entries.length; index++) {
|
||||||
|
const rawEntry = entries[index]
|
||||||
|
entries[index] = Object.assign(new CacheEntryListener(rawEntry.entryName), rawEntry)
|
||||||
|
}
|
||||||
|
return rehydrated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects information on the state of a single cache entry.
|
||||||
|
*/
|
||||||
|
export class CacheEntryListener {
|
||||||
|
entryName: string
|
||||||
|
requestedKey: string | undefined
|
||||||
|
requestedRestoreKeys: string[] | undefined
|
||||||
|
restoredKey: string | undefined
|
||||||
|
restoredSize: number | undefined
|
||||||
|
|
||||||
|
savedKey: string | undefined
|
||||||
|
savedSize: number | undefined
|
||||||
|
|
||||||
|
constructor(entryName: string) {
|
||||||
|
this.entryName = entryName
|
||||||
|
}
|
||||||
|
|
||||||
|
wasRequestedButNotRestored(): boolean {
|
||||||
|
return this.requestedKey !== undefined && this.restoredKey === undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
markRequested(key: string, restoreKeys: string[] = []): CacheEntryListener {
|
||||||
|
this.requestedKey = key
|
||||||
|
this.requestedRestoreKeys = restoreKeys
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
markRestored(key: string, size: number | undefined): CacheEntryListener {
|
||||||
|
this.restoredKey = key
|
||||||
|
this.restoredSize = size
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
markSaved(key: string, size: number | undefined): CacheEntryListener {
|
||||||
|
this.savedKey = key
|
||||||
|
this.savedSize = size
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logCachingReport(listener: CacheListener): void {
|
||||||
|
if (listener.cacheEntries.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`---------- Caching Summary -------------
|
||||||
|
Restored Entries Count: ${getCount(listener.cacheEntries, e => e.restoredSize)}
|
||||||
|
Size: ${getSum(listener.cacheEntries, e => e.restoredSize)}
|
||||||
|
Saved Entries Count: ${getCount(listener.cacheEntries, e => e.savedSize)}
|
||||||
|
Size: ${getSum(listener.cacheEntries, e => e.savedSize)}`)
|
||||||
|
|
||||||
|
core.startGroup('Cache Entry details')
|
||||||
|
for (const entry of listener.cacheEntries) {
|
||||||
|
core.info(`Entry: ${entry.entryName}
|
||||||
|
Requested Key : ${entry.requestedKey ?? ''}
|
||||||
|
Restored Key : ${entry.restoredKey ?? ''}
|
||||||
|
Size: ${formatSize(entry.restoredSize)}
|
||||||
|
Saved Key : ${entry.savedKey ?? ''}
|
||||||
|
Size: ${formatSize(entry.savedSize)}`)
|
||||||
|
}
|
||||||
|
core.endGroup()
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCount(
|
||||||
|
cacheEntries: CacheEntryListener[],
|
||||||
|
predicate: (value: CacheEntryListener) => number | undefined
|
||||||
|
): number {
|
||||||
|
return cacheEntries.filter(e => predicate(e) !== undefined).length
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSum(
|
||||||
|
cacheEntries: CacheEntryListener[],
|
||||||
|
predicate: (value: CacheEntryListener) => number | undefined
|
||||||
|
): string {
|
||||||
|
return formatSize(cacheEntries.map(e => predicate(e) ?? 0).reduce((p, v) => p + v, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSize(bytes: number | undefined): string {
|
||||||
|
if (bytes === undefined || bytes === 0) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return `${Math.round(bytes / (1024 * 1024))} MB (${bytes} B)`
|
||||||
|
}
|
123
src/cache-utils.ts
Normal file
123
src/cache-utils.ts
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as cache from '@actions/cache'
|
||||||
|
import * as crypto from 'crypto'
|
||||||
|
import * as path from 'path'
|
||||||
|
import * as fs from 'fs'
|
||||||
|
|
||||||
|
const JOB_CONTEXT_PARAMETER = 'workflow-job-context'
|
||||||
|
const CACHE_DISABLED_PARAMETER = 'cache-disabled'
|
||||||
|
const CACHE_READONLY_PARAMETER = 'cache-read-only'
|
||||||
|
const CACHE_DEBUG_VAR = 'GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED'
|
||||||
|
const CACHE_PREFIX_VAR = 'GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX'
|
||||||
|
|
||||||
|
export function isCacheDisabled(): boolean {
|
||||||
|
return core.getBooleanInput(CACHE_DISABLED_PARAMETER)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCacheReadOnly(): boolean {
|
||||||
|
return core.getBooleanInput(CACHE_READONLY_PARAMETER)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCacheDebuggingEnabled(): boolean {
|
||||||
|
return process.env[CACHE_DEBUG_VAR] ? true : false
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCacheKeyPrefix(): string {
|
||||||
|
// Prefix can be used to force change all cache keys (defaults to cache protocol version)
|
||||||
|
return process.env[CACHE_PREFIX_VAR] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export function determineJobContext(): string {
|
||||||
|
// By default, we hash the full `matrix` data for the run, to uniquely identify this job invocation
|
||||||
|
// The only way we can obtain the `matrix` data is via the `workflow-job-context` parameter in action.yml.
|
||||||
|
const workflowJobContext = core.getInput(JOB_CONTEXT_PARAMETER)
|
||||||
|
return hashStrings([workflowJobContext])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hashFileNames(fileNames: string[]): string {
|
||||||
|
return hashStrings(fileNames.map(x => x.replace(new RegExp(`\\${path.sep}`, 'g'), '/')))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hashStrings(values: string[]): string {
|
||||||
|
const hash = crypto.createHash('md5')
|
||||||
|
for (const value of values) {
|
||||||
|
hash.update(value)
|
||||||
|
}
|
||||||
|
return hash.digest('hex')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function restoreCache(
|
||||||
|
cachePath: string[],
|
||||||
|
cacheKey: string,
|
||||||
|
cacheRestoreKeys: string[] = []
|
||||||
|
): Promise<cache.CacheEntry | undefined> {
|
||||||
|
try {
|
||||||
|
return await cache.restoreCache(cachePath, cacheKey, cacheRestoreKeys)
|
||||||
|
} catch (error) {
|
||||||
|
handleCacheFailure(error, `Failed to restore ${cacheKey}`)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveCache(cachePath: string[], cacheKey: string): Promise<cache.CacheEntry | undefined> {
|
||||||
|
try {
|
||||||
|
return await cache.saveCache(cachePath, cacheKey)
|
||||||
|
} catch (error) {
|
||||||
|
handleCacheFailure(error, `Failed to save cache entry ${cacheKey}`)
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cacheDebug(message: string): void {
|
||||||
|
if (isCacheDebuggingEnabled()) {
|
||||||
|
core.info(message)
|
||||||
|
} else {
|
||||||
|
core.debug(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleCacheFailure(error: unknown, message: string): void {
|
||||||
|
if (error instanceof cache.ValidationError) {
|
||||||
|
// Fail on cache validation errors
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
if (error instanceof cache.ReserveCacheError) {
|
||||||
|
// Reserve cache errors are expected if the artifact has been previously cached
|
||||||
|
if (isCacheDebuggingEnabled()) {
|
||||||
|
core.info(`${message}: ${error}`)
|
||||||
|
} else {
|
||||||
|
core.debug(`${message}: ${error}`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Warn on all other errors
|
||||||
|
core.warning(`${message}: ${error}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to delete a file or directory, waiting to allow locks to be released
|
||||||
|
*/
|
||||||
|
export async function tryDelete(file: string): Promise<void> {
|
||||||
|
const stat = fs.lstatSync(file)
|
||||||
|
for (let count = 0; count < 3; count++) {
|
||||||
|
try {
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
fs.rmdirSync(file, {recursive: true})
|
||||||
|
} else {
|
||||||
|
fs.unlinkSync(file)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} catch (error) {
|
||||||
|
if (count === 2) {
|
||||||
|
throw error
|
||||||
|
} else {
|
||||||
|
core.warning(String(error))
|
||||||
|
await delay(1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function delay(ms: number): Promise<void> {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
@@ -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`
|
|
||||||
)
|
|
||||||
}
|
|
79
src/caches.ts
Normal file
79
src/caches.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
|
import {isCacheDisabled, isCacheReadOnly} from './cache-utils'
|
||||||
|
import {logCachingReport, CacheListener} from './cache-reporting'
|
||||||
|
import {GradleStateCache} from './cache-base'
|
||||||
|
|
||||||
|
const CACHE_RESTORED_VAR = 'GRADLE_BUILD_ACTION_CACHE_RESTORED'
|
||||||
|
const GRADLE_USER_HOME = 'GRADLE_USER_HOME'
|
||||||
|
const CACHE_LISTENER = 'CACHE_LISTENER'
|
||||||
|
|
||||||
|
export async function restore(gradleUserHome: string): Promise<void> {
|
||||||
|
if (!shouldRestoreCaches()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const gradleStateCache = new GradleStateCache(gradleUserHome)
|
||||||
|
gradleStateCache.init()
|
||||||
|
|
||||||
|
await core.group('Restore Gradle state from cache', async () => {
|
||||||
|
core.saveState(GRADLE_USER_HOME, gradleUserHome)
|
||||||
|
|
||||||
|
const cacheListener = new CacheListener()
|
||||||
|
await gradleStateCache.restore(cacheListener)
|
||||||
|
|
||||||
|
core.saveState(CACHE_LISTENER, cacheListener.stringify())
|
||||||
|
})
|
||||||
|
|
||||||
|
// Export var that is detected in all later restore steps
|
||||||
|
core.exportVariable(CACHE_RESTORED_VAR, true)
|
||||||
|
// Export state that is detected in corresponding post-action step
|
||||||
|
core.saveState(CACHE_RESTORED_VAR, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function save(): Promise<void> {
|
||||||
|
if (!shouldSaveCaches()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER))
|
||||||
|
|
||||||
|
if (isCacheReadOnly()) {
|
||||||
|
core.info('Cache is read-only: will not save state for use in subsequent builds.')
|
||||||
|
logCachingReport(cacheListener)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await core.group('Caching Gradle state', async () => {
|
||||||
|
const gradleUserHome = core.getState(GRADLE_USER_HOME)
|
||||||
|
return new GradleStateCache(gradleUserHome).save(cacheListener)
|
||||||
|
})
|
||||||
|
|
||||||
|
logCachingReport(cacheListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldRestoreCaches(): boolean {
|
||||||
|
if (isCacheDisabled()) {
|
||||||
|
core.info('Cache is disabled: will not restore state from previous builds.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env[CACHE_RESTORED_VAR]) {
|
||||||
|
core.info('Cache only restored on first action step.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldSaveCaches(): boolean {
|
||||||
|
if (isCacheDisabled()) {
|
||||||
|
core.info('Cache is disabled: will not save state for later builds.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!core.getState(CACHE_RESTORED_VAR)) {
|
||||||
|
core.info('Cache will only be saved in final post-action step.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
@@ -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,42 +1,33 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
import * as cacheDependencies from './cache-dependencies'
|
import fs from 'fs'
|
||||||
import * as cacheConfiguration from './cache-configuration'
|
import path from 'path'
|
||||||
|
import * as gradlew from './gradlew'
|
||||||
|
|
||||||
export async function execute(
|
export async function executeGradleBuild(executable: string | undefined, root: string, args: string[]): Promise<void> {
|
||||||
executable: string,
|
|
||||||
root: string,
|
|
||||||
argv: string[]
|
|
||||||
): Promise<BuildResult> {
|
|
||||||
await cacheDependencies.restoreCachedDependencies(root)
|
|
||||||
await cacheConfiguration.restoreCachedConfiguration(root)
|
|
||||||
|
|
||||||
let publishing = false
|
|
||||||
let buildScanUrl: string | undefined
|
let buildScanUrl: string | undefined
|
||||||
|
|
||||||
const status: number = await exec.exec(executable, argv, {
|
const buildScanFile = path.resolve(root, 'gradle-build-scan.txt')
|
||||||
|
if (fs.existsSync(buildScanFile)) {
|
||||||
|
fs.unlinkSync(buildScanFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the provided executable, or look for a Gradle wrapper script to run
|
||||||
|
const toExecute = executable ?? gradlew.locateGradleWrapperScript(root)
|
||||||
|
const status: number = await exec.exec(toExecute, args, {
|
||||||
cwd: root,
|
cwd: root,
|
||||||
ignoreReturnCode: true,
|
ignoreReturnCode: true
|
||||||
listeners: {
|
|
||||||
stdline: (line: string) => {
|
|
||||||
if (line.includes('Publishing build scan...')) {
|
|
||||||
publishing = true
|
|
||||||
}
|
|
||||||
if (publishing && line.startsWith('http')) {
|
|
||||||
buildScanUrl = line.trim()
|
|
||||||
publishing = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return new BuildResultImpl(status, buildScanUrl)
|
if (fs.existsSync(buildScanFile)) {
|
||||||
}
|
buildScanUrl = fs.readFileSync(buildScanFile, 'utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
export interface BuildResult {
|
if (status !== 0) {
|
||||||
readonly status: number
|
if (buildScanUrl) {
|
||||||
readonly buildScanUrl?: string
|
core.setFailed(`Gradle build failed: ${buildScanUrl}`)
|
||||||
}
|
} else {
|
||||||
|
core.setFailed(`Gradle build failed: process exited with status ${status}`)
|
||||||
class BuildResultImpl implements BuildResult {
|
}
|
||||||
constructor(readonly status: number, readonly buildScanUrl?: string) {}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@ import fs from 'fs'
|
|||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32'
|
const IS_WINDOWS = process.platform === 'win32'
|
||||||
|
|
||||||
export function wrapperFilename(): string {
|
export function wrapperScriptFilename(): string {
|
||||||
return IS_WINDOWS ? 'gradlew.bat' : 'gradlew'
|
return IS_WINDOWS ? 'gradlew.bat' : 'gradlew'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,11 +11,13 @@ export function installScriptFilename(): string {
|
|||||||
return IS_WINDOWS ? 'gradle.bat' : 'gradle'
|
return IS_WINDOWS ? 'gradle.bat' : 'gradle'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateGradleWrapper(gradlewDirectory: string): void {
|
export function locateGradleWrapperScript(buildRootDirectory: string): string {
|
||||||
const wrapperProperties = path.resolve(
|
validateGradleWrapper(buildRootDirectory)
|
||||||
gradlewDirectory,
|
return path.resolve(buildRootDirectory, wrapperScriptFilename())
|
||||||
'gradle/wrapper/gradle-wrapper.properties'
|
}
|
||||||
)
|
|
||||||
|
function validateGradleWrapper(buildRootDirectory: string): void {
|
||||||
|
const wrapperProperties = path.resolve(buildRootDirectory, 'gradle/wrapper/gradle-wrapper.properties')
|
||||||
if (!fs.existsSync(wrapperProperties)) {
|
if (!fs.existsSync(wrapperProperties)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Cannot locate a Gradle wrapper properties file at '${wrapperProperties}'. Specify 'gradle-version' or 'gradle-executable' for projects without Gradle wrapper configured.`
|
`Cannot locate a Gradle wrapper properties file at '${wrapperProperties}'. Specify 'gradle-version' or 'gradle-executable' for projects without Gradle wrapper configured.`
|
||||||
|
69
src/main.ts
69
src/main.ts
@@ -1,45 +1,45 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
import * as os from 'os'
|
||||||
import {parseArgsStringToArgv} from 'string-argv'
|
import {parseArgsStringToArgv} from 'string-argv'
|
||||||
|
|
||||||
import * as cacheWrapper from './cache-wrapper'
|
import * as caches from './caches'
|
||||||
import * as execution from './execution'
|
import * as execution from './execution'
|
||||||
import * as gradlew from './gradlew'
|
|
||||||
import * as provision from './provision'
|
import * as provision from './provision'
|
||||||
|
|
||||||
// Invoked by GitHub Actions
|
/**
|
||||||
|
* The main entry point for the action, called by Github Actions for the step.
|
||||||
|
*/
|
||||||
export async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || ''
|
const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || ''
|
||||||
const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory)
|
const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory)
|
||||||
|
const gradleUserHome = determineGradleUserHome(buildRootDirectory)
|
||||||
|
|
||||||
const result = await execution.execute(
|
await caches.restore(gradleUserHome)
|
||||||
await resolveGradleExecutable(
|
|
||||||
workspaceDirectory,
|
|
||||||
buildRootDirectory
|
|
||||||
),
|
|
||||||
buildRootDirectory,
|
|
||||||
parseCommandLineArguments()
|
|
||||||
)
|
|
||||||
|
|
||||||
if (result.buildScanUrl) {
|
const executable = await provisionGradle(workspaceDirectory)
|
||||||
core.setOutput('build-scan-url', result.buildScanUrl)
|
// executable will be undefined if using Gradle wrapper
|
||||||
|
if (executable !== undefined) {
|
||||||
|
core.addPath(path.dirname(executable))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.status !== 0) {
|
// Only execute if arguments have been provided
|
||||||
core.setFailed(`Gradle process exited with status ${result.status}`)
|
const args: string[] = parseCommandLineArguments()
|
||||||
|
if (args.length > 0) {
|
||||||
|
await execution.executeGradleBuild(executable, buildRootDirectory, args)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message)
|
core.setFailed(String(error))
|
||||||
|
if (error instanceof Error && error.stack) {
|
||||||
|
core.info(error.stack)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run()
|
run()
|
||||||
|
|
||||||
async function resolveGradleExecutable(
|
async function provisionGradle(workspaceDirectory: string): Promise<string | undefined> {
|
||||||
workspaceDirectory: string,
|
|
||||||
buildRootDirectory: string
|
|
||||||
): Promise<string> {
|
|
||||||
const gradleVersion = core.getInput('gradle-version')
|
const gradleVersion = core.getInput('gradle-version')
|
||||||
if (gradleVersion !== '' && gradleVersion !== 'wrapper') {
|
if (gradleVersion !== '' && gradleVersion !== 'wrapper') {
|
||||||
return path.resolve(await provision.gradleVersion(gradleVersion))
|
return path.resolve(await provision.gradleVersion(gradleVersion))
|
||||||
@@ -47,35 +47,28 @@ async function resolveGradleExecutable(
|
|||||||
|
|
||||||
const gradleExecutable = core.getInput('gradle-executable')
|
const gradleExecutable = core.getInput('gradle-executable')
|
||||||
if (gradleExecutable !== '') {
|
if (gradleExecutable !== '') {
|
||||||
if (gradleExecutable.endsWith(gradlew.wrapperFilename())) {
|
|
||||||
await cacheWrapper.restoreCachedWrapperDist(
|
|
||||||
path.resolve(gradleExecutable, '..')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return path.resolve(workspaceDirectory, gradleExecutable)
|
return path.resolve(workspaceDirectory, gradleExecutable)
|
||||||
}
|
}
|
||||||
|
|
||||||
const wrapperDirectory = core.getInput('wrapper-directory')
|
return undefined
|
||||||
const gradlewDirectory =
|
|
||||||
wrapperDirectory !== ''
|
|
||||||
? path.resolve(workspaceDirectory, wrapperDirectory)
|
|
||||||
: buildRootDirectory
|
|
||||||
|
|
||||||
gradlew.validateGradleWrapper(gradlewDirectory)
|
|
||||||
await cacheWrapper.restoreCachedWrapperDist(gradlewDirectory)
|
|
||||||
|
|
||||||
return path.resolve(gradlewDirectory, gradlew.wrapperFilename())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveBuildRootDirectory(baseDirectory: string): string {
|
function resolveBuildRootDirectory(baseDirectory: string): string {
|
||||||
const buildRootDirectory = core.getInput('build-root-directory')
|
const buildRootDirectory = core.getInput('build-root-directory')
|
||||||
const resolvedBuildRootDirectory =
|
const resolvedBuildRootDirectory =
|
||||||
buildRootDirectory === ''
|
buildRootDirectory === '' ? path.resolve(baseDirectory) : path.resolve(baseDirectory, buildRootDirectory)
|
||||||
? path.resolve(baseDirectory)
|
|
||||||
: path.resolve(baseDirectory, buildRootDirectory)
|
|
||||||
return resolvedBuildRootDirectory
|
return resolvedBuildRootDirectory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function determineGradleUserHome(rootDir: string): string {
|
||||||
|
const customGradleUserHome = process.env['GRADLE_USER_HOME']
|
||||||
|
if (customGradleUserHome) {
|
||||||
|
return path.resolve(rootDir, customGradleUserHome)
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.resolve(os.homedir(), '.gradle')
|
||||||
|
}
|
||||||
|
|
||||||
function parseCommandLineArguments(): string[] {
|
function parseCommandLineArguments(): string[] {
|
||||||
const input = core.getInput('arguments')
|
const input = core.getInput('arguments')
|
||||||
return parseArgsStringToArgv(input)
|
return parseArgsStringToArgv(input)
|
||||||
|
29
src/post.ts
29
src/post.ts
@@ -1,12 +1,27 @@
|
|||||||
import * as cacheWrapper from './cache-wrapper'
|
import * as core from '@actions/core'
|
||||||
import * as cacheDependencies from './cache-dependencies'
|
import * as caches from './caches'
|
||||||
import * as cacheConfiguration from './cache-configuration'
|
|
||||||
|
|
||||||
// Invoked by GitHub Actions
|
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||||
|
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
||||||
|
// throw an uncaught exception. Instead of failing this action, just warn.
|
||||||
|
process.on('uncaughtException', e => handleFailure(e))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The post-execution entry point for the action, called by Github Actions after completing all steps for the Job.
|
||||||
|
*/
|
||||||
export async function run(): Promise<void> {
|
export async function run(): Promise<void> {
|
||||||
await cacheWrapper.cacheWrapperDist()
|
try {
|
||||||
await cacheDependencies.cacheDependencies()
|
await caches.save()
|
||||||
await cacheConfiguration.cacheConfiguration()
|
} catch (error) {
|
||||||
|
handleFailure(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFailure(error: unknown): void {
|
||||||
|
core.warning(`Unhandled error saving cache - job will continue: ${error}`)
|
||||||
|
if (error instanceof Error && error.stack) {
|
||||||
|
core.info(error.stack)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run()
|
run()
|
||||||
|
104
src/provision.ts
104
src/provision.ts
@@ -7,6 +7,7 @@ import * as cache from '@actions/cache'
|
|||||||
import * as toolCache from '@actions/tool-cache'
|
import * as toolCache from '@actions/tool-cache'
|
||||||
|
|
||||||
import * as gradlew from './gradlew'
|
import * as gradlew from './gradlew'
|
||||||
|
import {handleCacheFailure, isCacheDisabled, isCacheReadOnly} from './cache-utils'
|
||||||
|
|
||||||
const gradleVersionsBaseUrl = 'https://services.gradle.org/versions'
|
const gradleVersionsBaseUrl = 'https://services.gradle.org/versions'
|
||||||
|
|
||||||
@@ -18,9 +19,7 @@ export async function gradleVersion(version: string): Promise<string> {
|
|||||||
case 'current':
|
case 'current':
|
||||||
return gradleCurrent()
|
return gradleCurrent()
|
||||||
case 'rc':
|
case 'rc':
|
||||||
core.warning(
|
core.warning(`Specifying gradle-version 'rc' has been deprecated. Use 'release-candidate' instead.`)
|
||||||
`Specifying gradle-version 'rc' has been deprecated. Use 'release-candidate' instead.`
|
|
||||||
)
|
|
||||||
return gradleReleaseCandidate()
|
return gradleReleaseCandidate()
|
||||||
case 'release-candidate':
|
case 'release-candidate':
|
||||||
return gradleReleaseCandidate()
|
return gradleReleaseCandidate()
|
||||||
@@ -34,16 +33,12 @@ export async function gradleVersion(version: string): Promise<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function gradleCurrent(): Promise<string> {
|
async function gradleCurrent(): Promise<string> {
|
||||||
const versionInfo = await gradleVersionDeclaration(
|
const versionInfo = await gradleVersionDeclaration(`${gradleVersionsBaseUrl}/current`)
|
||||||
`${gradleVersionsBaseUrl}/current`
|
|
||||||
)
|
|
||||||
return provisionGradle(versionInfo)
|
return provisionGradle(versionInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function gradleReleaseCandidate(): Promise<string> {
|
async function gradleReleaseCandidate(): Promise<string> {
|
||||||
const versionInfo = await gradleVersionDeclaration(
|
const versionInfo = await gradleVersionDeclaration(`${gradleVersionsBaseUrl}/release-candidate`)
|
||||||
`${gradleVersionsBaseUrl}/release-candidate`
|
|
||||||
)
|
|
||||||
if (versionInfo && versionInfo.version && versionInfo.downloadUrl) {
|
if (versionInfo && versionInfo.version && versionInfo.downloadUrl) {
|
||||||
return provisionGradle(versionInfo)
|
return provisionGradle(versionInfo)
|
||||||
}
|
}
|
||||||
@@ -52,16 +47,12 @@ async function gradleReleaseCandidate(): Promise<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function gradleNightly(): Promise<string> {
|
async function gradleNightly(): Promise<string> {
|
||||||
const versionInfo = await gradleVersionDeclaration(
|
const versionInfo = await gradleVersionDeclaration(`${gradleVersionsBaseUrl}/nightly`)
|
||||||
`${gradleVersionsBaseUrl}/nightly`
|
|
||||||
)
|
|
||||||
return provisionGradle(versionInfo)
|
return provisionGradle(versionInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function gradleReleaseNightly(): Promise<string> {
|
async function gradleReleaseNightly(): Promise<string> {
|
||||||
const versionInfo = await gradleVersionDeclaration(
|
const versionInfo = await gradleVersionDeclaration(`${gradleVersionsBaseUrl}/release-nightly`)
|
||||||
`${gradleVersionsBaseUrl}/release-nightly`
|
|
||||||
)
|
|
||||||
return provisionGradle(versionInfo)
|
return provisionGradle(versionInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,26 +64,24 @@ async function gradle(version: string): Promise<string> {
|
|||||||
return provisionGradle(versionInfo)
|
return provisionGradle(versionInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function gradleVersionDeclaration(
|
async function gradleVersionDeclaration(url: string): Promise<GradleVersionInfo> {
|
||||||
url: string
|
|
||||||
): Promise<GradleVersionInfo> {
|
|
||||||
return await httpGetGradleVersion(url)
|
return await httpGetGradleVersion(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findGradleVersionDeclaration(
|
async function findGradleVersionDeclaration(version: string): Promise<GradleVersionInfo | undefined> {
|
||||||
version: string
|
const gradleVersions = await httpGetGradleVersions(`${gradleVersionsBaseUrl}/all`)
|
||||||
): Promise<GradleVersionInfo | undefined> {
|
|
||||||
const gradleVersions = await httpGetGradleVersions(
|
|
||||||
`${gradleVersionsBaseUrl}/all`
|
|
||||||
)
|
|
||||||
return gradleVersions.find((entry: GradleVersionInfo) => {
|
return gradleVersions.find((entry: GradleVersionInfo) => {
|
||||||
return entry.version === version
|
return entry.version === version
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function provisionGradle(
|
async function provisionGradle(versionInfo: GradleVersionInfo): Promise<string> {
|
||||||
versionInfo: GradleVersionInfo
|
return core.group(`Provision Gradle ${versionInfo.version}`, async () => {
|
||||||
): Promise<string> {
|
return locateGradleAndDownloadIfRequired(versionInfo)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function locateGradleAndDownloadIfRequired(versionInfo: GradleVersionInfo): Promise<string> {
|
||||||
const installsDir = path.join(os.homedir(), 'gradle-installations/installs')
|
const installsDir = path.join(os.homedir(), 'gradle-installations/installs')
|
||||||
const installDir = path.join(installsDir, `gradle-${versionInfo.version}`)
|
const installDir = path.join(installsDir, `gradle-${versionInfo.version}`)
|
||||||
if (fs.existsSync(installDir)) {
|
if (fs.existsSync(installDir)) {
|
||||||
@@ -111,56 +100,41 @@ async function provisionGradle(
|
|||||||
return executable
|
return executable
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadAndCacheGradleDistribution(
|
async function downloadAndCacheGradleDistribution(versionInfo: GradleVersionInfo): Promise<string> {
|
||||||
versionInfo: GradleVersionInfo
|
const downloadPath = path.join(os.homedir(), `gradle-installations/downloads/gradle-${versionInfo.version}-bin.zip`)
|
||||||
): Promise<string> {
|
|
||||||
const downloadPath = path.join(
|
|
||||||
os.homedir(),
|
|
||||||
`gradle-installations/downloads/gradle-${versionInfo.version}-bin.zip`
|
|
||||||
)
|
|
||||||
|
|
||||||
if (isDistributionsCacheDisabled()) {
|
if (isCacheDisabled()) {
|
||||||
await downloadGradleDistribution(versionInfo, downloadPath)
|
await downloadGradleDistribution(versionInfo, downloadPath)
|
||||||
return downloadPath
|
return downloadPath
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheKey = `gradle-${versionInfo.version}`
|
const cacheKey = `gradle-${versionInfo.version}`
|
||||||
const restoreKey = await cache.restoreCache([downloadPath], cacheKey)
|
try {
|
||||||
if (restoreKey) {
|
const restoreKey = await cache.restoreCache([downloadPath], cacheKey)
|
||||||
core.info(
|
if (restoreKey) {
|
||||||
`Restored Gradle distribution ${cacheKey} from cache to ${downloadPath}`
|
core.info(`Restored Gradle distribution ${cacheKey} from cache to ${downloadPath}`)
|
||||||
)
|
return downloadPath
|
||||||
} else {
|
}
|
||||||
core.info(
|
} catch (error) {
|
||||||
`Gradle distribution ${versionInfo.version} not found in cache. Will download.`
|
handleCacheFailure(error, `Restore Gradle distribution ${versionInfo.version} failed`)
|
||||||
)
|
}
|
||||||
await downloadGradleDistribution(versionInfo, downloadPath)
|
|
||||||
|
|
||||||
|
core.info(`Gradle distribution ${versionInfo.version} not found in cache. Will download.`)
|
||||||
|
await downloadGradleDistribution(versionInfo, downloadPath)
|
||||||
|
|
||||||
|
if (!isCacheReadOnly()) {
|
||||||
try {
|
try {
|
||||||
await cache.saveCache([downloadPath], cacheKey)
|
await cache.saveCache([downloadPath], cacheKey)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.name === cache.ValidationError.name) {
|
handleCacheFailure(error, `Save Gradle distribution ${versionInfo.version} failed`)
|
||||||
throw error
|
|
||||||
} else if (error.name === cache.ReserveCacheError.name) {
|
|
||||||
core.info(error.message)
|
|
||||||
} else {
|
|
||||||
core.info(`[warning] ${error.message}`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return downloadPath
|
return downloadPath
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadGradleDistribution(
|
async function downloadGradleDistribution(versionInfo: GradleVersionInfo, downloadPath: string): Promise<void> {
|
||||||
versionInfo: GradleVersionInfo,
|
|
||||||
downloadPath: string
|
|
||||||
): Promise<void> {
|
|
||||||
await toolCache.downloadTool(versionInfo.downloadUrl, downloadPath)
|
await toolCache.downloadTool(versionInfo.downloadUrl, downloadPath)
|
||||||
core.info(
|
core.info(`Downloaded ${versionInfo.downloadUrl} to ${downloadPath} (size ${fs.statSync(downloadPath).size})`)
|
||||||
`Downloaded ${versionInfo.downloadUrl} to ${downloadPath} (size ${
|
|
||||||
fs.statSync(downloadPath).size
|
|
||||||
})`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function executableFrom(installDir: string): string {
|
function executableFrom(installDir: string): string {
|
||||||
@@ -171,9 +145,7 @@ async function httpGetGradleVersion(url: string): Promise<GradleVersionInfo> {
|
|||||||
return JSON.parse(await httpGetString(url))
|
return JSON.parse(await httpGetString(url))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function httpGetGradleVersions(
|
async function httpGetGradleVersions(url: string): Promise<GradleVersionInfo[]> {
|
||||||
url: string
|
|
||||||
): Promise<GradleVersionInfo[]> {
|
|
||||||
return JSON.parse(await httpGetString(url))
|
return JSON.parse(await httpGetString(url))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,10 +155,6 @@ async function httpGetString(url: string): Promise<string> {
|
|||||||
return response.readBody()
|
return response.readBody()
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDistributionsCacheDisabled(): boolean {
|
|
||||||
return !core.getBooleanInput('distributions-cache-enabled')
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GradleVersionInfo {
|
interface GradleVersionInfo {
|
||||||
version: string
|
version: string
|
||||||
downloadUrl: string
|
downloadUrl: string
|
||||||
|
Reference in New Issue
Block a user