@extrahorizon/exh-cli 1.5.0
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/CHANGELOG.md +53 -0
- package/LICENSE +21 -0
- package/README.md +66 -0
- package/build/commands/completion.d.ts +5 -0
- package/build/commands/completion.js +38 -0
- package/build/commands/data/schemas/delete.d.ts +10 -0
- package/build/commands/data/schemas/delete.js +29 -0
- package/build/commands/data/schemas/list.d.ts +8 -0
- package/build/commands/data/schemas/list.js +20 -0
- package/build/commands/data/schemas/sync/statusHelpers.d.ts +3 -0
- package/build/commands/data/schemas/sync/statusHelpers.js +49 -0
- package/build/commands/data/schemas/sync.d.ts +35 -0
- package/build/commands/data/schemas/sync.js +72 -0
- package/build/commands/data/schemas/util/listFilesInDir.d.ts +1 -0
- package/build/commands/data/schemas/util/listFilesInDir.js +25 -0
- package/build/commands/data/schemas/util/metaschema.json +455 -0
- package/build/commands/data/schemas/util/readJson.d.ts +1 -0
- package/build/commands/data/schemas/util/readJson.js +11 -0
- package/build/commands/data/schemas/util/schemaverify.d.ts +28 -0
- package/build/commands/data/schemas/util/schemaverify.js +202 -0
- package/build/commands/data/schemas/util/syncSchema.d.ts +20 -0
- package/build/commands/data/schemas/util/syncSchema.js +276 -0
- package/build/commands/data/schemas/util/tests/listFilesInDir.test.d.ts +1 -0
- package/build/commands/data/schemas/util/tests/listFilesInDir.test.js +40 -0
- package/build/commands/data/schemas/verify.d.ts +18 -0
- package/build/commands/data/schemas/verify.js +82 -0
- package/build/commands/data/schemas.d.ts +5 -0
- package/build/commands/data/schemas.js +10 -0
- package/build/commands/data.d.ts +5 -0
- package/build/commands/data.js +10 -0
- package/build/commands/dispatchers/sync.d.ts +21 -0
- package/build/commands/dispatchers/sync.js +24 -0
- package/build/commands/dispatchers.d.ts +5 -0
- package/build/commands/dispatchers.js +10 -0
- package/build/commands/login.d.ts +37 -0
- package/build/commands/login.js +59 -0
- package/build/commands/sync.d.ts +55 -0
- package/build/commands/sync.js +107 -0
- package/build/commands/tasks/createrepo.d.ts +22 -0
- package/build/commands/tasks/createrepo.js +70 -0
- package/build/commands/tasks/delete.d.ts +10 -0
- package/build/commands/tasks/delete.js +29 -0
- package/build/commands/tasks/list.d.ts +8 -0
- package/build/commands/tasks/list.js +27 -0
- package/build/commands/tasks/sync.d.ts +56 -0
- package/build/commands/tasks/sync.js +122 -0
- package/build/commands/tasks/taskConfig.d.ts +24 -0
- package/build/commands/tasks/taskConfig.js +169 -0
- package/build/commands/tasks/util.d.ts +1 -0
- package/build/commands/tasks/util.js +27 -0
- package/build/commands/tasks.d.ts +5 -0
- package/build/commands/tasks.js +10 -0
- package/build/commands/templates/delete.d.ts +19 -0
- package/build/commands/templates/delete.js +48 -0
- package/build/commands/templates/get.d.ts +19 -0
- package/build/commands/templates/get.js +37 -0
- package/build/commands/templates/list.d.ts +9 -0
- package/build/commands/templates/list.js +25 -0
- package/build/commands/templates/sync.d.ts +22 -0
- package/build/commands/templates/sync.js +65 -0
- package/build/commands/templates/util/buildTemplates.d.ts +2 -0
- package/build/commands/templates/util/buildTemplates.js +50 -0
- package/build/commands/templates/util/readTemplateFiles.d.ts +3 -0
- package/build/commands/templates/util/readTemplateFiles.js +52 -0
- package/build/commands/templates/util/templateService.d.ts +8 -0
- package/build/commands/templates/util/templateService.js +18 -0
- package/build/commands/templates/util/uploadTemplate.d.ts +2 -0
- package/build/commands/templates/util/uploadTemplate.js +20 -0
- package/build/commands/templates/util/utils.d.ts +4 -0
- package/build/commands/templates/util/utils.js +22 -0
- package/build/commands/templates.d.ts +5 -0
- package/build/commands/templates.js +10 -0
- package/build/constants.d.ts +13 -0
- package/build/constants.js +37 -0
- package/build/exh.d.ts +3 -0
- package/build/exh.js +65 -0
- package/build/helpers/error.d.ts +2 -0
- package/build/helpers/error.js +6 -0
- package/build/helpers/repoConfig.d.ts +2 -0
- package/build/helpers/repoConfig.js +60 -0
- package/build/helpers/util.d.ts +3 -0
- package/build/helpers/util.js +36 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +33 -0
- package/build/repositories/dispatchers.d.ts +8 -0
- package/build/repositories/dispatchers.js +31 -0
- package/build/repositories/functions.d.ts +24 -0
- package/build/repositories/functions.js +28 -0
- package/build/repositories/schemas.d.ts +44 -0
- package/build/repositories/schemas.js +86 -0
- package/build/services/dispatchers.d.ts +3 -0
- package/build/services/dispatchers.js +132 -0
- package/package.json +53 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
4
|
+
const fs = require("fs/promises");
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const constants_1 = require("../../constants");
|
|
7
|
+
const util_1 = require("../../helpers/util");
|
|
8
|
+
const functionRepository = require("../../repositories/functions");
|
|
9
|
+
const taskConfig_1 = require("./taskConfig");
|
|
10
|
+
const util_2 = require("./util");
|
|
11
|
+
exports.command = 'sync';
|
|
12
|
+
exports.desc = 'Sync a task. Will create the task first if it doesn\'t exist yet';
|
|
13
|
+
const builder = (yargs) => (0, util_1.epilogue)(yargs).options({
|
|
14
|
+
path: {
|
|
15
|
+
demandOption: false,
|
|
16
|
+
describe: `Path of the configuration json file containing task parameters. If a directory is given instead, all sub-directories will be searched for a task-config.json file & synced.
|
|
17
|
+
If this option is not used, each parameter (name, code, entryPoint, runtime, ...) will need to be supplied separately`,
|
|
18
|
+
type: 'string',
|
|
19
|
+
},
|
|
20
|
+
name: {
|
|
21
|
+
demandOption: false,
|
|
22
|
+
describe: 'Name of the task',
|
|
23
|
+
type: 'string',
|
|
24
|
+
},
|
|
25
|
+
code: {
|
|
26
|
+
demandOption: false,
|
|
27
|
+
describe: 'The path to a directory containing the built task. exh-cli will compress the directory and upload it',
|
|
28
|
+
type: 'string',
|
|
29
|
+
},
|
|
30
|
+
entryPoint: {
|
|
31
|
+
demandOption: false,
|
|
32
|
+
describe: "The code function that should be invoked. For example 'index.handler' for Nodejs",
|
|
33
|
+
type: 'string',
|
|
34
|
+
},
|
|
35
|
+
runtime: {
|
|
36
|
+
demandOption: false,
|
|
37
|
+
describe: 'Runtime to use for the task',
|
|
38
|
+
choices: constants_1.runtimeChoices,
|
|
39
|
+
type: 'string',
|
|
40
|
+
},
|
|
41
|
+
description: {
|
|
42
|
+
describe: 'A description for this task',
|
|
43
|
+
type: 'string',
|
|
44
|
+
default: '',
|
|
45
|
+
},
|
|
46
|
+
timeLimit: {
|
|
47
|
+
describe: 'The execution time limit for this task (in seconds). Min: 3 max: 900',
|
|
48
|
+
type: 'number',
|
|
49
|
+
},
|
|
50
|
+
memoryLimit: {
|
|
51
|
+
describe: 'The allocated memory for this task (in MB). Min: 128 max: 10240',
|
|
52
|
+
type: 'number',
|
|
53
|
+
},
|
|
54
|
+
env: {
|
|
55
|
+
describe: 'Environment Variables set for this task. This option can be used multiple times.',
|
|
56
|
+
type: 'string',
|
|
57
|
+
default: [],
|
|
58
|
+
},
|
|
59
|
+
executionPermission: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
.check(async ({ path, entryPoint, runtime, name, code, executionPermission }) => {
|
|
64
|
+
if (!path && (!name || !code || !runtime || !entryPoint)) {
|
|
65
|
+
throw new Error('Need to specify either a task config file or all parameters separately');
|
|
66
|
+
}
|
|
67
|
+
(0, taskConfig_1.assertExecutionPermission)(executionPermission);
|
|
68
|
+
return true;
|
|
69
|
+
});
|
|
70
|
+
exports.builder = builder;
|
|
71
|
+
const handler = async ({ sdk, ...cmdLineParams }) => {
|
|
72
|
+
for await (const config of (0, taskConfig_1.getValidatedConfigIterator)(cmdLineParams)) {
|
|
73
|
+
console.log('Syncing task', config.name, '...');
|
|
74
|
+
await syncSingleTask(sdk, config);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
exports.handler = handler;
|
|
78
|
+
async function syncSingleTask(sdk, config) {
|
|
79
|
+
const uploadFilePath = await (0, util_2.zipFileFromDirectory)(config.path);
|
|
80
|
+
const file = await fs.readFile(uploadFilePath);
|
|
81
|
+
const allFunctions = await functionRepository.find(sdk);
|
|
82
|
+
const myFunction = allFunctions.find((f) => f.name === config.name);
|
|
83
|
+
const request = {
|
|
84
|
+
name: config.name,
|
|
85
|
+
description: config.description || 'none',
|
|
86
|
+
entryPoint: config.entryPoint,
|
|
87
|
+
code: file.toString('base64'),
|
|
88
|
+
runtime: config.runtime,
|
|
89
|
+
};
|
|
90
|
+
if (config.executionPermission) {
|
|
91
|
+
request.executionOptions = { permissionMode: config.executionPermission };
|
|
92
|
+
}
|
|
93
|
+
if (config.timeLimit) {
|
|
94
|
+
request.timeLimit = config.timeLimit;
|
|
95
|
+
}
|
|
96
|
+
if (config.memoryLimit) {
|
|
97
|
+
request.memoryLimit = config.memoryLimit;
|
|
98
|
+
}
|
|
99
|
+
if (config.environment) {
|
|
100
|
+
request.environmentVariables =
|
|
101
|
+
Object.entries(config.environment).reduce((prev, curr) => ({ ...prev, [curr[0]]: { value: curr[1] } }), {});
|
|
102
|
+
}
|
|
103
|
+
if (config.retryPolicy) {
|
|
104
|
+
request.retryPolicy = config.retryPolicy;
|
|
105
|
+
}
|
|
106
|
+
if (myFunction === undefined) {
|
|
107
|
+
await functionRepository.create(sdk, request);
|
|
108
|
+
console.log(chalk.green('Successfully created task', config.name));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const existingFunction = await functionRepository.findByName(sdk, myFunction.name);
|
|
112
|
+
if (request.runtime === existingFunction.runtime) {
|
|
113
|
+
delete request.runtime;
|
|
114
|
+
}
|
|
115
|
+
const updateResponse = await functionRepository.update(sdk, request);
|
|
116
|
+
if (!updateResponse?.affectedRecords) {
|
|
117
|
+
throw new Error(`Failed to update task ${request.name}`);
|
|
118
|
+
}
|
|
119
|
+
console.log(chalk.green('Successfully updated task', config.name));
|
|
120
|
+
}
|
|
121
|
+
await fs.unlink(uploadFilePath);
|
|
122
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare enum permissionModes {
|
|
2
|
+
permissionRequired = "permissionRequired",
|
|
3
|
+
allUsers = "allUsers",
|
|
4
|
+
public = "public"
|
|
5
|
+
}
|
|
6
|
+
export interface TaskConfig {
|
|
7
|
+
name?: string;
|
|
8
|
+
path?: string;
|
|
9
|
+
entryPoint?: string;
|
|
10
|
+
runtime?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
timeLimit?: number;
|
|
13
|
+
memoryLimit?: number;
|
|
14
|
+
environment?: Record<string, string>;
|
|
15
|
+
executionPermission?: permissionModes;
|
|
16
|
+
retryPolicy?: {
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
errorsToRetry: string[];
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function assertExecutionPermission(mode: string): asserts mode is permissionModes | undefined;
|
|
22
|
+
export declare function validateConfig(config: TaskConfig): Promise<boolean>;
|
|
23
|
+
export declare function loadSingleConfigFile(path: string): Promise<TaskConfig>;
|
|
24
|
+
export declare function getValidatedConfigIterator({ path, name, code, entryPoint, runtime, description, timeLimit, memoryLimit, executionPermission, env }: any): AsyncGenerator<TaskConfig>;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getValidatedConfigIterator = exports.loadSingleConfigFile = exports.validateConfig = exports.assertExecutionPermission = exports.permissionModes = void 0;
|
|
4
|
+
const assert_1 = require("assert");
|
|
5
|
+
const fs = require("fs/promises");
|
|
6
|
+
const ospath = require("path");
|
|
7
|
+
const Joi = require("joi");
|
|
8
|
+
const constants_1 = require("../../constants");
|
|
9
|
+
var permissionModes;
|
|
10
|
+
(function (permissionModes) {
|
|
11
|
+
permissionModes["permissionRequired"] = "permissionRequired";
|
|
12
|
+
permissionModes["allUsers"] = "allUsers";
|
|
13
|
+
permissionModes["public"] = "public";
|
|
14
|
+
})(permissionModes = exports.permissionModes || (exports.permissionModes = {}));
|
|
15
|
+
const taskConfigSchema = Joi.object({
|
|
16
|
+
name: Joi.string().pattern(/^[A-Za-z0-9-]+$/).required(),
|
|
17
|
+
description: Joi.string(),
|
|
18
|
+
entryPoint: Joi.string().required(),
|
|
19
|
+
runtime: Joi.string().valid(...constants_1.runtimeChoices).required(),
|
|
20
|
+
timeLimit: Joi.number().min(constants_1.limits.time.min).max(constants_1.limits.time.max),
|
|
21
|
+
memoryLimit: Joi.number().min(constants_1.limits.memory.min).max(constants_1.limits.memory.max),
|
|
22
|
+
path: Joi.string(),
|
|
23
|
+
retryPolicy: Joi.object({
|
|
24
|
+
enabled: Joi.boolean().required(),
|
|
25
|
+
errorsToRetry: Joi.array().items(Joi.string()),
|
|
26
|
+
}),
|
|
27
|
+
environment: Joi.object().pattern(/.*/, Joi.string()),
|
|
28
|
+
executionPermission: Joi.string().valid(...Object.values(permissionModes)),
|
|
29
|
+
});
|
|
30
|
+
function assertExecutionPermission(mode) {
|
|
31
|
+
if (mode !== undefined && !Object.values(permissionModes).includes(mode)) {
|
|
32
|
+
throw new assert_1.AssertionError({ message: `executionPermission incorrect. Should be one of ${Object.values(permissionModes).join(',')}` });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.assertExecutionPermission = assertExecutionPermission;
|
|
36
|
+
function replaceConfigVariables(config) {
|
|
37
|
+
let result;
|
|
38
|
+
switch (typeof config) {
|
|
39
|
+
case 'object':
|
|
40
|
+
if (Array.isArray(config)) {
|
|
41
|
+
result = [];
|
|
42
|
+
for (const element of config) {
|
|
43
|
+
result.push(replaceConfigVariables(element));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
result = {};
|
|
48
|
+
for (const [key, value] of Object.entries(config)) {
|
|
49
|
+
result[key] = replaceConfigVariables(value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
case 'string':
|
|
54
|
+
if (config.charAt(0) === '$') {
|
|
55
|
+
const variable = config.slice(1);
|
|
56
|
+
if (process.env[variable]) {
|
|
57
|
+
return process.env[variable];
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`Variable ${variable} not found in environment`);
|
|
60
|
+
}
|
|
61
|
+
return config;
|
|
62
|
+
default:
|
|
63
|
+
result = config;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
async function validateConfig(config) {
|
|
69
|
+
try {
|
|
70
|
+
Joi.attempt(config, taskConfigSchema);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
throw new Error(err.details[0]?.message || 'Unknown config validation error');
|
|
74
|
+
}
|
|
75
|
+
if (config.path) {
|
|
76
|
+
try {
|
|
77
|
+
await fs.access(config.path);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
throw new Error(`Please provide a valid directory path for your code, ${config.path} not found`);
|
|
81
|
+
}
|
|
82
|
+
if ((await fs.stat(config.path)).isFile()) {
|
|
83
|
+
throw new Error(`please provide a valid directory path for your code, ${config.path} points to a file`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
throw new Error('Code path not specified');
|
|
88
|
+
}
|
|
89
|
+
assertExecutionPermission(config.executionPermission);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
exports.validateConfig = validateConfig;
|
|
93
|
+
async function loadSingleConfigFile(path) {
|
|
94
|
+
let taskConfig;
|
|
95
|
+
try {
|
|
96
|
+
const data = await fs.readFile(path);
|
|
97
|
+
try {
|
|
98
|
+
taskConfig = JSON.parse(data.toString());
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
throw new Error(`failed to parse file ${err.message}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (err2) {
|
|
105
|
+
throw new Error(`Invalid config file: ${err2.message}`);
|
|
106
|
+
}
|
|
107
|
+
taskConfig = replaceConfigVariables(taskConfig);
|
|
108
|
+
if (taskConfig.path) {
|
|
109
|
+
taskConfig.path = ospath.join(ospath.dirname(path), taskConfig.path);
|
|
110
|
+
}
|
|
111
|
+
return taskConfig;
|
|
112
|
+
}
|
|
113
|
+
exports.loadSingleConfigFile = loadSingleConfigFile;
|
|
114
|
+
async function* getValidatedConfigIterator({ path, name, code, entryPoint, runtime, description, timeLimit, memoryLimit, executionPermission, env }) {
|
|
115
|
+
let taskConfig = {};
|
|
116
|
+
if (path) {
|
|
117
|
+
const stat = await fs.stat(path);
|
|
118
|
+
if (stat.isDirectory()) {
|
|
119
|
+
const dirContents = await fs.readdir(path);
|
|
120
|
+
for (const file of dirContents) {
|
|
121
|
+
let filePath = ospath.join(path, file);
|
|
122
|
+
if ((await fs.stat(filePath)).isDirectory()) {
|
|
123
|
+
filePath = ospath.join(filePath, 'task-config.json');
|
|
124
|
+
const cfg = await loadSingleConfigFile(filePath);
|
|
125
|
+
if (cfg) {
|
|
126
|
+
await validateConfig(cfg);
|
|
127
|
+
yield cfg;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
taskConfig = await loadSingleConfigFile(path);
|
|
134
|
+
if (!taskConfig) {
|
|
135
|
+
throw new Error("Path is a file but doesn't point to a valid configuration file");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (name) {
|
|
139
|
+
taskConfig.name = name;
|
|
140
|
+
}
|
|
141
|
+
if (code) {
|
|
142
|
+
taskConfig.path = code;
|
|
143
|
+
}
|
|
144
|
+
if (entryPoint) {
|
|
145
|
+
taskConfig.entryPoint = entryPoint;
|
|
146
|
+
}
|
|
147
|
+
if (runtime) {
|
|
148
|
+
taskConfig.runtime = runtime;
|
|
149
|
+
}
|
|
150
|
+
if (description) {
|
|
151
|
+
taskConfig.description = description;
|
|
152
|
+
}
|
|
153
|
+
if (timeLimit) {
|
|
154
|
+
taskConfig.timeLimit = timeLimit;
|
|
155
|
+
}
|
|
156
|
+
if (memoryLimit) {
|
|
157
|
+
taskConfig.memoryLimit = memoryLimit;
|
|
158
|
+
}
|
|
159
|
+
if (executionPermission) {
|
|
160
|
+
taskConfig.executionPermission = executionPermission;
|
|
161
|
+
}
|
|
162
|
+
if (env && env.length) {
|
|
163
|
+
const envArr = Array.isArray(env) ? env : [env];
|
|
164
|
+
taskConfig.environment = envArr.map(e => e.split('=')).filter(e => e.length === 2).reduce((prev, curr) => ({ ...prev, [curr[0]]: curr[1] }), {});
|
|
165
|
+
}
|
|
166
|
+
await validateConfig(taskConfig);
|
|
167
|
+
yield taskConfig;
|
|
168
|
+
}
|
|
169
|
+
exports.getValidatedConfigIterator = getValidatedConfigIterator;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function zipFileFromDirectory(path: string): Promise<string>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.zipFileFromDirectory = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const os_1 = require("os");
|
|
6
|
+
const archiver = require("archiver");
|
|
7
|
+
const uuid_1 = require("uuid");
|
|
8
|
+
async function zipFileFromDirectory(path) {
|
|
9
|
+
return new Promise((res, rej) => {
|
|
10
|
+
const tmpPath = `${(0, os_1.tmpdir)()}/${(0, uuid_1.v4)()}`;
|
|
11
|
+
const output = (0, fs_1.createWriteStream)(tmpPath);
|
|
12
|
+
const archive = archiver('zip', {
|
|
13
|
+
zlib: { level: 9 },
|
|
14
|
+
});
|
|
15
|
+
output.on('close', () => {
|
|
16
|
+
res(tmpPath);
|
|
17
|
+
});
|
|
18
|
+
archive.on('error', (err) => {
|
|
19
|
+
(0, fs_1.unlink)(tmpPath, msg => { console.log(msg); });
|
|
20
|
+
rej(err);
|
|
21
|
+
});
|
|
22
|
+
archive.pipe(output);
|
|
23
|
+
archive.directory(`${path}/`, false);
|
|
24
|
+
archive.finalize();
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
exports.zipFileFromDirectory = zipFileFromDirectory;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
4
|
+
const util_1 = require("../helpers/util");
|
|
5
|
+
exports.command = 'tasks <command>';
|
|
6
|
+
exports.desc = 'Manage tasks';
|
|
7
|
+
const builder = (yargs) => (0, util_1.epilogue)(yargs).commandDir('tasks');
|
|
8
|
+
exports.builder = builder;
|
|
9
|
+
const handler = () => { };
|
|
10
|
+
exports.handler = handler;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/// <reference types="yargs" />
|
|
2
|
+
import { OAuth1Client } from '@extrahorizon/javascript-sdk';
|
|
3
|
+
export declare const command = "delete";
|
|
4
|
+
export declare const desc = "Delete a template";
|
|
5
|
+
export declare const builder: (yargs: any) => import("yargs").Argv<import("yargs").Omit<{}, "id" | "name"> & import("yargs").InferredOptionTypes<{
|
|
6
|
+
name: {
|
|
7
|
+
describe: string;
|
|
8
|
+
type: "string";
|
|
9
|
+
};
|
|
10
|
+
id: {
|
|
11
|
+
describe: string;
|
|
12
|
+
type: "string";
|
|
13
|
+
};
|
|
14
|
+
}>>;
|
|
15
|
+
export declare const handler: ({ sdk, name, id }: {
|
|
16
|
+
sdk: OAuth1Client;
|
|
17
|
+
name: string;
|
|
18
|
+
id: string;
|
|
19
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
4
|
+
const chalk = require("chalk");
|
|
5
|
+
const util_1 = require("../../helpers/util");
|
|
6
|
+
exports.command = 'delete';
|
|
7
|
+
exports.desc = 'Delete a template';
|
|
8
|
+
const builder = (yargs) => (0, util_1.epilogue)(yargs).options({
|
|
9
|
+
name: {
|
|
10
|
+
describe: 'Name of the template to delete',
|
|
11
|
+
type: 'string',
|
|
12
|
+
},
|
|
13
|
+
id: {
|
|
14
|
+
describe: 'ID of the template to delete',
|
|
15
|
+
type: 'string',
|
|
16
|
+
},
|
|
17
|
+
}).check(({ id, name }) => {
|
|
18
|
+
if ((!id && !name) || (id && name)) {
|
|
19
|
+
throw new Error('Either id or name needs to be provided');
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
});
|
|
23
|
+
exports.builder = builder;
|
|
24
|
+
const handler = async function list({ sdk, name, id }) {
|
|
25
|
+
let template = null;
|
|
26
|
+
if (name) {
|
|
27
|
+
template = await sdk.templates.findByName(name);
|
|
28
|
+
}
|
|
29
|
+
if (id) {
|
|
30
|
+
template = await sdk.templates.findById(id);
|
|
31
|
+
}
|
|
32
|
+
if (!template) {
|
|
33
|
+
console.log(chalk.red('Template not found!'));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const { affectedRecords } = await sdk.templates.remove(template.id);
|
|
38
|
+
if (!affectedRecords) {
|
|
39
|
+
console.log(chalk.red('Failed to remove template', name));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
console.log('Template deleted');
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
console.log(chalk.red('Failed to remove template', name));
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
exports.handler = handler;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/// <reference types="yargs" />
|
|
2
|
+
import { OAuth1Client } from '@extrahorizon/javascript-sdk';
|
|
3
|
+
export declare const command = "get";
|
|
4
|
+
export declare const desc = "Fetch a template";
|
|
5
|
+
export declare const builder: (yargs: any) => import("yargs").Argv<import("yargs").Omit<{}, "id" | "name"> & import("yargs").InferredOptionTypes<{
|
|
6
|
+
name: {
|
|
7
|
+
describe: string;
|
|
8
|
+
type: "string";
|
|
9
|
+
};
|
|
10
|
+
id: {
|
|
11
|
+
describe: string;
|
|
12
|
+
type: "string";
|
|
13
|
+
};
|
|
14
|
+
}>>;
|
|
15
|
+
export declare const handler: ({ sdk, name, id }: {
|
|
16
|
+
sdk: OAuth1Client;
|
|
17
|
+
name: string;
|
|
18
|
+
id: string;
|
|
19
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
4
|
+
const chalk = require("chalk");
|
|
5
|
+
const util_1 = require("../../helpers/util");
|
|
6
|
+
exports.command = 'get';
|
|
7
|
+
exports.desc = 'Fetch a template';
|
|
8
|
+
const builder = (yargs) => (0, util_1.epilogue)(yargs).options({
|
|
9
|
+
name: {
|
|
10
|
+
describe: 'Name of the template',
|
|
11
|
+
type: 'string',
|
|
12
|
+
},
|
|
13
|
+
id: {
|
|
14
|
+
describe: 'ID of the template',
|
|
15
|
+
type: 'string',
|
|
16
|
+
},
|
|
17
|
+
}).check(({ name, id }) => {
|
|
18
|
+
if ((name && id) || (!name && !id)) {
|
|
19
|
+
throw new Error('Either name or id should be specified (but not both at the same time)');
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
});
|
|
23
|
+
exports.builder = builder;
|
|
24
|
+
const handler = async function list({ sdk, name, id }) {
|
|
25
|
+
try {
|
|
26
|
+
const template = name ? await sdk.templates.findByName(name) : await sdk.templates.findById(id);
|
|
27
|
+
if (!template) {
|
|
28
|
+
console.log(chalk.red('Failed to get template!'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
console.log(JSON.stringify(template, null, 4));
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.log(chalk.red('Failed to get template', name));
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
exports.handler = handler;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="yargs" />
|
|
2
|
+
import { OAuth1Client } from '@extrahorizon/javascript-sdk';
|
|
3
|
+
export declare const command = "list";
|
|
4
|
+
export declare const desc = "List all templates";
|
|
5
|
+
export declare const builder: (yargs: any) => import("yargs").Argv<{}>;
|
|
6
|
+
export declare const handler: ({ sdk, isTTY }: {
|
|
7
|
+
sdk: OAuth1Client;
|
|
8
|
+
isTTY: boolean;
|
|
9
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
4
|
+
const chalk = require("chalk");
|
|
5
|
+
const util_1 = require("../../helpers/util");
|
|
6
|
+
exports.command = 'list';
|
|
7
|
+
exports.desc = 'List all templates';
|
|
8
|
+
const builder = (yargs) => (0, util_1.epilogue)(yargs);
|
|
9
|
+
exports.builder = builder;
|
|
10
|
+
const handler = async function list({ sdk, isTTY }) {
|
|
11
|
+
const templates = await sdk.templates.findAll();
|
|
12
|
+
if (templates) {
|
|
13
|
+
if (!templates.length) {
|
|
14
|
+
console.log(chalk.red('No templates found'));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (isTTY) {
|
|
18
|
+
console.table(templates.map((c) => ({ Id: c.id, Name: c.name, Description: c.description || '<none>', 'Last updated': c.updateTimestamp.toISOString() })));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
templates.forEach((f) => (console.log(f)));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
exports.handler = handler;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/// <reference types="yargs" />
|
|
2
|
+
import { TemplateService } from './util/templateService';
|
|
3
|
+
export declare const command = "sync";
|
|
4
|
+
export declare const desc = "Sync all templates in a directory with the ExH cloud";
|
|
5
|
+
export declare const builder: (yargs: any) => import("yargs").Argv<import("yargs").Omit<{}, "template" | "path"> & import("yargs").InferredOptionTypes<{
|
|
6
|
+
path: {
|
|
7
|
+
demandOption: false;
|
|
8
|
+
describe: string;
|
|
9
|
+
type: "string";
|
|
10
|
+
};
|
|
11
|
+
template: {
|
|
12
|
+
demandOption: false;
|
|
13
|
+
describe: string;
|
|
14
|
+
type: "string";
|
|
15
|
+
};
|
|
16
|
+
}>>;
|
|
17
|
+
export declare const handler: ({ sdk, path, template }: {
|
|
18
|
+
sdk: any;
|
|
19
|
+
path: any;
|
|
20
|
+
template: any;
|
|
21
|
+
}) => Promise<void>;
|
|
22
|
+
export declare function syncTargetDir(service: TemplateService, targetDir: string): Promise<void>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.syncTargetDir = exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const ospath = require("path");
|
|
6
|
+
const util_1 = require("../../helpers/util");
|
|
7
|
+
const buildTemplates_1 = require("./util/buildTemplates");
|
|
8
|
+
const readTemplateFiles_1 = require("./util/readTemplateFiles");
|
|
9
|
+
const templateService_1 = require("./util/templateService");
|
|
10
|
+
const uploadTemplate_1 = require("./util/uploadTemplate");
|
|
11
|
+
const utils_1 = require("./util/utils");
|
|
12
|
+
exports.command = 'sync';
|
|
13
|
+
exports.desc = 'Sync all templates in a directory with the ExH cloud';
|
|
14
|
+
const builder = (yargs) => (0, util_1.epilogue)(yargs).options({
|
|
15
|
+
path: {
|
|
16
|
+
demandOption: false,
|
|
17
|
+
describe: 'Directory containing the templates which need to be synced',
|
|
18
|
+
type: 'string',
|
|
19
|
+
},
|
|
20
|
+
template: {
|
|
21
|
+
demandOption: false,
|
|
22
|
+
describe: 'Template file to sync',
|
|
23
|
+
type: 'string',
|
|
24
|
+
},
|
|
25
|
+
}).check(({ path, template }) => {
|
|
26
|
+
if (template && !fs.existsSync(ospath.join(process.cwd(), template))) {
|
|
27
|
+
throw new Error('please provide a valid file path for your template');
|
|
28
|
+
}
|
|
29
|
+
if (path && (!fs.existsSync(ospath.join(process.cwd(), path)) || fs.statSync(ospath.join(process.cwd(), path)).isFile())) {
|
|
30
|
+
throw new Error('please provide a valid directory path for your code');
|
|
31
|
+
}
|
|
32
|
+
if ((template && path) || (!template && !path)) {
|
|
33
|
+
throw new Error('Either path or template must be specified (but not both at the same time)');
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
});
|
|
37
|
+
exports.builder = builder;
|
|
38
|
+
const handler = async ({ sdk, path, template }) => {
|
|
39
|
+
const service = new templateService_1.TemplateService(sdk);
|
|
40
|
+
if (path) {
|
|
41
|
+
await syncTargetDir(service, ospath.resolve(path || '.'));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let templ = null;
|
|
45
|
+
const templateName = (0, utils_1.removeFileNameExtension)(ospath.basename(template));
|
|
46
|
+
if (fs.statSync(ospath.join(process.cwd(), template)).isFile()) {
|
|
47
|
+
templ = await (0, readTemplateFiles_1.readTemplateJson)(template);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
templ = await (0, readTemplateFiles_1.readTemplateFolder)(template);
|
|
51
|
+
}
|
|
52
|
+
await buildAndUploadTemplates(service, { [templateName]: templ });
|
|
53
|
+
};
|
|
54
|
+
exports.handler = handler;
|
|
55
|
+
async function buildAndUploadTemplates(service, templateObject) {
|
|
56
|
+
const templates = await (0, buildTemplates_1.buildTemplates)(service, templateObject);
|
|
57
|
+
for (const template of templates) {
|
|
58
|
+
await (0, uploadTemplate_1.uploadTemplate)(service, template);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function syncTargetDir(service, targetDir) {
|
|
62
|
+
const templateFilesByName = await (0, readTemplateFiles_1.readTemplateFiles)(targetDir);
|
|
63
|
+
await buildAndUploadTemplates(service, templateFilesByName);
|
|
64
|
+
}
|
|
65
|
+
exports.syncTargetDir = syncTargetDir;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildTemplates = void 0;
|
|
4
|
+
async function buildTemplates(service, templateFilesByName) {
|
|
5
|
+
const templates = [];
|
|
6
|
+
for (const name of Object.keys(templateFilesByName)) {
|
|
7
|
+
templates.push(await buildTemplate(service, name, templateFilesByName));
|
|
8
|
+
}
|
|
9
|
+
return templates;
|
|
10
|
+
}
|
|
11
|
+
exports.buildTemplates = buildTemplates;
|
|
12
|
+
async function buildTemplate(service, name, templateFilesByName, callChain = []) {
|
|
13
|
+
if (callChain.includes(name)) {
|
|
14
|
+
throw new Error(`Circular extension detected. ${[...callChain, name].reverse().map((n) => `'${n}'`).join(' > ')}`);
|
|
15
|
+
}
|
|
16
|
+
let templateFile = templateFilesByName[name];
|
|
17
|
+
if (templateFile === undefined) {
|
|
18
|
+
templateFile = await service.byName(name);
|
|
19
|
+
if (!templateFile) {
|
|
20
|
+
throw new Error(`Template file dependency ${name} not found!`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const { description, extends_template, schema } = templateFile;
|
|
24
|
+
let { fields } = templateFile;
|
|
25
|
+
if (extends_template) {
|
|
26
|
+
const extendingTemplate = await buildTemplate(service, extends_template, templateFilesByName, [...callChain, name]);
|
|
27
|
+
const match = (_fullMatch, variableName) => {
|
|
28
|
+
const value = fields[variableName];
|
|
29
|
+
if (typeof value === 'undefined') {
|
|
30
|
+
throw new Error(`Could not find a value to fill '$content.${variableName}' ` +
|
|
31
|
+
`while extending '${extends_template}' ` +
|
|
32
|
+
`in ${[...callChain, name].reverse().map(n => `'${n}'`).join(' > ')}`);
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
};
|
|
36
|
+
const extendedFields = {};
|
|
37
|
+
for (const extendingField of Object.keys(extendingTemplate.fields)) {
|
|
38
|
+
const extendedValue = extendingTemplate.fields[extendingField]
|
|
39
|
+
.replace(/\$content\.([a-z0-9_-]+)/ig, match);
|
|
40
|
+
extendedFields[extendingField] = extendedValue;
|
|
41
|
+
}
|
|
42
|
+
fields = extendedFields;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
name,
|
|
46
|
+
description,
|
|
47
|
+
schema,
|
|
48
|
+
fields,
|
|
49
|
+
};
|
|
50
|
+
}
|