Compare commits

...

21 Commits

Author SHA1 Message Date
daz
af1da67850 Prevent concurrent jobs in integ-test-full 2024-08-03 15:54:44 -06:00
daz
f8ba43cf0a Better names for suite workflows 2024-08-03 15:10:49 -06:00
daz
bcd07e6643 Refactor integ-tests into suites
- Extract 2 suites to make it possible to reduce concurrency
- Add separate workflow for integ-test and integ-test-full
2024-08-03 14:56:37 -06:00
daz
d74ee73e9f Refactor integ-tests
- Include test name in all job names
- Remove cache key delegation as it is unused
2024-08-03 14:56:37 -06:00
bigdaz
fb2e6938b6 [bot] Update dist directory 2024-08-02 21:57:19 +00:00
Daz DeBoer
07190022f8 Improve error messages for min-wrapper-count (#321) 2024-08-02 15:56:14 -06:00
daz
ac3aebda93 Improve error messages for min-wrapper-count
- Specific message when no wrappers are found
- Better message when wrapper count is less than configured

Fixes #284
2024-08-02 15:51:41 -06:00
daz
d473db0899 Add tests for wrapper-validation with insufficient wrappers
- Test min-wrapper-count greater than wrappers
- Test caswrapper-validation with insufficient wrappers
2024-08-02 15:50:28 -06:00
bigdaz
833b05f3e6 [bot] Update dist directory 2024-08-01 17:05:22 +00:00
Daz DeBoer
06905c7a0f Enable wrapper-validation by default in setup-gradle (#318) 2024-08-01 11:04:20 -06:00
daz
73f1290de7 Improve docs linked for wrapper-validation failure 2024-08-01 10:59:51 -06:00
daz
b6395da67c Cache validated checksums for later executions
The most common case for validation will be that the wrapper jars are unchanged
from a previous workflow run. In this case, we cache the validated wrapper
checksums to minimise the work required on a subsequent run.

Fixes #172
2024-08-01 10:52:36 -06:00
daz
ce4c3a6c5e Move wrapper-validation into common setup code 2024-08-01 10:52:36 -06:00
daz
b644be617f Enable wrapper validation by default
- Add 'allow-snapshot-wrappers' input parameter
- Default 'validate-wrappers' to 'true'

Fixes #12
2024-08-01 10:51:02 -06:00
daz
7179909719 Verify wrappers for distribution-snapshots
By slurping the checksum URLs from https://services.gradle.org/distributions-snapshots/
we can include these unpublished wrapper checksums in validation.

Fixes #281
2024-07-31 21:26:55 -06:00
daz
c01aea0cb4 Introduce cheerio for fast HTML querying 2024-07-31 21:26:55 -06:00
bigdaz
479297d73e [bot] Update dist directory 2024-08-01 03:26:19 +00:00
daz
fe594a580d Group cache-cleanup log messages for clarity 2024-07-31 21:25:22 -06:00
daz
53f2a5657b Add newline to args message 2024-07-31 13:22:03 -06:00
bigdaz
fd87365911 [bot] Update dist directory 2024-07-23 02:56:59 +00:00
bot-githubaction
c3f989640d Bump references to Develocity Gradle plugin from 3.17.5 to 3.17.6 2024-07-22 20:56:04 -06:00
64 changed files with 100763 additions and 2306 deletions

View File

@@ -9,6 +9,11 @@ runs:
distribution: 'temurin' distribution: 'temurin'
java-version: 11 java-version: 11
- name: Configure environment
shell: bash
run: |
echo "ALLOWED_GRADLE_WRAPPER_CHECKSUMS=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" >> "$GITHUB_ENV"
# Downloads a 'dist' directory artifact that was uploaded in an earlier 'build-dist' step # Downloads a 'dist' directory artifact that was uploaded in an earlier 'build-dist' step
- name: Download dist - name: Download dist
if: ${{ env.SKIP_DIST != 'true' && !env.ACT }} if: ${{ env.SKIP_DIST != 'true' && !env.ACT }}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,35 @@
name: CI-integ-test-full
on:
workflow_dispatch:
push:
paths:
- 'dist/**'
permissions:
contents: write
concurrency:
group: integ-test-${{ github.ref }}
cancel-in-progress: false
jobs:
caching-integ-tests:
uses: ./.github/workflows/suite-integ-test-caching.yml
concurrency:
group: CI-integ-test-full
cancel-in-progress: false
with:
runner-os: '["ubuntu-latest", "windows-latest", "macos-latest"]'
skip-dist: true
secrets: inherit
other-integ-tests:
uses: ./.github/workflows/suite-integ-test-other.yml
concurrency:
group: CI-integ-test-full
cancel-in-progress: false
with:
runner-os: '["ubuntu-latest", "windows-latest", "macos-latest"]'
skip-dist: true
secrets: inherit

View File

@@ -8,43 +8,18 @@ on:
- 'main' - 'main'
- 'release/**' - 'release/**'
- 'dev/**' # Allow running tests on dev branches without a PR - 'dev/**' # Allow running tests on dev branches without a PR
paths-ignore:
- 'dist/**'
permissions:
contents: write
concurrency: concurrency:
group: integ-tests-${{ github.ref }} group: integ-test-${{ github.ref }}
cancel-in-progress: false cancel-in-progress: false
jobs: jobs:
determine-suite:
runs-on: ubuntu-latest
outputs:
runner-os: ${{ steps.determine-suite.outputs.suite == 'quick' && '["ubuntu-latest"]' || '["ubuntu-latest", "windows-latest", "macos-latest"]' }}
cache-key-prefix: '0' # TODO DAZ Try this again ${{ steps.determine-suite.outputs.suite == 'quick' && '0' || github.run_number }}
suite: ${{ steps.determine-suite.outputs.suite }}
steps:
- name: Determine suite to run
id: determine-suite
run: |
# Always run quick suite if we are not in the core `gradle/actions` repository
# This reduces the load for developers working on 'main' on forks
if [ "${{ github.repository }}" != "gradle/actions" ]; then
echo "Not in core repository: suite=quick"
echo "suite=quick" >> "$GITHUB_OUTPUT"
exit 0
fi
# Run full suite for push trigger with "[bot] Update dist directory" commit message
if [ "${{ github.event.head_commit.message }}" == "[bot] Update dist directory" ]; then
echo "Bot commit to main branch: suite=full"
echo "suite=full" >> "$GITHUB_OUTPUT"
exit 0
fi
# Run quick suite for everything else
echo "Everything else: suite=quick"
echo "suite=quick" >> "$GITHUB_OUTPUT"
build-distribution: build-distribution:
needs: [determine-suite]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -53,150 +28,16 @@ jobs:
if: ${{ needs.determine-suite.outputs.suite != 'full' }} if: ${{ needs.determine-suite.outputs.suite != 'full' }}
uses: ./.github/actions/build-dist uses: ./.github/actions/build-dist
build-scan-publish: caching-integ-tests:
needs: [determine-suite, build-distribution] needs: build-distribution
uses: ./.github/workflows/integ-test-build-scan-publish.yml uses: ./.github/workflows/suite-integ-test-caching.yml
with: with:
runner-os: '${{ needs.determine-suite.outputs.runner-os }}' skip-dist: false
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-' secrets: inherit
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
cache-cleanup: other-integ-tests:
needs: [determine-suite, build-distribution] needs: build-distribution
uses: ./.github/workflows/integ-test-cache-cleanup.yml uses: ./.github/workflows/suite-integ-test-other.yml
with: with:
runner-os: '${{ needs.determine-suite.outputs.runner-os }}' skip-dist: false
cache-key-prefix: '${{ needs.determine-suite.outputs.suite}}-${{github.run_number}}-' # Requires a fresh cache entry each run secrets: inherit
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
caching-config:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-caching-config.yml
with:
runner-os: '${{ needs.determine-suite.outputs.runner-os }}'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
dependency-graph:
if: ${{ ! github.event.pull_request.head.repo.fork }}
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-dependency-graph.yml
permissions:
contents: write
with:
runner-os: '${{ needs.determine-suite.outputs.runner-os }}'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
dependency-submission:
if: ${{ ! github.event.pull_request.head.repo.fork }}
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-dependency-submission.yml
permissions:
contents: write
with:
runner-os: '${{ needs.determine-suite.outputs.runner-os }}'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
dependency-submission-failures:
if: ${{ ! github.event.pull_request.head.repo.fork }}
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-dependency-submission-failures.yml
permissions:
contents: write
with:
runner-os: '${{ needs.determine-suite.outputs.runner-os }}'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
develocity-injection:
if: ${{ ! github.event.pull_request.head.repo.fork }}
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-inject-develocity.yml
with:
runner-os: '["ubuntu-latest"]'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
secrets:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DV_SOLUTIONS_ACCESS_KEY }}
provision-gradle-versions:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-provision-gradle-versions.yml
with:
runner-os: '["ubuntu-latest"]'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
restore-configuration-cache:
if: ${{ ! github.event.pull_request.head.repo.fork }}
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
with:
runner-os: '["ubuntu-latest"]'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
secrets:
GRADLE_ENCRYPTION_KEY: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
restore-containerized-gradle-home:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-restore-containerized-gradle-home.yml
with:
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
restore-custom-gradle-home:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-restore-custom-gradle-home.yml
with:
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
restore-gradle-home:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-restore-gradle-home.yml
with:
runner-os: '["ubuntu-latest"]'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
restore-java-toolchain:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-restore-java-toolchain.yml
with:
runner-os: '["ubuntu-latest"]'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
sample-kotlin-dsl:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-sample-kotlin-dsl.yml
with:
runner-os: '["ubuntu-latest"]'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
sample-gradle-plugin:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-sample-gradle-plugin.yml
with:
runner-os: '["ubuntu-latest"]'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
toolchain-detection:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-detect-java-toolchains.yml
with:
runner-os: '["ubuntu-latest"]'
cache-key-prefix: '${{ needs.determine-suite.outputs.cache-key-prefix }}-'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}
wrapper-validation:
needs: [determine-suite, build-distribution]
uses: ./.github/workflows/integ-test-wrapper-validation.yml
with:
runner-os: '["ubuntu-latest"]'
skip-dist: ${{ needs.determine-suite.outputs.suite == 'full' }}

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false

View File

