From a84b7738e227175505df6711976f1b4d1b75c741 Mon Sep 17 00:00:00 2001 From: Veaceslav <118342408+vCaisim@users.noreply.github.com> Date: Fri, 4 Oct 2024 12:57:50 +0300 Subject: [PATCH] fix: remove --no-fail flag, add --continue flag --- .../cmd/src/commands/__tests__/utils.spec.ts | 83 ++++----- packages/cmd/src/commands/cache/get.ts | 24 +-- packages/cmd/src/commands/cache/index.ts | 5 +- packages/cmd/src/commands/cache/options.ts | 8 +- packages/cmd/src/commands/cache/set.ts | 24 +-- packages/cmd/src/commands/utils.ts | 20 +- packages/cmd/src/config/cache/config.ts | 1 + packages/cmd/src/config/cache/env.ts | 4 + packages/cmd/src/config/cache/options.ts | 1 + .../src/services/cache/__tests__/get.spec.ts | 172 ++++++++++++++++++ .../src/services/cache/__tests__/set.spec.ts | 153 ++++++++++++++++ packages/cmd/src/services/cache/get.ts | 24 ++- packages/cmd/src/services/cache/set.ts | 4 +- 13 files changed, 414 insertions(+), 109 deletions(-) create mode 100644 packages/cmd/src/services/cache/__tests__/get.spec.ts create mode 100644 packages/cmd/src/services/cache/__tests__/set.spec.ts diff --git a/packages/cmd/src/commands/__tests__/utils.spec.ts b/packages/cmd/src/commands/__tests__/utils.spec.ts index 23b3dc7..14fdf62 100644 --- a/packages/cmd/src/commands/__tests__/utils.spec.ts +++ b/packages/cmd/src/commands/__tests__/utils.spec.ts @@ -1,6 +1,6 @@ import { CommanderError } from '@commander-js/extra-typings'; -import { error, warnWithNoTrace } from '@logger'; -import { describe, expect, it, vi, beforeEach } from 'vitest'; +import { error } from '@logger'; +import { beforeEach, describe, expect, it, MockInstance, vi } from 'vitest'; import { enableDebug } from '../../debug'; import { commandHandler, parseCommaSeparatedList } from '../utils'; @@ -41,70 +41,55 @@ describe('parseCommaSeparatedList', () => { }); describe('commandHandler', () => { - const mockAction = vi.fn(); - let mockExit = vi.spyOn(process, 'exit').mockImplementation((code) => { - throw new Error(`process.exit(${code})`); - }); + let exitSpy: MockInstance; beforeEach(() => { vi.clearAllMocks(); + // @ts-ignore + exitSpy = vi.spyOn(process, 'exit').mockImplementation((code) => { + return code as never; + }); }); - it('should call the action and exit with code 0 on success', async () => { - mockAction.mockResolvedValueOnce(undefined); - // @ts-ignore - mockExit = vi.spyOn(process, 'exit').mockImplementationOnce(() => void 0); + it('should call action with the given options and exit with code 0 on success', async () => { + const mockAction = vi.fn().mockResolvedValue(undefined); + const mockOptions = { debug: false }; - await commandHandler(mockAction, { debug: false }); - expect(mockAction).toHaveBeenCalled(); - expect(mockExit).toHaveBeenCalledWith(0); + await commandHandler(mockAction, mockOptions); + expect(mockAction).toHaveBeenCalledWith(mockOptions); + expect(exitSpy).toHaveBeenCalledWith(0); }); - it('should enable debug mode if debug is true', async () => { - mockAction.mockResolvedValueOnce(undefined); - // @ts-ignore - mockExit = vi.spyOn(process, 'exit').mockImplementationOnce(() => void 0); + it('should enable debug mode if debug option is true', async () => { + const mockAction = vi.fn().mockResolvedValue(undefined); + const mockOptions = { debug: true }; - await commandHandler(mockAction, { debug: true }); + await commandHandler(mockAction, mockOptions); expect(enableDebug).toHaveBeenCalled(); - expect(mockAction).toHaveBeenCalled(); - expect(mockExit).toHaveBeenCalledWith(0); + expect(mockAction).toHaveBeenCalledWith(mockOptions); + expect(exitSpy).toHaveBeenCalledWith(0); }); - it('should log error and exit with code 1 if an error occurs and failOnError is true', async () => { - const errorMessage = 'Test error'; - mockAction.mockRejectedValueOnce(new Error(errorMessage)); + it('should log an error and exit with code 1 if action throws a generic error', async () => { + const mockAction = vi.fn().mockRejectedValue(new Error('Test Error')); + const mockOptions = { debug: false }; - await expect(commandHandler(mockAction, { debug: false })).rejects.toThrow( - 'process.exit(1)' - ); - expect(error).toHaveBeenCalledWith(errorMessage); - expect(mockExit).toHaveBeenCalledWith(1); + await commandHandler(mockAction, mockOptions); + expect(error).toHaveBeenCalledWith('Test Error'); + expect(exitSpy).toHaveBeenCalledWith(1); }); - it('should log error and exit with specific exitCode if CommanderError occurs', async () => { - const commandError = new CommanderError( - 123, + it('should exit with CommanderError exitCode if action throws a CommanderError', async () => { + const commanderError = new CommanderError( + 2, 'commander.error', - 'Commander failed' + 'Commander Error' ); - mockAction.mockRejectedValueOnce(commandError); - - await expect(commandHandler(mockAction, { debug: false })).rejects.toThrow( - 'process.exit(123)' - ); - expect(error).toHaveBeenCalledWith('Commander failed'); - expect(mockExit).toHaveBeenCalledWith(123); - }); - - it('should log a warning and exit with code 0 if failOnError is false', async () => { - const errorMessage = 'Test warning'; - mockAction.mockRejectedValueOnce(new Error(errorMessage)); + const mockAction = vi.fn().mockRejectedValue(commanderError); + const mockOptions = { debug: false }; - await expect( - commandHandler(mockAction, { debug: false }, { failOnError: false }) - ).rejects.toThrow('process.exit(0)'); - expect(warnWithNoTrace).toHaveBeenCalledWith(errorMessage); - expect(mockExit).toHaveBeenCalledWith(0); + await commandHandler(mockAction, mockOptions); + expect(error).toHaveBeenCalledWith('Commander Error'); + expect(exitSpy).toHaveBeenCalledWith(2); }); }); diff --git a/packages/cmd/src/commands/cache/get.ts b/packages/cmd/src/commands/cache/get.ts index f45d95d..d9c3c3a 100644 --- a/packages/cmd/src/commands/cache/get.ts +++ b/packages/cmd/src/commands/cache/get.ts @@ -15,21 +15,15 @@ export type CacheGetCommandOpts = ReturnType< >; export async function getCacheGetHandler(options: CacheGetCommandOpts) { - await commandHandler( - async (opts) => { - setCacheGetCommandConfig(cacheGetCommandOptsToConfig(opts)); - const config = getCacheCommandConfig(); + await commandHandler(async (opts) => { + setCacheGetCommandConfig(cacheGetCommandOptsToConfig(opts)); + const config = getCacheCommandConfig(); - debug('Config: %o', { - ...config.values, - recordKey: config.values?.recordKey ? '*****' : undefined, - }); + debug('Config: %o', { + ...config.values, + recordKey: config.values?.recordKey ? '*****' : undefined, + }); - await handleGetCache(); - }, - options, - { - failOnError: options.fail, - } - ); + await handleGetCache(); + }, options); } diff --git a/packages/cmd/src/commands/cache/index.ts b/packages/cmd/src/commands/cache/index.ts index 762b8d2..88fbac8 100644 --- a/packages/cmd/src/commands/cache/index.ts +++ b/packages/cmd/src/commands/cache/index.ts @@ -3,11 +3,11 @@ import { dim } from '@logger'; import chalk from 'chalk'; import { getCacheGetHandler } from './get'; import { + continueOption, debugOption, idOption, matrixIndexOption, matrixTotalOption, - noFailOption, outputDirOption, pathOption, presetOption, @@ -63,7 +63,6 @@ export const getCacheSetCommand = () => { .addOption(pwOutputDirOption) .addOption(matrixIndexOption) .addOption(matrixTotalOption) - .addOption(noFailOption) .action(getCacheSetHandler); return command; @@ -81,7 +80,7 @@ export const getCacheGetCommand = () => { .addOption(debugOption) .addOption(matrixIndexOption) .addOption(matrixTotalOption) - .addOption(noFailOption) + .addOption(continueOption) .action(getCacheGetHandler); return command; diff --git a/packages/cmd/src/commands/cache/options.ts b/packages/cmd/src/commands/cache/options.ts index 6d53172..d69c979 100644 --- a/packages/cmd/src/commands/cache/options.ts +++ b/packages/cmd/src/commands/cache/options.ts @@ -73,7 +73,7 @@ function validatePositiveInteger(value: string) { return parsedValue; } -export const noFailOption = new Option( - '--no-fail', - 'Do not fail the process if the command fails' -); +export const continueOption = new Option( + '--continue', + 'Continue the script execution if the cache is not found' +).default(false); diff --git a/packages/cmd/src/commands/cache/set.ts b/packages/cmd/src/commands/cache/set.ts index 775ed25..c118af5 100644 --- a/packages/cmd/src/commands/cache/set.ts +++ b/packages/cmd/src/commands/cache/set.ts @@ -15,21 +15,15 @@ export type CacheSetCommandOpts = ReturnType< >; export async function getCacheSetHandler(options: CacheSetCommandOpts) { - await commandHandler( - async (opts) => { - setCacheSetCommandConfig(cacheSetCommandOptsToConfig(opts)); - const config = getCacheCommandConfig(); + await commandHandler(async (opts) => { + setCacheSetCommandConfig(cacheSetCommandOptsToConfig(opts)); + const config = getCacheCommandConfig(); - debug('Config: %o', { - ...config.values, - recordKey: config.values?.recordKey ? '*****' : undefined, - }); + debug('Config: %o', { + ...config.values, + recordKey: config.values?.recordKey ? '*****' : undefined, + }); - await handleSetCache(); - }, - options, - { - failOnError: options.fail, - } - ); + await handleSetCache(); + }, options); } diff --git a/packages/cmd/src/commands/utils.ts b/packages/cmd/src/commands/utils.ts index dbcf848..c655ab9 100644 --- a/packages/cmd/src/commands/utils.ts +++ b/packages/cmd/src/commands/utils.ts @@ -1,5 +1,5 @@ import { CommanderError } from '@commander-js/extra-typings'; -import { error, warnWithNoTrace } from '@logger'; +import { error } from '@logger'; import { enableDebug } from '../debug'; export function parseCommaSeparatedList( @@ -14,10 +14,7 @@ export function parseCommaSeparatedList( export async function commandHandler>( action: (options: T) => Promise, - commandOptions: T, - options?: { - failOnError?: boolean; - } + commandOptions: T ) { try { if (commandOptions.debug) { @@ -25,16 +22,9 @@ export async function commandHandler>( } await action(commandOptions); process.exit(0); - } catch (_e) { - const e = _e as Error; - const failOnError = options?.failOnError ?? true; - if (failOnError) { - error(e.message); - } else { - warnWithNoTrace(e.message); - } - + } catch (e) { + error((e as Error).message); const exitCode = e instanceof CommanderError ? e.exitCode : 1; - process.exit(failOnError ? exitCode : 0); + process.exit(exitCode); } } diff --git a/packages/cmd/src/config/cache/config.ts b/packages/cmd/src/config/cache/config.ts index a8b0632..133d417 100644 --- a/packages/cmd/src/config/cache/config.ts +++ b/packages/cmd/src/config/cache/config.ts @@ -32,6 +32,7 @@ export type CacheSetCommandConfig = CacheCommandConfig & export type CacheGetCommandConfig = CacheCommandConfig & CommonConfig & { + continue?: boolean; outputDir?: string; presetOutput?: string; }; diff --git a/packages/cmd/src/config/cache/env.ts b/packages/cmd/src/config/cache/env.ts index 9b9c12e..768e22d 100644 --- a/packages/cmd/src/config/cache/env.ts +++ b/packages/cmd/src/config/cache/env.ts @@ -65,6 +65,10 @@ const cacheGetCommandConfigKeys = { name: 'Matrix total', cli: '--matrix-total', }, + continue: { + name: 'Continue on cache miss', + cli: '--continue', + }, } as const; export const configKeys = { diff --git a/packages/cmd/src/config/cache/options.ts b/packages/cmd/src/config/cache/options.ts index 8965edb..4681743 100644 --- a/packages/cmd/src/config/cache/options.ts +++ b/packages/cmd/src/config/cache/options.ts @@ -14,6 +14,7 @@ export function cacheGetCommandOptsToConfig( debug: options.debug, matrixIndex: options.matrixIndex, matrixTotal: options.matrixTotal, + continue: options.continue, }; } diff --git a/packages/cmd/src/services/cache/__tests__/get.spec.ts b/packages/cmd/src/services/cache/__tests__/get.spec.ts new file mode 100644 index 0000000..f584b48 --- /dev/null +++ b/packages/cmd/src/services/cache/__tests__/get.spec.ts @@ -0,0 +1,172 @@ +import { isAxiosError } from 'axios'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { retrieveCache } from '../../../api'; +import { PRESETS } from '../../../commands/cache/options'; +import { + CacheCommandConfig, + CacheGetCommandConfig, + getCacheCommandConfig, +} from '../../../config/cache'; +import { getCI } from '../../../env/ciProvider'; +import { success, warnWithNoTrace } from '../../../logger'; +import { unzipBuffer } from '../fs'; +import { handleGetCache } from '../get'; +import { download } from '../network'; +import { handlePostLastRunPreset, handlePreLastRunPreset } from '../presets'; + +const mockConfig: { + type: 'GET_COMMAND_CONFIG'; + values: (CacheCommandConfig & CacheGetCommandConfig) | null; +} = { + type: 'GET_COMMAND_CONFIG', + values: { + recordKey: 'testKey', + id: 'testId', + preset: PRESETS.lastRun, + matrixIndex: 0, + matrixTotal: 1, + outputDir: 'testOutput', + continue: false, + }, +}; + +const mockCI: ReturnType = { + provider: 'testCI', + ciBuildId: { source: 'random', value: 'auto-ci-build-id' }, + params: {}, +}; + +const mockCacheResult = { + readUrl: 'http://cache.url', + metaReadUrl: 'http://meta.url', + cacheId: 'cacheId123', + orgId: 'org123', +}; + +const mockMetaFile = { version: '1.0' }; + +vi.mock('../../../config/cache'); +vi.mock('../../../env/ciProvider'); +vi.mock('../../../api'); +vi.mock('../network'); +vi.mock('../fs'); +vi.mock('../presets'); +vi.mock('axios'); +vi.mock('../../../logger'); + +describe('handleGetCache', () => { + beforeEach(() => { + vi.resetAllMocks(); + vi.mocked(getCacheCommandConfig).mockReturnValue(mockConfig); + vi.mocked(getCI).mockReturnValue(mockCI); + vi.mocked(retrieveCache).mockResolvedValue(mockCacheResult); + vi.mocked(download).mockResolvedValue( + Buffer.from(JSON.stringify(mockMetaFile)) + ); + vi.mocked(unzipBuffer).mockResolvedValue(undefined); + }); + + const expectCacheRetrievalAndDownload = async () => { + await handleGetCache(); + expect(retrieveCache).toHaveBeenCalledWith({ + recordKey: 'testKey', + ci: mockCI, + id: 'testId', + config: { matrixIndex: 0, matrixTotal: 1 }, + }); + expect(download).toHaveBeenCalledWith('http://cache.url'); + expect(unzipBuffer).toHaveBeenCalledWith( + expect.any(Buffer), + mockConfig.values?.outputDir + ); + }; + + it('should throw an error if config type is not GET_COMMAND_CONFIG', async () => { + vi.mocked(getCacheCommandConfig).mockReturnValue({ + type: 'SET_COMMAND_CONFIG', + values: mockConfig.values, + }); + await expect(handleGetCache()).rejects.toThrow('Config is missing!'); + }); + + it('should throw an error if config values are not set', async () => { + vi.mocked(getCacheCommandConfig).mockReturnValue({ + type: 'GET_COMMAND_CONFIG', + values: null, + }); + await expect(handleGetCache()).rejects.toThrow('Config is missing!'); + }); + + it('should call handlePreLastRunPreset if preset is lastRun', async () => { + await handleGetCache(); + expect(handlePreLastRunPreset).toHaveBeenCalledWith( + mockConfig.values, + mockCI + ); + }); + + it('should retrieve cache and download archive', async () => { + await expectCacheRetrievalAndDownload(); + }); + + it('should download and parse meta file', async () => { + const jsonParseSpy = vi.spyOn(JSON, 'parse'); + await handleGetCache(); + expect(download).toHaveBeenCalledWith('http://meta.url'); + expect(jsonParseSpy).toHaveBeenCalledWith( + Buffer.from(JSON.stringify(mockMetaFile)).toString('utf-8') + ); + }); + + it('should call handlePostLastRunPreset if preset is lastRun', async () => { + await handleGetCache(); + expect(handlePostLastRunPreset).toHaveBeenCalledWith( + mockConfig.values, + mockCI, + undefined + ); + }); + + it('should log success message when cache is restored', async () => { + await handleGetCache(); + expect(success).toHaveBeenCalledWith( + 'Cache restored. Cache ID: %s', + mockCacheResult.cacheId + ); + }); + + const testCacheNotFoundError = async (continueOnCacheMiss: boolean) => { + (mockConfig.values as CacheCommandConfig & CacheGetCommandConfig).continue = + continueOnCacheMiss; + const axiosError = { response: { status: 404 } }; + vi.mocked(isAxiosError).mockReturnValue(true); + vi.mocked(retrieveCache).mockResolvedValueOnce(mockCacheResult); + vi.mocked(download).mockRejectedValue(axiosError); + + if (continueOnCacheMiss) { + await handleGetCache(); + expect(warnWithNoTrace).toHaveBeenCalledWith( + `Cache with ID "${mockCacheResult.cacheId}" not found` + ); + } else { + await expect(handleGetCache()).rejects.toThrow( + `Cache with ID "${mockCacheResult.cacheId}" not found` + ); + expect(warnWithNoTrace).not.toHaveBeenCalled(); + } + }; + + it('should throw an error if cache is not found and continueOnCacheMiss is false', async () => { + await testCacheNotFoundError(false); + }); + + it('should warn and return if cache is not found and continueOnCacheMiss is true', async () => { + await testCacheNotFoundError(true); + }); + + it('should throw an unknown error if it is not an Axios error', async () => { + const unknownError = new Error('Unknown error'); + vi.mocked(download).mockRejectedValue(unknownError); + await expect(handleGetCache()).rejects.toThrow(unknownError); + }); +}); diff --git a/packages/cmd/src/services/cache/__tests__/set.spec.ts b/packages/cmd/src/services/cache/__tests__/set.spec.ts new file mode 100644 index 0000000..ff36b04 --- /dev/null +++ b/packages/cmd/src/services/cache/__tests__/set.spec.ts @@ -0,0 +1,153 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { createCache } from '../../../api'; +import { PRESETS } from '../../../commands/cache/options'; +import { + CacheCommandConfig, + CacheSetCommandConfig, + getCacheCommandConfig, +} from '../../../config/cache'; +import { getCI } from '../../../env/ciProvider'; +import { success } from '../../../logger'; +import { filterPaths, zipFilesToBuffer } from '../fs'; +import { createMeta, getLastRunFilePath } from '../lib'; +import { sendBuffer } from '../network'; +import { handleSetCache } from '../set'; + +vi.mock('../../../config/cache'); +vi.mock('../../../env/ciProvider'); +vi.mock('../../../api'); +vi.mock('../../../logger'); +vi.mock('../fs'); +vi.mock('../lib'); +vi.mock('../network'); + +describe('handleSetCache', () => { + const mockConfig: { + type: 'SET_COMMAND_CONFIG'; + values: CacheCommandConfig & CacheSetCommandConfig; + } = { + type: 'SET_COMMAND_CONFIG', + values: { + recordKey: 'testKey', + id: 'testId', + preset: PRESETS.lastRun, + pwOutputDir: 'outputDir', + matrixIndex: 0, + matrixTotal: 1, + path: ['file1', 'file2'], + }, + }; + + const mockCI: ReturnType = { + provider: 'testCI', + ciBuildId: { source: 'random', value: 'auto-ci-build-id' }, + params: {}, + }; + + const mockCreateCacheResult = { + cacheId: 'cacheId123', + uploadUrl: 'http://upload.url', + metaUploadUrl: 'http://meta.url', + orgId: 'org123', + }; + + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(getCacheCommandConfig).mockReturnValue(mockConfig); + vi.mocked(getCI).mockReturnValue(mockCI); + vi.mocked(createCache).mockResolvedValue(mockCreateCacheResult); + vi.mocked(zipFilesToBuffer).mockResolvedValue(Buffer.from('zip archive')); + vi.mocked(createMeta).mockReturnValue(Buffer.from('meta data')); + vi.mocked(getLastRunFilePath).mockReturnValue('.last-run.json'); + }); + + it('should throw an error if config type is not SET_COMMAND_CONFIG', async () => { + vi.mocked(getCacheCommandConfig).mockReturnValue({ + type: 'GET_COMMAND_CONFIG', + values: mockConfig.values, + }); + await expect(handleSetCache()).rejects.toThrow('Config is missing!'); + }); + + it('should throw an error if config values are not set', async () => { + vi.mocked(getCacheCommandConfig).mockReturnValue({ + type: 'GET_COMMAND_CONFIG', + values: null, + }); + await expect(handleSetCache()).rejects.toThrow('Config is missing!'); + }); + + it('should throw an error if no paths available to upload', async () => { + vi.mocked(getCacheCommandConfig).mockReturnValue({ + ...mockConfig, + values: { ...mockConfig.values, preset: undefined, path: [] }, + }); + await expect(handleSetCache()).rejects.toThrow( + 'No paths available to upload' + ); + }); + + it('should call filterPaths and zipFilesToBuffer', async () => { + await handleSetCache(); + expect(filterPaths).toHaveBeenCalledWith(mockConfig.values.path); + expect(zipFilesToBuffer).toHaveBeenCalledWith(['.last-run.json']); + }); + + it('should upload cache archive and meta data', async () => { + await handleSetCache(); + + expect(createCache).toHaveBeenCalledWith({ + recordKey: 'testKey', + ci: mockCI, + id: 'testId', + config: { matrixIndex: 0, matrixTotal: 1 }, + }); + + expect(sendBuffer).toHaveBeenCalledWith( + { + buffer: Buffer.from('zip archive'), + contentType: 'application/zip', + name: 'cacheId123', + uploadUrl: 'http://upload.url', + }, + 'application/zip', + undefined + ); + + expect(sendBuffer).toHaveBeenCalledWith( + { + buffer: Buffer.from('meta data'), + contentType: 'application/json', + name: 'cacheId123_meta', + uploadUrl: 'http://meta.url', + }, + 'application/json', + undefined + ); + }); + + it('should log success message when cache is uploaded', async () => { + await handleSetCache(); + expect(success).toHaveBeenCalledWith( + 'Cache uploaded. Cache ID: %s', + 'cacheId123' + ); + }); + + it('should call getLastRunFilePath if preset is lastRun', async () => { + await handleSetCache(); + expect(getLastRunFilePath).toHaveBeenCalledWith('outputDir'); + }); + + it('should throw error if handleArchiveUpload fails', async () => { + vi.mocked(zipFilesToBuffer).mockRejectedValue( + new Error('Failed to zip files') + ); + await expect(handleSetCache()).rejects.toThrow('Failed to zip files'); + }); + + it('should throw error if handleMetaUpload fails', async () => { + vi.mocked(sendBuffer).mockRejectedValue(new Error('Failed to uplaod')); + await expect(handleSetCache()).rejects.toThrow('Failed to uplaod'); + }); +}); diff --git a/packages/cmd/src/services/cache/get.ts b/packages/cmd/src/services/cache/get.ts index b1b3b7e..6eff08d 100644 --- a/packages/cmd/src/services/cache/get.ts +++ b/packages/cmd/src/services/cache/get.ts @@ -4,7 +4,7 @@ import { retrieveCache } from '../../api'; import { PRESETS } from '../../commands/cache/options'; import { getCacheCommandConfig } from '../../config/cache'; import { getCI } from '../../env/ciProvider'; -import { success } from '../../logger'; +import { success, warnWithNoTrace } from '../../logger'; import { unzipBuffer } from './fs'; import { MetaFile } from './lib'; import { download } from './network'; @@ -16,7 +16,14 @@ export async function handleGetCache() { throw new Error('Config is missing!'); } - const { recordKey, id, preset, matrixIndex, matrixTotal } = config.values; + const { + recordKey, + id, + preset, + matrixIndex, + matrixTotal, + continue: continueOnCacheMiss, + } = config.values; const outputDir = config.values.outputDir; const ci = getCI(); @@ -50,11 +57,14 @@ export async function handleGetCache() { success('Cache restored. Cache ID: %s', result.cacheId); } catch (e) { if (isAxiosError(e)) { - if ( - e.response?.status && - (e.response?.status === 403 || e.response?.status === 404) - ) { - throw new Error(`Cache with ID "${result.cacheId}" not found`); + if (e.response?.status === 403 || e.response?.status === 404) { + const message = `Cache with ID "${result.cacheId}" not found`; + if (continueOnCacheMiss) { + warnWithNoTrace(message); + return; + } + + throw new Error(message); } } diff --git a/packages/cmd/src/services/cache/set.ts b/packages/cmd/src/services/cache/set.ts index d54b7e1..2d93bf9 100644 --- a/packages/cmd/src/services/cache/set.ts +++ b/packages/cmd/src/services/cache/set.ts @@ -21,7 +21,9 @@ export async function handleSetCache() { const { recordKey, id, preset, pwOutputDir, matrixIndex, matrixTotal } = config.values; - const paths = config.values.path ? filterPaths(config.values.path) : []; + const paths = config.values.path?.length + ? filterPaths(config.values.path) + : []; const uploadPaths: string[] = [];