mirror of
https://github.com/actions/setup-node
synced 2025-04-19 22:53:12 +00:00
Handle globs in cacheDependencyPath
This commit is contained in:
parent
2b97a8fb23
commit
914a8e9bcc
@ -210,97 +210,4 @@ describe('authutil tests', () => {
|
|||||||
`@otherscope:registry=MMM${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
|
`@otherscope:registry=MMM${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getPackageManagerWorkingDir', () => {
|
|
||||||
let existsSpy: jest.SpyInstance;
|
|
||||||
let lstatSpy: jest.SpyInstance;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
existsSpy = jest.spyOn(fs, 'existsSync');
|
|
||||||
existsSpy.mockImplementation(() => true);
|
|
||||||
|
|
||||||
lstatSpy = jest.spyOn(fs, 'lstatSync');
|
|
||||||
lstatSpy.mockImplementation(arg => ({
|
|
||||||
isDirectory: () => true
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
existsSpy.mockRestore();
|
|
||||||
lstatSpy.mockRestore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getPackageManagerWorkingDir should return null for not yarn', async () => {
|
|
||||||
process.env['INPUT_CACHE'] = 'some';
|
|
||||||
delete process.env['INPUT_CACHE-DEPENDENCY-PATH'];
|
|
||||||
const dir = cacheUtils.getPackageManagerWorkingDir();
|
|
||||||
expect(dir).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getPackageManagerWorkingDir should return null for not yarn with cache-dependency-path', async () => {
|
|
||||||
process.env['INPUT_CACHE'] = 'some';
|
|
||||||
process.env['INPUT_CACHE-DEPENDENCY-PATH'] = '/foo/bar';
|
|
||||||
const dir = cacheUtils.getPackageManagerWorkingDir();
|
|
||||||
expect(dir).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getPackageManagerWorkingDir should return null for yarn but without cache-dependency-path', async () => {
|
|
||||||
process.env['INPUT_CACHE'] = 'yarn';
|
|
||||||
delete process.env['INPUT_CACHE-DEPENDENCY-PATH'];
|
|
||||||
const dir = cacheUtils.getPackageManagerWorkingDir();
|
|
||||||
expect(dir).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getPackageManagerWorkingDir should return null for yarn with cache-dependency-path for not-existing directory', async () => {
|
|
||||||
process.env['INPUT_CACHE'] = 'yarn';
|
|
||||||
const cachePath = '/foo/bar';
|
|
||||||
process.env['INPUT_CACHE-DEPENDENCY-PATH'] = cachePath;
|
|
||||||
lstatSpy.mockImplementation(arg => ({
|
|
||||||
isDirectory: () => false
|
|
||||||
}));
|
|
||||||
const dir = cacheUtils.getPackageManagerWorkingDir();
|
|
||||||
expect(dir).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getPackageManagerWorkingDir should return path for yarn with cache-dependency-path', async () => {
|
|
||||||
process.env['INPUT_CACHE'] = 'yarn';
|
|
||||||
const cachePath = '/foo/bar';
|
|
||||||
process.env['INPUT_CACHE-DEPENDENCY-PATH'] = cachePath;
|
|
||||||
const dir = cacheUtils.getPackageManagerWorkingDir();
|
|
||||||
expect(dir).toEqual(path.dirname(cachePath));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getCommandOutput(getPackageManagerVersion) should be called from with getPackageManagerWorkingDir result', async () => {
|
|
||||||
process.env['INPUT_CACHE'] = 'yarn';
|
|
||||||
const cachePath = '/foo/bar';
|
|
||||||
process.env['INPUT_CACHE-DEPENDENCY-PATH'] = cachePath;
|
|
||||||
const getCommandOutputSpy = jest
|
|
||||||
.spyOn(cacheUtils, 'getCommandOutput')
|
|
||||||
.mockReturnValue(Promise.resolve('baz'));
|
|
||||||
|
|
||||||
const version = await cacheUtils.getPackageManagerVersion('foo', 'bar');
|
|
||||||
expect(getCommandOutputSpy).toHaveBeenCalledWith(
|
|
||||||
`foo bar`,
|
|
||||||
path.dirname(cachePath)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getCommandOutput(getCacheDirectoryPath) should be called from with getPackageManagerWorkingDir result', async () => {
|
|
||||||
process.env['INPUT_CACHE'] = 'yarn';
|
|
||||||
const cachePath = '/foo/bar';
|
|
||||||
process.env['INPUT_CACHE-DEPENDENCY-PATH'] = cachePath;
|
|
||||||
const getCommandOutputSpy = jest
|
|
||||||
.spyOn(cacheUtils, 'getCommandOutput')
|
|
||||||
.mockReturnValue(Promise.resolve('baz'));
|
|
||||||
|
|
||||||
const version = await cacheUtils.getCacheDirectoryPath(
|
|
||||||
{lockFilePatterns: [], getCacheFolderCommand: 'quz'},
|
|
||||||
''
|
|
||||||
);
|
|
||||||
expect(getCommandOutputSpy).toHaveBeenCalledWith(
|
|
||||||
`quz`,
|
|
||||||
path.dirname(cachePath)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@ -32,13 +32,13 @@ describe('cache-restore', () => {
|
|||||||
|
|
||||||
function findCacheFolder(command: string) {
|
function findCacheFolder(command: string) {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case utils.supportedPackageManagers.npm.getCacheFolderCommand:
|
case utils.npmGetCacheFolderCommand:
|
||||||
return npmCachePath;
|
return npmCachePath;
|
||||||
case utils.supportedPackageManagers.pnpm.getCacheFolderCommand:
|
case utils.pnpmGetCacheFolderCommand:
|
||||||
return pnpmCachePath;
|
return pnpmCachePath;
|
||||||
case utils.supportedPackageManagers.yarn1.getCacheFolderCommand:
|
case utils.yarn1GetCacheFolderCommand:
|
||||||
return yarn1CachePath;
|
return yarn1CachePath;
|
||||||
case utils.supportedPackageManagers.yarn2.getCacheFolderCommand:
|
case utils.yarn2GetCacheFolderCommand:
|
||||||
return yarn2CachePath;
|
return yarn2CachePath;
|
||||||
default:
|
default:
|
||||||
return 'packge/not/found';
|
return 'packge/not/found';
|
||||||
@ -108,7 +108,7 @@ describe('cache-restore', () => {
|
|||||||
it.each([['npm7'], ['npm6'], ['pnpm6'], ['yarn1'], ['yarn2'], ['random']])(
|
it.each([['npm7'], ['npm6'], ['pnpm6'], ['yarn1'], ['yarn2'], ['random']])(
|
||||||
'Throw an error because %s is not supported',
|
'Throw an error because %s is not supported',
|
||||||
async packageManager => {
|
async packageManager => {
|
||||||
await expect(restoreCache(packageManager)).rejects.toThrow(
|
await expect(restoreCache(packageManager, '')).rejects.toThrow(
|
||||||
`Caching for '${packageManager}' is not supported`
|
`Caching for '${packageManager}' is not supported`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ describe('cache-restore', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await restoreCache(packageManager);
|
await restoreCache(packageManager, '');
|
||||||
expect(hashFilesSpy).toHaveBeenCalled();
|
expect(hashFilesSpy).toHaveBeenCalled();
|
||||||
expect(infoSpy).toHaveBeenCalledWith(
|
expect(infoSpy).toHaveBeenCalledWith(
|
||||||
`Cache restored from key: node-cache-${platform}-${packageManager}-v2-${fileHash}`
|
`Cache restored from key: node-cache-${platform}-${packageManager}-v2-${fileHash}`
|
||||||
@ -163,7 +163,7 @@ describe('cache-restore', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
restoreCacheSpy.mockImplementationOnce(() => undefined);
|
restoreCacheSpy.mockImplementationOnce(() => undefined);
|
||||||
await restoreCache(packageManager);
|
await restoreCache(packageManager, '');
|
||||||
expect(hashFilesSpy).toHaveBeenCalled();
|
expect(hashFilesSpy).toHaveBeenCalled();
|
||||||
expect(infoSpy).toHaveBeenCalledWith(
|
expect(infoSpy).toHaveBeenCalledWith(
|
||||||
`${packageManager} cache is not found`
|
`${packageManager} cache is not found`
|
||||||
|
@ -117,7 +117,9 @@ describe('run', () => {
|
|||||||
expect(getInputSpy).toHaveBeenCalled();
|
expect(getInputSpy).toHaveBeenCalled();
|
||||||
expect(getStateSpy).toHaveBeenCalledTimes(2);
|
expect(getStateSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
|
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(debugSpy).toHaveBeenCalledWith(`yarn path is ${commonPath}/yarn1`);
|
expect(debugSpy).toHaveBeenCalledWith(
|
||||||
|
'yarn path is /some/random/path/yarn1 (derived from cache-dependency-path: "")'
|
||||||
|
);
|
||||||
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 1.2.3');
|
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 1.2.3');
|
||||||
expect(infoSpy).toHaveBeenCalledWith(
|
expect(infoSpy).toHaveBeenCalledWith(
|
||||||
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
|
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
|
||||||
@ -137,7 +139,9 @@ describe('run', () => {
|
|||||||
expect(getInputSpy).toHaveBeenCalled();
|
expect(getInputSpy).toHaveBeenCalled();
|
||||||
expect(getStateSpy).toHaveBeenCalledTimes(2);
|
expect(getStateSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
|
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(debugSpy).toHaveBeenCalledWith(`yarn path is ${commonPath}/yarn2`);
|
expect(debugSpy).toHaveBeenCalledWith(
|
||||||
|
'yarn path is /some/random/path/yarn2 (derived from cache-dependency-path: "")'
|
||||||
|
);
|
||||||
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 2.2.3');
|
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 2.2.3');
|
||||||
expect(infoSpy).toHaveBeenCalledWith(
|
expect(infoSpy).toHaveBeenCalledWith(
|
||||||
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
|
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
|
||||||
@ -199,7 +203,9 @@ describe('run', () => {
|
|||||||
expect(getInputSpy).toHaveBeenCalled();
|
expect(getInputSpy).toHaveBeenCalled();
|
||||||
expect(getStateSpy).toHaveBeenCalledTimes(2);
|
expect(getStateSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
|
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(debugSpy).toHaveBeenCalledWith(`yarn path is ${commonPath}/yarn1`);
|
expect(debugSpy).toHaveBeenCalledWith(
|
||||||
|
'yarn path is /some/random/path/yarn1 (derived from cache-dependency-path: "")'
|
||||||
|
);
|
||||||
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 1.2.3');
|
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 1.2.3');
|
||||||
expect(infoSpy).not.toHaveBeenCalledWith(
|
expect(infoSpy).not.toHaveBeenCalledWith(
|
||||||
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
|
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
|
||||||
@ -229,7 +235,9 @@ describe('run', () => {
|
|||||||
expect(getInputSpy).toHaveBeenCalled();
|
expect(getInputSpy).toHaveBeenCalled();
|
||||||
expect(getStateSpy).toHaveBeenCalledTimes(2);
|
expect(getStateSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
|
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(debugSpy).toHaveBeenCalledWith(`yarn path is ${commonPath}/yarn2`);
|
expect(debugSpy).toHaveBeenCalledWith(
|
||||||
|
'yarn path is /some/random/path/yarn2 (derived from cache-dependency-path: "")'
|
||||||
|
);
|
||||||
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 2.2.3');
|
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 2.2.3');
|
||||||
expect(infoSpy).not.toHaveBeenCalledWith(
|
expect(infoSpy).not.toHaveBeenCalledWith(
|
||||||
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
|
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
|
||||||
|
@ -2,7 +2,18 @@ import * as core from '@actions/core';
|
|||||||
import * as cache from '@actions/cache';
|
import * as cache from '@actions/cache';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as utils from '../src/cache-utils';
|
import * as utils from '../src/cache-utils';
|
||||||
import {PackageManagerInfo, isCacheFeatureAvailable} from '../src/cache-utils';
|
import {
|
||||||
|
PackageManagerInfo,
|
||||||
|
isCacheFeatureAvailable,
|
||||||
|
supportedPackageManagers,
|
||||||
|
getCommandOutput,
|
||||||
|
expandCacheDependencyPath
|
||||||
|
} from '../src/cache-utils';
|
||||||
|
import fs from 'fs';
|
||||||
|
import * as cacheUtils from '../src/cache-utils';
|
||||||
|
import * as glob from '@actions/glob';
|
||||||
|
import {Globber} from '@actions/glob';
|
||||||
|
import {MockGlobber} from './mock/glob-mock';
|
||||||
|
|
||||||
describe('cache-utils', () => {
|
describe('cache-utils', () => {
|
||||||
const versionYarn1 = '1.2.3';
|
const versionYarn1 = '1.2.3';
|
||||||
@ -30,7 +41,7 @@ describe('cache-utils', () => {
|
|||||||
it.each<[string, PackageManagerInfo | null]>([
|
it.each<[string, PackageManagerInfo | null]>([
|
||||||
['npm', utils.supportedPackageManagers.npm],
|
['npm', utils.supportedPackageManagers.npm],
|
||||||
['pnpm', utils.supportedPackageManagers.pnpm],
|
['pnpm', utils.supportedPackageManagers.pnpm],
|
||||||
['yarn', utils.supportedPackageManagers.yarn1],
|
['yarn', utils.supportedPackageManagers.yarn],
|
||||||
['yarn1', null],
|
['yarn1', null],
|
||||||
['yarn2', null],
|
['yarn2', null],
|
||||||
['npm7', null]
|
['npm7', null]
|
||||||
@ -72,4 +83,284 @@ describe('cache-utils', () => {
|
|||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getCacheDirectoriesPaths', () => {
|
||||||
|
let existsSpy: jest.SpyInstance;
|
||||||
|
let lstatSpy: jest.SpyInstance;
|
||||||
|
let globCreateSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
existsSpy = jest.spyOn(fs, 'existsSync');
|
||||||
|
existsSpy.mockImplementation(() => true);
|
||||||
|
|
||||||
|
lstatSpy = jest.spyOn(fs, 'lstatSync');
|
||||||
|
lstatSpy.mockImplementation(arg => ({
|
||||||
|
isDirectory: () => true
|
||||||
|
}));
|
||||||
|
|
||||||
|
globCreateSpy = jest.spyOn(glob, 'create');
|
||||||
|
|
||||||
|
globCreateSpy.mockImplementation(
|
||||||
|
(pattern: string): Promise<Globber> =>
|
||||||
|
MockGlobber.create(['/foo', '/bar'])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
existsSpy.mockRestore();
|
||||||
|
lstatSpy.mockRestore();
|
||||||
|
globCreateSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('expandCacheDependencyPath should handle one line', async () => {
|
||||||
|
expect(await expandCacheDependencyPath('one')).toEqual(['one']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('expandCacheDependencyPath should handle one line glob', async () => {
|
||||||
|
globCreateSpy.mockImplementation(
|
||||||
|
(pattern: string): Promise<Globber> =>
|
||||||
|
MockGlobber.create(['one', 'two'])
|
||||||
|
);
|
||||||
|
expect(await expandCacheDependencyPath('**')).toEqual(['one', 'two']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('expandCacheDependencyPath should handle multiple lines', async () => {
|
||||||
|
const lines = `
|
||||||
|
one
|
||||||
|
two
|
||||||
|
|
||||||
|
`;
|
||||||
|
expect(await expandCacheDependencyPath(lines)).toEqual(['one', 'two']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('expandCacheDependencyPath should handle multiple globs', async () => {
|
||||||
|
const lines = `
|
||||||
|
one
|
||||||
|
**
|
||||||
|
|
||||||
|
`;
|
||||||
|
globCreateSpy.mockImplementation(
|
||||||
|
(pattern: string): Promise<Globber> =>
|
||||||
|
MockGlobber.create(['two', 'three'])
|
||||||
|
);
|
||||||
|
expect(await expandCacheDependencyPath(lines)).toEqual([
|
||||||
|
'one',
|
||||||
|
'two',
|
||||||
|
'three'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[supportedPackageManagers.npm, ''],
|
||||||
|
[supportedPackageManagers.npm, '/dir/file.lock'],
|
||||||
|
[supportedPackageManagers.npm, '/**/file.lock'],
|
||||||
|
[supportedPackageManagers.pnpm, ''],
|
||||||
|
[supportedPackageManagers.pnpm, '/dir/file.lock'],
|
||||||
|
[supportedPackageManagers.pnpm, '/**/file.lock']
|
||||||
|
])(
|
||||||
|
'getCacheDirectoriesPaths should return one dir for non yarn',
|
||||||
|
async (packageManagerInfo, cacheDependency) => {
|
||||||
|
getCommandOutputSpy.mockImplementation(() => 'foo');
|
||||||
|
|
||||||
|
const dirs = await cacheUtils.getCacheDirectoriesPaths(
|
||||||
|
packageManagerInfo,
|
||||||
|
cacheDependency
|
||||||
|
);
|
||||||
|
expect(dirs).toEqual(['foo']);
|
||||||
|
// to do not call for a version
|
||||||
|
// call once for get cache folder
|
||||||
|
expect(getCommandOutputSpy).toHaveBeenCalledTimes(1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('getCacheDirectoriesPaths should return one dir for yarn without cacheDependency', async () => {
|
||||||
|
getCommandOutputSpy.mockImplementation(() => 'foo');
|
||||||
|
|
||||||
|
const dirs = await cacheUtils.getCacheDirectoriesPaths(
|
||||||
|
supportedPackageManagers.yarn,
|
||||||
|
''
|
||||||
|
);
|
||||||
|
expect(dirs).toEqual(['foo']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[supportedPackageManagers.npm, ''],
|
||||||
|
[supportedPackageManagers.npm, '/dir/file.lock'],
|
||||||
|
[supportedPackageManagers.npm, '/**/file.lock'],
|
||||||
|
[supportedPackageManagers.pnpm, ''],
|
||||||
|
[supportedPackageManagers.pnpm, '/dir/file.lock'],
|
||||||
|
[supportedPackageManagers.pnpm, '/**/file.lock'],
|
||||||
|
[supportedPackageManagers.yarn, ''],
|
||||||
|
[supportedPackageManagers.yarn, '/dir/file.lock'],
|
||||||
|
[supportedPackageManagers.yarn, '/**/file.lock']
|
||||||
|
])(
|
||||||
|
'getCacheDirectoriesPaths should return empty array of folder in case of error',
|
||||||
|
async (packageManagerInfo, cacheDependency) => {
|
||||||
|
getCommandOutputSpy.mockImplementation((command: string) =>
|
||||||
|
// return empty string to indicate getCacheFolderPath failed
|
||||||
|
// --version still works
|
||||||
|
command.includes('version') ? '1.' : ''
|
||||||
|
);
|
||||||
|
lstatSpy.mockImplementation(arg => ({
|
||||||
|
isDirectory: () => false
|
||||||
|
}));
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
cacheUtils.getCacheDirectoriesPaths(
|
||||||
|
packageManagerInfo,
|
||||||
|
cacheDependency
|
||||||
|
)
|
||||||
|
).rejects.toThrow(); //'Could not get cache folder path for /dir');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each(['1.1.1', '2.2.2'])(
|
||||||
|
'getCacheDirectoriesPaths yarn v%s should return one dir without cacheDependency',
|
||||||
|
async version => {
|
||||||
|
getCommandOutputSpy.mockImplementationOnce(() => version);
|
||||||
|
getCommandOutputSpy.mockImplementationOnce(() => `foo${version}`);
|
||||||
|
|
||||||
|
const dirs = await cacheUtils.getCacheDirectoriesPaths(
|
||||||
|
supportedPackageManagers.yarn,
|
||||||
|
''
|
||||||
|
);
|
||||||
|
expect(dirs).toEqual([`foo${version}`]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each(['1.1.1', '2.2.2'])(
|
||||||
|
'getCacheDirectoriesPaths yarn v%s should return 2 dirs with globbed cacheDependency',
|
||||||
|
async version => {
|
||||||
|
let dirNo = 1;
|
||||||
|
getCommandOutputSpy.mockImplementation((command: string) =>
|
||||||
|
command.includes('version') ? version : `file_${version}_${dirNo++}`
|
||||||
|
);
|
||||||
|
globCreateSpy.mockImplementation(
|
||||||
|
(pattern: string): Promise<Globber> =>
|
||||||
|
MockGlobber.create(['/tmp/dir1/file', '/tmp/dir2/file'])
|
||||||
|
);
|
||||||
|
|
||||||
|
const dirs = await cacheUtils.getCacheDirectoriesPaths(
|
||||||
|
supportedPackageManagers.yarn,
|
||||||
|
'/tmp/**/file'
|
||||||
|
);
|
||||||
|
expect(dirs).toEqual([`file_${version}_1`, `file_${version}_2`]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: by design - glob is not expected to return duplicates so 3 patterns do not collapse to 2
|
||||||
|
it.each(['1.1.1', '2.2.2'])(
|
||||||
|
'getCacheDirectoriesPaths yarn v%s should return 3 dirs with globbed cacheDependency expanding to duplicates',
|
||||||
|
async version => {
|
||||||
|
let dirNo = 1;
|
||||||
|
getCommandOutputSpy.mockImplementation((command: string) =>
|
||||||
|
command.includes('version') ? version : `file_${version}_${dirNo++}`
|
||||||
|
);
|
||||||
|
globCreateSpy.mockImplementation(
|
||||||
|
(pattern: string): Promise<Globber> =>
|
||||||
|
MockGlobber.create([
|
||||||
|
'/tmp/dir1/file',
|
||||||
|
'/tmp/dir2/file',
|
||||||
|
'/tmp/dir1/file'
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const dirs = await cacheUtils.getCacheDirectoriesPaths(
|
||||||
|
supportedPackageManagers.yarn,
|
||||||
|
'/tmp/**/file'
|
||||||
|
);
|
||||||
|
expect(dirs).toEqual([
|
||||||
|
`file_${version}_1`,
|
||||||
|
`file_${version}_2`,
|
||||||
|
`file_${version}_3`
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each(['1.1.1', '2.2.2'])(
|
||||||
|
'getCacheDirectoriesPaths yarn v%s should return 2 uniq dirs despite duplicate cache directories',
|
||||||
|
async version => {
|
||||||
|
let dirNo = 1;
|
||||||
|
getCommandOutputSpy.mockImplementation((command: string) =>
|
||||||
|
command.includes('version')
|
||||||
|
? version
|
||||||
|
: `file_${version}_${dirNo++ % 2}`
|
||||||
|
);
|
||||||
|
globCreateSpy.mockImplementation(
|
||||||
|
(pattern: string): Promise<Globber> =>
|
||||||
|
MockGlobber.create([
|
||||||
|
'/tmp/dir1/file',
|
||||||
|
'/tmp/dir2/file',
|
||||||
|
'/tmp/dir3/file'
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const dirs = await cacheUtils.getCacheDirectoriesPaths(
|
||||||
|
supportedPackageManagers.yarn,
|
||||||
|
'/tmp/**/file'
|
||||||
|
);
|
||||||
|
expect(dirs).toEqual([`file_${version}_1`, `file_${version}_0`]);
|
||||||
|
expect(getCommandOutputSpy).toHaveBeenCalledTimes(6);
|
||||||
|
expect(getCommandOutputSpy).toHaveBeenCalledWith(
|
||||||
|
'yarn --version',
|
||||||
|
'/tmp/dir1'
|
||||||
|
);
|
||||||
|
expect(getCommandOutputSpy).toHaveBeenCalledWith(
|
||||||
|
'yarn --version',
|
||||||
|
'/tmp/dir2'
|
||||||
|
);
|
||||||
|
expect(getCommandOutputSpy).toHaveBeenCalledWith(
|
||||||
|
'yarn --version',
|
||||||
|
'/tmp/dir3'
|
||||||
|
);
|
||||||
|
expect(getCommandOutputSpy).toHaveBeenCalledWith(
|
||||||
|
version.startsWith('1.')
|
||||||
|
? 'yarn cache dir'
|
||||||
|
: 'yarn config get cacheFolder',
|
||||||
|
'/tmp/dir1'
|
||||||
|
);
|
||||||
|
expect(getCommandOutputSpy).toHaveBeenCalledWith(
|
||||||
|
version.startsWith('1.')
|
||||||
|
? 'yarn cache dir'
|
||||||
|
: 'yarn config get cacheFolder',
|
||||||
|
'/tmp/dir2'
|
||||||
|
);
|
||||||
|
expect(getCommandOutputSpy).toHaveBeenCalledWith(
|
||||||
|
version.startsWith('1.')
|
||||||
|
? 'yarn cache dir'
|
||||||
|
: 'yarn config get cacheFolder',
|
||||||
|
'/tmp/dir3'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each(['1.1.1', '2.2.2'])(
|
||||||
|
'getCacheDirectoriesPaths yarn v%s should return 4 dirs with multiple globs',
|
||||||
|
async version => {
|
||||||
|
// simulate wrong indents
|
||||||
|
const cacheDependencyPath = `/tmp/dir1/file
|
||||||
|
/tmp/dir2/file
|
||||||
|
/tmp/**/file
|
||||||
|
`;
|
||||||
|
globCreateSpy.mockImplementation(
|
||||||
|
(pattern: string): Promise<Globber> =>
|
||||||
|
MockGlobber.create(['/tmp/dir3/file', '/tmp/dir4/file'])
|
||||||
|
);
|
||||||
|
let dirNo = 1;
|
||||||
|
getCommandOutputSpy.mockImplementation((command: string) =>
|
||||||
|
command.includes('version') ? version : `file_${version}_${dirNo++}`
|
||||||
|
);
|
||||||
|
const dirs = await cacheUtils.getCacheDirectoriesPaths(
|
||||||
|
supportedPackageManagers.yarn,
|
||||||
|
cacheDependencyPath
|
||||||
|
);
|
||||||
|
expect(dirs).toEqual([
|
||||||
|
`file_${version}_1`,
|
||||||
|
`file_${version}_2`,
|
||||||
|
`file_${version}_3`,
|
||||||
|
`file_${version}_4`
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
18
__tests__/mock/glob-mock.test.ts
Normal file
18
__tests__/mock/glob-mock.test.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {MockGlobber} from './glob-mock';
|
||||||
|
|
||||||
|
describe('mocked globber tests', () => {
|
||||||
|
it('globber should return generator', async () => {
|
||||||
|
const globber = new MockGlobber(['aaa', 'bbb', 'ccc']);
|
||||||
|
const generator = globber.globGenerator();
|
||||||
|
const result: string[] = [];
|
||||||
|
for await (const itemPath of generator) {
|
||||||
|
result.push(itemPath);
|
||||||
|
}
|
||||||
|
expect(result).toEqual(['aaa', 'bbb', 'ccc']);
|
||||||
|
});
|
||||||
|
it('globber should return glob', async () => {
|
||||||
|
const globber = new MockGlobber(['aaa', 'bbb', 'ccc']);
|
||||||
|
const result: string[] = await globber.glob();
|
||||||
|
expect(result).toEqual(['aaa', 'bbb', 'ccc']);
|
||||||
|
});
|
||||||
|
});
|
29
__tests__/mock/glob-mock.ts
Normal file
29
__tests__/mock/glob-mock.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {Globber} from '@actions/glob';
|
||||||
|
|
||||||
|
export class MockGlobber implements Globber {
|
||||||
|
private readonly expected: string[];
|
||||||
|
constructor(expected: string[]) {
|
||||||
|
this.expected = expected;
|
||||||
|
}
|
||||||
|
getSearchPaths(): string[] {
|
||||||
|
return this.expected.slice();
|
||||||
|
}
|
||||||
|
|
||||||
|
async glob(): Promise<string[]> {
|
||||||
|
const result: string[] = [];
|
||||||
|
for await (const itemPath of this.globGenerator()) {
|
||||||
|
result.push(itemPath);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async *globGenerator(): AsyncGenerator<string, void> {
|
||||||
|
for (const e of this.expected) {
|
||||||
|
yield e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async create(expected: string[]): Promise<MockGlobber> {
|
||||||
|
return new MockGlobber(expected);
|
||||||
|
}
|
||||||
|
}
|
1322
dist/cache-save/index.js
vendored
1322
dist/cache-save/index.js
vendored
File diff suppressed because it is too large
Load Diff
124
dist/setup/index.js
vendored
124
dist/setup/index.js
vendored
@ -71144,7 +71144,7 @@ const restoreCache = (packageManager, cacheDependencyPath) => __awaiter(void 0,
|
|||||||
throw new Error(`Caching for '${packageManager}' is not supported`);
|
throw new Error(`Caching for '${packageManager}' is not supported`);
|
||||||
}
|
}
|
||||||
const platform = process.env.RUNNER_OS;
|
const platform = process.env.RUNNER_OS;
|
||||||
const cachePath = yield cache_utils_1.getCacheDirectoryPath(packageManagerInfo, packageManager);
|
const cachePaths = yield cache_utils_1.getCacheDirectoriesPaths(packageManagerInfo, cacheDependencyPath);
|
||||||
const lockFilePath = cacheDependencyPath
|
const lockFilePath = cacheDependencyPath
|
||||||
? cacheDependencyPath
|
? cacheDependencyPath
|
||||||
: findLockFile(packageManagerInfo);
|
: findLockFile(packageManagerInfo);
|
||||||
@ -71155,7 +71155,7 @@ const restoreCache = (packageManager, cacheDependencyPath) => __awaiter(void 0,
|
|||||||
const primaryKey = `node-cache-${platform}-${packageManager}-v2-${fileHash}`;
|
const primaryKey = `node-cache-${platform}-${packageManager}-v2-${fileHash}`;
|
||||||
core.debug(`primary key is ${primaryKey}`);
|
core.debug(`primary key is ${primaryKey}`);
|
||||||
core.saveState(constants_1.State.CachePrimaryKey, primaryKey);
|
core.saveState(constants_1.State.CachePrimaryKey, primaryKey);
|
||||||
const cacheKey = yield cache.restoreCache([cachePath], primaryKey);
|
const cacheKey = yield cache.restoreCache(cachePaths, primaryKey);
|
||||||
core.setOutput('cache-hit', Boolean(cacheKey));
|
core.setOutput('cache-hit', Boolean(cacheKey));
|
||||||
if (!cacheKey) {
|
if (!cacheKey) {
|
||||||
core.info(`${packageManager} cache is not found`);
|
core.info(`${packageManager} cache is not found`);
|
||||||
@ -71216,32 +71216,47 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoryPath = exports.getPackageManagerInfo = exports.getPackageManagerVersion = exports.getPackageManagerCommandOutput = exports.getPackageManagerWorkingDir = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
|
exports.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoriesPaths = exports.expandCacheDependencyPath = exports.getPackageManagerInfo = exports.getCommandOutputGuarded = exports.getCommandOutput = exports.supportedPackageManagers = exports.yarn2GetCacheFolderCommand = exports.yarn1GetCacheFolderCommand = exports.pnpmGetCacheFolderCommand = exports.npmGetCacheFolderCommand = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const exec = __importStar(__nccwpck_require__(1514));
|
const exec = __importStar(__nccwpck_require__(1514));
|
||||||
const cache = __importStar(__nccwpck_require__(7799));
|
const cache = __importStar(__nccwpck_require__(7799));
|
||||||
|
const glob = __importStar(__nccwpck_require__(8090));
|
||||||
const path_1 = __importDefault(__nccwpck_require__(1017));
|
const path_1 = __importDefault(__nccwpck_require__(1017));
|
||||||
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
||||||
|
// for testing purposes
|
||||||
|
exports.npmGetCacheFolderCommand = 'npm config get cache';
|
||||||
|
exports.pnpmGetCacheFolderCommand = 'pnpm store path --silent';
|
||||||
|
exports.yarn1GetCacheFolderCommand = 'yarn cache dir';
|
||||||
|
exports.yarn2GetCacheFolderCommand = 'yarn config get cacheFolder';
|
||||||
exports.supportedPackageManagers = {
|
exports.supportedPackageManagers = {
|
||||||
npm: {
|
npm: {
|
||||||
|
name: 'npm',
|
||||||
lockFilePatterns: ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock'],
|
lockFilePatterns: ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock'],
|
||||||
getCacheFolderCommand: 'npm config get cache'
|
getCacheFolderPath: () => exports.getCommandOutputGuarded(exports.npmGetCacheFolderCommand, 'Could not get npm cache folder path')
|
||||||
},
|
},
|
||||||
pnpm: {
|
pnpm: {
|
||||||
|
name: 'pnpm',
|
||||||
lockFilePatterns: ['pnpm-lock.yaml'],
|
lockFilePatterns: ['pnpm-lock.yaml'],
|
||||||
getCacheFolderCommand: 'pnpm store path --silent'
|
getCacheFolderPath: () => exports.getCommandOutputGuarded(exports.pnpmGetCacheFolderCommand, 'Could not get pnpm cache folder path')
|
||||||
},
|
},
|
||||||
yarn1: {
|
yarn: {
|
||||||
|
name: 'yarn',
|
||||||
lockFilePatterns: ['yarn.lock'],
|
lockFilePatterns: ['yarn.lock'],
|
||||||
getCacheFolderCommand: 'yarn cache dir'
|
getCacheFolderPath: (projectDir) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
},
|
const yarnVersion = yield exports.getCommandOutputGuarded(`yarn --version`, 'Could not retrieve version of yarn', projectDir);
|
||||||
yarn2: {
|
core.debug(`Consumed yarn version is ${yarnVersion}`);
|
||||||
lockFilePatterns: ['yarn.lock'],
|
const stdOut = yarnVersion.startsWith('1.')
|
||||||
getCacheFolderCommand: 'yarn config get cacheFolder'
|
? yield exports.getCommandOutput(exports.yarn1GetCacheFolderCommand, projectDir)
|
||||||
|
: yield exports.getCommandOutput(exports.yarn2GetCacheFolderCommand, projectDir);
|
||||||
|
if (!stdOut) {
|
||||||
|
throw new Error(`Could not get yarn cache folder path for ${projectDir}`);
|
||||||
|
}
|
||||||
|
return stdOut;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const getCommandOutput = (toolCommand, cwd) => __awaiter(void 0, void 0, void 0, function* () {
|
const getCommandOutput = (toolCommand, cwd) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, Object.assign({ ignoreReturnCode: true }, (cwd !== null && { cwd })));
|
let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, Object.assign({ ignoreReturnCode: true }, (cwd && { cwd })));
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
stderr = !stderr.trim()
|
stderr = !stderr.trim()
|
||||||
? `The '${toolCommand}' command failed with exit code: ${exitCode}`
|
? `The '${toolCommand}' command failed with exit code: ${exitCode}`
|
||||||
@ -71251,32 +71266,14 @@ const getCommandOutput = (toolCommand, cwd) => __awaiter(void 0, void 0, void 0,
|
|||||||
return stdout.trim();
|
return stdout.trim();
|
||||||
});
|
});
|
||||||
exports.getCommandOutput = getCommandOutput;
|
exports.getCommandOutput = getCommandOutput;
|
||||||
const getPackageManagerWorkingDir = () => {
|
const getCommandOutputGuarded = (toolCommand, error, cwd) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const cache = core.getInput('cache');
|
const stdOut = exports.getCommandOutput(toolCommand, cwd);
|
||||||
if (cache !== 'yarn') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const cacheDependencyPath = core.getInput('cache-dependency-path');
|
|
||||||
if (!cacheDependencyPath) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const wd = path_1.default.dirname(cacheDependencyPath);
|
|
||||||
if (fs_1.default.existsSync(wd) && fs_1.default.lstatSync(wd).isDirectory()) {
|
|
||||||
return wd;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
exports.getPackageManagerWorkingDir = getPackageManagerWorkingDir;
|
|
||||||
const getPackageManagerCommandOutput = (command) => exports.getCommandOutput(command, exports.getPackageManagerWorkingDir());
|
|
||||||
exports.getPackageManagerCommandOutput = getPackageManagerCommandOutput;
|
|
||||||
const getPackageManagerVersion = (packageManager, command) => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
const stdOut = yield exports.getPackageManagerCommandOutput(`${packageManager} ${command}`);
|
|
||||||
if (!stdOut) {
|
if (!stdOut) {
|
||||||
throw new Error(`Could not retrieve version of ${packageManager}`);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
return stdOut;
|
return stdOut;
|
||||||
});
|
});
|
||||||
exports.getPackageManagerVersion = getPackageManagerVersion;
|
exports.getCommandOutputGuarded = getCommandOutputGuarded;
|
||||||
const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () {
|
const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
if (packageManager === 'npm') {
|
if (packageManager === 'npm') {
|
||||||
return exports.supportedPackageManagers.npm;
|
return exports.supportedPackageManagers.npm;
|
||||||
@ -71285,29 +71282,56 @@ const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void
|
|||||||
return exports.supportedPackageManagers.pnpm;
|
return exports.supportedPackageManagers.pnpm;
|
||||||
}
|
}
|
||||||
else if (packageManager === 'yarn') {
|
else if (packageManager === 'yarn') {
|
||||||
const yarnVersion = yield exports.getPackageManagerVersion('yarn', '--version');
|
return exports.supportedPackageManagers.yarn;
|
||||||
core.debug(`Consumed yarn version is ${yarnVersion}`);
|
|
||||||
if (yarnVersion.startsWith('1.')) {
|
|
||||||
return exports.supportedPackageManagers.yarn1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return exports.supportedPackageManagers.yarn2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
exports.getPackageManagerInfo = getPackageManagerInfo;
|
exports.getPackageManagerInfo = getPackageManagerInfo;
|
||||||
const getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaiter(void 0, void 0, void 0, function* () {
|
const globPatternToArray = (pattern) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const stdOut = yield exports.getPackageManagerCommandOutput(packageManagerInfo.getCacheFolderCommand);
|
const globber = yield glob.create(pattern);
|
||||||
if (!stdOut) {
|
return globber.glob();
|
||||||
throw new Error(`Could not get cache folder path for ${packageManager}`);
|
|
||||||
}
|
|
||||||
core.debug(`${packageManager} path is ${stdOut}`);
|
|
||||||
return stdOut.trim();
|
|
||||||
});
|
});
|
||||||
exports.getCacheDirectoryPath = getCacheDirectoryPath;
|
const expandCacheDependencyPath = (cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const multilinePaths = cacheDependencyPath
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.map(path => path.trim())
|
||||||
|
.filter(path => Boolean(path));
|
||||||
|
const expandedPathsPromises = multilinePaths.map(path => path.includes('*') ? globPatternToArray(path) : Promise.resolve([path]));
|
||||||
|
const expandedPaths = yield Promise.all(expandedPathsPromises);
|
||||||
|
return expandedPaths.length === 0 ? [''] : expandedPaths.flat();
|
||||||
|
});
|
||||||
|
exports.expandCacheDependencyPath = expandCacheDependencyPath;
|
||||||
|
const cacheDependencyPathToCacheFolderPath = (packageManagerInfo, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const cacheDependencyPathDirectory = path_1.default.dirname(cacheDependencyPath);
|
||||||
|
const cacheFolderPath = fs_1.default.existsSync(cacheDependencyPathDirectory) &&
|
||||||
|
fs_1.default.lstatSync(cacheDependencyPathDirectory).isDirectory()
|
||||||
|
? yield packageManagerInfo.getCacheFolderPath(cacheDependencyPathDirectory)
|
||||||
|
: yield packageManagerInfo.getCacheFolderPath();
|
||||||
|
core.debug(`${packageManagerInfo.name} path is ${cacheFolderPath} (derived from cache-dependency-path: "${cacheDependencyPath}")`);
|
||||||
|
return cacheFolderPath;
|
||||||
|
});
|
||||||
|
const cacheDependenciesPathsToCacheFoldersPaths = (packageManagerInfo, cacheDependenciesPaths) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const cacheFoldersPaths = yield Promise.all(cacheDependenciesPaths.map(cacheDependencyPath => cacheDependencyPathToCacheFolderPath(packageManagerInfo, cacheDependencyPath)));
|
||||||
|
return cacheFoldersPaths.filter((cachePath, i, result) => result.indexOf(cachePath) === i);
|
||||||
|
});
|
||||||
|
const cacheDependencyPathToCacheFoldersPaths = (packageManagerInfo, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const cacheDependenciesPaths = yield exports.expandCacheDependencyPath(cacheDependencyPath);
|
||||||
|
return cacheDependenciesPathsToCacheFoldersPaths(packageManagerInfo, cacheDependenciesPaths);
|
||||||
|
});
|
||||||
|
const cacheFoldersPathsForRoot = (packageManagerInfo) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const cacheFolderPath = yield packageManagerInfo.getCacheFolderPath();
|
||||||
|
core.debug(`${packageManagerInfo.name} path is ${cacheFolderPath}`);
|
||||||
|
return [cacheFolderPath];
|
||||||
|
});
|
||||||
|
const getCacheDirectoriesPaths = (packageManagerInfo, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
// TODO: multiple directories limited to yarn so far
|
||||||
|
return packageManagerInfo === exports.supportedPackageManagers.yarn
|
||||||
|
? cacheDependencyPathToCacheFoldersPaths(packageManagerInfo, cacheDependencyPath)
|
||||||
|
: cacheFoldersPathsForRoot(packageManagerInfo);
|
||||||
|
});
|
||||||
|
exports.getCacheDirectoriesPaths = getCacheDirectoriesPaths;
|
||||||
function isGhes() {
|
function isGhes() {
|
||||||
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
||||||
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
||||||
|
@ -6,14 +6,14 @@ import fs from 'fs';
|
|||||||
|
|
||||||
import {State} from './constants';
|
import {State} from './constants';
|
||||||
import {
|
import {
|
||||||
getCacheDirectoryPath,
|
getCacheDirectoriesPaths,
|
||||||
getPackageManagerInfo,
|
getPackageManagerInfo,
|
||||||
PackageManagerInfo
|
PackageManagerInfo
|
||||||
} from './cache-utils';
|
} from './cache-utils';
|
||||||
|
|
||||||
export const restoreCache = async (
|
export const restoreCache = async (
|
||||||
packageManager: string,
|
packageManager: string,
|
||||||
cacheDependencyPath?: string
|
cacheDependencyPath: string
|
||||||
) => {
|
) => {
|
||||||
const packageManagerInfo = await getPackageManagerInfo(packageManager);
|
const packageManagerInfo = await getPackageManagerInfo(packageManager);
|
||||||
if (!packageManagerInfo) {
|
if (!packageManagerInfo) {
|
||||||
@ -21,9 +21,9 @@ export const restoreCache = async (
|
|||||||
}
|
}
|
||||||
const platform = process.env.RUNNER_OS;
|
const platform = process.env.RUNNER_OS;
|
||||||
|
|
||||||
const cachePath = await getCacheDirectoryPath(
|
const cachePaths = await getCacheDirectoriesPaths(
|
||||||
packageManagerInfo,
|
packageManagerInfo,
|
||||||
packageManager
|
cacheDependencyPath
|
||||||
);
|
);
|
||||||
const lockFilePath = cacheDependencyPath
|
const lockFilePath = cacheDependencyPath
|
||||||
? cacheDependencyPath
|
? cacheDependencyPath
|
||||||
@ -41,7 +41,7 @@ export const restoreCache = async (
|
|||||||
|
|
||||||
core.saveState(State.CachePrimaryKey, primaryKey);
|
core.saveState(State.CachePrimaryKey, primaryKey);
|
||||||
|
|
||||||
const cacheKey = await cache.restoreCache([cachePath], primaryKey);
|
const cacheKey = await cache.restoreCache(cachePaths, primaryKey);
|
||||||
core.setOutput('cache-hit', Boolean(cacheKey));
|
core.setOutput('cache-hit', Boolean(cacheKey));
|
||||||
|
|
||||||
if (!cacheKey) {
|
if (!cacheKey) {
|
||||||
|
@ -2,7 +2,7 @@ import * as core from '@actions/core';
|
|||||||
import * as cache from '@actions/cache';
|
import * as cache from '@actions/cache';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import {State} from './constants';
|
import {State} from './constants';
|
||||||
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
|
import {getCacheDirectoriesPaths, getPackageManagerInfo} from './cache-utils';
|
||||||
|
|
||||||
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||||
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
||||||
@ -31,14 +31,17 @@ const cachePackages = async (packageManager: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cachePath = await getCacheDirectoryPath(
|
// TODO: core.getInput has a bug - it can return undefined despite its definition
|
||||||
|
// export declare function getInput(name: string, options?: InputOptions): string;
|
||||||
|
const cacheDependencyPath = core.getInput('cache-dependency-path') || '';
|
||||||
|
const cachePaths = await getCacheDirectoriesPaths(
|
||||||
packageManagerInfo,
|
packageManagerInfo,
|
||||||
packageManager
|
cacheDependencyPath
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!fs.existsSync(cachePath)) {
|
if (cachePaths.length === 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Cache folder path is retrieved for ${packageManager} but doesn't exist on disk: ${cachePath}`
|
`Cache folder paths are not retrieved for ${packageManager} with cache-dependency-path = ${cacheDependencyPath}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +52,7 @@ const cachePackages = async (packageManager: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cacheId = await cache.saveCache([cachePath], primaryKey);
|
const cacheId = await cache.saveCache(cachePaths, primaryKey);
|
||||||
if (cacheId == -1) {
|
if (cacheId == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,45 +1,80 @@
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import * as cache from '@actions/cache';
|
import * as cache from '@actions/cache';
|
||||||
|
import * as glob from '@actions/glob';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
type SupportedPackageManagers = {
|
|
||||||
[prop: string]: PackageManagerInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface PackageManagerInfo {
|
export interface PackageManagerInfo {
|
||||||
|
name: string;
|
||||||
lockFilePatterns: Array<string>;
|
lockFilePatterns: Array<string>;
|
||||||
getCacheFolderCommand: string;
|
getCacheFolderPath: (projectDir?: string) => Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SupportedPackageManagers {
|
||||||
|
npm: PackageManagerInfo;
|
||||||
|
pnpm: PackageManagerInfo;
|
||||||
|
yarn: PackageManagerInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for testing purposes
|
||||||
|
export const npmGetCacheFolderCommand = 'npm config get cache';
|
||||||
|
export const pnpmGetCacheFolderCommand = 'pnpm store path --silent';
|
||||||
|
export const yarn1GetCacheFolderCommand = 'yarn cache dir';
|
||||||
|
export const yarn2GetCacheFolderCommand = 'yarn config get cacheFolder';
|
||||||
export const supportedPackageManagers: SupportedPackageManagers = {
|
export const supportedPackageManagers: SupportedPackageManagers = {
|
||||||
npm: {
|
npm: {
|
||||||
|
name: 'npm',
|
||||||
lockFilePatterns: ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock'],
|
lockFilePatterns: ['package-lock.json', 'npm-shrinkwrap.json', 'yarn.lock'],
|
||||||
getCacheFolderCommand: 'npm config get cache'
|
getCacheFolderPath: () =>
|
||||||
|
getCommandOutputGuarded(
|
||||||
|
npmGetCacheFolderCommand,
|
||||||
|
'Could not get npm cache folder path'
|
||||||
|
)
|
||||||
},
|
},
|
||||||
pnpm: {
|
pnpm: {
|
||||||
|
name: 'pnpm',
|
||||||
lockFilePatterns: ['pnpm-lock.yaml'],
|
lockFilePatterns: ['pnpm-lock.yaml'],
|
||||||
getCacheFolderCommand: 'pnpm store path --silent'
|
getCacheFolderPath: () =>
|
||||||
|
getCommandOutputGuarded(
|
||||||
|
pnpmGetCacheFolderCommand,
|
||||||
|
'Could not get pnpm cache folder path'
|
||||||
|
)
|
||||||
},
|
},
|
||||||
yarn1: {
|
yarn: {
|
||||||
|
name: 'yarn',
|
||||||
lockFilePatterns: ['yarn.lock'],
|
lockFilePatterns: ['yarn.lock'],
|
||||||
getCacheFolderCommand: 'yarn cache dir'
|
getCacheFolderPath: async projectDir => {
|
||||||
},
|
const yarnVersion = await getCommandOutputGuarded(
|
||||||
yarn2: {
|
`yarn --version`,
|
||||||
lockFilePatterns: ['yarn.lock'],
|
'Could not retrieve version of yarn',
|
||||||
getCacheFolderCommand: 'yarn config get cacheFolder'
|
projectDir
|
||||||
|
);
|
||||||
|
|
||||||
|
core.debug(`Consumed yarn version is ${yarnVersion}`);
|
||||||
|
|
||||||
|
const stdOut = yarnVersion.startsWith('1.')
|
||||||
|
? await getCommandOutput(yarn1GetCacheFolderCommand, projectDir)
|
||||||
|
: await getCommandOutput(yarn2GetCacheFolderCommand, projectDir);
|
||||||
|
|
||||||
|
if (!stdOut) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not get yarn cache folder path for ${projectDir}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return stdOut;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCommandOutput = async (
|
export const getCommandOutput = async (
|
||||||
toolCommand: string,
|
toolCommand: string,
|
||||||
cwd: string | null
|
cwd?: string
|
||||||
) => {
|
): Promise<string> => {
|
||||||
let {stdout, stderr, exitCode} = await exec.getExecOutput(
|
let {stdout, stderr, exitCode} = await exec.getExecOutput(
|
||||||
toolCommand,
|
toolCommand,
|
||||||
undefined,
|
undefined,
|
||||||
{ignoreReturnCode: true, ...(cwd !== null && {cwd})}
|
{ignoreReturnCode: true, ...(cwd && {cwd})}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
@ -52,41 +87,15 @@ export const getCommandOutput = async (
|
|||||||
return stdout.trim();
|
return stdout.trim();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getPackageManagerWorkingDir = (): string | null => {
|
export const getCommandOutputGuarded = async (
|
||||||
const cache = core.getInput('cache');
|
toolCommand: string,
|
||||||
if (cache !== 'yarn') {
|
error: string,
|
||||||
return null;
|
cwd?: string
|
||||||
}
|
): Promise<string> => {
|
||||||
|
const stdOut = getCommandOutput(toolCommand, cwd);
|
||||||
const cacheDependencyPath = core.getInput('cache-dependency-path');
|
|
||||||
if (!cacheDependencyPath) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wd = path.dirname(cacheDependencyPath);
|
|
||||||
|
|
||||||
if (fs.existsSync(wd) && fs.lstatSync(wd).isDirectory()) {
|
|
||||||
return wd;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPackageManagerCommandOutput = (command: string) =>
|
|
||||||
getCommandOutput(command, getPackageManagerWorkingDir());
|
|
||||||
|
|
||||||
export const getPackageManagerVersion = async (
|
|
||||||
packageManager: string,
|
|
||||||
command: string
|
|
||||||
) => {
|
|
||||||
const stdOut = await getPackageManagerCommandOutput(
|
|
||||||
`${packageManager} ${command}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!stdOut) {
|
if (!stdOut) {
|
||||||
throw new Error(`Could not retrieve version of ${packageManager}`);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return stdOut;
|
return stdOut;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,36 +105,99 @@ export const getPackageManagerInfo = async (packageManager: string) => {
|
|||||||
} else if (packageManager === 'pnpm') {
|
} else if (packageManager === 'pnpm') {
|
||||||
return supportedPackageManagers.pnpm;
|
return supportedPackageManagers.pnpm;
|
||||||
} else if (packageManager === 'yarn') {
|
} else if (packageManager === 'yarn') {
|
||||||
const yarnVersion = await getPackageManagerVersion('yarn', '--version');
|
return supportedPackageManagers.yarn;
|
||||||
|
|
||||||
core.debug(`Consumed yarn version is ${yarnVersion}`);
|
|
||||||
|
|
||||||
if (yarnVersion.startsWith('1.')) {
|
|
||||||
return supportedPackageManagers.yarn1;
|
|
||||||
} else {
|
|
||||||
return supportedPackageManagers.yarn2;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCacheDirectoryPath = async (
|
const globPatternToArray = async (pattern: string): Promise<string[]> => {
|
||||||
|
const globber = await glob.create(pattern);
|
||||||
|
return globber.glob();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const expandCacheDependencyPath = async (
|
||||||
|
cacheDependencyPath: string
|
||||||
|
): Promise<string[]> => {
|
||||||
|
const multilinePaths = cacheDependencyPath
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.map(path => path.trim())
|
||||||
|
.filter(path => Boolean(path));
|
||||||
|
const expandedPathsPromises: Promise<string[]>[] = multilinePaths.map(path =>
|
||||||
|
path.includes('*') ? globPatternToArray(path) : Promise.resolve([path])
|
||||||
|
);
|
||||||
|
const expandedPaths: string[][] = await Promise.all(expandedPathsPromises);
|
||||||
|
return expandedPaths.length === 0 ? [''] : expandedPaths.flat();
|
||||||
|
};
|
||||||
|
|
||||||
|
const cacheDependencyPathToCacheFolderPath = async (
|
||||||
packageManagerInfo: PackageManagerInfo,
|
packageManagerInfo: PackageManagerInfo,
|
||||||
packageManager: string
|
cacheDependencyPath: string
|
||||||
) => {
|
): Promise<string> => {
|
||||||
const stdOut = await getPackageManagerCommandOutput(
|
const cacheDependencyPathDirectory = path.dirname(cacheDependencyPath);
|
||||||
packageManagerInfo.getCacheFolderCommand
|
const cacheFolderPath =
|
||||||
|
fs.existsSync(cacheDependencyPathDirectory) &&
|
||||||
|
fs.lstatSync(cacheDependencyPathDirectory).isDirectory()
|
||||||
|
? await packageManagerInfo.getCacheFolderPath(
|
||||||
|
cacheDependencyPathDirectory
|
||||||
|
)
|
||||||
|
: await packageManagerInfo.getCacheFolderPath();
|
||||||
|
|
||||||
|
core.debug(
|
||||||
|
`${packageManagerInfo.name} path is ${cacheFolderPath} (derived from cache-dependency-path: "${cacheDependencyPath}")`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!stdOut) {
|
return cacheFolderPath;
|
||||||
throw new Error(`Could not get cache folder path for ${packageManager}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
core.debug(`${packageManager} path is ${stdOut}`);
|
|
||||||
|
|
||||||
return stdOut.trim();
|
|
||||||
};
|
};
|
||||||
|
const cacheDependenciesPathsToCacheFoldersPaths = async (
|
||||||
|
packageManagerInfo: PackageManagerInfo,
|
||||||
|
cacheDependenciesPaths: string[]
|
||||||
|
): Promise<string[]> => {
|
||||||
|
const cacheFoldersPaths = await Promise.all(
|
||||||
|
cacheDependenciesPaths.map(cacheDependencyPath =>
|
||||||
|
cacheDependencyPathToCacheFolderPath(
|
||||||
|
packageManagerInfo,
|
||||||
|
cacheDependencyPath
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return cacheFoldersPaths.filter(
|
||||||
|
(cachePath, i, result) => result.indexOf(cachePath) === i
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const cacheDependencyPathToCacheFoldersPaths = async (
|
||||||
|
packageManagerInfo: PackageManagerInfo,
|
||||||
|
cacheDependencyPath: string
|
||||||
|
): Promise<string[]> => {
|
||||||
|
const cacheDependenciesPaths = await expandCacheDependencyPath(
|
||||||
|
cacheDependencyPath
|
||||||
|
);
|
||||||
|
return cacheDependenciesPathsToCacheFoldersPaths(
|
||||||
|
packageManagerInfo,
|
||||||
|
cacheDependenciesPaths
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const cacheFoldersPathsForRoot = async (
|
||||||
|
packageManagerInfo: PackageManagerInfo
|
||||||
|
): Promise<string[]> => {
|
||||||
|
const cacheFolderPath = await packageManagerInfo.getCacheFolderPath();
|
||||||
|
core.debug(`${packageManagerInfo.name} path is ${cacheFolderPath}`);
|
||||||
|
return [cacheFolderPath];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getCacheDirectoriesPaths = async (
|
||||||
|
packageManagerInfo: PackageManagerInfo,
|
||||||
|
cacheDependencyPath: string
|
||||||
|
): Promise<string[]> =>
|
||||||
|
// TODO: multiple directories limited to yarn so far
|
||||||
|
packageManagerInfo === supportedPackageManagers.yarn
|
||||||
|
? cacheDependencyPathToCacheFoldersPaths(
|
||||||
|
packageManagerInfo,
|
||||||
|
cacheDependencyPath
|
||||||
|
)
|
||||||
|
: cacheFoldersPathsForRoot(packageManagerInfo);
|
||||||
|
|
||||||
export function isGhes(): boolean {
|
export function isGhes(): boolean {
|
||||||
const ghUrl = new URL(
|
const ghUrl = new URL(
|
||||||
|
Loading…
Reference in New Issue
Block a user