@@ -5,19 +5,21 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
env: env:
SKIP_DIST: ${{ inputs.skip-dist }} SKIP_DIST: ${{ inputs.skip-dist }}
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: cache-cleanup-${{ inputs.cache-key-prefix }} # Requires a fresh cache entry each run
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: cache-cleanup-${{ inputs.cache-key-prefix }}-${{github.run_number}}
jobs: jobs:
full-build: cache-cleanup-full-build:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -38,8 +40,8 @@ jobs:
run: ./gradlew --no-daemon --build-cache -Dcommons_math3_version="3.1" build run: ./gradlew --no-daemon --build-cache -Dcommons_math3_version="3.1" build
# Second build will use the cache from the first build, but cleanup should remove unused artifacts # Second build will use the cache from the first build, but cleanup should remove unused artifacts
assemble-build: cache-cleanup-assemble-build:
needs: full-build needs: cache-cleanup-full-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -60,8 +62,8 @@ jobs:
working-directory: sources/test/jest/resources/cache-cleanup working-directory: sources/test/jest/resources/cache-cleanup
run: ./gradlew --no-daemon --build-cache -Dcommons_math3_version="3.1.1" build run: ./gradlew --no-daemon --build-cache -Dcommons_math3_version="3.1.1" build
check-clean-cache: cache-cleanup-check-clean-cache:
needs: assemble-build needs: cache-cleanup-assemble-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -17,7 +18,7 @@ env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: caching-config-${{ inputs.cache-key-prefix }} GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: caching-config-${{ inputs.cache-key-prefix }}
jobs: jobs:
seed-build: caching-config-seed-build:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -46,8 +47,8 @@ jobs:
run: ./gradlew test run: ./gradlew test
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline # Test that the gradle-user-home cache will cache dependencies, by running build with --offline
verify-build: caching-config-verify-build:
needs: seed-build needs: caching-config-seed-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -75,7 +76,7 @@ jobs:
run: ./gradlew test --offline run: ./gradlew test --offline
# Test that build scans are captured when caching is explicitly disabled # Test that build scans are captured when caching is explicitly disabled
cache-disabled: caching-config-cache-disabled:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -103,7 +104,7 @@ jobs:
core.setFailed('No Build Scan detected') core.setFailed('No Build Scan detected')
# Test that build scans are captured when caching is disabled because Gradle User Home already exists # Test that build scans are captured when caching is disabled because Gradle User Home already exists
cache-disabled-pre-existing-gradle-home: caching-config-cache-disabled-pre-existing-gradle-home:
runs-on: ubuntu-latest # This test only runs on Ubuntu runs-on: ubuntu-latest # This test only runs on Ubuntu
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -127,9 +128,9 @@ jobs:
core.setFailed('No Build Scan detected') core.setFailed('No Build Scan detected')
# Test seed the cache with cache-write-only and verify with cache-read-only # Test seed the cache with cache-write-only and verify with cache-read-only
seed-build-write-only: caching-config-seed-write-only:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{ inputs.cache-key-prefix }}-write-only- GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: caching-config-write-only-${{ inputs.cache-key-prefix }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -149,10 +150,10 @@ jobs:
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: ./gradlew test run: ./gradlew test
verify-write-only-build: caching-config-verify-write-only:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: ${{ inputs.cache-key-prefix }}-write-only- GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: caching-config-write-only-${{ inputs.cache-key-prefix }}
needs: seed-build-write-only needs: caching-config-seed-write-only
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -21,7 +22,7 @@ env:
GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository
jobs: jobs:
groovy-upload: dependency-graph-groovy-upload:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -41,8 +42,8 @@ jobs:
run: ./gradlew build run: ./gradlew build
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
groovy-submit: dependency-graph-groovy-submit:
needs: [groovy-upload] needs: [dependency-graph-groovy-upload]
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -57,7 +58,7 @@ jobs:
env: env:
DEPENDENCY_GRAPH_DOWNLOAD_ARTIFACT_NAME: groovy-upload DEPENDENCY_GRAPH_DOWNLOAD_ARTIFACT_NAME: groovy-upload
kotlin-generate-and-submit: dependency-graph-kotlin-generate-and-submit:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -77,7 +78,7 @@ jobs:
run: ./gradlew build run: ./gradlew build
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
multiple-builds: dependency-graph-multiple-builds:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -122,7 +123,7 @@ jobs:
exit 1 exit 1
fi fi
config-cache: dependency-graph-config-cache:
runs-on: ubuntu-latest # Test is not compatible with Windows runs-on: ubuntu-latest # Test is not compatible with Windows
steps: steps:
- name: Checkout sources - name: Checkout sources

View File

@@ -5,6 +5,7 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest"]' default: '["ubuntu-latest"]'
@@ -18,7 +19,7 @@ env:
GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository
jobs: jobs:
failing-build: dependency-submission-failures-failing-build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -47,7 +48,7 @@ jobs:
exit 1 exit 1
fi fi
unsupported-gradle-version: dependency-submission-failures-unsupported-gradle-version:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -76,7 +77,7 @@ jobs:
exit 1 exit 1
fi fi
insufficient-permissions: dependency-submission-failures-insufficient-permissions:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: read

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -21,7 +22,7 @@ env:
GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository GITHUB_DEPENDENCY_GRAPH_REF: 'refs/tags/v0.0.1' # Use a different ref to avoid updating the real dependency graph for the repository
jobs: jobs:
groovy-generate-and-upload: dependency-submission-groovy-generate-and-upload:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -42,8 +43,8 @@ jobs:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: groovy-dependency-submission GRADLE_BUILD_ACTION_CACHE_KEY_JOB: groovy-dependency-submission
groovy-restore-cache: dependency-submission-groovy-restore-cache:
needs: [groovy-generate-and-upload] needs: [dependency-submission-groovy-generate-and-upload]
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -63,8 +64,8 @@ jobs:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: groovy-dependency-submission GRADLE_BUILD_ACTION_CACHE_KEY_JOB: groovy-dependency-submission
groovy-download-and-submit: dependency-submission-groovy-download-and-submit:
needs: [groovy-generate-and-upload] needs: [dependency-submission-groovy-generate-and-upload]
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -83,7 +84,7 @@ jobs:
env: env:
DEPENDENCY_GRAPH_DOWNLOAD_ARTIFACT_NAME: groovy-generate-and-upload-${{ matrix.os }} DEPENDENCY_GRAPH_DOWNLOAD_ARTIFACT_NAME: groovy-generate-and-upload-${{ matrix.os }}
kotlin-generate-and-submit: dependency-submission-kotlin-generate-and-submit:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -100,7 +101,7 @@ jobs:
with: with:
build-root-directory: .github/workflow-samples/kotlin-dsl build-root-directory: .github/workflow-samples/kotlin-dsl
multiple-builds: dependency-submission-multiple-builds:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -145,7 +146,7 @@ jobs:
exit 1 exit 1
fi fi
multiple-builds-upload: dependency-submission-multiple-builds-upload:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -168,7 +169,7 @@ jobs:
dependency-graph: generate-and-upload dependency-graph: generate-and-upload
build-root-directory: .github/workflow-samples/groovy-dsl build-root-directory: .github/workflow-samples/groovy-dsl
config-cache: dependency-submission-config-cache:
runs-on: ubuntu-latest # Test is not compatible with Windows runs-on: ubuntu-latest # Test is not compatible with Windows
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -203,7 +204,7 @@ jobs:
exit 1 exit 1
fi fi
gradle-versions: dependency-submission-gradle-versions:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -227,7 +228,7 @@ jobs:
gradle-version: ${{ matrix.gradle }} gradle-version: ${{ matrix.gradle }}
build-root-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }} build-root-directory: .github/workflow-samples/no-wrapper${{ matrix.build-root-suffix }}
with-setup-gradle: dependency-submission-with-setup-gradle:
runs-on: ubuntu-latest # Test is not compatible with Windows runs-on: ubuntu-latest # Test is not compatible with Windows
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -262,7 +263,7 @@ jobs:
exit 1 exit 1
fi fi
with-includes-and-excludes: dependency-submission-with-includes-and-excludes:
runs-on: ubuntu-latest # Test is not compatible with Windows runs-on: ubuntu-latest # Test is not compatible with Windows
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -296,7 +297,7 @@ jobs:
fi fi
custom-report-dir-submit: dependency-submission-custom-report-dir-submit:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -330,7 +331,7 @@ jobs:
exit 1 exit 1
fi fi
custom-report-dir-upload: dependency-submission-custom-report-dir-upload:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -347,7 +348,7 @@ jobs:
build-root-directory: .github/workflow-samples/groovy-dsl build-root-directory: .github/workflow-samples/groovy-dsl
custom-report-dir-download-and-submit: custom-report-dir-download-and-submit:
needs: custom-report-dir-upload needs: [dependency-submission-custom-report-dir-upload]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -18,7 +19,7 @@ env:
jobs: jobs:
# Test that pre-installed runner JDKs are detected # Test that pre-installed runner JDKs are detected
pre-installed-toolchains: detect-toolchains-pre-installed-jdks:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -48,7 +49,7 @@ jobs:
grep -q 'Eclipse Temurin JDK 21' output.txt || (echo "::error::Did not detect preinstalled JDK 21" && exit 1) grep -q 'Eclipse Temurin JDK 21' output.txt || (echo "::error::Did not detect preinstalled JDK 21" && exit 1)
# Test that JDKs provisioned by setup-java are detected # Test that JDKs provisioned by setup-java are detected
setup-java-installed-toolchain: detect-toolchains-setup-java-jdks:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -32,11 +33,11 @@ jobs:
matrix: matrix:
gradle: [current, 7.6.2, 6.9.4, 5.6.4] gradle: [current, 7.6.2, 6.9.4, 5.6.4]
os: ${{fromJSON(inputs.runner-os)}} os: ${{fromJSON(inputs.runner-os)}}
plugin-version: [3.16.2, 3.17.5] plugin-version: [3.16.2, 3.17.6]
include: include:
- plugin-version: 3.16.2 - plugin-version: 3.16.2
accessKeyEnv: GRADLE_ENTERPRISE_ACCESS_KEY accessKeyEnv: GRADLE_ENTERPRISE_ACCESS_KEY
- plugin-version: 3.17.5 - plugin-version: 3.17.6
accessKeyEnv: DEVELOCITY_ACCESS_KEY accessKeyEnv: DEVELOCITY_ACCESS_KEY
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@@ -83,7 +84,7 @@ jobs:
matrix: matrix:
gradle: [current, 7.6.2, 6.9.4, 5.6.4] gradle: [current, 7.6.2, 6.9.4, 5.6.4]
os: ${{fromJSON(inputs.runner-os)}} os: ${{fromJSON(inputs.runner-os)}}
plugin-version: [3.16.2, 3.17.5] plugin-version: [3.16.2, 3.17.6]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -132,7 +133,7 @@ jobs:
matrix: matrix:
gradle: [ current, 7.6.2, 6.9.4, 5.6.4 ] gradle: [ current, 7.6.2, 6.9.4, 5.6.4 ]
os: ${{fromJSON(inputs.runner-os)}} os: ${{fromJSON(inputs.runner-os)}}
plugin-version: [ 3.16.2, 3.17.5 ] plugin-version: [ 3.16.2, 3.17.6 ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -168,7 +169,7 @@ jobs:
matrix: matrix:
gradle: [ current, 7.6.2, 6.9.4, 5.6.4 ] gradle: [ current, 7.6.2, 6.9.4, 5.6.4 ]
os: ${{fromJSON(inputs.runner-os)}} os: ${{fromJSON(inputs.runner-os)}}
plugin-version: [ 3.16.2, 3.17.5 ] plugin-version: [ 3.16.2, 3.17.6 ]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout sources - name: Checkout sources

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -69,7 +70,7 @@ jobs:
script: | script: |
core.setFailed('Gradle version parameter not set correctly: value was "${{ steps.gradle-current.outputs.gradle-version }}"') core.setFailed('Gradle version parameter not set correctly: value was "${{ steps.gradle-current.outputs.gradle-version }}"')
gradle-versions: provision-gradle-version:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -20,7 +21,7 @@ env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-configuration-cache-${{ inputs.cache-key-prefix }} GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-configuration-cache-${{ inputs.cache-key-prefix }}
jobs: jobs:
seed-build-groovy: restore-cc-seed-build-groovy:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy
strategy: strategy:
@@ -50,11 +51,11 @@ jobs:
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: gradle test --configuration-cache run: gradle test --configuration-cache
verify-build-groovy: restore-cc-verify-build-groovy:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy
GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_1 GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_1
needs: seed-build-groovy needs: restore-cc-seed-build-groovy
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -91,11 +92,11 @@ jobs:
fi fi
# Ensure that cache-cleanup doesn't remove all necessary files # Ensure that cache-cleanup doesn't remove all necessary files
verify-no-cache-cleanup-groovy: restore-cc-verify-no-cache-cleanup-groovy:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy
GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_2 GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_2
needs: verify-build-groovy needs: restore-cc-verify-build-groovy
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -131,11 +132,11 @@ jobs:
fi fi
# Check that the build can run when no extracted cache entries are restored # Check that the build can run when no extracted cache entries are restored
gradle-user-home-not-fully-restored: restore-cc-gradle-user-home-not-fully-restored:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-groovy
GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_x GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_x
needs: seed-build-groovy needs: restore-cc-seed-build-groovy
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -164,7 +165,7 @@ jobs:
working-directory: .github/workflow-samples/groovy-dsl working-directory: .github/workflow-samples/groovy-dsl
run: gradle test --configuration-cache run: gradle test --configuration-cache
seed-build-kotlin: restore-cc-seed-build-kotlin:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-kotlin GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-kotlin
strategy: strategy:
@@ -194,11 +195,11 @@ jobs:
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
run: gradle help --configuration-cache run: gradle help --configuration-cache
modify-build-kotlin: restore-cc-modify-build-kotlin:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-kotlin GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-kotlin
GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_1 GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_1
needs: seed-build-kotlin needs: restore-cc-seed-build-kotlin
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -226,11 +227,11 @@ jobs:
run: gradle test --configuration-cache run: gradle test --configuration-cache
# Test restore configuration-cache from the third build invocation # Test restore configuration-cache from the third build invocation
verify-build-kotlin: restore-cc-verify-build-kotlin:
env: env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-kotlin GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-cc-kotlin
GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_2 GRADLE_BUILD_ACTION_CACHE_KEY_JOB_EXECUTION: ${{github.sha}}_2
needs: modify-build-kotlin needs: restore-cc-modify-build-kotlin
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@@ -5,6 +5,7 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -14,7 +15,7 @@ env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-containerized-gradle-home-${{ inputs.cache-key-prefix }} GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-containerized-gradle-home-${{ inputs.cache-key-prefix }}
jobs: jobs:
seed-build: restore-containerized-seed-build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: fedora:latest container: fedora:latest
steps: steps:
@@ -32,8 +33,8 @@ jobs:
run: ./gradlew test run: ./gradlew test
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline # Test that the gradle-user-home cache will cache dependencies, by running build with --offline
dependencies-cache: restore-containerized-dependencies-cache:
needs: seed-build needs: restore-containerized-seed-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: fedora:latest container: fedora:latest
steps: steps:

View File

@@ -5,6 +5,7 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -14,7 +15,7 @@ env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-custom-gradle-home-${{ inputs.cache-key-prefix }} GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-custom-gradle-home-${{ inputs.cache-key-prefix }}
jobs: jobs:
seed-build: restore-custom-gradle-home-seed-build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -35,8 +36,8 @@ jobs:
run: ./gradlew test --info run: ./gradlew test --info
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline # Test that the gradle-user-home cache will cache dependencies, by running build with --offline
dependencies-cache: restore-custom-gradle-home-dependencies-cache:
needs: seed-build needs: restore-custom-gradle-home-seed-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -57,8 +58,8 @@ jobs:
run: ./gradlew test --offline --info run: ./gradlew test --offline --info
# Test that the gradle-user-home cache will cache and restore local build-cache # Test that the gradle-user-home cache will cache and restore local build-cache
build-cache: restore-custom-gradle-home-build-cache:
needs: seed-build needs: restore-custom-gradle-home-seed-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -18,7 +19,7 @@ env:
GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-gradle-home GRADLE_BUILD_ACTION_CACHE_KEY_JOB: restore-gradle-home
jobs: jobs:
seed-build: restore-gradle-home-seed-build:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -39,8 +40,8 @@ jobs:
run: ./gradlew test run: ./gradlew test
# Test that the gradle-user-home cache will cache dependencies, by running build with --offline # Test that the gradle-user-home cache will cache dependencies, by running build with --offline
dependencies-cache: restore-gradle-home-dependencies-cache:
needs: seed-build needs: restore-gradle-home-seed-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -61,8 +62,8 @@ jobs:
run: ./gradlew test --offline run: ./gradlew test --offline
# Test that the gradle-user-home cache will cache and restore local build-cache # Test that the gradle-user-home cache will cache and restore local build-cache
build-cache: restore-gradle-home-build-cache:
needs: seed-build needs: restore-gradle-home-seed-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -83,8 +84,8 @@ jobs:
run: ./gradlew test -DverifyCachedBuild=true run: ./gradlew test -DverifyCachedBuild=true
# Check that the build can run when Gradle User Home is not fully restored # Check that the build can run when Gradle User Home is not fully restored
no-extracted-cache-entries-restored: restore-gradle-home-no-extracted-cache-entries-restored:
needs: seed-build needs: restore-gradle-home-seed-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -107,8 +108,8 @@ jobs:
run: ./gradlew test run: ./gradlew test
# Test that a pre-existing gradle-user-home can be overwritten by the restored cache # Test that a pre-existing gradle-user-home can be overwritten by the restored cache
pre-existing-gradle-home: restore-gradle-home-pre-existing-gradle-home:
needs: seed-build needs: restore-gradle-home-seed-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -17,7 +18,7 @@ env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-java-toolchain-${{ inputs.cache-key-prefix }} GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: restore-java-toolchain-${{ inputs.cache-key-prefix }}
jobs: jobs:
seed-build: restore-java-toolchain-seed-build:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -38,8 +39,8 @@ jobs:
run: ./gradlew test --info run: ./gradlew test --info
# Test that the gradle-user-home cache will cache the toolchain, by running build with --offline # Test that the gradle-user-home cache will cache the toolchain, by running build with --offline
toolchain-cache: restore-java-toolchain-verify-build:
needs: seed-build needs: restore-java-toolchain-seed-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -17,7 +18,7 @@ env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: sample-gradle-plugin-${{ inputs.cache-key-prefix }} GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: sample-gradle-plugin-${{ inputs.cache-key-prefix }}
jobs: jobs:
seed-build: sample-gradle-plugin-seed-build:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -37,8 +38,8 @@ jobs:
working-directory: .github/workflow-samples/gradle-plugin working-directory: .github/workflow-samples/gradle-plugin
run: ./gradlew build run: ./gradlew build
verify-build: sample-gradle-plugin-verify-build:
needs: seed-build needs: sample-gradle-plugin-seed-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@@ -5,9 +5,10 @@ on:
inputs: inputs:
cache-key-prefix: cache-key-prefix:
type: string type: string
default: '0'
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -17,7 +18,7 @@ env:
GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: sample-kotlin-dsl-${{ inputs.cache-key-prefix }} GRADLE_BUILD_ACTION_CACHE_KEY_PREFIX: sample-kotlin-dsl-${{ inputs.cache-key-prefix }}
jobs: jobs:
seed-build: sample-kotlin-dsl-seed-build:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -37,8 +38,8 @@ jobs:
working-directory: .github/workflow-samples/kotlin-dsl working-directory: .github/workflow-samples/kotlin-dsl
run: ./gradlew build run: ./gradlew build
verify-build: sample-kotlin-dsl-verify-build:
needs: seed-build needs: sample-kotlin-dsl-seed-build
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@@ -5,7 +5,7 @@ on:
inputs: inputs:
runner-os: runner-os:
type: string type: string
default: '["ubuntu-latest", "windows-latest", "macos-latest"]' default: '["ubuntu-latest"]'
skip-dist: skip-dist:
type: boolean type: boolean
default: false default: false
@@ -14,7 +14,7 @@ env:
SKIP_DIST: ${{ inputs.skip-dist }} SKIP_DIST: ${{ inputs.skip-dist }}
jobs: jobs:
test-setup-gradle-validation: wrapper-validation-setup-gradle:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -29,18 +29,19 @@ jobs:
- name: Run wrapper-validation-action - name: Run wrapper-validation-action
id: setup-gradle id: setup-gradle
uses: ./setup-gradle uses: ./setup-gradle
with: env:
validate-wrappers: true ALLOWED_GRADLE_WRAPPER_CHECKSUMS: ''
continue-on-error: true continue-on-error: true
- name: Check failure - name: Check failure
shell: bash
run: | run: |
if [ "${{ steps.setup-gradle.outcome}}" != "failure" ] ; then if [ "${{ steps.setup-gradle.outcome}}" != "failure" ] ; then
echo "Expected validation to fail, but it didn't" echo "Expected validation to fail, but it didn't"
exit 1 exit 1
fi fi
test-validation-success: wrapper-validation-success:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -54,6 +55,7 @@ jobs:
with: with:
# to allow the invalid wrapper jar present in test data # to allow the invalid wrapper jar present in test data
allow-checksums: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 allow-checksums: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
min-wrapper-count: 10
- name: Check outcome - name: Check outcome
env: env:
@@ -61,13 +63,14 @@ jobs:
# below to not accidentally inject code into shell script or break its syntax # below to not accidentally inject code into shell script or break its syntax
FAILED_WRAPPERS: ${{ steps.action-test.outputs.failed-wrapper }} FAILED_WRAPPERS: ${{ steps.action-test.outputs.failed-wrapper }}
FAILED_WRAPPERS_MATCHES: ${{ steps.action-test.outputs.failed-wrapper == '' }} FAILED_WRAPPERS_MATCHES: ${{ steps.action-test.outputs.failed-wrapper == '' }}
shell: bash
run: | run: |
if [ "$FAILED_WRAPPERS_MATCHES" != "true" ] ; then if [ "$FAILED_WRAPPERS_MATCHES" != "true" ] ; then
echo "'outputs.failed-wrapper' has unexpected content: $FAILED_WRAPPERS" echo "'outputs.failed-wrapper' has unexpected content: $FAILED_WRAPPERS"
exit 1 exit 1
fi fi
test-validation-error: wrapper-validation-error:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout sources - name: Checkout sources
@@ -88,6 +91,7 @@ jobs:
VALIDATION_FAILED: ${{ steps.action-test.outcome == 'failure' }} VALIDATION_FAILED: ${{ steps.action-test.outcome == 'failure' }}
FAILED_WRAPPERS: ${{ steps.action-test.outputs.failed-wrapper }} FAILED_WRAPPERS: ${{ steps.action-test.outputs.failed-wrapper }}
FAILED_WRAPPERS_MATCHES: ${{ steps.action-test.outputs.failed-wrapper == 'sources/test/jest/wrapper-validation/data/invalid/gradle-wrapper.jar|sources/test/jest/wrapper-validation/data/invalid/gradlе-wrapper.jar' }} FAILED_WRAPPERS_MATCHES: ${{ steps.action-test.outputs.failed-wrapper == 'sources/test/jest/wrapper-validation/data/invalid/gradle-wrapper.jar|sources/test/jest/wrapper-validation/data/invalid/gradlе-wrapper.jar' }}
shell: bash
run: | run: |
if [ "$VALIDATION_FAILED" != "true" ] ; then if [ "$VALIDATION_FAILED" != "true" ] ; then
echo "Expected validation to fail, but it didn't" echo "Expected validation to fail, but it didn't"
@@ -98,3 +102,64 @@ jobs:
echo "'outputs.failed-wrapper' has unexpected content: $FAILED_WRAPPERS" echo "'outputs.failed-wrapper' has unexpected content: $FAILED_WRAPPERS"
exit 1 exit 1
fi fi
wrapper-validation-minimum-wrapper-count:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- name: Run wrapper-validation-action
id: action-test
uses: ./wrapper-validation
with:
# to allow the invalid wrapper jar present in test data
allow-checksums: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
min-wrapper-count: 11
# Expected to fail; validated below
continue-on-error: true
- name: Check outcome
env:
# Evaluate workflow expressions here as env variable values instead of inside shell script
# below to not accidentally inject code into shell script or break its syntax
VALIDATION_FAILED: ${{ steps.action-test.outcome == 'failure' }}
shell: bash
run: |
if [ "$VALIDATION_FAILED" != "true" ] ; then
echo "Expected validation to fail, but it didn't"
exit 1
fi
wrapper-validation-zero-wrappers:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4 # Checkout the repository with no wrappers
with:
sparse-checkout: |
.github/actions
dist
wrapper-validation
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- name: Run wrapper-validation-action
id: action-test
uses: ./wrapper-validation
# Expected to fail; validated below
continue-on-error: true
- name: Check outcome
env:
# Evaluate workflow expressions here as env variable values instead of inside shell script
# below to not accidentally inject code into shell script or break its syntax
VALIDATION_FAILED: ${{ steps.action-test.outcome == 'failure' }}
shell: bash
run: |
if [ "$VALIDATION_FAILED" != "true" ] ; then
echo "Expected validation to fail, but it didn't"
exit 1
fi

View File

@@ -0,0 +1,52 @@
name: suite-integ-test-caching
on:
workflow_call:
inputs:
runner-os:
type: string
default: '["ubuntu-latest"]'
skip-dist:
type: boolean
default: false
jobs:
cache-cleanup:
uses: ./.github/workflows/integ-test-cache-cleanup.yml
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}
caching-config:
uses: ./.github/workflows/integ-test-caching-config.yml
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}
restore-configuration-cache:
if: ${{ ! github.event.pull_request.head.repo.fork }}
uses: ./.github/workflows/integ-test-restore-configuration-cache.yml
with:
skip-dist: ${{ inputs.skip-dist }}
secrets:
GRADLE_ENCRYPTION_KEY: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
restore-containerized-gradle-home:
uses: ./.github/workflows/integ-test-restore-containerized-gradle-home.yml
with:
skip-dist: ${{ inputs.skip-dist }}
restore-custom-gradle-home:
uses: ./.github/workflows/integ-test-restore-custom-gradle-home.yml
with:
skip-dist: ${{ inputs.skip-dist }}
restore-gradle-home:
uses: ./.github/workflows/integ-test-restore-gradle-home.yml
with:
skip-dist: ${{ inputs.skip-dist }}
restore-java-toolchain:
uses: ./.github/workflows/integ-test-restore-java-toolchain.yml
with:
skip-dist: ${{ inputs.skip-dist }}

