contensis-cli 1.0.0-beta.10 → 1.0.0-beta.100
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 +71 -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 +65 -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 +297 -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 +374 -0
- package/dist/mappers/DevInit-to-CIWorkflow.js.map +7 -0
- package/dist/mappers/DevInit-to-RolePermissions.js +56 -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 +1211 -420
- package/dist/services/ContensisCliService.js.map +3 -3
- package/dist/services/ContensisDevService.js +368 -0
- package/dist/services/ContensisDevService.js.map +7 -0
- package/dist/services/ContensisRoleService.js +114 -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 +116 -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 +128 -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 +42 -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 +14 -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 +83 -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 +428 -66
- package/src/mappers/ContensisCliService-to-RequestHanderSiteConfigYaml.ts +44 -0
- package/src/mappers/DevInit-to-CIWorkflow.ts +526 -0
- package/src/mappers/DevInit-to-RolePermissions.ts +32 -0
- package/src/mappers/DevRequests-to-RequestHanderSiteConfigYaml.ts +44 -0
- package/src/models/CliService.d.ts +36 -0
- package/src/models/DevService.d.ts +40 -0
- package/src/models/JsModules.d.ts +2 -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 +1532 -508
- package/src/services/ContensisDevService.ts +434 -0
- package/src/services/ContensisRoleService.ts +108 -0
- package/src/shell.ts +68 -18
- package/src/util/console.printer.ts +240 -78
- package/src/util/diff.ts +124 -0
- package/src/util/dotenv.ts +37 -0
- package/src/util/find.ts +8 -0
- package/src/util/git.ts +131 -0
- package/src/util/index.ts +16 -7
- package/src/util/logger.ts +145 -31
- package/src/util/os.ts +12 -0
- package/src/util/timers.ts +24 -0
- package/src/util/yaml.ts +13 -0
- package/src/version.ts +1 -1
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
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
|
-
import { BlockVersion, MigrateStatus } from 'migratortron';
|
|
2
|
+
import { BlockVersion, MigrateModelsResult, MigrateStatus } from 'migratortron';
|
|
3
3
|
import ContensisCli from '~/services/ContensisCliService';
|
|
4
|
+
import { Logger } from './logger';
|
|
4
5
|
|
|
5
6
|
const formatDate = (date: Date | string, format = 'DD/MM/YYYY HH:mm') =>
|
|
6
7
|
dayjs(date).format(format);
|
|
@@ -104,57 +105,22 @@ export const printBlockVersion = (
|
|
|
104
105
|
};
|
|
105
106
|
|
|
106
107
|
export const printMigrateResult = (
|
|
107
|
-
{ log, messages,
|
|
108
|
+
{ log, messages, currentProject }: ContensisCli,
|
|
108
109
|
migrateResult: any,
|
|
109
|
-
{
|
|
110
|
+
{
|
|
111
|
+
action = 'import',
|
|
112
|
+
showDiff = false,
|
|
113
|
+
showAllEntries = false,
|
|
114
|
+
showChangedEntries = false,
|
|
115
|
+
}: {
|
|
116
|
+
action?: 'import' | 'delete';
|
|
117
|
+
showDiff?: boolean;
|
|
118
|
+
showAllEntries?: boolean;
|
|
119
|
+
showChangedEntries?: boolean;
|
|
120
|
+
} = {}
|
|
110
121
|
) => {
|
|
111
122
|
console.log(``);
|
|
112
123
|
|
|
113
|
-
if (action === 'import') {
|
|
114
|
-
for (const [projectId, contentTypeCounts] of Object.entries(
|
|
115
|
-
migrateResult.entries || {}
|
|
116
|
-
) as [string, any][]) {
|
|
117
|
-
console.log(
|
|
118
|
-
`import from project ${log.highlightText(projectId)} to ${log.boldText(
|
|
119
|
-
log.successText(currentProject)
|
|
120
|
-
)}`
|
|
121
|
-
);
|
|
122
|
-
for (const [contentTypeId, count] of Object.entries(
|
|
123
|
-
contentTypeCounts
|
|
124
|
-
) as [string, number][]) {
|
|
125
|
-
const entriesToMigrate =
|
|
126
|
-
migrateResult.entriesToMigrate?.[projectId]?.[contentTypeId];
|
|
127
|
-
|
|
128
|
-
console.log(
|
|
129
|
-
` - ${
|
|
130
|
-
contentTypeId === 'totalCount'
|
|
131
|
-
? log.warningText(`${contentTypeId}: ${count}`)
|
|
132
|
-
: log.helpText(`${contentTypeId}: ${count}`)
|
|
133
|
-
} ${log.infoText`[existing: ${(
|
|
134
|
-
((migrateResult.existing?.[projectId]?.[contentTypeId] || 0) /
|
|
135
|
-
count) *
|
|
136
|
-
100
|
|
137
|
-
).toFixed(0)}%]`} [${
|
|
138
|
-
typeof entriesToMigrate !== 'number' ? `unchanged` : `to update`
|
|
139
|
-
}: ${(
|
|
140
|
-
((typeof entriesToMigrate !== 'number'
|
|
141
|
-
? entriesToMigrate?.['no change'] || 0
|
|
142
|
-
: entriesToMigrate) /
|
|
143
|
-
count) *
|
|
144
|
-
100
|
|
145
|
-
).toFixed(0)}%]`
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
console.log(``);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (
|
|
152
|
-
contensis?.isPreview &&
|
|
153
|
-
migrateResult.entriesToMigrate?.[currentProject]?.totalCount > 0 &&
|
|
154
|
-
!migrateResult.errors
|
|
155
|
-
) {
|
|
156
|
-
log.help(messages.entries.commitTip());
|
|
157
|
-
}
|
|
158
124
|
for (const [contentTypeId, entryRes] of Object.entries(
|
|
159
125
|
migrateResult.entriesToMigrate.entryIds
|
|
160
126
|
) as [string, any]) {
|
|
@@ -162,42 +128,238 @@ export const printMigrateResult = (
|
|
|
162
128
|
string,
|
|
163
129
|
any
|
|
164
130
|
][]) {
|
|
131
|
+
if (
|
|
132
|
+
showAllEntries ||
|
|
133
|
+
(showChangedEntries &&
|
|
134
|
+
(
|
|
135
|
+
Object.entries(
|
|
136
|
+
Object.entries(entryStatus[currentProject])[0]
|
|
137
|
+
)[1][1] as any
|
|
138
|
+
).status !== 'no change')
|
|
139
|
+
) {
|
|
140
|
+
console.log(
|
|
141
|
+
log.infoText(
|
|
142
|
+
`${originalId} ${Object.entries(entryStatus || {})
|
|
143
|
+
.filter(x => x[0] !== 'entryTitle')
|
|
144
|
+
.map(([projectId, projectStatus]) => {
|
|
145
|
+
const [targetGuid, { status }] = (Object.entries(
|
|
146
|
+
projectStatus || {}
|
|
147
|
+
)?.[0] as [string, { status: MigrateStatus }]) || [
|
|
148
|
+
'',
|
|
149
|
+
{ x: { status: undefined } },
|
|
150
|
+
];
|
|
151
|
+
return `${messages.migrate.status(status)(`${status}`)}${
|
|
152
|
+
targetGuid !== originalId ? `-> ${targetGuid}` : ''
|
|
153
|
+
}`;
|
|
154
|
+
})}`
|
|
155
|
+
) + ` ${log.helpText(contentTypeId)} ${entryStatus.entryTitle}`
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
for (const [projectId, projectStatus] of Object.entries(
|
|
159
|
+
entryStatus
|
|
160
|
+
).filter(([key]) => key !== 'entryTitle') as [string, any][]) {
|
|
161
|
+
const [targetGuid, { error, diff, status }] = Object.entries(
|
|
162
|
+
projectStatus
|
|
163
|
+
)[0] as [string, any];
|
|
164
|
+
if (error) log.error(error);
|
|
165
|
+
if (diff && showDiff) {
|
|
166
|
+
console.log(
|
|
167
|
+
` ${log.highlightText(`diff:`)} ${log.infoText(
|
|
168
|
+
highlightDiffText(diff)
|
|
169
|
+
)}\n`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (showAllEntries || showChangedEntries) console.log(``);
|
|
177
|
+
|
|
178
|
+
for (const [projectId, contentTypeCounts] of Object.entries(
|
|
179
|
+
migrateResult.entries || {}
|
|
180
|
+
) as [string, any][]) {
|
|
181
|
+
log.help(
|
|
182
|
+
`${action} from project ${
|
|
183
|
+
action === 'delete'
|
|
184
|
+
? log.warningText(currentProject)
|
|
185
|
+
: `${log.highlightText(projectId)} to ${log.boldText(
|
|
186
|
+
log.warningText(currentProject)
|
|
187
|
+
)}`
|
|
188
|
+
}`
|
|
189
|
+
);
|
|
190
|
+
for (const [contentTypeId, count] of Object.entries(contentTypeCounts) as [
|
|
191
|
+
string,
|
|
192
|
+
number
|
|
193
|
+
][]) {
|
|
194
|
+
const isTotalCountRow = contentTypeId === 'totalCount';
|
|
195
|
+
const migrateStatusAndCount =
|
|
196
|
+
migrateResult.entriesToMigrate[currentProject][contentTypeId];
|
|
197
|
+
const existingCount =
|
|
198
|
+
migrateResult.existing?.[currentProject]?.[contentTypeId] || 0;
|
|
199
|
+
const existingPercent = ((existingCount / count) * 100).toFixed(0);
|
|
200
|
+
const noChangeOrTotalEntriesCount =
|
|
201
|
+
typeof migrateStatusAndCount !== 'number'
|
|
202
|
+
? migrateStatusAndCount?.['no change'] || 0
|
|
203
|
+
: migrateStatusAndCount;
|
|
204
|
+
|
|
205
|
+
const changedPercentage = (
|
|
206
|
+
(noChangeOrTotalEntriesCount / count) *
|
|
207
|
+
100
|
|
208
|
+
).toFixed(0);
|
|
209
|
+
|
|
210
|
+
const existingColor =
|
|
211
|
+
existingPercent === '0' || action === 'delete'
|
|
212
|
+
? log.warningText
|
|
213
|
+
: log.infoText;
|
|
214
|
+
|
|
215
|
+
const changedColor = isTotalCountRow
|
|
216
|
+
? log.helpText
|
|
217
|
+
: changedPercentage === '100'
|
|
218
|
+
? log.successText
|
|
219
|
+
: log.warningText;
|
|
220
|
+
|
|
165
221
|
console.log(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
222
|
+
` - ${
|
|
223
|
+
isTotalCountRow
|
|
224
|
+
? log.highlightText(
|
|
225
|
+
`${contentTypeId}: ${noChangeOrTotalEntriesCount}`
|
|
226
|
+
)
|
|
227
|
+
: `${contentTypeId}: ${log.helpText(count)}`
|
|
228
|
+
}${
|
|
229
|
+
changedPercentage === '100' || isTotalCountRow
|
|
230
|
+
? ''
|
|
231
|
+
: existingColor(` [existing: ${`${existingPercent}%`}]`)
|
|
232
|
+
}${
|
|
233
|
+
existingPercent === '0' || (action === 'import' && isTotalCountRow)
|
|
234
|
+
? ''
|
|
235
|
+
: changedColor(
|
|
236
|
+
` ${
|
|
237
|
+
isTotalCountRow
|
|
238
|
+
? `[to ${action}: ${noChangeOrTotalEntriesCount}]`
|
|
239
|
+
: changedPercentage === '100'
|
|
240
|
+
? 'up to date'
|
|
241
|
+
: `[needs update: ${100 - Number(changedPercentage)}%]`
|
|
242
|
+
}`
|
|
243
|
+
)
|
|
244
|
+
}`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (migrateResult.errors?.length) {
|
|
249
|
+
console.log(
|
|
250
|
+
` - ${log.errorText(`errors: ${migrateResult.errors.length}`)}\n`
|
|
251
|
+
);
|
|
252
|
+
for (const error of migrateResult.errors)
|
|
253
|
+
log.error(error.message || error, null, '');
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const highlightDiffText = (str: string) => {
|
|
258
|
+
const addedRegex = new RegExp(/<<\+>>(.*?)<<\/\+>>/, 'g');
|
|
259
|
+
const removedRegex = new RegExp(/<<->>(.*?)<<\/->>/, 'g');
|
|
260
|
+
return str
|
|
261
|
+
.replace(addedRegex, match => {
|
|
262
|
+
return Logger.successText(
|
|
263
|
+
match.replace(/<<\+>>/g, '<+>').replace(/<<\/\+>>/g, '</+>')
|
|
264
|
+
);
|
|
265
|
+
})
|
|
266
|
+
.replace(removedRegex, match => {
|
|
267
|
+
return Logger.errorText(
|
|
268
|
+
match.replace(/<<->>/g, '<->').replace(/<<\/->>/g, '</->')
|
|
181
269
|
);
|
|
182
|
-
|
|
270
|
+
});
|
|
271
|
+
};
|
|
183
272
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
273
|
+
export const printModelMigrationAnalysis = (
|
|
274
|
+
{ log, messages }: ContensisCli,
|
|
275
|
+
result: any = {}
|
|
276
|
+
) => {
|
|
277
|
+
for (const [contentTypeId, model] of Object.entries(result) as [
|
|
278
|
+
string,
|
|
279
|
+
any
|
|
280
|
+
][]) {
|
|
281
|
+
let mainOutput = log.standardText(` - ${contentTypeId}`);
|
|
282
|
+
let extraOutput = '';
|
|
283
|
+
let errorOutput = '';
|
|
284
|
+
let diffOutput = '';
|
|
285
|
+
for (const [key, details] of Object.entries(model) as [string, any][]) {
|
|
286
|
+
if (key === 'dependencies') {
|
|
287
|
+
extraOutput += log.infoText(
|
|
288
|
+
` references: [${details?.join(', ')}]\n`
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
if (key === 'dependencyOf') {
|
|
292
|
+
extraOutput += log.infoText(
|
|
293
|
+
` required by: [${details?.join(', ')}]\n`
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
if (key === 'projects') {
|
|
297
|
+
for (const [projectId, projectDetails] of Object.entries(details) as [
|
|
298
|
+
string,
|
|
299
|
+
any
|
|
300
|
+
][]) {
|
|
301
|
+
mainOutput += log.infoText(
|
|
302
|
+
` [${messages.migrate.status(projectDetails.status)(
|
|
303
|
+
`${projectId}: ${projectDetails.status}`
|
|
304
|
+
)}] v${projectDetails.versionNo}`
|
|
196
305
|
);
|
|
197
|
-
|
|
198
|
-
|
|
306
|
+
if (projectDetails.diff)
|
|
307
|
+
diffOutput += ` ${log.highlightText(`diff:`)} ${log.infoText(
|
|
308
|
+
highlightDiffText(projectDetails.diff)
|
|
309
|
+
)}\n`;
|
|
310
|
+
if (projectDetails.error)
|
|
311
|
+
errorOutput += ` ${log.highlightText(
|
|
312
|
+
`error::`
|
|
313
|
+
)} ${log.errorText(projectDetails.error)}`;
|
|
199
314
|
}
|
|
200
315
|
}
|
|
201
316
|
}
|
|
317
|
+
console.log(mainOutput);
|
|
318
|
+
if (extraOutput) {
|
|
319
|
+
const search = '\n';
|
|
320
|
+
const replace = '';
|
|
321
|
+
console.log(
|
|
322
|
+
extraOutput.replace(
|
|
323
|
+
new RegExp(search + '([^' + search + ']*)$'),
|
|
324
|
+
replace + '$1'
|
|
325
|
+
)
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
if (diffOutput) console.log(diffOutput);
|
|
329
|
+
if (errorOutput) console.log(errorOutput);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
type MigrateResultSummary = MigrateModelsResult['']['contentTypes'];
|
|
334
|
+
type MigrateResultStatus = keyof MigrateResultSummary;
|
|
335
|
+
|
|
336
|
+
export const printModelMigrationResult = (
|
|
337
|
+
{ log, messages }: ContensisCli,
|
|
338
|
+
result: MigrateResultSummary
|
|
339
|
+
) => {
|
|
340
|
+
for (const [status, ids] of Object.entries(result) as [
|
|
341
|
+
MigrateResultStatus,
|
|
342
|
+
string[]
|
|
343
|
+
][]) {
|
|
344
|
+
if (ids?.length) {
|
|
345
|
+
if (status === 'errors') {
|
|
346
|
+
const errors: [string, MappedError][] = ids as any;
|
|
347
|
+
log.raw(
|
|
348
|
+
` - ${status}: [ ${messages.migrate.models.result(status)(
|
|
349
|
+
ids.map(id => id[0]).join(', ')
|
|
350
|
+
)} ]\n`
|
|
351
|
+
);
|
|
352
|
+
for (const [contentTypeId, error] of errors)
|
|
353
|
+
log.error(
|
|
354
|
+
`${log.highlightText(contentTypeId)}: ${error.message}`,
|
|
355
|
+
error
|
|
356
|
+
);
|
|
357
|
+
} else
|
|
358
|
+
log.raw(
|
|
359
|
+
` - ${status}: [ ${messages.migrate.models.result(status)(
|
|
360
|
+
ids.join(', ')
|
|
361
|
+
)} ]`
|
|
362
|
+
);
|
|
363
|
+
}
|
|
202
364
|
}
|
|
203
365
|
};
|
package/src/util/diff.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Change, diffLines } from 'diff';
|
|
3
|
+
import { normaliseLineEndings } from './os';
|
|
4
|
+
|
|
5
|
+
export const diffLogStrings = (updates: string, previous: string) => {
|
|
6
|
+
const lastFewLines = previous.split('\n').slice(-10);
|
|
7
|
+
const incomingLines = updates.split('\n');
|
|
8
|
+
|
|
9
|
+
// Find the line indices in the incoming lines
|
|
10
|
+
// of the last few lines previously rendered
|
|
11
|
+
const incomingLineIndices = [];
|
|
12
|
+
for (const lastRenderedLine of lastFewLines) {
|
|
13
|
+
if (lastRenderedLine.length > 10)
|
|
14
|
+
incomingLineIndices.push(incomingLines.lastIndexOf(lastRenderedLine));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Get the new lines from the next position on from the last of the already shown lines
|
|
18
|
+
const differentFromPos = Math.max(...incomingLineIndices, 0) + 1;
|
|
19
|
+
// Return just the incoming lines from the position we matched
|
|
20
|
+
return incomingLines.slice(differentFromPos).join('\n');
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const diffFileContent = (
|
|
24
|
+
existingContent: string,
|
|
25
|
+
newContent: string
|
|
26
|
+
) => {
|
|
27
|
+
const existingContentNormalised = normaliseLineEndings(existingContent, '\n');
|
|
28
|
+
const newContentNormalised = normaliseLineEndings(newContent, '\n');
|
|
29
|
+
|
|
30
|
+
const diff = diffLines(existingContentNormalised, newContentNormalised, {
|
|
31
|
+
newlineIsToken: true,
|
|
32
|
+
});
|
|
33
|
+
const diffRanges = addDiffPositionInfo(diff);
|
|
34
|
+
|
|
35
|
+
// Create formatted output for console
|
|
36
|
+
const output: string[] = [];
|
|
37
|
+
const lnSpaceLength = Math.max(
|
|
38
|
+
...diffRanges.map(d => d.startLineNumber.toString().length),
|
|
39
|
+
0
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const lnSpaces = Array(lnSpaceLength).join(' ');
|
|
43
|
+
|
|
44
|
+
let needsNewLine = false;
|
|
45
|
+
for (let i = 0; i < diffRanges.length; i++) {
|
|
46
|
+
const part = diffRanges[i];
|
|
47
|
+
if (part.added || part.removed) {
|
|
48
|
+
const colour = part.added ? 'green' : part.removed ? 'red' : 'grey';
|
|
49
|
+
|
|
50
|
+
if (part.value !== '\n') {
|
|
51
|
+
if (needsNewLine) {
|
|
52
|
+
output.push('\n### --');
|
|
53
|
+
needsNewLine = false;
|
|
54
|
+
}
|
|
55
|
+
output.push(
|
|
56
|
+
`\n${part.value
|
|
57
|
+
.split('\n')
|
|
58
|
+
.map((ln, idx) =>
|
|
59
|
+
ln.trim() !== ''
|
|
60
|
+
? `${
|
|
61
|
+
part.startLineNumber ? part.startLineNumber + idx : lnSpaces
|
|
62
|
+
}${part.added ? '+' : part.removed ? '-' : ' '} ${chalk[
|
|
63
|
+
colour
|
|
64
|
+
](`${ln}`)}`
|
|
65
|
+
: ln
|
|
66
|
+
)
|
|
67
|
+
.join('\n')}`
|
|
68
|
+
);
|
|
69
|
+
} else needsNewLine = true;
|
|
70
|
+
} else needsNewLine = true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return output.join('');
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const addDiffPositionInfo = (diff: Change[]) => {
|
|
77
|
+
const diffRanges: (Change & {
|
|
78
|
+
startLineNumber: number;
|
|
79
|
+
startColumn: number;
|
|
80
|
+
endLineNumber: number;
|
|
81
|
+
endColumn: number;
|
|
82
|
+
})[] = [];
|
|
83
|
+
|
|
84
|
+
let lineNumber = 0;
|
|
85
|
+
let column = 0;
|
|
86
|
+
for (let partIndex = 0; partIndex < diff.length; partIndex++) {
|
|
87
|
+
const part = diff[partIndex];
|
|
88
|
+
|
|
89
|
+
// // Skip any parts that aren't in `after`
|
|
90
|
+
// if (part.removed === true) {
|
|
91
|
+
// continue;
|
|
92
|
+
// }
|
|
93
|
+
|
|
94
|
+
const startLineNumber = lineNumber;
|
|
95
|
+
const startColumn = column;
|
|
96
|
+
|
|
97
|
+
// Split the part into lines. Loop throug these lines to find
|
|
98
|
+
// the line no. and column at the end of this part.
|
|
99
|
+
const substring = part.value;
|
|
100
|
+
const lines = substring.split('\n');
|
|
101
|
+
lines.forEach((line, lineIndex) => {
|
|
102
|
+
// The first `line` is actually just a continuation of the last line
|
|
103
|
+
if (lineIndex === 0) {
|
|
104
|
+
column += line.length;
|
|
105
|
+
// All other lines come after a line break.
|
|
106
|
+
} else if (lineIndex > 0) {
|
|
107
|
+
lineNumber += 1;
|
|
108
|
+
column = line.length;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Save a range for all of the parts with position info added
|
|
113
|
+
if (part.added === true || part.removed === true) {
|
|
114
|
+
diffRanges.push({
|
|
115
|
+
startLineNumber: startLineNumber + 1,
|
|
116
|
+
startColumn: startColumn,
|
|
117
|
+
endLineNumber: lineNumber,
|
|
118
|
+
endColumn: column,
|
|
119
|
+
...part,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return diffRanges;
|
|
124
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EnvContentsToAdd } from "~/models/DevService";
|
|
2
|
+
|
|
3
|
+
export const mergeDotEnvFileContents = (
|
|
4
|
+
existingFileLines: string[],
|
|
5
|
+
envContentsToAdd: EnvContentsToAdd
|
|
6
|
+
): string[] => {
|
|
7
|
+
const envFileLines: string[] = []; // the new .env file
|
|
8
|
+
if (existingFileLines.length === 0) {
|
|
9
|
+
// There is no env file, just create one from envContentsToAdd
|
|
10
|
+
envFileLines.push(
|
|
11
|
+
...Object.entries(envContentsToAdd).map(([k, v]) => `${k}=${v}`)
|
|
12
|
+
);
|
|
13
|
+
} else {
|
|
14
|
+
const updatedEnvKeys: string[] = [];
|
|
15
|
+
// Find lines in env that already exist for the keys in envContentsToAdd
|
|
16
|
+
// update them if they exist and add them to envFileLines
|
|
17
|
+
for (const ln of existingFileLines) {
|
|
18
|
+
let newline = '';
|
|
19
|
+
for (const [k, v] of Object.entries(envContentsToAdd))
|
|
20
|
+
if (ln.startsWith(`${k}=`)) {
|
|
21
|
+
newline = `${k}=${v}`;
|
|
22
|
+
updatedEnvKeys.push(k);
|
|
23
|
+
}
|
|
24
|
+
// Ensure an updated line or other lines from the existing env file are re-added
|
|
25
|
+
if (newline || ln) envFileLines.push(newline || ln);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Add the envContentsToAdd lines to the file that did not previously exist or had an update
|
|
29
|
+
for (const addKey of Object.keys(envContentsToAdd).filter(
|
|
30
|
+
efl =>
|
|
31
|
+
!updatedEnvKeys.find(uek => uek.startsWith(`${efl.split('=')?.[0]}`))
|
|
32
|
+
) as (keyof typeof envContentsToAdd)[]) {
|
|
33
|
+
envFileLines.push(`${addKey}=${envContentsToAdd[addKey]}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return envFileLines;
|
|
37
|
+
};
|