contensis-cli 1.0.0-beta.9 → 1.0.0-beta.91

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.
Files changed (125) hide show
  1. package/README.md +1146 -78
  2. package/cli.js +3 -0
  3. package/dist/commands/connect.js +3 -3
  4. package/dist/commands/connect.js.map +2 -2
  5. package/dist/commands/create.js +45 -10
  6. package/dist/commands/create.js.map +2 -2
  7. package/dist/commands/dev.js +75 -0
  8. package/dist/commands/dev.js.map +7 -0
  9. package/dist/commands/diff.js +57 -0
  10. package/dist/commands/diff.js.map +7 -0
  11. package/dist/commands/execute.js +103 -0
  12. package/dist/commands/execute.js.map +7 -0
  13. package/dist/commands/get.js +169 -32
  14. package/dist/commands/get.js.map +3 -3
  15. package/dist/commands/globalOptions.js +37 -12
  16. package/dist/commands/globalOptions.js.map +2 -2
  17. package/dist/commands/import.js +47 -12
  18. package/dist/commands/import.js.map +2 -2
  19. package/dist/commands/index.js +22 -2
  20. package/dist/commands/index.js.map +2 -2
  21. package/dist/commands/list.js +53 -10
  22. package/dist/commands/list.js.map +2 -2
  23. package/dist/commands/login.js +2 -2
  24. package/dist/commands/login.js.map +2 -2
  25. package/dist/commands/push.js +17 -13
  26. package/dist/commands/push.js.map +2 -2
  27. package/dist/commands/remove.js +51 -8
  28. package/dist/commands/remove.js.map +2 -2
  29. package/dist/commands/set.js +139 -12
  30. package/dist/commands/set.js.map +2 -2
  31. package/dist/index.js +1 -1
  32. package/dist/index.js.map +2 -2
  33. package/dist/localisation/en-GB.js +259 -49
  34. package/dist/localisation/en-GB.js.map +2 -2
  35. package/dist/mappers/ContensisCliService-to-RequestHanderSiteConfigYaml.js +56 -0
  36. package/dist/mappers/ContensisCliService-to-RequestHanderSiteConfigYaml.js.map +7 -0
  37. package/dist/mappers/DevInit-to-CIWorkflow.js +127 -0
  38. package/dist/mappers/DevInit-to-CIWorkflow.js.map +7 -0
  39. package/dist/mappers/DevInit-to-RolePermissions.js +54 -0
  40. package/dist/mappers/DevInit-to-RolePermissions.js.map +7 -0
  41. package/dist/mappers/DevRequests-to-RequestHanderSiteConfigYaml.js +56 -0
  42. package/dist/mappers/DevRequests-to-RequestHanderSiteConfigYaml.js.map +7 -0
  43. package/dist/models/CliService.d.js +17 -0
  44. package/dist/models/CliService.d.js.map +7 -0
  45. package/dist/models/DevService.d.js +17 -0
  46. package/dist/models/DevService.d.js.map +7 -0
  47. package/dist/providers/CredentialProvider.js +46 -14
  48. package/dist/providers/CredentialProvider.js.map +3 -3
  49. package/dist/providers/SessionCacheProvider.js +21 -1
  50. package/dist/providers/SessionCacheProvider.js.map +2 -2
  51. package/dist/providers/file-provider.js +12 -6
  52. package/dist/providers/file-provider.js.map +3 -3
  53. package/dist/services/ContensisCliService.js +1148 -421
  54. package/dist/services/ContensisCliService.js.map +3 -3
  55. package/dist/services/ContensisDevService.js +309 -0
  56. package/dist/services/ContensisDevService.js.map +7 -0
  57. package/dist/services/ContensisRoleService.js +87 -0
  58. package/dist/services/ContensisRoleService.js.map +7 -0
  59. package/dist/shell.js +58 -18
  60. package/dist/shell.js.map +3 -3
  61. package/dist/util/console.printer.js +171 -55
  62. package/dist/util/console.printer.js.map +2 -2
  63. package/dist/util/diff.js +102 -0
  64. package/dist/util/diff.js.map +7 -0
  65. package/dist/util/dotenv.js +57 -0
  66. package/dist/util/dotenv.js.map +7 -0
  67. package/dist/util/find.js +31 -0
  68. package/dist/util/find.js.map +7 -0
  69. package/dist/util/git.js +126 -0
  70. package/dist/util/git.js.map +7 -0
  71. package/dist/util/index.js +8 -2
  72. package/dist/util/index.js.map +3 -3
  73. package/dist/util/logger.js +90 -29
  74. package/dist/util/logger.js.map +3 -3
  75. package/dist/util/os.js +39 -0
  76. package/dist/util/os.js.map +7 -0
  77. package/dist/util/timers.js +49 -0
  78. package/dist/util/timers.js.map +7 -0
  79. package/dist/util/yaml.js +45 -0
  80. package/dist/util/yaml.js.map +7 -0
  81. package/dist/version.js +1 -1
  82. package/dist/version.js.map +1 -1
  83. package/esbuild.config.js +3 -1
  84. package/package.json +12 -3
  85. package/src/commands/connect.ts +3 -2
  86. package/src/commands/create.ts +61 -8
  87. package/src/commands/dev.ts +69 -0
  88. package/src/commands/diff.ts +41 -0
  89. package/src/commands/execute.ts +117 -0
  90. package/src/commands/get.ts +242 -28
  91. package/src/commands/globalOptions.ts +42 -12
  92. package/src/commands/import.ts +58 -8
  93. package/src/commands/index.ts +22 -1
  94. package/src/commands/list.ts +85 -11
  95. package/src/commands/login.ts +2 -1
  96. package/src/commands/push.ts +18 -11
  97. package/src/commands/remove.ts +66 -4
  98. package/src/commands/set.ts +189 -9
  99. package/src/index.ts +1 -4
  100. package/src/localisation/en-GB.ts +374 -66
  101. package/src/mappers/ContensisCliService-to-RequestHanderSiteConfigYaml.ts +44 -0
  102. package/src/mappers/DevInit-to-CIWorkflow.ts +150 -0
  103. package/src/mappers/DevInit-to-RolePermissions.ts +33 -0
  104. package/src/mappers/DevRequests-to-RequestHanderSiteConfigYaml.ts +44 -0
  105. package/src/models/CliService.d.ts +36 -0
  106. package/src/models/DevService.d.ts +5 -0
  107. package/src/models/JsModules.d.ts +1 -0
  108. package/src/providers/CredentialProvider.ts +51 -18
  109. package/src/providers/SessionCacheProvider.ts +29 -2
  110. package/src/providers/file-provider.ts +17 -6
  111. package/src/services/ContensisCliService.ts +1458 -518
  112. package/src/services/ContensisDevService.ts +365 -0
  113. package/src/services/ContensisRoleService.ts +76 -0
  114. package/src/shell.ts +68 -18
  115. package/src/util/console.printer.ts +240 -78
  116. package/src/util/diff.ts +113 -0
  117. package/src/util/dotenv.ts +37 -0
  118. package/src/util/find.ts +8 -0
  119. package/src/util/git.ts +130 -0
  120. package/src/util/index.ts +16 -7
  121. package/src/util/logger.ts +145 -31
  122. package/src/util/os.ts +7 -0
  123. package/src/util/timers.ts +24 -0
  124. package/src/util/yaml.ts +13 -0
  125. package/src/version.ts +1 -1
