@openfn/cli 0.0.19 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -57
- package/dist/index.js +38 -6
- package/dist/process/runner.js +193 -41
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,69 +1,101 @@
|
|
|
1
|
-
# @openfn/cli
|
|
1
|
+
# @openfn/cli
|
|
2
2
|
|
|
3
|
-
This package contains a new devtools CLI.
|
|
3
|
+
This package contains a new devtools CLI for running openfn jobs.
|
|
4
4
|
|
|
5
|
-
The CLI
|
|
5
|
+
The new CLI includes:
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
* A new runtime for executing openfn jobs
|
|
8
|
+
* A new compiler for making openfn jobs runnable
|
|
9
|
+
* Improved, customisable logging output
|
|
10
|
+
* Auto installation of language adaptors
|
|
11
|
+
* Support for the adaptors monorepo
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
## Getting Started
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
- If the path is a folder, the CLI will look for a job.js, state.json and write an output.json.
|
|
15
|
+
To install:
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
```
|
|
18
|
+
npm install -g @openfn/cli
|
|
19
|
+
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Make sure everything works by running the built-in test job:
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
```
|
|
24
|
+
openfn test
|
|
25
|
+
```
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
Check the version:
|
|
26
28
|
|
|
27
29
|
```
|
|
28
|
-
|
|
29
|
-
$ openfn --help
|
|
30
|
-
$ openfn path/to/expression.js`
|
|
30
|
+
openfn -v
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Get help:
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
```
|
|
36
|
+
openfn help
|
|
37
|
+
```
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
## Basic Usage
|
|
38
40
|
|
|
39
|
-
You
|
|
41
|
+
You're probably here to run jobs (expressions), which the CLI makes easy:
|
|
40
42
|
|
|
41
43
|
```
|
|
42
|
-
|
|
44
|
+
openfn path/to/job.js -ia adaptor-name
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
You
|
|
46
|
-
```
|
|
47
|
-
$ openfn job.js -a @openfn/language-commmon
|
|
48
|
-
```
|
|
47
|
+
You MUST specify which adaptor to use. Pass the `-i` flag to auto-install that adaptor (it's safe to do this redundantly).
|
|
49
48
|
|
|
50
|
-
You can pass
|
|
49
|
+
If output.json and state.json are not passed, the CLI will look for them next to the job.js file. You can pass a path to state by adding `-s path/to/state.json`, and output by passing `-o path/to/output.json`. You can use `-S` and `-O` to pass state through stdin and return the output through stdout.
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
$ openfn job.js -a commmon@1.7.3
|
|
54
|
-
```
|
|
51
|
+
The CLI can auto-install language adaptors to its own privately maintained repo. Run `openfn repo list` to see where the repo is, and what's in it. Set the `OPENFN_REPO_DIR` env var to specify the repo folder. When autoinstalling, the CLI will check to see if a matching version is found in the repo.
|
|
55
52
|
|
|
56
|
-
|
|
53
|
+
You can specify adaptors with a shorthand (`http`) or use the full package name (`@openfn/language-http`). You can add a specific version like `http@2.0.0`. You can pass a path to a locally installed adaptor like `http=/repo/openfn/adaptors/my-http-build`. Set the OPENFN_ADAPTORS_REPO env var to load adaptors straight out of the monorepo (pass the `--no-adaptors-repo` flag to disable this for a single run).
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
$ openfn install commmon
|
|
60
|
-
```
|
|
61
|
-
If no version is provided, the latest will be installed. Again, long and short-form names can be used.
|
|
55
|
+
You can pass `--log info` to get more feedback about what's happening, or `--log debug` for more details than you could ever use.
|
|
62
56
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
## Advanced Usage
|
|
58
|
+
|
|
59
|
+
The CLI has actually has a number of commands (the first argument after openfn)
|
|
60
|
+
|
|
61
|
+
* execute - run a job
|
|
62
|
+
* compile - compile a job to a .js file
|
|
63
|
+
* doc - show documentation for an adaptor function
|
|
64
|
+
* repo - manage the repo of installed modules
|
|
65
|
+
* docgen - generate JSON documentation for an adaptor based on its typescript
|
|
66
|
+
|
|
67
|
+
If no command is specified, execute will run.
|
|
68
|
+
|
|
69
|
+
To get more information about a command, including usage examples, run `openfn <command> help`, ie, `openfn compile help`.
|
|
70
|
+
|
|
71
|
+
## Compilation
|
|
72
|
+
|
|
73
|
+
The CLI will attempt to compile your job code into normalized Javascript. It will do a number of things to make your code robust and portable:
|
|
74
|
+
|
|
75
|
+
* The language adaptor will be imported into the file
|
|
76
|
+
* The adaptor's execute function will be exported form the file
|
|
77
|
+
* All top level operations will be added to an array
|
|
78
|
+
* That array will be made the default export of the file
|
|
79
|
+
|
|
80
|
+
The result of this is a lightweight, modern JS source file. It can be executed in any runtime environment: just execute each function in the exported array.
|
|
81
|
+
|
|
82
|
+
The CLI uses openfn's own runtime to execute jobs in a safe environment.
|
|
83
|
+
|
|
84
|
+
All jobs which work against `@openfn/core` will work in the new CLI and runtime environment (note: although this is a work in progress and we are actively looking for help to test this!).
|
|
85
|
+
|
|
86
|
+
## New Runtime notes
|
|
87
|
+
|
|
88
|
+
The new openfunction runtime basically does one thing: load a Javascript Module, find the default export, and execute the functions it holds.
|
|
89
|
+
|
|
90
|
+
So long as your job has an array of functions as its default export, it will run in the new runtime.
|
|
91
|
+
|
|
92
|
+
# Contributing
|
|
93
|
+
|
|
94
|
+
First of all, thanks for helping! You're contributing to a digital public good that will always be free and open source and aimed at serving innovative NGOs, governments, and social impact organizations the world over! You rock. heart
|
|
95
|
+
|
|
96
|
+
To get this started, you'll want to clone this repo.
|
|
97
|
+
|
|
98
|
+
You also need to install `pnpm`.
|
|
67
99
|
|
|
68
100
|
## Usage from this repo
|
|
69
101
|
|
|
@@ -78,7 +110,7 @@ See test/execute.test.ts for more usage examples
|
|
|
78
110
|
|
|
79
111
|
## Installing globally
|
|
80
112
|
|
|
81
|
-
To install the CLI globally from
|
|
113
|
+
To install the CLI globally from the build in repo:
|
|
82
114
|
|
|
83
115
|
```
|
|
84
116
|
$ npm install -g .
|
|
@@ -94,24 +126,15 @@ You should set the OPENFN_REPO_DIR env var to something sensible.
|
|
|
94
126
|
|
|
95
127
|
```
|
|
96
128
|
# In ~/.bashc or whatever
|
|
97
|
-
export OPENFN_REPO_DIR=~/
|
|
129
|
+
export OPENFN_REPO_DIR=~/repo/openfn/cli-repo
|
|
98
130
|
```
|
|
99
131
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
Monorepo support is coming soon.
|
|
132
|
+
To run adaptors straight from the adaptors monorepo:
|
|
103
133
|
|
|
104
|
-
|
|
134
|
+
export OPENFN_ADAPTORS_REPO=~/repo/openfn/adaptors
|
|
105
135
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
The v2 compiler can automatically insert import statements, but it needs to be told which adaptor to use.
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
$ openfn job.js --adaptors @openfn/language-http
|
|
112
|
-
$ openfn job.js --adaptors @openfn/language-http=path/to/adaptor
|
|
113
|
-
```
|
|
136
|
+
## Contributing changes
|
|
114
137
|
|
|
115
|
-
|
|
138
|
+
Open a PR at https://github.com/openfn/kit. Include a changeset and a description of your change.
|
|
116
139
|
|
|
117
|
-
|
|
140
|
+
See the root readme for more details about changests,
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import * as url from "url";
|
|
6
6
|
import { fork } from "node:child_process";
|
|
7
|
+
import process2 from "node:process";
|
|
7
8
|
function spawn_default(basePath, opts2) {
|
|
8
9
|
const execArgv = [
|
|
9
10
|
"--no-warnings",
|
|
@@ -12,13 +13,18 @@ function spawn_default(basePath, opts2) {
|
|
|
12
13
|
];
|
|
13
14
|
const dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
14
15
|
const child = fork(`${dirname}/process/runner.js`, [], { execArgv });
|
|
15
|
-
child.on("message", ({ done }) => {
|
|
16
|
+
child.on("message", ({ done, init, exitCode }) => {
|
|
17
|
+
if (init) {
|
|
18
|
+
child.send({ init: true, basePath, opts: opts2 });
|
|
19
|
+
}
|
|
16
20
|
if (done) {
|
|
17
21
|
child.kill();
|
|
18
|
-
|
|
22
|
+
process2.exit(exitCode);
|
|
19
23
|
}
|
|
20
24
|
});
|
|
21
|
-
child.
|
|
25
|
+
child.on("close", (code) => {
|
|
26
|
+
process2.exitCode = code;
|
|
27
|
+
});
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
// src/cli.ts
|
|
@@ -81,7 +87,7 @@ var list = {
|
|
|
81
87
|
// src/execute/command.ts
|
|
82
88
|
var executeCommand = {
|
|
83
89
|
command: "execute [path]",
|
|
84
|
-
desc:
|
|
90
|
+
desc: `Run an openfn job. Get more help by running openfn <command> help`,
|
|
85
91
|
aliases: ["$0"],
|
|
86
92
|
handler: (argv) => {
|
|
87
93
|
argv.command = "execute";
|
|
@@ -170,12 +176,38 @@ var command_default3 = {
|
|
|
170
176
|
}).example("test", "run the test script").example("test -S 42", "run the test script with state 42")
|
|
171
177
|
};
|
|
172
178
|
|
|
179
|
+
// src/docgen/command.ts
|
|
180
|
+
var docgenCommand = {
|
|
181
|
+
command: "docgen <specifier>",
|
|
182
|
+
desc: "Generate documentation into the repo. Specifier must include a version number.",
|
|
183
|
+
handler: (argv) => {
|
|
184
|
+
argv.command = "docgen";
|
|
185
|
+
},
|
|
186
|
+
builder: (yargs2) => {
|
|
187
|
+
return yargs2.example("docgen @openfn/language-common@1.7.5", "");
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
var command_default4 = docgenCommand;
|
|
191
|
+
|
|
192
|
+
// src/docs/command.ts
|
|
193
|
+
var command_default5 = {
|
|
194
|
+
command: "docs [adaptor] [operation]",
|
|
195
|
+
desc: "Print help for an adaptor function. You can use short-hand for adaptor names (ie, common instead of @openfn/language-common)",
|
|
196
|
+
handler: (argv) => {
|
|
197
|
+
argv.command = "docs";
|
|
198
|
+
},
|
|
199
|
+
builder: (yargs2) => yargs2.example("docs common fn", "Print help for the common fn operation")
|
|
200
|
+
};
|
|
201
|
+
|
|
173
202
|
// src/cli.ts
|
|
174
|
-
var cmd = yargs(hideBin(process.argv)).command(command_default).command(command_default2).command(install).command(repo).command(command_default3).option("log", {
|
|
203
|
+
var cmd = yargs(hideBin(process.argv)).command(command_default).command(command_default2).command(install).command(repo).command(command_default3).command(command_default5).command(command_default4).option("log", {
|
|
175
204
|
alias: ["l"],
|
|
176
205
|
description: "Set the default log level to none, default, info or debug",
|
|
177
206
|
array: true
|
|
178
|
-
}).
|
|
207
|
+
}).example("openfn execute help", "Show documentation for the execute command").example(
|
|
208
|
+
"openfn docs @openfn/language-common each",
|
|
209
|
+
"Get more help on the common.each command"
|
|
210
|
+
).alias("v", "version").help();
|
|
179
211
|
|
|
180
212
|
// src/index.ts
|
|
181
213
|
var opts = cmd.parse();
|
package/dist/process/runner.js
CHANGED
|
@@ -80,8 +80,10 @@ function ensureOpts(basePath = ".", opts) {
|
|
|
80
80
|
noCompile: Boolean(opts.noCompile),
|
|
81
81
|
expand: opts.expand !== false,
|
|
82
82
|
outputStdout: Boolean(opts.outputStdout),
|
|
83
|
+
operation: opts.operation,
|
|
83
84
|
packages: opts.packages,
|
|
84
85
|
stateStdin: opts.stateStdin,
|
|
86
|
+
specifier: opts.specifier,
|
|
85
87
|
strictOutput: opts.strictOutput ?? true,
|
|
86
88
|
immutable: opts.immutable || false
|
|
87
89
|
};
|
|
@@ -156,11 +158,11 @@ var execute_default = (code, state, opts) => {
|
|
|
156
158
|
function parseAdaptors(opts) {
|
|
157
159
|
const adaptors = {};
|
|
158
160
|
opts.adaptors.reduce((obj, exp) => {
|
|
159
|
-
const [module,
|
|
161
|
+
const [module, path3] = exp.split("=");
|
|
160
162
|
const { name, version } = getNameAndVersion(module);
|
|
161
163
|
const info = {};
|
|
162
|
-
if (
|
|
163
|
-
info.path =
|
|
164
|
+
if (path3) {
|
|
165
|
+
info.path = path3;
|
|
164
166
|
}
|
|
165
167
|
if (version) {
|
|
166
168
|
info.version = version;
|
|
@@ -202,10 +204,10 @@ var stripVersionSpecifier = (specifier) => {
|
|
|
202
204
|
return specifier;
|
|
203
205
|
};
|
|
204
206
|
var resolveSpecifierPath = async (pattern, repoDir, log) => {
|
|
205
|
-
const [specifier,
|
|
206
|
-
if (
|
|
207
|
-
log.debug(`Resolved ${specifier} to path: ${
|
|
208
|
-
return
|
|
207
|
+
const [specifier, path3] = pattern.split("=");
|
|
208
|
+
if (path3) {
|
|
209
|
+
log.debug(`Resolved ${specifier} to path: ${path3}`);
|
|
210
|
+
return path3;
|
|
209
211
|
}
|
|
210
212
|
const repoPath = await getModulePath(specifier, repoDir, log);
|
|
211
213
|
if (repoPath) {
|
|
@@ -223,15 +225,15 @@ var loadTransformOptions = async (opts, log) => {
|
|
|
223
225
|
const [pattern] = opts.adaptors;
|
|
224
226
|
const [specifier] = pattern.split("=");
|
|
225
227
|
log.debug(`Attempting to preload typedefs for ${specifier}`);
|
|
226
|
-
const
|
|
227
|
-
if (
|
|
228
|
+
const path3 = await resolveSpecifierPath(pattern, opts.repoDir, log);
|
|
229
|
+
if (path3) {
|
|
228
230
|
try {
|
|
229
|
-
exports = await preloadAdaptorExports(
|
|
231
|
+
exports = await preloadAdaptorExports(path3);
|
|
230
232
|
if (exports) {
|
|
231
233
|
log.info(`Loaded typedefs for ${specifier}`);
|
|
232
234
|
}
|
|
233
235
|
} catch (e) {
|
|
234
|
-
log.error(`Failed to load adaptor typedefs from path ${
|
|
236
|
+
log.error(`Failed to load adaptor typedefs from path ${path3}`);
|
|
235
237
|
log.error(e);
|
|
236
238
|
}
|
|
237
239
|
}
|
|
@@ -382,10 +384,17 @@ var executeHandler = async (options, logger) => {
|
|
|
382
384
|
}
|
|
383
385
|
const state = await load_state_default(options, logger);
|
|
384
386
|
const code = await compile_default(options, logger);
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
387
|
+
try {
|
|
388
|
+
const result = await execute_default(code, state, options);
|
|
389
|
+
await serialize_output_default(options, result, logger);
|
|
390
|
+
const duration = printDuration(new Date().getTime() - start);
|
|
391
|
+
logger.success(`Done in ${duration}! \u2728`);
|
|
392
|
+
} catch (error) {
|
|
393
|
+
logger.error(error);
|
|
394
|
+
const duration = printDuration(new Date().getTime() - start);
|
|
395
|
+
logger.error(`Took ${duration}.`);
|
|
396
|
+
process.exitCode = 1;
|
|
397
|
+
}
|
|
389
398
|
};
|
|
390
399
|
var handler_default = executeHandler;
|
|
391
400
|
|
|
@@ -424,7 +433,165 @@ var testHandler = async (options, logger) => {
|
|
|
424
433
|
};
|
|
425
434
|
var handler_default3 = testHandler;
|
|
426
435
|
|
|
436
|
+
// src/docgen/handler.ts
|
|
437
|
+
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
438
|
+
import { readFileSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
|
|
439
|
+
import path2 from "node:path";
|
|
440
|
+
import { describePackage } from "@openfn/describe-package";
|
|
441
|
+
import { getNameAndVersion as getNameAndVersion2 } from "@openfn/runtime";
|
|
442
|
+
var RETRY_DURATION = 500;
|
|
443
|
+
var RETRY_COUNT = 20;
|
|
444
|
+
var TIMEOUT_MS = 1e3 * 60;
|
|
445
|
+
var actualDocGen = (specifier) => describePackage(specifier, {});
|
|
446
|
+
var ensurePath = (filePath) => mkdirSync(path2.dirname(filePath), { recursive: true });
|
|
447
|
+
var generatePlaceholder = (path3) => {
|
|
448
|
+
writeFileSync(path3, `{ "loading": true, "timestamp": ${Date.now()}}`);
|
|
449
|
+
};
|
|
450
|
+
var finish = (logger, resultPath) => {
|
|
451
|
+
logger.success("Done! Docs can be found at:\n");
|
|
452
|
+
logger.print(` ${path2.resolve(resultPath)}`);
|
|
453
|
+
};
|
|
454
|
+
var generateDocs = async (specifier, path3, docgen, logger) => {
|
|
455
|
+
const result = await docgen(specifier);
|
|
456
|
+
await writeFile3(path3, JSON.stringify(result, null, 2));
|
|
457
|
+
finish(logger, path3);
|
|
458
|
+
return path3;
|
|
459
|
+
};
|
|
460
|
+
var waitForDocs = async (docs, path3, logger, retryDuration = RETRY_DURATION) => {
|
|
461
|
+
try {
|
|
462
|
+
if (docs.hasOwnProperty("loading")) {
|
|
463
|
+
logger.info("Docs are being loaded by another process. Waiting.");
|
|
464
|
+
return new Promise((resolve, reject) => {
|
|
465
|
+
let count = 0;
|
|
466
|
+
let i = setInterval(() => {
|
|
467
|
+
logger.info("Waiting..");
|
|
468
|
+
if (count > RETRY_COUNT) {
|
|
469
|
+
clearInterval(i);
|
|
470
|
+
reject(new Error("Timed out waiting for docs to load"));
|
|
471
|
+
}
|
|
472
|
+
const updated = JSON.parse(readFileSync(path3, "utf8"));
|
|
473
|
+
if (!updated.hasOwnProperty("loading")) {
|
|
474
|
+
logger.info("Docs found!");
|
|
475
|
+
clearInterval(i);
|
|
476
|
+
resolve(path3);
|
|
477
|
+
}
|
|
478
|
+
count++;
|
|
479
|
+
}, retryDuration);
|
|
480
|
+
});
|
|
481
|
+
} else {
|
|
482
|
+
logger.info(`Docs already written to cache at ${path3}`);
|
|
483
|
+
finish(logger, path3);
|
|
484
|
+
return path3;
|
|
485
|
+
}
|
|
486
|
+
} catch (e) {
|
|
487
|
+
logger.error("Existing doc JSON corrupt. Aborting");
|
|
488
|
+
throw e;
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
var docgenHandler = (options, logger, docgen = actualDocGen, retryDuration = RETRY_DURATION) => {
|
|
492
|
+
const { specifier, repoDir } = options;
|
|
493
|
+
const { version } = getNameAndVersion2(specifier);
|
|
494
|
+
if (!version) {
|
|
495
|
+
logger.error("Error: No version number detected");
|
|
496
|
+
logger.error("eg, @openfn/language-common@1.7.5");
|
|
497
|
+
logger.error("Aborting");
|
|
498
|
+
process.exit(9);
|
|
499
|
+
}
|
|
500
|
+
logger.success(`Generating docs for ${specifier}`);
|
|
501
|
+
const path3 = `${repoDir}/docs/${specifier}.json`;
|
|
502
|
+
ensurePath(path3);
|
|
503
|
+
const handleError = () => {
|
|
504
|
+
logger.info("Removing placeholder");
|
|
505
|
+
rmSync(path3);
|
|
506
|
+
};
|
|
507
|
+
try {
|
|
508
|
+
const existing = readFileSync(path3, "utf8");
|
|
509
|
+
const json = JSON.parse(existing);
|
|
510
|
+
if (json && json.timeout && Date.now() - json.timeout >= TIMEOUT_MS) {
|
|
511
|
+
logger.info(`Expired placeholder found. Removing.`);
|
|
512
|
+
rmSync(path3);
|
|
513
|
+
throw new Error("TIMEOUT");
|
|
514
|
+
}
|
|
515
|
+
return waitForDocs(json, path3, logger, retryDuration);
|
|
516
|
+
} catch (e) {
|
|
517
|
+
if (e.message !== "TIMEOUT") {
|
|
518
|
+
logger.info(`Docs JSON not found at ${path3}`);
|
|
519
|
+
}
|
|
520
|
+
logger.debug("Generating placeholder");
|
|
521
|
+
generatePlaceholder(path3);
|
|
522
|
+
return generateDocs(specifier, path3, docgen, logger).catch((e2) => {
|
|
523
|
+
logger.error("Error generating documentation");
|
|
524
|
+
logger.error(e2);
|
|
525
|
+
handleError();
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
var handler_default4 = docgenHandler;
|
|
530
|
+
|
|
531
|
+
// src/docs/handler.ts
|
|
532
|
+
import { readFile } from "node:fs/promises";
|
|
533
|
+
import { getNameAndVersion as getNameAndVersion3, getLatestVersion } from "@openfn/runtime";
|
|
534
|
+
var describe = (adaptorName, fn) => `## ${fn.name}(${fn.parameters.map(({ name }) => name).join(",")})
|
|
535
|
+
|
|
536
|
+
${fn.description}
|
|
537
|
+
|
|
538
|
+
### Usage Examples
|
|
539
|
+
|
|
540
|
+
${fn.examples.length ? fn.examples.map((eg) => eg).join("\n\n") : "None"}
|
|
541
|
+
|
|
542
|
+
### API Reference
|
|
543
|
+
|
|
544
|
+
https://docs.openfn.org/adaptors/packages/${adaptorName.replace(
|
|
545
|
+
"@openfn/language-",
|
|
546
|
+
""
|
|
547
|
+
)}-docs#${fn.name}
|
|
548
|
+
`;
|
|
549
|
+
var docsHandler = async (options, logger) => {
|
|
550
|
+
const { adaptor, operation, repoDir } = options;
|
|
551
|
+
const [adaptorName] = expand_adaptors_default([adaptor], logger);
|
|
552
|
+
let { name, version } = getNameAndVersion3(adaptorName);
|
|
553
|
+
if (!version) {
|
|
554
|
+
logger.info("No version number provided, looking for latest...");
|
|
555
|
+
version = await getLatestVersion(version);
|
|
556
|
+
logger.info("Found ", version);
|
|
557
|
+
logger.success(`Showing docs for ${adaptorName} v${version}`);
|
|
558
|
+
}
|
|
559
|
+
logger.info("Generating/loading documentation...");
|
|
560
|
+
const path3 = await handler_default4(
|
|
561
|
+
{
|
|
562
|
+
specifier: `${name}@${version}`,
|
|
563
|
+
repoDir
|
|
564
|
+
},
|
|
565
|
+
createNullLogger()
|
|
566
|
+
);
|
|
567
|
+
if (path3) {
|
|
568
|
+
const source = await readFile(path3, "utf8");
|
|
569
|
+
const data = JSON.parse(source);
|
|
570
|
+
const fn = data.functions.find(({ name: name2 }) => name2 === operation);
|
|
571
|
+
logger.debug("Operation schema:", fn);
|
|
572
|
+
logger.success(`Documentation for ${name}.${operation} v${version}:
|
|
573
|
+
`);
|
|
574
|
+
const desc = describe(name, fn);
|
|
575
|
+
logger.print(desc);
|
|
576
|
+
logger.success("Done!");
|
|
577
|
+
} else {
|
|
578
|
+
logger.error("Not found");
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
var handler_default5 = docsHandler;
|
|
582
|
+
|
|
427
583
|
// src/commands.ts
|
|
584
|
+
var handlers = {
|
|
585
|
+
execute: handler_default,
|
|
586
|
+
compile: handler_default2,
|
|
587
|
+
test: handler_default3,
|
|
588
|
+
docgen: handler_default4,
|
|
589
|
+
docs: handler_default5,
|
|
590
|
+
["repo-clean"]: clean,
|
|
591
|
+
["repo-install"]: install,
|
|
592
|
+
["repo-pwd"]: pwd,
|
|
593
|
+
["repo-list"]: list
|
|
594
|
+
};
|
|
428
595
|
var parse = async (basePath, options, log) => {
|
|
429
596
|
const opts = ensureOpts(basePath, options);
|
|
430
597
|
const logger = log || logger_default(CLI, opts);
|
|
@@ -439,31 +606,13 @@ var parse = async (basePath, options, log) => {
|
|
|
439
606
|
"You should set OPENFN_REPO_DIR or pass --repoDir=some/path in to the CLI"
|
|
440
607
|
);
|
|
441
608
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
break;
|
|
450
|
-
case "repo-pwd":
|
|
451
|
-
handler = pwd;
|
|
452
|
-
break;
|
|
453
|
-
case "repo-list":
|
|
454
|
-
handler = list;
|
|
455
|
-
break;
|
|
456
|
-
case "compile":
|
|
457
|
-
assertPath(basePath);
|
|
458
|
-
handler = handler_default2;
|
|
459
|
-
break;
|
|
460
|
-
case "test":
|
|
461
|
-
handler = handler_default3;
|
|
462
|
-
break;
|
|
463
|
-
case "execute":
|
|
464
|
-
default:
|
|
465
|
-
assertPath(basePath);
|
|
466
|
-
handler = handler_default;
|
|
609
|
+
const handler = options.command ? handlers[options.command] : handler_default;
|
|
610
|
+
if (!opts.command || /^(compile|execute)$/.test(opts.command)) {
|
|
611
|
+
assertPath(basePath);
|
|
612
|
+
}
|
|
613
|
+
if (!handler) {
|
|
614
|
+
logger.error(`Unrecognise command: ${options.command}`);
|
|
615
|
+
process.exit(1);
|
|
467
616
|
}
|
|
468
617
|
return handler(opts, logger);
|
|
469
618
|
};
|
|
@@ -483,7 +632,10 @@ var assertPath = (basePath) => {
|
|
|
483
632
|
process.on("message", ({ init, basePath, opts }) => {
|
|
484
633
|
if (init) {
|
|
485
634
|
commands_default(basePath, opts).then(() => {
|
|
486
|
-
process.send({ done: true });
|
|
635
|
+
process.send({ done: true, exitCode: process.exitCode });
|
|
487
636
|
});
|
|
488
637
|
}
|
|
489
638
|
});
|
|
639
|
+
process.send({
|
|
640
|
+
init: true
|
|
641
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"description": "CLI devtools for the openfn toolchain.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=16",
|
|
@@ -30,15 +30,16 @@
|
|
|
30
30
|
"@types/yargs": "^17.0.12",
|
|
31
31
|
"ava": "5.1.0",
|
|
32
32
|
"mock-fs": "^5.1.4",
|
|
33
|
-
"ts-node": "^10.
|
|
33
|
+
"ts-node": "^10.9.1",
|
|
34
34
|
"tslib": "^2.4.0",
|
|
35
35
|
"tsup": "^6.2.3",
|
|
36
36
|
"typescript": "^4.7.4"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@openfn/compiler": "^0.0.
|
|
40
|
-
"@openfn/
|
|
41
|
-
"@openfn/
|
|
39
|
+
"@openfn/compiler": "^0.0.19",
|
|
40
|
+
"@openfn/describe-package": "^0.0.11",
|
|
41
|
+
"@openfn/logger": "^0.0.8",
|
|
42
|
+
"@openfn/runtime": "^0.0.13",
|
|
42
43
|
"fast-safe-stringify": "^2.1.1",
|
|
43
44
|
"rimraf": "^3.0.2",
|
|
44
45
|
"treeify": "^1.1.0",
|