mirror of
https://github.com/actions/setup-java.git
synced 2026-07-30 17:19:27 +08:00
Add read-only dependency cache mode (#1169)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b3f6f152-8ac4-4c29-b04a-acac8e100777
This commit is contained in:
@@ -62,6 +62,7 @@ jobs:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: gradle
|
||||
cache-read-only: true
|
||||
- name: Confirm that ~/.gradle/caches directory has been made
|
||||
run: bash __tests__/check-dir.sh "$HOME/.gradle/caches"
|
||||
maven-save:
|
||||
@@ -105,6 +106,7 @@ jobs:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: maven
|
||||
cache-read-only: true
|
||||
- name: Confirm that ~/.m2/repository directory has been made
|
||||
run: bash __tests__/check-dir.sh "$HOME/.m2/repository"
|
||||
sbt-save:
|
||||
@@ -169,6 +171,7 @@ jobs:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: sbt
|
||||
cache-read-only: true
|
||||
|
||||
- name: Confirm that ~/Library/Caches/Coursier directory has been made
|
||||
if: matrix.os == 'macos-15-intel'
|
||||
|
||||
@@ -72,6 +72,8 @@ For more details, see the full release notes on the [releases page](https://git
|
||||
|
||||
- `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-read-only`: Restore dependency caches without saving changes in the post action. Defaults to `false`. Use this for pull requests, merge queues, short-lived branches, and fan-out jobs that should consume caches populated by a default-branch or seed job.
|
||||
|
||||
#### 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.
|
||||
|
||||
@@ -192,6 +194,54 @@ 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.
|
||||
|
||||
Set `cache-read-only: true` to restore the main dependency cache and any Maven
|
||||
or Gradle wrapper cache without archiving or uploading changes after the job.
|
||||
For example, a workflow can allow only the default branch to write caches while
|
||||
pull requests, merge queues, and short-lived branches remain read-only:
|
||||
|
||||
```yaml
|
||||
- uses: actions/setup-java@v6
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
|
||||
```
|
||||
|
||||
For a fan-out matrix, use one seed job to populate a complete cache and make
|
||||
every matrix job a read-only consumer. The seed and consumers must use the same
|
||||
runner OS and cache dependency inputs so they compute the same key:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
seed-cache:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-java@v6
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
- run: mvn dependency:go-offline dependency:resolve-plugins
|
||||
|
||||
build:
|
||||
needs: seed-cache
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
goal: [test, verify, package]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-java@v6
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
cache-read-only: true
|
||||
- run: mvn ${{ matrix.goal }}
|
||||
```
|
||||
|
||||
**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.
|
||||
|
||||
#### Caching gradle dependencies
|
||||
|
||||
@@ -120,6 +120,49 @@ describe('cleanup', () => {
|
||||
await cleanup();
|
||||
expect(spyCacheSave).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each(['maven', 'gradle', 'sbt'])(
|
||||
'does not save the %s cache in read-only mode',
|
||||
async packageManager => {
|
||||
createStateForSuccessfulRestoreWithWrapper(packageManager);
|
||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
|
||||
switch (name) {
|
||||
case 'cache':
|
||||
return packageManager;
|
||||
case 'cache-read-only':
|
||||
return 'true';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
await cleanup();
|
||||
|
||||
expect(spyCacheSave).not.toHaveBeenCalled();
|
||||
expect(core.getState).not.toHaveBeenCalled();
|
||||
expect(spyInfo).toHaveBeenCalledWith(
|
||||
'Cache saving is skipped because cache-read-only is enabled.'
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it('saves the cache when read-only mode is explicitly disabled', async () => {
|
||||
spyCacheSave.mockResolvedValue(0);
|
||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
|
||||
switch (name) {
|
||||
case 'cache':
|
||||
return 'maven';
|
||||
case 'cache-read-only':
|
||||
return 'false';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
await cleanup();
|
||||
|
||||
expect(spyCacheSave).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
function resetState() {
|
||||
@@ -141,3 +184,18 @@ function createStateForSuccessfulRestore() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createStateForSuccessfulRestoreWithWrapper(packageManager: string) {
|
||||
(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-${packageManager}-wrapper`:
|
||||
return `setup-java-${packageManager}-wrapper-primary-key`;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,6 +87,10 @@ inputs:
|
||||
cache-dependency-path:
|
||||
description: '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.'
|
||||
required: false
|
||||
cache-read-only:
|
||||
description: 'Restore dependency caches without saving cache changes in the post action.'
|
||||
required: false
|
||||
default: false
|
||||
job-status:
|
||||
description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting'
|
||||
required: false
|
||||
|
||||
Vendored
+10
-2
@@ -97338,6 +97338,7 @@ const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
|
||||
const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
|
||||
const INPUT_CACHE = 'cache';
|
||||
const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
|
||||
const INPUT_CACHE_READ_ONLY = 'cache-read-only';
|
||||
const INPUT_JOB_STATUS = 'job-status';
|
||||
const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
|
||||
const M2_DIR = '.m2';
|
||||
@@ -97365,7 +97366,7 @@ function getTempDir() {
|
||||
return tempDirectory;
|
||||
}
|
||||
function util_getBooleanInput(inputName, defaultValue = false) {
|
||||
const inputValue = core.getInput(inputName);
|
||||
const inputValue = getInput(inputName);
|
||||
const normalizedValue = inputValue.trim().toLowerCase();
|
||||
if (!normalizedValue) {
|
||||
return defaultValue;
|
||||
@@ -98076,7 +98077,14 @@ async function removePrivateKeyFromKeychain() {
|
||||
async function cleanup_java_saveCache() {
|
||||
const jobStatus = isJobStatusSuccess();
|
||||
const cache = getInput(INPUT_CACHE);
|
||||
return jobStatus && cache ? save(cache) : Promise.resolve();
|
||||
if (!jobStatus || !cache) {
|
||||
return;
|
||||
}
|
||||
if (util_getBooleanInput(INPUT_CACHE_READ_ONLY, false)) {
|
||||
info('Cache saving is skipped because cache-read-only is enabled.');
|
||||
return;
|
||||
}
|
||||
await save(cache);
|
||||
}
|
||||
/**
|
||||
* The save process is best-effort, and it should not make the workflow fail
|
||||
|
||||
Vendored
+1
@@ -72120,6 +72120,7 @@ const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
|
||||
const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
|
||||
const INPUT_CACHE = 'cache';
|
||||
const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
|
||||
const INPUT_CACHE_READ_ONLY = 'cache-read-only';
|
||||
const constants_INPUT_JOB_STATUS = 'job-status';
|
||||
const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
|
||||
const M2_DIR = '.m2';
|
||||
|
||||
+11
-2
@@ -1,7 +1,7 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as gpg from './gpg.js';
|
||||
import * as constants from './constants.js';
|
||||
import {isJobStatusSuccess} from './util.js';
|
||||
import {getBooleanInput, isJobStatusSuccess} from './util.js';
|
||||
import {save} from './cache.js';
|
||||
import {fileURLToPath} from 'url';
|
||||
|
||||
@@ -28,7 +28,16 @@ async function removePrivateKeyFromKeychain() {
|
||||
async function saveCache() {
|
||||
const jobStatus = isJobStatusSuccess();
|
||||
const cache = core.getInput(constants.INPUT_CACHE);
|
||||
return jobStatus && cache ? save(cache) : Promise.resolve();
|
||||
if (!jobStatus || !cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getBooleanInput(constants.INPUT_CACHE_READ_ONLY, false)) {
|
||||
core.info('Cache saving is skipped because cache-read-only is enabled.');
|
||||
return;
|
||||
}
|
||||
|
||||
await save(cache);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,7 @@ export const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
|
||||
|
||||
export const INPUT_CACHE = 'cache';
|
||||
export const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
|
||||
export const INPUT_CACHE_READ_ONLY = 'cache-read-only';
|
||||
export const INPUT_JOB_STATUS = 'job-status';
|
||||
|
||||
export const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
|
||||
|
||||
Reference in New Issue
Block a user