@@ -0,0 +1,365 @@
1
+ import to from 'await-to-js';
2
+ import { execFile, spawn } from 'child_process';
3
+ import inquirer from 'inquirer';
4
+ import path from 'path';
5
+ import { parse, stringify } from 'yaml';
6
+
7
+ import { Role } from 'contensis-management-api/lib/models';
8
+ import { MigrateRequest } from 'migratortron';
9
+
10
+ import ContensisRole from './ContensisRoleService';
11
+ import { OutputOptionsConstructorArg } from '~/models/CliService';
12
+ import { EnvContentsToAdd } from '~/models/DevService';
13
+ import { mapSiteConfigYaml } from '~/mappers/DevRequests-to-RequestHanderSiteConfigYaml';
14
+ import {
15
+ deployKeyRole,
16
+ devKeyRole,
17
+ } from '~/mappers/DevInit-to-RolePermissions';
18
+ import { appRootDir, readFile, writeFile } from '~/providers/file-provider';
19
+ import { jsonFormatter } from '~/util/json.formatter';
20
+ import { GitHelper } from '~/util/git';
21
+ import { findByIdOrName } from '~/util/find';
22
+ import { mergeDotEnvFileContents } from '~/util/dotenv';
23
+ import { mapCIWorkflowContent } from '~/mappers/DevInit-to-CIWorkflow';
24
+ import { diffFileContent } from '~/util/diff';
25
+
26
+ class ContensisDev extends ContensisRole {
27
+ constructor(
28
+ args: string[],
29
+ outputOpts?: OutputOptionsConstructorArg,
30
+ contensisOpts: Partial<MigrateRequest> = {}
31
+ ) {
32
+ super(args, outputOpts, contensisOpts);
33
+ }
34
+
35
+ DevelopmentInit = async (projectHome: string, opts: any) => {
36
+ const { dryRun = false } = opts || {};
37
+ const { currentEnv, currentProject, log, messages } = this;
38
+ const contensis = await this.ConnectContensis();
39
+
40
+ if (contensis) {
41
+ // Retrieve keys list for env
42
+ const [keysErr, apiKeys] = await contensis.apiKeys.GetKeys();
43
+ if (keysErr) {
44
+ log.error(messages.keys.noList(currentEnv));
45
+ log.error(jsonFormatter(keysErr));
46
+ return;
47
+ }
48
+ const apiKeyExists = (findKey: string) =>
49
+ apiKeys?.find(
50
+ k => k.name.trim().toLowerCase() === findKey?.trim().toLowerCase()
51
+ );
52
+
53
+ // Retrieve git info
54
+ const git = new GitHelper(projectHome);
55
+
56
+ // Retrieve ci workflow info
57
+ const workflowFiles = git.workflows;
58
+
59
+ // Set variables for performing operations and logging etc.
60
+ let ciFileName = git.ciFileName;
61
+
62
+ const devKeyName = `${git.name} development`;
63
+ const devKeyDescription = `${git.name} [contensis-cli]`;
64
+ let existingDevKey = apiKeyExists(devKeyName);
65
+
66
+ const deployKeyName = `${git.name} deployment`;
67
+ const deployKeyDescription = `${git.name} deploy [contensis-cli]`;
68
+
69
+ let existingDeployKey = apiKeyExists(deployKeyName);
70
+
71
+ const blockId = git.name;
72
+ const errors = [] as AppError[];
73
+
74
+ // Start render console output
75
+ log.raw('');
76
+ log.success(messages.devinit.intro());
77
+ log.raw('');
78
+ log.raw(
79
+ log.infoText(
80
+ messages.devinit.projectDetails(
81
+ git.name,
82
+ currentEnv,
83
+ currentProject,
84
+ git
85
+ )
86
+ )
87
+ );
88
+ log.raw(
89
+ log.infoText(
90
+ messages.devinit.developmentKey(devKeyName, !!existingDevKey)
91
+ )
92
+ );
93
+ log.raw(
94
+ log.infoText(
95
+ messages.devinit.deploymentKey(deployKeyName, !!existingDeployKey)
96
+ )
97
+ );
98
+ log.raw('');
99
+
100
+ if (Array.isArray(workflowFiles) && workflowFiles.length > 1) {
101
+ // Choose GitHub workflow file (if multiple)
102
+ ({ ciFileName } = await inquirer.prompt([
103
+ {
104
+ type: 'list',
105
+ message: messages.devinit.ciMultipleChoices(),
106
+ name: 'ciFileName',
107
+ choices: workflowFiles,
108
+ default: workflowFiles.find(f => f.includes('docker')),
109
+ },
110
+ ]));
111
+ log.raw('');
112
+ git.ciFileName = ciFileName;
113
+ }
114
+
115
+ log.raw(log.infoText(messages.devinit.ciDetails(ciFileName)));
116
+
117
+ // Look at the workflow file content and make updates
118
+ const mappedWorkflow = mapCIWorkflowContent(this, git);
119
+
120
+ log.help(messages.devinit.ciIntro(git));
121
+
122
+ if (!dryRun) {
123
+ // Confirm prompt
124
+ const { confirm } = await inquirer.prompt([
125
+ {
126
+ type: 'confirm',
127
+ message: messages.devinit.confirm(),
128
+ name: 'confirm',
129
+ default: false,
130
+ },
131
+ ]);
132
+ log.raw('');
133
+ if (!confirm) return;
134
+ }
135
+
136
+ // Access token prompt
137
+ const { accessToken }: { accessToken: string } = await inquirer.prompt([
138
+ {
139
+ type: 'input',
140
+ message: messages.devinit.accessTokenPrompt(),
141
+ name: 'accessToken',
142
+ },
143
+ ]);
144
+ log.raw('');
145
+
146
+ // Magic happens...
147
+ const checkpoint = (op: string) => {
148
+ if (errors.length) throw errors[0];
149
+ else log.debug(`${op} completed ok`);
150
+ return true;
151
+ };
152
+
153
+ // Arrange API keys for development and deployment
154
+ const [getRolesErr, roles] = await to(contensis.roles.GetRoles());
155
+ if (!roles && getRolesErr) errors.push(getRolesErr);
156
+ checkpoint(`fetched ${roles?.length} roles`);
157
+ if (dryRun) {
158
+ checkpoint(`skip api key creation (dry-run)`);
159
+ } else {
160
+ existingDevKey = await this.CreateOrUpdateApiKey(
161
+ existingDevKey,
162
+ devKeyName,
163
+ devKeyDescription
164
+ );
165
+ checkpoint('dev key created');
166
+
167
+ existingDeployKey = await this.CreateOrUpdateApiKey(
168
+ existingDeployKey,
169
+ deployKeyName,
170
+ deployKeyDescription
171
+ );
172
+ checkpoint('deploy key created');
173
+
174
+ // Ensure dev API key is assigned to a role
175
+ let existingDevRole = findByIdOrName(roles || [], devKeyName, true) as
176
+ | Role
177
+ | undefined;
178
+ existingDevRole = await this.CreateOrUpdateRole(
179
+ existingDevRole,
180
+ devKeyRole(devKeyName, devKeyDescription)
181
+ );
182
+ checkpoint('dev key role assigned');
183
+ log.success(messages.devinit.createDevKey(devKeyName, true));
184
+
185
+ // Ensure deploy API key is assigned to a role with the right permissions
186
+ let existingDeployRole = findByIdOrName(
187
+ roles || [],
188
+ deployKeyName,
189
+ true
190
+ ) as Role | undefined;
191
+ existingDeployRole = await this.CreateOrUpdateRole(
192
+ existingDeployRole,
193
+ deployKeyRole(deployKeyName, deployKeyDescription)
194
+ );
195
+
196
+ checkpoint('deploy key role assigned');
197
+ log.success(messages.devinit.createDeployKey(deployKeyName, true));
198
+ checkpoint('api keys done');
199
+ }
200
+
201
+ // Update or create a file called .env in project home
202
+ const envContentsToAdd: EnvContentsToAdd = {
203
+ ALIAS: currentEnv,
204
+ PROJECT: currentProject,
205
+ };
206
+ if (accessToken) envContentsToAdd['ACCESS_TOKEN'] = accessToken;
207
+
208
+ const envFilePath = `${projectHome}/.env`;
209
+ const existingEnvFile = readFile(envFilePath);
210
+ const envFileLines = mergeDotEnvFileContents(
211
+ (existingEnvFile || '').split('\n').filter(l => !!l),
212
+ envContentsToAdd
213
+ );
214
+ const envDiff = diffFileContent(
215
+ existingEnvFile || '',
216
+ envFileLines.join('\n')
217
+ );
218
+
219
+ if (dryRun) {
220
+ if (envDiff) {
221
+ log.info(`updating .env file ${envFilePath}: ${envDiff}`);
222
+ log.raw('');
223
+ }
224
+ checkpoint('skip .env file update (dry-run)');
225
+ } else {
226
+ if (envDiff) log.info(`updating .env file ${envFilePath}`);
227
+ writeFile(envFilePath, envFileLines.join('\n'));
228
+ checkpoint('.env file updated');
229
+ log.success(messages.devinit.writeEnvFile());
230
+ // log.help(messages.devinit.useEnvFileTip());
231
+ }
232
+
233
+ // Update CI file -- different for GH/GL -- create a sample one with build?
234
+ if (dryRun) {
235
+ if (mappedWorkflow?.diff) {
236
+ log.info(`updating${ciFileName} file: ${mappedWorkflow.diff}`);
237
+ log.raw('');
238
+ }
239
+ checkpoint('skip CI file update (dry-run)');
240
+ //log.object(ciFileLines);
241
+ } else {
242
+ if (mappedWorkflow?.diff) log.info(`updating${ciFileName} file`);
243
+ writeFile(git.ciFilePath, [].join('\n'));
244
+ log.success(messages.devinit.writeCiFile(`./${ciFileName}`));
245
+ log.info(
246
+ messages.devinit.ciBlockTip(blockId, currentEnv, currentProject)
247
+ );
248
+ checkpoint('CI file updated');
249
+ }
250
+
251
+ // Echo Deployment API key to console, ask user to add secrets to repo
252
+ log.warning(messages.devinit.addGitSecretsIntro());
253
+ log.help(
254
+ messages.devinit.addGitSecretsHelp(
255
+ git,
256
+ existingDeployKey?.id,
257
+ existingDeployKey?.sharedSecret
258
+ )
259
+ );
260
+
261
+ if (dryRun) {
262
+ log.success(messages.devinit.dryRun());
263
+ log.help(messages.devinit.noChanges());
264
+ } else {
265
+ log.success(messages.devinit.success());
266
+ log.help(messages.devinit.startProjectTip());
267
+ }
268
+ }
269
+ };
270
+
271
+ ExecRequestHandler = async (blockIds: string[], overrideArgs?: string[]) => {
272
+ // if no request handler exe
273
+ // download it.
274
+
275
+ // if update arg, redownload it
276
+
277
+ const { log } = this;
278
+ // const getPrefixOld = log.getPrefix;
279
+ const exeHome = path.join(appRootDir, 'reqhan');
280
+ const exe = 'Zengenti.Contensis.RequestHandler.LocalDevelopment';
281
+ const exePath = path.join(exeHome, exe);
282
+ const siteConfigPath = path.join(appRootDir, 'site_config.yaml');
283
+
284
+ const siteConfig = await mapSiteConfigYaml(this);
285
+ writeFile('site_config.yaml', stringify(siteConfig));
286
+
287
+ const args = overrideArgs
288
+ ? typeof overrideArgs?.[0] === 'string' &&
289
+ overrideArgs[0].includes(' ', 2)
290
+ ? overrideArgs[0].split(' ')
291
+ : overrideArgs
292
+ : []; // args could be [ '-c .\\site_config.yaml' ] or [ '-c', '.\\site_config.yaml' ]
293
+
294
+ // Add required args
295
+ if (!args.find(a => a === '-c')) args.push('-c', siteConfigPath);
296
+
297
+ // const child = execFile(exePath, args);
298
+
299
+ const child = spawn(exePath, args, { stdio: 'inherit' });
300
+
301
+ // log.raw('');
302
+ log.info(`Launching request handler...`);
303
+ if (overrideArgs?.length)
304
+ this.log.warning(
305
+ `Spawning process with supplied args: ${JSON.stringify(
306
+ child.spawnargs,
307
+ null,
308
+ 2
309
+ )}`
310
+ );
311
+
312
+ let isRunning = false;
313
+
314
+ // Log child output through event listeners
315
+ child?.stdout?.on('data', data => {
316
+ isRunning = true;
317
+ log.raw(data);
318
+ });
319
+
320
+ child?.stderr?.on('data', data => {
321
+ log.error(data);
322
+ });
323
+
324
+ child.on('spawn', () => {
325
+ isRunning = true;
326
+ log.help(
327
+ `You may see a firewall popup requesting network access, it is safe to approve`
328
+ );
329
+ // log.getPrefix = () => Logger.infoText(`[rqh]`);
330
+ });
331
+
332
+ child.on('exit', code => {
333
+ isRunning = false;
334
+
335
+ log[code === 0 ? 'success' : 'warning'](
336
+ `Request handler exited with code ${code}\n`
337
+ );
338
+ });
339
+
340
+ child.on('error', error => {
341
+ isRunning = false;
342
+ log.error(`Could not launch request handler due to error \n${error}`);
343
+ });
344
+
345
+ await new Promise(resolve => setTimeout(resolve, 2000));
346
+
347
+ // keep the method running until we can return
348
+ while (true === true) {
349
+ if (!isRunning) {
350
+ // log.getPrefix = getPrefixOld; // restore logger state
351
+ return;
352
+ }
353
+ await new Promise(resolve => setTimeout(resolve, 1000));
354
+ }
355
+ };
356
+ }
357
+ export const devCommand = (
358
+ commandArgs: string[],
359
+ outputOpts: OutputOptionsConstructorArg,
360
+ contensisOpts: Partial<MigrateRequest> = {}
361
+ ) => {
362
+ return new ContensisDev(['', '', ...commandArgs], outputOpts, contensisOpts);
363
+ };
364
+
365
+ export default ContensisDev;
@@ -0,0 +1,76 @@
1
+ import { Role } from 'contensis-management-api/lib/models';
2
+ import { ApiKey, MigrateRequest } from 'migratortron';
3
+
4
+ import ContensisCli from './ContensisCliService';
5
+ import { OutputOptionsConstructorArg } from '~/models/CliService';
6
+
7
+ class ContensisRole extends ContensisCli {
8
+ constructor(
9
+ args: string[],
10
+ outputOpts?: OutputOptionsConstructorArg,
11
+ contensisOpts: Partial<MigrateRequest> = {}
12
+ ) {
13
+ super(args, outputOpts, contensisOpts);
14
+ }
15
+
16
+ CreateOrUpdateApiKey = async (
17
+ existingKey: ApiKey | undefined,
18
+ name: string,
19
+ description: string
20
+ ) => {
21
+ const { contensis, currentEnv, messages } = this;
22
+ if (!contensis) throw new Error('shouldnt be here');
23
+ if (existingKey) {
24
+ const [err, key] = await contensis.apiKeys.UpdateKey(existingKey.id, {
25
+ name,
26
+ description,
27
+ });
28
+
29
+ if (err)
30
+ throw new Error(messages.keys.failedUpdate(currentEnv, name), {
31
+ cause: err,
32
+ });
33
+ return key;
34
+ } else {
35
+ const [err, key] = await contensis.apiKeys.CreateKey(name, description);
36
+ if (err)
37
+ throw new Error(messages.keys.failedCreate(currentEnv, name), {
38
+ cause: err,
39
+ });
40
+
41
+ return key;
42
+ }
43
+ };
44
+
45
+ CreateOrUpdateRole = async (
46
+ existingRole: Role | undefined,
47
+ role: Partial<Role>
48
+ ) => {
49
+ const { contensis, currentEnv, messages } = this;
50
+ if (!contensis) throw new Error('shouldnt be here');
51
+
52
+ if (existingRole) {
53
+ // TODO: check is update needed?
54
+ const [err, updated] = await contensis.roles.UpdateRole(existingRole.id, {
55
+ ...existingRole,
56
+ ...role,
57
+ });
58
+ if (err)
59
+ throw new Error(messages.roles.failedSet(currentEnv, role.name), {
60
+ cause: err,
61
+ });
62
+ return updated;
63
+ } else {
64
+ const [err, created] = await contensis.roles.CreateRole(
65
+ role as Omit<Role, 'id'>
66
+ );
67
+ if (err)
68
+ throw new Error(messages.roles.failedCreate(currentEnv, role.name), {
69
+ cause: err,
70
+ });
71
+
72
+ return created;
73
+ }
74
+ };
75
+ }
76
+ export default ContensisRole;
package/src/shell.ts CHANGED
@@ -1,13 +1,14 @@
1
- import path from 'path';
2
1
  import figlet from 'figlet';
