Compare commits

..

3 Commits

Author SHA1 Message Date
Bruno Borges 2c5fdefc8d Merge branch 'main' into copilot/fix-code-scanning-alerts-120 2026-07-14 16:00:22 -04:00
copilot-swe-agent[bot] e339ec234c Fix template injection in e2e-versions.yml (alert #120) 2026-07-14 19:38:04 +00:00
copilot-swe-agent[bot] 3682c106a4 Initial plan 2026-07-14 19:36:48 +00:00
27 changed files with 1032 additions and 3915 deletions
@@ -0,0 +1,102 @@
name: Validate cache with cache-dependency-path option
on:
push:
branches:
- main
- releases/*
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
permissions:
contents: read
defaults:
run:
shell: bash
jobs:
gradle1-save:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '17'
cache: gradle
cache-dependency-path: __tests__/cache/gradle1/*.gradle*
- name: Create files to cache
# Need to avoid using Gradle daemon to stabilize the save process on Windows
# https://github.com/actions/cache/issues/454#issuecomment-840493935
run: |
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
if [ ! -d ~/.gradle/caches ]; then
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
exit 1
fi
gradle1-restore:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
needs: gradle1-save
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: gradle
cache-dependency-path: __tests__/cache/gradle1/*.gradle*
- name: Confirm that ~/.gradle/caches directory has been made
run: |
if [ ! -d ~/.gradle/caches ]; then
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
exit 1
fi
ls ~/.gradle/caches/
gradle2-restore:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
needs: gradle1-save
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: gradle
cache-dependency-path: __tests__/cache/gradle2/*.gradle*
- name: Confirm that ~/.gradle/caches directory has not been made
run: |
if [ -d ~/.gradle/caches ]; then
echo "::error::The ~/.gradle/caches directory exists unexpectedly"
exit 1
fi
+54 -255
View File
@@ -42,7 +42,10 @@ jobs:
# https://github.com/actions/cache/issues/454#issuecomment-840493935 # https://github.com/actions/cache/issues/454#issuecomment-840493935
run: | run: |
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1 gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
bash __tests__/check-dir.sh "$HOME/.gradle/caches" if [ ! -d ~/.gradle/caches ]; then
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
exit 1
fi
gradle-restore: gradle-restore:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
@@ -63,7 +66,12 @@ jobs:
java-version: '11' java-version: '11'
cache: gradle cache: gradle
- name: Confirm that ~/.gradle/caches directory has been made - name: Confirm that ~/.gradle/caches directory has been made
run: bash __tests__/check-dir.sh "$HOME/.gradle/caches" run: |
if [ ! -d ~/.gradle/caches ]; then
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
exit 1
fi
ls ~/.gradle/caches/
maven-save: maven-save:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
@@ -85,7 +93,10 @@ jobs:
- name: Create files to cache - name: Create files to cache
run: | run: |
mvn verify -f __tests__/cache/maven/pom.xml mvn verify -f __tests__/cache/maven/pom.xml
bash __tests__/check-dir.sh "$HOME/.m2/repository" if [ ! -d ~/.m2/repository ]; then
echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
exit 1
fi
maven-restore: maven-restore:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
@@ -106,7 +117,12 @@ jobs:
java-version: '11' java-version: '11'
cache: maven cache: maven
- name: Confirm that ~/.m2/repository directory has been made - name: Confirm that ~/.m2/repository directory has been made
run: bash __tests__/check-dir.sh "$HOME/.m2/repository" run: |
if [ ! -d ~/.m2/repository ]; then
echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
exit 1
fi
ls ~/.m2/repository
sbt-save: sbt-save:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
defaults: defaults:
@@ -139,13 +155,25 @@ jobs:
- name: Check files to cache on macos-latest - name: Check files to cache on macos-latest
if: matrix.os == 'macos-15-intel' if: matrix.os == 'macos-15-intel'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier" run: |
if [ ! -d ~/Library/Caches/Coursier ]; then
echo "::error::The ~/Library/Caches/Coursier directory does not exist unexpectedly"
exit 1
fi
- name: Check files to cache on windows-latest - name: Check files to cache on windows-latest
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache" run: |
if [ ! -d ~/AppData/Local/Coursier/Cache ]; then
echo "::error::The ~/AppData/Local/Coursier/Cache directory does not exist unexpectedly"
exit 1
fi
- name: Check files to cache on ubuntu-latest - name: Check files to cache on ubuntu-latest
if: matrix.os == 'ubuntu-22.04' if: matrix.os == 'ubuntu-latest'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier" run: |
if [ ! -d ~/.cache/coursier ]; then
echo "::error::The ~/.cache/coursier directory does not exist unexpectedly"
exit 1
fi
sbt-restore: sbt-restore:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
defaults: defaults:
@@ -172,254 +200,25 @@ jobs:
- name: Confirm that ~/Library/Caches/Coursier directory has been made - name: Confirm that ~/Library/Caches/Coursier directory has been made
if: matrix.os == 'macos-15-intel' if: matrix.os == 'macos-15-intel'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier" run: |
if [ ! -d ~/Library/Caches/Coursier ]; then
echo "::error::The ~/Library/Caches/Coursier directory does not exist unexpectedly"
exit 1
fi
ls ~/Library/Caches/Coursier
- name: Confirm that ~/AppData/Local/Coursier/Cache directory has been made - name: Confirm that ~/AppData/Local/Coursier/Cache directory has been made
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache" run: |
if [ ! -d ~/AppData/Local/Coursier/Cache ]; then
echo "::error::The ~/AppData/Local/Coursier/Cache directory does not exist unexpectedly"
exit 1
fi
ls ~/AppData/Local/Coursier/Cache
- name: Confirm that ~/.cache/coursier directory has been made - name: Confirm that ~/.cache/coursier directory has been made
if: matrix.os == 'ubuntu-22.04' if: matrix.os == 'ubuntu-latest'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
gradle1-save:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '17'
cache: gradle
cache-dependency-path: __tests__/cache/gradle1/*.gradle*
- name: Create files to cache
# Need to avoid using Gradle daemon to stabilize the save process on Windows
# https://github.com/actions/cache/issues/454#issuecomment-840493935
run: | run: |
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1 if [ ! -d ~/.cache/coursier ]; then
bash __tests__/check-dir.sh "$HOME/.gradle/caches" echo "::error::The ~/.cache/coursier directory does not exist unexpectedly"
gradle1-restore: exit 1
runs-on: ${{ matrix.os }} fi
strategy: ls ~/.cache/coursier
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
needs: gradle1-save
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: gradle
cache-dependency-path: __tests__/cache/gradle1/*.gradle*
- name: Confirm that ~/.gradle/caches directory has been made
run: bash __tests__/check-dir.sh "$HOME/.gradle/caches"
gradle2-restore:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
needs: gradle1-save
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: gradle
cache-dependency-path: __tests__/cache/gradle2/*.gradle*
- name: Confirm that ~/.gradle/caches directory has not been made
run: bash __tests__/check-dir.sh "$HOME/.gradle/caches" absent
maven1-save:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-15-intel, windows-latest, ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for maven
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: maven
cache-dependency-path: __tests__/cache/maven/pom.xml
- name: Create files to cache
run: |
mvn verify -f __tests__/cache/maven/pom.xml
bash __tests__/check-dir.sh "$HOME/.m2/repository"
maven1-restore:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-15-intel, windows-latest, ubuntu-latest]
needs: maven1-save
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for maven
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: maven
cache-dependency-path: __tests__/cache/maven/pom.xml
- name: Confirm that ~/.m2/repository directory has been made
run: bash __tests__/check-dir.sh "$HOME/.m2/repository"
maven2-restore:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-15-intel, windows-latest, ubuntu-latest]
needs: maven1-save
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for maven
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: maven
cache-dependency-path: __tests__/cache/maven2/pom.xml
- name: Confirm that ~/.m2/repository directory has not been made
run: bash __tests__/check-dir.sh "$HOME/.m2/repository" absent
sbt1-save:
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
working-directory: __tests__/cache/sbt
strategy:
fail-fast: false
matrix:
os: [macos-15-intel, windows-latest, ubuntu-22.04]
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for sbt
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: sbt
cache-dependency-path: __tests__/cache/sbt/*.sbt
- name: Setup SBT
if: matrix.os == 'macos-15-intel'
run: |
echo ""Installing SBT...""
brew install sbt
- name: Create files to cache
run: sbt update
- name: Check files to cache on macos-latest
if: matrix.os == 'macos-15-intel'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
- name: Check files to cache on windows-latest
if: matrix.os == 'windows-latest'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
- name: Check files to cache on ubuntu-latest
if: matrix.os == 'ubuntu-22.04'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
sbt1-restore:
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
working-directory: __tests__/cache/sbt
strategy:
fail-fast: false
matrix:
os: [macos-15-intel, windows-latest, ubuntu-22.04]
needs: sbt1-save
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for sbt
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: sbt
cache-dependency-path: __tests__/cache/sbt/*.sbt
- name: Confirm that ~/Library/Caches/Coursier directory has been made
if: matrix.os == 'macos-15-intel'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
- name: Confirm that ~/AppData/Local/Coursier/Cache directory has been made
if: matrix.os == 'windows-latest'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
- name: Confirm that ~/.cache/coursier directory has been made
if: matrix.os == 'ubuntu-22.04'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
sbt2-restore:
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
working-directory: __tests__/cache/sbt2
strategy:
fail-fast: false
matrix:
os: [macos-15-intel, windows-latest, ubuntu-22.04]
needs: sbt1-save
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for sbt
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: sbt
cache-dependency-path: __tests__/cache/sbt2/*.sbt
- name: Confirm that ~/Library/Caches/Coursier directory has not been made
if: matrix.os == 'macos-15-intel'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier" absent
- name: Confirm that ~/AppData/Local/Coursier/Cache directory has not been made
if: matrix.os == 'windows-latest'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache" absent
- name: Confirm that ~/.cache/coursier directory has not been made
if: matrix.os == 'ubuntu-22.04'
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier" absent
+18 -30
View File
@@ -38,33 +38,21 @@ jobs:
distribution: 'adopt' distribution: 'adopt'
java-version: '11' java-version: '11'
server-id: maven server-id: maven
server-username-env-var: MAVEN_USERNAME server-username: MAVEN_USERNAME
server-password-env-var: MAVEN_CENTRAL_TOKEN server-password: MAVEN_CENTRAL_TOKEN
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE gpg-passphrase: MAVEN_GPG_PASSPHRASE
- name: Validate settings.xml - name: Validate settings.xml
run: | run: |
$xmlPath = Join-Path $HOME ".m2" "settings.xml" $xmlPath = Join-Path $HOME ".m2" "settings.xml"
Get-Content $xmlPath | ForEach-Object { Write-Host $_ } Get-Content $xmlPath | ForEach-Object { Write-Host $_ }
$content = [System.IO.File]::ReadAllText($xmlPath) [xml]$xml = Get-Content $xmlPath
$expected = @( $servers = $xml.settings.servers.server
'<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"' if (($servers[0].id -ne 'maven') -or ($servers[0].username -ne '${env.MAVEN_USERNAME}') -or ($servers[0].password -ne '${env.MAVEN_CENTRAL_TOKEN}')) {
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' throw "Generated XML file is incorrect"
' xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">' }
' <interactiveMode>false</interactiveMode>'
' <servers>'
' <server>'
' <id>maven</id>'
' <username>${env.MAVEN_USERNAME}</username>'
' <password>${env.MAVEN_CENTRAL_TOKEN}</password>'
' </server>'
' </servers>'
'</settings>'
) -join "`n"
if ($content -ne $expected) { if (($servers[1].id -ne 'gpg.passphrase') -or ($servers[1].passphrase -ne '${env.MAVEN_GPG_PASSPHRASE}')) {
Write-Host "Expected settings.xml:"
$expected -split "`n" | ForEach-Object { Write-Host $_ }
throw "Generated XML file is incorrect" throw "Generated XML file is incorrect"
} }
@@ -93,9 +81,9 @@ jobs:
distribution: 'adopt' distribution: 'adopt'
java-version: '11' java-version: '11'
server-id: maven server-id: maven
server-username-env-var: MAVEN_USERNAME server-username: MAVEN_USERNAME
server-password-env-var: MAVEN_CENTRAL_TOKEN server-password: MAVEN_CENTRAL_TOKEN
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE gpg-passphrase: MAVEN_GPG_PASSPHRASE
- name: Validate settings.xml is overwritten - name: Validate settings.xml is overwritten
run: | run: |
$xmlPath = Join-Path $HOME ".m2" "settings.xml" $xmlPath = Join-Path $HOME ".m2" "settings.xml"
@@ -131,10 +119,10 @@ jobs:
distribution: 'adopt' distribution: 'adopt'
java-version: '11' java-version: '11'
server-id: maven server-id: maven
server-username-env-var: MAVEN_USERNAME server-username: MAVEN_USERNAME
server-password-env-var: MAVEN_CENTRAL_TOKEN server-password: MAVEN_CENTRAL_TOKEN
overwrite-settings: false overwrite-settings: false
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE gpg-passphrase: MAVEN_GPG_PASSPHRASE
- name: Validate that settings.xml is not overwritten - name: Validate that settings.xml is not overwritten
run: | run: |
$xmlPath = Join-Path $HOME ".m2" "settings.xml" $xmlPath = Join-Path $HOME ".m2" "settings.xml"
@@ -164,9 +152,9 @@ jobs:
distribution: 'adopt' distribution: 'adopt'
java-version: '11' java-version: '11'
server-id: maven server-id: maven
server-username-env-var: MAVEN_USERNAME server-username: MAVEN_USERNAME
server-password-env-var: MAVEN_CENTRAL_TOKEN server-password: MAVEN_CENTRAL_TOKEN
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE gpg-passphrase: MAVEN_GPG_PASSPHRASE
settings-path: ${{ runner.temp }} settings-path: ${{ runner.temp }}
- name: Validate settings.xml location - name: Validate settings.xml location
run: | run: |
+151 -48
View File
@@ -96,8 +96,7 @@ jobs:
os: ubuntu-latest os: ubuntu-latest
version: '24-ea' version: '24-ea'
steps: steps:
- &checkout_step - name: Checkout
name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
@@ -128,7 +127,10 @@ jobs:
distribution: ['temurin', 'sapmachine'] distribution: ['temurin', 'sapmachine']
version: ['21', '17'] version: ['21', '17']
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Install bash - name: Install bash
run: apk add --no-cache bash run: apk add --no-cache bash
- name: setup-java - name: setup-java
@@ -151,7 +153,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: &default_os [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
distribution: ['temurin', 'zulu', 'liberica'] distribution: ['temurin', 'zulu', 'liberica']
version: version:
- '11.0' - '11.0'
@@ -180,7 +182,10 @@ jobs:
os: ubuntu-latest os: ubuntu-latest
version: '17.0.7' version: '17.0.7'
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -202,7 +207,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: *default_os os: [macos-latest, windows-latest, ubuntu-latest]
distribution: distribution:
[ [
'temurin', 'temurin',
@@ -216,7 +221,10 @@ jobs:
- distribution: dragonwell - distribution: dragonwell
os: macos-latest os: macos-latest
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -239,7 +247,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: *default_os os: [macos-latest, windows-latest, ubuntu-latest]
distribution: distribution:
[ [
'temurin', 'temurin',
@@ -253,7 +261,10 @@ jobs:
- distribution: dragonwell - distribution: dragonwell
os: macos-latest os: macos-latest
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -283,37 +294,26 @@ jobs:
run: bash __tests__/verify-java.sh "17" "$JAVA_PATH" run: bash __tests__/verify-java.sh "17" "$JAVA_PATH"
shell: bash shell: bash
setup-java-ea-versions: setup-java-ea-versions-zulu:
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }} name: zulu ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
needs: setup-java-major-minor-versions needs: setup-java-major-minor-versions
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: os: [macos-15-intel, windows-latest, ubuntu-latest]
- {os: macos-15-intel, version: '17-ea', distribution: zulu} version: ['17-ea', '15.0.0-ea.14']
- {os: windows-latest, version: '17-ea', distribution: zulu}
- {os: ubuntu-latest, version: '17-ea', distribution: zulu}
- {os: macos-15-intel, version: '15.0.0-ea.14', distribution: zulu}
- {os: windows-latest, version: '15.0.0-ea.14', distribution: zulu}
- {os: ubuntu-latest, version: '15.0.0-ea.14', distribution: zulu}
- {os: macos-latest, version: '17-ea', distribution: temurin}
- {os: windows-latest, version: '17-ea', distribution: temurin}
- {os: ubuntu-latest, version: '17-ea', distribution: temurin}
- {os: macos-latest, version: '17-ea', distribution: sapmachine}
- {os: windows-latest, version: '17-ea', distribution: sapmachine}
- {os: ubuntu-latest, version: '17-ea', distribution: sapmachine}
- {os: macos-latest, version: '21-ea', distribution: sapmachine}
- {os: windows-latest, version: '21-ea', distribution: sapmachine}
- {os: ubuntu-latest, version: '21-ea', distribution: sapmachine}
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
with: with:
java-version: ${{ matrix.version }} java-version: ${{ matrix.version }}
distribution: ${{ matrix.distribution }} distribution: zulu
- name: Verify Java - name: Verify Java
env: env:
JAVA_VERSION: ${{ matrix.version }} JAVA_VERSION: ${{ matrix.version }}
@@ -321,24 +321,53 @@ jobs:
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH" run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash shell: bash
setup-java-signature-verification: setup-java-ea-versions-temurin:
name: ${{ matrix.distribution }} ${{ matrix.version }} signature verification - ${{ matrix.os }} name: temurin ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
needs: setup-java-major-minor-versions needs: setup-java-major-minor-versions
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: *default_os os: [macos-latest, windows-latest, ubuntu-latest]
version: ['21', '17'] version: ['17-ea']
distribution: [temurin, microsoft]
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java
uses: ./
id: setup-java
with:
java-version: ${{ matrix.version }}
distribution: temurin
- name: Verify Java
env:
JAVA_VERSION: ${{ matrix.version }}
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash
setup-java-temurin-signature-verification:
name: temurin ${{ matrix.version }} signature verification - ${{ matrix.os }}
needs: setup-java-major-minor-versions
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
version: ['21', '17']
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java with signature verification - name: setup-java with signature verification
uses: ./ uses: ./
id: setup-java id: setup-java
with: with:
java-version: ${{ matrix.version }} java-version: ${{ matrix.version }}
distribution: ${{ matrix.distribution }} distribution: temurin
verify-signature: true verify-signature: true
- name: Verify Java - name: Verify Java
env: env:
@@ -347,6 +376,61 @@ jobs:
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH" run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash shell: bash
setup-java-microsoft-signature-verification:
name: microsoft ${{ matrix.version }} signature verification - ${{ matrix.os }}
needs: setup-java-major-minor-versions
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
version: ['21', '17']
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java with signature verification
uses: ./
id: setup-java
with:
java-version: ${{ matrix.version }}
distribution: microsoft
verify-signature: true
- name: Verify Java
env:
JAVA_VERSION: ${{ matrix.version }}
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash
setup-java-ea-versions-sapmachine:
name: sapmachine ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
needs: setup-java-major-minor-versions
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
version: ['17-ea', '21-ea']
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java
uses: ./
id: setup-java
with:
java-version: ${{ matrix.version }}
distribution: sapmachine
- name: Verify Java
env:
JAVA_VERSION: ${{ matrix.version }}
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash
setup-java-custom-package-type: setup-java-custom-package-type:
name: ${{ matrix.distribution }} ${{ matrix.version }} (${{ matrix.java-package }}-x64) - ${{ matrix.os }} name: ${{ matrix.distribution }} ${{ matrix.version }} (${{ matrix.java-package }}-x64) - ${{ matrix.os }}
needs: setup-java-major-minor-versions needs: setup-java-major-minor-versions
@@ -426,7 +510,10 @@ jobs:
os: ubuntu-latest os: ubuntu-latest
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -456,7 +543,10 @@ jobs:
distribution: ['liberica', 'zulu', 'corretto'] distribution: ['liberica', 'zulu', 'corretto']
version: ['11'] version: ['11']
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -477,11 +567,14 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: *default_os os: [macos-latest, windows-latest, ubuntu-latest]
distribution: ['temurin', 'microsoft', 'corretto'] distribution: ['temurin', 'microsoft', 'corretto']
java-version-file: ['.java-version', '.tool-versions'] java-version-file: ['.java-version', '.tool-versions']
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "17" > .java-version run: echo "17" > .java-version
@@ -507,11 +600,14 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: *default_os os: [macos-latest, windows-latest, ubuntu-latest]
distribution: ['temurin', 'zulu', 'liberica', 'microsoft', 'corretto'] distribution: ['temurin', 'zulu', 'liberica', 'microsoft', 'corretto']
java-version-file: ['.java-version', '.tool-versions'] java-version-file: ['.java-version', '.tool-versions']
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "11" > .java-version run: echo "11" > .java-version
@@ -536,11 +632,14 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: *default_os os: [macos-latest, windows-latest, ubuntu-latest]
distribution: ['adopt', 'adopt-openj9', 'zulu'] distribution: ['adopt', 'adopt-openj9', 'zulu']
java-version-file: ['.java-version', '.tool-versions'] java-version-file: ['.java-version', '.tool-versions']
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "17.0.10" > .java-version run: echo "17.0.10" > .java-version
@@ -565,11 +664,14 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: *default_os os: [macos-latest, windows-latest, ubuntu-latest]
distribution: ['adopt', 'zulu', 'liberica'] distribution: ['adopt', 'zulu', 'liberica']
java-version-file: ['.java-version', '.tool-versions', '.sdkmanrc'] java-version-file: ['.java-version', '.tool-versions', '.sdkmanrc']
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "openjdk64-17.0.10" > .java-version run: echo "openjdk64-17.0.10" > .java-version
@@ -598,9 +700,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: *default_os os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- *checkout_step - name: Checkout
uses: actions/checkout@v7
- name: Setup Java 17 as default - name: Setup Java 17 as default
uses: ./ uses: ./
id: setup-java-17 id: setup-java-17
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: "@actions/cache" name: "@actions/cache"
version: 6.2.0 version: 6.1.0
type: npm type: npm
summary: Actions cache lib summary: Actions cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/cache homepage: https://github.com/actions/toolkit/tree/main/packages/cache
+106 -117
View File
@@ -20,18 +20,7 @@ This action allows you to work with Java and Scala projects.
## What's new in V6 ## What's new in V6
> [!NOTE] - **Migrated to ESM** to enable support for the latest `@actions/*` package versions. This is an internal implementation change only. No changes are required to your workflow configuration, and the action's behavior is unchanged. Existing workflows continue to work as before.
> V6 is still in development (`main` branch) and is not yet recommended for production workflows.
- **Migrated to ESM** to enable support for the latest `@actions/*` package versions. This is an internal implementation change.
## Breaking changes in V6
- **Renamed inputs that accept environment-variable names** to make it clear that their values are not credentials. Replace `server-username`, `server-password`, and `gpg-passphrase` with `server-username-env-var`, `server-password-env-var`, and `gpg-passphrase-env-var`, respectively. The old names remain as deprecated aliases and emit a warning when used.
- **The GPG passphrase is now passed to the Maven GPG Plugin through an environment variable (`gpg.passphraseEnvName`) instead of the deprecated `gpg.passphrase` server in `settings.xml`.** Set the environment variable name with `gpg-passphrase-env-var`, which defaults to `GPG_PASSPHRASE`. This requires `maven-gpg-plugin` **3.2.0 or newer**; older versions do not honor `gpg.passphraseEnvName` and, because the `gpg.passphrase` server is no longer written, will not pick up the passphrase. Upgrade the plugin to 3.2.0+.
See [GPG](docs/advanced-usage.md#gpg) for details.
## Breaking changes in V5 ## Breaking changes in V5
@@ -42,79 +31,73 @@ For more details, see the full release notes on the [releases page](https://git
## Usage ## Usage
- `java-version`: The Java version that is going to be set up. Takes a whole or [semver](#supported-version-syntax) Java version. If not specified, the action will expect `java-version-file` input to be specified. - `java-version`: The Java version that is going to be set up. Takes a whole or [semver](#supported-version-syntax) Java version. If not specified, the action will expect `java-version-file` input to be specified.
- `java-version-file`: The path to a file containing java version. Supported file types are `.java-version`, `.tool-versions`, and `.sdkmanrc`. See more details in [about .java-version-file](docs/advanced-usage.md#Java-version-file). - `java-version-file`: The path to a file containing java version. Supported file types are `.java-version`, `.tool-versions`, and `.sdkmanrc`. See more details in [about .java-version-file](docs/advanced-usage.md#Java-version-file).
- `distribution`: Java [distribution](#supported-distributions). Required unless `java-version-file` points to `.sdkmanrc` with a recognized distribution suffix (for example `java=21.0.5-tem`). - `distribution`: Java [distribution](#supported-distributions). Required unless `java-version-file` points to `.sdkmanrc` with a recognized distribution suffix (for example `java=21.0.5-tem`).
- `java-package`: The packaging variant of the chosen distribution. Possible values: `jdk`, `jre`, `jdk+fx`, `jre+fx`. For Azul Zulu, `jdk+crac` and `jre+crac` are also supported. Default value: `jdk`. - `java-package`: The packaging variant of the chosen distribution. Possible values: `jdk`, `jre`, `jdk+fx`, `jre+fx`. For Azul Zulu, `jdk+crac` and `jre+crac` are also supported. Default value: `jdk`.
- `architecture`: The target architecture of the package. Possible values: `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`. Default value: Derived from the runner machine. - `architecture`: The target architecture of the package. Possible values: `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`. Default value: Derived from the runner machine.
- `jdk-file`: If a use-case requires a custom distribution setup-java uses the compressed JDK from the location pointed by this input and will take care of the installation and caching on the VM. Note: `distribution` must be set to 'jdkfile' (case-sensitive; all lowercase) when using this option. (The camelCase `jdkFile` input is still accepted as a deprecated alias and may be removed in a future release.) - `jdk-file`: If a use-case requires a custom distribution setup-java uses the compressed JDK from the location pointed by this input and will take care of the installation and caching on the VM. Note: `distribution` must be set to 'jdkfile' (case-sensitive; all lowercase) when using this option. (The camelCase `jdkFile` input is still accepted as a deprecated alias and may be removed in a future release.)
- `check-latest`: Setting this option makes the action to check for the latest available version for the version spec. - `check-latest`: Setting this option makes the action to check for the latest available version for the version spec.
- `set-default`: Set to `false` to install a JDK without making it the default. When `false`, `JAVA_HOME` and `PATH` are not updated, but `JAVA_HOME_<major>_<arch>` is still set so the JDK remains discoverable. Default value: `true`. See [Installing JDK without setting as default](docs/advanced-usage.md#Installing-JDK-without-setting-as-default) for more details. - `set-default`: Set to `false` to install a JDK without making it the default. When `false`, `JAVA_HOME` and `PATH` are not updated, but `JAVA_HOME_<major>_<arch>` is still set so the JDK remains discoverable. Default value: `true`. See [Installing JDK without setting as default](docs/advanced-usage.md#Installing-JDK-without-setting-as-default) for more details.
- `problem-matcher`: Set to `false` to disable Java problem matcher annotations (compiler diagnostics and uncaught exceptions). Default value: `true`. See [Java problem matcher](docs/advanced-usage.md#java-problem-matcher-compiler-annotations) for details and annotation limits. - `verify-signature`: Verifies downloaded Java package signatures when supported by the selected distribution. Currently supported for `temurin` and `microsoft`. If set to `true` for unsupported distributions, the action fails.
- `verify-signature`: Verifies downloaded Java package signatures when supported by the selected distribution. Currently supported for `temurin` and `microsoft`. If set to `true` for unsupported distributions, the action fails. - `verify-signature-public-key`: ASCII-armored GPG public key used to verify the downloaded package signature. Overrides the default bundled key for the selected distribution.
- `verify-signature-public-key`: ASCII-armored GPG public key used to verify the downloaded package signature. Overrides the default bundled key for the selected distribution. - `cache`: Quick [setup caching](#caching-packages-dependencies) for the dependencies managed through one of the predefined package managers. It can be one of "maven", "gradle" or "sbt".
- `token`: The token used to authenticate when fetching version manifests hosted on GitHub.com. Defaults to `${{ github.token }}` when running on GitHub.com; defaults to an empty string on GitHub Enterprise Server. On GHES, provide a GitHub.com personal access token if manifest requests are rate-limited. See [Using Microsoft distribution on GHES](docs/advanced-usage.md#using-microsoft-distribution-on-ghes) for more details. - `cache-dependency-path`: The path to a dependency file: pom.xml, build.gradle, build.sbt, etc. This option can be used with the `cache` option. If this option is omitted, the action searches for the dependency file in the entire repository. This option supports wildcards and a list of file names for caching multiple dependencies.
- `cache`: Quick [setup caching](#caching-packages-dependencies) for the dependencies managed through one of the predefined package managers. It can be one of "maven", "gradle" or "sbt".
- `cache-dependency-path`: The path to a dependency file: pom.xml, build.gradle, build.sbt, etc. This option can be used with the `cache` option. If this option is omitted, the action searches for the dependency file in the entire repository. This option supports wildcards and a list of file names for caching multiple dependencies.
#### Maven options #### Maven options
The action has a bunch of inputs to generate maven's [settings.xml](https://maven.apache.org/settings.html) on the fly and pass the values to Apache Maven GPG Plugin as well as Apache Maven Toolchains. See [advanced usage](docs/advanced-usage.md) for more. The action has a bunch of inputs to generate maven's [settings.xml](https://maven.apache.org/settings.html) on the fly and pass the values to Apache Maven GPG Plugin as well as Apache Maven Toolchains. See [advanced usage](docs/advanced-usage.md) for more.
- `overwrite-settings`: By default action overwrites the settings.xml. In order to skip generation of file if it exists, set this to `false`. - `overwrite-settings`: By default action overwrites the settings.xml. In order to skip generation of file if it exists, set this to `false`.
- `server-id`: ID of the distributionManagement repository in the pom.xml file. Default is `github`. - `server-id`: ID of the distributionManagement repository in the pom.xml file. Default is `github`.
- `server-username-env-var`: Environment variable name for the username for authentication to the Apache Maven repository. Default is GITHUB\_ACTOR. - `server-username`: Environment variable name for the username for authentication to the Apache Maven repository. Default is GITHUB_ACTOR.
- `server-password-env-var`: Environment variable name for password or token for authentication to the Apache Maven repository. Default is GITHUB\_TOKEN. - `server-password`: Environment variable name for password or token for authentication to the Apache Maven repository. Default is GITHUB_TOKEN.
- `settings-path`: Maven related setting to point to the directory where the settings.xml file will be written. Default is \~/.m2. - `settings-path`: Maven related setting to point to the directory where the settings.xml file will be written. Default is ~/.m2.
- `gpg-private-key`: GPG private key to import. Default is empty string. - `gpg-private-key`: GPG private key to import. Default is empty string.
- `gpg-passphrase-env-var`: Environment variable name for the GPG private key passphrase. Default is GPG\_PASSPHRASE. - `gpg-passphrase`: Environment variable name for the GPG private key passphrase. Default is GPG_PASSPHRASE.
- `mvn-toolchain-id`: Name of Maven Toolchain ID if the default name of `${distribution}_${java-version}` is not wanted. - `mvn-toolchain-id`: Name of Maven Toolchain ID if the default name of `${distribution}_${java-version}` is not wanted.
- `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted. - `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted.
- `show-download-progress`: Set to `true` to keep Maven artifact download and transfer progress in build logs. Default value: `false`. By default, the action adds `-ntp` (`--no-transfer-progress`) to `MAVEN_ARGS`. This input has no effect on non-Maven builds. See [Maven transfer progress](docs/advanced-usage.md#maven-transfer-progress-download-logs) for more details.
### Basic Configuration ### Basic Configuration
#### Eclipse Temurin #### Eclipse Temurin
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v6
- uses: actions/setup-java@v6 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '25' java-version: '25'
- run: java --version - run: java --version
``` ```
#### Azul Zulu OpenJDK #### Azul Zulu OpenJDK
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v6
- uses: actions/setup-java@v6 - uses: actions/setup-java@v5
with: with:
distribution: 'zulu' # See 'Supported distributions' for available options distribution: 'zulu' # See 'Supported distributions' for available options
java-version: '25' java-version: '25'
- run: java --version - run: java --version
``` ```
#### Supported version syntax #### Supported version syntax
@@ -180,26 +163,24 @@ The workflow output `cache-primary-key` exposes the primary cache key computed b
The cache input is optional, and caching is turned off by default. The cache input is optional, and caching is turned off by default.
**Maven Wrapper:** when `cache: 'maven'` is enabled, the action also caches and restores the Maven Wrapper distribution downloaded to `~/.m2/wrapper/dists` (in addition to the local repository), so wrapper-based (`./mvnw`) builds don't re-download the Maven distribution. The wrapper distribution is stored in a **separate** cache entry keyed only on `**/.mvn/wrapper/maven-wrapper.properties`, so it stays cached across the frequent `pom.xml` changes that rotate the main dependency cache key. **Maven Wrapper:** when `cache: 'maven'` is enabled, the action also caches and restores the Maven Wrapper distribution downloaded to `~/.m2/wrapper/dists` (in addition to the local repository), so wrapper-based (`./mvnw`) builds don't re-download the wrapper on every run. This is keyed on `**/.mvn/wrapper/maven-wrapper.properties` as shown above.
#### Caching gradle dependencies #### Caching gradle dependencies
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v6
- uses: actions/setup-java@v6 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '25' java-version: '25'
cache: 'gradle' cache: 'gradle'
cache-dependency-path: | # optional cache-dependency-path: | # optional
sub-project/*.gradle* sub-project/*.gradle*
sub-project/**/gradle-wrapper.properties sub-project/**/gradle-wrapper.properties
- run: ./gradlew build --no-daemon - run: ./gradlew build --no-daemon
``` ```
Using the `cache: gradle` provides a simple and effective way to cache Gradle dependencies with minimal configuration. Using the `cache: gradle` provides a simple and effective way to cache Gradle dependencies with minimal configuration.
**Gradle Wrapper:** when `cache: 'gradle'` is enabled, the action also caches and restores the Gradle Wrapper distribution downloaded to `~/.gradle/wrapper` (in addition to the Gradle caches), so wrapper-based (`./gradlew`) builds don't re-download the Gradle distribution. The wrapper distribution is stored in a **separate** cache entry keyed only on `**/gradle-wrapper.properties`, so it stays cached across the frequent `*.gradle*` changes that rotate the main dependency cache key.
For projects that require more advanced `Gradle` caching features, such as caching build outputs, support for Gradle configuration cache, encrypted cache storage, fine-grained cache control (including options to enable or disable the cache, set it to read-only or write-only, perform automated cleanup, and define custom cache rules), or optimized performance for complex CI workflows, consider using [`gradle/actions/setup-gradle`](https://github.com/gradle/actions/tree/main/setup-gradle). For projects that require more advanced `Gradle` caching features, such as caching build outputs, support for Gradle configuration cache, encrypted cache storage, fine-grained cache control (including options to enable or disable the cache, set it to read-only or write-only, perform automated cleanup, and define custom cache rules), or optimized performance for complex CI workflows, consider using [`gradle/actions/setup-gradle`](https://github.com/gradle/actions/tree/main/setup-gradle).
For setup details and a comprehensive overview of all available features, visit the [setup-gradle documentation](https://github.com/gradle/actions/blob/main/docs/setup-gradle.md). For setup details and a comprehensive overview of all available features, visit the [setup-gradle documentation](https://github.com/gradle/actions/blob/main/docs/setup-gradle.md).
@@ -207,15 +188,15 @@ For setup details and a comprehensive overview of all available features, visit
#### Caching maven dependencies #### Caching maven dependencies
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v6
- uses: actions/setup-java@v6 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '25' java-version: '25'
cache: 'maven' cache: 'maven'
cache-dependency-path: 'sub-project/pom.xml' # optional cache-dependency-path: 'sub-project/pom.xml' # optional
- name: Build with Maven - name: Build with Maven
run: mvn package --file pom.xml run: mvn -B package --file pom.xml
``` ```
> [!NOTE] > [!NOTE]
@@ -228,17 +209,17 @@ steps:
#### Caching sbt dependencies #### Caching sbt dependencies
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v6
- uses: actions/setup-java@v6 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '25' java-version: '25'
cache: 'sbt' cache: 'sbt'
cache-dependency-path: | # optional cache-dependency-path: | # optional
sub-project/build.sbt sub-project/build.sbt
sub-project/project/build.properties sub-project/project/build.properties
- name: Build with SBT - name: Build with SBT
run: sbt package run: sbt package
``` ```
#### Cache segment restore timeout #### Cache segment restore timeout
@@ -248,13 +229,13 @@ Usually, cache gets downloaded in multiple segments of fixed sizes. Sometimes, a
env: env:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: '5' SEGMENT_DOWNLOAD_TIMEOUT_MINS: '5'
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v6
- uses: actions/setup-java@v6 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '25' java-version: '25'
cache: 'gradle' cache: 'gradle'
- run: ./gradlew build --no-daemon - run: ./gradlew build --no-daemon
``` ```
### Check latest ### Check latest
@@ -268,13 +249,13 @@ For Java distributions that are not cached on Hosted images, `check-latest` alwa
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v6
- uses: actions/setup-java@v6 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '25' java-version: '25'
check-latest: true check-latest: true
- run: java --version - run: java --version
``` ```
### Testing against different Java versions ### Testing against different Java versions
@@ -287,9 +268,9 @@ jobs:
java: [ '8', '11', '17', '21', '25' ] java: [ '8', '11', '17', '21', '25' ]
name: Java ${{ matrix.Java }} sample name: Java ${{ matrix.Java }} sample
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v6
- name: Setup java - name: Setup java
uses: actions/setup-java@v6 uses: actions/setup-java@v5
with: with:
distribution: '<distribution>' distribution: '<distribution>'
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
@@ -298,11 +279,11 @@ jobs:
### Install multiple JDKs ### Install multiple JDKs
All configured Java versions are added to the PATH. The last one added to the PATH (i.e., the last JDK set up by this action) will be used as the default and available globally. Other Java versions can be accessed through environment variables such as 'JAVA\_HOME\_{{ MAJOR\_VERSION }}\_{{ ARCHITECTURE }}'. To use a specific Java version, set the JAVA\_HOME environment variable accordingly and prepend its bin directory to the PATH to ensure it takes priority during execution. All configured Java versions are added to the PATH. The last one added to the PATH (i.e., the last JDK set up by this action) will be used as the default and available globally. Other Java versions can be accessed through environment variables such as 'JAVA_HOME_{{ MAJOR_VERSION }}_{{ ARCHITECTURE }}'. To use a specific Java version, set the JAVA_HOME environment variable accordingly and prepend its bin directory to the PATH to ensure it takes priority during execution.
```yaml ```yaml
steps: steps:
- uses: actions/setup-java@v6 - uses: actions/setup-java@v5
with: with:
distribution: '<distribution>' distribution: '<distribution>'
java-version: | java-version: |
@@ -317,31 +298,39 @@ In the example above multiple JDKs are installed for the same job. The result af
### Advanced Configuration ### Advanced Configuration
- [Selecting a Java distribution](docs/advanced-usage.md#Selecting-a-Java-distribution) - [Selecting a Java distribution](docs/advanced-usage.md#Selecting-a-Java-distribution)
- [Eclipse Temurin](docs/advanced-usage.md#Eclipse-Temurin) - [Eclipse Temurin](docs/advanced-usage.md#Eclipse-Temurin)
- [Adopt](docs/advanced-usage.md#Adopt) - [Adopt](docs/advanced-usage.md#Adopt)
- [Zulu](docs/advanced-usage.md#Zulu) - [Zulu](docs/advanced-usage.md#Zulu)
- [Liberica](docs/advanced-usage.md#Liberica) - [Liberica](docs/advanced-usage.md#Liberica)
- [Liberica Native Image Kit](docs/advanced-usage.md#Liberica-Native-Image-Kit) - [Liberica Native Image Kit](docs/advanced-usage.md#Liberica-Native-Image-Kit)
- [Microsoft](docs/advanced-usage.md#Microsoft) - [Microsoft](docs/advanced-usage.md#Microsoft)
- [Amazon Corretto](docs/advanced-usage.md#Amazon-Corretto) - [Amazon Corretto](docs/advanced-usage.md#Amazon-Corretto)
- [Oracle](docs/advanced-usage.md#Oracle) - [Oracle](docs/advanced-usage.md#Oracle)
- [Alibaba Dragonwell](docs/advanced-usage.md#Alibaba-Dragonwell) - [Alibaba Dragonwell](docs/advanced-usage.md#Alibaba-Dragonwell)
- [SapMachine](docs/advanced-usage.md#SapMachine) - [SapMachine](docs/advanced-usage.md#SapMachine)
- [GraalVM](docs/advanced-usage.md#GraalVM) - [GraalVM](docs/advanced-usage.md#GraalVM)
- [JetBrains](docs/advanced-usage.md#JetBrains) - [JetBrains](docs/advanced-usage.md#JetBrains)
- [Tencent Kona](docs/advanced-usage.md#Tencent-Kona) - [Tencent Kona](docs/advanced-usage.md#Tencent-Kona)
- [Installing custom Java package type](docs/advanced-usage.md#Installing-custom-Java-package-type) - [Installing custom Java package type](docs/advanced-usage.md#Installing-custom-Java-package-type)
- [Installing custom Java architecture](docs/advanced-usage.md#Installing-custom-Java-architecture) - [Installing custom Java architecture](docs/advanced-usage.md#Installing-custom-Java-architecture)
- [Installing custom Java distribution from local file](docs/advanced-usage.md#Installing-Java-from-local-file) - [Installing custom Java distribution from local file](docs/advanced-usage.md#Installing-Java-from-local-file)
- [Testing against different Java distributions](docs/advanced-usage.md#Testing-against-different-Java-distributions) - [Testing against different Java distributions](docs/advanced-usage.md#Testing-against-different-Java-distributions)
- [Testing against different platforms](docs/advanced-usage.md#Testing-against-different-platforms) - [Testing against different platforms](docs/advanced-usage.md#Testing-against-different-platforms)
- [Publishing using Apache Maven](docs/advanced-usage.md#Publishing-using-Apache-Maven) - [Publishing using Apache Maven](docs/advanced-usage.md#Publishing-using-Apache-Maven)
- [Maven transfer progress (download logs)](docs/advanced-usage.md#maven-transfer-progress-download-logs)
- [Publishing using Gradle](docs/advanced-usage.md#Publishing-using-Gradle) - [Publishing using Gradle](docs/advanced-usage.md#Publishing-using-Gradle)
- [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache) - [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache)
- [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains) - [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains)
- [Java Version File](docs/advanced-usage.md#Java-version-file) - [Java Version File](docs/advanced-usage.md#Java-version-file)
## V2 vs V1
Examples in this README use `actions/setup-java@v5`, but the main migration note from V1 still applies to all later major versions (`v2`, `v3`, `v4`, and `v5`):
- Starting with V2, the action supports custom distributions. V1 supports only Azul Zulu OpenJDK.
- Starting with V2, you must specify distribution along with the version. V1 defaults to Azul Zulu OpenJDK, so only version input is required. Follow [the migration guide](docs/switching-to-v2.md) to switch from V1 to V2.
For information about the latest releases, recent updates, and newly supported distributions, please refer to the `setup-java` [Releases](https://github.com/actions/setup-java/releases).
## Recommended permissions ## Recommended permissions
When using the `setup-java` action in your GitHub Actions workflow, it is recommended to set the following permissions to ensure proper functionality: When using the `setup-java` action in your GitHub Actions workflow, it is recommended to set the following permissions to ensure proper functionality:
+2 -84
View File
@@ -228,40 +228,9 @@ describe('auth tests', () => {
<username>\${env.${username}}</username> <username>\${env.${username}}</username>
<password>\${env.&amp;&lt;&gt;"''"&gt;&lt;&amp;}</password> <password>\${env.&amp;&lt;&gt;"''"&gt;&lt;&amp;}</password>
</server> </server>
</servers>
<profiles>
<profile>
<id>setup-java-gpg</id>
<properties>
<gpg.passphraseEnvName>${gpgPassphrase}</gpg.passphraseEnvName>
</properties>
</profile>
</profiles>
<activeProfiles>
<activeProfile>setup-java-gpg</activeProfile>
</activeProfiles>
</settings>`;
expect(auth.generate(id, username, password, gpgPassphrase)).toEqual(
expectedSettings
);
});
it('does not add a gpg profile when the passphrase env var is the maven-gpg-plugin default', () => {
const id = 'packages';
const username = 'USER';
const password = '&<>"\'\'"><&';
const gpgPassphrase = 'MAVEN_GPG_PASSPHRASE';
const expectedSettings = `<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<interactiveMode>false</interactiveMode>
<servers>
<server> <server>
<id>${id}</id> <id>gpg.passphrase</id>
<username>\${env.${username}}</username> <passphrase>\${env.${gpgPassphrase}}</passphrase>
<password>\${env.&amp;&lt;&gt;"''"&gt;&lt;&amp;}</password>
</server> </server>
</servers> </servers>
</settings>`; </settings>`;
@@ -270,55 +239,4 @@ describe('auth tests', () => {
expectedSettings expectedSettings
); );
}); });
it('uses deprecated input aliases and warns', () => {
const mockGetInput = core.getInput as jest.MockedFunction<
typeof core.getInput
>;
const mockWarning = core.warning as jest.MockedFunction<
typeof core.warning
>;
mockGetInput.mockImplementation(name =>
name === 'server-username' ? 'LEGACY_USERNAME' : ''
);
expect(
auth.getInputWithDeprecatedAlias(
'server-username-env-var',
'server-username',
'GITHUB_ACTOR'
)
).toBe('LEGACY_USERNAME');
expect(mockWarning).toHaveBeenCalledWith(
"The 'server-username' input is deprecated and may be removed in a future release. Please use 'server-username-env-var' instead."
);
mockGetInput.mockReset();
mockWarning.mockReset();
});
it('prefers the replacement input over its deprecated alias', () => {
const mockGetInput = core.getInput as jest.MockedFunction<
typeof core.getInput
>;
mockGetInput.mockImplementation(name => {
const inputs: Record<string, string> = {
'server-password-env-var': 'NEW_PASSWORD',
'server-password': 'LEGACY_PASSWORD'
};
return inputs[name] || '';
});
expect(
auth.getInputWithDeprecatedAlias(
'server-password-env-var',
'server-password',
'GITHUB_TOKEN'
)
).toBe('NEW_PASSWORD');
expect(core.warning).toHaveBeenCalled();
mockGetInput.mockReset();
(core.warning as jest.Mock).mockReset();
});
}); });
+12 -196
View File
@@ -166,7 +166,10 @@ describe('dependency cache', () => {
await restore('maven', ''); await restore('maven', '');
expect(spyCacheRestore).toHaveBeenCalledWith( expect(spyCacheRestore).toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'repository')], [
join(os.homedir(), '.m2', 'repository'),
join(os.homedir(), '.m2', 'wrapper', 'dists')
],
expect.any(String) expect.any(String)
); );
expect(spyGlobHashFiles).toHaveBeenCalledWith( expect(spyGlobHashFiles).toHaveBeenCalledWith(
@@ -193,7 +196,10 @@ describe('dependency cache', () => {
await restore('maven', ''); await restore('maven', '');
expect(spyCacheRestore).toHaveBeenCalledWith( expect(spyCacheRestore).toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'repository')], [
join(os.homedir(), '.m2', 'repository'),
join(os.homedir(), '.m2', 'wrapper', 'dists')
],
expect.any(String) expect.any(String)
); );
expect(spyGlobHashFiles).toHaveBeenCalledWith( expect(spyGlobHashFiles).toHaveBeenCalledWith(
@@ -208,7 +214,10 @@ describe('dependency cache', () => {
await restore('maven', ''); await restore('maven', '');
expect(spyCacheRestore).toHaveBeenCalledWith( expect(spyCacheRestore).toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'repository')], [
join(os.homedir(), '.m2', 'repository'),
join(os.homedir(), '.m2', 'wrapper', 'dists')
],
expect.any(String) expect.any(String)
); );
expect(spyGlobHashFiles).toHaveBeenCalledWith( expect(spyGlobHashFiles).toHaveBeenCalledWith(
@@ -217,47 +226,6 @@ describe('dependency cache', () => {
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('maven cache is not found'); expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
}); });
it('restores the maven wrapper distribution cache independently of the main cache', async () => {
createDirectory(join(workspace, '.mvn'));
createDirectory(join(workspace, '.mvn', 'wrapper'));
createFile(
join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
);
await restore('maven', '');
// Main dependency cache no longer carries the wrapper dists path.
expect(spyCacheRestore).toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'repository')],
expect.any(String)
);
expect(spyCacheRestore).toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'wrapper', 'dists')],
expect.stringContaining('maven-wrapper')
);
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/.mvn/wrapper/maven-wrapper.properties'
);
});
it('skips the maven wrapper cache when no wrapper properties exist', async () => {
createFile(join(workspace, 'pom.xml'));
spyGlobHashFiles.mockImplementation((pattern: string) =>
Promise.resolve(
pattern === '**/.mvn/wrapper/maven-wrapper.properties'
? ''
: 'hash-stub'
)
);
await restore('maven', '');
// Only the main dependency cache is restored; the wrapper cache path is
// never touched because the project does not use mvnw.
expect(spyCacheRestore).toHaveBeenCalledTimes(1);
expect(spyCacheRestore).toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'repository')],
expect.any(String)
);
expect(spyWarning).not.toHaveBeenCalled();
});
}); });
describe('for gradle', () => { describe('for gradle', () => {
it('throws error if no build.gradle found', async () => { it('throws error if no build.gradle found', async () => {
@@ -314,43 +282,6 @@ describe('dependency cache', () => {
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found'); expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
}); });
it('restores the gradle wrapper distribution cache independently of the main cache', async () => {
createFile(join(workspace, 'build.gradle'));
await restore('gradle', '');
// Main dependency cache no longer carries the wrapper path.
expect(spyCacheRestore).toHaveBeenCalledWith(
[join(os.homedir(), '.gradle', 'caches')],
expect.any(String)
);
// Wrapper distribution is restored on its own, keyed only on the
// wrapper properties file.
expect(spyCacheRestore).toHaveBeenCalledWith(
[join(os.homedir(), '.gradle', 'wrapper')],
expect.stringContaining('setup-java-')
);
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/gradle-wrapper.properties'
);
});
it('skips the gradle wrapper cache when no wrapper properties exist', async () => {
createFile(join(workspace, 'build.gradle'));
spyGlobHashFiles.mockImplementation((pattern: string) =>
Promise.resolve(
pattern === '**/gradle-wrapper.properties' ? '' : 'hash-stub'
)
);
await restore('gradle', '');
// Only the main dependency cache is restored; the wrapper cache path is
// never touched because the project does not use the gradle wrapper.
expect(spyCacheRestore).toHaveBeenCalledTimes(1);
expect(spyCacheRestore).toHaveBeenCalledWith(
[join(os.homedir(), '.gradle', 'caches')],
expect.any(String)
);
expect(spyWarning).not.toHaveBeenCalled();
});
}); });
describe('for sbt', () => { describe('for sbt', () => {
it('throws error if no build.sbt found', async () => { it('throws error if no build.sbt found', async () => {
@@ -526,77 +457,6 @@ describe('dependency cache', () => {
expect.stringMatching(/^Cache saved with the key:.*/) expect.stringMatching(/^Cache saved with the key:.*/)
); );
}); });
it('saves the maven wrapper distribution cache under its own key', async () => {
createFile(join(workspace, 'pom.xml'));
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
case 'cache-matched-key':
return 'setup-java-cache-matched-key';
case 'cache-primary-key-maven-wrapper':
return 'setup-java-maven-wrapper-key';
default:
return '';
}
});
await save('maven');
expect(spyCacheSave).toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'wrapper', 'dists')],
'setup-java-maven-wrapper-key'
);
expect(spyWarning).not.toHaveBeenCalled();
});
it('does not save the maven wrapper cache on an exact wrapper hit', async () => {
createFile(join(workspace, 'pom.xml'));
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
case 'cache-matched-key':
return 'setup-java-cache-matched-key';
case 'cache-primary-key-maven-wrapper':
case 'cache-matched-key-maven-wrapper':
return 'setup-java-maven-wrapper-key';
default:
return '';
}
});
await save('maven');
expect(spyCacheSave).not.toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'wrapper', 'dists')],
expect.any(String)
);
});
it('does not fail the post step when the wrapper distribution path is missing', async () => {
createFile(join(workspace, 'pom.xml'));
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
case 'cache-matched-key':
return 'setup-java-cache-matched-key';
case 'cache-primary-key-maven-wrapper':
return 'setup-java-maven-wrapper-key';
default:
return '';
}
});
spyCacheSave.mockImplementation((paths: string[]) =>
paths.includes(join(os.homedir(), '.m2', 'wrapper', 'dists'))
? Promise.reject(
new cache.ValidationError(
'Path Validation Error: Path(s) specified in the action for caching do(es) not exist'
)
)
: Promise.resolve(0)
);
await expect(save('maven')).resolves.toBeUndefined();
expect(spyWarning).not.toHaveBeenCalled();
});
}); });
describe('for gradle', () => { describe('for gradle', () => {
it('uploads cache even if no build.gradle found', async () => { it('uploads cache even if no build.gradle found', async () => {
@@ -649,50 +509,6 @@ describe('dependency cache', () => {
expect.stringMatching(/^Cache saved with the key:.*/) expect.stringMatching(/^Cache saved with the key:.*/)
); );
}); });
it('saves the gradle wrapper distribution cache under its own key', async () => {
createFile(join(workspace, 'build.gradle'));
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
case 'cache-matched-key':
return 'setup-java-cache-matched-key';
case 'cache-primary-key-gradle-wrapper':
return 'setup-java-gradle-wrapper-key';
default:
return '';
}
});
await save('gradle');
expect(spyCacheSave).toHaveBeenCalledWith(
[join(os.homedir(), '.gradle', 'wrapper')],
'setup-java-gradle-wrapper-key'
);
expect(spyWarning).not.toHaveBeenCalled();
});
it('does not save the gradle wrapper cache on an exact wrapper hit', async () => {
createFile(join(workspace, 'build.gradle'));
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
case 'cache-matched-key':
return 'setup-java-cache-matched-key';
case 'cache-primary-key-gradle-wrapper':
case 'cache-matched-key-gradle-wrapper':
return 'setup-java-gradle-wrapper-key';
default:
return '';
}
});
await save('gradle');
expect(spyCacheSave).not.toHaveBeenCalledWith(
[join(os.homedir(), '.gradle', 'wrapper')],
expect.any(String)
);
});
}); });
describe('for sbt', () => { describe('for sbt', () => {
it('uploads cache even if no build.sbt found', async () => { it('uploads cache even if no build.sbt found', async () => {
-11
View File
@@ -1,11 +0,0 @@
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.actions</groupId>
<artifactId>setup-java-maven2-example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
</project>
-1
View File
@@ -1 +0,0 @@
target/
-3
View File
@@ -1,3 +0,0 @@
ThisBuild / scalaVersion := "2.12.15"
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1"
-39
View File
@@ -1,39 +0,0 @@
#!/bin/sh
# Assert whether a directory exists, for use in the e2e cache workflows.
#
# Usage: check-dir.sh <dir> [present|absent]
#
# present (default): fail if <dir> does NOT exist, otherwise list its contents.
# absent: fail if <dir> DOES exist.
#
# Call with already-expanded paths (e.g. "$HOME/.gradle/caches") to avoid
# tilde-expansion pitfalls.
set -eu
if [ "$#" -lt 1 ]; then
echo "Usage: check-dir.sh <dir> [present|absent]" >&2
exit 2
fi
dir=$1
mode=${2:-present}
case "$mode" in
present)
if [ ! -d "$dir" ]; then
echo "::error::The $dir directory does not exist unexpectedly"
exit 1
fi
ls "$dir"
;;
absent)
if [ -d "$dir" ]; then
echo "::error::The $dir directory exists unexpectedly"
exit 1
fi
;;
*)
echo "::error::Unknown mode '$mode' (expected 'present' or 'absent')"
exit 1
;;
esac
-44
View File
@@ -1,44 +0,0 @@
import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
const mockGetInput = jest.fn<(...args: any[]) => any>();
const mockInfo = jest.fn<(...args: any[]) => any>();
const mockDebug = jest.fn<(...args: any[]) => any>();
jest.unstable_mockModule('@actions/core', () => ({
getInput: mockGetInput,
info: mockInfo,
debug: mockDebug,
warning: jest.fn(),
setSecret: jest.fn()
}));
const {configureProblemMatcher} = await import('../src/problem-matcher.js');
const {INPUT_PROBLEM_MATCHER} = await import('../src/constants.js');
describe('configureProblemMatcher', () => {
let inputs: Record<string, string>;
beforeEach(() => {
inputs = {};
mockGetInput.mockImplementation((name: string) => inputs[name] ?? '');
});
afterEach(() => {
jest.resetAllMocks();
});
it('registers the Java problem matcher by default', () => {
configureProblemMatcher('/matchers/java.json');
expect(mockInfo).toHaveBeenCalledWith('##[add-matcher]/matchers/java.json');
});
it('does not register the Java problem matcher when disabled', () => {
inputs[INPUT_PROBLEM_MATCHER] = 'false';
configureProblemMatcher('/matchers/java.json');
expect(mockInfo).not.toHaveBeenCalled();
expect(mockDebug).toHaveBeenCalledWith('Java problem matcher is disabled');
});
});
+5 -16
View File
@@ -46,20 +46,16 @@ inputs:
file. Default is `github`' file. Default is `github`'
required: false required: false
default: 'github' default: 'github'
server-username-env-var: server-username:
description: 'Environment variable name for the username for authentication description: 'Environment variable name for the username for authentication
to the Apache Maven repository. Default is $GITHUB_ACTOR' to the Apache Maven repository. Default is $GITHUB_ACTOR'
required: false required: false
server-username: default: 'GITHUB_ACTOR'
description: 'Deprecated alias for server-username-env-var' server-password:
required: false
server-password-env-var:
description: 'Environment variable name for password or token for description: 'Environment variable name for password or token for
authentication to the Apache Maven repository. Default is $GITHUB_TOKEN' authentication to the Apache Maven repository. Default is $GITHUB_TOKEN'
required: false required: false
server-password: default: 'GITHUB_TOKEN'
description: 'Deprecated alias for server-password-env-var'
required: false
settings-path: settings-path:
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.' description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
required: false required: false
@@ -71,11 +67,8 @@ inputs:
description: 'GPG private key to import. Default is empty string.' description: 'GPG private key to import. Default is empty string.'
required: false required: false
default: '' default: ''
gpg-passphrase-env-var:
description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set.'
required: false
gpg-passphrase: gpg-passphrase:
description: 'Deprecated alias for gpg-passphrase-env-var' description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set; ignored otherwise.'
required: false required: false
cache: cache:
description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".' description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".'
@@ -101,10 +94,6 @@ inputs:
description: 'Whether Maven should print artifact download/transfer progress to the build log. When "false" (default) the action sets "-ntp" (--no-transfer-progress) in MAVEN_ARGS to produce cleaner logs. Set to "true" to keep the progress output. Has no effect on non-Maven builds.' description: 'Whether Maven should print artifact download/transfer progress to the build log. When "false" (default) the action sets "-ntp" (--no-transfer-progress) in MAVEN_ARGS to produce cleaner logs. Set to "true" to keep the progress output. Has no effect on non-Maven builds.'
required: false required: false
default: false default: false
problem-matcher:
description: 'Whether to register the Java problem matcher (compiler errors/warnings and uncaught exceptions). Set to "false" to disable annotations.'
required: false
default: true
outputs: outputs:
distribution: distribution:
description: 'Distribution of Java that has been installed' description: 'Distribution of Java that has been installed'
+41 -250
View File
@@ -39023,7 +39023,7 @@ module.exports = { version: packageJson.version }
/***/ 4012: /***/ 4012:
/***/ ((module) => { /***/ ((module) => {
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.2.0","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.1","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.1","@actions/io":"^3.0.2","@azure/core-rest-pipeline":"^1.23.0","@azure/storage-blob":"^12.31.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.4"},"devDependencies":{"@protobuf-ts/plugin":"^2.11.1","@types/node":"^25.6.0","@types/semver":"^7.7.1","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}'); module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.1.0","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.1","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.1","@actions/io":"^3.0.2","@azure/core-rest-pipeline":"^1.23.0","@azure/storage-blob":"^12.31.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.4"},"devDependencies":{"@protobuf-ts/plugin":"^2.11.1","@types/node":"^25.6.0","@types/semver":"^7.7.1","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}');
/***/ }) /***/ })
@@ -44068,10 +44068,6 @@ const SystemTarPathOnWindows = `${process.env['SYSTEMDRIVE']}\\Windows\\System32
const TarFilename = 'cache.tar'; const TarFilename = 'cache.tar';
const ManifestFilename = 'manifest.txt'; const ManifestFilename = 'manifest.txt';
const CacheFileSizeLimit = 10 * Math.pow(1024, 3); // 10GiB per repository const CacheFileSizeLimit = 10 * Math.pow(1024, 3); // 10GiB per repository
// Prefix the cache backend embeds in a read-denial message (v2 twirp
// GetCacheEntryDownloadURL error or the GHES v1 `_apis/artifactcache` 403 body).
// Shared so cache.ts and cacheHttpClient.ts match the same contract value.
const constants_CacheReadDeniedMessagePrefix = 'cache read denied:';
//# sourceMappingURL=constants.js.map //# sourceMappingURL=constants.js.map
;// CONCATENATED MODULE: ./node_modules/@actions/cache/lib/internal/cacheUtils.js ;// CONCATENATED MODULE: ./node_modules/@actions/cache/lib/internal/cacheUtils.js
var cacheUtils_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { var cacheUtils_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
@@ -93952,24 +93948,6 @@ function config_getCacheServiceVersion() {
return 'v1'; return 'v1';
return process.env['ACTIONS_CACHE_SERVICE_V2'] ? 'v2' : 'v1'; return process.env['ACTIONS_CACHE_SERVICE_V2'] ? 'v2' : 'v1';
} }
// The cache-mode lattice: readable = {read, write}, writable = {write,
// write-only}, none = neither.
const KNOWN_CACHE_MODES = ['none', 'read', 'write', 'write-only'];
// The effective cache-mode exported by the runner, or '' when not set.
function config_getCacheMode() {
return (process.env['ACTIONS_CACHE_MODE'] || '').trim().toLowerCase();
}
// Unset or unrecognized modes are permissive so behavior matches today.
function config_isCacheReadable(mode) {
if (!KNOWN_CACHE_MODES.includes(mode))
return true;
return mode === 'read' || mode === 'write';
}
function isCacheWritable(mode) {
if (!KNOWN_CACHE_MODES.includes(mode))
return true;
return mode === 'write' || mode === 'write-only';
}
function getCacheServiceURL() { function getCacheServiceURL() {
const version = config_getCacheServiceVersion(); const version = config_getCacheServiceVersion();
// Based on the version of the cache service, we will determine which // Based on the version of the cache service, we will determine which
@@ -94019,7 +93997,6 @@ var cacheHttpClient_awaiter = (undefined && undefined.__awaiter) || function (th
function getCacheApiUrl(resource) { function getCacheApiUrl(resource) {
const baseUrl = getCacheServiceURL(); const baseUrl = getCacheServiceURL();
if (!baseUrl) { if (!baseUrl) {
@@ -94047,7 +94024,6 @@ function createHttpClient() {
} }
function getCacheEntry(keys, paths, options) { function getCacheEntry(keys, paths, options) {
return cacheHttpClient_awaiter(this, void 0, void 0, function* () { return cacheHttpClient_awaiter(this, void 0, void 0, function* () {
var _a;
const httpClient = createHttpClient(); const httpClient = createHttpClient();
const version = utils.getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive); const version = utils.getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`; const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
@@ -94061,12 +94037,6 @@ function getCacheEntry(keys, paths, options) {
return null; return null;
} }
if (!isSuccessStatusCode(response.statusCode)) { if (!isSuccessStatusCode(response.statusCode)) {
// Only surface the receiver's body for a `cache read denied:` policy denial
// so callers can dispatch on it; keep the generic message otherwise.
const errorMessage = (_a = response.error) === null || _a === void 0 ? void 0 : _a.message;
if (errorMessage === null || errorMessage === void 0 ? void 0 : errorMessage.includes(CacheReadDeniedMessagePrefix)) {
throw new Error(errorMessage);
}
throw new Error(`Cache service responded with ${response.statusCode}`); throw new Error(`Cache service responded with ${response.statusCode}`);
} }
const cacheResult = response.result; const cacheResult = response.result;
@@ -95327,7 +95297,6 @@ var cache_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
class ValidationError extends Error { class ValidationError extends Error {
constructor(message) { constructor(message) {
super(message); super(message);
@@ -95343,20 +95312,19 @@ class ReserveCacheError extends Error {
} }
} }
/** /**
* Stable prefix the cache service writes into the cache reservation response * Stable prefix the receiver writes into the cache reservation response when
* when the issuer downgraded the cache token to read-only (for example, because * the issuer downgraded the cache token to read-only (for example, because
* the run was triggered by an untrusted event). saveCacheV1 / saveCacheV2 * the run was triggered by an untrusted event). saveCacheV1 / saveCacheV2
* dispatch on this prefix to re-classify the failure as a CacheWriteDeniedError * dispatch on this prefix to re-classify the failure as a
* so consumers and tests can distinguish a policy denial from other reservation * CacheWriteDeniedError so consumers (and the outer catch arm) can
* failures. Internally it is logged as a non-fatal warning like other * distinguish a policy denial from other reservation failures.
* best-effort save failures.
*/ */
const CACHE_WRITE_DENIED_PREFIX = 'cache write denied:'; const CACHE_WRITE_DENIED_PREFIX = 'cache write denied:';
/** /**
* Raised when the cache backend refuses to reserve a writable cache entry * Raised when the cache backend refuses to reserve a writable cache entry
* because the JWT issued for this run was scoped read-only (for example, the * because the JWT issued for this run was scoped read-only (for example, the
* run was triggered by an event the repository administrator classified as * run was triggered by an event the repository administrator classified as
* untrusted). The service-supplied detail message always begins with * untrusted). The receiver-supplied detail message always begins with
* `cache write denied:` (the full error message includes additional context * `cache write denied:` (the full error message includes additional context
* like the cache key). * like the cache key).
* *
@@ -95372,19 +95340,6 @@ class CacheWriteDeniedError extends ReserveCacheError {
Object.setPrototypeOf(this, CacheWriteDeniedError.prototype); Object.setPrototypeOf(this, CacheWriteDeniedError.prototype);
} }
} }
// Re-exported from constants so consumers keep referencing it here; the shared
// value also drives detection in cacheHttpClient without duplicating the string.
const CACHE_READ_DENIED_PREFIX = (/* unused pure expression or super */ null && (CacheReadDeniedMessagePrefix));
// Raised when the cache backend denies a download URL because the run's token
// has no readable cache scopes. Caching is best-effort, so restoreCache logs a
// warning and reports a cache miss rather than rethrowing this.
class CacheReadDeniedError extends Error {
constructor(message) {
super(message);
this.name = 'CacheReadDeniedError';
Object.setPrototypeOf(this, CacheReadDeniedError.prototype);
}
}
class FinalizeCacheError extends Error { class FinalizeCacheError extends Error {
constructor(message) { constructor(message) {
super(message); super(message);
@@ -95439,12 +95394,6 @@ function restoreCache(paths_1, primaryKey_1, restoreKeys_1, options_1) {
const cacheServiceVersion = getCacheServiceVersion(); const cacheServiceVersion = getCacheServiceVersion();
core.debug(`Cache service version: ${cacheServiceVersion}`); core.debug(`Cache service version: ${cacheServiceVersion}`);
checkPaths(paths); checkPaths(paths);
const cacheMode = getCacheMode();
if (!isCacheReadable(cacheMode)) {
core.info(`Cache restore skipped: the effective cache-mode '${cacheMode}' does not permit reads.`);
core.debug(`Skipped restore for paths [${paths.join(', ')}] with primary key '${primaryKey}'.`);
return undefined;
}
switch (cacheServiceVersion) { switch (cacheServiceVersion) {
case 'v2': case 'v2':
return yield restoreCacheV2(paths, primaryKey, restoreKeys, options, enableCrossOsArchive); return yield restoreCacheV2(paths, primaryKey, restoreKeys, options, enableCrossOsArchive);
@@ -95466,7 +95415,6 @@ function restoreCache(paths_1, primaryKey_1, restoreKeys_1, options_1) {
*/ */
function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) { function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) { return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
var _a;
restoreKeys = restoreKeys || []; restoreKeys = restoreKeys || [];
const keys = [primaryKey, ...restoreKeys]; const keys = [primaryKey, ...restoreKeys];
core.debug('Resolved Keys:'); core.debug('Resolved Keys:');
@@ -95481,26 +95429,10 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
let archivePath = ''; let archivePath = '';
try { try {
// path are needed to compute version // path are needed to compute version
let cacheEntry; const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
try { compressionMethod,
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, { enableCrossOsArchive
compressionMethod, });
enableCrossOsArchive
});
}
catch (error) {
// The v1 artifact cache service returns HTTP 403 with a
// `cache read denied:` body when the run's token has no readable cache
// scopes. getCacheEntry lives in a dependency-free internal module and
// cannot import CacheReadDeniedError without a circular dependency, so it
// only surfaces the raw denial message; we classify it into the typed
// error here so the outer catch and consumers can dispatch on it.
const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : '';
if (errorMessage.includes(CACHE_READ_DENIED_PREFIX)) {
throw new CacheReadDeniedError(errorMessage);
}
throw error;
}
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) { if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
// Cache not found // Cache not found
return undefined; return undefined;
@@ -95529,9 +95461,7 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
} }
else { else {
// warn on cache restore failure and continue build // warn on cache restore failure and continue build
// Log server errors (5xx) as errors, all other errors as warnings. // Log server errors (5xx) as errors, all other errors as warnings
// A read denied by policy (CacheReadDeniedError) is not an HttpClientError
// so it falls here and is warned, treated as a cache miss.
if (typedError instanceof HttpClientError && if (typedError instanceof HttpClientError &&
typeof typedError.statusCode === 'number' && typeof typedError.statusCode === 'number' &&
typedError.statusCode >= 500) { typedError.statusCode >= 500) {
@@ -95566,7 +95496,6 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
*/ */
function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) { function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) { return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
var _a;
// Override UploadOptions to force the use of Azure // Override UploadOptions to force the use of Azure
options = Object.assign(Object.assign({}, options), { useAzureSdk: true }); options = Object.assign(Object.assign({}, options), { useAzureSdk: true });
restoreKeys = restoreKeys || []; restoreKeys = restoreKeys || [];
@@ -95588,20 +95517,7 @@ function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
restoreKeys, restoreKeys,
version: utils.getCacheVersion(paths, compressionMethod, enableCrossOsArchive) version: utils.getCacheVersion(paths, compressionMethod, enableCrossOsArchive)
}; };
let response; const response = yield twirpClient.GetCacheEntryDownloadURL(request);
try {
response = yield twirpClient.GetCacheEntryDownloadURL(request);
}
catch (error) {
// The receiver returns twirp PermissionDenied (403) when the run's token
// has no readable cache scopes. The client wraps that 403, so the stable
// prefix is embedded in the message rather than leading it.
const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : '';
if (errorMessage.includes(CACHE_READ_DENIED_PREFIX)) {
throw new CacheReadDeniedError(errorMessage);
}
throw error;
}
if (!response.ok) { if (!response.ok) {
core.debug(`Cache not found for version ${request.version} of keys: ${keys.join(', ')}`); core.debug(`Cache not found for version ${request.version} of keys: ${keys.join(', ')}`);
return undefined; return undefined;
@@ -95636,10 +95552,8 @@ function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
throw error; throw error;
} }
else { else {
// Suppress all non-validation cache related errors because caching should be optional // Supress all non-validation cache related errors because caching should be optional
// Log server errors (5xx) as errors, all other errors as warnings. // Log server errors (5xx) as errors, all other errors as warnings
// A read denied by policy (CacheReadDeniedError) is not an HttpClientError
// so it falls here and is warned, treated as a cache miss.
if (typedError instanceof HttpClientError && if (typedError instanceof HttpClientError &&
typeof typedError.statusCode === 'number' && typeof typedError.statusCode === 'number' &&
typedError.statusCode >= 500) { typedError.statusCode >= 500) {
@@ -95678,12 +95592,6 @@ function cache_saveCache(paths_1, key_1, options_1) {
core_debug(`Cache service version: ${cacheServiceVersion}`); core_debug(`Cache service version: ${cacheServiceVersion}`);
checkPaths(paths); checkPaths(paths);
checkKey(key); checkKey(key);
const cacheMode = config_getCacheMode();
if (!isCacheWritable(cacheMode)) {
info(`Cache save skipped: the effective cache-mode '${cacheMode}' does not permit writes.`);
core_debug(`Skipped save for paths [${paths.join(', ')}] with key '${key}'.`);
return -1;
}
switch (cacheServiceVersion) { switch (cacheServiceVersion) {
case 'v2': case 'v2':
return yield saveCacheV2(paths, key, options, enableCrossOsArchive); return yield saveCacheV2(paths, key, options, enableCrossOsArchive);
@@ -95761,14 +95669,17 @@ function saveCacheV1(paths_1, key_1, options_1) {
if (typedError.name === ValidationError.name) { if (typedError.name === ValidationError.name) {
throw error; throw error;
} }
else if (typedError.name === CacheWriteDeniedError.name) {
// Cache write was denied by policy (read-only token). Surface to the
// customer at warning level so it is visible in the workflow log
// without failing the run.
warning(`Failed to save: ${typedError.message}`);
}
else if (typedError.name === ReserveCacheError.name) { else if (typedError.name === ReserveCacheError.name) {
info(`Failed to save: ${typedError.message}`); info(`Failed to save: ${typedError.message}`);
} }
else { else {
// Log server errors (5xx) as errors, all other errors as warnings. // Log server errors (5xx) as errors, all other errors as warnings
// A write denied by policy (CacheWriteDeniedError) is not an
// HttpClientError and its name does not match the ReserveCacheError arm,
// so it falls here and is warned without failing the run.
if (typedError instanceof lib_HttpClientError && if (typedError instanceof lib_HttpClientError &&
typeof typedError.statusCode === 'number' && typeof typedError.statusCode === 'number' &&
typedError.statusCode >= 500) { typedError.statusCode >= 500) {
@@ -95879,6 +95790,12 @@ function saveCacheV2(paths_1, key_1, options_1) {
if (typedError.name === ValidationError.name) { if (typedError.name === ValidationError.name) {
throw error; throw error;
} }
else if (typedError.name === CacheWriteDeniedError.name) {
// Cache write was denied by policy (read-only token). Surface to the
// customer at warning level so it is visible in the workflow log
// without failing the run.
warning(`Failed to save: ${typedError.message}`);
}
else if (typedError.name === ReserveCacheError.name) { else if (typedError.name === ReserveCacheError.name) {
info(`Failed to save: ${typedError.message}`); info(`Failed to save: ${typedError.message}`);
} }
@@ -95886,10 +95803,7 @@ function saveCacheV2(paths_1, key_1, options_1) {
warning(typedError.message); warning(typedError.message);
} }
else { else {
// Log server errors (5xx) as errors, all other errors as warnings. // Log server errors (5xx) as errors, all other errors as warnings
// A write denied by policy (CacheWriteDeniedError) is not an
// HttpClientError and its name does not match the ReserveCacheError arm,
// so it falls here and is warned without failing the run.
if (typedError instanceof lib_HttpClientError && if (typedError instanceof lib_HttpClientError &&
typeof typedError.statusCode === 'number' && typeof typedError.statusCode === 'number' &&
typedError.statusCode >= 500) { typedError.statusCode >= 500) {
@@ -95924,29 +95838,17 @@ const INPUT_JDK_FILE = 'jdk-file';
const INPUT_JDK_FILE_DEPRECATED = 'jdkFile'; const INPUT_JDK_FILE_DEPRECATED = 'jdkFile';
const INPUT_CHECK_LATEST = 'check-latest'; const INPUT_CHECK_LATEST = 'check-latest';
const INPUT_SET_DEFAULT = 'set-default'; const INPUT_SET_DEFAULT = 'set-default';
const INPUT_PROBLEM_MATCHER = 'problem-matcher';
const INPUT_VERIFY_SIGNATURE = 'verify-signature'; const INPUT_VERIFY_SIGNATURE = 'verify-signature';
const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key'; const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key';
const INPUT_SERVER_ID = 'server-id'; const INPUT_SERVER_ID = 'server-id';
const INPUT_SERVER_USERNAME_ENV_VAR = 'server-username-env-var'; const INPUT_SERVER_USERNAME = 'server-username';
const INPUT_SERVER_PASSWORD_ENV_VAR = 'server-password-env-var'; const INPUT_SERVER_PASSWORD = 'server-password';
const INPUT_SERVER_USERNAME_DEPRECATED = 'server-username';
const INPUT_SERVER_PASSWORD_DEPRECATED = 'server-password';
const INPUT_SETTINGS_PATH = 'settings-path'; const INPUT_SETTINGS_PATH = 'settings-path';
const INPUT_OVERWRITE_SETTINGS = 'overwrite-settings'; const INPUT_OVERWRITE_SETTINGS = 'overwrite-settings';
const INPUT_GPG_PRIVATE_KEY = 'gpg-private-key'; const INPUT_GPG_PRIVATE_KEY = 'gpg-private-key';
const INPUT_GPG_PASSPHRASE_ENV_VAR = 'gpg-passphrase-env-var'; const INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
const INPUT_GPG_PASSPHRASE_DEPRECATED = 'gpg-passphrase';
const INPUT_DEFAULT_SERVER_USERNAME = 'GITHUB_ACTOR';
const INPUT_DEFAULT_SERVER_PASSWORD = 'GITHUB_TOKEN';
const INPUT_DEFAULT_GPG_PRIVATE_KEY = (/* unused pure expression or super */ null && (undefined)); const INPUT_DEFAULT_GPG_PRIVATE_KEY = (/* unused pure expression or super */ null && (undefined));
const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE'; const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
// The default name of the environment variable the maven-gpg-plugin reads the
// passphrase from (property `gpg.passphraseEnvName`). When the configured
// passphrase env var name matches this, no extra configuration is required.
const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
// Id of the settings.xml profile used to set `gpg.passphraseEnvName`.
const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
const INPUT_CACHE = 'cache'; const INPUT_CACHE = 'cache';
const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path'; const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
const INPUT_JOB_STATUS = 'job-status'; const INPUT_JOB_STATUS = 'job-status';
@@ -99764,28 +99666,23 @@ const CACHE_KEY_PREFIX = 'setup-java';
const supportedPackageManager = [ const supportedPackageManager = [
{ {
id: 'maven', id: 'maven',
path: [(0,external_path_.join)(external_os_default().homedir(), '.m2', 'repository')], path: [
(0,external_path_.join)(external_os_default().homedir(), '.m2', 'repository'),
(0,external_path_.join)(external_os_default().homedir(), '.m2', 'wrapper', 'dists')
],
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
pattern: [ pattern: [
'**/pom.xml', '**/pom.xml',
'**/.mvn/wrapper/maven-wrapper.properties', '**/.mvn/wrapper/maven-wrapper.properties',
'**/.mvn/extensions.xml' '**/.mvn/extensions.xml'
],
// The Maven wrapper distribution only depends on the wrapper properties,
// which change very rarely, so it is cached separately from the local
// repository. This keeps it available across the frequent pom.xml changes
// that rotate the main cache key. See issue #1095.
additionalCaches: [
{
name: 'maven-wrapper',
path: [(0,external_path_.join)(external_os_default().homedir(), '.m2', 'wrapper', 'dists')],
pattern: ['**/.mvn/wrapper/maven-wrapper.properties']
}
] ]
}, },
{ {
id: 'gradle', id: 'gradle',
path: [(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'caches')], path: [
(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'caches'),
(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'wrapper')
],
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle
pattern: [ pattern: [
'**/*.gradle*', '**/*.gradle*',
@@ -99794,17 +99691,6 @@ const supportedPackageManager = [
'buildSrc/**/Dependencies.kt', 'buildSrc/**/Dependencies.kt',
'gradle/*.versions.toml', 'gradle/*.versions.toml',
'**/versions.properties' '**/versions.properties'
],
// The Gradle wrapper distribution only depends on the wrapper properties,
// which change very rarely, so it is cached separately from the Gradle
// caches. This keeps it available across the frequent *.gradle* changes
// that rotate the main cache key. See issue #269.
additionalCaches: [
{
name: 'gradle-wrapper',
path: [(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'wrapper')],
pattern: ['**/gradle-wrapper.properties']
}
] ]
}, },
{ {
@@ -99840,19 +99726,6 @@ function findPackageManager(id) {
} }
return packageManager; return packageManager;
} }
/**
* State keys used to carry an additional cache's restore-time information over
* to the post (save) action, scoped by the additional cache name.
*/
function additionalCachePrimaryKeyState(name) {
return `${STATE_CACHE_PRIMARY_KEY}-${name}`;
}
function additionalCacheMatchedKeyState(name) {
return `${CACHE_MATCHED_KEY}-${name}`;
}
function buildCacheKey(id, fileHash) {
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`;
}
/** /**
* A function that generates a cache key to use. * A function that generates a cache key to use.
* Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"". * Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"".
@@ -99866,19 +99739,7 @@ async function computeCacheKey(packageManager, cacheDependencyPath) {
if (!fileHash) { if (!fileHash) {
throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`); throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`);
} }
return buildCacheKey(packageManager.id, fileHash); return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${packageManager.id}-${fileHash}`;
}
/**
* Computes the cache key for an additional cache. Unlike {@link computeCacheKey}
* this returns undefined (instead of throwing) when no file matches the pattern,
* because additional caches are optional features that many projects do not use.
*/
async function computeAdditionalCacheKey(additionalCache) {
const fileHash = await glob.hashFiles(additionalCache.pattern.join('\n'));
if (!fileHash) {
return undefined;
}
return buildCacheKey(additionalCache.name, fileHash);
} }
/** /**
* Restore the dependency cache * Restore the dependency cache
@@ -99902,29 +99763,6 @@ async function restore(id, cacheDependencyPath) {
core.setOutput('cache-hit', false); core.setOutput('cache-hit', false);
core.info(`${packageManager.id} cache is not found`); core.info(`${packageManager.id} cache is not found`);
} }
for (const additionalCache of packageManager.additionalCaches ?? []) {
await restoreAdditionalCache(additionalCache);
}
}
/**
* Restore an additional cache (e.g. a build-tool wrapper distribution) that is
* keyed independently of the main dependency cache so that it survives changes
* to volatile dependency files. Skips silently when the project does not use
* the corresponding feature.
*/
async function restoreAdditionalCache(additionalCache) {
const primaryKey = await computeAdditionalCacheKey(additionalCache);
if (!primaryKey) {
core.debug(`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`);
return;
}
core.debug(`${additionalCache.name} primary key is ${primaryKey}`);
core.saveState(additionalCachePrimaryKeyState(additionalCache.name), primaryKey);
const matchedKey = await cache.restoreCache(additionalCache.path, primaryKey);
if (matchedKey) {
core.saveState(additionalCacheMatchedKeyState(additionalCache.name), matchedKey);
core.info(`${additionalCache.name} cache restored from key: ${matchedKey}`);
}
} }
/** /**
* Save the dependency cache * Save the dependency cache
@@ -99935,9 +99773,6 @@ async function save(id) {
const matchedKey = getState(CACHE_MATCHED_KEY); const matchedKey = getState(CACHE_MATCHED_KEY);
// Inputs are re-evaluated before the post action, so we want the original key used for restore // Inputs are re-evaluated before the post action, so we want the original key used for restore
const primaryKey = getState(STATE_CACHE_PRIMARY_KEY); const primaryKey = getState(STATE_CACHE_PRIMARY_KEY);
for (const additionalCache of packageManager.additionalCaches ?? []) {
await saveAdditionalCache(packageManager, additionalCache);
}
if (!primaryKey) { if (!primaryKey) {
warning('Error retrieving key from state.'); warning('Error retrieving key from state.');
return; return;
@@ -99972,50 +99807,6 @@ async function save(id) {
} }
} }
} }
/**
* Save an additional cache under its own key. Skips when no key was recorded at
* restore time (feature unused) or when the exact key was already restored.
*/
async function saveAdditionalCache(packageManager, additionalCache) {
const primaryKey = getState(additionalCachePrimaryKeyState(additionalCache.name));
const matchedKey = getState(additionalCacheMatchedKeyState(additionalCache.name));
if (!primaryKey) {
// The feature is not used by this project, nothing to save.
core_debug(`No primary key for the ${additionalCache.name} cache, not saving cache.`);
return;
}
else if (matchedKey === primaryKey) {
info(`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`);
return;
}
try {
const cacheId = await cache_saveCache(additionalCache.path, primaryKey);
if (cacheId === -1) {
core_debug(`${additionalCache.name} cache was not saved for the key: ${primaryKey}`);
return;
}
info(`${additionalCache.name} cache saved with the key: ${primaryKey}`);
}
catch (error) {
const err = error;
if (err.name === ValidationError.name) {
// The cache paths did not resolve, e.g. the wrapper distribution was
// never downloaded because a system build tool was used or the download
// failed. Optional wrapper caches must not fail the post step, so skip.
core_debug(`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`);
return;
}
if (err.name === ReserveCacheError.name) {
info(err.message);
}
else {
if (isProbablyGradleDaemonProblem(packageManager, err)) {
warning('Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.');
}
throw error;
}
}
}
/** /**
* @param packageManager the specified package manager by user * @param packageManager the specified package manager by user
* @param error the error thrown by the saveCache * @param error the error thrown by the saveCache
+57 -300
View File
@@ -70021,7 +70021,7 @@ module.exports = { version: packageJson.version }
/***/ 4012: /***/ 4012:
/***/ ((module) => { /***/ ((module) => {
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.2.0","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.1","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.1","@actions/io":"^3.0.2","@azure/core-rest-pipeline":"^1.23.0","@azure/storage-blob":"^12.31.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.4"},"devDependencies":{"@protobuf-ts/plugin":"^2.11.1","@types/node":"^25.6.0","@types/semver":"^7.7.1","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}'); module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.1.0","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.1","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.1","@actions/io":"^3.0.2","@azure/core-rest-pipeline":"^1.23.0","@azure/storage-blob":"^12.31.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.4"},"devDependencies":{"@protobuf-ts/plugin":"^2.11.1","@types/node":"^25.6.0","@types/semver":"^7.7.1","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}');
/***/ }) /***/ })
@@ -73283,29 +73283,17 @@ const INPUT_JDK_FILE = 'jdk-file';
const INPUT_JDK_FILE_DEPRECATED = 'jdkFile'; const INPUT_JDK_FILE_DEPRECATED = 'jdkFile';
const INPUT_CHECK_LATEST = 'check-latest'; const INPUT_CHECK_LATEST = 'check-latest';
const INPUT_SET_DEFAULT = 'set-default'; const INPUT_SET_DEFAULT = 'set-default';
const INPUT_PROBLEM_MATCHER = 'problem-matcher';
const INPUT_VERIFY_SIGNATURE = 'verify-signature'; const INPUT_VERIFY_SIGNATURE = 'verify-signature';
const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key'; const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key';
const INPUT_SERVER_ID = 'server-id'; const INPUT_SERVER_ID = 'server-id';
const INPUT_SERVER_USERNAME_ENV_VAR = 'server-username-env-var'; const INPUT_SERVER_USERNAME = 'server-username';
const INPUT_SERVER_PASSWORD_ENV_VAR = 'server-password-env-var'; const INPUT_SERVER_PASSWORD = 'server-password';
const INPUT_SERVER_USERNAME_DEPRECATED = 'server-username';
const INPUT_SERVER_PASSWORD_DEPRECATED = 'server-password';
const INPUT_SETTINGS_PATH = 'settings-path'; const INPUT_SETTINGS_PATH = 'settings-path';
const INPUT_OVERWRITE_SETTINGS = 'overwrite-settings'; const INPUT_OVERWRITE_SETTINGS = 'overwrite-settings';
const INPUT_GPG_PRIVATE_KEY = 'gpg-private-key'; const INPUT_GPG_PRIVATE_KEY = 'gpg-private-key';
const INPUT_GPG_PASSPHRASE_ENV_VAR = 'gpg-passphrase-env-var'; const INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
const INPUT_GPG_PASSPHRASE_DEPRECATED = 'gpg-passphrase';
const INPUT_DEFAULT_SERVER_USERNAME = 'GITHUB_ACTOR';
const INPUT_DEFAULT_SERVER_PASSWORD = 'GITHUB_TOKEN';
const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined; const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined;
const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE'; const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
// The default name of the environment variable the maven-gpg-plugin reads the
// passphrase from (property `gpg.passphraseEnvName`). When the configured
// passphrase env var name matches this, no extra configuration is required.
const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
// Id of the settings.xml profile used to set `gpg.passphraseEnvName`.
const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
const INPUT_CACHE = 'cache'; const INPUT_CACHE = 'cache';
const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path'; const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
const constants_INPUT_JOB_STATUS = 'job-status'; const constants_INPUT_JOB_STATUS = 'job-status';
@@ -75107,10 +75095,6 @@ const SystemTarPathOnWindows = `${process.env['SYSTEMDRIVE']}\\Windows\\System32
const TarFilename = 'cache.tar'; const TarFilename = 'cache.tar';
const constants_ManifestFilename = 'manifest.txt'; const constants_ManifestFilename = 'manifest.txt';
const CacheFileSizeLimit = 10 * Math.pow(1024, 3); // 10GiB per repository const CacheFileSizeLimit = 10 * Math.pow(1024, 3); // 10GiB per repository
// Prefix the cache backend embeds in a read-denial message (v2 twirp
// GetCacheEntryDownloadURL error or the GHES v1 `_apis/artifactcache` 403 body).
// Shared so cache.ts and cacheHttpClient.ts match the same contract value.
const CacheReadDeniedMessagePrefix = 'cache read denied:';
//# sourceMappingURL=constants.js.map //# sourceMappingURL=constants.js.map
;// CONCATENATED MODULE: ./node_modules/@actions/cache/lib/internal/cacheUtils.js ;// CONCATENATED MODULE: ./node_modules/@actions/cache/lib/internal/cacheUtils.js
var cacheUtils_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { var cacheUtils_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
@@ -124992,24 +124976,6 @@ function config_getCacheServiceVersion() {
return 'v1'; return 'v1';
return process.env['ACTIONS_CACHE_SERVICE_V2'] ? 'v2' : 'v1'; return process.env['ACTIONS_CACHE_SERVICE_V2'] ? 'v2' : 'v1';
} }
// The cache-mode lattice: readable = {read, write}, writable = {write,
// write-only}, none = neither.
const KNOWN_CACHE_MODES = ['none', 'read', 'write', 'write-only'];
// The effective cache-mode exported by the runner, or '' when not set.
function config_getCacheMode() {
return (process.env['ACTIONS_CACHE_MODE'] || '').trim().toLowerCase();
}
// Unset or unrecognized modes are permissive so behavior matches today.
function isCacheReadable(mode) {
if (!KNOWN_CACHE_MODES.includes(mode))
return true;
return mode === 'read' || mode === 'write';
}
function config_isCacheWritable(mode) {
if (!KNOWN_CACHE_MODES.includes(mode))
return true;
return mode === 'write' || mode === 'write-only';
}
function getCacheServiceURL() { function getCacheServiceURL() {
const version = config_getCacheServiceVersion(); const version = config_getCacheServiceVersion();
// Based on the version of the cache service, we will determine which // Based on the version of the cache service, we will determine which
@@ -125059,7 +125025,6 @@ var cacheHttpClient_awaiter = (undefined && undefined.__awaiter) || function (th
function getCacheApiUrl(resource) { function getCacheApiUrl(resource) {
const baseUrl = getCacheServiceURL(); const baseUrl = getCacheServiceURL();
if (!baseUrl) { if (!baseUrl) {
@@ -125087,7 +125052,6 @@ function createHttpClient() {
} }
function getCacheEntry(keys, paths, options) { function getCacheEntry(keys, paths, options) {
return cacheHttpClient_awaiter(this, void 0, void 0, function* () { return cacheHttpClient_awaiter(this, void 0, void 0, function* () {
var _a;
const httpClient = createHttpClient(); const httpClient = createHttpClient();
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive); const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`; const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
@@ -125101,12 +125065,6 @@ function getCacheEntry(keys, paths, options) {
return null; return null;
} }
if (!requestUtils_isSuccessStatusCode(response.statusCode)) { if (!requestUtils_isSuccessStatusCode(response.statusCode)) {
// Only surface the receiver's body for a `cache read denied:` policy denial
// so callers can dispatch on it; keep the generic message otherwise.
const errorMessage = (_a = response.error) === null || _a === void 0 ? void 0 : _a.message;
if (errorMessage === null || errorMessage === void 0 ? void 0 : errorMessage.includes(CacheReadDeniedMessagePrefix)) {
throw new Error(errorMessage);
}
throw new Error(`Cache service responded with ${response.statusCode}`); throw new Error(`Cache service responded with ${response.statusCode}`);
} }
const cacheResult = response.result; const cacheResult = response.result;
@@ -126368,7 +126326,6 @@ var cache_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
class ValidationError extends Error { class ValidationError extends Error {
constructor(message) { constructor(message) {
super(message); super(message);
@@ -126384,20 +126341,19 @@ class ReserveCacheError extends Error {
} }
} }
/** /**
* Stable prefix the cache service writes into the cache reservation response * Stable prefix the receiver writes into the cache reservation response when
* when the issuer downgraded the cache token to read-only (for example, because * the issuer downgraded the cache token to read-only (for example, because
* the run was triggered by an untrusted event). saveCacheV1 / saveCacheV2 * the run was triggered by an untrusted event). saveCacheV1 / saveCacheV2
* dispatch on this prefix to re-classify the failure as a CacheWriteDeniedError * dispatch on this prefix to re-classify the failure as a
* so consumers and tests can distinguish a policy denial from other reservation * CacheWriteDeniedError so consumers (and the outer catch arm) can
* failures. Internally it is logged as a non-fatal warning like other * distinguish a policy denial from other reservation failures.
* best-effort save failures.
*/ */
const CACHE_WRITE_DENIED_PREFIX = 'cache write denied:'; const CACHE_WRITE_DENIED_PREFIX = 'cache write denied:';
/** /**
* Raised when the cache backend refuses to reserve a writable cache entry * Raised when the cache backend refuses to reserve a writable cache entry
* because the JWT issued for this run was scoped read-only (for example, the * because the JWT issued for this run was scoped read-only (for example, the
* run was triggered by an event the repository administrator classified as * run was triggered by an event the repository administrator classified as
* untrusted). The service-supplied detail message always begins with * untrusted). The receiver-supplied detail message always begins with
* `cache write denied:` (the full error message includes additional context * `cache write denied:` (the full error message includes additional context
* like the cache key). * like the cache key).
* *
@@ -126413,19 +126369,6 @@ class CacheWriteDeniedError extends ReserveCacheError {
Object.setPrototypeOf(this, CacheWriteDeniedError.prototype); Object.setPrototypeOf(this, CacheWriteDeniedError.prototype);
} }
} }
// Re-exported from constants so consumers keep referencing it here; the shared
// value also drives detection in cacheHttpClient without duplicating the string.
const CACHE_READ_DENIED_PREFIX = CacheReadDeniedMessagePrefix;
// Raised when the cache backend denies a download URL because the run's token
// has no readable cache scopes. Caching is best-effort, so restoreCache logs a
// warning and reports a cache miss rather than rethrowing this.
class CacheReadDeniedError extends Error {
constructor(message) {
super(message);
this.name = 'CacheReadDeniedError';
Object.setPrototypeOf(this, CacheReadDeniedError.prototype);
}
}
class FinalizeCacheError extends Error { class FinalizeCacheError extends Error {
constructor(message) { constructor(message) {
super(message); super(message);
@@ -126480,12 +126423,6 @@ function restoreCache(paths_1, primaryKey_1, restoreKeys_1, options_1) {
const cacheServiceVersion = config_getCacheServiceVersion(); const cacheServiceVersion = config_getCacheServiceVersion();
core_debug(`Cache service version: ${cacheServiceVersion}`); core_debug(`Cache service version: ${cacheServiceVersion}`);
checkPaths(paths); checkPaths(paths);
const cacheMode = config_getCacheMode();
if (!isCacheReadable(cacheMode)) {
info(`Cache restore skipped: the effective cache-mode '${cacheMode}' does not permit reads.`);
core_debug(`Skipped restore for paths [${paths.join(', ')}] with primary key '${primaryKey}'.`);
return undefined;
}
switch (cacheServiceVersion) { switch (cacheServiceVersion) {
case 'v2': case 'v2':
return yield restoreCacheV2(paths, primaryKey, restoreKeys, options, enableCrossOsArchive); return yield restoreCacheV2(paths, primaryKey, restoreKeys, options, enableCrossOsArchive);
@@ -126507,7 +126444,6 @@ function restoreCache(paths_1, primaryKey_1, restoreKeys_1, options_1) {
*/ */
function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) { function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) { return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
var _a;
restoreKeys = restoreKeys || []; restoreKeys = restoreKeys || [];
const keys = [primaryKey, ...restoreKeys]; const keys = [primaryKey, ...restoreKeys];
core_debug('Resolved Keys:'); core_debug('Resolved Keys:');
@@ -126522,26 +126458,10 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
let archivePath = ''; let archivePath = '';
try { try {
// path are needed to compute version // path are needed to compute version
let cacheEntry; const cacheEntry = yield getCacheEntry(keys, paths, {
try { compressionMethod,
cacheEntry = yield getCacheEntry(keys, paths, { enableCrossOsArchive
compressionMethod, });
enableCrossOsArchive
});
}
catch (error) {
// The v1 artifact cache service returns HTTP 403 with a
// `cache read denied:` body when the run's token has no readable cache
// scopes. getCacheEntry lives in a dependency-free internal module and
// cannot import CacheReadDeniedError without a circular dependency, so it
// only surfaces the raw denial message; we classify it into the typed
// error here so the outer catch and consumers can dispatch on it.
const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : '';
if (errorMessage.includes(CACHE_READ_DENIED_PREFIX)) {
throw new CacheReadDeniedError(errorMessage);
}
throw error;
}
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) { if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
// Cache not found // Cache not found
return undefined; return undefined;
@@ -126570,9 +126490,7 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
} }
else { else {
// warn on cache restore failure and continue build // warn on cache restore failure and continue build
// Log server errors (5xx) as errors, all other errors as warnings. // Log server errors (5xx) as errors, all other errors as warnings
// A read denied by policy (CacheReadDeniedError) is not an HttpClientError
// so it falls here and is warned, treated as a cache miss.
if (typedError instanceof lib_HttpClientError && if (typedError instanceof lib_HttpClientError &&
typeof typedError.statusCode === 'number' && typeof typedError.statusCode === 'number' &&
typedError.statusCode >= 500) { typedError.statusCode >= 500) {
@@ -126607,7 +126525,6 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
*/ */
function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) { function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) { return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
var _a;
// Override UploadOptions to force the use of Azure // Override UploadOptions to force the use of Azure
options = Object.assign(Object.assign({}, options), { useAzureSdk: true }); options = Object.assign(Object.assign({}, options), { useAzureSdk: true });
restoreKeys = restoreKeys || []; restoreKeys = restoreKeys || [];
@@ -126629,20 +126546,7 @@ function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
restoreKeys, restoreKeys,
version: getCacheVersion(paths, compressionMethod, enableCrossOsArchive) version: getCacheVersion(paths, compressionMethod, enableCrossOsArchive)
}; };
let response; const response = yield twirpClient.GetCacheEntryDownloadURL(request);
try {
response = yield twirpClient.GetCacheEntryDownloadURL(request);
}
catch (error) {
// The receiver returns twirp PermissionDenied (403) when the run's token
// has no readable cache scopes. The client wraps that 403, so the stable
// prefix is embedded in the message rather than leading it.
const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : '';
if (errorMessage.includes(CACHE_READ_DENIED_PREFIX)) {
throw new CacheReadDeniedError(errorMessage);
}
throw error;
}
if (!response.ok) { if (!response.ok) {
core_debug(`Cache not found for version ${request.version} of keys: ${keys.join(', ')}`); core_debug(`Cache not found for version ${request.version} of keys: ${keys.join(', ')}`);
return undefined; return undefined;
@@ -126677,10 +126581,8 @@ function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
throw error; throw error;
} }
else { else {
// Suppress all non-validation cache related errors because caching should be optional // Supress all non-validation cache related errors because caching should be optional
// Log server errors (5xx) as errors, all other errors as warnings. // Log server errors (5xx) as errors, all other errors as warnings
// A read denied by policy (CacheReadDeniedError) is not an HttpClientError
// so it falls here and is warned, treated as a cache miss.
if (typedError instanceof lib_HttpClientError && if (typedError instanceof lib_HttpClientError &&
typeof typedError.statusCode === 'number' && typeof typedError.statusCode === 'number' &&
typedError.statusCode >= 500) { typedError.statusCode >= 500) {
@@ -126719,12 +126621,6 @@ function cache_saveCache(paths_1, key_1, options_1) {
core.debug(`Cache service version: ${cacheServiceVersion}`); core.debug(`Cache service version: ${cacheServiceVersion}`);
checkPaths(paths); checkPaths(paths);
checkKey(key); checkKey(key);
const cacheMode = getCacheMode();
if (!isCacheWritable(cacheMode)) {
core.info(`Cache save skipped: the effective cache-mode '${cacheMode}' does not permit writes.`);
core.debug(`Skipped save for paths [${paths.join(', ')}] with key '${key}'.`);
return -1;
}
switch (cacheServiceVersion) { switch (cacheServiceVersion) {
case 'v2': case 'v2':
return yield saveCacheV2(paths, key, options, enableCrossOsArchive); return yield saveCacheV2(paths, key, options, enableCrossOsArchive);
@@ -126802,14 +126698,17 @@ function saveCacheV1(paths_1, key_1, options_1) {
if (typedError.name === ValidationError.name) { if (typedError.name === ValidationError.name) {
throw error; throw error;
} }
else if (typedError.name === CacheWriteDeniedError.name) {
// Cache write was denied by policy (read-only token). Surface to the
// customer at warning level so it is visible in the workflow log
// without failing the run.
core.warning(`Failed to save: ${typedError.message}`);
}
else if (typedError.name === ReserveCacheError.name) { else if (typedError.name === ReserveCacheError.name) {
core.info(`Failed to save: ${typedError.message}`); core.info(`Failed to save: ${typedError.message}`);
} }
else { else {
// Log server errors (5xx) as errors, all other errors as warnings. // Log server errors (5xx) as errors, all other errors as warnings
// A write denied by policy (CacheWriteDeniedError) is not an
// HttpClientError and its name does not match the ReserveCacheError arm,
// so it falls here and is warned without failing the run.
if (typedError instanceof HttpClientError && if (typedError instanceof HttpClientError &&
typeof typedError.statusCode === 'number' && typeof typedError.statusCode === 'number' &&
typedError.statusCode >= 500) { typedError.statusCode >= 500) {
@@ -126920,6 +126819,12 @@ function saveCacheV2(paths_1, key_1, options_1) {
if (typedError.name === ValidationError.name) { if (typedError.name === ValidationError.name) {
throw error; throw error;
} }
else if (typedError.name === CacheWriteDeniedError.name) {
// Cache write was denied by policy (read-only token). Surface to the
// customer at warning level so it is visible in the workflow log
// without failing the run.
core.warning(`Failed to save: ${typedError.message}`);
}
else if (typedError.name === ReserveCacheError.name) { else if (typedError.name === ReserveCacheError.name) {
core.info(`Failed to save: ${typedError.message}`); core.info(`Failed to save: ${typedError.message}`);
} }
@@ -126927,10 +126832,7 @@ function saveCacheV2(paths_1, key_1, options_1) {
core.warning(typedError.message); core.warning(typedError.message);
} }
else { else {
// Log server errors (5xx) as errors, all other errors as warnings. // Log server errors (5xx) as errors, all other errors as warnings
// A write denied by policy (CacheWriteDeniedError) is not an
// HttpClientError and its name does not match the ReserveCacheError arm,
// so it falls here and is warned without failing the run.
if (typedError instanceof HttpClientError && if (typedError instanceof HttpClientError &&
typeof typedError.statusCode === 'number' && typeof typedError.statusCode === 'number' &&
typedError.statusCode >= 500) { typedError.statusCode >= 500) {
@@ -127364,41 +127266,34 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
async function configureAuthentication() { async function configureAuthentication() {
const id = getInput(INPUT_SERVER_ID); const id = getInput(INPUT_SERVER_ID);
const usernameEnvVar = getInputWithDeprecatedAlias(INPUT_SERVER_USERNAME_ENV_VAR, INPUT_SERVER_USERNAME_DEPRECATED, INPUT_DEFAULT_SERVER_USERNAME); const username = getInput(INPUT_SERVER_USERNAME);
const passwordEnvVar = getInputWithDeprecatedAlias(INPUT_SERVER_PASSWORD_ENV_VAR, INPUT_SERVER_PASSWORD_DEPRECATED, INPUT_DEFAULT_SERVER_PASSWORD); const password = getInput(INPUT_SERVER_PASSWORD);
const settingsDirectory = getInput(INPUT_SETTINGS_PATH) || const settingsDirectory = getInput(INPUT_SETTINGS_PATH) ||
external_path_.join(external_os_.homedir(), M2_DIR); external_path_.join(external_os_.homedir(), M2_DIR);
const overwriteSettings = util_getBooleanInput(INPUT_OVERWRITE_SETTINGS, true); const overwriteSettings = util_getBooleanInput(INPUT_OVERWRITE_SETTINGS, true);
const gpgPrivateKey = getInput(INPUT_GPG_PRIVATE_KEY) || const gpgPrivateKey = getInput(INPUT_GPG_PRIVATE_KEY) ||
INPUT_DEFAULT_GPG_PRIVATE_KEY; INPUT_DEFAULT_GPG_PRIVATE_KEY;
const gpgPassphraseEnvVar = getInputWithDeprecatedAlias(INPUT_GPG_PASSPHRASE_ENV_VAR, INPUT_GPG_PASSPHRASE_DEPRECATED, gpgPrivateKey ? INPUT_DEFAULT_GPG_PASSPHRASE : undefined); const gpgPassphrase = getInput(INPUT_GPG_PASSPHRASE) ||
(gpgPrivateKey ? INPUT_DEFAULT_GPG_PASSPHRASE : undefined);
if (gpgPrivateKey) { if (gpgPrivateKey) {
core_setSecret(gpgPrivateKey); core_setSecret(gpgPrivateKey);
} }
await createAuthenticationSettings(id, usernameEnvVar, passwordEnvVar, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar); await createAuthenticationSettings(id, username, password, settingsDirectory, overwriteSettings, gpgPassphrase);
if (gpgPrivateKey) { if (gpgPrivateKey) {
info('Importing private gpg key'); info('Importing private gpg key');
const keyFingerprint = (await importKey(gpgPrivateKey)) || ''; const keyFingerprint = (await importKey(gpgPrivateKey)) || '';
saveState(STATE_GPG_PRIVATE_KEY_FINGERPRINT, keyFingerprint); saveState(STATE_GPG_PRIVATE_KEY_FINGERPRINT, keyFingerprint);
} }
} }
function getInputWithDeprecatedAlias(inputName, deprecatedInputName, defaultValue) { async function createAuthenticationSettings(id, username, password, settingsDirectory, overwriteSettings, gpgPassphrase = undefined) {
const value = getInput(inputName);
const deprecatedValue = getInput(deprecatedInputName);
if (deprecatedValue) {
warning(`The '${deprecatedInputName}' input is deprecated and may be removed in a future release. Please use '${inputName}' instead.`);
}
return value || deprecatedValue || defaultValue || '';
}
async function createAuthenticationSettings(id, usernameEnvVar, passwordEnvVar, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar = undefined) {
info(`Creating ${MVN_SETTINGS_FILE} with server-id: ${id}`); info(`Creating ${MVN_SETTINGS_FILE} with server-id: ${id}`);
// when an alternate m2 location is specified use only that location (no .m2 directory) // when an alternate m2 location is specified use only that location (no .m2 directory)
// otherwise use the home/.m2/ path // otherwise use the home/.m2/ path
await mkdirP(settingsDirectory); await mkdirP(settingsDirectory);
await write(settingsDirectory, generate(id, usernameEnvVar, passwordEnvVar, gpgPassphraseEnvVar), overwriteSettings); await write(settingsDirectory, generate(id, username, password, gpgPassphrase), overwriteSettings);
} }
// only exported for testing purposes // only exported for testing purposes
function generate(id, usernameEnvVar, passwordEnvVar, gpgPassphraseEnvVar) { function generate(id, username, password, gpgPassphrase) {
const xmlObj = { const xmlObj = {
settings: { settings: {
'@xmlns': 'http://maven.apache.org/SETTINGS/1.0.0', '@xmlns': 'http://maven.apache.org/SETTINGS/1.0.0',
@@ -127409,32 +127304,19 @@ function generate(id, usernameEnvVar, passwordEnvVar, gpgPassphraseEnvVar) {
server: [ server: [
{ {
id: id, id: id,
username: `\${env.${usernameEnvVar}}`, username: `\${env.${username}}`,
password: `\${env.${passwordEnvVar}}` password: `\${env.${password}}`
} }
] ]
} }
} }
}; };
// The maven-gpg-plugin reads the passphrase from the environment variable if (gpgPassphrase) {
// named by the `gpg.passphraseEnvName` property (default MAVEN_GPG_PASSPHRASE). const gpgServer = {
// Only configure it when the requested env var name differs from that default; id: 'gpg.passphrase',
// otherwise the plugin already reads the right variable and no extra settings passphrase: `\${env.${gpgPassphrase}}`
// are needed. Writing `gpg.passphrase` to settings.xml is deprecated and fails
// when the plugin's `bestPractices` mode is enabled.
if (gpgPassphraseEnvVar &&
gpgPassphraseEnvVar !== MAVEN_GPG_PASSPHRASE_DEFAULT_ENV) {
xmlObj.settings.profiles = {
profile: {
id: GPG_PASSPHRASE_PROFILE_ID,
properties: {
'gpg.passphraseEnvName': gpgPassphraseEnvVar
}
}
};
xmlObj.settings.activeProfiles = {
activeProfile: GPG_PASSPHRASE_PROFILE_ID
}; };
xmlObj.settings.servers.server.push(gpgServer);
} }
return (0,lib/* create */.vt)(xmlObj).end({ return (0,lib/* create */.vt)(xmlObj).end({
headless: true, headless: true,
@@ -131005,28 +130887,23 @@ const CACHE_KEY_PREFIX = 'setup-java';
const supportedPackageManager = [ const supportedPackageManager = [
{ {
id: 'maven', id: 'maven',
path: [(0,external_path_.join)(external_os_default().homedir(), '.m2', 'repository')], path: [
(0,external_path_.join)(external_os_default().homedir(), '.m2', 'repository'),
(0,external_path_.join)(external_os_default().homedir(), '.m2', 'wrapper', 'dists')
],
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
pattern: [ pattern: [
'**/pom.xml', '**/pom.xml',
'**/.mvn/wrapper/maven-wrapper.properties', '**/.mvn/wrapper/maven-wrapper.properties',
'**/.mvn/extensions.xml' '**/.mvn/extensions.xml'
],
// The Maven wrapper distribution only depends on the wrapper properties,
// which change very rarely, so it is cached separately from the local
// repository. This keeps it available across the frequent pom.xml changes
// that rotate the main cache key. See issue #1095.
additionalCaches: [
{
name: 'maven-wrapper',
path: [(0,external_path_.join)(external_os_default().homedir(), '.m2', 'wrapper', 'dists')],
pattern: ['**/.mvn/wrapper/maven-wrapper.properties']
}
] ]
}, },
{ {
id: 'gradle', id: 'gradle',
path: [(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'caches')], path: [
(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'caches'),
(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'wrapper')
],
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle
pattern: [ pattern: [
'**/*.gradle*', '**/*.gradle*',
@@ -131035,17 +130912,6 @@ const supportedPackageManager = [
'buildSrc/**/Dependencies.kt', 'buildSrc/**/Dependencies.kt',
'gradle/*.versions.toml', 'gradle/*.versions.toml',
'**/versions.properties' '**/versions.properties'
],
// The Gradle wrapper distribution only depends on the wrapper properties,
// which change very rarely, so it is cached separately from the Gradle
// caches. This keeps it available across the frequent *.gradle* changes
// that rotate the main cache key. See issue #269.
additionalCaches: [
{
name: 'gradle-wrapper',
path: [(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'wrapper')],
pattern: ['**/gradle-wrapper.properties']
}
] ]
}, },
{ {
@@ -131081,19 +130947,6 @@ function findPackageManager(id) {
} }
return packageManager; return packageManager;
} }
/**
* State keys used to carry an additional cache's restore-time information over
* to the post (save) action, scoped by the additional cache name.
*/
function additionalCachePrimaryKeyState(name) {
return `${STATE_CACHE_PRIMARY_KEY}-${name}`;
}
function additionalCacheMatchedKeyState(name) {
return `${CACHE_MATCHED_KEY}-${name}`;
}
function buildCacheKey(id, fileHash) {
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`;
}
/** /**
* A function that generates a cache key to use. * A function that generates a cache key to use.
* Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"". * Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"".
@@ -131107,19 +130960,7 @@ async function computeCacheKey(packageManager, cacheDependencyPath) {
if (!fileHash) { if (!fileHash) {
throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`); throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`);
} }
return buildCacheKey(packageManager.id, fileHash); return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${packageManager.id}-${fileHash}`;
}
/**
* Computes the cache key for an additional cache. Unlike {@link computeCacheKey}
* this returns undefined (instead of throwing) when no file matches the pattern,
* because additional caches are optional features that many projects do not use.
*/
async function computeAdditionalCacheKey(additionalCache) {
const fileHash = await lib_glob_hashFiles(additionalCache.pattern.join('\n'));
if (!fileHash) {
return undefined;
}
return buildCacheKey(additionalCache.name, fileHash);
} }
/** /**
* Restore the dependency cache * Restore the dependency cache
@@ -131143,29 +130984,6 @@ async function restore(id, cacheDependencyPath) {
setOutput('cache-hit', false); setOutput('cache-hit', false);
info(`${packageManager.id} cache is not found`); info(`${packageManager.id} cache is not found`);
} }
for (const additionalCache of packageManager.additionalCaches ?? []) {
await restoreAdditionalCache(additionalCache);
}
}
/**
* Restore an additional cache (e.g. a build-tool wrapper distribution) that is
* keyed independently of the main dependency cache so that it survives changes
* to volatile dependency files. Skips silently when the project does not use
* the corresponding feature.
*/
async function restoreAdditionalCache(additionalCache) {
const primaryKey = await computeAdditionalCacheKey(additionalCache);
if (!primaryKey) {
core_debug(`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`);
return;
}
core_debug(`${additionalCache.name} primary key is ${primaryKey}`);
saveState(additionalCachePrimaryKeyState(additionalCache.name), primaryKey);
const matchedKey = await restoreCache(additionalCache.path, primaryKey);
if (matchedKey) {
saveState(additionalCacheMatchedKeyState(additionalCache.name), matchedKey);
info(`${additionalCache.name} cache restored from key: ${matchedKey}`);
}
} }
/** /**
* Save the dependency cache * Save the dependency cache
@@ -131176,9 +130994,6 @@ async function save(id) {
const matchedKey = core.getState(CACHE_MATCHED_KEY); const matchedKey = core.getState(CACHE_MATCHED_KEY);
// Inputs are re-evaluated before the post action, so we want the original key used for restore // Inputs are re-evaluated before the post action, so we want the original key used for restore
const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY); const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY);
for (const additionalCache of packageManager.additionalCaches ?? []) {
await saveAdditionalCache(packageManager, additionalCache);
}
if (!primaryKey) { if (!primaryKey) {
core.warning('Error retrieving key from state.'); core.warning('Error retrieving key from state.');
return; return;
@@ -131213,50 +131028,6 @@ async function save(id) {
} }
} }
} }
/**
* Save an additional cache under its own key. Skips when no key was recorded at
* restore time (feature unused) or when the exact key was already restored.
*/
async function saveAdditionalCache(packageManager, additionalCache) {
const primaryKey = core.getState(additionalCachePrimaryKeyState(additionalCache.name));
const matchedKey = core.getState(additionalCacheMatchedKeyState(additionalCache.name));
if (!primaryKey) {
// The feature is not used by this project, nothing to save.
core.debug(`No primary key for the ${additionalCache.name} cache, not saving cache.`);
return;
}
else if (matchedKey === primaryKey) {
core.info(`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`);
return;
}
try {
const cacheId = await cache.saveCache(additionalCache.path, primaryKey);
if (cacheId === -1) {
core.debug(`${additionalCache.name} cache was not saved for the key: ${primaryKey}`);
return;
}
core.info(`${additionalCache.name} cache saved with the key: ${primaryKey}`);
}
catch (error) {
const err = error;
if (err.name === cache.ValidationError.name) {
// The cache paths did not resolve, e.g. the wrapper distribution was
// never downloaded because a system build tool was used or the download
// failed. Optional wrapper caches must not fail the post step, so skip.
core.debug(`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`);
return;
}
if (err.name === cache.ReserveCacheError.name) {
core.info(err.message);
}
else {
if (isProbablyGradleDaemonProblem(packageManager, err)) {
core.warning('Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.');
}
throw error;
}
}
}
/** /**
* @param packageManager the specified package manager by user * @param packageManager the specified package manager by user
* @param error the error thrown by the saveCache * @param error the error thrown by the saveCache
@@ -134001,19 +133772,6 @@ function configureMavenArgs() {
`Set '${INPUT_SHOW_DOWNLOAD_PROGRESS}: true' to keep the download progress output.`); `Set '${INPUT_SHOW_DOWNLOAD_PROGRESS}: true' to keep the download progress output.`);
} }
;// CONCATENATED MODULE: ./src/problem-matcher.ts
function configureProblemMatcher(matcherPath) {
const problemMatcherEnabled = util_getBooleanInput(INPUT_PROBLEM_MATCHER, true);
if (!problemMatcherEnabled) {
core_debug('Java problem matcher is disabled');
return;
}
info(`##[add-matcher]${matcherPath}`);
}
;// CONCATENATED MODULE: ./src/setup-java.ts ;// CONCATENATED MODULE: ./src/setup-java.ts
@@ -134026,7 +133784,6 @@ function configureProblemMatcher(matcherPath) {
async function run() { async function run() {
try { try {
const versions = getMultilineInput(INPUT_JAVA_VERSION); const versions = getMultilineInput(INPUT_JAVA_VERSION);
@@ -134100,7 +133857,7 @@ async function run() {
} }
endGroup(); endGroup();
const matchersPath = external_path_.join(external_path_.dirname((0,external_url_.fileURLToPath)(import.meta.url)), '..', '..', '.github'); const matchersPath = external_path_.join(external_path_.dirname((0,external_url_.fileURLToPath)(import.meta.url)), '..', '..', '.github');
configureProblemMatcher(external_path_.join(matchersPath, 'java.json')); info(`##[add-matcher]${external_path_.join(matchersPath, 'java.json')}`);
await configureAuthentication(); await configureAuthentication();
configureMavenArgs(); configureMavenArgs();
if (cache && isCacheFeatureAvailable()) { if (cache && isCacheFeatureAvailable()) {
+354 -394
View File
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -4,13 +4,13 @@ The major breaking change in V2 is the new mandatory `distribution` input. This
Use the `zulu` keyword if you would like to continue using the same distribution as in V1. Use the `zulu` keyword if you would like to continue using the same distribution as in V1.
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-java@v2 - uses: actions/setup-java@v2
with: with:
distribution: 'zulu' distribution: 'zulu'
java-version: '11' java-version: '11'
java-package: jdk # optional (jdk or jre) - defaults to jdk java-package: jdk # optional (jdk or jre) - defaults to jdk
- run: java -cp java HelloWorldApp - run: java -cp java HelloWorldApp
``` ```
**General recommendation** — configure CI with the same distribution that is used on your local dev machine. **General recommendation** — configure CI with the same distribution that is used on your local dev machine.
@@ -19,15 +19,15 @@ steps:
Since the `distribution` input is required in V2, you should specify it using `jdkfile` to continue installing Java from a local file on the runner Since the `distribution` input is required in V2, you should specify it using `jdkfile` to continue installing Java from a local file on the runner
```yaml ```yaml
steps: steps:
- run: | - run: |
download_url="https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.10_9.tar.gz" download_url="https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.10_9.tar.gz"
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
- uses: actions/setup-java@v2 - uses: actions/setup-java@v2
with: with:
distribution: 'jdkfile' distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/java_package.tar.gz jdkFile: ${{ runner.temp }}/java_package.tar.gz
java-version: '11.0.0' java-version: '11.0.0'
architecture: x64 architecture: x64
``` ```
## Dropping legacy Java version syntax 1.x ## Dropping legacy Java version syntax 1.x
+34 -4
View File
@@ -9,7 +9,7 @@
"version": "6.0.0", "version": "6.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/cache": "^6.2.0", "@actions/cache": "^6.1.0",
"@actions/core": "^3.0.1", "@actions/core": "^3.0.1",
"@actions/exec": "^3.0.0", "@actions/exec": "^3.0.0",
"@actions/glob": "^0.7.0", "@actions/glob": "^0.7.0",
@@ -44,9 +44,9 @@
} }
}, },
"node_modules/@actions/cache": { "node_modules/@actions/cache": {
"version": "6.2.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-6.2.0.tgz", "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-6.1.0.tgz",
"integrity": "sha512-Nv0xWRmbxfDbAn/70flO/F6tj2Nv4XTYMAsQHiDFSojCDfso/Zni+fRKa14ToI9hnmOW/rQcY1WYb6wsM7Pgwg==", "integrity": "sha512-LVqybSbzhBp2uAETOQ3HnVjXA4AcjavgMH+LCr+cjgO+PZfciv/1QAgoW+esXBaAhvDid+vXeV70GGJpAh4V5Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^3.0.1", "@actions/core": "^3.0.1",
@@ -2365,6 +2365,9 @@
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2379,6 +2382,9 @@
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2393,6 +2399,9 @@
"loong64" "loong64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2407,6 +2416,9 @@
"loong64" "loong64"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2421,6 +2433,9 @@
"ppc64" "ppc64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2435,6 +2450,9 @@
"riscv64" "riscv64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2449,6 +2467,9 @@
"riscv64" "riscv64"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2463,6 +2484,9 @@
"s390x" "s390x"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2477,6 +2501,9 @@
"x64" "x64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@@ -2491,6 +2518,9 @@
"x64" "x64"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
+1 -1
View File
@@ -42,7 +42,7 @@
"author": "GitHub", "author": "GitHub",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/cache": "^6.2.0", "@actions/cache": "^6.1.0",
"@actions/core": "^3.0.1", "@actions/core": "^3.0.1",
"@actions/exec": "^3.0.0", "@actions/exec": "^3.0.0",
"@actions/glob": "^0.7.0", "@actions/glob": "^0.7.0",
+22 -64
View File
@@ -12,16 +12,8 @@ import {getBooleanInput} from './util.js';
export async function configureAuthentication() { export async function configureAuthentication() {
const id = core.getInput(constants.INPUT_SERVER_ID); const id = core.getInput(constants.INPUT_SERVER_ID);
const usernameEnvVar = getInputWithDeprecatedAlias( const username = core.getInput(constants.INPUT_SERVER_USERNAME);
constants.INPUT_SERVER_USERNAME_ENV_VAR, const password = core.getInput(constants.INPUT_SERVER_PASSWORD);
constants.INPUT_SERVER_USERNAME_DEPRECATED,
constants.INPUT_DEFAULT_SERVER_USERNAME
);
const passwordEnvVar = getInputWithDeprecatedAlias(
constants.INPUT_SERVER_PASSWORD_ENV_VAR,
constants.INPUT_SERVER_PASSWORD_DEPRECATED,
constants.INPUT_DEFAULT_SERVER_PASSWORD
);
const settingsDirectory = const settingsDirectory =
core.getInput(constants.INPUT_SETTINGS_PATH) || core.getInput(constants.INPUT_SETTINGS_PATH) ||
path.join(os.homedir(), constants.M2_DIR); path.join(os.homedir(), constants.M2_DIR);
@@ -32,11 +24,9 @@ export async function configureAuthentication() {
const gpgPrivateKey = const gpgPrivateKey =
core.getInput(constants.INPUT_GPG_PRIVATE_KEY) || core.getInput(constants.INPUT_GPG_PRIVATE_KEY) ||
constants.INPUT_DEFAULT_GPG_PRIVATE_KEY; constants.INPUT_DEFAULT_GPG_PRIVATE_KEY;
const gpgPassphraseEnvVar = getInputWithDeprecatedAlias( const gpgPassphrase =
constants.INPUT_GPG_PASSPHRASE_ENV_VAR, core.getInput(constants.INPUT_GPG_PASSPHRASE) ||
constants.INPUT_GPG_PASSPHRASE_DEPRECATED, (gpgPrivateKey ? constants.INPUT_DEFAULT_GPG_PASSPHRASE : undefined);
gpgPrivateKey ? constants.INPUT_DEFAULT_GPG_PASSPHRASE : undefined
);
if (gpgPrivateKey) { if (gpgPrivateKey) {
core.setSecret(gpgPrivateKey); core.setSecret(gpgPrivateKey);
@@ -44,11 +34,11 @@ export async function configureAuthentication() {
await createAuthenticationSettings( await createAuthenticationSettings(
id, id,
usernameEnvVar, username,
passwordEnvVar, password,
settingsDirectory, settingsDirectory,
overwriteSettings, overwriteSettings,
gpgPassphraseEnvVar gpgPassphrase
); );
if (gpgPrivateKey) { if (gpgPrivateKey) {
@@ -58,30 +48,13 @@ export async function configureAuthentication() {
} }
} }
export function getInputWithDeprecatedAlias(
inputName: string,
deprecatedInputName: string,
defaultValue?: string
): string {
const value = core.getInput(inputName);
const deprecatedValue = core.getInput(deprecatedInputName);
if (deprecatedValue) {
core.warning(
`The '${deprecatedInputName}' input is deprecated and may be removed in a future release. Please use '${inputName}' instead.`
);
}
return value || deprecatedValue || defaultValue || '';
}
export async function createAuthenticationSettings( export async function createAuthenticationSettings(
id: string, id: string,
usernameEnvVar: string, username: string,
passwordEnvVar: string, password: string,
settingsDirectory: string, settingsDirectory: string,
overwriteSettings: boolean, overwriteSettings: boolean,
gpgPassphraseEnvVar: string | undefined = undefined gpgPassphrase: string | undefined = undefined
) { ) {
core.info(`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${id}`); core.info(`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${id}`);
// when an alternate m2 location is specified use only that location (no .m2 directory) // when an alternate m2 location is specified use only that location (no .m2 directory)
@@ -89,7 +62,7 @@ export async function createAuthenticationSettings(
await io.mkdirP(settingsDirectory); await io.mkdirP(settingsDirectory);
await write( await write(
settingsDirectory, settingsDirectory,
generate(id, usernameEnvVar, passwordEnvVar, gpgPassphraseEnvVar), generate(id, username, password, gpgPassphrase),
overwriteSettings overwriteSettings
); );
} }
@@ -97,9 +70,9 @@ export async function createAuthenticationSettings(
// only exported for testing purposes // only exported for testing purposes
export function generate( export function generate(
id: string, id: string,
usernameEnvVar: string, username: string,
passwordEnvVar: string, password: string,
gpgPassphraseEnvVar?: string | undefined gpgPassphrase?: string | undefined
) { ) {
const xmlObj: {[key: string]: any} = { const xmlObj: {[key: string]: any} = {
settings: { settings: {
@@ -112,35 +85,20 @@ export function generate(
server: [ server: [
{ {
id: id, id: id,
username: `\${env.${usernameEnvVar}}`, username: `\${env.${username}}`,
password: `\${env.${passwordEnvVar}}` password: `\${env.${password}}`
} }
] ]
} }
} }
}; };
// The maven-gpg-plugin reads the passphrase from the environment variable if (gpgPassphrase) {
// named by the `gpg.passphraseEnvName` property (default MAVEN_GPG_PASSPHRASE). const gpgServer = {
// Only configure it when the requested env var name differs from that default; id: 'gpg.passphrase',
// otherwise the plugin already reads the right variable and no extra settings passphrase: `\${env.${gpgPassphrase}}`
// are needed. Writing `gpg.passphrase` to settings.xml is deprecated and fails
// when the plugin's `bestPractices` mode is enabled.
if (
gpgPassphraseEnvVar &&
gpgPassphraseEnvVar !== constants.MAVEN_GPG_PASSPHRASE_DEFAULT_ENV
) {
xmlObj.settings.profiles = {
profile: {
id: constants.GPG_PASSPHRASE_PROFILE_ID,
properties: {
'gpg.passphraseEnvName': gpgPassphraseEnvVar
}
}
};
xmlObj.settings.activeProfiles = {
activeProfile: constants.GPG_PASSPHRASE_PROFILE_ID
}; };
xmlObj.settings.servers.server.push(gpgServer);
} }
return xmlCreate(xmlObj).end({ return xmlCreate(xmlObj).end({
+9 -185
View File
@@ -12,30 +12,6 @@ const STATE_CACHE_PRIMARY_KEY = 'cache-primary-key';
const CACHE_MATCHED_KEY = 'cache-matched-key'; const CACHE_MATCHED_KEY = 'cache-matched-key';
const CACHE_KEY_PREFIX = 'setup-java'; const CACHE_KEY_PREFIX = 'setup-java';
/**
* An additional cache entry that is restored and saved independently of the
* main dependency cache. Used for build-tool wrapper distributions that rarely
* change (e.g. the Maven wrapper distribution) so that they are not evicted
* every time a volatile dependency file such as pom.xml changes. See
* https://github.com/actions/setup-java/issues/1095.
*/
interface AdditionalCache {
/**
* Short identifier for the cache, used to build its cache key and to scope
* the state keys that carry information from restore to save.
*/
name: string;
/**
* Paths that make up this cache entry.
*/
path: string[];
/**
* Glob patterns whose hash forms the cache key. If no file matches, the
* cache is skipped silently (the project simply does not use this feature).
*/
pattern: string[];
}
interface PackageManager { interface PackageManager {
id: 'maven' | 'gradle' | 'sbt'; id: 'maven' | 'gradle' | 'sbt';
/** /**
@@ -43,36 +19,27 @@ interface PackageManager {
*/ */
path: string[]; path: string[];
pattern: string[]; pattern: string[];
/**
* Additional caches keyed independently of the main dependency cache.
*/
additionalCaches?: AdditionalCache[];
} }
const supportedPackageManager: PackageManager[] = [ const supportedPackageManager: PackageManager[] = [
{ {
id: 'maven', id: 'maven',
path: [join(os.homedir(), '.m2', 'repository')], path: [
join(os.homedir(), '.m2', 'repository'),
join(os.homedir(), '.m2', 'wrapper', 'dists')
],
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
pattern: [ pattern: [
'**/pom.xml', '**/pom.xml',
'**/.mvn/wrapper/maven-wrapper.properties', '**/.mvn/wrapper/maven-wrapper.properties',
'**/.mvn/extensions.xml' '**/.mvn/extensions.xml'
],
// The Maven wrapper distribution only depends on the wrapper properties,
// which change very rarely, so it is cached separately from the local
// repository. This keeps it available across the frequent pom.xml changes
// that rotate the main cache key. See issue #1095.
additionalCaches: [
{
name: 'maven-wrapper',
path: [join(os.homedir(), '.m2', 'wrapper', 'dists')],
pattern: ['**/.mvn/wrapper/maven-wrapper.properties']
}
] ]
}, },
{ {
id: 'gradle', id: 'gradle',
path: [join(os.homedir(), '.gradle', 'caches')], path: [
join(os.homedir(), '.gradle', 'caches'),
join(os.homedir(), '.gradle', 'wrapper')
],
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle
pattern: [ pattern: [
'**/*.gradle*', '**/*.gradle*',
@@ -81,17 +48,6 @@ const supportedPackageManager: PackageManager[] = [
'buildSrc/**/Dependencies.kt', 'buildSrc/**/Dependencies.kt',
'gradle/*.versions.toml', 'gradle/*.versions.toml',
'**/versions.properties' '**/versions.properties'
],
// The Gradle wrapper distribution only depends on the wrapper properties,
// which change very rarely, so it is cached separately from the Gradle
// caches. This keeps it available across the frequent *.gradle* changes
// that rotate the main cache key. See issue #269.
additionalCaches: [
{
name: 'gradle-wrapper',
path: [join(os.homedir(), '.gradle', 'wrapper')],
pattern: ['**/gradle-wrapper.properties']
}
] ]
}, },
{ {
@@ -131,21 +87,6 @@ function findPackageManager(id: string): PackageManager {
return packageManager; return packageManager;
} }
/**
* State keys used to carry an additional cache's restore-time information over
* to the post (save) action, scoped by the additional cache name.
*/
function additionalCachePrimaryKeyState(name: string): string {
return `${STATE_CACHE_PRIMARY_KEY}-${name}`;
}
function additionalCacheMatchedKeyState(name: string): string {
return `${CACHE_MATCHED_KEY}-${name}`;
}
function buildCacheKey(id: string, fileHash: string): string {
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`;
}
/** /**
* A function that generates a cache key to use. * A function that generates a cache key to use.
* Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"". * Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"".
@@ -164,22 +105,7 @@ async function computeCacheKey(
`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository` `No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`
); );
} }
return buildCacheKey(packageManager.id, fileHash); return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${packageManager.id}-${fileHash}`;
}
/**
* Computes the cache key for an additional cache. Unlike {@link computeCacheKey}
* this returns undefined (instead of throwing) when no file matches the pattern,
* because additional caches are optional features that many projects do not use.
*/
async function computeAdditionalCacheKey(
additionalCache: AdditionalCache
): Promise<string | undefined> {
const fileHash = await glob.hashFiles(additionalCache.pattern.join('\n'));
if (!fileHash) {
return undefined;
}
return buildCacheKey(additionalCache.name, fileHash);
} }
/** /**
@@ -204,40 +130,6 @@ export async function restore(id: string, cacheDependencyPath: string) {
core.setOutput('cache-hit', false); core.setOutput('cache-hit', false);
core.info(`${packageManager.id} cache is not found`); core.info(`${packageManager.id} cache is not found`);
} }
for (const additionalCache of packageManager.additionalCaches ?? []) {
await restoreAdditionalCache(additionalCache);
}
}
/**
* Restore an additional cache (e.g. a build-tool wrapper distribution) that is
* keyed independently of the main dependency cache so that it survives changes
* to volatile dependency files. Skips silently when the project does not use
* the corresponding feature.
*/
async function restoreAdditionalCache(additionalCache: AdditionalCache) {
const primaryKey = await computeAdditionalCacheKey(additionalCache);
if (!primaryKey) {
core.debug(
`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`
);
return;
}
core.debug(`${additionalCache.name} primary key is ${primaryKey}`);
core.saveState(
additionalCachePrimaryKeyState(additionalCache.name),
primaryKey
);
const matchedKey = await cache.restoreCache(additionalCache.path, primaryKey);
if (matchedKey) {
core.saveState(
additionalCacheMatchedKeyState(additionalCache.name),
matchedKey
);
core.info(`${additionalCache.name} cache restored from key: ${matchedKey}`);
}
} }
/** /**
@@ -251,10 +143,6 @@ export async function save(id: string) {
// Inputs are re-evaluated before the post action, so we want the original key used for restore // Inputs are re-evaluated before the post action, so we want the original key used for restore
const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY); const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY);
for (const additionalCache of packageManager.additionalCaches ?? []) {
await saveAdditionalCache(packageManager, additionalCache);
}
if (!primaryKey) { if (!primaryKey) {
core.warning('Error retrieving key from state.'); core.warning('Error retrieving key from state.');
return; return;
@@ -292,70 +180,6 @@ export async function save(id: string) {
} }
} }
/**
* Save an additional cache under its own key. Skips when no key was recorded at
* restore time (feature unused) or when the exact key was already restored.
*/
async function saveAdditionalCache(
packageManager: PackageManager,
additionalCache: AdditionalCache
) {
const primaryKey = core.getState(
additionalCachePrimaryKeyState(additionalCache.name)
);
const matchedKey = core.getState(
additionalCacheMatchedKeyState(additionalCache.name)
);
if (!primaryKey) {
// The feature is not used by this project, nothing to save.
core.debug(
`No primary key for the ${additionalCache.name} cache, not saving cache.`
);
return;
} else if (matchedKey === primaryKey) {
core.info(
`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`
);
return;
}
try {
const cacheId = await cache.saveCache(additionalCache.path, primaryKey);
if (cacheId === -1) {
core.debug(
`${additionalCache.name} cache was not saved for the key: ${primaryKey}`
);
return;
}
core.info(
`${additionalCache.name} cache saved with the key: ${primaryKey}`
);
} catch (error) {
const err = error as Error;
if (err.name === cache.ValidationError.name) {
// The cache paths did not resolve, e.g. the wrapper distribution was
// never downloaded because a system build tool was used or the download
// failed. Optional wrapper caches must not fail the post step, so skip.
core.debug(
`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`
);
return;
}
if (err.name === cache.ReserveCacheError.name) {
core.info(err.message);
} else {
if (isProbablyGradleDaemonProblem(packageManager, err)) {
core.warning(
'Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.'
);
}
throw error;
}
}
}
/** /**
* @param packageManager the specified package manager by user * @param packageManager the specified package manager by user
* @param error the error thrown by the saveCache * @param error the error thrown by the saveCache
+3 -17
View File
@@ -8,33 +8,19 @@ export const INPUT_JDK_FILE = 'jdk-file';
export const INPUT_JDK_FILE_DEPRECATED = 'jdkFile'; export const INPUT_JDK_FILE_DEPRECATED = 'jdkFile';
export const INPUT_CHECK_LATEST = 'check-latest'; export const INPUT_CHECK_LATEST = 'check-latest';
export const INPUT_SET_DEFAULT = 'set-default'; export const INPUT_SET_DEFAULT = 'set-default';
export const INPUT_PROBLEM_MATCHER = 'problem-matcher';
export const INPUT_VERIFY_SIGNATURE = 'verify-signature'; export const INPUT_VERIFY_SIGNATURE = 'verify-signature';
export const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key'; export const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key';
export const INPUT_SERVER_ID = 'server-id'; export const INPUT_SERVER_ID = 'server-id';
export const INPUT_SERVER_USERNAME_ENV_VAR = 'server-username-env-var'; export const INPUT_SERVER_USERNAME = 'server-username';
export const INPUT_SERVER_PASSWORD_ENV_VAR = 'server-password-env-var'; export const INPUT_SERVER_PASSWORD = 'server-password';
export const INPUT_SERVER_USERNAME_DEPRECATED = 'server-username';
export const INPUT_SERVER_PASSWORD_DEPRECATED = 'server-password';
export const INPUT_SETTINGS_PATH = 'settings-path'; export const INPUT_SETTINGS_PATH = 'settings-path';
export const INPUT_OVERWRITE_SETTINGS = 'overwrite-settings'; export const INPUT_OVERWRITE_SETTINGS = 'overwrite-settings';
export const INPUT_GPG_PRIVATE_KEY = 'gpg-private-key'; export const INPUT_GPG_PRIVATE_KEY = 'gpg-private-key';
export const INPUT_GPG_PASSPHRASE_ENV_VAR = 'gpg-passphrase-env-var'; export const INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
export const INPUT_GPG_PASSPHRASE_DEPRECATED = 'gpg-passphrase';
export const INPUT_DEFAULT_SERVER_USERNAME = 'GITHUB_ACTOR';
export const INPUT_DEFAULT_SERVER_PASSWORD = 'GITHUB_TOKEN';
export const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined; export const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined;
export const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE'; export const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
// The default name of the environment variable the maven-gpg-plugin reads the
// passphrase from (property `gpg.passphraseEnvName`). When the configured
// passphrase env var name matches this, no extra configuration is required.
export const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
// Id of the settings.xml profile used to set `gpg.passphraseEnvName`.
export const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
export const INPUT_CACHE = 'cache'; export const INPUT_CACHE = 'cache';
export const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path'; export const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
export const INPUT_JOB_STATUS = 'job-status'; export const INPUT_JOB_STATUS = 'job-status';
File diff suppressed because it is too large Load Diff
-14
View File
@@ -1,14 +0,0 @@
import * as core from '@actions/core';
import {INPUT_PROBLEM_MATCHER} from './constants.js';
import {getBooleanInput} from './util.js';
export function configureProblemMatcher(matcherPath: string): void {
const problemMatcherEnabled = getBooleanInput(INPUT_PROBLEM_MATCHER, true);
if (!problemMatcherEnabled) {
core.debug('Java problem matcher is disabled');
return;
}
core.info(`##[add-matcher]${matcherPath}`);
}
+1 -2
View File
@@ -14,7 +14,6 @@ import {fileURLToPath} from 'url';
import {getJavaDistribution} from './distributions/distribution-factory.js'; import {getJavaDistribution} from './distributions/distribution-factory.js';
import {JavaInstallerOptions} from './distributions/base-models.js'; import {JavaInstallerOptions} from './distributions/base-models.js';
import {configureMavenArgs} from './maven-args.js'; import {configureMavenArgs} from './maven-args.js';
import {configureProblemMatcher} from './problem-matcher.js';
async function run() { async function run() {
try { try {
@@ -121,7 +120,7 @@ async function run() {
'..', '..',
'.github' '.github'
); );
configureProblemMatcher(path.join(matchersPath, 'java.json')); core.info(`##[add-matcher]${path.join(matchersPath, 'java.json')}`);
await auth.configureAuthentication(); await auth.configureAuthentication();
configureMavenArgs(); configureMavenArgs();