View File

@@ -0,0 +1,82 @@
name: suite-integ-test-other
on:
workflow_call:
inputs:
runner-os:
type: string
default: '["ubuntu-latest"]'
skip-dist:
type: boolean
default: false
jobs:
build-scan-publish:
uses: ./.github/workflows/integ-test-build-scan-publish.yml
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}
dependency-graph:
if: ${{ ! github.event.pull_request.head.repo.fork }}
uses: ./.github/workflows/integ-test-dependency-graph.yml
permissions:
contents: write
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}
dependency-submission:
if: ${{ ! github.event.pull_request.head.repo.fork }}
uses: ./.github/workflows/integ-test-dependency-submission.yml
permissions:
contents: write
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}
dependency-submission-failures:
if: ${{ ! github.event.pull_request.head.repo.fork }}
uses: ./.github/workflows/integ-test-dependency-submission-failures.yml
permissions:
contents: write
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}
develocity-injection:
if: ${{ ! github.event.pull_request.head.repo.fork }}
uses: ./.github/workflows/integ-test-inject-develocity.yml
with:
skip-dist: ${{ inputs.skip-dist }}
secrets:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DV_SOLUTIONS_ACCESS_KEY }}
provision-gradle-versions:
uses: ./.github/workflows/integ-test-provision-gradle-versions.yml
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}
sample-kotlin-dsl:
uses: ./.github/workflows/integ-test-sample-kotlin-dsl.yml
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}
sample-gradle-plugin:
uses: ./.github/workflows/integ-test-sample-gradle-plugin.yml
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}
toolchain-detection:
uses: ./.github/workflows/integ-test-detect-toolchains.yml
with:
skip-dist: ${{ inputs.skip-dist }}
wrapper-validation:
uses: ./.github/workflows/integ-test-wrapper-validation.yml
with:
runner-os: '${{ inputs.runner-os }}'
skip-dist: ${{ inputs.skip-dist }}

