feat: implement cache-dependency-path option to control caching dependency (#499)

This commit is contained in:
itchyny 2023-11-23 00:43:14 +09:00 committed by GitHub
parent 78078da0cd
commit 9eda6b51cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 278 additions and 59 deletions

View file

@ -0,0 +1,93 @@
name: Validate cache with cache-dependency-path option
on:
push:
branches:
- main
- releases/*
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
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@v3
- 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: 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@v3
- 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@v3
- 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

View file

@ -36,7 +36,7 @@ jobs:
# Need to avoid using Gradle daemon to stabilize the save process on Windows # Need to avoid using Gradle daemon to stabilize the save process on Windows
# 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/gradle gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
if [ ! -d ~/.gradle/caches ]; then if [ ! -d ~/.gradle/caches ]; then
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly" echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
exit 1 exit 1

View file

@ -41,6 +41,8 @@ This action allows you to work with Java and Scala projects.
- `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`: 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.
@ -115,10 +117,13 @@ Currently, the following distributions are supported:
### Caching packages dependencies ### Caching packages dependencies
The action has a built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under hood for caching dependencies but requires less configuration settings. Supported package managers are gradle, maven and sbt. The format of the used cache key is `setup-java-${{ platform }}-${{ packageManager }}-${{ fileHash }}`, where the hash is based on the following files: The action has a built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under hood for caching dependencies but requires less configuration settings. Supported package managers are gradle, maven and sbt. The format of the used cache key is `setup-java-${{ platform }}-${{ packageManager }}-${{ fileHash }}`, where the hash is based on the following files:
- gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, and `**/versions.properties` - gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, and `**/versions.properties`
- maven: `**/pom.xml` - maven: `**/pom.xml`
- sbt: all sbt build definition files `**/*.sbt`, `**/project/build.properties`, `**/project/**.scala`, `**/project/**.sbt` - sbt: all sbt build definition files `**/*.sbt`, `**/project/build.properties`, `**/project/**.scala`, `**/project/**.sbt`
When the option `cache-dependency-path` is specified, the hash is based on the matching file. This option supports wildcards and a list of file names, and is especially useful for monorepos.
The workflow output `cache-hit` is set to indicate if an exact match was found for the key [as actions/cache does](https://github.com/actions/cache/tree/main#outputs). The workflow output `cache-hit` is set to indicate if an exact match was found for the key [as actions/cache does](https://github.com/actions/cache/tree/main#outputs).
The cache input is optional, and caching is turned off by default. The cache input is optional, and caching is turned off by default.
@ -132,6 +137,9 @@ steps:
distribution: 'temurin' distribution: 'temurin'
java-version: '17' java-version: '17'
cache: 'gradle' cache: 'gradle'
cache-dependency-path: | # optional
sub-project/*.gradle*
sub-project/**/gradle-wrapper.properties
- run: ./gradlew build --no-daemon - run: ./gradlew build --no-daemon
``` ```
@ -144,6 +152,7 @@ steps:
distribution: 'temurin' distribution: 'temurin'
java-version: '17' java-version: '17'
cache: 'maven' cache: 'maven'
cache-dependency-path: 'sub-project/pom.xml' # optional
- name: Build with Maven - name: Build with Maven
run: mvn -B package --file pom.xml run: mvn -B package --file pom.xml
``` ```
@ -157,6 +166,9 @@ steps:
distribution: 'temurin' distribution: 'temurin'
java-version: '17' java-version: '17'
cache: 'sbt' cache: 'sbt'
cache-dependency-path: | # optional
sub-project/build.sbt
sub-project/project/build.properties
- name: Build with SBT - name: Build with SBT
run: sbt package run: sbt package
``` ```

View file

@ -6,6 +6,7 @@ import * as fs from 'fs';
import * as os from 'os'; import * as os from 'os';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as cache from '@actions/cache'; import * as cache from '@actions/cache';
import * as glob from '@actions/glob';
describe('dependency cache', () => { describe('dependency cache', () => {
const ORIGINAL_RUNNER_OS = process.env['RUNNER_OS']; const ORIGINAL_RUNNER_OS = process.env['RUNNER_OS'];
@ -64,6 +65,10 @@ describe('dependency cache', () => {
ReturnType<typeof cache.restoreCache>, ReturnType<typeof cache.restoreCache>,
Parameters<typeof cache.restoreCache> Parameters<typeof cache.restoreCache>
>; >;
let spyGlobHashFiles: jest.SpyInstance<
ReturnType<typeof glob.hashFiles>,
Parameters<typeof glob.hashFiles>
>;
beforeEach(() => { beforeEach(() => {
spyCacheRestore = jest spyCacheRestore = jest
@ -71,18 +76,19 @@ describe('dependency cache', () => {
.mockImplementation((paths: string[], primaryKey: string) => .mockImplementation((paths: string[], primaryKey: string) =>
Promise.resolve(undefined) Promise.resolve(undefined)
); );
spyGlobHashFiles = jest.spyOn(glob, 'hashFiles');
spyWarning.mockImplementation(() => null); spyWarning.mockImplementation(() => null);
}); });
it('throws error if unsupported package manager specified', () => { it('throws error if unsupported package manager specified', () => {
return expect(restore('ant')).rejects.toThrow( return expect(restore('ant', '')).rejects.toThrow(
'unknown package manager specified: ant' 'unknown package manager specified: ant'
); );
}); });
describe('for maven', () => { describe('for maven', () => {
it('throws error if no pom.xml found', async () => { it('throws error if no pom.xml found', async () => {
await expect(restore('maven')).rejects.toThrow( await expect(restore('maven', '')).rejects.toThrow(
`No file in ${projectRoot( `No file in ${projectRoot(
workspace workspace
)} matched to [**/pom.xml], make sure you have checked out the target repository` )} matched to [**/pom.xml], make sure you have checked out the target repository`
@ -91,15 +97,16 @@ describe('dependency cache', () => {
it('downloads cache', async () => { it('downloads cache', async () => {
createFile(join(workspace, 'pom.xml')); createFile(join(workspace, 'pom.xml'));
await restore('maven'); await restore('maven', '');
expect(spyCacheRestore).toHaveBeenCalled(); expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith('**/pom.xml');
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('maven cache is not found'); expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
}); });
}); });
describe('for gradle', () => { describe('for gradle', () => {
it('throws error if no build.gradle found', async () => { it('throws error if no build.gradle found', async () => {
await expect(restore('gradle')).rejects.toThrow( await expect(restore('gradle', '')).rejects.toThrow(
`No file in ${projectRoot( `No file in ${projectRoot(
workspace workspace
)} matched to [**/*.gradle*,**/gradle-wrapper.properties,buildSrc/**/Versions.kt,buildSrc/**/Dependencies.kt,gradle/*.versions.toml,**/versions.properties], make sure you have checked out the target repository` )} matched to [**/*.gradle*,**/gradle-wrapper.properties,buildSrc/**/Versions.kt,buildSrc/**/Dependencies.kt,gradle/*.versions.toml,**/versions.properties], make sure you have checked out the target repository`
@ -108,16 +115,22 @@ describe('dependency cache', () => {
it('downloads cache based on build.gradle', async () => { it('downloads cache based on build.gradle', async () => {
createFile(join(workspace, 'build.gradle')); createFile(join(workspace, 'build.gradle'));
await restore('gradle'); await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled(); expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
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('downloads cache based on build.gradle.kts', async () => { it('downloads cache based on build.gradle.kts', async () => {
createFile(join(workspace, 'build.gradle.kts')); createFile(join(workspace, 'build.gradle.kts'));
await restore('gradle'); await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled(); expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found'); expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
}); });
@ -125,24 +138,30 @@ describe('dependency cache', () => {
createDirectory(join(workspace, 'gradle')); createDirectory(join(workspace, 'gradle'));
createFile(join(workspace, 'gradle', 'libs.versions.toml')); createFile(join(workspace, 'gradle', 'libs.versions.toml'));
await restore('gradle'); await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled(); expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
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('downloads cache based on buildSrc/Versions.kt', async () => { it('downloads cache based on buildSrc/Versions.kt', async () => {
createDirectory(join(workspace, 'buildSrc')); createDirectory(join(workspace, 'buildSrc'));
createFile(join(workspace, 'buildSrc', 'Versions.kt')); createFile(join(workspace, 'buildSrc', 'Versions.kt'));
await restore('gradle'); await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled(); expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found'); expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
}); });
});
describe('for sbt', () => { describe('for sbt', () => {
it('throws error if no build.sbt found', async () => { it('throws error if no build.sbt found', async () => {
await expect(restore('sbt')).rejects.toThrow( await expect(restore('sbt', '')).rejects.toThrow(
`No file in ${projectRoot( `No file in ${projectRoot(
workspace workspace
)} matched to [**/*.sbt,**/project/build.properties,**/project/**.scala,**/project/**.sbt], make sure you have checked out the target repository` )} matched to [**/*.sbt,**/project/build.properties,**/project/**.scala,**/project/**.sbt], make sure you have checked out the target repository`
@ -151,8 +170,11 @@ describe('dependency cache', () => {
it('downloads cache', async () => { it('downloads cache', async () => {
createFile(join(workspace, 'build.sbt')); createFile(join(workspace, 'build.sbt'));
await restore('sbt'); await restore('sbt', '');
expect(spyCacheRestore).toHaveBeenCalled(); expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/*.sbt\n**/project/build.properties\n**/project/**.scala\n**/project/**.sbt'
);
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('sbt cache is not found'); expect(spyInfo).toHaveBeenCalledWith('sbt cache is not found');
}); });
@ -161,11 +183,11 @@ describe('dependency cache', () => {
createDirectory(join(workspace, 'project')); createDirectory(join(workspace, 'project'));
createFile(join(workspace, 'project/DependenciesV1.scala')); createFile(join(workspace, 'project/DependenciesV1.scala'));
await restore('sbt'); await restore('sbt', '');
const firstCall = spySaveState.mock.calls.toString(); const firstCall = spySaveState.mock.calls.toString();
spySaveState.mockClear(); spySaveState.mockClear();
await restore('sbt'); await restore('sbt', '');
const secondCall = spySaveState.mock.calls.toString(); const secondCall = spySaveState.mock.calls.toString();
// Make sure multiple restores produce the same cache // Make sure multiple restores produce the same cache
@ -173,7 +195,7 @@ describe('dependency cache', () => {
spySaveState.mockClear(); spySaveState.mockClear();
createFile(join(workspace, 'project/DependenciesV2.scala')); createFile(join(workspace, 'project/DependenciesV2.scala'));
await restore('sbt'); await restore('sbt', '');
const thirdCall = spySaveState.mock.calls.toString(); const thirdCall = spySaveState.mock.calls.toString();
expect(firstCall).not.toBe(thirdCall); expect(firstCall).not.toBe(thirdCall);
@ -182,11 +204,55 @@ describe('dependency cache', () => {
it('downloads cache based on versions.properties', async () => { it('downloads cache based on versions.properties', async () => {
createFile(join(workspace, 'versions.properties')); createFile(join(workspace, 'versions.properties'));
await restore('gradle'); await restore('gradle', '');
expect(spyCacheRestore).toHaveBeenCalled(); expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/*.gradle*\n**/gradle-wrapper.properties\nbuildSrc/**/Versions.kt\nbuildSrc/**/Dependencies.kt\ngradle/*.versions.toml\n**/versions.properties'
);
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found'); expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
}); });
describe('cache-dependency-path', () => {
it('throws error if no matching dependency file found', async () => {
createFile(join(workspace, 'build.gradle.kts'));
await expect(
restore('gradle', 'sub-project/**/build.gradle.kts')
).rejects.toThrow(
`No file in ${projectRoot(
workspace
)} matched to [sub-project/**/build.gradle.kts], make sure you have checked out the target repository`
);
});
it('downloads cache based on the specified pattern', async () => {
createFile(join(workspace, 'build.gradle.kts'));
createDirectory(join(workspace, 'sub-project1'));
createFile(join(workspace, 'sub-project1', 'build.gradle.kts'));
createDirectory(join(workspace, 'sub-project2'));
createFile(join(workspace, 'sub-project2', 'build.gradle.kts'));
await restore('gradle', 'build.gradle.kts');
expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith('build.gradle.kts');
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
await restore('gradle', 'sub-project1/**/*.gradle*\n');
expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'sub-project1/**/*.gradle*'
);
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
await restore('gradle', '*.gradle*\nsub-project2/**/*.gradle*\n');
expect(spyCacheRestore).toHaveBeenCalled();
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'*.gradle*\nsub-project2/**/*.gradle*'
);
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
});
});
}); });
describe('save', () => { describe('save', () => {
let spyCacheSave: jest.SpyInstance< let spyCacheSave: jest.SpyInstance<

12
__tests__/cache/gradle2/.gitignore vendored Normal file
View file

@ -0,0 +1,12 @@
.gradle
**/build/
!src/**/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Cache of project
.gradletasknamecache

17
__tests__/cache/gradle2/build.gradle vendored Normal file
View file

@ -0,0 +1,17 @@
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.junit.jupiter:junit-jupiter-api:5.7.2'
}
tasks.register('downloadDependencies') {
doLast {
def total = configurations.compileClasspath.inject (0) { sum, file ->
sum + file.length()
}
println total
}
}

View file

@ -56,6 +56,9 @@ inputs:
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".'
required: false required: false
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
job-status: job-status:
description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting' description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting'
default: ${{ job.status }} default: ${{ job.status }}

24
dist/cleanup/index.js vendored
View file

@ -89724,28 +89724,31 @@ function findPackageManager(id) {
/** /**
* 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 }}"".
* If there is no file matched to {@link PackageManager.path}, the generated key ends with a dash (-).
* @see {@link https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#matching-a-cache-key|spec of cache key} * @see {@link https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#matching-a-cache-key|spec of cache key}
*/ */
function computeCacheKey(packageManager) { function computeCacheKey(packageManager, cacheDependencyPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const hash = yield glob.hashFiles(packageManager.pattern.join('\n')); const pattern = cacheDependencyPath
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${packageManager.id}-${hash}`; ? cacheDependencyPath.trim().split('\n')
: packageManager.pattern;
const fileHash = yield glob.hashFiles(pattern.join('\n'));
if (!fileHash) {
throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`);
}
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${packageManager.id}-${fileHash}`;
}); });
} }
/** /**
* Restore the dependency cache * Restore the dependency cache
* @param id ID of the package manager, should be "maven" or "gradle" * @param id ID of the package manager, should be "maven" or "gradle"
* @param cacheDependencyPath The path to a dependency file
*/ */
function restore(id) { function restore(id, cacheDependencyPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const packageManager = findPackageManager(id); const packageManager = findPackageManager(id);
const primaryKey = yield computeCacheKey(packageManager); const primaryKey = yield computeCacheKey(packageManager, cacheDependencyPath);
core.debug(`primary key is ${primaryKey}`); core.debug(`primary key is ${primaryKey}`);
core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey); core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey);
if (primaryKey.endsWith('-')) {
throw new Error(`No file in ${process.cwd()} matched to [${packageManager.pattern}], make sure you have checked out the target repository`);
}
// No "restoreKeys" is set, to start with a clear cache after dependency update (see https://github.com/actions/setup-java/issues/269) // No "restoreKeys" is set, to start with a clear cache after dependency update (see https://github.com/actions/setup-java/issues/269)
const matchedKey = yield cache.restoreCache(packageManager.path, primaryKey); const matchedKey = yield cache.restoreCache(packageManager.path, primaryKey);
if (matchedKey) { if (matchedKey) {
@ -89922,7 +89925,7 @@ else {
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0;
exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home'; exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home';
exports.INPUT_JAVA_VERSION = 'java-version'; exports.INPUT_JAVA_VERSION = 'java-version';
exports.INPUT_JAVA_VERSION_FILE = 'java-version-file'; exports.INPUT_JAVA_VERSION_FILE = 'java-version-file';
@ -89941,6 +89944,7 @@ exports.INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined; exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined;
exports.INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE'; exports.INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
exports.INPUT_CACHE = 'cache'; exports.INPUT_CACHE = 'cache';
exports.INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
exports.INPUT_JOB_STATUS = 'job-status'; exports.INPUT_JOB_STATUS = 'job-status';
exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint'; exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
exports.M2_DIR = '.m2'; exports.M2_DIR = '.m2';

27
dist/setup/index.js vendored
View file

@ -124929,28 +124929,31 @@ function findPackageManager(id) {
/** /**
* 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 }}"".
* If there is no file matched to {@link PackageManager.path}, the generated key ends with a dash (-).
* @see {@link https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#matching-a-cache-key|spec of cache key} * @see {@link https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#matching-a-cache-key|spec of cache key}
*/ */
function computeCacheKey(packageManager) { function computeCacheKey(packageManager, cacheDependencyPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const hash = yield glob.hashFiles(packageManager.pattern.join('\n')); const pattern = cacheDependencyPath
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${packageManager.id}-${hash}`; ? cacheDependencyPath.trim().split('\n')
: packageManager.pattern;
const fileHash = yield glob.hashFiles(pattern.join('\n'));
if (!fileHash) {
throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`);
}
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${packageManager.id}-${fileHash}`;
}); });
} }
/** /**
* Restore the dependency cache * Restore the dependency cache
* @param id ID of the package manager, should be "maven" or "gradle" * @param id ID of the package manager, should be "maven" or "gradle"
* @param cacheDependencyPath The path to a dependency file
*/ */
function restore(id) { function restore(id, cacheDependencyPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const packageManager = findPackageManager(id); const packageManager = findPackageManager(id);
const primaryKey = yield computeCacheKey(packageManager); const primaryKey = yield computeCacheKey(packageManager, cacheDependencyPath);
core.debug(`primary key is ${primaryKey}`); core.debug(`primary key is ${primaryKey}`);
core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey); core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey);
if (primaryKey.endsWith('-')) {
throw new Error(`No file in ${process.cwd()} matched to [${packageManager.pattern}], make sure you have checked out the target repository`);
}
// No "restoreKeys" is set, to start with a clear cache after dependency update (see https://github.com/actions/setup-java/issues/269) // No "restoreKeys" is set, to start with a clear cache after dependency update (see https://github.com/actions/setup-java/issues/269)
const matchedKey = yield cache.restoreCache(packageManager.path, primaryKey); const matchedKey = yield cache.restoreCache(packageManager.path, primaryKey);
if (matchedKey) { if (matchedKey) {
@ -125026,7 +125029,7 @@ function isProbablyGradleDaemonProblem(packageManager, error) {
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0;
exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home'; exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home';
exports.INPUT_JAVA_VERSION = 'java-version'; exports.INPUT_JAVA_VERSION = 'java-version';
exports.INPUT_JAVA_VERSION_FILE = 'java-version-file'; exports.INPUT_JAVA_VERSION_FILE = 'java-version-file';
@ -125045,6 +125048,7 @@ exports.INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined; exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined;
exports.INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE'; exports.INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
exports.INPUT_CACHE = 'cache'; exports.INPUT_CACHE = 'cache';
exports.INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
exports.INPUT_JOB_STATUS = 'job-status'; exports.INPUT_JOB_STATUS = 'job-status';
exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint'; exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
exports.M2_DIR = '.m2'; exports.M2_DIR = '.m2';
@ -127061,6 +127065,7 @@ function run() {
const packageType = core.getInput(constants.INPUT_JAVA_PACKAGE); const packageType = core.getInput(constants.INPUT_JAVA_PACKAGE);
const jdkFile = core.getInput(constants.INPUT_JDK_FILE); const jdkFile = core.getInput(constants.INPUT_JDK_FILE);
const cache = core.getInput(constants.INPUT_CACHE); const cache = core.getInput(constants.INPUT_CACHE);
const cacheDependencyPath = core.getInput(constants.INPUT_CACHE_DEPENDENCY_PATH);
const checkLatest = util_1.getBooleanInput(constants.INPUT_CHECK_LATEST, false); const checkLatest = util_1.getBooleanInput(constants.INPUT_CHECK_LATEST, false);
let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID); let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID);
core.startGroup('Installed distributions'); core.startGroup('Installed distributions');
@ -127096,7 +127101,7 @@ function run() {
core.info(`##[add-matcher]${path.join(matchersPath, 'java.json')}`); core.info(`##[add-matcher]${path.join(matchersPath, 'java.json')}`);
yield auth.configureAuthentication(); yield auth.configureAuthentication();
if (cache && util_1.isCacheFeatureAvailable()) { if (cache && util_1.isCacheFeatureAvailable()) {
yield cache_1.restore(cache); yield cache_1.restore(cache, cacheDependencyPath);
} }
} }
catch (error) { catch (error) {

View file

@ -83,31 +83,34 @@ function findPackageManager(id: string): PackageManager {
/** /**
* 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 }}"".
* If there is no file matched to {@link PackageManager.path}, the generated key ends with a dash (-).
* @see {@link https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#matching-a-cache-key|spec of cache key} * @see {@link https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#matching-a-cache-key|spec of cache key}
*/ */
async function computeCacheKey(packageManager: PackageManager) { async function computeCacheKey(
const hash = await glob.hashFiles(packageManager.pattern.join('\n')); packageManager: PackageManager,
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${packageManager.id}-${hash}`; cacheDependencyPath: string
) {
const pattern = cacheDependencyPath
? cacheDependencyPath.trim().split('\n')
: packageManager.pattern;
const fileHash = await glob.hashFiles(pattern.join('\n'));
if (!fileHash) {
throw new Error(
`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`
);
}
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${packageManager.id}-${fileHash}`;
} }
/** /**
* Restore the dependency cache * Restore the dependency cache
* @param id ID of the package manager, should be "maven" or "gradle" * @param id ID of the package manager, should be "maven" or "gradle"
* @param cacheDependencyPath The path to a dependency file
*/ */
export async function restore(id: string) { export async function restore(id: string, cacheDependencyPath: string) {
const packageManager = findPackageManager(id); const packageManager = findPackageManager(id);
const primaryKey = await computeCacheKey(packageManager); const primaryKey = await computeCacheKey(packageManager, cacheDependencyPath);
core.debug(`primary key is ${primaryKey}`); core.debug(`primary key is ${primaryKey}`);
core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey); core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey);
if (primaryKey.endsWith('-')) {
throw new Error(
`No file in ${process.cwd()} matched to [${
packageManager.pattern
}], make sure you have checked out the target repository`
);
}
// No "restoreKeys" is set, to start with a clear cache after dependency update (see https://github.com/actions/setup-java/issues/269) // No "restoreKeys" is set, to start with a clear cache after dependency update (see https://github.com/actions/setup-java/issues/269)
const matchedKey = await cache.restoreCache(packageManager.path, primaryKey); const matchedKey = await cache.restoreCache(packageManager.path, primaryKey);

View file

@ -18,6 +18,7 @@ export const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined;
export const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE'; export const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
export const INPUT_CACHE = 'cache'; export const INPUT_CACHE = 'cache';
export const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
export const INPUT_JOB_STATUS = 'job-status'; export const INPUT_JOB_STATUS = 'job-status';
export const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint'; export const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';

View file

@ -24,6 +24,9 @@ async function run() {
const packageType = core.getInput(constants.INPUT_JAVA_PACKAGE); const packageType = core.getInput(constants.INPUT_JAVA_PACKAGE);
const jdkFile = core.getInput(constants.INPUT_JDK_FILE); const jdkFile = core.getInput(constants.INPUT_JDK_FILE);
const cache = core.getInput(constants.INPUT_CACHE); const cache = core.getInput(constants.INPUT_CACHE);
const cacheDependencyPath = core.getInput(
constants.INPUT_CACHE_DEPENDENCY_PATH
);
const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false); const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false);
let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID); let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID);
@ -73,7 +76,7 @@ async function run() {
await auth.configureAuthentication(); await auth.configureAuthentication();
if (cache && isCacheFeatureAvailable()) { if (cache && isCacheFeatureAvailable()) {
await restore(cache); await restore(cache, cacheDependencyPath);
} }
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);