@openfn/cli
Advanced tools
Comparing version
#!/usr/bin/env node | ||
import { | ||
DEFAULT_REPO_DIR, | ||
expand_adaptors_default | ||
} from "./chunk-UBDWXKSG.js"; | ||
@@ -12,5 +8,7 @@ // src/process/spawn.ts | ||
import process2 from "node:process"; | ||
function spawn_default(basePath, opts2) { | ||
function spawn_default(opts2) { | ||
const execArgv = [ | ||
// Suppress experimental argument warnings | ||
"--no-warnings", | ||
// Allows us to load an ESM module from a text string | ||
"--experimental-vm-modules" | ||
@@ -22,3 +20,3 @@ ]; | ||
if (init) { | ||
child.send({ init: true, basePath, opts: opts2 }); | ||
child.send({ init: true, opts: opts2 }); | ||
} | ||
@@ -41,2 +39,101 @@ if (done) { | ||
import path2 from "node:path"; | ||
// src/constants.ts | ||
var DEFAULT_REPO_DIR = "/tmp/openfn/repo"; | ||
// src/util/expand-adaptors.ts | ||
var expand = (name) => { | ||
if (typeof name === "string") { | ||
const [left] = name.split("="); | ||
if (left.match("/") || left.endsWith(".js")) { | ||
return name; | ||
} | ||
return `@openfn/language-${name}`; | ||
} | ||
return name; | ||
}; | ||
var expand_adaptors_default = (opts2) => { | ||
const { adaptors: adaptors2, workflow } = opts2; | ||
if (adaptors2) { | ||
opts2.adaptors = adaptors2?.map(expand); | ||
} | ||
if (workflow) { | ||
Object.values(workflow.jobs).forEach((job) => { | ||
if (job.adaptor) { | ||
job.adaptor = expand(job.adaptor); | ||
} | ||
}); | ||
} | ||
return opts2; | ||
}; | ||
// src/util/logger.ts | ||
import actualCreateLogger, { printDuration } from "@openfn/logger"; | ||
import { isValidLogLevel, defaultLogger } from "@openfn/logger"; | ||
var CLI = "cli"; | ||
var COMPILER = "compiler"; | ||
var RUNTIME = "runtime"; | ||
var JOB = "job"; | ||
var namespaces = { | ||
[CLI]: "CLI", | ||
[RUNTIME]: "R/T", | ||
[COMPILER]: "CMP", | ||
[JOB]: "JOB" | ||
}; | ||
// src/util/ensure-log-opts.ts | ||
var defaultLoggerOptions = { | ||
default: "default", | ||
// TODO fix to lower case | ||
job: "debug" | ||
}; | ||
var ERROR_MESSAGE_LOG_LEVEL = "Unknown log level. Valid levels are none, debug, info and default."; | ||
var ERROR_MESSAGE_LOG_COMPONENT = "Unknown log component. Valid components are cli, compiler, runtime and job."; | ||
var componentShorthands = { | ||
cmp: "compiler", | ||
rt: "runtime", | ||
"r/t": "runtime" | ||
}; | ||
var ensureLogOpts = (opts2) => { | ||
const components = {}; | ||
const outgoingOpts = opts2; | ||
if (!opts2.log && /^(version|test)$/.test(opts2.command)) { | ||
outgoingOpts.log = { default: "info" }; | ||
return outgoingOpts; | ||
} | ||
if (opts2.log) { | ||
const parts = opts2.log.split(","); | ||
parts.forEach((l) => { | ||
let component = ""; | ||
let level = ""; | ||
if (l.match(/=/)) { | ||
const parts2 = l.split("="); | ||
component = parts2[0].toLowerCase(); | ||
if (componentShorthands[component]) { | ||
component = componentShorthands[component]; | ||
} | ||
level = parts2[1].toLowerCase(); | ||
} else { | ||
component = "default"; | ||
level = l.toLowerCase(); | ||
} | ||
if (!/^(cli|runtime|compiler|job|default)$/i.test(component)) { | ||
throw new Error(ERROR_MESSAGE_LOG_COMPONENT); | ||
} | ||
level = level.toLowerCase(); | ||
if (!isValidLogLevel(level)) { | ||
throw new Error(ERROR_MESSAGE_LOG_LEVEL); | ||
} | ||
components[component] = level; | ||
}); | ||
} | ||
outgoingOpts.log = { | ||
...defaultLoggerOptions, | ||
...components | ||
}; | ||
return outgoingOpts; | ||
}; | ||
var ensure_log_opts_default = ensureLogOpts; | ||
// src/options.ts | ||
var setDefaultValue = (opts2, key, value) => { | ||
@@ -178,2 +275,13 @@ const v = opts2[key]; | ||
}; | ||
var log = { | ||
name: "log", | ||
yargs: { | ||
alias: ["l"], | ||
description: "Set the log level", | ||
string: true | ||
}, | ||
ensure: (opts2) => { | ||
ensure_log_opts_default(opts2); | ||
} | ||
}; | ||
var logJson = { | ||
@@ -184,4 +292,2 @@ name: "log-json", | ||
boolean: true | ||
}, | ||
ensure: () => { | ||
} | ||
@@ -354,2 +460,3 @@ }; | ||
inputPath, | ||
log, | ||
logJson, | ||
@@ -365,3 +472,3 @@ override(outputStdout, { | ||
command: "compile [path]", | ||
desc: "Compile an openfn job or workflow and print or save the resulting JavaScript.", | ||
describe: "Compile an openfn job or workflow and print or save the resulting JavaScript.", | ||
handler: ensure("compile", options), | ||
@@ -382,10 +489,16 @@ builder: (yargs2) => build(options, yargs2).positional("path", { | ||
// src/deploy/command.ts | ||
var options2 = [statePath, projectPath, configPath, confirm, describe]; | ||
var options2 = [ | ||
configPath, | ||
confirm, | ||
describe, | ||
log, | ||
logJson, | ||
projectPath, | ||
statePath | ||
]; | ||
var deployCommand = { | ||
command: "deploy", | ||
desc: "Deploy a project's config to a remote Lightning instance", | ||
builder: (yargs2) => { | ||
return build(options2, yargs2).example("deploy", ""); | ||
}, | ||
handler: ensure("deploy", options2) | ||
describe: "Deploy a project's config to a remote Lightning instance", | ||
handler: ensure("deploy", options2), | ||
builder: (yargs2) => build(options2, yargs2) | ||
}; | ||
@@ -397,9 +510,9 @@ var command_default2 = deployCommand; | ||
command: "docgen <specifier>", | ||
desc: false, | ||
// Hide this command as it's not really for public usage | ||
describe: false, | ||
// 'Generate documentation into the repo. Specifier must include a version number.' | ||
handler: (argv) => { | ||
argv.command = "docgen"; | ||
}, | ||
builder: (yargs2) => { | ||
return yargs2.example("docgen @openfn/language-common@1.7.5", ""); | ||
} | ||
builder: (yargs2) => yargs2.example("docgen @openfn/language-common@1.7.5", "") | ||
}; | ||
@@ -409,13 +522,16 @@ var command_default3 = docgenCommand; | ||
// src/docs/command.ts | ||
var command_default4 = { | ||
var options3 = [log, logJson, repoDir]; | ||
var docsCommand = { | ||
command: "docs <adaptor> [operation]", | ||
desc: "Print help for an adaptor function. You can use short-hand for adaptor names (ie, common instead of @openfn/language-common)", | ||
handler: (argv) => { | ||
argv.command = "docs"; | ||
}, | ||
builder: (yargs2) => yargs2.example("docs common fn", "Print help for the common fn operation") | ||
describe: "Print help for an adaptor function. You can use short-hand for adaptor names (ie, common instead of @openfn/language-common)", | ||
handler: ensure("docs", options3), | ||
builder: (yargs2) => build(options3, yargs2).example( | ||
"docs common fn", | ||
"Print help for the common fn operation" | ||
) | ||
}; | ||
var command_default4 = docsCommand; | ||
// src/execute/command.ts | ||
var options3 = [ | ||
var options4 = [ | ||
expandAdaptors, | ||
@@ -428,2 +544,3 @@ adaptors, | ||
inputPath, | ||
log, | ||
logJson, | ||
@@ -444,3 +561,3 @@ outputPath, | ||
command: "execute [path]", | ||
desc: `Run an openfn job or workflow. Get more help by running openfn <command> help. | ||
describe: `Run an openfn job or workflow. Get more help by running openfn <command> help. | ||
@@ -453,4 +570,4 @@ Execute will run a job/workflow at the path and write the output state to disk (to ./state.json unless otherwise specified) | ||
aliases: ["$0"], | ||
handler: ensure("execute", options3), | ||
builder: (yargs2) => build(options3, yargs2).positional("path", { | ||
handler: ensure("execute", options4), | ||
builder: (yargs2) => build(options4, yargs2).positional("path", { | ||
describe: "The path to load the job or workflow from (a .js or .json file or a dir containing a job.js file)", | ||
@@ -475,6 +592,7 @@ demandOption: true | ||
// src/metadata/command.ts | ||
var options4 = [ | ||
var options5 = [ | ||
expandAdaptors, | ||
adaptors, | ||
force, | ||
log, | ||
logJson, | ||
@@ -488,5 +606,5 @@ repoDir, | ||
command: "metadata", | ||
desc: "Generate metadata for an adaptor config", | ||
handler: ensure("metadata", options4), | ||
builder: (yargs2) => build(options4, yargs2).example( | ||
describe: "Generate metadata for an adaptor config", | ||
handler: ensure("metadata", options5), | ||
builder: (yargs2) => build(options5, yargs2).example( | ||
"metadata -a salesforce -s tmp/state.json", | ||
@@ -498,10 +616,14 @@ "Generate salesforce metadata from config in state.json" | ||
// src/pull/command.ts | ||
var options5 = [statePath, projectPath, configPath]; | ||
var options6 = [statePath, projectPath, configPath, log, logJson]; | ||
var pullCommand = { | ||
command: "pull", | ||
desc: "Pull aproject's state and spec from a Lightning Instance to the local directory", | ||
builder: (yargs2) => { | ||
return build(options5, yargs2).example("pull", "Pull an updated copy of a project spec and state from a Lightning Instance"); | ||
}, | ||
handler: ensure("pull", options5) | ||
command: "pull [projectId]", | ||
describe: "Pull a project's state and spec from a Lightning Instance to the local directory", | ||
builder: (yargs2) => build(options6, yargs2).positional("projectId", { | ||
describe: "The id of the project that should be pulled shouled be a UUID", | ||
demandOption: true | ||
}).example( | ||
"pull 57862287-23e6-4650-8d79-e1dd88b24b1c", | ||
"Pull an updated copy of a the above spec and state from a Lightning Instance" | ||
), | ||
handler: ensure("pull", options6) | ||
}; | ||
@@ -513,6 +635,8 @@ var command_default7 = pullCommand; | ||
command: "repo [subcommand]", | ||
desc: "Run commands on the module repo (install|clean)", | ||
describe: "Run commands on the module repo (install|clean)", | ||
builder: (yargs2) => yargs2.command(clean).command(install).command(list).example("repo install -a http", "Install @openfn/language-http").example("repo clean", "Remove everything from the repo working dir") | ||
}; | ||
var installOptions = [ | ||
log, | ||
logJson, | ||
repoDir, | ||
@@ -529,3 +653,3 @@ override(expandAdaptors, { | ||
command: "install [packages...]", | ||
desc: "install one or more packages to the runtime repo. Use -a to pass shorthand adaptor names.", | ||
describe: "install one or more packages to the runtime repo. Use -a to pass shorthand adaptor names.", | ||
handler: ensure("repo-install", installOptions), | ||
@@ -540,36 +664,37 @@ builder: (yargs2) => build(installOptions, yargs2).example("install axios", "Install the axios npm package to the repo").example( | ||
}; | ||
var cleanOptions = [ | ||
log, | ||
logJson, | ||
repoDir, | ||
{ | ||
name: "force", | ||
yargs: { | ||
alias: ["f"], | ||
description: "Skip the prompt and force deletion", | ||
boolean: true | ||
} | ||
} | ||
]; | ||
var clean = { | ||
command: "clean", | ||
desc: "Removes all modules from the runtime module repo", | ||
handler: ensure("repo-clean", [repoDir]), | ||
builder: (yargs2) => build( | ||
[ | ||
repoDir, | ||
{ | ||
name: "force", | ||
yargs: { | ||
alias: ["f"], | ||
description: "Skip the prompt and force deletion", | ||
boolean: true | ||
} | ||
} | ||
], | ||
yargs2 | ||
) | ||
describe: "Removes all modules from the runtime module repo", | ||
handler: ensure("repo-clean", cleanOptions), | ||
builder: (yargs2) => build(cleanOptions, yargs2) | ||
}; | ||
var listOptions = [repoDir, log, logJson]; | ||
var list = { | ||
command: "list", | ||
desc: "Show a report on what is installed in the repo", | ||
describe: "Show a report on what is installed in the repo", | ||
aliases: ["$0"], | ||
handler: ensure("repo-list", [repoDir]), | ||
builder: (yargs2) => build([repoDir], yargs2) | ||
handler: ensure("repo-list", listOptions), | ||
builder: (yargs2) => build(listOptions, yargs2) | ||
}; | ||
// src/test/command.ts | ||
var options6 = [stateStdin]; | ||
var options7 = [stateStdin, log, logJson]; | ||
var command_default8 = { | ||
command: "test", | ||
desc: "Compiles and runs a test job, printing the result to stdout", | ||
handler: ensure("test", options6), | ||
builder: (yargs2) => build(options6, yargs2).example("test", "Run the test script") | ||
handler: ensure("test", options7), | ||
builder: (yargs2) => build(options7, yargs2).example("test", "Run the test script") | ||
}; | ||
@@ -579,14 +704,5 @@ | ||
var y = yargs(hideBin(process.argv)); | ||
var cmd = y.command(command_default5).command(command_default).command(command_default2).command(install).command(repo).command(command_default8).command(command_default4).command(command_default6).command(command_default3).command(command_default7).option("log", { | ||
alias: ["l"], | ||
description: "Set the default log level to none, default, info or debug", | ||
array: true | ||
}).option("log-json", { | ||
description: "Output all logs as JSON objects", | ||
boolean: true | ||
}).example("openfn execute help", "Show documentation for the execute command").example( | ||
"openfn docs @openfn/language-common each", | ||
"Get more help on the common.each command" | ||
).command({ | ||
var cmd = y.command(command_default5).command(command_default).command(command_default2).command(install).command(repo).command(command_default8).command(command_default4).command(command_default6).command(command_default3).command(command_default7).command({ | ||
command: "version", | ||
describe: "Show the currently installed version of the CLI, compiler and runtime.", | ||
handler: (argv) => { | ||
@@ -598,3 +714,3 @@ argv.command = "version"; | ||
// src/index.ts | ||
var opts = cmd.parse(); | ||
spawn_default(opts.path, opts); | ||
var opts = cmd.parseSync(); | ||
spawn_default(opts); |
export { } |
@@ -1,6 +0,1 @@ | ||
import { | ||
DEFAULT_REPO_DIR, | ||
expand_adaptors_default | ||
} from "../chunk-UBDWXKSG.js"; | ||
// src/execute/execute.ts | ||
@@ -42,4 +37,4 @@ import run, { getNameAndVersion } from "@openfn/runtime"; | ||
super(reason); | ||
this.handled = true; | ||
} | ||
handled = true; | ||
}; | ||
@@ -82,3 +77,3 @@ var abort_default = (logger, reason, error, help) => { | ||
const extractInfo = (specifier) => { | ||
const [module, path8] = specifier.split("="); | ||
const [module, path7] = specifier.split("="); | ||
const { name, version } = getNameAndVersion(module); | ||
@@ -88,4 +83,4 @@ const info = { | ||
}; | ||
if (path8) { | ||
info.path = path8; | ||
if (path7) { | ||
info.path = path7; | ||
} | ||
@@ -231,3 +226,5 @@ if (version) { | ||
}); | ||
logger.success("Installed packages:\n\n" + treeify.asTree(output)); | ||
logger.success( | ||
"Installed packages:\n\n" + treeify.asTree(output, false, false) | ||
); | ||
}; | ||
@@ -293,6 +290,6 @@ | ||
var resolveSpecifierPath = async (pattern, repoDir, log) => { | ||
const [specifier, path8] = pattern.split("="); | ||
if (path8) { | ||
log.debug(`Resolved ${specifier} to path: ${path8}`); | ||
return path8; | ||
const [specifier, path7] = pattern.split("="); | ||
if (path7) { | ||
log.debug(`Resolved ${specifier} to path: ${path7}`); | ||
return path7; | ||
} | ||
@@ -314,7 +311,7 @@ const repoPath = await getModulePath(specifier, repoDir, log); | ||
log.debug(`Attempting to preload types for ${specifier}`); | ||
const path8 = await resolveSpecifierPath(pattern, opts.repoDir, log); | ||
if (path8) { | ||
const path7 = await resolveSpecifierPath(pattern, opts.repoDir, log); | ||
if (path7) { | ||
try { | ||
exports = await preloadAdaptorExports( | ||
path8, | ||
path7, | ||
opts.useAdaptorsMonorepo, | ||
@@ -324,3 +321,3 @@ log | ||
} catch (e) { | ||
log.error(`Failed to load adaptor typedefs from path ${path8}`); | ||
log.error(`Failed to load adaptor typedefs from path ${path7}`); | ||
log.error(e); | ||
@@ -521,2 +518,28 @@ } | ||
// src/util/expand-adaptors.ts | ||
var expand = (name) => { | ||
if (typeof name === "string") { | ||
const [left] = name.split("="); | ||
if (left.match("/") || left.endsWith(".js")) { | ||
return name; | ||
} | ||
return `@openfn/language-${name}`; | ||
} | ||
return name; | ||
}; | ||
var expand_adaptors_default = (opts) => { | ||
const { adaptors, workflow } = opts; | ||
if (adaptors) { | ||
opts.adaptors = adaptors?.map(expand); | ||
} | ||
if (workflow) { | ||
Object.values(workflow.jobs).forEach((job) => { | ||
if (job.adaptor) { | ||
job.adaptor = expand(job.adaptor); | ||
} | ||
}); | ||
} | ||
return opts; | ||
}; | ||
// src/util/map-adaptors-to-monorepo.ts | ||
@@ -575,5 +598,18 @@ import { readFile } from "node:fs/promises"; | ||
// src/util/assert-path.ts | ||
var assert_path_default = (path7) => { | ||
if (!path7) { | ||
console.error("ERROR: no path provided!"); | ||
console.error("\nUsage:"); | ||
console.error(" open path/to/job"); | ||
console.error("\nFor more help do:"); | ||
console.error(" openfn --help "); | ||
process.exit(1); | ||
} | ||
}; | ||
// src/execute/handler.ts | ||
var executeHandler = async (options, logger) => { | ||
const start = new Date().getTime(); | ||
const start = (/* @__PURE__ */ new Date()).getTime(); | ||
assert_path_default(options.path); | ||
await validate_adaptors_default(options, logger); | ||
@@ -609,3 +645,3 @@ let input = await load_input_default(options, logger); | ||
await serialize_output_default(options, result, logger); | ||
const duration = printDuration(new Date().getTime() - start); | ||
const duration = printDuration((/* @__PURE__ */ new Date()).getTime() - start); | ||
if (result.errors) { | ||
@@ -623,3 +659,3 @@ logger.warn( | ||
} | ||
const duration = printDuration(new Date().getTime() - start); | ||
const duration = printDuration((/* @__PURE__ */ new Date()).getTime() - start); | ||
logger.always(`Workflow failed in ${duration}.`); | ||
@@ -634,2 +670,3 @@ process.exitCode = 1; | ||
var compileHandler = async (options, logger) => { | ||
assert_path_default(options.path); | ||
await load_input_default(options, logger); | ||
@@ -660,5 +697,6 @@ if (options.workflow) { | ||
logger.log("Running test job..."); | ||
options.compile = true; | ||
options.adaptors = []; | ||
options.workflow = { | ||
const opts = { ...options }; | ||
opts.compile = true; | ||
opts.adaptors = []; | ||
opts.workflow = { | ||
start: "start", | ||
@@ -689,5 +727,5 @@ jobs: [ | ||
logger.info("Workflow object:"); | ||
logger.info(JSON.stringify(options.workflow, null, 2)); | ||
logger.info(JSON.stringify(opts.workflow, null, 2)); | ||
logger.break(); | ||
if (!options.stateStdin) { | ||
if (!opts.stateStdin) { | ||
logger.debug( | ||
@@ -699,5 +737,10 @@ "No state provided: pass an object with state.data.answer to provide custom input" | ||
const silentLogger = createNullLogger(); | ||
const state = await load_state_default(options, silentLogger); | ||
const code = await compile_default(options, logger); | ||
const result = await execute_default(code, state, options, silentLogger); | ||
const state = await load_state_default(opts, silentLogger); | ||
const code = await compile_default(opts, logger); | ||
const result = await execute_default( | ||
code, | ||
state, | ||
opts, | ||
silentLogger | ||
); | ||
logger.success(`Result: ${result.data.answer}`); | ||
@@ -772,4 +815,4 @@ return result; | ||
var ensurePath = (filePath) => mkdirSync(path3.dirname(filePath), { recursive: true }); | ||
var generatePlaceholder = (path8) => { | ||
writeFileSync(path8, `{ "loading": true, "timestamp": ${Date.now()}}`); | ||
var generatePlaceholder = (path7) => { | ||
writeFileSync(path7, `{ "loading": true, "timestamp": ${Date.now()}}`); | ||
}; | ||
@@ -780,9 +823,9 @@ var finish = (logger, resultPath) => { | ||
}; | ||
var generateDocs = async (specifier, path8, docgen, logger) => { | ||
var generateDocs = async (specifier, path7, docgen, logger) => { | ||
const result = await docgen(specifier); | ||
await writeFile3(path8, JSON.stringify(result, null, 2)); | ||
finish(logger, path8); | ||
return path8; | ||
await writeFile3(path7, JSON.stringify(result, null, 2)); | ||
finish(logger, path7); | ||
return path7; | ||
}; | ||
var waitForDocs = async (docs, path8, logger, retryDuration = RETRY_DURATION) => { | ||
var waitForDocs = async (docs, path7, logger, retryDuration = RETRY_DURATION) => { | ||
try { | ||
@@ -799,7 +842,7 @@ if (docs.hasOwnProperty("loading")) { | ||
} | ||
const updated = JSON.parse(readFileSync(path8, "utf8")); | ||
const updated = JSON.parse(readFileSync(path7, "utf8")); | ||
if (!updated.hasOwnProperty("loading")) { | ||
logger.info("Docs found!"); | ||
clearInterval(i); | ||
resolve(path8); | ||
resolve(path7); | ||
} | ||
@@ -810,5 +853,5 @@ count++; | ||
} else { | ||
logger.info(`Docs already written to cache at ${path8}`); | ||
finish(logger, path8); | ||
return path8; | ||
logger.info(`Docs already written to cache at ${path7}`); | ||
finish(logger, path7); | ||
return path7; | ||
} | ||
@@ -830,24 +873,24 @@ } catch (e) { | ||
logger.success(`Generating docs for ${specifier}`); | ||
const path8 = `${repoDir}/docs/${specifier}.json`; | ||
ensurePath(path8); | ||
const path7 = `${repoDir}/docs/${specifier}.json`; | ||
ensurePath(path7); | ||
const handleError = () => { | ||
logger.info("Removing placeholder"); | ||
rmSync(path8); | ||
rmSync(path7); | ||
}; | ||
try { | ||
const existing = readFileSync(path8, "utf8"); | ||
const existing = readFileSync(path7, "utf8"); | ||
const json = JSON.parse(existing); | ||
if (json && json.timeout && Date.now() - json.timeout >= TIMEOUT_MS) { | ||
logger.info(`Expired placeholder found. Removing.`); | ||
rmSync(path8); | ||
rmSync(path7); | ||
throw new Error("TIMEOUT"); | ||
} | ||
return waitForDocs(json, path8, logger, retryDuration); | ||
return waitForDocs(json, path7, logger, retryDuration); | ||
} catch (e) { | ||
if (e.message !== "TIMEOUT") { | ||
logger.info(`Docs JSON not found at ${path8}`); | ||
logger.info(`Docs JSON not found at ${path7}`); | ||
} | ||
logger.debug("Generating placeholder"); | ||
generatePlaceholder(path8); | ||
return generateDocs(specifier, path8, docgen, logger).catch((e2) => { | ||
generatePlaceholder(path7); | ||
return generateDocs(specifier, path7, docgen, logger).catch((e2) => { | ||
logger.error("Error generating documentation"); | ||
@@ -901,3 +944,3 @@ logger.error(e2); | ||
logger.info("Generating/loading documentation..."); | ||
const path8 = await handler_default5( | ||
const path7 = await handler_default5( | ||
{ | ||
@@ -907,7 +950,8 @@ specifier: `${name}@${version}`, | ||
}, | ||
// TODO I'm not sure how to handle logging here - we ought to feedback SOMETHING though | ||
createNullLogger() | ||
); | ||
let didError = false; | ||
if (path8) { | ||
const source = await readFile2(path8, "utf8"); | ||
if (path7) { | ||
const source = await readFile2(path7, "utf8"); | ||
const data = JSON.parse(source); | ||
@@ -983,3 +1027,3 @@ let desc; | ||
var decorateMetadata = (metadata) => { | ||
metadata.created = new Date().toISOString(); | ||
metadata.created = (/* @__PURE__ */ new Date()).toISOString(); | ||
}; | ||
@@ -1063,16 +1107,40 @@ var getAdaptorPath = async (adaptor, logger, repoDir) => { | ||
import { | ||
getProject, | ||
getConfig as getConfig2, | ||
getState | ||
getState, | ||
mergeSpecIntoState, | ||
getSpec | ||
} from "@openfn/deploy"; | ||
async function pullHandler(options, logger) { | ||
try { | ||
assert_path_default(options.projectId); | ||
const config = mergeOverrides2(await getConfig2(options.configPath), options); | ||
logger.always("Downloading project yaml and state from instance"); | ||
logger.always("Downloading project yaml and state from instance"); | ||
const state = await getState(config.statePath); | ||
const { data: new_state } = await getProject(config, state.id); | ||
const url = new URL(`/download/yaml?id=${state.id}`, config.endpoint); | ||
const res = await fetch(url); | ||
await fs3.writeFile(path5.resolve(config.specPath), res.body); | ||
await fs3.writeFile(path5.resolve(config.statePath), new_state); | ||
const url2 = new URL( | ||
`api/provision/yaml?id=${options.projectId}`, | ||
config.endpoint | ||
); | ||
logger.debug("Fetching project spec from", url2); | ||
const res = await fetch(url2, { | ||
headers: { | ||
Authorization: `Bearer ${config.apiKey}`, | ||
Accept: "application/json" | ||
} | ||
}); | ||
const resolvedPath = path5.resolve(config.specPath); | ||
logger.debug("reading spec from", resolvedPath); | ||
await fs3.writeFile(resolvedPath, res.body); | ||
const spec = await getSpec(config.specPath); | ||
logger.debug("validated spec: ", spec); | ||
if (spec.errors.length > 0) { | ||
logger.error("ERROR: invalid spec"); | ||
logger.error(spec.errors); | ||
process.exitCode = 1; | ||
process.exit(1); | ||
} | ||
const nextState = mergeSpecIntoState(state, spec.doc); | ||
await fs3.writeFile( | ||
path5.resolve(config.statePath), | ||
JSON.stringify(nextState, null, 2) | ||
); | ||
logger.success("Project pulled successfully"); | ||
@@ -1099,101 +1167,7 @@ process.exitCode = 0; | ||
// src/util/ensure-opts.ts | ||
import path6 from "node:path"; | ||
var defaultLoggerOptions = { | ||
default: "default", | ||
job: "debug" | ||
}; | ||
var ERROR_MESSAGE_LOG_LEVEL = "Unknown log level. Valid levels are none, debug, info and default."; | ||
var ERROR_MESSAGE_LOG_COMPONENT = "Unknown log component. Valid components are cli, compiler, runtime and job."; | ||
var componentShorthands = { | ||
cmp: "compiler", | ||
rt: "runtime", | ||
"r/t": "runtime" | ||
}; | ||
var isValidComponent = (v) => /^(cli|runtime|compiler|job|default)$/i.test(v); | ||
var ensureLogOpts = (opts) => { | ||
const components = {}; | ||
if (!opts.log && /^(version|test)$/.test(opts.command)) { | ||
opts.log = { default: "info" }; | ||
return opts; | ||
} else if (opts.log) { | ||
opts.log.forEach((l) => { | ||
let component = ""; | ||
let level = ""; | ||
if (l.match(/=/)) { | ||
const parts = l.split("="); | ||
component = parts[0].toLowerCase(); | ||
if (componentShorthands[component]) { | ||
component = componentShorthands[component]; | ||
} | ||
level = parts[1].toLowerCase(); | ||
} else { | ||
component = "default"; | ||
level = l.toLowerCase(); | ||
} | ||
if (!isValidComponent(component)) { | ||
throw new Error(ERROR_MESSAGE_LOG_COMPONENT); | ||
} | ||
level = level.toLowerCase(); | ||
if (!isValidLogLevel(level)) { | ||
throw new Error(ERROR_MESSAGE_LOG_LEVEL); | ||
} | ||
components[component] = level; | ||
}); | ||
} | ||
opts.log = { | ||
...defaultLoggerOptions, | ||
...components | ||
}; | ||
return opts; | ||
}; | ||
function ensureOpts(basePath = ".", opts) { | ||
const newOpts = { | ||
adaptor: opts.adaptor, | ||
adaptors: opts.adaptors || [], | ||
autoinstall: opts.autoinstall, | ||
command: opts.command, | ||
expandAdaptors: opts.expandAdaptors !== false, | ||
force: opts.force || false, | ||
immutable: opts.immutable || false, | ||
log: opts.log, | ||
logJson: typeof opts.logJson == "boolean" ? opts.logJson : Boolean(process.env.OPENFN_LOG_JSON), | ||
compile: Boolean(opts.compile), | ||
operation: opts.operation, | ||
outputStdout: Boolean(opts.outputStdout), | ||
packages: opts.packages, | ||
repoDir: opts.repoDir || process.env.OPENFN_REPO_DIR || DEFAULT_REPO_DIR, | ||
skipAdaptorValidation: opts.skipAdaptorValidation ?? false, | ||
specifier: opts.specifier, | ||
stateStdin: opts.stateStdin, | ||
timeout: opts.timeout | ||
}; | ||
const set2 = (key, value) => { | ||
newOpts[key] = opts.hasOwnProperty(key) ? opts[key] : value; | ||
}; | ||
if (opts.useAdaptorsMonorepo) { | ||
newOpts.monorepoPath = process.env.OPENFN_ADAPTORS_REPO || "ERR"; | ||
} | ||
let baseDir = basePath; | ||
if (basePath.endsWith(".js")) { | ||
baseDir = path6.dirname(basePath); | ||
set2("jobPath", basePath); | ||
} else { | ||
set2("jobPath", `${baseDir}/job.js`); | ||
} | ||
set2("statePath", `${baseDir}/state.json`); | ||
if (!opts.outputStdout) { | ||
set2( | ||
"outputPath", | ||
newOpts.command === "compile" ? `${baseDir}/output.js` : `${baseDir}/output.json` | ||
); | ||
} | ||
ensureLogOpts(newOpts); | ||
return newOpts; | ||
} | ||
// src/util/print-versions.ts | ||
import { readFileSync as readFileSync3 } from "node:fs"; | ||
import path7 from "node:path"; | ||
import { getNameAndVersion as getNameAndVersion6 } from "@openfn/runtime"; | ||
import path6 from "node:path"; | ||
import url from "node:url"; | ||
import { getNameAndVersion as getNameAndVersion5 } from "@openfn/runtime"; | ||
import { mainSymbols } from "figures"; | ||
@@ -1207,3 +1181,5 @@ var NODE = "node.js"; | ||
try { | ||
const pkg = JSON.parse(readFileSync3(path7.resolve(adaptorPath, "package.json"), "utf8")); | ||
const pkg = JSON.parse( | ||
readFileSync3(path6.resolve(adaptorPath, "package.json"), "utf8") | ||
); | ||
return pkg.version; | ||
@@ -1226,5 +1202,5 @@ } catch (e) { | ||
adaptorVersion = loadVersionFromPath(pathPart); | ||
adaptorName = getNameAndVersion6(namePart).name; | ||
adaptorName = getNameAndVersion5(namePart).name; | ||
} else { | ||
const { name, version: version2 } = getNameAndVersion6(adaptor); | ||
const { name, version: version2 } = getNameAndVersion5(adaptor); | ||
adaptorName = name; | ||
@@ -1234,12 +1210,9 @@ adaptorVersion = version2 || "latest"; | ||
} | ||
const longest = Math.max(...[ | ||
NODE, | ||
CLI2, | ||
RUNTIME2, | ||
COMPILER2, | ||
adaptorName | ||
].map((s) => s.length)); | ||
const longest = Math.max( | ||
...[NODE, CLI2, RUNTIME2, COMPILER2, adaptorName].map((s) => s.length) | ||
); | ||
const prefix = (str) => ` ${t} ${str.padEnd(longest + 4, " ")}`; | ||
const pkg = await import("../../package.json", { assert: { type: "json" } }); | ||
const { version, dependencies } = pkg.default; | ||
const dirname = path6.dirname(url.fileURLToPath(import.meta.url)); | ||
const pkg = JSON.parse(readFileSync3(`${dirname}/../../package.json`, "utf8")); | ||
const { version, dependencies } = pkg; | ||
const compilerVersion = dependencies["@openfn/compiler"]; | ||
@@ -1269,3 +1242,3 @@ const runtimeVersion = dependencies["@openfn/runtime"]; | ||
} | ||
logger.info(output); | ||
logger.always(output); | ||
}; | ||
@@ -1290,11 +1263,9 @@ var print_versions_default = printVersions; | ||
}; | ||
var maybeEnsureOpts = (basePath, options) => /(^(deploy|execute|compile|test)$)|(repo-)/.test(options.command) ? ensureLogOpts(options) : ensureOpts(basePath, options); | ||
var parse = async (basePath, options, log) => { | ||
const opts = maybeEnsureOpts(basePath, options); | ||
const logger = log || logger_default(CLI, opts); | ||
if (opts.command === "execute" || opts.command === "test") { | ||
await print_versions_default(logger, opts); | ||
var parse = async (options, log) => { | ||
const logger = log || logger_default(CLI, options); | ||
if (options.command === "execute" || options.command === "test") { | ||
await print_versions_default(logger, options); | ||
} | ||
if (opts.monorepoPath) { | ||
if (opts.monorepoPath === "ERR") { | ||
if (options.monorepoPath) { | ||
if (options.monorepoPath === "ERR") { | ||
logger.error( | ||
@@ -1306,7 +1277,8 @@ "ERROR: --use-adaptors-monorepo was passed, but OPENFN_ADAPTORS_REPO env var is undefined" | ||
} | ||
await map_adaptors_to_monorepo_default(opts, logger); | ||
} else if (opts.adaptors && opts.expandAdaptors) { | ||
expand_adaptors_default(opts); | ||
await map_adaptors_to_monorepo_default( | ||
options, | ||
logger | ||
); | ||
} | ||
if (!/^(deploy|test|version)$/.test(opts.command) && !opts.repoDir) { | ||
if (!/^(pull|deploy|test|version)$/.test(options.command) && !options.repoDir) { | ||
logger.warn( | ||
@@ -1319,6 +1291,3 @@ "WARNING: no repo module dir found! Using the default (/tmp/repo)" | ||
} | ||
const handler = options.command ? handlers[options.command] : handler_default; | ||
if (!opts.command || /^(compile|execute)$/.test(opts.command)) { | ||
assertPath(basePath); | ||
} | ||
const handler = handlers[options.command]; | ||
if (!handler) { | ||
@@ -1329,4 +1298,3 @@ logger.error(`Unrecognised command: ${options.command}`); | ||
try { | ||
const result = await handler(opts, logger); | ||
return result; | ||
return await handler(options, logger); | ||
} catch (e) { | ||
@@ -1345,17 +1313,7 @@ if (!process.exitCode) { | ||
var commands_default = parse; | ||
var assertPath = (basePath) => { | ||
if (!basePath) { | ||
console.error("ERROR: no path provided!"); | ||
console.error("\nUsage:"); | ||
console.error(" open path/to/job"); | ||
console.error("\nFor more help do:"); | ||
console.error(" openfn --help "); | ||
process.exit(1); | ||
} | ||
}; | ||
// src/process/runner.ts | ||
process.on("message", ({ init, basePath, opts }) => { | ||
process.on("message", ({ init, opts }) => { | ||
if (init) { | ||
commands_default(basePath, opts).then(() => { | ||
commands_default(opts).then(() => { | ||
process.send({ done: true, exitCode: process.exitCode }); | ||
@@ -1362,0 +1320,0 @@ }); |
{ | ||
"name": "@openfn/cli", | ||
"version": "0.2.4", | ||
"version": "0.3.1", | ||
"description": "CLI devtools for the openfn toolchain.", | ||
@@ -29,12 +29,15 @@ "engines": { | ||
"@types/mock-fs": "^4.13.1", | ||
"@types/node": "^17.0.45", | ||
"@types/node": "^18.15.13", | ||
"@types/rimraf": "^3.0.2", | ||
"@types/treeify": "^1.0.0", | ||
"@types/yargs": "^17.0.24", | ||
"ava": "5.1.0", | ||
"ava": "5.3.1", | ||
"mock-fs": "^5.1.4", | ||
"ts-node": "^10.9.1", | ||
"tslib": "^2.4.0", | ||
"tsup": "^6.2.3", | ||
"typescript": "^4.7.4" | ||
"tsup": "^7.2.0", | ||
"typescript": "^5.1.6" | ||
}, | ||
"dependencies": { | ||
"@inquirer/prompts": "^1.1.4", | ||
"figures": "^5.0.0", | ||
@@ -44,7 +47,7 @@ "rimraf": "^3.0.2", | ||
"yargs": "^17.7.2", | ||
"@openfn/compiler": "0.0.34", | ||
"@openfn/deploy": "0.2.2", | ||
"@openfn/compiler": "0.0.35", | ||
"@openfn/deploy": "0.2.5", | ||
"@openfn/describe-package": "0.0.18", | ||
"@openfn/logger": "0.0.15", | ||
"@openfn/runtime": "0.0.28" | ||
"@openfn/logger": "0.0.16", | ||
"@openfn/runtime": "0.0.29" | ||
}, | ||
@@ -58,3 +61,3 @@ "files": [ | ||
"test:watch": "pnpm ava -w", | ||
"test:types": "pnpm tsc --noEmit --project tsconfig.json", | ||
"test:types": "pnpm tsc --project tsconfig.test.json", | ||
"build": "tsup --config ./tsup.config.js", | ||
@@ -61,0 +64,0 @@ "build:watch": "pnpm build --watch", |
@@ -228,3 +228,3 @@ # @openfn/cli | ||
To set the log level, pass `--log info` into your command. You can configure this for individual packages, ie `--log cmp=debug` will run the compiler with debug logging but leave everything else at default. | ||
To set the log level, pass `--log info` into your command. You can configure this for individual packages, ie `--log cmp=debug` will run the compiler with debug logging but leave everything else at default. To control multiple components, use comma-seperated values, ie, `--log debug,r/t=none,job=info` | ||
@@ -231,0 +231,0 @@ Note that, unless explicitly overriden, jobs will always report at debug verbosity (meaning job logging will always be shown). |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
70270
0.93%1933
2.01%12
-20%10
11.11%12
20%6
-14.29%+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated