diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..4e683081 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +indent_style = space +trim_trailing_whitespace = false + +[*.yml] +indent_size = 2 +indent_style = space diff --git a/build/index.js b/build/index.js index 8b987b93..cc809960 100644 --- a/build/index.js +++ b/build/index.js @@ -54217,7 +54217,7 @@ const os_1 = __importDefault(__webpack_require__(87)); */ function fromLocalCache(version) { return __awaiter(this, void 0, void 0, function* () { - return toolCache.find('expo-cli', version, os_1.default.arch()); + return toolCache.find('expo-cli', version); }); } exports.fromLocalCache = fromLocalCache; @@ -54229,7 +54229,7 @@ exports.fromLocalCache = fromLocalCache; */ function toLocalCache(root, version) { return __awaiter(this, void 0, void 0, function* () { - return toolCache.cacheDir(root, 'expo-cli', version, os_1.default.arch()); + return toolCache.cacheDir(root, 'expo-cli', version); }); } exports.toLocalCache = toLocalCache; @@ -54249,7 +54249,8 @@ function fromRemoteCache(version, packager, customCacheKey) { } } catch (error) { - core.setFailed(error.message); + core.setFailed(error); + throw error; } }); } @@ -54265,7 +54266,8 @@ function toRemoteCache(source, version, packager, customCacheKey) { yield lib_1.saveCache(source, cacheKey); } catch (error) { - core.setFailed(error.message); + core.setFailed(error); + throw error; } }); } diff --git a/src/cache.ts b/src/cache.ts index f11664e3..e0349c62 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -11,7 +11,7 @@ import os from 'os'; * @see https://github.com/actions/toolkit/issues/47 */ export async function fromLocalCache(version: string) { - return toolCache.find('expo-cli', version, os.arch()); + return toolCache.find('expo-cli', version); } /** @@ -21,7 +21,7 @@ export async function fromLocalCache(version: string) { * @see https://github.com/actions/toolkit/issues/47 */ export async function toLocalCache(root: string, version: string) { - return toolCache.cacheDir(root, 'expo-cli', version, os.arch()); + return toolCache.cacheDir(root, 'expo-cli', version); } /** @@ -40,7 +40,8 @@ export async function fromRemoteCache(version: string, packager: string, customC return target; } } catch (error) { - core.setFailed(error.message); + core.setFailed(error); + throw error; } } @@ -54,7 +55,8 @@ export async function toRemoteCache(source: string, version: string, packager: s try { await saveCache(source, cacheKey); } catch (error) { - core.setFailed(error.message); + core.setFailed(error); + throw error; } } diff --git a/tests/cache.test.ts b/tests/cache.test.ts new file mode 100644 index 00000000..9a7a5a69 --- /dev/null +++ b/tests/cache.test.ts @@ -0,0 +1,102 @@ +import * as remoteCache from '@actions/cache/lib'; +import * as core from '@actions/core'; +import * as toolCache from '@actions/tool-cache'; +import os from 'os'; +import * as cache from '../src/cache'; +import * as utils from './utils'; + +describe('fromLocalCache', () => { + it('fetches the version specific cache', async () => { + const path = '/path/to/local/cache'; + // todo: check why jest wants `never` instead of `string` + const find = jest.spyOn(toolCache, 'find').mockResolvedValue(path as never); + const result = await cache.fromLocalCache('3.20.1'); + expect(result).toBe(path); + expect(find).toBeCalledWith('expo-cli', '3.20.1'); + }); +}); + +describe('toLocalCache', () => { + it('stores the version specific cache', async () => { + const path = '/path/to/local/cache'; + const root = '/path/from/source'; + const cacheDir = jest.spyOn(toolCache, 'cacheDir').mockResolvedValue(path); + const result = await cache.toLocalCache(root, '3.20.1'); + expect(result).toBe(path); + expect(cacheDir).toBeCalledWith(root, 'expo-cli', '3.20.1'); + }); +}); + +describe('fromRemoteCache', () => { + const spy = { + fail: jest.spyOn(core, 'setFailed').mockImplementation(), + restore: jest.spyOn(remoteCache, 'restoreCache').mockImplementation(), + }; + + beforeAll(() => { + utils.setEnv('RUNNER_TOOL_CACHE', '/cache/path'); + }); + + afterAll(() => { + utils.restoreEnv(); + }); + + it('restores remote cache with default key', async () => { + expect(await cache.fromRemoteCache('3.20.1', 'yarn')).toBeUndefined(); + expect(remoteCache.restoreCache).toBeCalledWith( + `/cache/path/expo-cli/3.20.1/${os.arch()}`, + `expo-cli-${process.platform}-${os.arch()}-yarn-3.20.1`, + `expo-cli-${process.platform}-${os.arch()}-yarn-3.20.1`, + ); + }); + + it('restores remote cache with custom key', async () => { + expect(await cache.fromRemoteCache('3.20.0', 'yarn', 'custom-cache-key')).toBeUndefined(); + expect(remoteCache.restoreCache).toBeCalledWith( + `/cache/path/expo-cli/3.20.0/${os.arch()}`, + 'custom-cache-key', + 'custom-cache-key', + ); + }); + + it('returns path when remote cache exists', async () => { + spy.restore.mockResolvedValueOnce(true); + await expect(cache.fromRemoteCache('3.20.1', 'npm')).resolves.toBe( + `/cache/path/expo-cli/3.20.1/${os.arch()}`, + ); + }); + + it('fails when remote cache throws', async () => { + const error = new Error('Remote cache restore failed'); + spy.restore.mockRejectedValueOnce(error); + await expect(cache.fromRemoteCache('3.20.1', 'yarn')).rejects.toBe(error); + expect(spy.fail).toBeCalledWith(error); + }); +}); + +describe('toRemoteCache', () => { + const spy = { + fail: jest.spyOn(core, 'setFailed').mockImplementation(), + save: jest.spyOn(remoteCache, 'saveCache').mockImplementation(), + }; + + it('saves remote cache with default key', async () => { + expect(await cache.toRemoteCache('/local/path', '3.20.1', 'npm')).toBeUndefined(); + expect(remoteCache.saveCache).toBeCalledWith( + '/local/path', + `expo-cli-${process.platform}-${os.arch()}-npm-3.20.1`, + ); + }); + + it('saves remote cache with custom key', async () => { + expect(await cache.toRemoteCache('/local/path', '3.20.1', 'yarn', 'custom-cache-key')).toBeUndefined(); + expect(remoteCache.saveCache).toBeCalledWith('/local/path', 'custom-cache-key'); + }); + + it('fails when remote cache throws', async () => { + const error = new Error('Remote cache save failed'); + spy.save.mockRejectedValueOnce(error); + await expect(cache.toRemoteCache('/local/path', '3.20.1', 'yarn')).rejects.toBe(error); + expect(spy.fail).toBeCalledWith(error); + }); +}); diff --git a/tests/expo.test.ts b/tests/expo.test.ts index 52d16924..72235523 100644 --- a/tests/expo.test.ts +++ b/tests/expo.test.ts @@ -1,7 +1,7 @@ import * as core from '@actions/core'; import * as cli from '@actions/exec'; import * as expo from '../src/expo'; -import { setPlatform, restorePlatform, setEnv, restoreEnv } from './utils'; +import * as utils from './utils'; describe('authenticate', () => { const spy = { @@ -25,7 +25,7 @@ describe('authenticate', () => { }); it('executes login command with password through environment', async () => { - setEnv('TEST_INCLUDED', 'hellyeah'); + utils.setEnv('TEST_INCLUDED', 'hellyeah'); await expo.authenticate('bycedric', 'mypassword'); expect(spy.exec).toBeCalled(); expect(spy.exec.mock.calls[0][0]).toBe('expo'); @@ -36,15 +36,15 @@ describe('authenticate', () => { EXPO_CLI_PASSWORD: 'mypassword', }, }); - restoreEnv(); + utils.restoreEnv(); }); it('executes login command with `.cmd` suffix on windows', async () => { - setPlatform('win32'); + utils.setPlatform('win32'); await expo.authenticate('bycedric', 'mypassword'); expect(spy.exec).toBeCalled(); expect(spy.exec.mock.calls[0][0]).toBe('expo.cmd'); - restorePlatform(); + utils.restorePlatform(); }); it('fails when credentials are incorrect', async () => { diff --git a/tests/install.test.ts b/tests/install.test.ts index 122c50bc..4565b5ef 100644 --- a/tests/install.test.ts +++ b/tests/install.test.ts @@ -14,7 +14,7 @@ jest.mock('libnpm', () => registry); jest.mock('../src/cache', () => cache); import * as install from '../src/install'; -import { setEnv, restoreEnv } from './utils'; +import * as utils from './utils'; describe('resolve', () => { it('fetches exact version of expo-cli', async () => { @@ -25,40 +25,59 @@ describe('resolve', () => { }); describe('install', () => { - it('installs path from cache', async () => { + it('installs path from local cache', async () => { cache.fromLocalCache.mockResolvedValue('/cache/path'); const expoPath = await install.install({ version: '3.0.10', packager: 'npm' }); expect(expoPath).toBe('/cache/path/node_modules/.bin'); }); - it('installs path from packager and cache it', async () => { - process.env['RUNNER_TEMP'] = '/temp/path'; + it('installs path from packager and cache it locally', async () => { + utils.setEnv('RUNNER_TEMP', '/temp/path'); cache.fromLocalCache.mockResolvedValue(undefined); cache.toLocalCache.mockResolvedValue('/cache/path'); const expoPath = await install.install({ version: '3.0.10', packager: 'npm' }); expect(expoPath).toBe('/cache/path/node_modules/.bin'); expect(cache.toLocalCache).toBeCalledWith('/temp/path', '3.0.10'); + utils.restoreEnv(); }); -}); -describe('fromPackager', () => { - afterEach(() => { - restoreEnv(); + it('installs path from remote cache', async () => { + cache.fromLocalCache.mockResolvedValue(undefined); + cache.fromRemoteCache.mockResolvedValue('/cache/path'); + registry.manifest.mockResolvedValue({ version: '3.20.0' }); + const expoPath = await install.install({ version: '3.20.1', packager: 'npm', cache: true }); + expect(expoPath).toBe('/cache/path/node_modules/.bin'); + expect(cache.fromRemoteCache).toBeCalledWith('3.20.0', 'npm', undefined); + }); + + it('installs path from packager and cache it remotely', async () => { + utils.setEnv('RUNNER_TEMP', '/temp/path'); + cache.fromLocalCache.mockResolvedValue(undefined); + cache.fromRemoteCache.mockResolvedValue(undefined); + cache.toLocalCache.mockResolvedValue('/cache/path'); + registry.manifest.mockResolvedValue({ version: '3.20.1' }); + const expoPath = await install.install({ version: '3.20.1', packager: 'npm', cache: true }); + expect(expoPath).toBe('/cache/path/node_modules/.bin'); + expect(cache.toRemoteCache).toBeCalledWith('/cache/path', '3.20.1', 'npm', undefined); + utils.restoreEnv(); }); +}); +describe('fromPackager', () => { it('resolves tool path', async () => { await install.fromPackager('3.0.10', 'npm'); expect(io.which).toBeCalledWith('npm'); }); it('creates temporary folder', async () => { - setEnv('RUNNER_TEMP', '/temp/path'); + utils.setEnv('RUNNER_TEMP', '/temp/path'); await install.fromPackager('latest', 'yarn'); expect(io.mkdirP).toBeCalledWith('/temp/path'); + utils.restoreEnv(); }); it('installs expo with tool', async () => { - setEnv('RUNNER_TEMP', '/temp/path'); + utils.setEnv('RUNNER_TEMP', '/temp/path'); io.which.mockResolvedValue('npm'); const expoPath = await install.fromPackager('beta', 'npm'); expect(expoPath).toBe('/temp/path'); @@ -66,25 +85,6 @@ describe('fromPackager', () => { expect(cli.exec.mock.calls[0][0]).toBe('npm'); expect(cli.exec.mock.calls[0][1]).toStrictEqual(['add', 'expo-cli@beta']); expect(cli.exec.mock.calls[0][2]).toMatchObject({ cwd: '/temp/path' }); + utils.restoreEnv(); }); }); - -// todo: move this to cache tests - -// describe('fromCache', () => { -// it('uses cache for exact version', async () => { -// toolCache.find.mockResolvedValue('/cache/expo/path'); -// const cachePath = await install.fromCache('3.0.10'); -// expect(toolCache.find).toBeCalledWith('expo-cli', '3.0.10'); -// expect(cachePath).toBe('/cache/expo/path'); -// }); -// }); - -// describe('toCache', () => { -// it('uses cache for installed folder', async () => { -// toolCache.cacheDir.mockResolvedValue('/cache/expo/path'); -// const cachePath = await install.toCache('3.0.10', '/expo/install/path'); -// expect(toolCache.cacheDir).toBeCalledWith('/expo/install/path', 'expo-cli', '3.0.10'); -// expect(cachePath).toBe('/cache/expo/path'); -// }); -// }); diff --git a/tests/system.test.ts b/tests/system.test.ts index 2bebd0c8..873fe00c 100644 --- a/tests/system.test.ts +++ b/tests/system.test.ts @@ -1,7 +1,7 @@ import * as core from '@actions/core'; import * as cli from '@actions/exec'; import * as system from '../src/system'; -import { setPlatform, restorePlatform } from './utils'; +import * as utils from './utils'; describe('patchWatchers', () => { const spy = { @@ -11,11 +11,11 @@ describe('patchWatchers', () => { }; afterEach(() => { - restorePlatform(); + utils.restorePlatform(); }); it('increses fs inotify settings with sysctl', async () => { - setPlatform('linux'); + utils.setPlatform('linux'); await system.patchWatchers(); expect(spy.exec).toBeCalledWith('sudo sysctl fs.inotify.max_user_instances=524288'); expect(spy.exec).toBeCalledWith('sudo sysctl fs.inotify.max_user_watches=524288'); @@ -26,7 +26,7 @@ describe('patchWatchers', () => { it('warns for unsuccessful patches', async () => { const error = new Error('Something went wrong'); spy.exec.mockRejectedValueOnce(error); - setPlatform('linux'); + utils.setPlatform('linux'); await system.patchWatchers(); expect(core.warning).toBeCalledWith(expect.stringContaining('can\'t patch watchers')); expect(core.warning).toBeCalledWith( @@ -35,21 +35,21 @@ describe('patchWatchers', () => { }); it('skips on windows platform', async () => { - setPlatform('win32'); + utils.setPlatform('win32'); await system.patchWatchers(); expect(spy.info).toBeCalledWith(expect.stringContaining('Skipping')); expect(spy.exec).not.toHaveBeenCalled(); }); it('skips on macos platform', async () => { - setPlatform('darwin'); + utils.setPlatform('darwin'); await system.patchWatchers(); expect(spy.info).toBeCalledWith(expect.stringContaining('Skipping')); expect(spy.exec).not.toHaveBeenCalled(); }); it('runs on linux platform', async () => { - setPlatform('linux'); + utils.setPlatform('linux'); await system.patchWatchers(); expect(spy.info).toBeCalledWith(expect.stringContaining('Patching')); expect(spy.exec).toHaveBeenCalled();