diff --git a/__tests__/authutil.test.ts b/__tests__/authutil.test.ts index a9b1dd04..0676a850 100644 --- a/__tests__/authutil.test.ts +++ b/__tests__/authutil.test.ts @@ -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` ); }); - - 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) - ); - }); - }); }); diff --git a/__tests__/cache-restore.test.ts b/__tests__/cache-restore.test.ts index 59135452..ba20a22d 100644 --- a/__tests__/cache-restore.test.ts +++ b/__tests__/cache-restore.test.ts @@ -32,13 +32,13 @@ describe('cache-restore', () => { function findCacheFolder(command: string) { switch (command) { - case utils.supportedPackageManagers.npm.getCacheFolderCommand: + case utils.npmGetCacheFolderCommand: return npmCachePath; - case utils.supportedPackageManagers.pnpm.getCacheFolderCommand: + case utils.pnpmGetCacheFolderCommand: return pnpmCachePath; - case utils.supportedPackageManagers.yarn1.getCacheFolderCommand: + case utils.yarn1GetCacheFolderCommand: return yarn1CachePath; - case utils.supportedPackageManagers.yarn2.getCacheFolderCommand: + case utils.yarn2GetCacheFolderCommand: return yarn2CachePath; default: return 'packge/not/found'; @@ -108,7 +108,7 @@ describe('cache-restore', () => { it.each([['npm7'], ['npm6'], ['pnpm6'], ['yarn1'], ['yarn2'], ['random']])( 'Throw an error because %s is not supported', async packageManager => { - await expect(restoreCache(packageManager)).rejects.toThrow( + await expect(restoreCache(packageManager, '')).rejects.toThrow( `Caching for '${packageManager}' is not supported` ); } @@ -132,7 +132,7 @@ describe('cache-restore', () => { } }); - await restoreCache(packageManager); + await restoreCache(packageManager, ''); expect(hashFilesSpy).toHaveBeenCalled(); expect(infoSpy).toHaveBeenCalledWith( `Cache restored from key: node-cache-${platform}-${packageManager}-v2-${fileHash}` @@ -163,7 +163,7 @@ describe('cache-restore', () => { }); restoreCacheSpy.mockImplementationOnce(() => undefined); - await restoreCache(packageManager); + await restoreCache(packageManager, ''); expect(hashFilesSpy).toHaveBeenCalled(); expect(infoSpy).toHaveBeenCalledWith( `${packageManager} cache is not found` diff --git a/__tests__/cache-save.test.ts b/__tests__/cache-save.test.ts index f96cde5a..0651138e 100644 --- a/__tests__/cache-save.test.ts +++ b/__tests__/cache-save.test.ts @@ -117,7 +117,9 @@ describe('run', () => { expect(getInputSpy).toHaveBeenCalled(); expect(getStateSpy).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(infoSpy).toHaveBeenCalledWith( `Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.` @@ -137,7 +139,9 @@ describe('run', () => { expect(getInputSpy).toHaveBeenCalled(); expect(getStateSpy).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(infoSpy).toHaveBeenCalledWith( `Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.` @@ -199,7 +203,9 @@ describe('run', () => { expect(getInputSpy).toHaveBeenCalled(); expect(getStateSpy).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(infoSpy).not.toHaveBeenCalledWith( `Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.` @@ -229,7 +235,9 @@ describe('run', () => { expect(getInputSpy).toHaveBeenCalled(); expect(getStateSpy).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(infoSpy).not.toHaveBeenCalledWith( `Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.` diff --git a/__tests__/cache-utils.test.ts b/__tests__/cache-utils.test.ts index 9e8d653d..80e4a084 100644 --- a/__tests__/cache-utils.test.ts +++ b/__tests__/cache-utils.test.ts @@ -2,7 +2,18 @@ import * as core from '@actions/core'; import * as cache from '@actions/cache'; import path from 'path'; 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', () => { const versionYarn1 = '1.2.3'; @@ -30,7 +41,7 @@ describe('cache-utils', () => { it.each<[string, PackageManagerInfo | null]>([ ['npm', utils.supportedPackageManagers.npm], ['pnpm', utils.supportedPackageManagers.pnpm], - ['yarn', utils.supportedPackageManagers.yarn1], + ['yarn', utils.supportedPackageManagers.yarn], ['yarn1', null], ['yarn2', null], ['npm7', null] @@ -72,4 +83,284 @@ describe('cache-utils', () => { jest.resetAllMocks(); 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 => + 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 => + 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 => + 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 => + 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 => + 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 => + 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 => + 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` + ]); + } + ); + }); }); diff --git a/__tests__/mock/glob-mock.test.ts b/__tests__/mock/glob-mock.test.ts new file mode 100644 index 00000000..db10ced1 --- /dev/null +++ b/__tests__/mock/glob-mock.test.ts @@ -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']); + }); +}); diff --git a/__tests__/mock/glob-mock.ts b/__tests__/mock/glob-mock.ts new file mode 100644 index 00000000..a2eabf75 --- /dev/null +++ b/__tests__/mock/glob-mock.ts @@ -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 { + const result: string[] = []; + for await (const itemPath of this.globGenerator()) { + result.push(itemPath); + } + return result; + } + + async *globGenerator(): AsyncGenerator { + for (const e of this.expected) { + yield e; + } + } + + static async create(expected: string[]): Promise { + return new MockGlobber(expected); + } +} diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js index aad77084..6b045c6d 100644 --- a/dist/cache-save/index.js +++ b/dist/cache-save/index.js @@ -6480,6 +6480,1193 @@ class ExecState extends events.EventEmitter { /***/ }), +/***/ 8090: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.hashFiles = exports.create = void 0; +const internal_globber_1 = __nccwpck_require__(8298); +const internal_hash_files_1 = __nccwpck_require__(2448); +/** + * Constructs a globber + * + * @param patterns Patterns separated by newlines + * @param options Glob options + */ +function create(patterns, options) { + return __awaiter(this, void 0, void 0, function* () { + return yield internal_globber_1.DefaultGlobber.create(patterns, options); + }); +} +exports.create = create; +/** + * Computes the sha256 hash of a glob + * + * @param patterns Patterns separated by newlines + * @param options Glob options + */ +function hashFiles(patterns, options) { + return __awaiter(this, void 0, void 0, function* () { + let followSymbolicLinks = true; + if (options && typeof options.followSymbolicLinks === 'boolean') { + followSymbolicLinks = options.followSymbolicLinks; + } + const globber = yield create(patterns, { followSymbolicLinks }); + return internal_hash_files_1.hashFiles(globber); + }); +} +exports.hashFiles = hashFiles; +//# sourceMappingURL=glob.js.map + +/***/ }), + +/***/ 1026: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.getOptions = void 0; +const core = __importStar(__nccwpck_require__(2186)); +/** + * Returns a copy with defaults filled in. + */ +function getOptions(copy) { + const result = { + followSymbolicLinks: true, + implicitDescendants: true, + matchDirectories: true, + omitBrokenSymbolicLinks: true + }; + if (copy) { + if (typeof copy.followSymbolicLinks === 'boolean') { + result.followSymbolicLinks = copy.followSymbolicLinks; + core.debug(`followSymbolicLinks '${result.followSymbolicLinks}'`); + } + if (typeof copy.implicitDescendants === 'boolean') { + result.implicitDescendants = copy.implicitDescendants; + core.debug(`implicitDescendants '${result.implicitDescendants}'`); + } + if (typeof copy.matchDirectories === 'boolean') { + result.matchDirectories = copy.matchDirectories; + core.debug(`matchDirectories '${result.matchDirectories}'`); + } + if (typeof copy.omitBrokenSymbolicLinks === 'boolean') { + result.omitBrokenSymbolicLinks = copy.omitBrokenSymbolicLinks; + core.debug(`omitBrokenSymbolicLinks '${result.omitBrokenSymbolicLinks}'`); + } + } + return result; +} +exports.getOptions = getOptions; +//# sourceMappingURL=internal-glob-options-helper.js.map + +/***/ }), + +/***/ 8298: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __asyncValues = (this && this.__asyncValues) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +}; +var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } +var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.DefaultGlobber = void 0; +const core = __importStar(__nccwpck_require__(2186)); +const fs = __importStar(__nccwpck_require__(7147)); +const globOptionsHelper = __importStar(__nccwpck_require__(1026)); +const path = __importStar(__nccwpck_require__(1017)); +const patternHelper = __importStar(__nccwpck_require__(9005)); +const internal_match_kind_1 = __nccwpck_require__(1063); +const internal_pattern_1 = __nccwpck_require__(4536); +const internal_search_state_1 = __nccwpck_require__(9117); +const IS_WINDOWS = process.platform === 'win32'; +class DefaultGlobber { + constructor(options) { + this.patterns = []; + this.searchPaths = []; + this.options = globOptionsHelper.getOptions(options); + } + getSearchPaths() { + // Return a copy + return this.searchPaths.slice(); + } + glob() { + var e_1, _a; + return __awaiter(this, void 0, void 0, function* () { + const result = []; + try { + for (var _b = __asyncValues(this.globGenerator()), _c; _c = yield _b.next(), !_c.done;) { + const itemPath = _c.value; + result.push(itemPath); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_c && !_c.done && (_a = _b.return)) yield _a.call(_b); + } + finally { if (e_1) throw e_1.error; } + } + return result; + }); + } + globGenerator() { + return __asyncGenerator(this, arguments, function* globGenerator_1() { + // Fill in defaults options + const options = globOptionsHelper.getOptions(this.options); + // Implicit descendants? + const patterns = []; + for (const pattern of this.patterns) { + patterns.push(pattern); + if (options.implicitDescendants && + (pattern.trailingSeparator || + pattern.segments[pattern.segments.length - 1] !== '**')) { + patterns.push(new internal_pattern_1.Pattern(pattern.negate, true, pattern.segments.concat('**'))); + } + } + // Push the search paths + const stack = []; + for (const searchPath of patternHelper.getSearchPaths(patterns)) { + core.debug(`Search path '${searchPath}'`); + // Exists? + try { + // Intentionally using lstat. Detection for broken symlink + // will be performed later (if following symlinks). + yield __await(fs.promises.lstat(searchPath)); + } + catch (err) { + if (err.code === 'ENOENT') { + continue; + } + throw err; + } + stack.unshift(new internal_search_state_1.SearchState(searchPath, 1)); + } + // Search + const traversalChain = []; // used to detect cycles + while (stack.length) { + // Pop + const item = stack.pop(); + // Match? + const match = patternHelper.match(patterns, item.path); + const partialMatch = !!match || patternHelper.partialMatch(patterns, item.path); + if (!match && !partialMatch) { + continue; + } + // Stat + const stats = yield __await(DefaultGlobber.stat(item, options, traversalChain) + // Broken symlink, or symlink cycle detected, or no longer exists + ); + // Broken symlink, or symlink cycle detected, or no longer exists + if (!stats) { + continue; + } + // Directory + if (stats.isDirectory()) { + // Matched + if (match & internal_match_kind_1.MatchKind.Directory && options.matchDirectories) { + yield yield __await(item.path); + } + // Descend? + else if (!partialMatch) { + continue; + } + // Push the child items in reverse + const childLevel = item.level + 1; + const childItems = (yield __await(fs.promises.readdir(item.path))).map(x => new internal_search_state_1.SearchState(path.join(item.path, x), childLevel)); + stack.push(...childItems.reverse()); + } + // File + else if (match & internal_match_kind_1.MatchKind.File) { + yield yield __await(item.path); + } + } + }); + } + /** + * Constructs a DefaultGlobber + */ + static create(patterns, options) { + return __awaiter(this, void 0, void 0, function* () { + const result = new DefaultGlobber(options); + if (IS_WINDOWS) { + patterns = patterns.replace(/\r\n/g, '\n'); + patterns = patterns.replace(/\r/g, '\n'); + } + const lines = patterns.split('\n').map(x => x.trim()); + for (const line of lines) { + // Empty or comment + if (!line || line.startsWith('#')) { + continue; + } + // Pattern + else { + result.patterns.push(new internal_pattern_1.Pattern(line)); + } + } + result.searchPaths.push(...patternHelper.getSearchPaths(result.patterns)); + return result; + }); + } + static stat(item, options, traversalChain) { + return __awaiter(this, void 0, void 0, function* () { + // Note: + // `stat` returns info about the target of a symlink (or symlink chain) + // `lstat` returns info about a symlink itself + let stats; + if (options.followSymbolicLinks) { + try { + // Use `stat` (following symlinks) + stats = yield fs.promises.stat(item.path); + } + catch (err) { + if (err.code === 'ENOENT') { + if (options.omitBrokenSymbolicLinks) { + core.debug(`Broken symlink '${item.path}'`); + return undefined; + } + throw new Error(`No information found for the path '${item.path}'. This may indicate a broken symbolic link.`); + } + throw err; + } + } + else { + // Use `lstat` (not following symlinks) + stats = yield fs.promises.lstat(item.path); + } + // Note, isDirectory() returns false for the lstat of a symlink + if (stats.isDirectory() && options.followSymbolicLinks) { + // Get the realpath + const realPath = yield fs.promises.realpath(item.path); + // Fixup the traversal chain to match the item level + while (traversalChain.length >= item.level) { + traversalChain.pop(); + } + // Test for a cycle + if (traversalChain.some((x) => x === realPath)) { + core.debug(`Symlink cycle detected for path '${item.path}' and realpath '${realPath}'`); + return undefined; + } + // Update the traversal chain + traversalChain.push(realPath); + } + return stats; + }); + } +} +exports.DefaultGlobber = DefaultGlobber; +//# sourceMappingURL=internal-globber.js.map + +/***/ }), + +/***/ 2448: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __asyncValues = (this && this.__asyncValues) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.hashFiles = void 0; +const crypto = __importStar(__nccwpck_require__(6113)); +const core = __importStar(__nccwpck_require__(2186)); +const fs = __importStar(__nccwpck_require__(7147)); +const stream = __importStar(__nccwpck_require__(2781)); +const util = __importStar(__nccwpck_require__(3837)); +const path = __importStar(__nccwpck_require__(1017)); +function hashFiles(globber) { + var e_1, _a; + var _b; + return __awaiter(this, void 0, void 0, function* () { + let hasMatch = false; + const githubWorkspace = (_b = process.env['GITHUB_WORKSPACE']) !== null && _b !== void 0 ? _b : process.cwd(); + const result = crypto.createHash('sha256'); + let count = 0; + try { + for (var _c = __asyncValues(globber.globGenerator()), _d; _d = yield _c.next(), !_d.done;) { + const file = _d.value; + core.debug(file); + if (!file.startsWith(`${githubWorkspace}${path.sep}`)) { + core.debug(`Ignore '${file}' since it is not under GITHUB_WORKSPACE.`); + continue; + } + if (fs.statSync(file).isDirectory()) { + core.debug(`Skip directory '${file}'.`); + continue; + } + const hash = crypto.createHash('sha256'); + const pipeline = util.promisify(stream.pipeline); + yield pipeline(fs.createReadStream(file), hash); + result.write(hash.digest()); + count++; + if (!hasMatch) { + hasMatch = true; + } + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_d && !_d.done && (_a = _c.return)) yield _a.call(_c); + } + finally { if (e_1) throw e_1.error; } + } + result.end(); + if (hasMatch) { + core.debug(`Found ${count} files to hash.`); + return result.digest('hex'); + } + else { + core.debug(`No matches found for glob`); + return ''; + } + }); +} +exports.hashFiles = hashFiles; +//# sourceMappingURL=internal-hash-files.js.map + +/***/ }), + +/***/ 1063: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MatchKind = void 0; +/** + * Indicates whether a pattern matches a path + */ +var MatchKind; +(function (MatchKind) { + /** Not matched */ + MatchKind[MatchKind["None"] = 0] = "None"; + /** Matched if the path is a directory */ + MatchKind[MatchKind["Directory"] = 1] = "Directory"; + /** Matched if the path is a regular file */ + MatchKind[MatchKind["File"] = 2] = "File"; + /** Matched */ + MatchKind[MatchKind["All"] = 3] = "All"; +})(MatchKind = exports.MatchKind || (exports.MatchKind = {})); +//# sourceMappingURL=internal-match-kind.js.map + +/***/ }), + +/***/ 1849: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.safeTrimTrailingSeparator = exports.normalizeSeparators = exports.hasRoot = exports.hasAbsoluteRoot = exports.ensureAbsoluteRoot = exports.dirname = void 0; +const path = __importStar(__nccwpck_require__(1017)); +const assert_1 = __importDefault(__nccwpck_require__(9491)); +const IS_WINDOWS = process.platform === 'win32'; +/** + * Similar to path.dirname except normalizes the path separators and slightly better handling for Windows UNC paths. + * + * For example, on Linux/macOS: + * - `/ => /` + * - `/hello => /` + * + * For example, on Windows: + * - `C:\ => C:\` + * - `C:\hello => C:\` + * - `C: => C:` + * - `C:hello => C:` + * - `\ => \` + * - `\hello => \` + * - `\\hello => \\hello` + * - `\\hello\world => \\hello\world` + */ +function dirname(p) { + // Normalize slashes and trim unnecessary trailing slash + p = safeTrimTrailingSeparator(p); + // Windows UNC root, e.g. \\hello or \\hello\world + if (IS_WINDOWS && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) { + return p; + } + // Get dirname + let result = path.dirname(p); + // Trim trailing slash for Windows UNC root, e.g. \\hello\world\ + if (IS_WINDOWS && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) { + result = safeTrimTrailingSeparator(result); + } + return result; +} +exports.dirname = dirname; +/** + * Roots the path if not already rooted. On Windows, relative roots like `\` + * or `C:` are expanded based on the current working directory. + */ +function ensureAbsoluteRoot(root, itemPath) { + assert_1.default(root, `ensureAbsoluteRoot parameter 'root' must not be empty`); + assert_1.default(itemPath, `ensureAbsoluteRoot parameter 'itemPath' must not be empty`); + // Already rooted + if (hasAbsoluteRoot(itemPath)) { + return itemPath; + } + // Windows + if (IS_WINDOWS) { + // Check for itemPath like C: or C:foo + if (itemPath.match(/^[A-Z]:[^\\/]|^[A-Z]:$/i)) { + let cwd = process.cwd(); + assert_1.default(cwd.match(/^[A-Z]:\\/i), `Expected current directory to start with an absolute drive root. Actual '${cwd}'`); + // Drive letter matches cwd? Expand to cwd + if (itemPath[0].toUpperCase() === cwd[0].toUpperCase()) { + // Drive only, e.g. C: + if (itemPath.length === 2) { + // Preserve specified drive letter case (upper or lower) + return `${itemPath[0]}:\\${cwd.substr(3)}`; + } + // Drive + path, e.g. C:foo + else { + if (!cwd.endsWith('\\')) { + cwd += '\\'; + } + // Preserve specified drive letter case (upper or lower) + return `${itemPath[0]}:\\${cwd.substr(3)}${itemPath.substr(2)}`; + } + } + // Different drive + else { + return `${itemPath[0]}:\\${itemPath.substr(2)}`; + } + } + // Check for itemPath like \ or \foo + else if (normalizeSeparators(itemPath).match(/^\\$|^\\[^\\]/)) { + const cwd = process.cwd(); + assert_1.default(cwd.match(/^[A-Z]:\\/i), `Expected current directory to start with an absolute drive root. Actual '${cwd}'`); + return `${cwd[0]}:\\${itemPath.substr(1)}`; + } + } + assert_1.default(hasAbsoluteRoot(root), `ensureAbsoluteRoot parameter 'root' must have an absolute root`); + // Otherwise ensure root ends with a separator + if (root.endsWith('/') || (IS_WINDOWS && root.endsWith('\\'))) { + // Intentionally empty + } + else { + // Append separator + root += path.sep; + } + return root + itemPath; +} +exports.ensureAbsoluteRoot = ensureAbsoluteRoot; +/** + * On Linux/macOS, true if path starts with `/`. On Windows, true for paths like: + * `\\hello\share` and `C:\hello` (and using alternate separator). + */ +function hasAbsoluteRoot(itemPath) { + assert_1.default(itemPath, `hasAbsoluteRoot parameter 'itemPath' must not be empty`); + // Normalize separators + itemPath = normalizeSeparators(itemPath); + // Windows + if (IS_WINDOWS) { + // E.g. \\hello\share or C:\hello + return itemPath.startsWith('\\\\') || /^[A-Z]:\\/i.test(itemPath); + } + // E.g. /hello + return itemPath.startsWith('/'); +} +exports.hasAbsoluteRoot = hasAbsoluteRoot; +/** + * On Linux/macOS, true if path starts with `/`. On Windows, true for paths like: + * `\`, `\hello`, `\\hello\share`, `C:`, and `C:\hello` (and using alternate separator). + */ +function hasRoot(itemPath) { + assert_1.default(itemPath, `isRooted parameter 'itemPath' must not be empty`); + // Normalize separators + itemPath = normalizeSeparators(itemPath); + // Windows + if (IS_WINDOWS) { + // E.g. \ or \hello or \\hello + // E.g. C: or C:\hello + return itemPath.startsWith('\\') || /^[A-Z]:/i.test(itemPath); + } + // E.g. /hello + return itemPath.startsWith('/'); +} +exports.hasRoot = hasRoot; +/** + * Removes redundant slashes and converts `/` to `\` on Windows + */ +function normalizeSeparators(p) { + p = p || ''; + // Windows + if (IS_WINDOWS) { + // Convert slashes on Windows + p = p.replace(/\//g, '\\'); + // Remove redundant slashes + const isUnc = /^\\\\+[^\\]/.test(p); // e.g. \\hello + return (isUnc ? '\\' : '') + p.replace(/\\\\+/g, '\\'); // preserve leading \\ for UNC + } + // Remove redundant slashes + return p.replace(/\/\/+/g, '/'); +} +exports.normalizeSeparators = normalizeSeparators; +/** + * Normalizes the path separators and trims the trailing separator (when safe). + * For example, `/foo/ => /foo` but `/ => /` + */ +function safeTrimTrailingSeparator(p) { + // Short-circuit if empty + if (!p) { + return ''; + } + // Normalize separators + p = normalizeSeparators(p); + // No trailing slash + if (!p.endsWith(path.sep)) { + return p; + } + // Check '/' on Linux/macOS and '\' on Windows + if (p === path.sep) { + return p; + } + // On Windows check if drive root. E.g. C:\ + if (IS_WINDOWS && /^[A-Z]:\\$/i.test(p)) { + return p; + } + // Otherwise trim trailing slash + return p.substr(0, p.length - 1); +} +exports.safeTrimTrailingSeparator = safeTrimTrailingSeparator; +//# sourceMappingURL=internal-path-helper.js.map + +/***/ }), + +/***/ 6836: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Path = void 0; +const path = __importStar(__nccwpck_require__(1017)); +const pathHelper = __importStar(__nccwpck_require__(1849)); +const assert_1 = __importDefault(__nccwpck_require__(9491)); +const IS_WINDOWS = process.platform === 'win32'; +/** + * Helper class for parsing paths into segments + */ +class Path { + /** + * Constructs a Path + * @param itemPath Path or array of segments + */ + constructor(itemPath) { + this.segments = []; + // String + if (typeof itemPath === 'string') { + assert_1.default(itemPath, `Parameter 'itemPath' must not be empty`); + // Normalize slashes and trim unnecessary trailing slash + itemPath = pathHelper.safeTrimTrailingSeparator(itemPath); + // Not rooted + if (!pathHelper.hasRoot(itemPath)) { + this.segments = itemPath.split(path.sep); + } + // Rooted + else { + // Add all segments, while not at the root + let remaining = itemPath; + let dir = pathHelper.dirname(remaining); + while (dir !== remaining) { + // Add the segment + const basename = path.basename(remaining); + this.segments.unshift(basename); + // Truncate the last segment + remaining = dir; + dir = pathHelper.dirname(remaining); + } + // Remainder is the root + this.segments.unshift(remaining); + } + } + // Array + else { + // Must not be empty + assert_1.default(itemPath.length > 0, `Parameter 'itemPath' must not be an empty array`); + // Each segment + for (let i = 0; i < itemPath.length; i++) { + let segment = itemPath[i]; + // Must not be empty + assert_1.default(segment, `Parameter 'itemPath' must not contain any empty segments`); + // Normalize slashes + segment = pathHelper.normalizeSeparators(itemPath[i]); + // Root segment + if (i === 0 && pathHelper.hasRoot(segment)) { + segment = pathHelper.safeTrimTrailingSeparator(segment); + assert_1.default(segment === pathHelper.dirname(segment), `Parameter 'itemPath' root segment contains information for multiple segments`); + this.segments.push(segment); + } + // All other segments + else { + // Must not contain slash + assert_1.default(!segment.includes(path.sep), `Parameter 'itemPath' contains unexpected path separators`); + this.segments.push(segment); + } + } + } + } + /** + * Converts the path to it's string representation + */ + toString() { + // First segment + let result = this.segments[0]; + // All others + let skipSlash = result.endsWith(path.sep) || (IS_WINDOWS && /^[A-Z]:$/i.test(result)); + for (let i = 1; i < this.segments.length; i++) { + if (skipSlash) { + skipSlash = false; + } + else { + result += path.sep; + } + result += this.segments[i]; + } + return result; + } +} +exports.Path = Path; +//# sourceMappingURL=internal-path.js.map + +/***/ }), + +/***/ 9005: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.partialMatch = exports.match = exports.getSearchPaths = void 0; +const pathHelper = __importStar(__nccwpck_require__(1849)); +const internal_match_kind_1 = __nccwpck_require__(1063); +const IS_WINDOWS = process.platform === 'win32'; +/** + * Given an array of patterns, returns an array of paths to search. + * Duplicates and paths under other included paths are filtered out. + */ +function getSearchPaths(patterns) { + // Ignore negate patterns + patterns = patterns.filter(x => !x.negate); + // Create a map of all search paths + const searchPathMap = {}; + for (const pattern of patterns) { + const key = IS_WINDOWS + ? pattern.searchPath.toUpperCase() + : pattern.searchPath; + searchPathMap[key] = 'candidate'; + } + const result = []; + for (const pattern of patterns) { + // Check if already included + const key = IS_WINDOWS + ? pattern.searchPath.toUpperCase() + : pattern.searchPath; + if (searchPathMap[key] === 'included') { + continue; + } + // Check for an ancestor search path + let foundAncestor = false; + let tempKey = key; + let parent = pathHelper.dirname(tempKey); + while (parent !== tempKey) { + if (searchPathMap[parent]) { + foundAncestor = true; + break; + } + tempKey = parent; + parent = pathHelper.dirname(tempKey); + } + // Include the search pattern in the result + if (!foundAncestor) { + result.push(pattern.searchPath); + searchPathMap[key] = 'included'; + } + } + return result; +} +exports.getSearchPaths = getSearchPaths; +/** + * Matches the patterns against the path + */ +function match(patterns, itemPath) { + let result = internal_match_kind_1.MatchKind.None; + for (const pattern of patterns) { + if (pattern.negate) { + result &= ~pattern.match(itemPath); + } + else { + result |= pattern.match(itemPath); + } + } + return result; +} +exports.match = match; +/** + * Checks whether to descend further into the directory + */ +function partialMatch(patterns, itemPath) { + return patterns.some(x => !x.negate && x.partialMatch(itemPath)); +} +exports.partialMatch = partialMatch; +//# sourceMappingURL=internal-pattern-helper.js.map + +/***/ }), + +/***/ 4536: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Pattern = void 0; +const os = __importStar(__nccwpck_require__(2037)); +const path = __importStar(__nccwpck_require__(1017)); +const pathHelper = __importStar(__nccwpck_require__(1849)); +const assert_1 = __importDefault(__nccwpck_require__(9491)); +const minimatch_1 = __nccwpck_require__(3973); +const internal_match_kind_1 = __nccwpck_require__(1063); +const internal_path_1 = __nccwpck_require__(6836); +const IS_WINDOWS = process.platform === 'win32'; +class Pattern { + constructor(patternOrNegate, isImplicitPattern = false, segments, homedir) { + /** + * Indicates whether matches should be excluded from the result set + */ + this.negate = false; + // Pattern overload + let pattern; + if (typeof patternOrNegate === 'string') { + pattern = patternOrNegate.trim(); + } + // Segments overload + else { + // Convert to pattern + segments = segments || []; + assert_1.default(segments.length, `Parameter 'segments' must not empty`); + const root = Pattern.getLiteral(segments[0]); + assert_1.default(root && pathHelper.hasAbsoluteRoot(root), `Parameter 'segments' first element must be a root path`); + pattern = new internal_path_1.Path(segments).toString().trim(); + if (patternOrNegate) { + pattern = `!${pattern}`; + } + } + // Negate + while (pattern.startsWith('!')) { + this.negate = !this.negate; + pattern = pattern.substr(1).trim(); + } + // Normalize slashes and ensures absolute root + pattern = Pattern.fixupPattern(pattern, homedir); + // Segments + this.segments = new internal_path_1.Path(pattern).segments; + // Trailing slash indicates the pattern should only match directories, not regular files + this.trailingSeparator = pathHelper + .normalizeSeparators(pattern) + .endsWith(path.sep); + pattern = pathHelper.safeTrimTrailingSeparator(pattern); + // Search path (literal path prior to the first glob segment) + let foundGlob = false; + const searchSegments = this.segments + .map(x => Pattern.getLiteral(x)) + .filter(x => !foundGlob && !(foundGlob = x === '')); + this.searchPath = new internal_path_1.Path(searchSegments).toString(); + // Root RegExp (required when determining partial match) + this.rootRegExp = new RegExp(Pattern.regExpEscape(searchSegments[0]), IS_WINDOWS ? 'i' : ''); + this.isImplicitPattern = isImplicitPattern; + // Create minimatch + const minimatchOptions = { + dot: true, + nobrace: true, + nocase: IS_WINDOWS, + nocomment: true, + noext: true, + nonegate: true + }; + pattern = IS_WINDOWS ? pattern.replace(/\\/g, '/') : pattern; + this.minimatch = new minimatch_1.Minimatch(pattern, minimatchOptions); + } + /** + * Matches the pattern against the specified path + */ + match(itemPath) { + // Last segment is globstar? + if (this.segments[this.segments.length - 1] === '**') { + // Normalize slashes + itemPath = pathHelper.normalizeSeparators(itemPath); + // Append a trailing slash. Otherwise Minimatch will not match the directory immediately + // preceding the globstar. For example, given the pattern `/foo/**`, Minimatch returns + // false for `/foo` but returns true for `/foo/`. Append a trailing slash to handle that quirk. + if (!itemPath.endsWith(path.sep) && this.isImplicitPattern === false) { + // Note, this is safe because the constructor ensures the pattern has an absolute root. + // For example, formats like C: and C:foo on Windows are resolved to an absolute root. + itemPath = `${itemPath}${path.sep}`; + } + } + else { + // Normalize slashes and trim unnecessary trailing slash + itemPath = pathHelper.safeTrimTrailingSeparator(itemPath); + } + // Match + if (this.minimatch.match(itemPath)) { + return this.trailingSeparator ? internal_match_kind_1.MatchKind.Directory : internal_match_kind_1.MatchKind.All; + } + return internal_match_kind_1.MatchKind.None; + } + /** + * Indicates whether the pattern may match descendants of the specified path + */ + partialMatch(itemPath) { + // Normalize slashes and trim unnecessary trailing slash + itemPath = pathHelper.safeTrimTrailingSeparator(itemPath); + // matchOne does not handle root path correctly + if (pathHelper.dirname(itemPath) === itemPath) { + return this.rootRegExp.test(itemPath); + } + return this.minimatch.matchOne(itemPath.split(IS_WINDOWS ? /\\+/ : /\/+/), this.minimatch.set[0], true); + } + /** + * Escapes glob patterns within a path + */ + static globEscape(s) { + return (IS_WINDOWS ? s : s.replace(/\\/g, '\\\\')) // escape '\' on Linux/macOS + .replace(/(\[)(?=[^/]+\])/g, '[[]') // escape '[' when ']' follows within the path segment + .replace(/\?/g, '[?]') // escape '?' + .replace(/\*/g, '[*]'); // escape '*' + } + /** + * Normalizes slashes and ensures absolute root + */ + static fixupPattern(pattern, homedir) { + // Empty + assert_1.default(pattern, 'pattern cannot be empty'); + // Must not contain `.` segment, unless first segment + // Must not contain `..` segment + const literalSegments = new internal_path_1.Path(pattern).segments.map(x => Pattern.getLiteral(x)); + assert_1.default(literalSegments.every((x, i) => (x !== '.' || i === 0) && x !== '..'), `Invalid pattern '${pattern}'. Relative pathing '.' and '..' is not allowed.`); + // Must not contain globs in root, e.g. Windows UNC path \\foo\b*r + assert_1.default(!pathHelper.hasRoot(pattern) || literalSegments[0], `Invalid pattern '${pattern}'. Root segment must not contain globs.`); + // Normalize slashes + pattern = pathHelper.normalizeSeparators(pattern); + // Replace leading `.` segment + if (pattern === '.' || pattern.startsWith(`.${path.sep}`)) { + pattern = Pattern.globEscape(process.cwd()) + pattern.substr(1); + } + // Replace leading `~` segment + else if (pattern === '~' || pattern.startsWith(`~${path.sep}`)) { + homedir = homedir || os.homedir(); + assert_1.default(homedir, 'Unable to determine HOME directory'); + assert_1.default(pathHelper.hasAbsoluteRoot(homedir), `Expected HOME directory to be a rooted path. Actual '${homedir}'`); + pattern = Pattern.globEscape(homedir) + pattern.substr(1); + } + // Replace relative drive root, e.g. pattern is C: or C:foo + else if (IS_WINDOWS && + (pattern.match(/^[A-Z]:$/i) || pattern.match(/^[A-Z]:[^\\]/i))) { + let root = pathHelper.ensureAbsoluteRoot('C:\\dummy-root', pattern.substr(0, 2)); + if (pattern.length > 2 && !root.endsWith('\\')) { + root += '\\'; + } + pattern = Pattern.globEscape(root) + pattern.substr(2); + } + // Replace relative root, e.g. pattern is \ or \foo + else if (IS_WINDOWS && (pattern === '\\' || pattern.match(/^\\[^\\]/))) { + let root = pathHelper.ensureAbsoluteRoot('C:\\dummy-root', '\\'); + if (!root.endsWith('\\')) { + root += '\\'; + } + pattern = Pattern.globEscape(root) + pattern.substr(1); + } + // Otherwise ensure absolute root + else { + pattern = pathHelper.ensureAbsoluteRoot(Pattern.globEscape(process.cwd()), pattern); + } + return pathHelper.normalizeSeparators(pattern); + } + /** + * Attempts to unescape a pattern segment to create a literal path segment. + * Otherwise returns empty string. + */ + static getLiteral(segment) { + let literal = ''; + for (let i = 0; i < segment.length; i++) { + const c = segment[i]; + // Escape + if (c === '\\' && !IS_WINDOWS && i + 1 < segment.length) { + literal += segment[++i]; + continue; + } + // Wildcard + else if (c === '*' || c === '?') { + return ''; + } + // Character set + else if (c === '[' && i + 1 < segment.length) { + let set = ''; + let closed = -1; + for (let i2 = i + 1; i2 < segment.length; i2++) { + const c2 = segment[i2]; + // Escape + if (c2 === '\\' && !IS_WINDOWS && i2 + 1 < segment.length) { + set += segment[++i2]; + continue; + } + // Closed + else if (c2 === ']') { + closed = i2; + break; + } + // Otherwise + else { + set += c2; + } + } + // Closed? + if (closed >= 0) { + // Cannot convert + if (set.length > 1) { + return ''; + } + // Convert to literal + if (set) { + literal += set; + i = closed; + continue; + } + } + // Otherwise fall thru + } + // Append + literal += c; + } + return literal; + } + /** + * Escapes regexp special characters + * https://javascript.info/regexp-escaping + */ + static regExpEscape(s) { + return s.replace(/[[\\^$.|?*+()]/g, '\\$&'); + } +} +exports.Pattern = Pattern; +//# sourceMappingURL=internal-pattern.js.map + +/***/ }), + +/***/ 9117: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.SearchState = void 0; +class SearchState { + constructor(path, level) { + this.path = path; + this.level = level; + } +} +exports.SearchState = SearchState; +//# sourceMappingURL=internal-search-state.js.map + +/***/ }), + /***/ 1962: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { @@ -59155,14 +60342,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.run = void 0; const core = __importStar(__nccwpck_require__(2186)); const cache = __importStar(__nccwpck_require__(7799)); -const fs_1 = __importDefault(__nccwpck_require__(7147)); const constants_1 = __nccwpck_require__(9042); const cache_utils_1 = __nccwpck_require__(1678); // Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in @@ -59192,15 +60375,18 @@ const cachePackages = (packageManager) => __awaiter(void 0, void 0, void 0, func core.debug(`Caching for '${packageManager}' is not supported`); return; } - const cachePath = yield cache_utils_1.getCacheDirectoryPath(packageManagerInfo, packageManager); - if (!fs_1.default.existsSync(cachePath)) { - throw new Error(`Cache folder path is retrieved for ${packageManager} but doesn't exist on disk: ${cachePath}`); + // 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 = yield cache_utils_1.getCacheDirectoriesPaths(packageManagerInfo, cacheDependencyPath); + if (cachePaths.length === 0) { + throw new Error(`Cache folder paths are not retrieved for ${packageManager} with cache-dependency-path = ${cacheDependencyPath}`); } if (primaryKey === state) { core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`); return; } - const cacheId = yield cache.saveCache([cachePath], primaryKey); + const cacheId = yield cache.saveCache(cachePaths, primaryKey); if (cacheId == -1) { return; } @@ -59248,32 +60434,47 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; 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 exec = __importStar(__nccwpck_require__(1514)); const cache = __importStar(__nccwpck_require__(7799)); +const glob = __importStar(__nccwpck_require__(8090)); const path_1 = __importDefault(__nccwpck_require__(1017)); 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 = { npm: { + name: 'npm', 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: { + name: 'pnpm', 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'], - getCacheFolderCommand: 'yarn cache dir' - }, - yarn2: { - lockFilePatterns: ['yarn.lock'], - getCacheFolderCommand: 'yarn config get cacheFolder' + getCacheFolderPath: (projectDir) => __awaiter(void 0, void 0, void 0, function* () { + const yarnVersion = yield exports.getCommandOutputGuarded(`yarn --version`, 'Could not retrieve version of yarn', projectDir); + core.debug(`Consumed yarn version is ${yarnVersion}`); + const stdOut = yarnVersion.startsWith('1.') + ? 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* () { - 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) { stderr = !stderr.trim() ? `The '${toolCommand}' command failed with exit code: ${exitCode}` @@ -59283,32 +60484,14 @@ const getCommandOutput = (toolCommand, cwd) => __awaiter(void 0, void 0, void 0, return stdout.trim(); }); exports.getCommandOutput = getCommandOutput; -const getPackageManagerWorkingDir = () => { - const cache = core.getInput('cache'); - 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}`); +const getCommandOutputGuarded = (toolCommand, error, cwd) => __awaiter(void 0, void 0, void 0, function* () { + const stdOut = exports.getCommandOutput(toolCommand, cwd); if (!stdOut) { - throw new Error(`Could not retrieve version of ${packageManager}`); + throw new Error(error); } return stdOut; }); -exports.getPackageManagerVersion = getPackageManagerVersion; +exports.getCommandOutputGuarded = getCommandOutputGuarded; const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () { if (packageManager === 'npm') { return exports.supportedPackageManagers.npm; @@ -59317,29 +60500,56 @@ const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void return exports.supportedPackageManagers.pnpm; } else if (packageManager === 'yarn') { - const yarnVersion = yield exports.getPackageManagerVersion('yarn', '--version'); - core.debug(`Consumed yarn version is ${yarnVersion}`); - if (yarnVersion.startsWith('1.')) { - return exports.supportedPackageManagers.yarn1; - } - else { - return exports.supportedPackageManagers.yarn2; - } + return exports.supportedPackageManagers.yarn; } else { return null; } }); exports.getPackageManagerInfo = getPackageManagerInfo; -const getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaiter(void 0, void 0, void 0, function* () { - const stdOut = yield exports.getPackageManagerCommandOutput(packageManagerInfo.getCacheFolderCommand); - if (!stdOut) { - throw new Error(`Could not get cache folder path for ${packageManager}`); - } - core.debug(`${packageManager} path is ${stdOut}`); - return stdOut.trim(); +const globPatternToArray = (pattern) => __awaiter(void 0, void 0, void 0, function* () { + const globber = yield glob.create(pattern); + return globber.glob(); }); -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() { const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com'); return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; diff --git a/dist/setup/index.js b/dist/setup/index.js index eae17a84..7230bd04 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -71144,7 +71144,7 @@ const restoreCache = (packageManager, cacheDependencyPath) => __awaiter(void 0, throw new Error(`Caching for '${packageManager}' is not supported`); } 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 ? cacheDependencyPath : findLockFile(packageManagerInfo); @@ -71155,7 +71155,7 @@ const restoreCache = (packageManager, cacheDependencyPath) => __awaiter(void 0, const primaryKey = `node-cache-${platform}-${packageManager}-v2-${fileHash}`; core.debug(`primary key is ${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)); if (!cacheKey) { 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 }; }; 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 exec = __importStar(__nccwpck_require__(1514)); const cache = __importStar(__nccwpck_require__(7799)); +const glob = __importStar(__nccwpck_require__(8090)); const path_1 = __importDefault(__nccwpck_require__(1017)); 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 = { npm: { + name: 'npm', 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: { + name: 'pnpm', 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'], - getCacheFolderCommand: 'yarn cache dir' - }, - yarn2: { - lockFilePatterns: ['yarn.lock'], - getCacheFolderCommand: 'yarn config get cacheFolder' + getCacheFolderPath: (projectDir) => __awaiter(void 0, void 0, void 0, function* () { + const yarnVersion = yield exports.getCommandOutputGuarded(`yarn --version`, 'Could not retrieve version of yarn', projectDir); + core.debug(`Consumed yarn version is ${yarnVersion}`); + const stdOut = yarnVersion.startsWith('1.') + ? 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* () { - 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) { stderr = !stderr.trim() ? `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(); }); exports.getCommandOutput = getCommandOutput; -const getPackageManagerWorkingDir = () => { - const cache = core.getInput('cache'); - 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}`); +const getCommandOutputGuarded = (toolCommand, error, cwd) => __awaiter(void 0, void 0, void 0, function* () { + const stdOut = exports.getCommandOutput(toolCommand, cwd); if (!stdOut) { - throw new Error(`Could not retrieve version of ${packageManager}`); + throw new Error(error); } return stdOut; }); -exports.getPackageManagerVersion = getPackageManagerVersion; +exports.getCommandOutputGuarded = getCommandOutputGuarded; const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void 0, function* () { if (packageManager === 'npm') { return exports.supportedPackageManagers.npm; @@ -71285,29 +71282,56 @@ const getPackageManagerInfo = (packageManager) => __awaiter(void 0, void 0, void return exports.supportedPackageManagers.pnpm; } else if (packageManager === 'yarn') { - const yarnVersion = yield exports.getPackageManagerVersion('yarn', '--version'); - core.debug(`Consumed yarn version is ${yarnVersion}`); - if (yarnVersion.startsWith('1.')) { - return exports.supportedPackageManagers.yarn1; - } - else { - return exports.supportedPackageManagers.yarn2; - } + return exports.supportedPackageManagers.yarn; } else { return null; } }); exports.getPackageManagerInfo = getPackageManagerInfo; -const getCacheDirectoryPath = (packageManagerInfo, packageManager) => __awaiter(void 0, void 0, void 0, function* () { - const stdOut = yield exports.getPackageManagerCommandOutput(packageManagerInfo.getCacheFolderCommand); - if (!stdOut) { - throw new Error(`Could not get cache folder path for ${packageManager}`); - } - core.debug(`${packageManager} path is ${stdOut}`); - return stdOut.trim(); +const globPatternToArray = (pattern) => __awaiter(void 0, void 0, void 0, function* () { + const globber = yield glob.create(pattern); + return globber.glob(); }); -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() { const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com'); return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; diff --git a/src/cache-restore.ts b/src/cache-restore.ts index 0341c109..801d525c 100644 --- a/src/cache-restore.ts +++ b/src/cache-restore.ts @@ -6,14 +6,14 @@ import fs from 'fs'; import {State} from './constants'; import { - getCacheDirectoryPath, + getCacheDirectoriesPaths, getPackageManagerInfo, PackageManagerInfo } from './cache-utils'; export const restoreCache = async ( packageManager: string, - cacheDependencyPath?: string + cacheDependencyPath: string ) => { const packageManagerInfo = await getPackageManagerInfo(packageManager); if (!packageManagerInfo) { @@ -21,9 +21,9 @@ export const restoreCache = async ( } const platform = process.env.RUNNER_OS; - const cachePath = await getCacheDirectoryPath( + const cachePaths = await getCacheDirectoriesPaths( packageManagerInfo, - packageManager + cacheDependencyPath ); const lockFilePath = cacheDependencyPath ? cacheDependencyPath @@ -41,7 +41,7 @@ export const restoreCache = async ( 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)); if (!cacheKey) { diff --git a/src/cache-save.ts b/src/cache-save.ts index 24565a8e..660ec37c 100644 --- a/src/cache-save.ts +++ b/src/cache-save.ts @@ -2,7 +2,7 @@ import * as core from '@actions/core'; import * as cache from '@actions/cache'; import fs from 'fs'; 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 // @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; } - 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, - packageManager + cacheDependencyPath ); - if (!fs.existsSync(cachePath)) { + if (cachePaths.length === 0) { 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; } - const cacheId = await cache.saveCache([cachePath], primaryKey); + const cacheId = await cache.saveCache(cachePaths, primaryKey); if (cacheId == -1) { return; } diff --git a/src/cache-utils.ts b/src/cache-utils.ts index ebd5144b..9c7f2827 100644 --- a/src/cache-utils.ts +++ b/src/cache-utils.ts @@ -1,45 +1,80 @@ import * as core from '@actions/core'; import * as exec from '@actions/exec'; import * as cache from '@actions/cache'; +import * as glob from '@actions/glob'; import path from 'path'; import fs from 'fs'; -type SupportedPackageManagers = { - [prop: string]: PackageManagerInfo; -}; - export interface PackageManagerInfo { + name: string; lockFilePatterns: Array; - getCacheFolderCommand: string; + getCacheFolderPath: (projectDir?: string) => Promise; } +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 = { npm: { + name: 'npm', 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: { + name: 'pnpm', 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'], - getCacheFolderCommand: 'yarn cache dir' - }, - yarn2: { - lockFilePatterns: ['yarn.lock'], - getCacheFolderCommand: 'yarn config get cacheFolder' + getCacheFolderPath: async projectDir => { + const yarnVersion = await getCommandOutputGuarded( + `yarn --version`, + 'Could not retrieve version of yarn', + 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 ( toolCommand: string, - cwd: string | null -) => { + cwd?: string +): Promise => { let {stdout, stderr, exitCode} = await exec.getExecOutput( toolCommand, undefined, - {ignoreReturnCode: true, ...(cwd !== null && {cwd})} + {ignoreReturnCode: true, ...(cwd && {cwd})} ); if (exitCode) { @@ -52,41 +87,15 @@ export const getCommandOutput = async ( return stdout.trim(); }; -export const getPackageManagerWorkingDir = (): string | null => { - const cache = core.getInput('cache'); - if (cache !== 'yarn') { - return null; - } - - 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}` - ); - +export const getCommandOutputGuarded = async ( + toolCommand: string, + error: string, + cwd?: string +): Promise => { + const stdOut = getCommandOutput(toolCommand, cwd); if (!stdOut) { - throw new Error(`Could not retrieve version of ${packageManager}`); + throw new Error(error); } - return stdOut; }; @@ -96,36 +105,99 @@ export const getPackageManagerInfo = async (packageManager: string) => { } else if (packageManager === 'pnpm') { return supportedPackageManagers.pnpm; } else if (packageManager === 'yarn') { - const yarnVersion = await getPackageManagerVersion('yarn', '--version'); - - core.debug(`Consumed yarn version is ${yarnVersion}`); - - if (yarnVersion.startsWith('1.')) { - return supportedPackageManagers.yarn1; - } else { - return supportedPackageManagers.yarn2; - } + return supportedPackageManagers.yarn; } else { return null; } }; -export const getCacheDirectoryPath = async ( +const globPatternToArray = async (pattern: string): Promise => { + const globber = await glob.create(pattern); + return globber.glob(); +}; + +export const expandCacheDependencyPath = async ( + cacheDependencyPath: string +): Promise => { + const multilinePaths = cacheDependencyPath + .split(/\r?\n/) + .map(path => path.trim()) + .filter(path => Boolean(path)); + const expandedPathsPromises: Promise[] = 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, - packageManager: string -) => { - const stdOut = await getPackageManagerCommandOutput( - packageManagerInfo.getCacheFolderCommand + cacheDependencyPath: string +): Promise => { + const cacheDependencyPathDirectory = path.dirname(cacheDependencyPath); + 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) { - throw new Error(`Could not get cache folder path for ${packageManager}`); - } - - core.debug(`${packageManager} path is ${stdOut}`); - - return stdOut.trim(); + return cacheFolderPath; }; +const cacheDependenciesPathsToCacheFoldersPaths = async ( + packageManagerInfo: PackageManagerInfo, + cacheDependenciesPaths: string[] +): Promise => { + 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 => { + const cacheDependenciesPaths = await expandCacheDependencyPath( + cacheDependencyPath + ); + return cacheDependenciesPathsToCacheFoldersPaths( + packageManagerInfo, + cacheDependenciesPaths + ); +}; + +const cacheFoldersPathsForRoot = async ( + packageManagerInfo: PackageManagerInfo +): Promise => { + const cacheFolderPath = await packageManagerInfo.getCacheFolderPath(); + core.debug(`${packageManagerInfo.name} path is ${cacheFolderPath}`); + return [cacheFolderPath]; +}; + +export const getCacheDirectoriesPaths = async ( + packageManagerInfo: PackageManagerInfo, + cacheDependencyPath: string +): Promise => + // TODO: multiple directories limited to yarn so far + packageManagerInfo === supportedPackageManagers.yarn + ? cacheDependencyPathToCacheFoldersPaths( + packageManagerInfo, + cacheDependencyPath + ) + : cacheFoldersPathsForRoot(packageManagerInfo); export function isGhes(): boolean { const ghUrl = new URL(