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
|
@@ -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,113 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Change, diffLines } from 'diff';
|
|
3
|
+
import { add } from 'lodash';
|
|
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) + 1 || 0;
|
|
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 diff = diffLines(existingContent, newContent, { newlineIsToken: true });
|
|
28
|
+
const diffRanges = addDiffPositionInfo(diff);
|
|
29
|
+
|
|
30
|
+
// Create formatted output for console
|
|
31
|
+
const output: string[] = [];
|
|
32
|
+
const lnSpaceLength = Math.max(
|
|
33
|
+
...diffRanges.map(d => d.startLineNumber.toString().length)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const lnSpaces = Array(lnSpaceLength).join(' ');
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < diffRanges.length; i++) {
|
|
39
|
+
const part = diffRanges[i];
|
|
40
|
+
if (part.added || part.removed) {
|
|
41
|
+
const colour = part.added ? 'green' : part.removed ? 'red' : 'grey';
|
|
42
|
+
|
|
43
|
+
if (part.value !== '\n')
|
|
44
|
+
output.push(
|
|
45
|
+
`\n${part.value
|
|
46
|
+
.split('\n')
|
|
47
|
+
.map((ln, idx) =>
|
|
48
|
+
ln.trim() !== ''
|
|
49
|
+
? `${
|
|
50
|
+
part.startLineNumber ? part.startLineNumber + idx : lnSpaces
|
|
51
|
+
}${part.added ? '+' : part.removed ? '-' : ' '} ${chalk[
|
|
52
|
+
colour
|
|
53
|
+
](`${ln}`)}`
|
|
54
|
+
: ln
|
|
55
|
+
)
|
|
56
|
+
.join('\n')}`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return output.join('');
|
|
62
|
+
// return retOutput.endsWith('\n') ? retOutput : `${retOutput}\n`;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const addDiffPositionInfo = (diff: Change[]) => {
|
|
66
|
+
const diffRanges: (Change & {
|
|
67
|
+
startLineNumber: number;
|
|
68
|
+
startColumn: number;
|
|
69
|
+
endLineNumber: number;
|
|
70
|
+
endColumn: number;
|
|
71
|
+
})[] = [];
|
|
72
|
+
|
|
73
|
+
let lineNumber = 0;
|
|
74
|
+
let column = 0;
|
|
75
|
+
for (let partIndex = 0; partIndex < diff.length; partIndex++) {
|
|
76
|
+
const part = diff[partIndex];
|
|
77
|
+
|
|
78
|
+
// // Skip any parts that aren't in `after`
|
|
79
|
+
// if (part.removed === true) {
|
|
80
|
+
// continue;
|
|
81
|
+
// }
|
|
82
|
+
|
|
83
|
+
const startLineNumber = lineNumber;
|
|
84
|
+
const startColumn = column;
|
|
85
|
+
|
|
86
|
+
// Split the part into lines. Loop throug these lines to find
|
|
87
|
+
// the line no. and column at the end of this part.
|
|
88
|
+
const substring = part.value;
|
|
89
|
+
const lines = substring.split('\n');
|
|
90
|
+
lines.forEach((line, lineIndex) => {
|
|
91
|
+
// The first `line` is actually just a continuation of the last line
|
|
92
|
+
if (lineIndex === 0) {
|
|
93
|
+
column += line.length;
|
|
94
|
+
// All other lines come after a line break.
|
|
95
|
+
} else if (lineIndex > 0) {
|
|
96
|
+
lineNumber += 1;
|
|
97
|
+
column = line.length;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Save a range for all of the parts with position info added
|
|
102
|
+
if (part.added === true || part.removed === true) {
|
|
103
|
+
diffRanges.push({
|
|
104
|
+
startLineNumber: startLineNumber + 1,
|
|
105
|
+
startColumn: startColumn,
|
|
106
|
+
endLineNumber: lineNumber,
|
|
107
|
+
endColumn: column,
|
|
108
|
+
...part,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return diffRanges;
|
|
113
|
+
};
|
|
@@ -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
|
+
};
|
package/src/util/find.ts
ADDED
package/src/util/git.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import giturl from 'giturl';
|
|
2
|
+
import hostedGitInfo from 'hosted-git-info';
|
|
3
|
+
import parseGitConfig from 'parse-git-config';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
import { linuxSlash } from './os';
|
|
7
|
+
import { readFile, readFiles } from '~/providers/file-provider';
|
|
8
|
+
|
|
9
|
+
const GITLAB_CI_FILENAME = '.gitlab-ci.yml';
|
|
10
|
+
|
|
11
|
+
type GitConfig = parseGitConfig.Config;
|
|
12
|
+
|
|
13
|
+
export type GitTypes = hostedGitInfo.Hosts;
|
|
14
|
+
|
|
15
|
+
export class GitHelper {
|
|
16
|
+
private gitRepoPath: string;
|
|
17
|
+
private ciFile?: string;
|
|
18
|
+
|
|
19
|
+
config = {} as GitConfig;
|
|
20
|
+
info: hostedGitInfo | undefined;
|
|
21
|
+
home: string | undefined;
|
|
22
|
+
|
|
23
|
+
set ciFileName(fileName: string) {
|
|
24
|
+
this.ciFile = fileName;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get ciFileName() {
|
|
28
|
+
return (
|
|
29
|
+
this.ciFile ||
|
|
30
|
+
(this.workflows
|
|
31
|
+
? this.type === 'github'
|
|
32
|
+
? this.workflows.length > 1
|
|
33
|
+
? '[multiple workflows]'
|
|
34
|
+
: this.workflows?.[0]
|
|
35
|
+
: GITLAB_CI_FILENAME
|
|
36
|
+
: '[unknown]')
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
get ciFilePath() {
|
|
40
|
+
return `${this.gitRepoPath}/${this.ciFileName}`;
|
|
41
|
+
}
|
|
42
|
+
get name() {
|
|
43
|
+
return (
|
|
44
|
+
this.info?.project || this.home?.split('/').pop() || '[set arg --name]'
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
get originUrl() {
|
|
48
|
+
return this.config.remote.origin.url;
|
|
49
|
+
}
|
|
50
|
+
get secretsUri() {
|
|
51
|
+
return `${
|
|
52
|
+
this.type === 'github'
|
|
53
|
+
? `${this.home}/settings/secrets/actions`
|
|
54
|
+
: `${this.home}/-/settings/ci_cd`
|
|
55
|
+
}`;
|
|
56
|
+
}
|
|
57
|
+
get type() {
|
|
58
|
+
return this.info?.type || this.hostType();
|
|
59
|
+
}
|
|
60
|
+
get workflows() {
|
|
61
|
+
return this.type === 'github'
|
|
62
|
+
? this.githubWorkflows()
|
|
63
|
+
: this.gitlabWorkflow();
|
|
64
|
+
}
|
|
65
|
+
constructor(gitRepoPath: string = process.cwd()) {
|
|
66
|
+
this.gitRepoPath = gitRepoPath;
|
|
67
|
+
this.config = this.gitConfig();
|
|
68
|
+
this.home = giturl.parse(this.originUrl);
|
|
69
|
+
this.info = this.gitInfo();
|
|
70
|
+
// console.log(this.config);
|
|
71
|
+
// console.log(this.home);
|
|
72
|
+
// console.log(this.info);
|
|
73
|
+
}
|
|
74
|
+
gitcwd = () => path.join(this.gitRepoPath);
|
|
75
|
+
gitInfo = (url: string = this.originUrl) => hostedGitInfo.fromUrl(url);
|
|
76
|
+
hostType = (url: string = this.originUrl): GitTypes => {
|
|
77
|
+
if (url.includes('github.com')) return 'github';
|
|
78
|
+
return 'gitlab';
|
|
79
|
+
// if (url.includes('gitlab.com')) return 'gl';
|
|
80
|
+
// if (url.includes('gitlab.zengenti.com')) return 'gl';
|
|
81
|
+
};
|
|
82
|
+
gitConfig = (cwd = this.gitRepoPath) => {
|
|
83
|
+
// Find .git/config in project cwd
|
|
84
|
+
const config = parseGitConfig.sync({
|
|
85
|
+
path: '.git/config',
|
|
86
|
+
expandKeys: true,
|
|
87
|
+
});
|
|
88
|
+
// console.log(cwd, config);
|
|
89
|
+
if (Object.keys(config || {}).length) return config;
|
|
90
|
+
|
|
91
|
+
// Recursively check the directory heirarchy for existance of a .git/config
|
|
92
|
+
const pathParts = linuxSlash(cwd).split('/');
|
|
93
|
+
for (let i = 1; i <= pathParts.length; i++) {
|
|
94
|
+
const relPath = `${Array(i).fill('..').join('/')}/.git/config`;
|
|
95
|
+
// Does not appear to work when using a shortened cwd, using relative path instead
|
|
96
|
+
const config = parseGitConfig.sync({
|
|
97
|
+
path: relPath,
|
|
98
|
+
expandKeys: true,
|
|
99
|
+
});
|
|
100
|
+
// console.log(relPath, config);
|
|
101
|
+
if (Object.keys(config || {}).length) {
|
|
102
|
+
this.gitRepoPath = path.join(
|
|
103
|
+
this.gitRepoPath,
|
|
104
|
+
Array(i).fill('..').join('/')
|
|
105
|
+
);
|
|
106
|
+
return config;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return config;
|
|
110
|
+
};
|
|
111
|
+
githubWorkflows = () => {
|
|
112
|
+
const workflowPath = path.join(this.gitcwd(), '.github/workflows');
|
|
113
|
+
const workflowFiles = readFiles(workflowPath, false);
|
|
114
|
+
// console.log('gh workflows: ', workflowFiles);
|
|
115
|
+
const addFolderSuffix = (files: string[]) =>
|
|
116
|
+
files.map(f => `.github/workflows/${f}`);
|
|
117
|
+
|
|
118
|
+
if (workflowFiles.some(f => f.includes('build')))
|
|
119
|
+
return addFolderSuffix(workflowFiles.filter(f => f.includes('build')));
|
|
120
|
+
return addFolderSuffix(workflowFiles);
|
|
121
|
+
};
|
|
122
|
+
gitlabWorkflow = (ciFileName = GITLAB_CI_FILENAME) => {
|
|
123
|
+
const workflowPath = this.gitcwd();
|
|
124
|
+
const workflowFilePath = path.join(workflowPath, ciFileName);
|
|
125
|
+
const workflowFile = readFile(workflowFilePath);
|
|
126
|
+
// console.log(ciFileName, workflowFile);
|
|
127
|
+
|
|
128
|
+
return workflowFile;
|
|
129
|
+
};
|
|
130
|
+
}
|
package/src/util/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import mergeWith from 'lodash/mergeWith';
|
|
2
2
|
import { Logger } from './logger';
|
|
3
|
+
import { LogMessages as enGB } from '../localisation/en-GB.js';
|
|
3
4
|
|
|
4
5
|
export const isSharedSecret = (str = '') =>
|
|
5
6
|
str.length > 80 && str.split('-').length === 3 ? str : undefined;
|
|
@@ -7,7 +8,7 @@ export const isSharedSecret = (str = '') =>
|
|
|
7
8
|
export const isPassword = (str = '') =>
|
|
8
9
|
!isSharedSecret(str) ? str : undefined;
|
|
9
10
|
|
|
10
|
-
export const tryParse = (str:
|
|
11
|
+
export const tryParse = (str: any) => {
|
|
11
12
|
try {
|
|
12
13
|
return typeof str === 'object' ? str : JSON.parse(str);
|
|
13
14
|
} catch (e) {
|
|
@@ -26,6 +27,9 @@ export const tryStringify = (obj: any) => {
|
|
|
26
27
|
}
|
|
27
28
|
};
|
|
28
29
|
|
|
30
|
+
export const isSysError = (error: any): error is Error =>
|
|
31
|
+
error?.message !== undefined && error.stack;
|
|
32
|
+
|
|
29
33
|
export const isUuid = (str: string) => {
|
|
30
34
|
// Regular expression to check if string is a valid UUID
|
|
31
35
|
const regexExp =
|
|
@@ -50,12 +54,17 @@ export const url = (alias: string, project: string) => {
|
|
|
50
54
|
};
|
|
51
55
|
|
|
52
56
|
export const Logging = async (language = 'en-GB') => {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const defaultMessages = enGB;
|
|
58
|
+
// const { LogMessages: defaultMessages } = await import(
|
|
59
|
+
// `../localisation/en-GB.js`
|
|
60
|
+
// );
|
|
61
|
+
let localisedMessages = defaultMessages;
|
|
62
|
+
|
|
63
|
+
if (language === 'en-GB') {
|
|
64
|
+
// Using a variable import e.g. `import(`../localisation/${language}.js`);`
|
|
65
|
+
// does not play well with packaged executables
|
|
66
|
+
// So we have to hard code the import for each language individually
|
|
67
|
+
}
|
|
59
68
|
return {
|
|
60
69
|
messages: mergeWith(
|
|
61
70
|
localisedMessages,
|