zorb 0.0.1-alpha.0 → 0.0.3
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/dist/runners/run.cjs +59 -0
- package/dist/runners/run.mjs +61 -0
- package/dist/runners/run.py +31 -0
- package/dist/runners/run.ts +60 -0
- package/dist/zorb +0 -0
- package/package.json +13 -24
- package/.editorconfig +0 -9
- package/README.md +0 -3
- package/bin.js +0 -74
- package/index.js +0 -11
- package/lib/context.js +0 -35
- package/lib/files.js +0 -50
- package/lib/logger.js +0 -27
- package/lib/runner.js +0 -50
- package/lib/schemas.js +0 -56
- package/lib/utils.js +0 -66
- package/steps/run.js +0 -43
- package/steps/use.js +0 -38
- package/types.d.ts +0 -13
- package/zorb.yml +0 -16
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file should not be bundled into Deno - it's a Javascript wrapper to load a file & run a function
|
|
3
|
+
*/
|
|
4
|
+
// deno-lint-ignore-file no-process-global
|
|
5
|
+
const { resolve } = require("node:path");
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
// node run.cjs <modulePath> <symbol> <inputsJson>
|
|
9
|
+
const [, , modulePath, symbol, inputsJson = "{}"] = process.argv;
|
|
10
|
+
|
|
11
|
+
if (!modulePath || !symbol) {
|
|
12
|
+
console.error(
|
|
13
|
+
"Usage: node run.cjs <modulePath> <symbol> <inputsJson> <ctxJson>",
|
|
14
|
+
);
|
|
15
|
+
process.exit(2);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let inputs;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
inputs = JSON.parse(inputsJson);
|
|
22
|
+
} catch {
|
|
23
|
+
console.error("Invalid inputs JSON");
|
|
24
|
+
process.exit(2);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Resolve to absolute path so require() is deterministic
|
|
28
|
+
const absPath = resolve(modulePath);
|
|
29
|
+
|
|
30
|
+
let mod;
|
|
31
|
+
try {
|
|
32
|
+
mod = require(absPath);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(`Failed to import ${absPath}`);
|
|
35
|
+
console.error(err);
|
|
36
|
+
process.exit(3);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const fn = mod[symbol];
|
|
40
|
+
if (typeof fn !== "function") {
|
|
41
|
+
console.error(`Export "${symbol}" is not a function in ${absPath}`);
|
|
42
|
+
process.exit(4);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const result = fn(inputs);
|
|
47
|
+
if (result && typeof result.then === "function") {
|
|
48
|
+
await result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
process.exit(0);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
console.error(`Error running ${symbol} from ${absPath}`);
|
|
54
|
+
console.error(err);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
main();
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file should not be bundled into Deno - it's a Javascript wrapper to load a file & run a function
|
|
3
|
+
*/
|
|
4
|
+
// deno-lint-ignore-file no-process-global
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import { resolve } from "node:path";
|
|
7
|
+
|
|
8
|
+
async function main() {
|
|
9
|
+
// node run.mjs <modulePath> <symbol> <inputsJson>
|
|
10
|
+
const [, , modulePath, symbol, inputsJson = "{}"] = process.argv;
|
|
11
|
+
|
|
12
|
+
if (!modulePath || !symbol) {
|
|
13
|
+
console.error(
|
|
14
|
+
"Usage: node run.mjs <modulePath> <symbol> <inputsJson> <ctxJson>",
|
|
15
|
+
);
|
|
16
|
+
process.exit(2);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let inputs;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
inputs = JSON.parse(inputsJson);
|
|
23
|
+
} catch {
|
|
24
|
+
console.error("Invalid inputs JSON");
|
|
25
|
+
process.exit(2);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Resolve to absolute path so import() is deterministic
|
|
29
|
+
const absPath = resolve(modulePath);
|
|
30
|
+
const { href: moduleUrl } = pathToFileURL(absPath);
|
|
31
|
+
|
|
32
|
+
let mod;
|
|
33
|
+
try {
|
|
34
|
+
mod = await import(moduleUrl);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error(`Failed to import ${absPath}`);
|
|
37
|
+
console.error(err);
|
|
38
|
+
process.exit(3);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const fn = mod[symbol];
|
|
42
|
+
if (typeof fn !== "function") {
|
|
43
|
+
console.error(`Export "${symbol}" is not a function in ${absPath}`);
|
|
44
|
+
process.exit(4);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const result = fn(inputs);
|
|
49
|
+
if (result && typeof result.then === "function") {
|
|
50
|
+
await result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
process.exit(0);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
console.error(`Error running ${symbol} from ${absPath}`);
|
|
56
|
+
console.error(err);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
main();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Usage: python run.py <modulePath> <symbol> <inputsJson>
|
|
2
|
+
import importlib.util, json, sys, traceback
|
|
3
|
+
|
|
4
|
+
if len(sys.argv) < 3:
|
|
5
|
+
print("Usage: run.py <modulePath> <symbol> <inputsJson>", file=sys.stderr)
|
|
6
|
+
sys.exit(2)
|
|
7
|
+
|
|
8
|
+
module_path = sys.argv[1]
|
|
9
|
+
symbol = sys.argv[2]
|
|
10
|
+
inputs = json.loads(sys.argv[3]) if len(sys.argv) > 3 else {}
|
|
11
|
+
|
|
12
|
+
spec = importlib.util.spec_from_file_location("zorb_user_module", module_path)
|
|
13
|
+
if spec is None or spec.loader is None:
|
|
14
|
+
print(f"Failed to load module from {module_path}", file=sys.stderr)
|
|
15
|
+
sys.exit(3)
|
|
16
|
+
|
|
17
|
+
mod = importlib.util.module_from_spec(spec)
|
|
18
|
+
spec.loader.exec_module(mod)
|
|
19
|
+
|
|
20
|
+
fn = getattr(mod, symbol, None)
|
|
21
|
+
if not callable(fn):
|
|
22
|
+
print(f'Symbol "{symbol}" is not callable in {module_path}', file=sys.stderr)
|
|
23
|
+
sys.exit(4)
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
res = fn(inputs)
|
|
27
|
+
# If you want async python support, you can detect coroutine and run it.
|
|
28
|
+
sys.exit(0)
|
|
29
|
+
except Exception:
|
|
30
|
+
traceback.print_exc()
|
|
31
|
+
sys.exit(1)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file should not be bundled into Deno - it's a Typescript wrapper to load a file & run a function
|
|
3
|
+
*/
|
|
4
|
+
// deno-lint-ignore-file no-process-global
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
import { resolve } from 'node:path';
|
|
7
|
+
|
|
8
|
+
async function main() {
|
|
9
|
+
// tsx run.ts <modulePath> <symbol> <inputsJson>
|
|
10
|
+
const [, , modulePath, symbol, inputsJson = '{}'] = process.argv;
|
|
11
|
+
|
|
12
|
+
if (!modulePath || !symbol) {
|
|
13
|
+
console.error('Usage: tsx run.ts <modulePath> <symbol> <inputsJson> <ctxJson>');
|
|
14
|
+
process.exit(2);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let inputs: unknown;
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
inputs = JSON.parse(inputsJson);
|
|
21
|
+
} catch {
|
|
22
|
+
console.error('Invalid inputs JSON');
|
|
23
|
+
process.exit(2);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Resolve to absolute path so import() is deterministic
|
|
27
|
+
const absPath = resolve(modulePath);
|
|
28
|
+
const { href: moduleUrl } = pathToFileURL(absPath);
|
|
29
|
+
|
|
30
|
+
let mod: Record<string, unknown>;
|
|
31
|
+
try {
|
|
32
|
+
mod = await import(moduleUrl);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(`Failed to import ${absPath}`);
|
|
35
|
+
console.error(err);
|
|
36
|
+
process.exit(3);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const fn = mod![symbol];
|
|
40
|
+
if (typeof fn !== 'function') {
|
|
41
|
+
console.error(`Export "${symbol}" is not a function in ${absPath}`);
|
|
42
|
+
process.exit(4);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
// deno-lint-ignore no-explicit-any
|
|
47
|
+
const result = (fn as any)(inputs);
|
|
48
|
+
if (result && typeof result.then === 'function') {
|
|
49
|
+
await result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
process.exit(0);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.error(`Error running ${symbol} from ${absPath}`);
|
|
55
|
+
console.error(err);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
main();
|
package/dist/zorb
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,30 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zorb",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Standalone workflow runner",
|
|
5
|
+
"bin": {
|
|
6
|
+
"zorb": "dist/zorb"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
9
|
-
"types": "./types.d.ts",
|
|
10
|
-
"bin": "./bin.js",
|
|
11
|
-
"author": "James D <james@jdrydn.com> (https://jdrydn.com)",
|
|
8
|
+
"author": "jdrydn <james@jdrydn.com> (https://jdrydn.com)",
|
|
12
9
|
"license": "MIT",
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"@someimportantcompany/utils": "^1.3.1",
|
|
18
|
-
"http-assert-plus": "^2.0.1",
|
|
19
|
-
"yaml": "^2.3.4",
|
|
20
|
-
"yargs": "^17.7.2",
|
|
21
|
-
"yup": "^1.3.3"
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/jdrydn/zorb.git"
|
|
22
13
|
},
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"npm": ">7"
|
|
29
|
-
}
|
|
14
|
+
"bugs": "https://github.com/jdrydn/zorb/issues",
|
|
15
|
+
"homepage": "https://github.com/jdrydn/zorb",
|
|
16
|
+
"files": [
|
|
17
|
+
"./dist"
|
|
18
|
+
]
|
|
30
19
|
}
|
package/.editorconfig
DELETED
package/README.md
DELETED
package/bin.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
const yargs = require('yargs');
|
|
2
|
-
const { hideBin } = require('yargs/helpers');
|
|
3
|
-
|
|
4
|
-
const { runWorkflow } = require('./lib/runner');
|
|
5
|
-
const { validateSchemaFile } = require('./lib/schemas');
|
|
6
|
-
|
|
7
|
-
const { loadFile } = require('./lib/files');
|
|
8
|
-
const { createLogger } = require('./lib/logger');
|
|
9
|
-
|
|
10
|
-
const parser = yargs(hideBin(process.argv))
|
|
11
|
-
.count('verbose')
|
|
12
|
-
.alias('v', 'verbose')
|
|
13
|
-
.option('cwd', {
|
|
14
|
-
type: 'string',
|
|
15
|
-
default: process.env.PWD ?? '/',
|
|
16
|
-
})
|
|
17
|
-
.command('run <script>', 'run the specific script', args => args
|
|
18
|
-
.option('file', {
|
|
19
|
-
type: 'string',
|
|
20
|
-
default: 'zorb.yml',
|
|
21
|
-
alias: 'f',
|
|
22
|
-
})
|
|
23
|
-
.option('with', {
|
|
24
|
-
type: 'array',
|
|
25
|
-
coerce: args => Object.fromEntries(args.map(a => a.split('='))),
|
|
26
|
-
})
|
|
27
|
-
.positional('script', {}))
|
|
28
|
-
.command('use <package>', 'run the specific package', args => args
|
|
29
|
-
.option('with', {
|
|
30
|
-
type: 'array',
|
|
31
|
-
coerce: args => Object.fromEntries(args.map(a => a.split('='))),
|
|
32
|
-
})
|
|
33
|
-
.positional('package', {}))
|
|
34
|
-
.demandCommand(1);
|
|
35
|
-
|
|
36
|
-
(async () => {
|
|
37
|
-
try {
|
|
38
|
-
const args = await parser.parseAsync();
|
|
39
|
-
const log = (args.verbose > 0) ? createLogger(args.verbose) : undefined;
|
|
40
|
-
log?.debug({ args });
|
|
41
|
-
|
|
42
|
-
switch (args._.shift()) {
|
|
43
|
-
case 'run':
|
|
44
|
-
const file = await loadFile(args.cwd, args.file);
|
|
45
|
-
const config = validateSchemaFile(file);
|
|
46
|
-
log?.debug({ config });
|
|
47
|
-
// @TODO Resolve variables within the config script
|
|
48
|
-
await runWorkflow({ cwd: args.cwd, log }, config, args.script, args.with);
|
|
49
|
-
break;
|
|
50
|
-
|
|
51
|
-
case 'use':
|
|
52
|
-
// @TODO Resolve variables within the config script
|
|
53
|
-
await runWorkflow({
|
|
54
|
-
cwd: args.cwd,
|
|
55
|
-
log,
|
|
56
|
-
}, {
|
|
57
|
-
scripts: {
|
|
58
|
-
'0': {
|
|
59
|
-
steps: [
|
|
60
|
-
{ uses: args.package, with: args.with ? args.with : undefined },
|
|
61
|
-
],
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
}, '0');
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
log?.debug('Finished');
|
|
69
|
-
process.exit(0);
|
|
70
|
-
} catch (err) {
|
|
71
|
-
console.error(err);
|
|
72
|
-
process.exit(1);
|
|
73
|
-
}
|
|
74
|
-
})();
|
package/index.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const { runWorkflow } = require('./lib/runner');
|
|
2
|
-
const { validateSchemaFile } = require('./lib/schemas');
|
|
3
|
-
|
|
4
|
-
module.exports = function zorb(input, { log }) {
|
|
5
|
-
const config = validateSchemaFile(input);
|
|
6
|
-
|
|
7
|
-
return Object.keys(config.scripts).reduce((fns, key) => ({
|
|
8
|
-
...fns,
|
|
9
|
-
[key]: () => runWorkflow({ cwd: args.cwd, log }, config, args.script),
|
|
10
|
-
}), {});
|
|
11
|
-
};
|
package/lib/context.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param {Partial<import('../types').ZorbContext>} ctx
|
|
3
|
-
* @param {Nullable<import('../types').ZorbContext['cwd']>} ctx.cwd
|
|
4
|
-
* @param {Nullable<import('../types').ZorbContext['env']>} ctx.env
|
|
5
|
-
* @param {Nullable<import('../types').ZorbContext['log']>} ctx.log
|
|
6
|
-
* @returns {import('../types').ZorbContext}
|
|
7
|
-
*/
|
|
8
|
-
function createContext({ cwd, env, log }) {
|
|
9
|
-
return Object.create({}, {
|
|
10
|
-
cwd: {
|
|
11
|
-
enumerable: true,
|
|
12
|
-
value: cwd ?? process.env.PWD,
|
|
13
|
-
},
|
|
14
|
-
env: {
|
|
15
|
-
enumerable: true,
|
|
16
|
-
value: { ...env },
|
|
17
|
-
},
|
|
18
|
-
log: {
|
|
19
|
-
enumerable: true,
|
|
20
|
-
get: () => log,
|
|
21
|
-
},
|
|
22
|
-
output: {
|
|
23
|
-
enumerable: true,
|
|
24
|
-
value: {},
|
|
25
|
-
},
|
|
26
|
-
// state: {
|
|
27
|
-
// enumerable: true,
|
|
28
|
-
// value: {},
|
|
29
|
-
// },
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
module.exports = {
|
|
34
|
-
createContext,
|
|
35
|
-
};
|
package/lib/files.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
const assert = require('http-assert-plus');
|
|
2
|
-
const fs = require('fs/promises');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const yaml = require('yaml');
|
|
5
|
-
|
|
6
|
-
const { tryCatch } = require('./utils');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @param {string} dirname
|
|
10
|
-
* @param {string} filename
|
|
11
|
-
* @returns {Promise<Record<string, any>>}
|
|
12
|
-
*/
|
|
13
|
-
async function loadFile(dirname, filename) {
|
|
14
|
-
assert(typeof dirname === 'string', new TypeError('Expected dirname to be a string'));
|
|
15
|
-
assert(typeof filename === 'string', new TypeError('Expected filename to be a string'));
|
|
16
|
-
|
|
17
|
-
const contents = await fs.readFile(path.resolve(dirname, filename), 'utf8').catch(err => {
|
|
18
|
-
let prefix = `Failed to read file at ${path.resolve(dirname, filename)}`;
|
|
19
|
-
// @TODO Change prefix based on fs err code
|
|
20
|
-
err.message = `${prefix}: ${err.message}`;
|
|
21
|
-
throw err;
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
// let parsed;
|
|
25
|
-
|
|
26
|
-
switch (path.extname(filename)) {
|
|
27
|
-
case '.json': {
|
|
28
|
-
return tryCatch(() => JSON.parse(contents), err => {
|
|
29
|
-
// @TODO Change prefix based on JSON.parse err code
|
|
30
|
-
err.message = `Failed to parse JSON file: ${err.message}`;
|
|
31
|
-
throw err;
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
case '.yaml': case '.yml': {
|
|
36
|
-
return tryCatch(() => yaml.parse(contents), err => {
|
|
37
|
-
// @TODO Change prefix based on yaml.parse err code
|
|
38
|
-
err.message = `Failed to parse YAML file: ${err.message}`;
|
|
39
|
-
throw err;
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
default:
|
|
44
|
-
throw new Error(`Unknown file extension: ${filename}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
module.exports = {
|
|
49
|
-
loadFile,
|
|
50
|
-
};
|
package/lib/logger.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
function createLogLevel(prefix) {
|
|
2
|
-
return function (first, ...rest) {
|
|
3
|
-
if (typeof first === 'string') {
|
|
4
|
-
console.log(prefix, (new Date()).toISOString(), first, ...rest);
|
|
5
|
-
} else {
|
|
6
|
-
console.log(prefix, (new Date()).toISOString(), first);
|
|
7
|
-
if (rest.length) {
|
|
8
|
-
console.log(prefix, (new Date()).toISOString(), first, ...rest);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const noop = () => {};
|
|
15
|
-
|
|
16
|
-
function createLogger(verbose) {
|
|
17
|
-
return {
|
|
18
|
-
error: createLogLevel('[ERROR]'),
|
|
19
|
-
warn: createLogLevel('[WARN] '),
|
|
20
|
-
info: verbose >= 1 ? createLogLevel('[INFO] ') : noop,
|
|
21
|
-
debug: verbose > 1 ? createLogLevel('[DEBUG]') : noop,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
module.exports = {
|
|
26
|
-
createLogger,
|
|
27
|
-
};
|
package/lib/runner.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
const assert = require('http-assert-plus');
|
|
2
|
-
|
|
3
|
-
const { createContext } = require('./context');
|
|
4
|
-
|
|
5
|
-
const { runShellStep } = require('../steps/run');
|
|
6
|
-
const { runActionStep, loadActionSteps } = require('../steps/use');
|
|
7
|
-
|
|
8
|
-
// Given a valid runner file
|
|
9
|
-
// And some instruction
|
|
10
|
-
// Complete the steps at hand
|
|
11
|
-
|
|
12
|
-
async function runWorkflow({ cwd, log }, config, handle) {
|
|
13
|
-
assert(config.scripts?.[handle], 'Script not found', {
|
|
14
|
-
code: 'SCRIPT_NOT_FOUND',
|
|
15
|
-
meta: { handle },
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const { [handle]: script } = config.scripts;
|
|
19
|
-
|
|
20
|
-
assert(Array.isArray(script.steps), 'No steps found for script', {
|
|
21
|
-
code: 'SCRIPT_STEPS_NOT_FOUND',
|
|
22
|
-
meta: { handle },
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const ctx = createContext({
|
|
26
|
-
cwd: typeof script.defaults?.run?.cwd === 'string'
|
|
27
|
-
? script.defaults.run.cwd
|
|
28
|
-
: process.env.PWD,
|
|
29
|
-
env: { ...config.env, ...script.defaults?.run?.env, ...script.env },
|
|
30
|
-
log
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
loadActionSteps({ cwd, log }, script.steps
|
|
34
|
-
.filter(step => typeof step.uses === 'string')
|
|
35
|
-
.map(step => step.uses));
|
|
36
|
-
|
|
37
|
-
for (const step of script.steps) {
|
|
38
|
-
log?.info({ step }, '@zorb/run step');
|
|
39
|
-
|
|
40
|
-
if (typeof step.uses === 'string') {
|
|
41
|
-
await runActionStep(ctx, step, script);
|
|
42
|
-
} else if (typeof step.run === 'string') {
|
|
43
|
-
await runShellStep(ctx, step, script);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
module.exports = {
|
|
49
|
-
runWorkflow,
|
|
50
|
-
};
|
package/lib/schemas.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const yup = require('yup');
|
|
2
|
-
|
|
3
|
-
function dynamicObject(value) {
|
|
4
|
-
return yup.lazy(map => yup.object((map ? Object.keys(map) : [])
|
|
5
|
-
.reduce((newMap, key) => ({...newMap, [key]: value}), {})));
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const runnerActionStep = module.exports.runnerActionStep = yup.object().noUnknown(true).shape({
|
|
9
|
-
uses: yup.string().required(),
|
|
10
|
-
with: yup.object(),
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
// const runnerCodeStep = module.exports.runnerCodeStep = yup.object().noUnknown(true).shape({
|
|
14
|
-
// code: yup.string().required(),
|
|
15
|
-
// with: yup.object(),
|
|
16
|
-
// });
|
|
17
|
-
|
|
18
|
-
const runnerShellStep = module.exports.runnerShellStep = yup.object().noUnknown(true).shape({
|
|
19
|
-
run: yup.string().required(),
|
|
20
|
-
cwd: yup.string(),
|
|
21
|
-
env: dynamicObject(yup.string()),
|
|
22
|
-
shell: yup.string(),
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const runnerScriptSchema = module.exports.runnerScriptSchema = yup.object().noUnknown(true).shape({
|
|
26
|
-
env: dynamicObject(yup.string()),
|
|
27
|
-
defaults: yup.object(),
|
|
28
|
-
steps: yup.array().required().min(1).of(yup.lazy(o => {
|
|
29
|
-
if (o && typeof o.uses === 'string') {
|
|
30
|
-
return runnerActionStep.clone();
|
|
31
|
-
} else {
|
|
32
|
-
return runnerShellStep.clone();
|
|
33
|
-
}
|
|
34
|
-
})),
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const runnerFileSchema = module.exports.runnerFileSchema = yup.object().required().shape({
|
|
38
|
-
version: yup.string().oneOf(['1']),
|
|
39
|
-
env: dynamicObject(yup.string()),
|
|
40
|
-
params: yup.object(),
|
|
41
|
-
scripts: dynamicObject(runnerScriptSchema),
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @param {Record<string, any>} input
|
|
46
|
-
* @returns {NonNullable<ReturnType<typeof runnerFileSchema.cast>>}
|
|
47
|
-
*/
|
|
48
|
-
function validateSchemaFile(input) {
|
|
49
|
-
return runnerFileSchema.validateSync(input, {
|
|
50
|
-
abortEarly: false,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
module.exports = {
|
|
55
|
-
validateSchemaFile,
|
|
56
|
-
};
|
package/lib/utils.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
const { assert } = require('@someimportantcompany/utils');
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @param {string} str
|
|
5
|
-
* @param {string|number} split
|
|
6
|
-
* @param {boolean} first
|
|
7
|
-
* @returns {[string, string | undefined]}
|
|
8
|
-
*/
|
|
9
|
-
function splitOnIndex(str, split, first = true) {
|
|
10
|
-
assert(typeof str === 'string', new TypeError('Expected first argument to be a string'));
|
|
11
|
-
assert(['string', 'number'].includes(typeof split), new TypeError('Expected second argument to be a string or number'));
|
|
12
|
-
assert(typeof first === 'boolean', new TypeError('Expected third argument to be a boolean'));
|
|
13
|
-
|
|
14
|
-
if (typeof split === 'string') {
|
|
15
|
-
split = first ? str.indexOf(split) : str.lastIndexOf(split);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return split >= 0 ? [str.slice(0, split), str.slice(split + 1)] : [str, undefined];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @template T
|
|
23
|
-
* @param {() => T} fn
|
|
24
|
-
* @param {*} [err]
|
|
25
|
-
* @returns {T}
|
|
26
|
-
|
|
27
|
-
* @template T
|
|
28
|
-
* @param {() => Promise<T>} fn
|
|
29
|
-
* @param {*} [err]
|
|
30
|
-
* @returns {Promise<T>}
|
|
31
|
-
|
|
32
|
-
* @template T
|
|
33
|
-
* @param {(() => T) | (() => Promise<T>)} fn
|
|
34
|
-
* @param {*} [err]
|
|
35
|
-
* @returns {T | Promise<T>}
|
|
36
|
-
*/
|
|
37
|
-
function tryCatch(fn, err) {
|
|
38
|
-
try {
|
|
39
|
-
const r = fn();
|
|
40
|
-
// If the function return a Promise-like result
|
|
41
|
-
if (r instanceof Promise) {
|
|
42
|
-
// Then wrap the promise to protect against errors
|
|
43
|
-
return r.catch((e) => {
|
|
44
|
-
if (typeof err === 'function') {
|
|
45
|
-
return err(e);
|
|
46
|
-
} else {
|
|
47
|
-
throw e;
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
} else {
|
|
51
|
-
// Otherwise, return the raw value returned from the function
|
|
52
|
-
return r;
|
|
53
|
-
}
|
|
54
|
-
} catch (e) {
|
|
55
|
-
if (typeof err === 'function') {
|
|
56
|
-
return err(e);
|
|
57
|
-
} else {
|
|
58
|
-
throw e;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
module.exports = {
|
|
64
|
-
splitOnIndex,
|
|
65
|
-
tryCatch,
|
|
66
|
-
};
|
package/steps/run.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
const assert = require('http-assert-plus');
|
|
2
|
-
const childProcess = require('child_process');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param {import('../types').ZorbContext} ctx
|
|
7
|
-
* @param {Object} step
|
|
8
|
-
* @param {string} step.run
|
|
9
|
-
* @param {Object} script
|
|
10
|
-
* @returns {number|undefined}
|
|
11
|
-
*/
|
|
12
|
-
function runShellStep(ctx, step, script) {
|
|
13
|
-
assert(typeof step.run === 'string', new TypeError('Expected $.run to be a string'));
|
|
14
|
-
|
|
15
|
-
const cwd = typeof step.cwd === 'string' ? path.resolve(ctx.cwd, step.cwd) : ctx.cwd;
|
|
16
|
-
|
|
17
|
-
const env = {
|
|
18
|
-
...script.env,
|
|
19
|
-
...script.defaults?.run?.env,
|
|
20
|
-
...step.env,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const shell = step.shell ?? script.defaults?.run?.shell ?? undefined;
|
|
24
|
-
|
|
25
|
-
return new Promise((resolve, reject) => {
|
|
26
|
-
ctx.log?.debug({ run: step.run, opts: { cwd, env, shell } });
|
|
27
|
-
|
|
28
|
-
const child = childProcess.exec(step.run, { cwd, env, shell });
|
|
29
|
-
|
|
30
|
-
child.stdout.setEncoding('utf8');
|
|
31
|
-
child.stdout.on('data', data => process.stdout.write(data));
|
|
32
|
-
|
|
33
|
-
child.stderr.setEncoding('utf8');
|
|
34
|
-
child.stderr.on('data', data => process.stderr.write(data));
|
|
35
|
-
|
|
36
|
-
child.on('close', code => resolve(code ?? undefined));
|
|
37
|
-
child.on('err', err => reject(err));
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
module.exports = {
|
|
42
|
-
runShellStep,
|
|
43
|
-
};
|
package/steps/use.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const { assert } = require('@someimportantcompany/utils');
|
|
3
|
-
|
|
4
|
-
const { tryCatch } = require('../lib/utils');
|
|
5
|
-
|
|
6
|
-
const actions = new Map();
|
|
7
|
-
|
|
8
|
-
function loadActionSteps(ctx, usesList) {
|
|
9
|
-
for (const useName of usesList) {
|
|
10
|
-
const functionName = path.extname(useName);
|
|
11
|
-
const fileName = functionName ? useName.substring(0, useName.length - functionName.length) : useName;
|
|
12
|
-
|
|
13
|
-
const requireName = tryCatch(() => require.resolve(fileName), () => null)
|
|
14
|
-
?? tryCatch(() => require.resolve(path.resolve(ctx.cwd, fileName)), () => null)
|
|
15
|
-
?? fileName;
|
|
16
|
-
|
|
17
|
-
const mod = require(requireName);
|
|
18
|
-
const handler = functionName ? mod[functionName] : mod;
|
|
19
|
-
assert(typeof handler === 'function', new TypeError('Expected handler to be a function'));
|
|
20
|
-
actions.set(useName, {
|
|
21
|
-
handler,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
ctx.log?.debug({ name: '@zorb/core', use: Array.from(actions.keys()) }, 'Loaded actions');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function runActionStep(ctx, step) {
|
|
29
|
-
assert(typeof step.uses === 'string', new TypeError('Expected $.uses to be a string'));
|
|
30
|
-
const { handler } = actions.get(step.uses) || {};
|
|
31
|
-
assert(typeof handler === 'function', new Error('Expected use handler to be a function'));
|
|
32
|
-
return handler(ctx, step.with ?? undefined);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
module.exports = {
|
|
36
|
-
loadActionSteps,
|
|
37
|
-
runActionStep,
|
|
38
|
-
};
|
package/types.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export interface ZorbContext {
|
|
2
|
-
cwd: string,
|
|
3
|
-
env: Record<string, string | undefined>,
|
|
4
|
-
log?: Record<'debug' | 'info' | 'warn' | 'error',
|
|
5
|
-
((msg: string) => void) |
|
|
6
|
-
((args: Record<string, any>, msg: string) => void)>,
|
|
7
|
-
output: Record<string, any>,
|
|
8
|
-
// state: Record<string, any>,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface ZorbAction {
|
|
12
|
-
(ctx: ZorbContext, args: Record<string, any>): void | Promise<void>
|
|
13
|
-
}
|
package/zorb.yml
DELETED