View File

@@ -172,6 +172,21 @@ inputs:
description: The Develocity short-lived access tokens expiry in hours. Default is 2 hours. description: The Develocity short-lived access tokens expiry in hours. Default is 2 hours.
required: false required: false
# Wrapper validation configuration
validate-wrappers:
description: |
When 'true' the action will automatically validate all wrapper jars found in the repository.
If the wrapper checksums are not valid, the action will fail.
required: false
default: false
allow-snapshot-wrappers:
description: |
When 'true', wrapper validation will include the checksums of snapshot wrapper jars.
Use this if you are running with nightly or snapshot versions of the Gradle wrapper.
required: false
default: false
# DEPRECATED ACTION INPUTS # DEPRECATED ACTION INPUTS
# EXPERIMENTAL ACTION INPUTS # EXPERIMENTAL ACTION INPUTS

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -515,14 +515,30 @@ Since Gradle applies init scripts in alphabetical order, one way to ensure this
## Gradle Wrapper validation ## Gradle Wrapper validation
Instead of using the [wrapper-validation action](./wrapper-validation.md) separately, you can enable By default, this action will perform the same wrapper validation as is performed by the dedicated
wrapper validation directly in your Setup Gradle step. [wrapper-validation action](./wrapper-validation.md).
This means that invalid wrapper jars will be automatically detected when using `setup-gradle`.
If you do not want wrapper-validation to occur automatically, you can disable it:
```yaml
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
validate-wrappers: false
```
If your repository uses snapshot versions of the Gradle wrapper, such as nightly builds, then you'll need to
explicitly allow snapshot wrappers in wrapper validation.
These are not allowed by default.
```yaml ```yaml
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:
validate-wrappers: true validate-wrappers: true
allow-snapshot-wrappers: true
``` ```
If you need more advanced configuration, then you're advised to continue using a separate workflow step If you need more advanced configuration, then you're advised to continue using a separate workflow step
@@ -733,7 +749,7 @@ Here's a minimal example:
run: ./gradlew build run: ./gradlew build
``` ```
This configuration will automatically apply `v3.17.5` of the [Develocity Gradle plugin](https://docs.gradle.com/develocity/gradle-plugin/), and publish build scans to https://develocity.your-server.com. This configuration will automatically apply `v3.17.6` of the [Develocity Gradle plugin](https://docs.gradle.com/develocity/gradle-plugin/), and publish build scans to https://develocity.your-server.com.
This example assumes that the `develocity.your-server.com` server allows anonymous publishing of build scans. This example assumes that the `develocity.your-server.com` server allows anonymous publishing of build scans.
In the likely scenario that your Develocity server requires authentication, you will also need to pass a valid [Develocity access key](https://docs.gradle.com/develocity/gradle-plugin/#via_environment_variable) taken from a secret: In the likely scenario that your Develocity server requires authentication, you will also need to pass a valid [Develocity access key](https://docs.gradle.com/develocity/gradle-plugin/#via_environment_variable) taken from a secret:
@@ -805,7 +821,7 @@ Here's an example using the env vars:
env: env:
DEVELOCITY_INJECTION_ENABLED: true DEVELOCITY_INJECTION_ENABLED: true
DEVELOCITY_URL: https://develocity.your-server.com DEVELOCITY_URL: https://develocity.your-server.com
DEVELOCITY_PLUGIN_VERSION: 3.17.5 DEVELOCITY_PLUGIN_VERSION: 3.17.6
``` ```
## Publishing to scans.gradle.com ## Publishing to scans.gradle.com

View File

@@ -4,6 +4,9 @@ This action validates the checksums of _all_ [Gradle Wrapper](https://docs.gradl
The action should be run in the root of the repository, as it will recursively search for any files named `gradle-wrapper.jar`. The action should be run in the root of the repository, as it will recursively search for any files named `gradle-wrapper.jar`.
The `setup-gradle` action will perform wrapper validation on each execution. If you are using `setup-gradle` in your
workflows, it is unlikely that you will need to use this action.
## The Gradle Wrapper Problem in Open Source ## The Gradle Wrapper Problem in Open Source
The `gradle-wrapper.jar` is a binary blob of executable code that is checked into nearly The `gradle-wrapper.jar` is a binary blob of executable code that is checked into nearly
@@ -90,18 +93,22 @@ We recommend the message commit contents of:
From there, you can easily follow the rest of the prompts to create a Pull Request against the project. From there, you can easily follow the rest of the prompts to create a Pull Request against the project.
## Reporting Failures ## Validation Failures
If this GitHub action fails because a `gradle-wrapper.jar` doesn't match one of our published SHA-256 checksums, A wrapper jar can fail validation for a few reasons:
1. The wrapper is from a snapshot build of Gradle (nightly or release nightly) and you have not set `allow-snapshots`
or `allow-snapshot-wrappers` to `true`.
2. The wrapper jar is from a version of Gradle with an unverifiable wrapper jar (see below).
3. The wrapper jar was not published by Gradle, and could be compromised.
If this GitHub action fails because a `gradle-wrapper.jar` was not published by Gradle,
we highly recommend that you reach out to us at [security@gradle.com](mailto:security@gradle.com). we highly recommend that you reach out to us at [security@gradle.com](mailto:security@gradle.com).
**Note:** `gradle-wrapper.jar` generated by Gradle 3.3 to 4.0 are not verifiable because those files were dynamically generated by Gradle in a non-reproducible way. It's not possible to verify the `gradle-wrapper.jar` for those versions are legitimate using a hash comparison. You should try to determine if the `gradle-wrapper.jar` was generated by one of these versions before running the build. #### Unverifiable Wrapper Jars
Wrapper Jars generated by Gradle versions `3.3` to `4.0` are not verifiable because those files were dynamically generated by Gradle in a non-reproducible way. It's not possible to verify the `gradle-wrapper.jar` for those versions are legitimate using a hash comparison. If you have a validation failure, you should try to determine if the `gradle-wrapper.jar` was generated by one of these versions before running the build.
If the Gradle version in `gradle-wrapper.properties` is out of this range, you may need to regenerate the `gradle-wrapper.jar` by running `./gradlew wrapper`. If you need to use a version of Gradle between 3.3 and 4.0, you can use a newer version of Gradle to generate the `gradle-wrapper.jar`. - If the Gradle version in `gradle-wrapper.properties` is outside of this range, you can regenerate the `gradle-wrapper.jar` by running `./gradlew wrapper`. This will generate a new, verifiable wrapper jar.
- If you need to run your build with a version of Gradle between 3.3 and 4.0, you can use a newer version of Gradle to generate the `gradle-wrapper.jar`.
If you're curious and want to explore what the differences are between the `gradle-wrapper.jar` in your possession
and one of our valid release, you can compare them using this online utility: [diffoscope](https://try.diffoscope.org/).
Regardless of what you find, we still kindly request that you reach out to us and let us know.
## Resources ## Resources

View File

@@ -190,9 +190,16 @@ inputs:
# Wrapper validation configuration # Wrapper validation configuration
validate-wrappers: validate-wrappers:
description: | description: |
When 'true', the action will perform the 'wrapper-validation' action automatically. When 'true' (the default) the action will automatically validate all wrapper jars found in the repository.
If the wrapper checksums are not valid, the action will fail. If the wrapper checksums are not valid, the action will fail.
required: false required: false
default: true
allow-snapshot-wrappers:
description: |
When 'true', wrapper validation will include the checksums of snapshot wrapper jars.
Use this if you are running with nightly or snapshot versions of the Gradle wrapper.
required: false
default: false default: false
# DEPRECATED ACTION INPUTS # DEPRECATED ACTION INPUTS

View File

@@ -20,6 +20,7 @@
"@actions/tool-cache": "2.0.1", "@actions/tool-cache": "2.0.1",
"@octokit/rest": "20.1.0", "@octokit/rest": "20.1.0",
"@octokit/webhooks-types": "7.5.0", "@octokit/webhooks-types": "7.5.0",
"cheerio": "^1.0.0-rc.12",
"semver": "7.6.0", "semver": "7.6.0",
"string-argv": "0.3.2", "string-argv": "0.3.2",
"typed-rest-client": "1.8.11", "typed-rest-client": "1.8.11",
@@ -3309,6 +3310,11 @@
"readable-stream": "^3.4.0" "readable-stream": "^3.4.0"
} }
}, },
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
},
"node_modules/bottleneck": { "node_modules/bottleneck": {
"version": "2.19.5", "version": "2.19.5",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
@@ -3526,6 +3532,42 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/cheerio": {
"version": "1.0.0-rc.12",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
"integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
"dependencies": {
"cheerio-select": "^2.1.0",
"dom-serializer": "^2.0.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1",
"htmlparser2": "^8.0.1",
"parse5": "^7.0.0",
"parse5-htmlparser2-tree-adapter": "^7.0.0"
},
"engines": {
"node": ">= 6"
},
"funding": {
"url": "https://github.com/cheeriojs/cheerio?sponsor=1"
}
},
"node_modules/cheerio-select": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
"integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
"dependencies": {
"boolbase": "^1.0.0",
"css-select": "^5.1.0",
"css-what": "^6.1.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/ci-info": { "node_modules/ci-info": {
"version": "3.8.0", "version": "3.8.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
@@ -3723,6 +3765,32 @@
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in." "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in."
}, },
"node_modules/css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
"dependencies": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
"engines": {
"node": ">= 6"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/damerau-levenshtein": { "node_modules/damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@@ -3900,6 +3968,57 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
]
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/dot-object": { "node_modules/dot-object": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/dot-object/-/dot-object-2.1.4.tgz", "resolved": "https://registry.npmjs.org/dot-object/-/dot-object-2.1.4.tgz",
@@ -3944,6 +4063,17 @@
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/error-ex": { "node_modules/error-ex": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -5187,6 +5317,24 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true "dev": true
}, },
"node_modules/htmlparser2": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1",
"entities": "^4.4.0"
}
},
"node_modules/human-signals": { "node_modules/human-signals": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -7060,6 +7208,17 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"dependencies": {
"boolbase": "^1.0.0"
},
"funding": {
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.1", "version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
@@ -7293,6 +7452,29 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/parse5": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
"dependencies": {
"entities": "^4.4.0"
},
"funding": {
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/parse5-htmlparser2-tree-adapter": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
"integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
"dependencies": {
"domhandler": "^5.0.2",
"parse5": "^7.0.0"
},
"funding": {
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/pascal-case": { "node_modules/pascal-case": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
@@ -11649,6 +11831,11 @@
"readable-stream": "^3.4.0" "readable-stream": "^3.4.0"
} }
}, },
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
},
"bottleneck": { "bottleneck": {
"version": "2.19.5", "version": "2.19.5",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
@@ -11790,6 +11977,33 @@
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
"dev": true "dev": true
}, },
"cheerio": {
"version": "1.0.0-rc.12",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
"integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
"requires": {
"cheerio-select": "^2.1.0",
"dom-serializer": "^2.0.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1",
"htmlparser2": "^8.0.1",
"parse5": "^7.0.0",
"parse5-htmlparser2-tree-adapter": "^7.0.0"
}
},
"cheerio-select": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
"integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
"requires": {
"boolbase": "^1.0.0",
"css-select": "^5.1.0",
"css-what": "^6.1.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1"
}
},
"ci-info": { "ci-info": {
"version": "3.8.0", "version": "3.8.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
@@ -11936,6 +12150,23 @@
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==" "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig=="
}, },
"css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
"requires": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
}
},
"css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="
},
"damerau-levenshtein": { "damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@@ -12062,6 +12293,39 @@
"esutils": "^2.0.2" "esutils": "^2.0.2"
} }
}, },
"dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"requires": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
}
},
"domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
},
"domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"requires": {
"domelementtype": "^2.3.0"
}
},
"domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"requires": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
}
},
"dot-object": { "dot-object": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/dot-object/-/dot-object-2.1.4.tgz", "resolved": "https://registry.npmjs.org/dot-object/-/dot-object-2.1.4.tgz",
@@ -12097,6 +12361,11 @@
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
},
"error-ex": { "error-ex": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -13007,6 +13276,17 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true "dev": true
}, },
"htmlparser2": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
"requires": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1",
"entities": "^4.4.0"
}
},
"human-signals": { "human-signals": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -14426,6 +14706,14 @@
"path-key": "^3.0.0" "path-key": "^3.0.0"
} }
}, },
"nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"requires": {
"boolbase": "^1.0.0"
}
},
"object-inspect": { "object-inspect": {
"version": "1.13.1", "version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
@@ -14584,6 +14872,23 @@
"lines-and-columns": "^1.1.6" "lines-and-columns": "^1.1.6"
} }
}, },
"parse5": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
"requires": {
"entities": "^4.4.0"
}
},
"parse5-htmlparser2-tree-adapter": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
"integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
"requires": {
"domhandler": "^5.0.2",
"parse5": "^7.0.0"
}
},
"pascal-case": { "pascal-case": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",

View File

@@ -42,6 +42,7 @@
"@actions/tool-cache": "2.0.1", "@actions/tool-cache": "2.0.1",
"@octokit/rest": "20.1.0", "@octokit/rest": "20.1.0",
"@octokit/webhooks-types": "7.5.0", "@octokit/webhooks-types": "7.5.0",
"cheerio": "^1.0.0-rc.12",
"semver": "7.6.0", "semver": "7.6.0",
"string-argv": "0.3.2", "string-argv": "0.3.2",
"typed-rest-client": "1.8.11", "typed-rest-client": "1.8.11",

View File

@@ -10,7 +10,8 @@ import {
DependencyGraphConfig, DependencyGraphConfig,
DependencyGraphOption, DependencyGraphOption,
GradleExecutionConfig, GradleExecutionConfig,
setActionId setActionId,
WrapperValidationConfig
} from '../../configuration' } from '../../configuration'
import {saveDeprecationState} from '../../deprecation-collector' import {saveDeprecationState} from '../../deprecation-collector'
import {handleMainActionError} from '../../errors' import {handleMainActionError} from '../../errors'
@@ -23,7 +24,7 @@ export async function run(): Promise<void> {
setActionId('gradle/actions/dependency-submission') setActionId('gradle/actions/dependency-submission')
// Configure Gradle environment (Gradle User Home) // Configure Gradle environment (Gradle User Home)
await setupGradle.setup(new CacheConfig(), new BuildScanConfig()) await setupGradle.setup(new CacheConfig(), new BuildScanConfig(), new WrapperValidationConfig())
// Capture the enabled state of dependency-graph // Capture the enabled state of dependency-graph
const originallyEnabled = process.env['GITHUB_DEPENDENCY_GRAPH_ENABLED'] const originallyEnabled = process.env['GITHUB_DEPENDENCY_GRAPH_ENABLED']

View File

@@ -6,7 +6,7 @@ import {
CacheConfig, CacheConfig,
DependencyGraphConfig, DependencyGraphConfig,
GradleExecutionConfig, GradleExecutionConfig,
doValidateWrappers, WrapperValidationConfig,
getActionId, getActionId,
setActionId setActionId
} from '../../configuration' } from '../../configuration'
@@ -26,13 +26,8 @@ export async function run(): Promise<void> {
setActionId('gradle/actions/setup-gradle') setActionId('gradle/actions/setup-gradle')
// Check for invalid wrapper JARs if requested
if (doValidateWrappers()) {
await setupGradle.checkNoInvalidWrapperJars()
}
// Configure Gradle environment (Gradle User Home) // Configure Gradle environment (Gradle User Home)
await setupGradle.setup(new CacheConfig(), new BuildScanConfig()) await setupGradle.setup(new CacheConfig(), new BuildScanConfig(), new WrapperValidationConfig())
// Configure the dependency graph submission // Configure the dependency graph submission
await dependencyGraph.setup(new DependencyGraphConfig()) await dependencyGraph.setup(new DependencyGraphConfig())

View File

@@ -18,15 +18,23 @@ export async function run(): Promise<void> {
const result = await validate.findInvalidWrapperJars( const result = await validate.findInvalidWrapperJars(
path.resolve('.'), path.resolve('.'),
+core.getInput('min-wrapper-count'),
core.getInput('allow-snapshots') === 'true', core.getInput('allow-snapshots') === 'true',
core.getInput('allow-checksums').split(',') core.getInput('allow-checksums').split(',')
) )
if (result.isValid()) { if (result.isValid()) {
core.info(result.toDisplayString()) core.info(result.toDisplayString())
const minWrapperCount = +core.getInput('min-wrapper-count')
if (result.valid.length < minWrapperCount) {
const message =
result.valid.length === 0
? 'Wrapper validation failed: no Gradle Wrapper jars found. Did you forget to checkout the repository?'
: `Wrapper validation failed: expected at least ${minWrapperCount} Gradle Wrapper jars, but found ${result.valid.length}.`
core.setFailed(message)
}
} else { } else {
core.setFailed( core.setFailed(
`Gradle Wrapper Validation Failed!\n See https://github.com/gradle/actions/blob/main/docs/wrapper-validation.md#reporting-failures\n${result.toDisplayString()}` `At least one Gradle Wrapper Jar failed validation!\n See https://github.com/gradle/actions/blob/main/docs/wrapper-validation.md#validation-failures\n${result.toDisplayString()}`
) )
if (result.invalid.length > 0) { if (result.invalid.length > 0) {
core.setOutput('failed-wrapper', `${result.invalid.map(w => w.path).join('|')}`) core.setOutput('failed-wrapper', `${result.invalid.map(w => w.path).join('|')}`)

View File

@@ -1,7 +1,9 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as exec from '@actions/exec'
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import {provisionAndMaybeExecute} from '../execution/gradle' import * as provisioner from '../execution/provision'
export class CacheCleaner { export class CacheCleaner {
private readonly gradleUserHome: string private readonly gradleUserHome: string
@@ -24,9 +26,8 @@ export class CacheCleaner {
await this.forceCleanupFilesOlderThan(cleanTimestamp) await this.forceCleanupFilesOlderThan(cleanTimestamp)
} }
// Visible for testing
async forceCleanupFilesOlderThan(cleanTimestamp: string): Promise<void> { async forceCleanupFilesOlderThan(cleanTimestamp: string): Promise<void> {
core.info(`Cleaning up caches before ${cleanTimestamp}`)
// Run a dummy Gradle build to trigger cache cleanup // Run a dummy Gradle build to trigger cache cleanup
const cleanupProjectDir = path.resolve(this.tmpDir, 'dummy-cleanup-project') const cleanupProjectDir = path.resolve(this.tmpDir, 'dummy-cleanup-project')
fs.mkdirSync(cleanupProjectDir, {recursive: true}) fs.mkdirSync(cleanupProjectDir, {recursive: true})
@@ -54,7 +55,16 @@ export class CacheCleaner {
) )
fs.writeFileSync(path.resolve(cleanupProjectDir, 'build.gradle'), 'task("noop") {}') fs.writeFileSync(path.resolve(cleanupProjectDir, 'build.gradle'), 'task("noop") {}')
await provisionAndMaybeExecute('current', cleanupProjectDir, [ const executable = await provisioner.provisionGradle('current')
await core.group('Executing Gradle to clean up caches', async () => {
core.info(`Cleaning up caches last used before ${cleanTimestamp}`)
await this.executeCleanupBuild(executable!, cleanupProjectDir)
})
}
private async executeCleanupBuild(executable: string, cleanupProjectDir: string): Promise<void> {
const args = [
'-g', '-g',
this.gradleUserHome, this.gradleUserHome,
'-I', '-I',
@@ -65,6 +75,13 @@ export class CacheCleaner {
'--build-cache', '--build-cache',
'-DGITHUB_DEPENDENCY_GRAPH_ENABLED=false', '-DGITHUB_DEPENDENCY_GRAPH_ENABLED=false',
'noop' 'noop'
]) ]
const result = await exec.getExecOutput(executable, args, {
cwd: cleanupProjectDir,
silent: true
})
core.info(result.stdout)
} }
} }

View File

@@ -92,7 +92,9 @@ export async function save(
return return
} }
await daemonController.stopAllDaemons() await core.group('Stopping Gradle daemons', async () => {
await daemonController.stopAllDaemons()
})
if (cacheConfig.isCacheCleanupEnabled()) { if (cacheConfig.isCacheCleanupEnabled()) {
if (buildResults.anyConfigCacheHit()) { if (buildResults.anyConfigCacheHit()) {
@@ -113,7 +115,6 @@ export async function save(
} }
async function performCacheCleanup(gradleUserHome: string): Promise<void> { async function performCacheCleanup(gradleUserHome: string): Promise<void> {
core.info('Forcing cache cleanup.')
const cacheCleaner = new CacheCleaner(gradleUserHome, process.env['RUNNER_TEMP']!) const cacheCleaner = new CacheCleaner(gradleUserHome, process.env['RUNNER_TEMP']!)
try { try {
await cacheCleaner.forceCleanup() await cacheCleaner.forceCleanup()

View File

@@ -4,12 +4,11 @@ import * as core from '@actions/core'
import * as glob from '@actions/glob' import * as glob from '@actions/glob'
import * as semver from 'semver' import * as semver from 'semver'
import {META_FILE_DIR} from './gradle-user-home-cache'
import {CacheEntryListener, CacheListener} from './cache-reporting' import {CacheEntryListener, CacheListener} from './cache-reporting'
import {cacheDebug, hashFileNames, isCacheDebuggingEnabled, restoreCache, saveCache, tryDelete} from './cache-utils' import {cacheDebug, hashFileNames, isCacheDebuggingEnabled, restoreCache, saveCache, tryDelete} from './cache-utils'
import {BuildResult, loadBuildResults} from '../build-results' import {BuildResult, loadBuildResults} from '../build-results'
import {CacheConfig} from '../configuration' import {CacheConfig, ACTION_METADATA_DIR} from '../configuration'
import {getCacheKeyBase} from './cache-key' import {getCacheKeyBase} from './cache-key'
const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE' const SKIP_RESTORE_VAR = 'GRADLE_BUILD_ACTION_SKIP_RESTORE'
@@ -298,7 +297,7 @@ abstract class AbstractEntryExtractor {
} }
private getCacheMetadataFile(): string { private getCacheMetadataFile(): string {
const actionMetadataDirectory = path.resolve(this.gradleUserHome, META_FILE_DIR) const actionMetadataDirectory = path.resolve(this.gradleUserHome, ACTION_METADATA_DIR)
fs.mkdirSync(actionMetadataDirectory, {recursive: true}) fs.mkdirSync(actionMetadataDirectory, {recursive: true})
return path.resolve(actionMetadataDirectory, `${this.extractorName}-entry-metadata.json`) return path.resolve(actionMetadataDirectory, `${this.extractorName}-entry-metadata.json`)

View File

@@ -7,14 +7,12 @@ import fs from 'fs'
import {generateCacheKey} from './cache-key' import {generateCacheKey} from './cache-key'
import {CacheListener} from './cache-reporting' import {CacheListener} from './cache-reporting'
import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete} from './cache-utils' import {saveCache, restoreCache, cacheDebug, isCacheDebuggingEnabled, tryDelete} from './cache-utils'
import {CacheConfig} from '../configuration' import {CacheConfig, ACTION_METADATA_DIR} from '../configuration'
import {GradleHomeEntryExtractor, ConfigurationCacheEntryExtractor} from './gradle-home-extry-extractor' import {GradleHomeEntryExtractor, ConfigurationCacheEntryExtractor} from './gradle-home-extry-extractor'
import {getPredefinedToolchains, mergeToolchainContent, readResourceFileAsString} from './gradle-user-home-utils' import {getPredefinedToolchains, mergeToolchainContent, readResourceFileAsString} from './gradle-user-home-utils'
const RESTORED_CACHE_KEY_KEY = 'restored-cache-key' const RESTORED_CACHE_KEY_KEY = 'restored-cache-key'
export const META_FILE_DIR = '.setup-gradle'
export class GradleUserHomeCache { export class GradleUserHomeCache {
private readonly cacheName = 'home' private readonly cacheName = 'home'
private readonly cacheDescription = 'Gradle User Home' private readonly cacheDescription = 'Gradle User Home'
@@ -172,7 +170,7 @@ export class GradleUserHomeCache {
*/ */
protected getCachePath(): string[] { protected getCachePath(): string[] {
const rawPaths: string[] = this.cacheConfig.getCacheIncludes() const rawPaths: string[] = this.cacheConfig.getCacheIncludes()
rawPaths.push(META_FILE_DIR) rawPaths.push(ACTION_METADATA_DIR)
const resolvedPaths = rawPaths.map(x => this.resolveCachePath(x)) const resolvedPaths = rawPaths.map(x => this.resolveCachePath(x))
cacheDebug(`Using cache paths: ${resolvedPaths}`) cacheDebug(`Using cache paths: ${resolvedPaths}`)
return resolvedPaths return resolvedPaths
@@ -188,7 +186,7 @@ export class GradleUserHomeCache {
private initializeGradleUserHome(): void { private initializeGradleUserHome(): void {
// Create a directory for storing action metadata // Create a directory for storing action metadata
const actionCacheDir = path.resolve(this.gradleUserHome, META_FILE_DIR) const actionCacheDir = path.resolve(this.gradleUserHome, ACTION_METADATA_DIR)
fs.mkdirSync(actionCacheDir, {recursive: true}) fs.mkdirSync(actionCacheDir, {recursive: true})
this.copyInitScripts() this.copyInitScripts()

View File

@@ -8,6 +8,8 @@ import path from 'path'
const ACTION_ID_VAR = 'GRADLE_ACTION_ID' const ACTION_ID_VAR = 'GRADLE_ACTION_ID'
export const ACTION_METADATA_DIR = '.setup-gradle'
export class DependencyGraphConfig { export class DependencyGraphConfig {
getDependencyGraphOption(): DependencyGraphOption { getDependencyGraphOption(): DependencyGraphOption {
const val = core.getInput('dependency-graph') const val = core.getInput('dependency-graph')
@@ -357,8 +359,14 @@ export class GradleExecutionConfig {
} }
} }
export function doValidateWrappers(): boolean { export class WrapperValidationConfig {
return getBooleanInput('validate-wrappers') doValidateWrappers(): boolean {
return getBooleanInput('validate-wrappers')
}
allowSnapshotWrappers(): boolean {
return getBooleanInput('allow-snapshot-wrappers')
}
} }
// Internal parameters // Internal parameters

View File

@@ -12,8 +12,6 @@ export class DaemonController {
} }
async stopAllDaemons(): Promise<void> { async stopAllDaemons(): Promise<void> {
core.info('Stopping all Gradle daemons before saving Gradle User Home state')
const executions: Promise<number>[] = [] const executions: Promise<number>[] = []
const args = ['--stop'] const args = ['--stop']

View File

@@ -25,7 +25,7 @@ export function recordDeprecation(message: string): void {
export function failOnUseOfRemovedFeature(removalMessage: string, deprecationMessage: string = removalMessage): void { export function failOnUseOfRemovedFeature(removalMessage: string, deprecationMessage: string = removalMessage): void {
const deprecation = new Deprecation(deprecationMessage) const deprecation = new Deprecation(deprecationMessage)
const errorMessage = `${removalMessage}. See ${deprecation.getDocumentationLink()}` const errorMessage = `${removalMessage}.\nSee ${deprecation.getDocumentationLink()}`
recordedErrors.push(errorMessage) recordedErrors.push(errorMessage)
core.setFailed(errorMessage) core.setFailed(errorMessage)
} }

View File

@@ -7,7 +7,7 @@ export async function setup(config: BuildScanConfig): Promise<void> {
maybeExportVariable('DEVELOCITY_AUTO_INJECTION_CUSTOM_VALUE', 'gradle-actions') maybeExportVariable('DEVELOCITY_AUTO_INJECTION_CUSTOM_VALUE', 'gradle-actions')
if (config.getBuildScanPublishEnabled()) { if (config.getBuildScanPublishEnabled()) {
maybeExportVariable('DEVELOCITY_INJECTION_ENABLED', 'true') maybeExportVariable('DEVELOCITY_INJECTION_ENABLED', 'true')
maybeExportVariable('DEVELOCITY_PLUGIN_VERSION', '3.17.5') maybeExportVariable('DEVELOCITY_PLUGIN_VERSION', '3.17.6')
maybeExportVariable('DEVELOCITY_CCUD_PLUGIN_VERSION', '2.0') maybeExportVariable('DEVELOCITY_CCUD_PLUGIN_VERSION', '2.0')
maybeExportVariable('DEVELOCITY_TERMS_OF_USE_URL', config.getBuildScanTermsOfUseUrl()) maybeExportVariable('DEVELOCITY_TERMS_OF_USE_URL', config.getBuildScanTermsOfUseUrl())
maybeExportVariable('DEVELOCITY_TERMS_OF_USE_AGREE', config.getBuildScanTermsOfUseAgree()) maybeExportVariable('DEVELOCITY_TERMS_OF_USE_AGREE', config.getBuildScanTermsOfUseAgree())

View File

@@ -10,16 +10,25 @@ import * as buildScan from './develocity/build-scan'
import {loadBuildResults, markBuildResultsProcessed} from './build-results' import {loadBuildResults, markBuildResultsProcessed} from './build-results'
import {CacheListener, generateCachingReport} from './caching/cache-reporting' import {CacheListener, generateCachingReport} from './caching/cache-reporting'
import {DaemonController} from './daemon-controller' import {DaemonController} from './daemon-controller'
import {BuildScanConfig, CacheConfig, SummaryConfig, getWorkspaceDirectory} from './configuration' import {
import {findInvalidWrapperJars} from './wrapper-validation/validate' BuildScanConfig,
import {JobFailure} from './errors' CacheConfig,
SummaryConfig,
WrapperValidationConfig,
getWorkspaceDirectory
} from './configuration'
import * as wrapperValidator from './wrapper-validation/wrapper-validator'
const GRADLE_SETUP_VAR = 'GRADLE_BUILD_ACTION_SETUP_COMPLETED' const GRADLE_SETUP_VAR = 'GRADLE_BUILD_ACTION_SETUP_COMPLETED'
const USER_HOME = 'USER_HOME' const USER_HOME = 'USER_HOME'
const GRADLE_USER_HOME = 'GRADLE_USER_HOME' const GRADLE_USER_HOME = 'GRADLE_USER_HOME'
const CACHE_LISTENER = 'CACHE_LISTENER' const CACHE_LISTENER = 'CACHE_LISTENER'
export async function setup(cacheConfig: CacheConfig, buildScanConfig: BuildScanConfig): Promise<boolean> { export async function setup(
cacheConfig: CacheConfig,
buildScanConfig: BuildScanConfig,
wrapperValidationConfig: WrapperValidationConfig
): Promise<boolean> {
const userHome = await determineUserHome() const userHome = await determineUserHome()
const gradleUserHome = await determineGradleUserHome() const gradleUserHome = await determineGradleUserHome()
@@ -42,6 +51,8 @@ export async function setup(cacheConfig: CacheConfig, buildScanConfig: BuildScan
core.saveState(CACHE_LISTENER, cacheListener.stringify()) core.saveState(CACHE_LISTENER, cacheListener.stringify())
await wrapperValidator.validateWrappers(wrapperValidationConfig, getWorkspaceDirectory(), gradleUserHome)
await buildScan.setup(buildScanConfig) await buildScan.setup(buildScanConfig)
return true return true
@@ -116,16 +127,3 @@ async function determineUserHome(): Promise<string> {
core.debug(`Determined user.home from java -version output: '${userHome}'`) core.debug(`Determined user.home from java -version output: '${userHome}'`)
return userHome return userHome
} }
export async function checkNoInvalidWrapperJars(rootDir = getWorkspaceDirectory()): Promise<void> {
const allowedChecksums = process.env['ALLOWED_GRADLE_WRAPPER_CHECKSUMS']?.split(',') || []
const result = await findInvalidWrapperJars(rootDir, 1, false, allowedChecksums)
if (result.isValid()) {
core.info(result.toDisplayString())
} else {
core.info(result.toDisplayString())
throw new JobFailure(
`Gradle Wrapper Validation Failed!\n See https://github.com/gradle/actions/blob/main/docs/wrapper-validation.md#reporting-failures\n${result.toDisplayString()}`
)
}
}

View File

@@ -0,0 +1,26 @@
import fs from 'fs'
import path from 'path'
import {ACTION_METADATA_DIR} from '../configuration'
export class ChecksumCache {
private readonly cacheFile: string
constructor(gradleUserHome: string) {
this.cacheFile = path.resolve(gradleUserHome, ACTION_METADATA_DIR, 'valid-wrappers.json')
}
load(): string[] {
// Load previously validated checksums saved in Gradle User Home
if (fs.existsSync(this.cacheFile)) {
return JSON.parse(fs.readFileSync(this.cacheFile, 'utf-8'))
}
return []
}
save(checksums: string[]): void {
const uniqueChecksums = [...new Set(checksums)]
// Save validated checksums to Gradle User Home
fs.mkdirSync(path.dirname(this.cacheFile), {recursive: true})
fs.writeFileSync(this.cacheFile, JSON.stringify(uniqueChecksums))
}
}

View File

@@ -1,4 +1,5 @@
import * as httpm from 'typed-rest-client/HttpClient' import * as httpm from 'typed-rest-client/HttpClient'
import * as cheerio from 'cheerio'
import fileWrapperChecksums from './wrapper-checksums.json' import fileWrapperChecksums from './wrapper-checksums.json'
@@ -54,7 +55,15 @@ export async function fetchUnknownChecksums(
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
(entry: any) => entry.wrapperChecksumUrl as string (entry: any) => entry.wrapperChecksumUrl as string
) )
const checksums = await Promise.all(checksumUrls.map(async (url: string) => httpGetText(url))) if (allowSnapshots) {
await addDistributionSnapshotChecksums(checksumUrls)
}
const checksums = await Promise.all(
checksumUrls.map(async (url: string) => {
// console.log(`Fetching checksum from ${url}`)
return httpGetText(url)
})
)
return new Set(checksums) return new Set(checksums)
} }
@@ -66,3 +75,22 @@ async function httpGetText(url: string): Promise<string> {
const response = await httpc.get(url) const response = await httpc.get(url)
return await response.readBody() return await response.readBody()
} }
// Public for testing
export async function addDistributionSnapshotChecksums(checksumUrls: string[]): Promise<void> {
// Load the index page of the distribution snapshot repository
const indexPage = await httpGetText('https://services.gradle.org/distributions-snapshots/')
// // Extract all wrapper checksum from the index page. These end in -wrapper.jar.sha256
// // Load the HTML into cheerio
const $ = cheerio.load(indexPage)
// // Find all links ending with '-wrapper.jar.sha256'
const wrapperChecksumLinks = $('a[href$="-wrapper.jar.sha256"]')
// build the absolute URL for each wrapper checksum
wrapperChecksumLinks.each((index, element) => {
const url = $(element).attr('href')
checksumUrls.push(`https://services.gradle.org${url}`)
})
}

View File

@@ -5,23 +5,22 @@ import {resolve} from 'path'
export async function findInvalidWrapperJars( export async function findInvalidWrapperJars(
gitRepoRoot: string, gitRepoRoot: string,
minWrapperCount: number,
allowSnapshots: boolean, allowSnapshots: boolean,
allowedChecksums: string[], allowedChecksums: string[],
previouslyValidatedChecksums: string[] = [],
knownValidChecksums: checksums.WrapperChecksums = checksums.KNOWN_CHECKSUMS knownValidChecksums: checksums.WrapperChecksums = checksums.KNOWN_CHECKSUMS
): Promise<ValidationResult> { ): Promise<ValidationResult> {
const wrapperJars = await find.findWrapperJars(gitRepoRoot) const wrapperJars = await find.findWrapperJars(gitRepoRoot)
const result = new ValidationResult([], []) const result = new ValidationResult([], [])
if (wrapperJars.length < minWrapperCount) {
result.errors.push(
`Expected to find at least ${minWrapperCount} Gradle Wrapper JARs but got only ${wrapperJars.length}`
)
}
if (wrapperJars.length > 0) { if (wrapperJars.length > 0) {
const notYetValidatedWrappers = [] const notYetValidatedWrappers = []
for (const wrapperJar of wrapperJars) { for (const wrapperJar of wrapperJars) {
const sha = await hash.sha256File(resolve(gitRepoRoot, wrapperJar)) const sha = await hash.sha256File(resolve(gitRepoRoot, wrapperJar))
if (allowedChecksums.includes(sha) || knownValidChecksums.checksums.has(sha)) { if (
allowedChecksums.includes(sha) ||
previouslyValidatedChecksums.includes(sha) ||
knownValidChecksums.checksums.has(sha)
) {
result.valid.push(new WrapperJar(wrapperJar, sha)) result.valid.push(new WrapperJar(wrapperJar, sha))
} else { } else {
notYetValidatedWrappers.push(new WrapperJar(wrapperJar, sha)) notYetValidatedWrappers.push(new WrapperJar(wrapperJar, sha))
@@ -49,7 +48,6 @@ export class ValidationResult {
valid: WrapperJar[] valid: WrapperJar[]
invalid: WrapperJar[] invalid: WrapperJar[]
fetchedChecksums = false fetchedChecksums = false
errors: string[] = []
constructor(valid: WrapperJar[], invalid: WrapperJar[]) { constructor(valid: WrapperJar[], invalid: WrapperJar[]) {
this.valid = valid this.valid = valid
@@ -57,7 +55,7 @@ export class ValidationResult {
} }
isValid(): boolean { isValid(): boolean {
return this.invalid.length === 0 && this.errors.length === 0 return this.invalid.length === 0
} }
toDisplayString(): string { toDisplayString(): string {
@@ -67,10 +65,6 @@ export class ValidationResult {
this.invalid this.invalid
)}` )}`
} }
if (this.errors.length > 0) {
if (displayString.length > 0) displayString += '\n'
displayString += `✗ Other validation errors:\n ${this.errors.join(`\n `)}`
}
if (this.valid.length > 0) { if (this.valid.length > 0) {
if (displayString.length > 0) displayString += '\n' if (displayString.length > 0) displayString += '\n'
displayString += `✓ Found known Gradle Wrapper JAR files:\n${ValidationResult.toDisplayList(this.valid)}` displayString += `✓ Found known Gradle Wrapper JAR files:\n${ValidationResult.toDisplayList(this.valid)}`

View File

@@ -0,0 +1,40 @@
import * as core from '@actions/core'
import {WrapperValidationConfig} from '../configuration'
import {ChecksumCache} from './cache'
import {findInvalidWrapperJars} from './validate'
import {JobFailure} from '../errors'
export async function validateWrappers(
config: WrapperValidationConfig,
workspaceRoot: string,
gradleUserHome: string
): Promise<void> {
if (!config.doValidateWrappers()) {
return // Wrapper validation is disabled
}
const checksumCache = new ChecksumCache(gradleUserHome)
const allowedChecksums = process.env['ALLOWED_GRADLE_WRAPPER_CHECKSUMS']?.split(',') || []
const previouslyValidatedChecksums = checksumCache.load()
const result = await findInvalidWrapperJars(
workspaceRoot,
config.allowSnapshotWrappers(),
allowedChecksums,
previouslyValidatedChecksums
)
if (result.isValid()) {
await core.group('All Gradle Wrapper jars are valid', async () => {
core.debug(`Loaded previously validated checksums from cache: ${previouslyValidatedChecksums.join(', ')}`)
core.info(result.toDisplayString())
})
} else {
core.info(result.toDisplayString())
throw new JobFailure(
`At least one Gradle Wrapper Jar failed validation!\n See https://github.com/gradle/actions/blob/main/docs/wrapper-validation.md#validation-failures\n${result.toDisplayString()}`
)
}
checksumCache.save(result.valid.map(wrapper => wrapper.checksum))
}

View File

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

View File

@@ -16,7 +16,7 @@ import java.nio.file.Files
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
class BaseInitScriptTest extends Specification { class BaseInitScriptTest extends Specification {
static final String DEVELOCITY_PLUGIN_VERSION = '3.17.5' static final String DEVELOCITY_PLUGIN_VERSION = '3.17.6'
static final String CCUD_PLUGIN_VERSION = '2.0.1' static final String CCUD_PLUGIN_VERSION = '2.0.1'
static final TestGradleVersion GRADLE_3_X = new TestGradleVersion(GradleVersion.version('3.5.1'), 7, 9) static final TestGradleVersion GRADLE_3_X = new TestGradleVersion(GradleVersion.version('3.5.1'), 7, 9)

View File

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

View File

@@ -32,6 +32,22 @@ test('fetches wrapper jars checksums', async () => {
).toBe(true) ).toBe(true)
}) })
test('fetches wrapper jar checksums for snapshots', async () => {
const nonSnapshotChecksums = await checksums.fetchUnknownChecksums(false, new checksums.WrapperChecksums)
const validChecksums = await checksums.fetchUnknownChecksums(true, new checksums.WrapperChecksums)
// Expect that at least one snapshot checksum is different from the non-snapshot checksums
expect(validChecksums.size).toBeGreaterThan(nonSnapshotChecksums.size)
})
test('fetches all wrapper checksum URLS for snapshots', async () => {
const checksumUrls: string[] = []
await checksums.addDistributionSnapshotChecksums(checksumUrls)
expect(checksumUrls.length).toBeGreaterThan(100) // May only be a few unique checksums
console.log(checksumUrls)
})
describe('retry', () => { describe('retry', () => {
afterEach(() => { afterEach(() => {
nock.cleanAll() nock.cleanAll()

View File

@@ -1,14 +1,18 @@
import * as path from 'path' import * as path from 'path'
import * as fs from 'fs'
import * as validate from '../../../src/wrapper-validation/validate' import * as validate from '../../../src/wrapper-validation/validate'
import {expect, test, jest} from '@jest/globals' import {expect, test, jest} from '@jest/globals'
import { WrapperChecksums } from '../../../src/wrapper-validation/checksums' import { WrapperChecksums } from '../../../src/wrapper-validation/checksums'
import { ChecksumCache } from '../../../src/wrapper-validation/cache'
import exp from 'constants'
jest.setTimeout(30000) jest.setTimeout(30000)
const baseDir = path.resolve('./test/jest/wrapper-validation') const baseDir = path.resolve('./test/jest/wrapper-validation')
const tmpDir = path.resolve('./test/jest/tmp')
test('succeeds if all found wrapper jars are valid', async () => { test('succeeds if all found wrapper jars are valid', async () => {
const result = await validate.findInvalidWrapperJars(baseDir, 3, false, [ const result = await validate.findInvalidWrapperJars(baseDir, false, [
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
]) ])
@@ -24,13 +28,31 @@ test('succeeds if all found wrapper jars are valid', async () => {
) )
}) })
test('succeeds if all found wrapper jars are previously valid', async () => {
const result = await validate.findInvalidWrapperJars(baseDir, false, [], [
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
'3888c76faa032ea8394b8a54e04ce2227ab1f4be64f65d450f8509fe112d38ce'
])
expect(result.isValid()).toBe(true)
// Only hardcoded and explicitly allowed checksums should have been used
expect(result.fetchedChecksums).toBe(false)
expect(result.toDisplayString()).toBe(
'✓ Found known Gradle Wrapper JAR files:\n' +
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 data/invalid/gradle-wrapper.jar\n' +
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 data/invalid/gradlе-wrapper.jar\n' + // homoglyph
' 3888c76faa032ea8394b8a54e04ce2227ab1f4be64f65d450f8509fe112d38ce data/valid/gradle-wrapper.jar'
)
})
test('succeeds if all found wrapper jars are valid (and checksums are fetched from Gradle API)', async () => { test('succeeds if all found wrapper jars are valid (and checksums are fetched from Gradle API)', async () => {
const knownValidChecksums = new WrapperChecksums() const knownValidChecksums = new WrapperChecksums()
const result = await validate.findInvalidWrapperJars( const result = await validate.findInvalidWrapperJars(
baseDir, baseDir,
1,
false, false,
['e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'], ['e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'],
[],
knownValidChecksums knownValidChecksums
) )
console.log(`fetchedChecksums = ${result.fetchedChecksums}`) console.log(`fetchedChecksums = ${result.fetchedChecksums}`)
@@ -48,7 +70,7 @@ test('succeeds if all found wrapper jars are valid (and checksums are fetched fr
}) })
test('fails if invalid wrapper jars are found', async () => { test('fails if invalid wrapper jars are found', async () => {
const result = await validate.findInvalidWrapperJars(baseDir, 3, false, []) const result = await validate.findInvalidWrapperJars(baseDir, false, [])
expect(result.isValid()).toBe(false) expect(result.isValid()).toBe(false)
@@ -79,22 +101,16 @@ test('fails if invalid wrapper jars are found', async () => {
) )
}) })
test('fails if not enough wrapper jars are found', async () => { test('can save and load checksums', async () => {
const result = await validate.findInvalidWrapperJars(baseDir, 4, false, []) const cacheDir = path.join(tmpDir, 'wrapper-validation-cache')
fs.rmSync(cacheDir, {recursive: true, force: true})
expect(result.isValid()).toBe(false) const checksumCache = new ChecksumCache(cacheDir)
expect(result.errors).toEqual([ expect(checksumCache.load()).toEqual([])
'Expected to find at least 4 Gradle Wrapper JARs but got only 3'
])
expect(result.toDisplayString()).toBe( checksumCache.save(['123', '456'])
'✗ Found unknown Gradle Wrapper JAR files:\n' +
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 data/invalid/gradle-wrapper.jar\n' + expect(checksumCache.load()).toEqual(['123', '456'])
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 data/invalid/gradlе-wrapper.jar\n' + // homoglyph expect(fs.existsSync(cacheDir)).toBe(true)
'✗ Other validation errors:\n' +
' Expected to find at least 4 Gradle Wrapper JARs but got only 3\n' +
'✓ Found known Gradle Wrapper JAR files:\n' +
' 3888c76faa032ea8394b8a54e04ce2227ab1f4be64f65d450f8509fe112d38ce data/valid/gradle-wrapper.jar'
)
}) })