@cyberismo/cli 0.0.17 → 0.0.19
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/index.js +264 -210
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +539 -314
package/dist/index.js
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
details. You should have received a copy of the GNU Affero General Public
|
|
12
12
|
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { constants, existsSync } from 'node:fs';
|
|
15
|
+
import { access, lstat, readFile } from 'node:fs/promises';
|
|
15
16
|
import { resolve } from 'node:path';
|
|
16
17
|
import { Argument, Command, Option } from 'commander';
|
|
17
18
|
import confirm from '@inquirer/confirm';
|
|
@@ -100,61 +101,6 @@ const program = new Command();
|
|
|
100
101
|
// Ensure that all names have the same guideline.
|
|
101
102
|
const nameGuideline = 'Name can contain letters (a-z|A-Z), spaces, underscores or hyphens.';
|
|
102
103
|
const pathGuideline = 'Path to the project root. Mandatory if not running inside a project tree.';
|
|
103
|
-
const additionalHelpForCreate = `Sub-command help:
|
|
104
|
-
create attachment <cardKey> <filename>, where
|
|
105
|
-
<cardKey> is card key of a card to have the attachment,
|
|
106
|
-
<filename> is attachment filename.
|
|
107
|
-
|
|
108
|
-
create card <template> [cardKey], where
|
|
109
|
-
<template> Template to use. You can list the templates in a project with "show templates" command.
|
|
110
|
-
[cardKey] Parent card's card key. If defined, new card will be created as a child card to that card.
|
|
111
|
-
|
|
112
|
-
create cardType <name> <workflow>, where
|
|
113
|
-
<name> Name for cardType. ${nameGuideline}
|
|
114
|
-
<workflow> Workflow for the card type. You can list workflows in a project with "show workflows" command.
|
|
115
|
-
|
|
116
|
-
create fieldType <name> <dataType>, where
|
|
117
|
-
<name> Name for fieldType. ${nameGuideline}
|
|
118
|
-
<dataType> Type of field. You can list field types in a project with "show fieldTypes" command.
|
|
119
|
-
|
|
120
|
-
create graphModel <name>, where
|
|
121
|
-
<name> Name for graph model. ${nameGuideline}
|
|
122
|
-
|
|
123
|
-
create graphView <name>, where
|
|
124
|
-
<name> Name for graph view. ${nameGuideline}
|
|
125
|
-
|
|
126
|
-
create label <cardKey> <labelName>, where
|
|
127
|
-
<cardKey> Card key of the label
|
|
128
|
-
<labelName> Name for the new label
|
|
129
|
-
|
|
130
|
-
create link <source> <destination> <linkType> [description], where
|
|
131
|
-
<source> Source card key of the link
|
|
132
|
-
<destination> Destination card key of the link
|
|
133
|
-
<linkType> Link type to create
|
|
134
|
-
[description] Link description
|
|
135
|
-
|
|
136
|
-
create linkType <name>, where
|
|
137
|
-
<name> Name for linkType. ${nameGuideline}
|
|
138
|
-
|
|
139
|
-
create project <name> <prefix> <path>, where
|
|
140
|
-
<name> Name of the project.
|
|
141
|
-
<prefix> Prefix for the project.
|
|
142
|
-
<path> Path where to create the project
|
|
143
|
-
|
|
144
|
-
create report <name>, where
|
|
145
|
-
<name> Name for report. ${nameGuideline}
|
|
146
|
-
|
|
147
|
-
create template <name> [content], where
|
|
148
|
-
<name> Name for template. ${nameGuideline}
|
|
149
|
-
[content] If empty, template is created with default values. Template content must conform to schema "templateSchema.json"
|
|
150
|
-
|
|
151
|
-
create workflow <name> [content], where
|
|
152
|
-
<name> Name for workflow. ${nameGuideline}
|
|
153
|
-
[content] If empty, workflow is created with default values. Workflow content must conform to schema "workflowSchema.json"
|
|
154
|
-
|
|
155
|
-
create <resourceName> [content], where
|
|
156
|
-
<resourceName> Name of the resource (e.g. <prefix>/<type>/<identifier>)
|
|
157
|
-
[content] If empty, resource is created with default values. Content must conform to its resource schema.`;
|
|
158
104
|
const additionalHelpForRemove = `Sub-command help:
|
|
159
105
|
remove attachment <cardKey> <filename>, where
|
|
160
106
|
<cardKey> is card key of the owning card,
|
|
@@ -211,6 +157,17 @@ const additionalHelpForUpdate = `Sub-command help:
|
|
|
211
157
|
const contextOption = new Option('-c, --context [context]', 'Context to run the logic programs in.')
|
|
212
158
|
.choices(validContexts)
|
|
213
159
|
.default('app');
|
|
160
|
+
const pathOption = new Option('-p, --project-path <path>', pathGuideline);
|
|
161
|
+
// Custom Command class with pathOption pre-configured
|
|
162
|
+
class CommandWithPath extends Command {
|
|
163
|
+
createCommand(name) {
|
|
164
|
+
return new CommandWithPath(name);
|
|
165
|
+
}
|
|
166
|
+
constructor(name) {
|
|
167
|
+
super(name);
|
|
168
|
+
this.addOption(pathOption);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
214
171
|
// Main CLI program.
|
|
215
172
|
program
|
|
216
173
|
.name('cyberismo')
|
|
@@ -220,7 +177,8 @@ program
|
|
|
220
177
|
.addOption(new Option('-L, --log-level <level>', 'Set the log level')
|
|
221
178
|
.choices(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])
|
|
222
179
|
.default('fatal'));
|
|
223
|
-
const addCmd =
|
|
180
|
+
const addCmd = new CommandWithPath('add').description('Add items to the project');
|
|
181
|
+
program.addCommand(addCmd);
|
|
224
182
|
// Add card to a template
|
|
225
183
|
addCmd
|
|
226
184
|
.command('card')
|
|
@@ -228,7 +186,6 @@ addCmd
|
|
|
228
186
|
.argument('<template>', 'Template for a new card. \nYou can list the templates in a project with "show templates" command.')
|
|
229
187
|
.argument('<cardType>', 'Card type to use for the new card. \nYou can list the card types in a project with "show cardTypes" command.')
|
|
230
188
|
.argument('[cardKey]', "Parent card's card key")
|
|
231
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
232
189
|
.option('-r, --repeat <quantity>', 'Add multiple cards to a template')
|
|
233
190
|
.action(async (template, cardType, cardKey, options) => {
|
|
234
191
|
const result = await commandHandler.command(Cmd.add, ['card', template, cardType, cardKey], Object.assign({}, options, program.opts()));
|
|
@@ -238,7 +195,6 @@ addCmd
|
|
|
238
195
|
.command('hub')
|
|
239
196
|
.description('Add a hub to the project')
|
|
240
197
|
.argument('<location>', 'Hub URL. Default hub can be added by using "default"')
|
|
241
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
242
198
|
.action(async (location, options) => {
|
|
243
199
|
if (location === 'default') {
|
|
244
200
|
location = DEFAULT_HUB;
|
|
@@ -246,15 +202,13 @@ addCmd
|
|
|
246
202
|
const result = await commandHandler.command(Cmd.add, ['hub', location], Object.assign({}, options, program.opts()));
|
|
247
203
|
handleResponse(result);
|
|
248
204
|
});
|
|
249
|
-
const calculate =
|
|
250
|
-
|
|
251
|
-
.description('Used for running logic programs');
|
|
205
|
+
const calculate = new CommandWithPath('calc').description('Used for running logic programs');
|
|
206
|
+
program.addCommand(calculate);
|
|
252
207
|
calculate
|
|
253
208
|
.command('generate')
|
|
254
209
|
.description('Generate a logic program')
|
|
255
210
|
.argument('<destination>', 'Path to an output file. Command writes the logic program to this file.')
|
|
256
211
|
.argument('[query]', 'Query to run')
|
|
257
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
258
212
|
.action(async (destination, query, options) => {
|
|
259
213
|
const result = await commandHandler.command(Cmd.calc, ['generate', destination, query], Object.assign({}, options, program.opts()));
|
|
260
214
|
handleResponse(result);
|
|
@@ -264,83 +218,118 @@ calculate
|
|
|
264
218
|
.description('Run a logic program')
|
|
265
219
|
.argument('<filePath>', 'Path to the logic program')
|
|
266
220
|
.addOption(contextOption)
|
|
267
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
268
221
|
.action(async (filePath, options) => {
|
|
269
222
|
const result = await commandHandler.command(Cmd.calc, ['run', filePath], Object.assign({}, options, program.opts()));
|
|
270
223
|
handleResponse(result);
|
|
271
224
|
});
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
.
|
|
277
|
-
.
|
|
278
|
-
.argument('
|
|
279
|
-
.argument('
|
|
280
|
-
.
|
|
281
|
-
.
|
|
225
|
+
const createCmd = new CommandWithPath('create').description('Create cards, resources and other project items');
|
|
226
|
+
program.addCommand(createCmd);
|
|
227
|
+
// Create attachment subcommand
|
|
228
|
+
createCmd
|
|
229
|
+
.command('attachment')
|
|
230
|
+
.description('Create an attachment for a card')
|
|
231
|
+
.argument('<cardKey>', 'Card key of the card to attach to')
|
|
232
|
+
.argument('<filename>', 'Path to the file to attach')
|
|
233
|
+
.action(async (cardKey, filename, options) => {
|
|
234
|
+
const result = await commandHandler.command(Cmd.create, ['attachment', cardKey, filename], Object.assign({}, options, program.opts()));
|
|
235
|
+
handleResponse(result);
|
|
236
|
+
});
|
|
237
|
+
// Create card subcommand
|
|
238
|
+
createCmd
|
|
239
|
+
.command('card')
|
|
240
|
+
.description('Create a card from a template')
|
|
241
|
+
.argument('<template>', 'Template to use. You can list templates with "show templates" command')
|
|
242
|
+
.argument('[parentCardKey]', "Parent card's card key. If defined, new card will be created as a child")
|
|
243
|
+
.action(async (template, parentCardKey, options) => {
|
|
244
|
+
const result = await commandHandler.command(Cmd.create, ['card', template, parentCardKey].filter(Boolean), Object.assign({}, options, program.opts()));
|
|
245
|
+
handleResponse(result);
|
|
246
|
+
});
|
|
247
|
+
// Create cardType subcommand
|
|
248
|
+
createCmd
|
|
249
|
+
.command('cardType')
|
|
250
|
+
.description('Create a new card type')
|
|
251
|
+
.argument('<name>', `Name for card type. ${nameGuideline}`)
|
|
252
|
+
.argument('<workflow>', 'Workflow for the card type. You can list workflows with "show workflows" command')
|
|
253
|
+
.action(async (name, workflow, options) => {
|
|
254
|
+
const result = await commandHandler.command(Cmd.create, ['cardType', name, workflow], Object.assign({}, options, program.opts()));
|
|
255
|
+
handleResponse(result);
|
|
256
|
+
});
|
|
257
|
+
// Create fieldType subcommand
|
|
258
|
+
createCmd
|
|
259
|
+
.command('fieldType')
|
|
260
|
+
.description('Create a new field type')
|
|
261
|
+
.argument('<name>', `Name for field type. ${nameGuideline}`)
|
|
262
|
+
.argument('<dataType>', 'Type of field. You can list field types with "show fieldTypes" command')
|
|
263
|
+
.action(async (name, dataType, options) => {
|
|
264
|
+
const result = await commandHandler.command(Cmd.create, ['fieldType', name, dataType], Object.assign({}, options, program.opts()));
|
|
265
|
+
handleResponse(result);
|
|
266
|
+
});
|
|
267
|
+
// Create graphModel subcommand
|
|
268
|
+
createCmd
|
|
269
|
+
.command('graphModel')
|
|
270
|
+
.description('Create a new graph model')
|
|
271
|
+
.argument('<name>', `Name for graph model. ${nameGuideline}`)
|
|
272
|
+
.action(async (name, options) => {
|
|
273
|
+
const result = await commandHandler.command(Cmd.create, ['graphModel', name], Object.assign({}, options, program.opts()));
|
|
274
|
+
handleResponse(result);
|
|
275
|
+
});
|
|
276
|
+
// Create graphView subcommand
|
|
277
|
+
createCmd
|
|
278
|
+
.command('graphView')
|
|
279
|
+
.description('Create a new graph view')
|
|
280
|
+
.argument('<name>', `Name for graph view. ${nameGuideline}`)
|
|
281
|
+
.action(async (name, options) => {
|
|
282
|
+
const result = await commandHandler.command(Cmd.create, ['graphView', name], Object.assign({}, options, program.opts()));
|
|
283
|
+
handleResponse(result);
|
|
284
|
+
});
|
|
285
|
+
// Create label subcommand
|
|
286
|
+
createCmd
|
|
287
|
+
.command('label')
|
|
288
|
+
.description('Create a label on a card')
|
|
289
|
+
.argument('<cardKey>', 'Card key')
|
|
290
|
+
.argument('<labelName>', 'Name for the new label')
|
|
291
|
+
.action(async (cardKey, labelName, options) => {
|
|
292
|
+
const result = await commandHandler.command(Cmd.create, ['label', cardKey, labelName], Object.assign({}, options, program.opts()));
|
|
293
|
+
handleResponse(result);
|
|
294
|
+
});
|
|
295
|
+
// Create link subcommand
|
|
296
|
+
createCmd
|
|
297
|
+
.command('link')
|
|
298
|
+
.description('Create a link between two cards')
|
|
299
|
+
.argument('<source>', 'Source card key')
|
|
300
|
+
.argument('<destination>', 'Destination card key')
|
|
301
|
+
.argument('<linkType>', 'Link type to create')
|
|
302
|
+
.argument('[description]', 'Optional link description')
|
|
303
|
+
.action(async (source, destination, linkType, description, options) => {
|
|
304
|
+
const result = await commandHandler.command(Cmd.create, ['link', source, destination, linkType, description].filter(Boolean), Object.assign({}, options, program.opts()));
|
|
305
|
+
handleResponse(result);
|
|
306
|
+
});
|
|
307
|
+
// Create linkType subcommand
|
|
308
|
+
createCmd
|
|
309
|
+
.command('linkType')
|
|
310
|
+
.description('Create a new link type')
|
|
311
|
+
.argument('<name>', `Name for link type. ${nameGuideline}`)
|
|
312
|
+
.action(async (name, options) => {
|
|
313
|
+
const result = await commandHandler.command(Cmd.create, ['linkType', name], Object.assign({}, options, program.opts()));
|
|
314
|
+
handleResponse(result);
|
|
315
|
+
});
|
|
316
|
+
// Create project subcommand
|
|
317
|
+
createCmd
|
|
318
|
+
.command('project')
|
|
319
|
+
.description('Create a new project')
|
|
320
|
+
.argument('<name>', 'Project name')
|
|
321
|
+
.argument('<prefix>', 'Project prefix')
|
|
322
|
+
.argument('<path>', 'Path where to create the project')
|
|
323
|
+
.argument('[category]', 'Project category (optional)')
|
|
324
|
+
.argument('[description]', 'Project description (optional)')
|
|
282
325
|
.option('-s, --skipModuleImport', 'Skip importing modules when creating a project')
|
|
283
|
-
.action(async (
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
const resourceName = type.split('/').length === 3;
|
|
288
|
-
function nameOfFirstArgument(type) {
|
|
289
|
-
if (type === 'attachment' || type === 'label')
|
|
290
|
-
return 'cardKey';
|
|
291
|
-
if (type === 'card')
|
|
292
|
-
return 'template';
|
|
293
|
-
if (type === 'link')
|
|
294
|
-
return 'source';
|
|
295
|
-
return 'name';
|
|
296
|
-
}
|
|
297
|
-
function nameOfSecondArgument(type) {
|
|
298
|
-
if (type === 'attachment')
|
|
299
|
-
return 'fileName';
|
|
300
|
-
if (type === 'cardType')
|
|
301
|
-
return 'workflow';
|
|
302
|
-
if (type === 'fieldType')
|
|
303
|
-
return 'dataType';
|
|
304
|
-
if (type === 'label')
|
|
305
|
-
return 'labelName';
|
|
306
|
-
if (type === 'link')
|
|
307
|
-
return 'destination';
|
|
308
|
-
if (type === 'project')
|
|
309
|
-
return 'prefix';
|
|
310
|
-
return type;
|
|
311
|
-
}
|
|
312
|
-
if (!target && !resourceName) {
|
|
313
|
-
program.error(`missing required argument <${nameOfFirstArgument(type)}>`);
|
|
314
|
-
}
|
|
315
|
-
if (!resourceName &&
|
|
316
|
-
!parameter1 &&
|
|
317
|
-
type !== 'card' &&
|
|
318
|
-
type !== 'graphModel' &&
|
|
319
|
-
type !== 'graphView' &&
|
|
320
|
-
type !== 'linkType' &&
|
|
321
|
-
type !== 'report' &&
|
|
322
|
-
type !== 'template' &&
|
|
323
|
-
type !== 'workflow') {
|
|
324
|
-
program.error(`missing required argument <${nameOfSecondArgument(type)}>`);
|
|
325
|
-
}
|
|
326
|
-
if (resourceName &&
|
|
327
|
-
(type.includes('cardTypes') || type.includes('fieldTypes')) &&
|
|
328
|
-
!target) {
|
|
329
|
-
program.error(`missing required argument <${nameOfSecondArgument(type)}>`);
|
|
330
|
-
}
|
|
331
|
-
if (type === 'project') {
|
|
332
|
-
if (!parameter2) {
|
|
333
|
-
program.error(`missing required argument <path>`);
|
|
334
|
-
}
|
|
335
|
-
// Project path must be set to 'options' when creating a project.
|
|
336
|
-
options.projectPath = parameter2;
|
|
337
|
-
}
|
|
326
|
+
.action(async (name, prefix, path, category, description, options) => {
|
|
327
|
+
// Project path must be set to 'options' when creating a project
|
|
328
|
+
options.projectPath = path;
|
|
338
329
|
const commandOptions = Object.assign({}, options, program.opts());
|
|
339
|
-
const result = await commandHandler.command(Cmd.create, [
|
|
340
|
-
// Post-handling after creating a new project
|
|
341
|
-
if (
|
|
342
|
-
!commandOptions.skipModuleImport &&
|
|
343
|
-
result.statusCode === 200) {
|
|
330
|
+
const result = await commandHandler.command(Cmd.create, ['project', name, prefix, path, category || '', description || ''], commandOptions);
|
|
331
|
+
// Post-handling after creating a new project
|
|
332
|
+
if (!commandOptions.skipModuleImport && result.statusCode === 200) {
|
|
344
333
|
try {
|
|
345
334
|
// add default hub
|
|
346
335
|
await commandHandler.command(Cmd.add, ['hub', DEFAULT_HUB], commandOptions);
|
|
@@ -372,24 +361,61 @@ program
|
|
|
372
361
|
}
|
|
373
362
|
handleResponse(result);
|
|
374
363
|
});
|
|
364
|
+
// Create report subcommand
|
|
365
|
+
createCmd
|
|
366
|
+
.command('report')
|
|
367
|
+
.description('Create a new report')
|
|
368
|
+
.argument('<name>', `Name for report. ${nameGuideline}`)
|
|
369
|
+
.action(async (name, options) => {
|
|
370
|
+
const result = await commandHandler.command(Cmd.create, ['report', name], Object.assign({}, options, program.opts()));
|
|
371
|
+
handleResponse(result);
|
|
372
|
+
});
|
|
373
|
+
// Create template subcommand
|
|
374
|
+
createCmd
|
|
375
|
+
.command('template')
|
|
376
|
+
.description('Create a new template')
|
|
377
|
+
.argument('<name>', `Name for template. ${nameGuideline}`)
|
|
378
|
+
.argument('[content]', 'Template content. If empty, template is created with default values. Must conform to templateSchema.json')
|
|
379
|
+
.action(async (name, content, options) => {
|
|
380
|
+
const result = await commandHandler.command(Cmd.create, ['template', name, content].filter(Boolean), Object.assign({}, options, program.opts()));
|
|
381
|
+
handleResponse(result);
|
|
382
|
+
});
|
|
383
|
+
// Create workflow subcommand
|
|
384
|
+
createCmd
|
|
385
|
+
.command('workflow')
|
|
386
|
+
.description('Create a new workflow')
|
|
387
|
+
.argument('<name>', `Name for workflow. ${nameGuideline}`)
|
|
388
|
+
.argument('[content]', 'Workflow content. If empty, workflow is created with default values. Must conform to workflowSchema.json')
|
|
389
|
+
.action(async (name, content, options) => {
|
|
390
|
+
const result = await commandHandler.command(Cmd.create, ['workflow', name, content].filter(Boolean), Object.assign({}, options, program.opts()));
|
|
391
|
+
handleResponse(result);
|
|
392
|
+
});
|
|
393
|
+
// Create new resource subcommand
|
|
394
|
+
createCmd
|
|
395
|
+
.command('resource')
|
|
396
|
+
.description('Create a new resource')
|
|
397
|
+
.argument('<resourceName>', 'Resource name (e.g. <prefix>/<type>/<identifier>)')
|
|
398
|
+
.argument('[content]', 'Resource content. If empty, resource is created with default values. Must conform to its resource schema')
|
|
399
|
+
.action(async (resourceName, content, options) => {
|
|
400
|
+
const result = await commandHandler.command(Cmd.create, [resourceName, content].filter(Boolean), Object.assign({}, options, program.opts()));
|
|
401
|
+
handleResponse(result);
|
|
402
|
+
});
|
|
375
403
|
// Edit command
|
|
376
|
-
|
|
377
|
-
.command('edit')
|
|
404
|
+
const editCmd = new CommandWithPath('edit')
|
|
378
405
|
.description('Edit a card')
|
|
379
|
-
.argument('<cardKey>', 'Card key of card')
|
|
380
|
-
|
|
381
|
-
|
|
406
|
+
.argument('<cardKey>', 'Card key of card');
|
|
407
|
+
program.addCommand(editCmd);
|
|
408
|
+
editCmd.action(async (cardKey, options) => {
|
|
382
409
|
const result = await commandHandler.command(Cmd.edit, [cardKey], Object.assign({}, options, program.opts()));
|
|
383
410
|
handleResponse(result);
|
|
384
411
|
});
|
|
385
412
|
// Export command
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
413
|
+
const exportCmd = new CommandWithPath('export').description('Export a project or a card');
|
|
414
|
+
program.addCommand(exportCmd);
|
|
415
|
+
exportCmd
|
|
389
416
|
.addArgument(new Argument('<format>', 'Export format').choices(Object.values(ExportFormats)))
|
|
390
417
|
.argument('<output>', 'Output path')
|
|
391
418
|
.argument('[cardKey]', 'Export a specific card by card key. If omitted, exports the whole site.')
|
|
392
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
393
419
|
.option('-r, --recursive', 'Export cards under the specified card recursively')
|
|
394
420
|
.option('-t, --title [title]', 'Title of the exported document(pdf export only)')
|
|
395
421
|
.option('-n, --name [name]', 'Name of the exported document(pdf export only)')
|
|
@@ -436,22 +462,17 @@ program
|
|
|
436
462
|
const result = await commandHandler.command(Cmd.export, [format, output, cardKey], Object.assign({}, options, program.opts()));
|
|
437
463
|
handleResponse(result);
|
|
438
464
|
});
|
|
439
|
-
const fetchCmd =
|
|
440
|
-
|
|
441
|
-
.description('Retrieve external data to local file system.')
|
|
442
|
-
.option('-p, --project-path [path]', `${pathGuideline}`);
|
|
465
|
+
const fetchCmd = new CommandWithPath('fetch').description('Retrieve external data to local file system.');
|
|
466
|
+
program.addCommand(fetchCmd);
|
|
443
467
|
fetchCmd
|
|
444
468
|
.command('hubs')
|
|
445
469
|
.description('Retrieves module lists from hubs')
|
|
446
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
447
470
|
.action(async (options) => {
|
|
448
471
|
const result = await commandHandler.command(Cmd.fetch, ['hubs'], Object.assign({}, options, program.opts()));
|
|
449
472
|
handleResponse(result);
|
|
450
473
|
});
|
|
451
|
-
const importCmd =
|
|
452
|
-
|
|
453
|
-
.description('Import modules and data into the project')
|
|
454
|
-
.option('-p, --project-path [path]', `${pathGuideline}`);
|
|
474
|
+
const importCmd = new CommandWithPath('import').description('Import modules and data into the project');
|
|
475
|
+
program.addCommand(importCmd);
|
|
455
476
|
// Import module
|
|
456
477
|
importCmd
|
|
457
478
|
.command('module')
|
|
@@ -459,7 +480,6 @@ importCmd
|
|
|
459
480
|
.argument('[source]', 'Path to import from or module name. If omitted, shows interactive selection')
|
|
460
481
|
.argument('[branch]', 'When using git URL defines the branch. Default: main')
|
|
461
482
|
.argument('[useCredentials]', 'When using git URL uses credentials for cloning. Default: false')
|
|
462
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
463
483
|
.action(async (source, branch, useCredentials, options) => {
|
|
464
484
|
let resolvedSource = source;
|
|
465
485
|
let resolvedBranch = branch;
|
|
@@ -525,20 +545,68 @@ importCmd
|
|
|
525
545
|
.command('csv')
|
|
526
546
|
.description('Imports cards from a csv file')
|
|
527
547
|
.argument('<csvFile>', 'File to import from')
|
|
528
|
-
.argument('[cardKey]', '
|
|
529
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
548
|
+
.argument('[cardKey]', 'Parent card key. If defined, cards are created as children of this card')
|
|
530
549
|
.action(async (csvFile, cardKey, options) => {
|
|
531
550
|
const result = await commandHandler.command(Cmd.import, ['csv', csvFile, cardKey], Object.assign({}, options, program.opts()));
|
|
532
551
|
handleResponse(result);
|
|
533
552
|
});
|
|
534
|
-
//
|
|
553
|
+
// Migrate command
|
|
535
554
|
program
|
|
536
|
-
.command('
|
|
555
|
+
.command('migrate')
|
|
556
|
+
.description('Migrate project schema to a newer version.')
|
|
557
|
+
.argument('[version]', 'Target schema version. If not provided, migrates to the latest version. Can only migrate one version at a time when specified.')
|
|
558
|
+
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
559
|
+
.option('-b, --backup <directory>', 'Create a backup before migration in the specified directory. Directory must exist.')
|
|
560
|
+
.option('-t, --timeout <minutes>', 'Timeout for migration in minutes (default: 2 minutes)', '2')
|
|
561
|
+
.action(async (version, options) => {
|
|
562
|
+
if (version) {
|
|
563
|
+
const versionNumber = parseInt(version);
|
|
564
|
+
if (isNaN(versionNumber)) {
|
|
565
|
+
console.error(`Error: migration version is not a number: '${version}'`);
|
|
566
|
+
process.exit(1);
|
|
567
|
+
}
|
|
568
|
+
if (versionNumber <= 0) {
|
|
569
|
+
console.error(`Error: migration version must be above zero: '${version}'`);
|
|
570
|
+
process.exit(1);
|
|
571
|
+
}
|
|
572
|
+
if (options.backup) {
|
|
573
|
+
options.backup = resolve(options.backup.toString().trim());
|
|
574
|
+
if (!existsSync(options.backup)) {
|
|
575
|
+
console.error(`Error: Backup directory does not exist: ${options.backup}`);
|
|
576
|
+
process.exit(1);
|
|
577
|
+
}
|
|
578
|
+
try {
|
|
579
|
+
await access(options.backup, constants.W_OK);
|
|
580
|
+
}
|
|
581
|
+
catch {
|
|
582
|
+
console.error(`Error: Cannot write to backup directory: ${options.backup}`);
|
|
583
|
+
process.exit(1);
|
|
584
|
+
}
|
|
585
|
+
if (!(await lstat(options.backup)).isDirectory()) {
|
|
586
|
+
console.error(`Error: Backup directory is a file: ${options.backup}`);
|
|
587
|
+
process.exit(1);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
if (options.timeout !== undefined) {
|
|
592
|
+
const timeoutMinutes = Number(options.timeout);
|
|
593
|
+
if (isNaN(timeoutMinutes) || timeoutMinutes <= 0) {
|
|
594
|
+
console.error(`Error: Timeout must be a positive number`);
|
|
595
|
+
process.exit(1);
|
|
596
|
+
}
|
|
597
|
+
// Convert minutes to milliseconds
|
|
598
|
+
options.timeout = timeoutMinutes * 60 * 1000;
|
|
599
|
+
}
|
|
600
|
+
const result = await commandHandler.command(Cmd.migrate, [version], Object.assign({}, options, program.opts()));
|
|
601
|
+
handleResponse(result);
|
|
602
|
+
});
|
|
603
|
+
// Move command
|
|
604
|
+
const moveCmd = new CommandWithPath('move')
|
|
537
605
|
.description('Moves a card from root to under another card, from under another card to root, or from under a one card to another.')
|
|
538
606
|
.argument('[source]', 'Source Card key that needs to be moved')
|
|
539
|
-
.argument('[destination]', 'Destination Card key where "source" is moved to. If moving to root, use "root"')
|
|
540
|
-
|
|
541
|
-
|
|
607
|
+
.argument('[destination]', 'Destination Card key where "source" is moved to. If moving to root, use "root"');
|
|
608
|
+
program.addCommand(moveCmd);
|
|
609
|
+
moveCmd.action(async (source, destination, options) => {
|
|
542
610
|
const result = await commandHandler.command(Cmd.move, [source, destination], Object.assign({}, options, program.opts()));
|
|
543
611
|
handleResponse(result);
|
|
544
612
|
});
|
|
@@ -549,16 +617,13 @@ program
|
|
|
549
617
|
.action(async (dir) => {
|
|
550
618
|
await previewSite(dir || '.', true);
|
|
551
619
|
});
|
|
552
|
-
const rank =
|
|
553
|
-
|
|
554
|
-
.description('Manage card ranking and ordering')
|
|
555
|
-
.option('-p, --project-path [path]', `${pathGuideline}`);
|
|
620
|
+
const rank = new CommandWithPath('rank').description('Manage card ranking and ordering');
|
|
621
|
+
program.addCommand(rank);
|
|
556
622
|
rank
|
|
557
623
|
.command('card')
|
|
558
624
|
.description('Set the rank of a card. Ranks define the order in which cards are shown.')
|
|
559
625
|
.argument('<cardKey>', 'Card key of the card to be moved')
|
|
560
626
|
.argument('<afterCardKey>', 'Card key of the card that the card should be after. Use "first" to rank the card first.')
|
|
561
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
562
627
|
.action(async (cardKey, afterCardKey, options) => {
|
|
563
628
|
const result = await commandHandler.command(Cmd.rank, ['card', cardKey, afterCardKey], Object.assign({}, options, program.opts()));
|
|
564
629
|
handleResponse(result);
|
|
@@ -566,22 +631,20 @@ rank
|
|
|
566
631
|
rank
|
|
567
632
|
.command('rebalance')
|
|
568
633
|
.description('Rebalance the rank of all cards in the project. Can be also used, if ranks do not exist')
|
|
569
|
-
.argument('[parentCardKey]', 'if null, rebalance the whole project, otherwise rebalance only the direct children
|
|
570
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
634
|
+
.argument('[parentCardKey]', 'if null, rebalance the whole project, otherwise rebalance only the direct children')
|
|
571
635
|
.action(async (cardKey, options) => {
|
|
572
636
|
const result = await commandHandler.command(Cmd.rank, ['rebalance', cardKey], Object.assign({}, options, program.opts()));
|
|
573
637
|
handleResponse(result);
|
|
574
638
|
});
|
|
575
639
|
// Remove command
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
640
|
+
const removeCmd = new CommandWithPath('remove').description('Remove cards, resources and other project items');
|
|
641
|
+
program.addCommand(removeCmd);
|
|
642
|
+
removeCmd
|
|
579
643
|
.argument('<type>', `removable types: '${Parser.listTargets('remove').join("', '")}', or resource name (e.g. <prefix>/<type>/<identifier>)`, Parser.parseRemoveTypes)
|
|
580
644
|
.argument('[parameter1]', 'Depends on context; see below for specific remove operation')
|
|
581
645
|
.argument('[parameter2]', 'Depends on context; see below for specific remove operation')
|
|
582
646
|
.argument('[parameter3]', 'Depends on context; see below for specific remove operation')
|
|
583
647
|
.addHelpText('after', additionalHelpForRemove)
|
|
584
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
585
648
|
.action(async (type, parameter1, parameter2, parameter3, options) => {
|
|
586
649
|
if (type) {
|
|
587
650
|
if (!parameter1) {
|
|
@@ -620,36 +683,33 @@ program
|
|
|
620
683
|
}
|
|
621
684
|
});
|
|
622
685
|
// Rename command
|
|
623
|
-
|
|
624
|
-
.command('rename')
|
|
686
|
+
const renameCmd = new CommandWithPath('rename')
|
|
625
687
|
.description('Change project prefix and rename all the content with the new prefix')
|
|
626
|
-
.argument('<to>', 'New project prefix')
|
|
627
|
-
|
|
628
|
-
|
|
688
|
+
.argument('<to>', 'New project prefix');
|
|
689
|
+
program.addCommand(renameCmd);
|
|
690
|
+
renameCmd.action(async (to, options) => {
|
|
629
691
|
const result = await commandHandler.command(Cmd.rename, [to], Object.assign({}, options, program.opts()));
|
|
630
692
|
handleResponse(result);
|
|
631
693
|
});
|
|
632
694
|
// Report command
|
|
633
|
-
|
|
634
|
-
.command('report')
|
|
695
|
+
const reportCmd = new CommandWithPath('report')
|
|
635
696
|
.description('Runs a report')
|
|
636
697
|
.argument('<parameters>', 'Path to parameters file. This file defines which report to run and what parameters to use.')
|
|
637
698
|
.argument('[output]', 'Optional output file; if omitted output will be directed to stdout')
|
|
638
|
-
.addOption(contextOption)
|
|
639
|
-
|
|
640
|
-
|
|
699
|
+
.addOption(contextOption);
|
|
700
|
+
program.addCommand(reportCmd);
|
|
701
|
+
reportCmd.action(async (parameters, output, options) => {
|
|
641
702
|
const result = await commandHandler.command(Cmd.report, [parameters, output], Object.assign({}, options, program.opts()));
|
|
642
703
|
handleResponse(result);
|
|
643
704
|
});
|
|
644
705
|
// Show command
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
706
|
+
const showCmd = new CommandWithPath('show').description('Shows details from a project');
|
|
707
|
+
program.addCommand(showCmd);
|
|
708
|
+
showCmd
|
|
648
709
|
.argument('<type>', `details can be seen from: ${Parser.listTargets('show').join(', ')}`, Parser.parseShowTypes)
|
|
649
710
|
.argument('[typeDetail]', 'additional information about the requested type; for example a card key')
|
|
650
711
|
.option('-d --details', 'Certain types (such as cards) can have additional details')
|
|
651
712
|
.option('-a --showAll', 'Show all modules, irregardless if it has been imported or not. Only with "show importableModules"')
|
|
652
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
653
713
|
.option('-u --show-use', 'Show where resource is used. Only used with resources, otherwise will be ignored.')
|
|
654
714
|
.action(async (type, typeDetail, options) => {
|
|
655
715
|
if (type !== '') {
|
|
@@ -666,48 +726,43 @@ program
|
|
|
666
726
|
}
|
|
667
727
|
});
|
|
668
728
|
// Transition command
|
|
669
|
-
|
|
670
|
-
.command('transition')
|
|
729
|
+
const transitionCmd = new CommandWithPath('transition')
|
|
671
730
|
.description('Transition a card to the specified state')
|
|
672
731
|
.argument('<cardKey>', 'card key of a card')
|
|
673
|
-
.argument('<transition>', 'Workflow state transition that is done.\nYou can list the workflows in a project with "show workflows" command.\nYou can see the available transitions with "show workflow <name>" command.')
|
|
674
|
-
|
|
675
|
-
|
|
732
|
+
.argument('<transition>', 'Workflow state transition that is done.\nYou can list the workflows in a project with "show workflows" command.\nYou can see the available transitions with "show workflow <name>" command.');
|
|
733
|
+
program.addCommand(transitionCmd);
|
|
734
|
+
transitionCmd.action(async (cardKey, transition, options) => {
|
|
676
735
|
const result = await commandHandler.command(Cmd.transition, [cardKey, transition], Object.assign({}, options, program.opts()));
|
|
677
736
|
handleResponse(result);
|
|
678
737
|
});
|
|
679
738
|
// Update command
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
739
|
+
const updateCmd = new CommandWithPath('update').description('Update resource details');
|
|
740
|
+
program.addCommand(updateCmd);
|
|
741
|
+
updateCmd
|
|
683
742
|
.argument('<resourceName>', 'Resource name')
|
|
684
743
|
.argument('<operation>', 'Type of change, either "add", "change", "rank" or "remove" ')
|
|
685
744
|
.argument('<key>', 'Detail to be changed')
|
|
686
745
|
.argument('<value>', 'Value for a detail')
|
|
687
746
|
.argument('[newValue]', 'When using "change" define new value for detail.\nWhen using "remove" provide optional replacement value for removed value')
|
|
688
|
-
.option('-m, --mapping-file
|
|
689
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
747
|
+
.option('-m, --mapping-file <path>', 'Path to JSON file containing workflow state mapping (only used when changing workflow)')
|
|
690
748
|
.addHelpText('after', additionalHelpForUpdate)
|
|
691
749
|
.action(async (resourceName, operation, key, value, newValue, options) => {
|
|
692
750
|
const result = await commandHandler.command(Cmd.update, [resourceName, operation, key, value, newValue], Object.assign({}, options, program.opts()));
|
|
693
751
|
handleResponse(result);
|
|
694
752
|
});
|
|
695
753
|
// Updates all modules, or specific named module in the project.
|
|
696
|
-
|
|
697
|
-
.command('update-modules')
|
|
754
|
+
const updateModulesCmd = new CommandWithPath('update-modules')
|
|
698
755
|
.description('Updates to latest versions either all modules or a specific module')
|
|
699
|
-
.argument('[moduleName]', 'Module name')
|
|
700
|
-
|
|
701
|
-
|
|
756
|
+
.argument('[moduleName]', 'Module name');
|
|
757
|
+
program.addCommand(updateModulesCmd);
|
|
758
|
+
updateModulesCmd.action(async (moduleName, options) => {
|
|
702
759
|
const result = await commandHandler.command(Cmd.updateModules, [moduleName], Object.assign({}, options, program.opts()), credentials());
|
|
703
760
|
handleResponse(result);
|
|
704
761
|
});
|
|
705
762
|
// Validate command
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
.option('-p, --project-path [path]', `${pathGuideline}`)
|
|
710
|
-
.action(async (options) => {
|
|
763
|
+
const validateCmd = new CommandWithPath('validate').description('Validate project structure');
|
|
764
|
+
program.addCommand(validateCmd);
|
|
765
|
+
validateCmd.action(async (options) => {
|
|
711
766
|
const result = await commandHandler.command(Cmd.validate, [], Object.assign({}, options, program.opts()));
|
|
712
767
|
handleResponse(result);
|
|
713
768
|
});
|
|
@@ -716,12 +771,11 @@ program
|
|
|
716
771
|
// There is 10 sec timeout on the prompt. If user does not reply, then
|
|
717
772
|
// it is assumed that validation errors do not matter and application
|
|
718
773
|
// start is resumed.
|
|
719
|
-
|
|
720
|
-
.command('app')
|
|
774
|
+
const appCmd = new CommandWithPath('app')
|
|
721
775
|
.description('Starts the cyberismo app, accessible with a web browser at http://localhost:3000')
|
|
722
|
-
.option('-w, --watch-resource-changes', 'Project watches changes in .cards folder resources')
|
|
723
|
-
|
|
724
|
-
|
|
776
|
+
.option('-w, --watch-resource-changes', 'Project watches changes in .cards folder resources');
|
|
777
|
+
program.addCommand(appCmd);
|
|
778
|
+
appCmd.action(async (options) => {
|
|
725
779
|
// validate project
|
|
726
780
|
const result = await commandHandler.command(Cmd.validate, [], Object.assign({}, options, program.opts()));
|
|
727
781
|
if (!result.message) {
|