@squiz/dxp-cli-next 5.6.0-develop.1 → 5.6.0-develop.11
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/lib/ApiService.d.ts +1 -1
- package/lib/ApiService.js +5 -2
- package/lib/__tests__/integration/main.spec.js +17 -0
- package/lib/cmp/init.js +40 -2
- package/lib/dxp.js +4 -0
- package/lib/job-runner/index.d.ts +3 -0
- package/lib/job-runner/index.js +22 -0
- package/lib/job-runner/job/listJobs/listJobs.d.ts +3 -0
- package/lib/job-runner/job/listJobs/listJobs.js +64 -0
- package/lib/job-runner/job/listJobs/listJobs.spec.d.ts +1 -0
- package/lib/job-runner/job/listJobs/listJobs.spec.js +42 -0
- package/lib/job-runner/job/uploadJob/uploadJob.d.ts +3 -0
- package/lib/job-runner/job/uploadJob/uploadJob.js +52 -0
- package/lib/job-runner/job/uploadJob/uploadJob.spec.d.ts +1 -0
- package/lib/job-runner/job/uploadJob/uploadJob.spec.js +41 -0
- package/lib/job-runner/jobContext/listJobContexts.d.ts +3 -0
- package/lib/job-runner/jobContext/listJobContexts.js +71 -0
- package/lib/job-runner/jobContext/listJobContexts.spec.d.ts +1 -0
- package/lib/job-runner/jobContext/listJobContexts.spec.js +64 -0
- package/lib/job-runner/jobExecution/beginJob/beginJob.d.ts +3 -0
- package/lib/job-runner/jobExecution/beginJob/beginJob.js +66 -0
- package/lib/job-runner/jobExecution/beginJob/beginJob.spec.d.ts +1 -0
- package/lib/job-runner/jobExecution/beginJob/beginJob.spec.js +62 -0
- package/lib/job-runner/jobExecution/listJobExecutions/listJobExecutions.d.ts +3 -0
- package/lib/job-runner/jobExecution/listJobExecutions/listJobExecutions.js +65 -0
- package/lib/job-runner/jobExecution/listJobExecutions/listJobExecutions.spec.d.ts +1 -0
- package/lib/job-runner/jobExecution/listJobExecutions/listJobExecutions.spec.js +63 -0
- package/lib/job-runner/jobExecution/terminateJob/terminateJob.d.ts +3 -0
- package/lib/job-runner/jobExecution/terminateJob/terminateJob.js +62 -0
- package/lib/job-runner/jobExecution/terminateJob/terminateJob.spec.d.ts +1 -0
- package/lib/job-runner/jobExecution/terminateJob/terminateJob.spec.js +60 -0
- package/lib/job-runner/utils.d.ts +19 -0
- package/lib/job-runner/utils.js +144 -0
- package/lib/job-runner/utils.spec.d.ts +1 -0
- package/lib/job-runner/utils.spec.js +116 -0
- package/package.json +5 -2
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const nock_1 = __importDefault(require("nock"));
|
|
16
|
+
const beginJob_1 = __importDefault(require("./beginJob"));
|
|
17
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
+
const path_1 = __importDefault(require("path"));
|
|
19
|
+
const logSpy = jest.spyOn(global.console, 'log');
|
|
20
|
+
describe('beginJob', () => {
|
|
21
|
+
it('correctly displays the console logs for beginning a job', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
+
process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL = 'true';
|
|
23
|
+
(0, nock_1.default)('http://localhost:9999').post('/executions/begin').reply(200, {
|
|
24
|
+
context: 'dev',
|
|
25
|
+
ecsTaskId: null,
|
|
26
|
+
id: 'd0aab852-365e-42de-a642-eac11bb95ccc',
|
|
27
|
+
jobName: 'simple-job',
|
|
28
|
+
status: 'queued',
|
|
29
|
+
timeFinished: null,
|
|
30
|
+
timeQueued: '2023-06-23T01:36:44.792Z',
|
|
31
|
+
timeStarted: null,
|
|
32
|
+
type: 'jobExecution',
|
|
33
|
+
version: null,
|
|
34
|
+
});
|
|
35
|
+
const program = (0, beginJob_1.default)();
|
|
36
|
+
yield program.parseAsync([
|
|
37
|
+
'node',
|
|
38
|
+
'dxp-cli',
|
|
39
|
+
'simple-job',
|
|
40
|
+
'dev',
|
|
41
|
+
'-i',
|
|
42
|
+
path_1.default.join('./src/__tests__/job-runner/inputs/input.json'),
|
|
43
|
+
'-t',
|
|
44
|
+
'myTenant',
|
|
45
|
+
'-ou',
|
|
46
|
+
'http://localhost:9999',
|
|
47
|
+
]);
|
|
48
|
+
const opts = program.opts();
|
|
49
|
+
const args = program.args;
|
|
50
|
+
expect(args[0]).toEqual('simple-job');
|
|
51
|
+
expect(args[1]).toEqual('dev');
|
|
52
|
+
expect(opts.inputFile).toEqual(path_1.default.join('./src/__tests__/job-runner/inputs/input.json'));
|
|
53
|
+
expect(opts.tenant).toEqual('myTenant');
|
|
54
|
+
expect(opts.overrideUrl).toEqual('http://localhost:9999');
|
|
55
|
+
expect(logSpy).toHaveBeenCalledTimes(12);
|
|
56
|
+
expect(logSpy).toHaveBeenCalledWith(chalk_1.default.cyan('------------------------------'));
|
|
57
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('context')}: "dev"`);
|
|
58
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('id')}: "d0aab852-365e-42de-a642-eac11bb95ccc"`);
|
|
59
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('jobName')}: "simple-job"`);
|
|
60
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('timeQueued')}: "2023-06-23T01:36:44.792Z"`);
|
|
61
|
+
}));
|
|
62
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const commander_1 = require("commander");
|
|
16
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
17
|
+
const ora_1 = __importDefault(require("ora"));
|
|
18
|
+
const ApiService_1 = require("../../../ApiService");
|
|
19
|
+
const utils_1 = require("../../utils");
|
|
20
|
+
const createListJobExecutionsCommand = () => {
|
|
21
|
+
const listJobExecutionsCommand = new commander_1.Command('listJobExecutions')
|
|
22
|
+
.name('listJobExecutions')
|
|
23
|
+
.description('List all job executions')
|
|
24
|
+
.addOption(new commander_1.Option('-s, --size <string>', 'Pagination page size. Choices are tiny (5), small (20), medium (50), large (100). If not included, will default to small').choices(['tiny', 'small', 'medium', 'large']))
|
|
25
|
+
.addOption(new commander_1.Option('-b, --before <string>', 'Pagination page before token'))
|
|
26
|
+
.addOption(new commander_1.Option('-a, --after <string>', 'Pagination page after token'))
|
|
27
|
+
.addOption(new commander_1.Option('-t, --tenant <string>', 'Tenant ID to run against. If not provided will use configured tenant from login'))
|
|
28
|
+
.addArgument(new commander_1.Argument('<jobName>', 'Name of the job to pass to the request'))
|
|
29
|
+
.configureOutput({
|
|
30
|
+
outputError(str, write) {
|
|
31
|
+
write(chalk_1.default.red(str));
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
.action((jobName, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
+
yield (0, utils_1.throwErrorIfNotLoggedIn)(listJobExecutionsCommand);
|
|
36
|
+
const spinner = (0, ora_1.default)('Retrieving job executions').start();
|
|
37
|
+
try {
|
|
38
|
+
const apiService = new ApiService_1.ApiService(utils_1.validateAxiosStatus);
|
|
39
|
+
let listExecutionsUrl = `${yield (0, utils_1.buildJobRunnerUrl)(options.tenant, options.overrideUrl)}/executions/jobName/${jobName}?`;
|
|
40
|
+
listExecutionsUrl = (0, utils_1.addPaginationToUrl)(listExecutionsUrl, {
|
|
41
|
+
before: options.before,
|
|
42
|
+
after: options.after,
|
|
43
|
+
size: options.size,
|
|
44
|
+
});
|
|
45
|
+
const res = yield apiService.client.get(listExecutionsUrl);
|
|
46
|
+
if (Array.isArray(res.data.data) && res.data.data.length > 0) {
|
|
47
|
+
spinner.succeed(`Retrieved ${res.data.data.length} executions`);
|
|
48
|
+
yield (0, utils_1.logArrayResults)(res.data.data, res.data.links);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
spinner.succeed('No executions found');
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
spinner.fail();
|
|
57
|
+
(0, utils_1.handleCommandError)(listJobExecutionsCommand, error);
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
if (process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL === 'true') {
|
|
61
|
+
listJobExecutionsCommand.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire job runner url with a custom value'));
|
|
62
|
+
}
|
|
63
|
+
return listJobExecutionsCommand;
|
|
64
|
+
};
|
|
65
|
+
exports.default = createListJobExecutionsCommand;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const nock_1 = __importDefault(require("nock"));
|
|
16
|
+
const listJobExecutions_1 = __importDefault(require("./listJobExecutions"));
|
|
17
|
+
const logSpy = jest.spyOn(global.console, 'log');
|
|
18
|
+
describe('listJobExecutions', () => {
|
|
19
|
+
it('correctly lists the job executions', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL = 'true';
|
|
21
|
+
(0, nock_1.default)('http://localhost:9999')
|
|
22
|
+
.get('/executions/jobName/job-runner?&page[size]=5')
|
|
23
|
+
.reply(200, [
|
|
24
|
+
{
|
|
25
|
+
context: 'dev',
|
|
26
|
+
id: 'd0aab852-365e-42de-a642-eac11bb95ccc',
|
|
27
|
+
jobName: 'simple-job',
|
|
28
|
+
status: 'successfully-completed',
|
|
29
|
+
timeFinished: '2023-06-23T01:36:48.345Z',
|
|
30
|
+
timeQueued: '2023-06-23T01:36:44.792Z',
|
|
31
|
+
timeStarted: '2023-06-23T01:36:44.792Z',
|
|
32
|
+
type: 'jobExecution',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
context: 'dev',
|
|
36
|
+
id: 'e7e8de7c-2c5d-4a78-81d9-76c856ed6a85',
|
|
37
|
+
jobName: 'simple-job',
|
|
38
|
+
status: 'successfully-completed',
|
|
39
|
+
timeFinished: '2023-06-23T01:34:24.669Z',
|
|
40
|
+
timeQueued: '2023-06-23T01:34:23.627Z',
|
|
41
|
+
timeStarted: '2023-06-23T01:34:23.627Z',
|
|
42
|
+
type: 'jobExecution',
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
const program = (0, listJobExecutions_1.default)();
|
|
46
|
+
yield program.parseAsync([
|
|
47
|
+
'node',
|
|
48
|
+
'dxp-cli',
|
|
49
|
+
'job-runner',
|
|
50
|
+
'listJobExecutions',
|
|
51
|
+
'-s',
|
|
52
|
+
'tiny',
|
|
53
|
+
'-t',
|
|
54
|
+
'myTenant',
|
|
55
|
+
'-ou',
|
|
56
|
+
'http://localhost:9999',
|
|
57
|
+
]);
|
|
58
|
+
const opts = program.opts();
|
|
59
|
+
expect(opts.tenant).toEqual('myTenant');
|
|
60
|
+
expect(opts.overrideUrl).toEqual('http://localhost:9999');
|
|
61
|
+
expect(opts.size).toBe('tiny');
|
|
62
|
+
}));
|
|
63
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const commander_1 = require("commander");
|
|
16
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
17
|
+
const ora_1 = __importDefault(require("ora"));
|
|
18
|
+
const ApiService_1 = require("../../../ApiService");
|
|
19
|
+
const utils_1 = require("../../utils");
|
|
20
|
+
const createTerminateJobCommand = () => {
|
|
21
|
+
const terminateJobCommand = new commander_1.Command('terminateJob')
|
|
22
|
+
.name('terminateJob')
|
|
23
|
+
.description('Terminate a job in the queue')
|
|
24
|
+
.addOption(new commander_1.Option('-t, --tenant <string>', 'Tenant ID to run against. If not provided will use configured tenant from login'))
|
|
25
|
+
.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire job runner url with a custom value'))
|
|
26
|
+
.addArgument(new commander_1.Argument('<jobName>', 'Name of the job to pass to the request'))
|
|
27
|
+
.addArgument(new commander_1.Argument('<executionId>', 'Name of the job execution id to pass to the request'))
|
|
28
|
+
.addArgument(new commander_1.Argument('<reason>', 'Reason for job termination, eg "Cancelling due to mistake in inputs"'))
|
|
29
|
+
.configureOutput({
|
|
30
|
+
outputError(str, write) {
|
|
31
|
+
write(chalk_1.default.red(str));
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
.action((jobName, executionId, reason, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
+
yield (0, utils_1.throwErrorIfNotLoggedIn)(terminateJobCommand);
|
|
36
|
+
const spinner = (0, ora_1.default)('Terminating job').start();
|
|
37
|
+
console.log('');
|
|
38
|
+
try {
|
|
39
|
+
const apiService = new ApiService_1.ApiService(utils_1.validateAxiosStatus);
|
|
40
|
+
const terminateJobUrl = `${yield (0, utils_1.buildJobRunnerUrl)(options.tenant, options.overrideUrl)}/executions/terminate`;
|
|
41
|
+
const res = yield apiService.client.post(terminateJobUrl, {
|
|
42
|
+
jobName: jobName,
|
|
43
|
+
executionId: executionId,
|
|
44
|
+
reason: reason,
|
|
45
|
+
});
|
|
46
|
+
for (const [key, value] of Object.entries(res.data)) {
|
|
47
|
+
console.log(`${chalk_1.default.bold([key])}: ${JSON.stringify(value)}`);
|
|
48
|
+
}
|
|
49
|
+
spinner.succeed('Job terminated');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
spinner.fail();
|
|
54
|
+
(0, utils_1.handleCommandError)(terminateJobCommand, error);
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
if (process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL === 'true') {
|
|
58
|
+
terminateJobCommand.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire job runner url with a custom value'));
|
|
59
|
+
}
|
|
60
|
+
return terminateJobCommand;
|
|
61
|
+
};
|
|
62
|
+
exports.default = createTerminateJobCommand;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const nock_1 = __importDefault(require("nock"));
|
|
16
|
+
const terminateJob_1 = __importDefault(require("./terminateJob"));
|
|
17
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
+
const logSpy = jest.spyOn(global.console, 'log');
|
|
19
|
+
describe('terminateJob', () => {
|
|
20
|
+
process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL = 'true';
|
|
21
|
+
it('correctly displays the console logs for terminating the job', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
+
(0, nock_1.default)('http://localhost:9999').post('/executions/terminate').reply(200, {
|
|
23
|
+
context: 'dev',
|
|
24
|
+
ecsTaskId: '1233445',
|
|
25
|
+
id: 'simple-job-d6a418eb-dd63-4594-b299-07410ccd30d5',
|
|
26
|
+
jobName: 'simple-job',
|
|
27
|
+
status: 'terminated',
|
|
28
|
+
timeFinished: '2023-06-23T01:49:09.433Z',
|
|
29
|
+
timeQueued: '2023-06-23T01:49:09.431Z',
|
|
30
|
+
timeStarted: '2023-06-23T00:49:09.433Z',
|
|
31
|
+
type: 'jobExecution',
|
|
32
|
+
version: '1.0.1',
|
|
33
|
+
});
|
|
34
|
+
const program = (0, terminateJob_1.default)();
|
|
35
|
+
yield program.parseAsync([
|
|
36
|
+
'node',
|
|
37
|
+
'dxp-cli',
|
|
38
|
+
'simple-job',
|
|
39
|
+
'907fc4e5-8b4a-4e47-bab0-e95e45385347',
|
|
40
|
+
'test termination',
|
|
41
|
+
'-t',
|
|
42
|
+
'myTenant',
|
|
43
|
+
'-ou',
|
|
44
|
+
'http://localhost:9999',
|
|
45
|
+
]);
|
|
46
|
+
const opts = program.opts();
|
|
47
|
+
const args = program.args;
|
|
48
|
+
expect(args[0]).toEqual('simple-job');
|
|
49
|
+
expect(args[1]).toEqual('907fc4e5-8b4a-4e47-bab0-e95e45385347');
|
|
50
|
+
expect(opts.tenant).toEqual('myTenant');
|
|
51
|
+
expect(opts.overrideUrl).toEqual('http://localhost:9999');
|
|
52
|
+
expect(logSpy).toHaveBeenCalledTimes(11);
|
|
53
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('status')}: ${JSON.stringify('terminated')}`);
|
|
54
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('jobName')}: ${JSON.stringify('simple-job')}`);
|
|
55
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('id')}: ${JSON.stringify('simple-job-d6a418eb-dd63-4594-b299-07410ccd30d5')}`);
|
|
56
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('context')}: ${JSON.stringify('dev')}`);
|
|
57
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('timeFinished')}: ${JSON.stringify('2023-06-23T01:49:09.433Z')}`);
|
|
58
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('version')}: ${JSON.stringify('1.0.1')}`);
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export declare function handleCommandError(command: Command, error: Error): void;
|
|
3
|
+
export declare function throwErrorIfNotLoggedIn(command: Command): Promise<void>;
|
|
4
|
+
export declare function buildJobRunnerUrl(tenantID?: string, overrideUrl?: string): Promise<string>;
|
|
5
|
+
export declare function readInputFile(inputPath: string): Promise<any>;
|
|
6
|
+
export declare function writeLineSeparator(): void;
|
|
7
|
+
export declare function validateAxiosStatus(status: number): boolean;
|
|
8
|
+
export declare function addPaginationToUrl(url: string, opts: PaginationOpts): string;
|
|
9
|
+
export declare function logArrayResults(results: Array<any>, links?: PaginationLinks): Promise<void>;
|
|
10
|
+
interface PaginationLinks {
|
|
11
|
+
prev: string;
|
|
12
|
+
next: string;
|
|
13
|
+
}
|
|
14
|
+
interface PaginationOpts {
|
|
15
|
+
before: string;
|
|
16
|
+
after: string;
|
|
17
|
+
size: 'tiny' | 'small' | 'medium' | 'large';
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.logArrayResults = exports.addPaginationToUrl = exports.validateAxiosStatus = exports.writeLineSeparator = exports.readInputFile = exports.buildJobRunnerUrl = exports.throwErrorIfNotLoggedIn = exports.handleCommandError = void 0;
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
+
const ApplicationConfig_1 = require("../ApplicationConfig");
|
|
19
|
+
const axios_1 = __importDefault(require("axios"));
|
|
20
|
+
const ApplicationStore_1 = require("../ApplicationStore");
|
|
21
|
+
function handleCommandError(command, error) {
|
|
22
|
+
var _a, _b, _c, _d;
|
|
23
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
24
|
+
let message = `${error.message}`;
|
|
25
|
+
if ((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) {
|
|
26
|
+
message += `: ${error.response.data.message}`;
|
|
27
|
+
}
|
|
28
|
+
if ((_d = (_c = error.response) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.details) {
|
|
29
|
+
message += ` - ${error.response.data.details}`;
|
|
30
|
+
}
|
|
31
|
+
command.error(chalk_1.default.red(message));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
if (!!process.env.DEBUG && error.stack) {
|
|
35
|
+
command.error(error.stack);
|
|
36
|
+
}
|
|
37
|
+
if (error.message) {
|
|
38
|
+
command.error(chalk_1.default.red(error.message));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
command.error(chalk_1.default.red('An unknown error occurred'));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.handleCommandError = handleCommandError;
|
|
46
|
+
function throwErrorIfNotLoggedIn(command) {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
if (!(yield (0, ApplicationStore_1.getApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie))) {
|
|
49
|
+
command.error(chalk_1.default.red('You must login to interact with the job runner. See `dxp-next auth login`'));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
exports.throwErrorIfNotLoggedIn = throwErrorIfNotLoggedIn;
|
|
54
|
+
function buildJobRunnerUrl(tenantID, overrideUrl) {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
if (!overrideUrl) {
|
|
57
|
+
const existingConfig = yield (0, ApplicationConfig_1.fetchApplicationConfig)(tenantID);
|
|
58
|
+
return `${existingConfig.baseUrl}/__dxp/${existingConfig.region}/job-runner/${existingConfig.tenant}`;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
return overrideUrl;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
exports.buildJobRunnerUrl = buildJobRunnerUrl;
|
|
66
|
+
function readInputFile(inputPath) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
if (inputPath.endsWith('.json')) {
|
|
69
|
+
if (fs_1.default.existsSync(inputPath)) {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(fs_1.default.readFileSync(inputPath, { encoding: 'utf-8' }));
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
throw new Error(`Unable to read file ${inputPath} - ${e.message}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
throw new Error('Input could not be found');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
throw new Error('Input must be a .json file');
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
exports.readInputFile = readInputFile;
|
|
87
|
+
function writeLineSeparator() {
|
|
88
|
+
console.log(chalk_1.default.cyan('------------------------------'));
|
|
89
|
+
}
|
|
90
|
+
exports.writeLineSeparator = writeLineSeparator;
|
|
91
|
+
function validateAxiosStatus(status) {
|
|
92
|
+
return status < 400;
|
|
93
|
+
}
|
|
94
|
+
exports.validateAxiosStatus = validateAxiosStatus;
|
|
95
|
+
function addPaginationToUrl(url, opts) {
|
|
96
|
+
if (opts.before && opts.after) {
|
|
97
|
+
throw new Error('Only one of before and after can be set');
|
|
98
|
+
}
|
|
99
|
+
if (opts.size) {
|
|
100
|
+
url += `&page[size]=${PaginationPageLimit[opts.size]}`;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
`&page[size]=${PaginationPageLimit.small}`;
|
|
104
|
+
}
|
|
105
|
+
if (opts.before) {
|
|
106
|
+
url += `&page[before]=${opts.before}`;
|
|
107
|
+
}
|
|
108
|
+
if (opts.after) {
|
|
109
|
+
url += `&page[after]=${opts.after}`;
|
|
110
|
+
}
|
|
111
|
+
return url;
|
|
112
|
+
}
|
|
113
|
+
exports.addPaginationToUrl = addPaginationToUrl;
|
|
114
|
+
function logArrayResults(results, links) {
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
if (Array.isArray(results) && results.length > 0) {
|
|
117
|
+
writeLineSeparator();
|
|
118
|
+
results.forEach((res) => {
|
|
119
|
+
for (const [key, value] of Object.entries(res)) {
|
|
120
|
+
console.log(`${chalk_1.default.bold([key])}: ${JSON.stringify(value)}`);
|
|
121
|
+
}
|
|
122
|
+
writeLineSeparator();
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (links) {
|
|
126
|
+
const afterStr = 'page[after]=';
|
|
127
|
+
console.log(`${chalk_1.default.bold('nextPageToken')}: ${links.next !== null
|
|
128
|
+
? links.next.slice(links.next.lastIndexOf(afterStr) + afterStr.length)
|
|
129
|
+
: null}`);
|
|
130
|
+
const beforeStr = 'page[before]=';
|
|
131
|
+
console.log(`${chalk_1.default.bold('prevPageToken')}: ${links.prev !== null
|
|
132
|
+
? links.prev.slice(links.prev.lastIndexOf(beforeStr) + beforeStr.length)
|
|
133
|
+
: null}`);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
exports.logArrayResults = logArrayResults;
|
|
138
|
+
var PaginationPageLimit;
|
|
139
|
+
(function (PaginationPageLimit) {
|
|
140
|
+
PaginationPageLimit[PaginationPageLimit["tiny"] = 5] = "tiny";
|
|
141
|
+
PaginationPageLimit[PaginationPageLimit["small"] = 20] = "small";
|
|
142
|
+
PaginationPageLimit[PaginationPageLimit["medium"] = 50] = "medium";
|
|
143
|
+
PaginationPageLimit[PaginationPageLimit["large"] = 100] = "large";
|
|
144
|
+
})(PaginationPageLimit || (PaginationPageLimit = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const utils_1 = require("./utils");
|
|
16
|
+
const commander_1 = require("commander");
|
|
17
|
+
const axios_1 = require("axios");
|
|
18
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
21
|
+
return undefined;
|
|
22
|
+
}); // prevent process exit on error
|
|
23
|
+
const stderrSpy = jest.spyOn(process.stderr, 'write');
|
|
24
|
+
const logSpy = jest.spyOn(global.console, 'log');
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
jest.resetAllMocks();
|
|
27
|
+
});
|
|
28
|
+
describe('handleCommandError', () => {
|
|
29
|
+
it('correctly displays the console logs for command error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
+
const command = new commander_1.Command();
|
|
31
|
+
const message = 'Something bad happened';
|
|
32
|
+
(0, utils_1.handleCommandError)(command, new Error(message));
|
|
33
|
+
expect(stderrSpy).toHaveBeenCalledTimes(1);
|
|
34
|
+
console.log(stderrSpy.mock.calls);
|
|
35
|
+
// read the mock call strings directly otherwise colours cause test failures with .toEqual()
|
|
36
|
+
expect(stderrSpy.mock.calls[0][0]).toContain(message);
|
|
37
|
+
}));
|
|
38
|
+
it('correctly displays the console logs for axios error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
39
|
+
const command = new commander_1.Command();
|
|
40
|
+
const message = 'Something bad happened';
|
|
41
|
+
const responseMessage = 'I am an error response';
|
|
42
|
+
const errDetails = 'i am error details';
|
|
43
|
+
(0, utils_1.handleCommandError)(command, new axios_1.AxiosError(message, '500', undefined, undefined, {
|
|
44
|
+
data: { message: responseMessage, details: errDetails },
|
|
45
|
+
}));
|
|
46
|
+
expect(stderrSpy).toHaveBeenCalledTimes(1);
|
|
47
|
+
// read the mock call strings directly otherwise colours cause test failures with .toEqual()
|
|
48
|
+
expect(stderrSpy.mock.calls[0][0]).toContain(`${message}: ${responseMessage} - ${errDetails}`);
|
|
49
|
+
}));
|
|
50
|
+
it('correctly displays the console logs for error without a message', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
51
|
+
const command = new commander_1.Command();
|
|
52
|
+
(0, utils_1.handleCommandError)(command, new Error());
|
|
53
|
+
expect(stderrSpy).toHaveBeenCalledTimes(1);
|
|
54
|
+
// read the mock call strings directly otherwise colours cause test failures with .toEqual()
|
|
55
|
+
expect(stderrSpy.mock.calls[0][0]).toContain('An unknown error occurred');
|
|
56
|
+
}));
|
|
57
|
+
});
|
|
58
|
+
describe('writeLineSeparator', () => {
|
|
59
|
+
it('correctly displays the console logs for line separator', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
|
+
(0, utils_1.writeLineSeparator)();
|
|
61
|
+
expect(logSpy).toHaveBeenCalledTimes(1);
|
|
62
|
+
expect(logSpy).toHaveBeenCalledWith(chalk_1.default.cyan('------------------------------'));
|
|
63
|
+
}));
|
|
64
|
+
});
|
|
65
|
+
describe('validateAxiosStatus', () => {
|
|
66
|
+
it('correctly validates the status', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
67
|
+
expect((0, utils_1.validateAxiosStatus)(200)).toBe(true);
|
|
68
|
+
expect((0, utils_1.validateAxiosStatus)(400)).toBe(false);
|
|
69
|
+
}));
|
|
70
|
+
});
|
|
71
|
+
describe('buildJobRunnerUrl', () => {
|
|
72
|
+
it('correctly builds the url with override set ', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
+
const url = yield (0, utils_1.buildJobRunnerUrl)(undefined, 'http://localhost:9999/someTenant');
|
|
74
|
+
expect(url).toBe('http://localhost:9999/someTenant');
|
|
75
|
+
}));
|
|
76
|
+
});
|
|
77
|
+
describe('readInputFile', () => {
|
|
78
|
+
it('correctly reads the file ', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
79
|
+
const res = yield (0, utils_1.readInputFile)(path_1.default.join('./src/__tests__/job-runner/inputs/input.json'));
|
|
80
|
+
expect(res).toStrictEqual({ something: 'amazing' });
|
|
81
|
+
}));
|
|
82
|
+
it('errors if file extension is not .json', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
yield expect((0, utils_1.readInputFile)(path_1.default.join('./src/__tests__/job-runner/simple-job/main.js'))).rejects.toThrow('Input must be a .json file');
|
|
84
|
+
}));
|
|
85
|
+
it('errors if file does not exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
86
|
+
yield expect((0, utils_1.readInputFile)(path_1.default.join('./src/__tests__/job-runner/simple-job/input.json'))).rejects.toThrow('Input could not be found');
|
|
87
|
+
}));
|
|
88
|
+
it('errors if file has json extension but cannot be parsed', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
89
|
+
const source = './src/__tests__/job-runner/inputs/badInput.json';
|
|
90
|
+
yield expect((0, utils_1.readInputFile)(path_1.default.join(source))).rejects.toThrow(`Unable to read file ${path_1.default.join(source)} - Unexpected token i in JSON at position 1`);
|
|
91
|
+
}));
|
|
92
|
+
});
|
|
93
|
+
describe('addPaginationToUrl', () => {
|
|
94
|
+
it('correctly adds the pagination size param to the url', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
95
|
+
const url = (0, utils_1.addPaginationToUrl)('http://localhost:9999//__dxp/au/job-runner/someTenant/job/latest?', { size: 'tiny', before: '', after: '' });
|
|
96
|
+
expect(url).toBe('http://localhost:9999//__dxp/au/job-runner/someTenant/job/latest?&page[size]=5');
|
|
97
|
+
}));
|
|
98
|
+
it('correctly adds the pagination params to the url', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
99
|
+
const url = (0, utils_1.addPaginationToUrl)('http://localhost:9999//__dxp/au/job-runner/someTenant/job/latest?', { size: 'tiny', before: '12345', after: '' });
|
|
100
|
+
expect(url).toBe('http://localhost:9999//__dxp/au/job-runner/someTenant/job/latest?&page[size]=5&page[before]=12345');
|
|
101
|
+
}));
|
|
102
|
+
it('correctly throws error for before and after params', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
|
+
expect(() => {
|
|
104
|
+
(0, utils_1.addPaginationToUrl)('http://localhost:9999//__dxp/au/job-runner/someTenant/job/latest?', { size: 'tiny', before: '12345', after: '54321' });
|
|
105
|
+
}).toThrow('Only one of before and after can be set');
|
|
106
|
+
}));
|
|
107
|
+
});
|
|
108
|
+
describe('logArrayResults', () => {
|
|
109
|
+
it('correctly logs results with links', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
110
|
+
yield (0, utils_1.logArrayResults)([{ something: 'awesome' }, { somethingElse: 'also awesome' }], { next: 'page[after]=12345', prev: 'page[before]=1234' });
|
|
111
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('something')}: "awesome"`);
|
|
112
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('somethingElse')}: "also awesome"`);
|
|
113
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('prevPageToken')}: 1234`);
|
|
114
|
+
expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('nextPageToken')}: 12345`);
|
|
115
|
+
}));
|
|
116
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squiz/dxp-cli-next",
|
|
3
|
-
"version": "5.6.0-develop.
|
|
3
|
+
"version": "5.6.0-develop.11",
|
|
4
4
|
"repository": {
|
|
5
5
|
"url": "https://gitlab.squiz.net/developer-experience/dxp-cli-next"
|
|
6
6
|
},
|
|
@@ -39,12 +39,14 @@
|
|
|
39
39
|
"codecov"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@squiz/component-cli-lib": "1.
|
|
42
|
+
"@squiz/component-cli-lib": "^1.51.1-alpha",
|
|
43
43
|
"axios": "1.1.3",
|
|
44
44
|
"cli-color": "2.0.3",
|
|
45
45
|
"commander": "9.4.0",
|
|
46
|
+
"dotenv": "^16.3.1",
|
|
46
47
|
"env-paths": "2.2.1",
|
|
47
48
|
"inquirer": "8.2.5",
|
|
49
|
+
"ora": "^5.4.1",
|
|
48
50
|
"prompt": "^1.3.0",
|
|
49
51
|
"tough-cookie": "4.1.2",
|
|
50
52
|
"update-notifier": "5.1.0"
|
|
@@ -74,6 +76,7 @@
|
|
|
74
76
|
"husky": "8.0.1",
|
|
75
77
|
"jest": "28.1.3",
|
|
76
78
|
"lint-staged": "13.0.3",
|
|
79
|
+
"nock": "^13.3.1",
|
|
77
80
|
"prettier": "2.7.1",
|
|
78
81
|
"semantic-release": "19.0.3",
|
|
79
82
|
"ts-jest": "28.0.7",
|