diff --git a/.changeset/chubby-lines-think.md b/.changeset/chubby-lines-think.md new file mode 100644 index 000000000..e7e434f9b --- /dev/null +++ b/.changeset/chubby-lines-think.md @@ -0,0 +1,5 @@ +--- +'@openfn/cli': patch +--- + +Write the .gitignore file for cli cache to the cache root. This means the command will generate more ignore files, but prevents them getting generated at the system root diff --git a/packages/cli/src/execute/handler.ts b/packages/cli/src/execute/handler.ts index 7c926102c..607e73b33 100644 --- a/packages/cli/src/execute/handler.ts +++ b/packages/cli/src/execute/handler.ts @@ -15,7 +15,7 @@ import loadState from '../util/load-state'; import validateAdaptors from '../util/validate-adaptors'; import loadPlan from '../util/load-plan'; import assertPath from '../util/assert-path'; -import { clearCache, getCachePath } from '../util/cache'; +import { clearCache } from '../util/cache'; import fuzzyMatchStep from '../util/fuzzy-match-step'; import abort from '../util/abort'; import validatePlan from '../util/validate-plan'; @@ -175,15 +175,6 @@ const executeHandler = async (options: ExecuteOptions, logger: Logger) => { try { const result = await execute(finalPlan, state, options, logger); - if (options.cacheSteps) { - logger.success( - `Cached output written to ${getCachePath( - options, - plan.workflow.name - )} (see info logs for details)` - ); - } - await serializeOutput(options, result, logger); const duration = printDuration(new Date().getTime() - start); if (result?.errors) { diff --git a/packages/cli/src/util/cache.ts b/packages/cli/src/util/cache.ts index 846cb9cf2..0f4dbf1a0 100644 --- a/packages/cli/src/util/cache.ts +++ b/packages/cli/src/util/cache.ts @@ -8,7 +8,8 @@ import type { Logger } from './logger'; export const CACHE_DIR = '.cli-cache'; -// TODO this is all a bit over complicated tbh +// When called without workflowName/stepId, returns the CACHE_DIR root. +// This is used directly in saveToCache to locate the .gitignore. export const getCachePath = ( options: Pick, workflowName?: string, @@ -24,7 +25,8 @@ export const getCachePath = ( const basePath = path.resolve( baseDir ?? process.cwd(), - `${CACHE_DIR}/${workflowName}` + CACHE_DIR, + workflowName ?? '' ); if (stepId) { @@ -33,50 +35,45 @@ export const getCachePath = ( return basePath; }; -const ensureGitIgnore = (options: any, cachePath: string) => { +const ensureGitIgnore = (options: any, cacheRoot: string, logger?: Logger) => { if (!options._hasGitIgnore) { - // Find the root cache folder - let root = cachePath; - while (root.length > 1 && !root.endsWith(CACHE_DIR)) { - root = path.dirname(root); - } - // From the root cache, look for a .gitignore - const ignorePath = path.resolve(root, '.gitignore'); + const ignorePath = path.join(cacheRoot, '.gitignore'); try { fs.accessSync(ignorePath); } catch (e) { - // doesn't exist! + logger?.debug('Creating .gitignore at ', ignorePath); fs.writeFileSync(ignorePath, '*'); } + options._hasGitIgnore = true; } - options._hasGitIgnore = true; }; export const saveToCache = async ( plan: ExecutionPlan, stepId: string, output: any, - options: Pick, + options: Pick, logger: Logger ) => { if (options.cacheSteps) { - const cachePath = await getCachePath(options, plan.workflow.name, stepId); + const cachePath = getCachePath(options, plan.workflow.name, stepId); // Note that this is sync because other execution order gets messed up fs.mkdirSync(path.dirname(cachePath), { recursive: true }); - ensureGitIgnore(options, path.dirname(cachePath)); + // getCachePath with no workflowName returns the CACHE_DIR root + ensureGitIgnore(options, getCachePath(options)); - logger.info(`Writing ${stepId} output to ${cachePath}`); + logger.info(`Writing cached ${stepId} output to ${cachePath}`); fs.writeFileSync(cachePath, JSON.stringify(output)); } }; export const clearCache = async ( plan: ExecutionPlan, - options: Pick, + options: Pick, logger: Logger ) => { - const cacheDir = await getCachePath(options, plan.workflow?.name); + const cacheDir = getCachePath(options, plan.workflow?.name); try { await rmdir(cacheDir, { recursive: true }); diff --git a/packages/cli/test/execute/execute.test.ts b/packages/cli/test/execute/execute.test.ts index 2b500fa1b..8b7184aff 100644 --- a/packages/cli/test/execute/execute.test.ts +++ b/packages/cli/test/execute/execute.test.ts @@ -418,6 +418,24 @@ test.serial('.cli-cache has a gitignore', async (t) => { t.is(gitignore, '*'); }); +test.serial('.cli-cache writes a .gitignore', async (t) => { + mockFs({ + '/job.js': `${fn}fn((state) => ({ ...state, x: 1 }));`, + }); + + const options = { + ...defaultOptions, + expressionPath: '/job.js', + baseDir: '/', + cacheSteps: true, + }; + + await handler(options, logger); + + const gitignore = await fs.readFile('/.cli-cache/.gitignore', 'utf8'); + t.is(gitignore, '*'); +}); + test.serial('run a workflow with initial state from stdin', async (t) => { const workflow = { workflow: {