3
2
  import inquirer from 'inquirer';
4
3
  import inquirerPrompt from 'inquirer-command-prompt';
5
4
  import commands from './commands';
6
5
  import { LogMessages } from './localisation/en-GB';
7
- import { logError, Logger } from './util/logger';
8
6
  import CredentialProvider from './providers/CredentialProvider';
7
+ import { appRootDir } from './providers/file-provider';
9
8
  import ContensisCli, { cliCommand } from './services/ContensisCliService';
10
9
  import { Logging } from './util';
10
+ import { logError, Logger } from './util/logger';
11
+ import { LIB_VERSION } from './version';
11
12
 
12
13
  class ContensisShell {
13
14
  private currentEnvironment!: string;
@@ -39,12 +40,11 @@ class ContensisShell {
39
40
  inquirerPrompt.setConfig({
40
41
  history: {
41
42
  save: true,
42
- folder: path.join(__dirname, '../'),
43
+ folder: appRootDir,
43
44
  limit: 100,
44
45
  blacklist: ['quit'],
45
46
  },
46
47
  });
47
- // inquirer.registerPrompt('command', inquirerPrompt);
48
48
 
49
49
  const { log, messages } = this;
50
50
 
@@ -64,7 +64,7 @@ class ContensisShell {
64
64
  return;
65
65
  }
66
66
  console.log(log.successText(data));
67
- console.log(log.infoText(messages.app.startup()));
67
+ console.log(log.infoText(messages.app.startup(LIB_VERSION)));
68
68
  console.log(log.helpText(messages.app.help()));
69
69
 
70
70
  this.start().catch(ex => log.error(ex));
@@ -72,8 +72,13 @@ class ContensisShell {
72
72
  );
73
73
  }
74
74
 
75
+ restart = async () => {
76
+ this.firstStart = false;
77
+ this.log.line(); // add a line so we can see where the shell has been restarted
78
+ await this.start();
79
+ };
80
+
75
81
  start = async () => {
76
- this.log.line();
77
82
  this.refreshEnvironment();
78
83
  this.userId = '';
79
84
  const { currentEnvironment, env, log, messages } = this;
@@ -98,7 +103,10 @@ class ContensisShell {
98
103
  silent: true,
99
104
  }
100
105
  );
101
- if (token) this.userId = env.lastUserId;
106
+ if (token) {
107
+ this.userId = env.lastUserId;
108
+ if (!env.currentProject) log.warning(messages.projects.tip());
109
+ }
102
110
  this.firstStart = false;
103
111
  this.refreshEnvironment();
104
112
  } else {
@@ -127,26 +135,52 @@ class ContensisShell {
127
135
  availableCommands.push('login', 'list projects', 'set project');
128
136
  if (userId)
129
137
  availableCommands.push(
138
+ 'create key',
139
+ 'create project',
140
+ 'create role',
141
+ 'diff models',
142
+ 'execute block action release',
143
+ 'execute block action makelive',
144
+ 'execute block action rollback',
145
+ 'execute block action markasbroken',
130
146
  'get block',
131
147
  'get block logs',
132
148
  'get contenttype',
133
149
  'get component',
134
150
  'get entries',
151
+ 'get nodes',
152
+ 'get model',
153
+ 'get project',
154
+ 'get role',
155
+ 'get token',
156
+ 'get version',
157
+ 'get webhook',
135
158
  'import contenttypes',
136
159
  'import components',
137
160
  'import entries',
161
+ 'import models',
138
162
  'list blocks',
139
163
  'list contenttypes',
140
164
  'list components',
141
- 'list models',
142
165
  'list keys',
166
+ 'list models',
167
+ 'list proxies',
168
+ 'list renderers',
169
+ 'list roles',
143
170
  'list webhooks',
144
- 'create key',
145
171
  'push block',
146
- 'remove key',
147
- 'remove entry',
172
+ 'remove components',
148
173
  'remove contenttypes',
149
- 'remove components'
174
+ 'remove key',
175
+ 'remove entries',
176
+ 'remove role',
177
+ 'set project name',
178
+ 'set project description',
179
+ 'set role name',
180
+ 'set role description',
181
+ 'set role assignments',
182
+ 'set role enabled',
183
+ 'set role permissions'
150
184
  );
151
185
 
152
186
  const prompt = inquirer.createPromptModule();
@@ -155,7 +189,7 @@ class ContensisShell {
155
189
  {
156
190
  type: 'command',
157
191
  name: 'cmd',
158
- autoCompletion: availableCommands,
192
+ autoCompletion: availableCommands.sort(),
159
193
  autocompletePrompt: log.infoText(messages.app.autocomplete()),
160
194
  message: `${userId ? `${userId}@` : ''}${currentEnvironment || ''}>`,
161
195
  context: 0,
@@ -168,7 +202,7 @@ class ContensisShell {
168
202
  return true;
169
203
  }
170
204
  },
171
- prefix: `${env?.currentProject || 'contensis'}`,
205
+ prefix: `${env?.currentProject || log.infoText('contensis')}`,
172
206
  short: true,
173
207
  },
174
208
  ])
