contensis-cli 1.0.0-beta.82 → 1.0.0-beta.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/dev.js +68 -0
- package/dist/commands/dev.js.map +7 -0
- package/dist/commands/index.js +6 -0
- package/dist/commands/index.js.map +2 -2
- package/dist/localisation/en-GB.js +52 -0
- package/dist/localisation/en-GB.js.map +2 -2
- package/dist/providers/file-provider.js +4 -2
- package/dist/providers/file-provider.js.map +2 -2
- package/dist/services/ContensisCliService.js +10 -8
- package/dist/services/ContensisCliService.js.map +2 -2
- package/dist/services/ContensisDevService.js +203 -0
- package/dist/services/ContensisDevService.js.map +7 -0
- package/dist/shell.js +7 -5
- package/dist/shell.js.map +2 -2
- package/dist/util/git.js +119 -0
- package/dist/util/git.js.map +7 -0
- package/dist/util/os.js +39 -0
- package/dist/util/os.js.map +7 -0
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +8 -2
- package/src/commands/dev.ts +59 -0
- package/src/commands/index.ts +6 -0
- package/src/localisation/en-GB.ts +85 -0
- package/src/models/JsModules.d.ts +1 -0
- package/src/providers/file-provider.ts +5 -2
- package/src/services/ContensisCliService.ts +47 -22
- package/src/services/ContensisDevService.ts +243 -0
- package/src/shell.ts +8 -3
- package/src/util/git.ts +118 -0
- package/src/util/os.ts +7 -0
- package/src/version.ts +1 -1
package/src/commands/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Logger } from '~/util/logger';
|
|
|
3
3
|
import { LIB_VERSION } from '~/version';
|
|
4
4
|
import { makeConnectCommand } from './connect';
|
|
5
5
|
import { makeCreateCommand } from './create';
|
|
6
|
+
import { makeDevCommand } from './dev';
|
|
6
7
|
import { makeDiffCommand } from './diff';
|
|
7
8
|
import { makeExecuteCommand } from './execute';
|
|
8
9
|
import { makeGetCommand } from './get';
|
|
@@ -49,6 +50,11 @@ const commands = () => {
|
|
|
49
50
|
program.addCommand(
|
|
50
51
|
addGlobalOptions(makeCreateCommand()).copyInheritedSettings(program)
|
|
51
52
|
);
|
|
53
|
+
program.addCommand(
|
|
54
|
+
addConnectOptions(
|
|
55
|
+
addAuthenticationOptions(makeDevCommand())
|
|
56
|
+
).copyInheritedSettings(program)
|
|
57
|
+
);
|
|
52
58
|
program.addCommand(
|
|
53
59
|
addGlobalOptions(makeExecuteCommand()).copyInheritedSettings(program)
|
|
54
60
|
);
|
|
@@ -4,7 +4,9 @@ import {
|
|
|
4
4
|
MigrateModelsResult,
|
|
5
5
|
MigrateStatus,
|
|
6
6
|
} from 'migratortron';
|
|
7
|
+
import { GitHelper } from '~/util/git';
|
|
7
8
|
import { Logger } from '~/util/logger';
|
|
9
|
+
import { winSlash } from '~/util/os';
|
|
8
10
|
|
|
9
11
|
export const LogMessages = {
|
|
10
12
|
app: {
|
|
@@ -411,4 +413,87 @@ export const LogMessages = {
|
|
|
411
413
|
id
|
|
412
414
|
)}`,
|
|
413
415
|
},
|
|
416
|
+
devinit: {
|
|
417
|
+
intro: () => `Contensis developer environment initialisation`,
|
|
418
|
+
//`This will initialise your local working directory to develop with the current connected Contensis project`,
|
|
419
|
+
projectDetails: (
|
|
420
|
+
name: string,
|
|
421
|
+
env: string,
|
|
422
|
+
projectId: string,
|
|
423
|
+
git: GitHelper
|
|
424
|
+
) =>
|
|
425
|
+
`Project: ${Logger.highlightText(name)} set arg --name to override
|
|
426
|
+
- Home: ${Logger.standardText(process.cwd())}
|
|
427
|
+
- Repository: ${git.home}
|
|
428
|
+
|
|
429
|
+
Connect to Contensis instance: ${Logger.standardText(env)}
|
|
430
|
+
- Project id: ${Logger.standardText(projectId)}`,
|
|
431
|
+
developmentKey: (name: string, existing: boolean) =>
|
|
432
|
+
` - ${
|
|
433
|
+
!existing ? 'Create development API key' : 'Development API key found'
|
|
434
|
+
}: ${Logger[!existing ? 'highlightText' : 'standardText'](name)}`,
|
|
435
|
+
deploymentKey: (name: string, existing: boolean) =>
|
|
436
|
+
` - ${
|
|
437
|
+
!existing ? 'Create deployment API key' : 'Deployment API key found'
|
|
438
|
+
}: ${Logger[!existing ? 'highlightText' : 'standardText'](name)}`,
|
|
439
|
+
ciIntro: (git: GitHelper) =>
|
|
440
|
+
`We will create API keys with permissions to use this project with Contensis, and add a job to your CI that will deploy a container build. We will ask you to add secrets/variables to your git repository to give your workflow permission to push a Block to Contensis.
|
|
441
|
+
|
|
442
|
+
You could visit ${git.secretsUri} to check that you can see repository settings`,
|
|
443
|
+
ciDetails: (filename: string) =>
|
|
444
|
+
`Add push-block job to CI file: ${Logger.highlightText(filename)}\n`,
|
|
445
|
+
confirm: () =>
|
|
446
|
+
`Confirm these details are correct so we can make changes to your project`,
|
|
447
|
+
accessTokenPrompt: () =>
|
|
448
|
+
`Please supply the access token for the Delivery API (optional)`,
|
|
449
|
+
createDevKey: (keyName: string, existing: boolean) =>
|
|
450
|
+
`${
|
|
451
|
+
!existing ? 'Created' : 'Checked permissions for'
|
|
452
|
+
} development API key ${Logger.standardText(keyName)}`,
|
|
453
|
+
createDeployKey: (keyName: string, existing: boolean) =>
|
|
454
|
+
`${
|
|
455
|
+
!existing ? 'Created' : 'Checked permissions for'
|
|
456
|
+
} deployment API key ${Logger.standardText(keyName)}`,
|
|
457
|
+
createKeyFail: (keyName: string, existing: boolean) =>
|
|
458
|
+
`Failed to ${
|
|
459
|
+
!existing ? 'create' : 'update'
|
|
460
|
+
} API key ${Logger.highlightText(keyName)}`,
|
|
461
|
+
writeEnvFile: () => `Written .env file to project home directory`,
|
|
462
|
+
useEnvFileTip: () =>
|
|
463
|
+
`You should alter existing project code that connects a Contensis client to use the variables from this file`,
|
|
464
|
+
writeCiFile: (ciFilePath: string) =>
|
|
465
|
+
`Updated CI file ${Logger.standardText(winSlash(ciFilePath))}`,
|
|
466
|
+
ciBlockTip: (blockId: string, env: string, projectId: string) =>
|
|
467
|
+
`A job is included to deploy your built container image to ${Logger.standardText(
|
|
468
|
+
projectId
|
|
469
|
+
)} at ${Logger.standardText(env)} in a block called ${Logger.standardText(
|
|
470
|
+
blockId
|
|
471
|
+
)}`,
|
|
472
|
+
addGitSecretsIntro: () =>
|
|
473
|
+
`We have ceated an API key that allows you to deploy your app image to a Contensis Block but we need you to add these details to your GitLab repository.`,
|
|
474
|
+
addGitSecretsHelp: (git: GitHelper, id: string, secret: string) =>
|
|
475
|
+
`Add secrets or variables in your repository's settings page\n\nGo to ${Logger.highlightText(
|
|
476
|
+
git.secretsUri
|
|
477
|
+
)}\n\n${
|
|
478
|
+
git.type === 'github'
|
|
479
|
+
? `Add a "New repository secret"`
|
|
480
|
+
: `Expand "Variables" and hit "Add variable"`
|
|
481
|
+
}\n\n ${
|
|
482
|
+
git.type === 'github' ? `Secret name:` : `Key:`
|
|
483
|
+
} ${Logger.highlightText(`CONTENSIS_CLIENT_ID`)}\n ${
|
|
484
|
+
git.type === 'github' ? `Secret:` : `Value:`
|
|
485
|
+
} ${Logger.highlightText(
|
|
486
|
+
id
|
|
487
|
+
)}\n\n ${`Add one more secret/variable to the repository`}\n\n ${
|
|
488
|
+
git.type === 'github' ? `Secret name:` : `Key:`
|
|
489
|
+
} ${Logger.highlightText(`CONTENSIS_SHARED_SECRET`)}\n ${
|
|
490
|
+
git.type === 'github' ? `Secret:` : `Value:`
|
|
491
|
+
} ${Logger.highlightText(secret)}`,
|
|
492
|
+
success: () => `Contensis developer environment initialisation complete`,
|
|
493
|
+
partialSuccess: () =>
|
|
494
|
+
`Contensis developer environment initialisation completed with errors`,
|
|
495
|
+
failed: () => `Contensis developer environment initialisation failed`,
|
|
496
|
+
startProjectTip: () =>
|
|
497
|
+
`Start up your project in the normal way for development`,
|
|
498
|
+
},
|
|
414
499
|
};
|
|
@@ -25,14 +25,17 @@ export const readFile = (filePath: string) => {
|
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
export const readFiles = (directory: string) => {
|
|
28
|
+
export const readFiles = (directory: string, createDirectory = true) => {
|
|
29
29
|
const directoryPath = localPath(directory);
|
|
30
30
|
if (fs.existsSync(directoryPath)) {
|
|
31
31
|
const files = fs.readdirSync(directoryPath);
|
|
32
32
|
return files;
|
|
33
|
-
} else {
|
|
33
|
+
} else if (createDirectory) {
|
|
34
34
|
fs.mkdirSync(directoryPath, { recursive: true });
|
|
35
35
|
return [];
|
|
36
|
+
} else {
|
|
37
|
+
throw new Error(`ENOENT: Directory does not exist ${directoryPath}`);
|
|
38
|
+
// return undefined;
|
|
36
39
|
}
|
|
37
40
|
};
|
|
38
41
|
|
|
@@ -4,20 +4,9 @@ import fetch from 'node-fetch';
|
|
|
4
4
|
import inquirer from 'inquirer';
|
|
5
5
|
import to from 'await-to-js';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
+
|
|
7
8
|
import { Component, ContentType, Project } from 'contensis-core-api';
|
|
8
|
-
import {
|
|
9
|
-
isPassword,
|
|
10
|
-
isSharedSecret,
|
|
11
|
-
isUuid,
|
|
12
|
-
tryParse,
|
|
13
|
-
tryStringify,
|
|
14
|
-
url,
|
|
15
|
-
} from '~/util';
|
|
16
|
-
import SessionCacheProvider from '../providers/SessionCacheProvider';
|
|
17
|
-
import ContensisAuthService from './ContensisAuthService';
|
|
18
|
-
import CredentialProvider from '~/providers/CredentialProvider';
|
|
19
|
-
import { logError, Logger } from '~/util/logger';
|
|
20
|
-
import { LogMessages } from '~/localisation/en-GB';
|
|
9
|
+
import { Entry, Role } from 'contensis-management-api/lib/models';
|
|
21
10
|
import {
|
|
22
11
|
ContensisMigrationService,
|
|
23
12
|
MigrateRequest,
|
|
@@ -29,20 +18,36 @@ import {
|
|
|
29
18
|
MigrateModelsResult,
|
|
30
19
|
BlockActionType,
|
|
31
20
|
} from 'migratortron';
|
|
32
|
-
import { Entry, Role } from 'contensis-management-api/lib/models';
|
|
33
21
|
|
|
34
|
-
import
|
|
35
|
-
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
import {
|
|
22
|
+
import ContensisAuthService from './ContensisAuthService';
|
|
23
|
+
|
|
24
|
+
import { LogMessages } from '~/localisation/en-GB';
|
|
25
|
+
|
|
26
|
+
import { readJsonFile } from '~/providers/file-provider';
|
|
27
|
+
import SessionCacheProvider from '../providers/SessionCacheProvider';
|
|
28
|
+
import CredentialProvider from '~/providers/CredentialProvider';
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
isPassword,
|
|
32
|
+
isSharedSecret,
|
|
33
|
+
isUuid,
|
|
34
|
+
tryParse,
|
|
35
|
+
tryStringify,
|
|
36
|
+
url,
|
|
37
|
+
} from '~/util';
|
|
39
38
|
import {
|
|
40
39
|
printBlockVersion,
|
|
41
40
|
printMigrateResult,
|
|
42
41
|
printModelMigrationAnalysis,
|
|
43
42
|
printModelMigrationResult,
|
|
44
43
|
} from '~/util/console.printer';
|
|
45
|
-
import {
|
|
44
|
+
import { csvFormatter } from '~/util/csv.formatter';
|
|
45
|
+
import { xmlFormatter } from '~/util/xml.formatter';
|
|
46
|
+
import { jsonFormatter } from '~/util/json.formatter';
|
|
47
|
+
import { diffLogStrings } from '~/util/diff';
|
|
48
|
+
import { logError, Logger } from '~/util/logger';
|
|
49
|
+
import { promiseDelay } from '~/util/timers';
|
|
50
|
+
|
|
46
51
|
|
|
47
52
|
type OutputFormat = 'json' | 'csv' | 'xml';
|
|
48
53
|
|
|
@@ -68,6 +73,17 @@ interface IImportOptions {
|
|
|
68
73
|
sourceProjectId?: string;
|
|
69
74
|
}
|
|
70
75
|
|
|
76
|
+
export type OutputOptionsConstructorArg = OutputOptions &
|
|
77
|
+
IConnectOptions &
|
|
78
|
+
IImportOptions;
|
|
79
|
+
|
|
80
|
+
export interface ContensisCliConstructor {
|
|
81
|
+
new (
|
|
82
|
+
args: string[],
|
|
83
|
+
outputOpts?: OutputOptionsConstructorArg,
|
|
84
|
+
contensisOpts?: Partial<MigrateRequest>
|
|
85
|
+
): ContensisCli;
|
|
86
|
+
}
|
|
71
87
|
let insecurePasswordWarningShown = false;
|
|
72
88
|
|
|
73
89
|
class ContensisCli {
|
|
@@ -138,7 +154,12 @@ class ContensisCli {
|
|
|
138
154
|
|
|
139
155
|
constructor(
|
|
140
156
|
args: string[],
|
|
141
|
-
outputOpts?:
|
|
157
|
+
outputOpts?: OutputOptionsConstructorArg,
|
|
158
|
+
contensisOpts?: Partial<MigrateRequest>
|
|
159
|
+
);
|
|
160
|
+
constructor(
|
|
161
|
+
args: string[],
|
|
162
|
+
outputOpts?: OutputOptionsConstructorArg,
|
|
142
163
|
contensisOpts: Partial<MigrateRequest> = {}
|
|
143
164
|
) {
|
|
144
165
|
// console.log('args: ', JSON.stringify(args, null, 2));
|
|
@@ -1834,6 +1855,8 @@ class ContensisCli {
|
|
|
1834
1855
|
);
|
|
1835
1856
|
}
|
|
1836
1857
|
});
|
|
1858
|
+
|
|
1859
|
+
return blocks;
|
|
1837
1860
|
}
|
|
1838
1861
|
|
|
1839
1862
|
if (err) {
|
|
@@ -1878,6 +1901,8 @@ class ContensisCli {
|
|
|
1878
1901
|
: undefined
|
|
1879
1902
|
);
|
|
1880
1903
|
});
|
|
1904
|
+
|
|
1905
|
+
return blocks;
|
|
1881
1906
|
}
|
|
1882
1907
|
|
|
1883
1908
|
if (err) {
|
|
@@ -2282,7 +2307,7 @@ class ContensisCli {
|
|
|
2282
2307
|
|
|
2283
2308
|
export const cliCommand = (
|
|
2284
2309
|
commandArgs: string[],
|
|
2285
|
-
outputOpts:
|
|
2310
|
+
outputOpts: OutputOptionsConstructorArg,
|
|
2286
2311
|
contensisOpts: Partial<MigrateRequest> = {}
|
|
2287
2312
|
) => {
|
|
2288
2313
|
return new ContensisCli(['', '', ...commandArgs], outputOpts, contensisOpts);
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { execFile, spawn } from 'child_process';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
import { MigrateRequest } from 'migratortron';
|
|
6
|
+
import { stringify } from 'yaml';
|
|
7
|
+
|
|
8
|
+
import ContensisCli, {
|
|
9
|
+
OutputOptionsConstructorArg,
|
|
10
|
+
} from './ContensisCliService';
|
|
11
|
+
import { mapSiteConfigYaml } from '~/mappers/ContensisCliService-to-RequestHanderSiteConfigYaml';
|
|
12
|
+
import { appRootDir, writeFile } from '~/providers/file-provider';
|
|
13
|
+
import { jsonFormatter } from '~/util/json.formatter';
|
|
14
|
+
import { GitHelper } from '~/util/git';
|
|
15
|
+
|
|
16
|
+
class ContensisDev extends ContensisCli {
|
|
17
|
+
constructor(
|
|
18
|
+
args: string[],
|
|
19
|
+
outputOpts?: OutputOptionsConstructorArg,
|
|
20
|
+
contensisOpts: Partial<MigrateRequest> = {}
|
|
21
|
+
) {
|
|
22
|
+
super(args, outputOpts, contensisOpts);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
DevelopmentInit = async (projectHome: string, opts: any) => {
|
|
26
|
+
const { currentEnv, currentProject, log, messages } = this;
|
|
27
|
+
const contensis = await this.ConnectContensis();
|
|
28
|
+
|
|
29
|
+
if (contensis) {
|
|
30
|
+
// Retrieve keys list for env
|
|
31
|
+
const [keysErr, apiKeys] = await contensis.apiKeys.GetKeys();
|
|
32
|
+
if (keysErr) {
|
|
33
|
+
log.error(messages.keys.noList(currentEnv));
|
|
34
|
+
log.error(jsonFormatter(keysErr));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const apiKeyExists = (findKey: string) =>
|
|
38
|
+
apiKeys?.find(
|
|
39
|
+
k => k.name.trim().toLowerCase() === findKey?.trim().toLowerCase()
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Retrieve git info
|
|
43
|
+
const git = new GitHelper(projectHome);
|
|
44
|
+
|
|
45
|
+
// Retrieve ci workflow info
|
|
46
|
+
const workflowFiles = git.workflows;
|
|
47
|
+
|
|
48
|
+
// Set variables for logging etc.
|
|
49
|
+
let ciFileName = git.ciFileName;
|
|
50
|
+
|
|
51
|
+
const devKey = `${git.name} development`;
|
|
52
|
+
const deployKey = `${git.name} deployment`;
|
|
53
|
+
const blockId = git.name;
|
|
54
|
+
|
|
55
|
+
// Start render console output
|
|
56
|
+
log.raw('');
|
|
57
|
+
log.success(messages.devinit.intro());
|
|
58
|
+
log.raw('');
|
|
59
|
+
log.raw(
|
|
60
|
+
log.infoText(
|
|
61
|
+
messages.devinit.projectDetails(
|
|
62
|
+
git.name,
|
|
63
|
+
currentEnv,
|
|
64
|
+
currentProject,
|
|
65
|
+
git
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
log.raw(
|
|
70
|
+
log.infoText(
|
|
71
|
+
messages.devinit.developmentKey(devKey, !!apiKeyExists(devKey))
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
log.raw(
|
|
75
|
+
log.infoText(
|
|
76
|
+
messages.devinit.deploymentKey(deployKey, !!apiKeyExists(deployKey))
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
log.raw('');
|
|
80
|
+
|
|
81
|
+
if (Array.isArray(workflowFiles) && workflowFiles.length > 1) {
|
|
82
|
+
// Choose GitHub workflow file (if multiple)
|
|
83
|
+
({ ciFileName } = await inquirer.prompt([
|
|
84
|
+
{
|
|
85
|
+
type: 'list',
|
|
86
|
+
message: `Multiple GitHub workflow files found\n${log.infoText(
|
|
87
|
+
`Tell us which GitHub workflow builds the container image after each push:`
|
|
88
|
+
)}`,
|
|
89
|
+
name: 'ciFileName',
|
|
90
|
+
choices: workflowFiles,
|
|
91
|
+
default: workflowFiles.find(f => f.includes('docker')),
|
|
92
|
+
},
|
|
93
|
+
]));
|
|
94
|
+
log.raw('');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
log.raw(log.infoText(messages.devinit.ciDetails(ciFileName)));
|
|
98
|
+
log.help(messages.devinit.ciIntro(git));
|
|
99
|
+
|
|
100
|
+
// Confirm prompt
|
|
101
|
+
const { confirm } = await inquirer.prompt([
|
|
102
|
+
{
|
|
103
|
+
type: 'confirm',
|
|
104
|
+
message: messages.devinit.confirm(),
|
|
105
|
+
name: 'confirm',
|
|
106
|
+
default: false,
|
|
107
|
+
},
|
|
108
|
+
]);
|
|
109
|
+
log.raw('');
|
|
110
|
+
if (!confirm) return;
|
|
111
|
+
|
|
112
|
+
// Access token prompt
|
|
113
|
+
const { accessToken } = await inquirer.prompt([
|
|
114
|
+
{
|
|
115
|
+
type: 'input',
|
|
116
|
+
message: messages.devinit.accessTokenPrompt(),
|
|
117
|
+
name: 'accessToken',
|
|
118
|
+
},
|
|
119
|
+
]);
|
|
120
|
+
log.raw('');
|
|
121
|
+
|
|
122
|
+
// Magic happens...
|
|
123
|
+
|
|
124
|
+
// Arrange API keys for development and deployment
|
|
125
|
+
log.success(messages.devinit.createDevKey(devKey, false));
|
|
126
|
+
log.success(messages.devinit.createDeployKey(deployKey, true));
|
|
127
|
+
|
|
128
|
+
// Update or create a file called .env in project home
|
|
129
|
+
log.success(messages.devinit.writeEnvFile());
|
|
130
|
+
// log.help(messages.devinit.useEnvFileTip());
|
|
131
|
+
|
|
132
|
+
// Update CI file -- different for GH/GL -- create a sample one with build?
|
|
133
|
+
log.success(messages.devinit.writeCiFile(`./${ciFileName}`));
|
|
134
|
+
log.info(
|
|
135
|
+
messages.devinit.ciBlockTip(blockId, currentEnv, currentProject)
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
// Echo Deployment API key to console, ask user to add secrets to repo
|
|
139
|
+
log.warning(messages.devinit.addGitSecretsIntro());
|
|
140
|
+
log.help(
|
|
141
|
+
messages.devinit.addGitSecretsHelp(git, '123-456', '789-012-345')
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
log.success(messages.devinit.success());
|
|
145
|
+
log.help(messages.devinit.startProjectTip());
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
ExecRequestHandler = async (blockIds: string[], overrideArgs?: string[]) => {
|
|
150
|
+
// if no request handler exe
|
|
151
|
+
// download it.
|
|
152
|
+
|
|
153
|
+
// if update arg, redownload it
|
|
154
|
+
|
|
155
|
+
const { log } = this;
|
|
156
|
+
// const getPrefixOld = log.getPrefix;
|
|
157
|
+
const exeHome = path.join(appRootDir, 'reqhan');
|
|
158
|
+
const exe = 'Zengenti.Contensis.RequestHandler.LocalDevelopment';
|
|
159
|
+
const exePath = path.join(exeHome, exe);
|
|
160
|
+
const siteConfigPath = path.join(appRootDir, 'site_config.yaml');
|
|
161
|
+
|
|
162
|
+
const siteConfig = await mapSiteConfigYaml(this);
|
|
163
|
+
writeFile('site_config.yaml', stringify(siteConfig));
|
|
164
|
+
|
|
165
|
+
const args = overrideArgs
|
|
166
|
+
? typeof overrideArgs?.[0] === 'string' &&
|
|
167
|
+
overrideArgs[0].includes(' ', 2)
|
|
168
|
+
? overrideArgs[0].split(' ')
|
|
169
|
+
: overrideArgs
|
|
170
|
+
: []; // args could be [ '-c .\\site_config.yaml' ] or [ '-c', '.\\site_config.yaml' ]
|
|
171
|
+
|
|
172
|
+
// Add required args
|
|
173
|
+
if (!args.find(a => a === '-c')) args.push('-c', siteConfigPath);
|
|
174
|
+
|
|
175
|
+
// const child = execFile(exePath, args);
|
|
176
|
+
|
|
177
|
+
const child = spawn(exePath, args, { stdio: 'inherit' });
|
|
178
|
+
|
|
179
|
+
// log.raw('');
|
|
180
|
+
log.info(`Launching request handler...`);
|
|
181
|
+
if (overrideArgs?.length)
|
|
182
|
+
this.log.warning(
|
|
183
|
+
`Spawning process with supplied args: ${JSON.stringify(
|
|
184
|
+
child.spawnargs,
|
|
185
|
+
null,
|
|
186
|
+
2
|
|
187
|
+
)}`
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
let isRunning = false;
|
|
191
|
+
|
|
192
|
+
// Log child output through event listeners
|
|
193
|
+
child?.stdout?.on('data', data => {
|
|
194
|
+
isRunning = true;
|
|
195
|
+
log.raw(data);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
child?.stderr?.on('data', data => {
|
|
199
|
+
log.error(data);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
child.on('spawn', () => {
|
|
203
|
+
isRunning = true;
|
|
204
|
+
log.help(
|
|
205
|
+
`You may see a firewall popup requesting network access, it is safe to approve`
|
|
206
|
+
);
|
|
207
|
+
// log.getPrefix = () => Logger.infoText(`[rqh]`);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
child.on('exit', code => {
|
|
211
|
+
isRunning = false;
|
|
212
|
+
|
|
213
|
+
log[code === 0 ? 'success' : 'warning'](
|
|
214
|
+
`Request handler exited with code ${code}\n`
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
child.on('error', error => {
|
|
219
|
+
isRunning = false;
|
|
220
|
+
log.error(`Could not launch request handler due to error \n${error}`);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
224
|
+
|
|
225
|
+
// keep the method running until we can return
|
|
226
|
+
while (true === true) {
|
|
227
|
+
if (!isRunning) {
|
|
228
|
+
// log.getPrefix = getPrefixOld; // restore logger state
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
export const devCommand = (
|
|
236
|
+
commandArgs: string[],
|
|
237
|
+
outputOpts: OutputOptionsConstructorArg,
|
|
238
|
+
contensisOpts: Partial<MigrateRequest> = {}
|
|
239
|
+
) => {
|
|
240
|
+
return new ContensisDev(['', '', ...commandArgs], outputOpts, contensisOpts);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
export default ContensisDev;
|
package/src/shell.ts
CHANGED
|
@@ -258,7 +258,10 @@ export const shell = () => {
|
|
|
258
258
|
// as some commands need to restart the shell to show an updated prompt
|
|
259
259
|
// after successful connect / login / set project
|
|
260
260
|
if (typeof process.argv?.[2] !== 'undefined')
|
|
261
|
-
return {
|
|
261
|
+
return {
|
|
262
|
+
quit: ContensisCli.quit,
|
|
263
|
+
restart() {},
|
|
264
|
+
} as any;
|
|
262
265
|
if (!globalShell) globalShell = new ContensisShell();
|
|
263
266
|
return globalShell;
|
|
264
267
|
};
|
|
@@ -269,12 +272,14 @@ process.on('uncaughtException', function (err) {
|
|
|
269
272
|
});
|
|
270
273
|
|
|
271
274
|
process.on('SIGINT', () => {
|
|
272
|
-
|
|
275
|
+
Logger.warning('received SIGINT');
|
|
273
276
|
shell().quit();
|
|
277
|
+
// setTimeout(() => {
|
|
278
|
+
// }, 2000);
|
|
274
279
|
});
|
|
275
280
|
|
|
276
281
|
process.on('SIGTERM', () => {
|
|
277
|
-
|
|
282
|
+
Logger.warning('received SIGTERM');
|
|
278
283
|
shell().quit();
|
|
279
284
|
});
|
|
280
285
|
|
package/src/util/git.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
config = {} as GitConfig;
|
|
18
|
+
info: hostedGitInfo | undefined;
|
|
19
|
+
home: string | undefined;
|
|
20
|
+
|
|
21
|
+
get ciFileName() {
|
|
22
|
+
return this.workflows
|
|
23
|
+
? this.type === 'github'
|
|
24
|
+
? this.workflows.length > 1
|
|
25
|
+
? '[multiple workflows]'
|
|
26
|
+
: this.workflows?.[0]
|
|
27
|
+
: GITLAB_CI_FILENAME
|
|
28
|
+
: '[unknown]';
|
|
29
|
+
}
|
|
30
|
+
get name() {
|
|
31
|
+
return (
|
|
32
|
+
this.info?.project || this.home?.split('/').pop() || '[set arg --name]'
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
get originUrl() {
|
|
36
|
+
return this.config.remote.origin.url;
|
|
37
|
+
}
|
|
38
|
+
get secretsUri() {
|
|
39
|
+
return `${
|
|
40
|
+
this.type === 'github'
|
|
41
|
+
? `${this.home}/settings/secrets/actions`
|
|
42
|
+
: `${this.home}/-/settings/ci_cd`
|
|
43
|
+
}`;
|
|
44
|
+
}
|
|
45
|
+
get type() {
|
|
46
|
+
return this.info?.type || this.hostType();
|
|
47
|
+
}
|
|
48
|
+
get workflows() {
|
|
49
|
+
return this.type === 'github'
|
|
50
|
+
? this.githubWorkflows()
|
|
51
|
+
: this.gitlabWorkflow();
|
|
52
|
+
}
|
|
53
|
+
constructor(gitRepoPath: string = process.cwd()) {
|
|
54
|
+
this.gitRepoPath = gitRepoPath;
|
|
55
|
+
this.config = this.gitConfig();
|
|
56
|
+
this.home = giturl.parse(this.originUrl);
|
|
57
|
+
this.info = this.gitInfo();
|
|
58
|
+
// console.log(this.config);
|
|
59
|
+
// console.log(this.home);
|
|
60
|
+
// console.log(this.info);
|
|
61
|
+
}
|
|
62
|
+
gitcwd = () => path.join(this.gitRepoPath);
|
|
63
|
+
gitInfo = (url: string = this.originUrl) => hostedGitInfo.fromUrl(url);
|
|
64
|
+
hostType = (url: string = this.originUrl): GitTypes => {
|
|
65
|
+
if (url.includes('github.com')) return 'github';
|
|
66
|
+
return 'gitlab';
|
|
67
|
+
// if (url.includes('gitlab.com')) return 'gl';
|
|
68
|
+
// if (url.includes('gitlab.zengenti.com')) return 'gl';
|
|
69
|
+
};
|
|
70
|
+
gitConfig = (cwd = this.gitRepoPath) => {
|
|
71
|
+
// Find .git/config in project cwd
|
|
72
|
+
const config = parseGitConfig.sync({
|
|
73
|
+
path: '.git/config',
|
|
74
|
+
expandKeys: true,
|
|
75
|
+
});
|
|
76
|
+
// console.log(cwd, config);
|
|
77
|
+
if (Object.keys(config || {}).length) return config;
|
|
78
|
+
|
|
79
|
+
// Recursively check the directory heirarchy for existance of a .git/config
|
|
80
|
+
const pathParts = linuxSlash(cwd).split('/');
|
|
81
|
+
for (let i = 1; i <= pathParts.length; i++) {
|
|
82
|
+
const relPath = `${Array(i).fill('..').join('/')}/.git/config`;
|
|
83
|
+
// Does not appear to work when using a shortened cwd, using relative path instead
|
|
84
|
+
const config = parseGitConfig.sync({
|
|
85
|
+
path: relPath,
|
|
86
|
+
expandKeys: true,
|
|
87
|
+
});
|
|
88
|
+
// console.log(relPath, config);
|
|
89
|
+
if (Object.keys(config || {}).length) {
|
|
90
|
+
this.gitRepoPath = path.join(
|
|
91
|
+
this.gitRepoPath,
|
|
92
|
+
Array(i).fill('..').join('/')
|
|
93
|
+
);
|
|
94
|
+
return config;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return config;
|
|
98
|
+
};
|
|
99
|
+
githubWorkflows = () => {
|
|
100
|
+
const workflowPath = path.join(this.gitcwd(), '.github/workflows');
|
|
101
|
+
const workflowFiles = readFiles(workflowPath, false);
|
|
102
|
+
// console.log('gh workflows: ', workflowFiles);
|
|
103
|
+
const addFolderSuffix = (files: string[]) =>
|
|
104
|
+
files.map(f => `.github/workflows/${f}`);
|
|
105
|
+
|
|
106
|
+
if (workflowFiles.some(f => f.includes('build')))
|
|
107
|
+
return addFolderSuffix(workflowFiles.filter(f => f.includes('build')));
|
|
108
|
+
return addFolderSuffix(workflowFiles);
|
|
109
|
+
};
|
|
110
|
+
gitlabWorkflow = (ciFileName = GITLAB_CI_FILENAME) => {
|
|
111
|
+
const workflowPath = this.gitcwd();
|
|
112
|
+
const workflowFilePath = path.join(workflowPath, ciFileName);
|
|
113
|
+
const workflowFile = readFile(workflowFilePath);
|
|
114
|
+
// console.log(ciFileName, workflowFile);
|
|
115
|
+
|
|
116
|
+
return workflowFile;
|
|
117
|
+
};
|
|
118
|
+
}
|
package/src/util/os.ts
ADDED
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = "1.0.0-beta.
|
|
1
|
+
export const LIB_VERSION = "1.0.0-beta.84";
|