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.
- package/README.md +1146 -78
- package/cli.js +3 -0
- package/dist/commands/connect.js +3 -3
- package/dist/commands/connect.js.map +2 -2
- package/dist/commands/create.js +45 -10
- package/dist/commands/create.js.map +2 -2
- package/dist/commands/dev.js +75 -0
- package/dist/commands/dev.js.map +7 -0
- package/dist/commands/diff.js +57 -0
- package/dist/commands/diff.js.map +7 -0
- package/dist/commands/execute.js +103 -0
- package/dist/commands/execute.js.map +7 -0
- package/dist/commands/get.js +169 -32
- package/dist/commands/get.js.map +3 -3
- package/dist/commands/globalOptions.js +37 -12
- package/dist/commands/globalOptions.js.map +2 -2
- package/dist/commands/import.js +47 -12
- package/dist/commands/import.js.map +2 -2
- package/dist/commands/index.js +22 -2
- package/dist/commands/index.js.map +2 -2
- package/dist/commands/list.js +53 -10
- package/dist/commands/list.js.map +2 -2
- package/dist/commands/login.js +2 -2
- package/dist/commands/login.js.map +2 -2
- package/dist/commands/push.js +17 -13
- package/dist/commands/push.js.map +2 -2
- package/dist/commands/remove.js +51 -8
- package/dist/commands/remove.js.map +2 -2
- package/dist/commands/set.js +139 -12
- package/dist/commands/set.js.map +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/dist/localisation/en-GB.js +259 -49
- package/dist/localisation/en-GB.js.map +2 -2
- package/dist/mappers/ContensisCliService-to-RequestHanderSiteConfigYaml.js +56 -0
- package/dist/mappers/ContensisCliService-to-RequestHanderSiteConfigYaml.js.map +7 -0
- package/dist/mappers/DevInit-to-CIWorkflow.js +127 -0
- package/dist/mappers/DevInit-to-CIWorkflow.js.map +7 -0
- package/dist/mappers/DevInit-to-RolePermissions.js +54 -0
- package/dist/mappers/DevInit-to-RolePermissions.js.map +7 -0
- package/dist/mappers/DevRequests-to-RequestHanderSiteConfigYaml.js +56 -0
- package/dist/mappers/DevRequests-to-RequestHanderSiteConfigYaml.js.map +7 -0
- package/dist/models/CliService.d.js +17 -0
- package/dist/models/CliService.d.js.map +7 -0
- package/dist/models/DevService.d.js +17 -0
- package/dist/models/DevService.d.js.map +7 -0
- package/dist/providers/CredentialProvider.js +46 -14
- package/dist/providers/CredentialProvider.js.map +3 -3
- package/dist/providers/SessionCacheProvider.js +21 -1
- package/dist/providers/SessionCacheProvider.js.map +2 -2
- package/dist/providers/file-provider.js +12 -6
- package/dist/providers/file-provider.js.map +3 -3
- package/dist/services/ContensisCliService.js +1148 -421
- package/dist/services/ContensisCliService.js.map +3 -3
- package/dist/services/ContensisDevService.js +309 -0
- package/dist/services/ContensisDevService.js.map +7 -0
- package/dist/services/ContensisRoleService.js +87 -0
- package/dist/services/ContensisRoleService.js.map +7 -0
- package/dist/shell.js +58 -18
- package/dist/shell.js.map +3 -3
- package/dist/util/console.printer.js +171 -55
- package/dist/util/console.printer.js.map +2 -2
- package/dist/util/diff.js +102 -0
- package/dist/util/diff.js.map +7 -0
- package/dist/util/dotenv.js +57 -0
- package/dist/util/dotenv.js.map +7 -0
- package/dist/util/find.js +31 -0
- package/dist/util/find.js.map +7 -0
- package/dist/util/git.js +126 -0
- package/dist/util/git.js.map +7 -0
- package/dist/util/index.js +8 -2
- package/dist/util/index.js.map +3 -3
- package/dist/util/logger.js +90 -29
- package/dist/util/logger.js.map +3 -3
- package/dist/util/os.js +39 -0
- package/dist/util/os.js.map +7 -0
- package/dist/util/timers.js +49 -0
- package/dist/util/timers.js.map +7 -0
- package/dist/util/yaml.js +45 -0
- package/dist/util/yaml.js.map +7 -0
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/esbuild.config.js +3 -1
- package/package.json +12 -3
- package/src/commands/connect.ts +3 -2
- package/src/commands/create.ts +61 -8
- package/src/commands/dev.ts +69 -0
- package/src/commands/diff.ts +41 -0
- package/src/commands/execute.ts +117 -0
- package/src/commands/get.ts +242 -28
- package/src/commands/globalOptions.ts +42 -12
- package/src/commands/import.ts +58 -8
- package/src/commands/index.ts +22 -1
- package/src/commands/list.ts +85 -11
- package/src/commands/login.ts +2 -1
- package/src/commands/push.ts +18 -11
- package/src/commands/remove.ts +66 -4
- package/src/commands/set.ts +189 -9
- package/src/index.ts +1 -4
- package/src/localisation/en-GB.ts +374 -66
- package/src/mappers/ContensisCliService-to-RequestHanderSiteConfigYaml.ts +44 -0
- package/src/mappers/DevInit-to-CIWorkflow.ts +150 -0
- package/src/mappers/DevInit-to-RolePermissions.ts +33 -0
- package/src/mappers/DevRequests-to-RequestHanderSiteConfigYaml.ts +44 -0
- package/src/models/CliService.d.ts +36 -0
- package/src/models/DevService.d.ts +5 -0
- package/src/models/JsModules.d.ts +1 -0
- package/src/providers/CredentialProvider.ts +51 -18
- package/src/providers/SessionCacheProvider.ts +29 -2
- package/src/providers/file-provider.ts +17 -6
- package/src/services/ContensisCliService.ts +1458 -518
- package/src/services/ContensisDevService.ts +365 -0
- package/src/services/ContensisRoleService.ts +76 -0
- package/src/shell.ts +68 -18
- package/src/util/console.printer.ts +240 -78
- package/src/util/diff.ts +113 -0
- package/src/util/dotenv.ts +37 -0
- package/src/util/find.ts +8 -0
- package/src/util/git.ts +130 -0
- package/src/util/index.ts +16 -7
- package/src/util/logger.ts +145 -31
- package/src/util/os.ts +7 -0
- package/src/util/timers.ts +24 -0
- package/src/util/yaml.ts +13 -0
- 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:
|
|
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)
|
|
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
|
|
147
|
-
'remove entry',
|
|
172
|
+
'remove components',
|
|
148
173
|
'remove contenttypes',
|
|
149
|
-
'remove
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
283
|
+
Logger.warning('received SIGINT');
|
|
236
284
|
shell().quit();
|
|
285
|
+
// setTimeout(() => {
|
|
286
|
+
// }, 2000);
|
|
237
287
|
});
|
|
238
288
|
|
|
239
289
|
process.on('SIGTERM', () => {
|
|
240
|
-
|
|
290
|
+
Logger.warning('received SIGTERM');
|
|
241
291
|
shell().quit();
|
|
242
292
|
});
|
|
243
293
|
|