@@ -191,7 +225,14 @@ class ContensisShell {
191
225
  } catch (ex: any) {
192
226
  const str = ex.toString();
193
227
  if (!str.includes('CommanderError'))
194
- logError(ex, `Shell ${ex.toString()}`);
228
+ logError(
229
+ ex,
230
+ `Shell ${
231
+ ex instanceof Error
232
+ ? ex.toString()
233
+ : JSON.stringify(ex, null, 2)
234
+ }`
235
+ );
195
236
  } finally {
196
237
  return this.contensisPrompt();
197
238
  }
@@ -221,7 +262,14 @@ class ContensisShell {
221
262
  let globalShell: ContensisShell;
222
263
 
223
264
  export const shell = () => {
224
- if (typeof process.argv?.[2] !== 'undefined') return { start() {} } as any;
265
+ // Return a benign function for shell().restart() when used in cli context
266
+ // as some commands need to restart the shell to show an updated prompt
267
+ // after successful connect / login / set project
268
+ if (typeof process.argv?.[2] !== 'undefined')
269
+ return {
270
+ quit: ContensisCli.quit,
271
+ restart() {},
272
+ } as any;
225
273
  if (!globalShell) globalShell = new ContensisShell();
226
274
  return globalShell;
227
275
  };
@@ -232,12 +280,14 @@ process.on('uncaughtException', function (err) {
232
280
  });
233
281
 
234
282
  process.on('SIGINT', () => {
235
- console.log('catching SIGINT');
283
+ Logger.warning('received SIGINT');
236
284
  shell().quit();
285
+ // setTimeout(() => {
286
+ // }, 2000);
237
287
  });
238
288
 
239
289
  process.on('SIGTERM', () => {
240
- console.log('catching SIGTERM');
290
+ Logger.warning('received SIGTERM');
241
291
  shell().quit();
242
292
  });
243
293