@squiz/dxp-cli-next 5.5.1 → 5.6.0-develop.2

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.
Files changed (36) hide show
  1. package/lib/ApiService.d.ts +1 -1
  2. package/lib/ApiService.js +15 -8
  3. package/lib/ApiService.spec.js +15 -0
  4. package/lib/__tests__/integration/main.spec.js +17 -0
  5. package/lib/dxp.js +4 -0
  6. package/lib/job-runner/index.d.ts +3 -0
  7. package/lib/job-runner/index.js +22 -0
  8. package/lib/job-runner/job/listJobs/listJobs.d.ts +3 -0
  9. package/lib/job-runner/job/listJobs/listJobs.js +62 -0
  10. package/lib/job-runner/job/listJobs/listJobs.spec.d.ts +1 -0
  11. package/lib/job-runner/job/listJobs/listJobs.spec.js +45 -0
  12. package/lib/job-runner/job/uploadJob/uploadJob.d.ts +3 -0
  13. package/lib/job-runner/job/uploadJob/uploadJob.js +52 -0
  14. package/lib/job-runner/job/uploadJob/uploadJob.spec.d.ts +1 -0
  15. package/lib/job-runner/job/uploadJob/uploadJob.spec.js +41 -0
  16. package/lib/job-runner/jobContext/listJobContexts.d.ts +3 -0
  17. package/lib/job-runner/jobContext/listJobContexts.js +63 -0
  18. package/lib/job-runner/jobContext/listJobContexts.spec.d.ts +1 -0
  19. package/lib/job-runner/jobContext/listJobContexts.spec.js +64 -0
  20. package/lib/job-runner/jobExecution/beginJob/beginJob.d.ts +3 -0
  21. package/lib/job-runner/jobExecution/beginJob/beginJob.js +61 -0
  22. package/lib/job-runner/jobExecution/beginJob/beginJob.spec.d.ts +1 -0
  23. package/lib/job-runner/jobExecution/beginJob/beginJob.spec.js +61 -0
  24. package/lib/job-runner/jobExecution/listJobExecutions/listJobExecutions.d.ts +3 -0
  25. package/lib/job-runner/jobExecution/listJobExecutions/listJobExecutions.js +59 -0
  26. package/lib/job-runner/jobExecution/listJobExecutions/listJobExecutions.spec.d.ts +1 -0
  27. package/lib/job-runner/jobExecution/listJobExecutions/listJobExecutions.spec.js +66 -0
  28. package/lib/job-runner/jobExecution/terminateJob/terminateJob.d.ts +3 -0
  29. package/lib/job-runner/jobExecution/terminateJob/terminateJob.js +60 -0
  30. package/lib/job-runner/jobExecution/terminateJob/terminateJob.spec.d.ts +1 -0
  31. package/lib/job-runner/jobExecution/terminateJob/terminateJob.spec.js +59 -0
  32. package/lib/job-runner/utils.d.ts +6 -0
  33. package/lib/job-runner/utils.js +65 -0
  34. package/lib/job-runner/utils.spec.d.ts +1 -0
  35. package/lib/job-runner/utils.spec.js +74 -0
  36. package/package.json +5 -2
@@ -7,7 +7,7 @@ export declare const COOKIE_KEY = "dxp-sessionid";
7
7
  */
8
8
  export declare class ApiService {
9
9
  client: AxiosInstance;
10
- constructor();
10
+ constructor(validateStatus?: (status: number) => boolean, baseUrl?: string);
11
11
  }
12
12
  /**
13
13
  * The API Service requestInterceptor will load the session cookie from
package/lib/ApiService.js CHANGED
@@ -23,8 +23,11 @@ exports.COOKIE_KEY = 'dxp-sessionid';
23
23
  * adding the session cookie to requests.
24
24
  */
25
25
  class ApiService {
26
- constructor() {
27
- this.client = axios_1.default.create({ validateStatus: null });
26
+ constructor(validateStatus, baseUrl) {
27
+ this.client = axios_1.default.create({
28
+ validateStatus: validateStatus,
29
+ baseURL: baseUrl,
30
+ });
28
31
  this.client.interceptors.request.use(requestInterceptor);
29
32
  this.client.interceptors.response.use(responseInterceptor);
30
33
  }
@@ -36,16 +39,20 @@ exports.ApiService = ApiService;
36
39
  * will seamlessly have the authorization required.
37
40
  */
38
41
  function requestInterceptor(request) {
42
+ var _a;
39
43
  return __awaiter(this, void 0, void 0, function* () {
44
+ const additionalHeaders = {};
40
45
  const maybeSessionCookie = yield (0, ApplicationStore_1.getApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie);
41
- if (!maybeSessionCookie) {
42
- return request;
46
+ if (maybeSessionCookie) {
47
+ additionalHeaders.cookie =
48
+ (_a = tough_cookie_1.Cookie.fromJSON(maybeSessionCookie)) === null || _a === void 0 ? void 0 : _a.cookieString();
49
+ }
50
+ if (process.env.DXP_JWT) {
51
+ additionalHeaders.authorization = `Bearer ${process.env.DXP_JWT}`;
43
52
  }
44
- const sessionCookie = tough_cookie_1.Cookie.fromJSON(maybeSessionCookie);
45
- if (!sessionCookie) {
46
- return request;
53
+ if (Object.keys(additionalHeaders).length > 0) {
54
+ request.headers = Object.assign(Object.assign({}, (request.headers || {})), additionalHeaders);
47
55
  }
48
- request.headers = Object.assign(Object.assign({}, (request.headers || {})), { cookie: sessionCookie === null || sessionCookie === void 0 ? void 0 : sessionCookie.cookieString() });
49
56
  return request;
50
57
  });
51
58
  }
@@ -19,6 +19,7 @@ const VALID_COOKIE = new tough_cookie_1.Cookie({
19
19
  describe('ApiService', () => {
20
20
  describe('requestInterceptor', () => {
21
21
  beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
22
+ delete process.env.DXP_JWT;
22
23
  yield (0, ApplicationStore_1.deleteApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie);
23
24
  }));
24
25
  it('loads stored session cookie into request config', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -32,6 +33,20 @@ describe('ApiService', () => {
32
33
  const requestConfig = yield (0, ApiService_1.requestInterceptor)({});
33
34
  expect(requestConfig).toEqual({});
34
35
  }));
36
+ it('attaches DXP JWT as authorization header if environment variable defined', () => __awaiter(void 0, void 0, void 0, function* () {
37
+ process.env.DXP_JWT = 'xxx.yyy.zzz';
38
+ const requestConfig = yield (0, ApiService_1.requestInterceptor)({
39
+ headers: {
40
+ 'x-custom-header': 'header value',
41
+ },
42
+ });
43
+ expect(requestConfig).toEqual({
44
+ headers: {
45
+ authorization: 'Bearer xxx.yyy.zzz',
46
+ 'x-custom-header': 'header value',
47
+ },
48
+ });
49
+ }));
35
50
  });
36
51
  describe('responseInterceptor', () => {
37
52
  beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
@@ -4,9 +4,11 @@ const helpers_1 = require("../helpers");
4
4
  describe('dxp', () => {
5
5
  beforeEach(() => {
6
6
  process.env.FEATURE_TD_ACTIVE = 'true';
7
+ process.env.ENABLE_JOB_RUNNER = 'true';
7
8
  });
8
9
  afterAll(() => {
9
10
  process.env.FEATURE_TD_ACTIVE = undefined;
11
+ process.env.ENABLE_JOB_RUNNER = undefined;
10
12
  });
11
13
  it('should display the help contents', () => {
12
14
  const { stdout } = (0, helpers_1.runCLI)(process.cwd(), ['--help']);
@@ -14,17 +16,32 @@ describe('dxp', () => {
14
16
  });
15
17
  it('should show all available commands', () => {
16
18
  var _a;
19
+ process.env.ENABLE_JOB_RUNNER = 'true';
17
20
  const { stdout } = (0, helpers_1.runCLI)(process.cwd(), ['--help']);
18
21
  const commandsText = (_a = stdout
19
22
  .match(/Commands\:(.*)/is)) === null || _a === void 0 ? void 0 : _a[1].split('\n').map(a => a.trim()).filter(a => !!a);
20
23
  expect(commandsText).toEqual([
21
24
  'auth Authenticate into the DXP CLI',
25
+ 'job-runner Job Runner Service Commands',
22
26
  'cmp Component Service Commands',
23
27
  ]);
24
28
  });
25
29
  it('if FEATURE_TD_ACTIVE not set to true, td command should not be visible', () => {
26
30
  var _a;
27
31
  process.env.FEATURE_TD_ACTIVE = undefined;
32
+ process.env.ENABLE_JOB_RUNNER = 'true';
33
+ const { stdout } = (0, helpers_1.runCLI)(process.cwd(), ['--help']);
34
+ const commandsText = (_a = stdout
35
+ .match(/Commands\:(.*)/is)) === null || _a === void 0 ? void 0 : _a[1].split('\n').map(a => a.trim()).filter(a => !!a);
36
+ expect(commandsText).toEqual([
37
+ 'auth Authenticate into the DXP CLI',
38
+ 'job-runner Job Runner Service Commands',
39
+ 'cmp Component Service Commands',
40
+ ]);
41
+ });
42
+ it('if ENABLE_JOB_RUNNER not set to true, job-runner command should not be visible', () => {
43
+ var _a;
44
+ process.env.ENABLE_JOB_RUNNER = undefined;
28
45
  const { stdout } = (0, helpers_1.runCLI)(process.cwd(), ['--help']);
29
46
  const commandsText = (_a = stdout
30
47
  .match(/Commands\:(.*)/is)) === null || _a === void 0 ? void 0 : _a[1].split('\n').map(a => a.trim()).filter(a => !!a);
package/lib/dxp.js CHANGED
@@ -14,6 +14,7 @@ validateNodeVersion();
14
14
  const auth_1 = __importDefault(require("./auth"));
15
15
  // import tdCommand from './td';
16
16
  const cmp_1 = __importDefault(require("./cmp"));
17
+ const job_runner_1 = __importDefault(require("./job-runner"));
17
18
  const program = new commander_1.default.Command();
18
19
  const packageJson = require('../package.json');
19
20
  const version = packageJson.version;
@@ -22,6 +23,9 @@ program
22
23
  .version(version)
23
24
  .description('dxp commands')
24
25
  .addCommand(auth_1.default);
26
+ if (process.env.ENABLE_JOB_RUNNER === 'true') {
27
+ program.addCommand(job_runner_1.default);
28
+ }
25
29
  // if (process.env.FEATURE_TD_ACTIVE === 'true') {
26
30
  // program.addCommand(tdCommand);
27
31
  // }
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const jobRunnerCommand: Command;
3
+ export default jobRunnerCommand;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const commander_1 = require("commander");
7
+ const listJobs_1 = __importDefault(require("./job/listJobs/listJobs"));
8
+ const beginJob_1 = __importDefault(require("./jobExecution/beginJob/beginJob"));
9
+ const terminateJob_1 = __importDefault(require("./jobExecution/terminateJob/terminateJob"));
10
+ const listJobContexts_1 = __importDefault(require("./jobContext/listJobContexts"));
11
+ const listJobExecutions_1 = __importDefault(require("./jobExecution/listJobExecutions/listJobExecutions"));
12
+ const uploadJob_1 = __importDefault(require("./job/uploadJob/uploadJob"));
13
+ const jobRunnerCommand = new commander_1.Command('job-runner');
14
+ jobRunnerCommand
15
+ .description('Job Runner Service Commands')
16
+ .addCommand((0, uploadJob_1.default)())
17
+ .addCommand((0, beginJob_1.default)())
18
+ .addCommand((0, terminateJob_1.default)())
19
+ .addCommand((0, listJobs_1.default)())
20
+ .addCommand((0, listJobExecutions_1.default)())
21
+ .addCommand((0, listJobContexts_1.default)());
22
+ exports.default = jobRunnerCommand;
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const createListJobsCommand: () => Command;
3
+ export default createListJobsCommand;
@@ -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 createListJobsCommand = () => {
21
+ const listJobsCommand = new commander_1.Command('listJobs')
22
+ .name('listJobs')
23
+ .description('List all jobs')
24
+ .addOption(new commander_1.Option('-t, --tenant <string>', 'Tenant ID to deploy to. If not provided will use configured tenant from login'))
25
+ .configureOutput({
26
+ outputError(str, write) {
27
+ write(chalk_1.default.red(str));
28
+ },
29
+ })
30
+ .action((options) => __awaiter(void 0, void 0, void 0, function* () {
31
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(listJobsCommand);
32
+ const spinner = (0, ora_1.default)('Retrieving jobs').start();
33
+ try {
34
+ const apiService = new ApiService_1.ApiService(utils_1.validateAxiosStatus);
35
+ const listJobsUrl = `${yield (0, utils_1.buildJobRunnerUrl)(options.tenant, options.overrideUrl)}/job`;
36
+ const res = yield apiService.client.get(listJobsUrl);
37
+ if (Array.isArray(res.data) && res.data.length > 0) {
38
+ spinner.succeed(`Retrieved ${res.data.length} jobs`);
39
+ (0, utils_1.writeLineSeparator)();
40
+ res.data.forEach((element) => {
41
+ Object.keys(element).forEach(key => {
42
+ console.log(`${key}: ${element[key]}`);
43
+ });
44
+ (0, utils_1.writeLineSeparator)();
45
+ });
46
+ return;
47
+ }
48
+ else {
49
+ spinner.succeed('No jobs found');
50
+ }
51
+ }
52
+ catch (error) {
53
+ spinner.fail();
54
+ (0, utils_1.handleCommandError)(listJobsCommand, error);
55
+ }
56
+ }));
57
+ if (process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL === 'true') {
58
+ listJobsCommand.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire job runner url with a custom value'));
59
+ }
60
+ return listJobsCommand;
61
+ };
62
+ exports.default = createListJobsCommand;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
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 listJobs_1 = __importDefault(require("./listJobs"));
17
+ const chalk_1 = __importDefault(require("chalk"));
18
+ const logSpy = jest.spyOn(global.console, 'log');
19
+ describe('listJobs', () => {
20
+ it('correctly lists the job', () => __awaiter(void 0, void 0, void 0, function* () {
21
+ process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL = 'true';
22
+ (0, nock_1.default)('http://localhost:9999')
23
+ .get('/job')
24
+ .reply(200, [{ name: 'simple-job', type: 'job', version: '1.0.0' }]);
25
+ const program = (0, listJobs_1.default)();
26
+ yield program.parseAsync([
27
+ 'node',
28
+ 'dxp-cli',
29
+ 'job-runner',
30
+ 'listJobs',
31
+ '-t',
32
+ 'myTenant',
33
+ '-ou',
34
+ 'http://localhost:9999',
35
+ ]);
36
+ const opts = program.opts();
37
+ expect(opts.tenant).toEqual('myTenant');
38
+ expect(opts.overrideUrl).toEqual('http://localhost:9999');
39
+ expect(logSpy).toHaveBeenCalledTimes(5);
40
+ expect(logSpy).toHaveBeenCalledWith('name: simple-job');
41
+ expect(logSpy).toHaveBeenCalledWith('type: job');
42
+ expect(logSpy).toHaveBeenCalledWith('version: 1.0.0');
43
+ expect(logSpy).toHaveBeenCalledWith(chalk_1.default.cyan('------------------------------'));
44
+ }));
45
+ });
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const createUploadJobCommand: () => Command;
3
+ export default createUploadJobCommand;
@@ -0,0 +1,52 @@
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 component_cli_lib_1 = require("@squiz/component-cli-lib");
20
+ const utils_1 = require("../../utils");
21
+ const createUploadJobCommand = () => {
22
+ const uploadJobCommand = new commander_1.Command('uploadJob')
23
+ .name('uploadJob')
24
+ .description('Upload a new job to the job-runner')
25
+ .addOption(new commander_1.Option('-t, --tenant <string>', 'Tenant ID to deploy to. If not provided will use configured tenant from login'))
26
+ .addArgument(new commander_1.Argument('<inputSource>', 'Path to the folder containing the job code .js files and the manifest.json file'))
27
+ .configureOutput({
28
+ outputError(str, write) {
29
+ write(chalk_1.default.red(str));
30
+ },
31
+ })
32
+ .action((inputSource, options) => __awaiter(void 0, void 0, void 0, function* () {
33
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(uploadJobCommand);
34
+ const spinner = (0, ora_1.default)('Uploading job ').start();
35
+ try {
36
+ const apiService = new ApiService_1.ApiService(utils_1.validateAxiosStatus, yield (0, utils_1.buildJobRunnerUrl)(options.tenant, options.overrideUrl));
37
+ yield (0, component_cli_lib_1.uploadJobFolder)(apiService.client, inputSource);
38
+ spinner.succeed();
39
+ return;
40
+ }
41
+ catch (error) {
42
+ console.log(error);
43
+ spinner.fail();
44
+ (0, utils_1.handleCommandError)(uploadJobCommand, error);
45
+ }
46
+ }));
47
+ if (process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL === 'true') {
48
+ uploadJobCommand.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire job runner url with a custom value'));
49
+ }
50
+ return uploadJobCommand;
51
+ };
52
+ exports.default = createUploadJobCommand;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
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 uploadJob_1 = __importDefault(require("./uploadJob"));
16
+ const logSpy = jest.spyOn(global.console, 'log');
17
+ describe('upload job', () => {
18
+ it('correctly displays the console logs for uploading the job', () => __awaiter(void 0, void 0, void 0, function* () {
19
+ process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL = 'true';
20
+ const program = (0, uploadJob_1.default)();
21
+ yield program.parseAsync([
22
+ 'node',
23
+ 'dxp-cli',
24
+ './src/__tests__/jobrunner/simple-job',
25
+ '-t',
26
+ 'myTenant',
27
+ '-ou',
28
+ 'http://localhost:9999',
29
+ ]);
30
+ const opts = program.opts();
31
+ const args = program.args;
32
+ expect(args[0]).toEqual('./src/__tests__/jobrunner/simple-job');
33
+ expect(opts.tenant).toEqual('myTenant');
34
+ expect(opts.overrideUrl).toEqual('http://localhost:9999');
35
+ expect(logSpy).toHaveBeenCalledTimes(4);
36
+ expect(logSpy).toHaveBeenCalledWith('Initial scanning');
37
+ expect(logSpy).toHaveBeenCalledWith('deployment id: test-12345 status: transferring');
38
+ expect(logSpy).toHaveBeenCalledWith('deployment id: test-12345 status: deploying job folder');
39
+ expect(logSpy).toHaveBeenCalledWith('deployment id: test-12345 status: success');
40
+ }));
41
+ });
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const createListJobContextsCommand: () => Command;
3
+ export default createListJobContextsCommand;
@@ -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 commander_1 = require("commander");
16
+ const ora_1 = __importDefault(require("ora"));
17
+ const chalk_1 = __importDefault(require("chalk"));
18
+ const ApiService_1 = require("../../ApiService");
19
+ const utils_1 = require("../utils");
20
+ const createListJobContextsCommand = () => {
21
+ const listJobContextsCommand = new commander_1.Command('listJobContexts')
22
+ .name('listJobContexts')
23
+ .description('List all job contexts')
24
+ .addOption(new commander_1.Option('-t, --tenant <string>', 'Tenant ID to deploy to. If not provided will use configured tenant from login'))
25
+ .configureOutput({
26
+ outputError(str, write) {
27
+ write(chalk_1.default.red(str));
28
+ },
29
+ })
30
+ .action((options) => __awaiter(void 0, void 0, void 0, function* () {
31
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(listJobContextsCommand);
32
+ const spinner = (0, ora_1.default)('Retrieving job contexts\r\n').start();
33
+ try {
34
+ const apiService = new ApiService_1.ApiService(utils_1.validateAxiosStatus);
35
+ const listJobContextsUrl = `${yield (0, utils_1.buildJobRunnerUrl)(options.tenant, options.overrideUrl)}/job-context`;
36
+ const res = yield apiService.client.get(listJobContextsUrl);
37
+ if (Array.isArray(res.data) && res.data.length > 0) {
38
+ spinner.succeed(`${res.data.length} contexts successfully retrieved`);
39
+ (0, utils_1.writeLineSeparator)();
40
+ res.data.forEach((context) => {
41
+ console.log(`${chalk_1.default.green(chalk_1.default.bold(context.contextName))}: ${chalk_1.default.green(context.description)}`);
42
+ for (const [key, value] of Object.entries(context.environment)) {
43
+ console.log(`${chalk_1.default.bold(key)}: ${value}`);
44
+ }
45
+ (0, utils_1.writeLineSeparator)();
46
+ });
47
+ }
48
+ else {
49
+ spinner.succeed('No job contexts found');
50
+ }
51
+ return;
52
+ }
53
+ catch (error) {
54
+ spinner.fail();
55
+ (0, utils_1.handleCommandError)(listJobContextsCommand, error);
56
+ }
57
+ }));
58
+ if (process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL === 'true') {
59
+ listJobContextsCommand.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire job runner url with a custom value'));
60
+ }
61
+ return listJobContextsCommand;
62
+ };
63
+ exports.default = createListJobContextsCommand;
@@ -0,0 +1,64 @@
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 listJobContexts_1 = __importDefault(require("./listJobContexts"));
17
+ const chalk_1 = __importDefault(require("chalk"));
18
+ const logSpy = jest.spyOn(global.console, 'log');
19
+ describe('listJobContexts', () => {
20
+ process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL = 'true';
21
+ it('correctly lists the job contexts', () => __awaiter(void 0, void 0, void 0, function* () {
22
+ (0, nock_1.default)('http://localhost:9999')
23
+ .get('/job-context')
24
+ .reply(200, [
25
+ {
26
+ contextName: 'dev',
27
+ type: 'context',
28
+ description: 'dev context',
29
+ environment: {
30
+ baz: '12345',
31
+ foo: 'bar',
32
+ },
33
+ },
34
+ {
35
+ contextName: 'stage',
36
+ type: 'context',
37
+ description: 'staging context',
38
+ environment: {
39
+ something: 'cool',
40
+ somethingElse: 'cooler',
41
+ },
42
+ },
43
+ ]);
44
+ const program = (0, listJobContexts_1.default)();
45
+ yield program.parseAsync([
46
+ 'node',
47
+ 'dxp-cli',
48
+ 'job-runner',
49
+ 'listJobContexts',
50
+ '-t',
51
+ 'myTenant',
52
+ '-ou',
53
+ 'http://localhost:9999',
54
+ ]);
55
+ const opts = program.opts();
56
+ expect(opts.tenant).toEqual('myTenant');
57
+ expect(opts.overrideUrl).toEqual('http://localhost:9999');
58
+ expect(logSpy).toHaveBeenCalledTimes(9);
59
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.green(chalk_1.default.bold('dev'))}: ${chalk_1.default.green('dev context')}`);
60
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('something')}: cool`);
61
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('somethingElse')}: cooler`);
62
+ expect(logSpy).toHaveBeenCalledWith(chalk_1.default.cyan('------------------------------'));
63
+ }));
64
+ });
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const createBeginJobCommand: () => Command;
3
+ export default createBeginJobCommand;
@@ -0,0 +1,61 @@
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 createBeginJobCommand = () => {
21
+ const beginJobCommand = new commander_1.Command('beginJob')
22
+ .name('beginJob')
23
+ .description('Add a job to the queue')
24
+ .addOption(new commander_1.Option('-t, --tenant <string>', 'Tenant ID to deploy to. If not provided will use configured tenant from login'))
25
+ .addArgument(new commander_1.Argument('<jobName>', 'Name of the job to pass to the request'))
26
+ .addArgument(new commander_1.Argument('<contextName>', 'Name of the job context to pass to the request'))
27
+ .addArgument(new commander_1.Argument('<inputSource>', 'Path to the .json input file for the job execution'))
28
+ .configureOutput({
29
+ outputError(str, write) {
30
+ write(chalk_1.default.red(str));
31
+ },
32
+ })
33
+ .action((jobName, contextName, inputSource, options) => __awaiter(void 0, void 0, void 0, function* () {
34
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(beginJobCommand);
35
+ const spinner = (0, ora_1.default)('Queueing job').start();
36
+ console.log('');
37
+ try {
38
+ const apiService = new ApiService_1.ApiService(utils_1.validateAxiosStatus);
39
+ const beginJobUrl = `${yield (0, utils_1.buildJobRunnerUrl)(options.tenant, options.overrideUrl)}/executions/begin`;
40
+ const res = yield apiService.client.post(beginJobUrl, {
41
+ jobName: jobName,
42
+ context: contextName,
43
+ });
44
+ spinner.succeed('Job queued successfully');
45
+ (0, utils_1.writeLineSeparator)();
46
+ for (const [key, value] of Object.entries(res.data)) {
47
+ console.log(`${chalk_1.default.bold([key])}: ${value}`);
48
+ }
49
+ return;
50
+ }
51
+ catch (error) {
52
+ spinner.fail();
53
+ (0, utils_1.handleCommandError)(beginJobCommand, error);
54
+ }
55
+ }));
56
+ if (process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL === 'true') {
57
+ beginJobCommand.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire job runner url with a custom value'));
58
+ }
59
+ return beginJobCommand;
60
+ };
61
+ exports.default = createBeginJobCommand;
@@ -0,0 +1,61 @@
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 logSpy = jest.spyOn(global.console, 'log');
19
+ describe('beginJob', () => {
20
+ it('correctly displays the console logs for beginning a job', () => __awaiter(void 0, void 0, void 0, function* () {
21
+ process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL = 'true';
22
+ (0, nock_1.default)('http://localhost:9999').post('/executions/begin').reply(200, {
23
+ context: 'dev',
24
+ ecsTaskId: null,
25
+ id: 'd0aab852-365e-42de-a642-eac11bb95ccc',
26
+ jobName: 'simple-job',
27
+ status: 'queued',
28
+ timeFinished: null,
29
+ timeQueued: '2023-06-23T01:36:44.792Z',
30
+ timeStarted: null,
31
+ type: 'jobExecution',
32
+ version: null,
33
+ });
34
+ const program = (0, beginJob_1.default)();
35
+ yield program.parseAsync([
36
+ 'node',
37
+ 'dxp-cli',
38
+ 'simple-job',
39
+ 'dev',
40
+ 'myinputs/input',
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('dev');
50
+ expect(args[2]).toEqual('myinputs/input');
51
+ expect(opts.tenant).toEqual('myTenant');
52
+ expect(opts.overrideUrl).toEqual('http://localhost:9999');
53
+ expect(logSpy).toHaveBeenCalledTimes(12);
54
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('status')}: queued`);
55
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('id')}: d0aab852-365e-42de-a642-eac11bb95ccc`);
56
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('jobName')}: simple-job`);
57
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('status')}: queued`);
58
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('timeQueued')}: 2023-06-23T01:36:44.792Z`);
59
+ expect(logSpy).toHaveBeenCalledWith(chalk_1.default.cyan('------------------------------'));
60
+ }));
61
+ });
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const createListJobExecutionsCommand: () => Command;
3
+ export default createListJobExecutionsCommand;
@@ -0,0 +1,59 @@
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('-t, --tenant <string>', 'Tenant ID to deploy to. If not provided will use configured tenant from login'))
25
+ .configureOutput({
26
+ outputError(str, write) {
27
+ write(chalk_1.default.red(str));
28
+ },
29
+ })
30
+ .action((options) => __awaiter(void 0, void 0, void 0, function* () {
31
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(listJobExecutionsCommand);
32
+ const spinner = (0, ora_1.default)('Retrieving job executions').start();
33
+ try {
34
+ const apiService = new ApiService_1.ApiService(utils_1.validateAxiosStatus);
35
+ const listJobsUrl = `${yield (0, utils_1.buildJobRunnerUrl)(options.tenant, options.overrideUrl)}/executions`;
36
+ const res = yield apiService.client.get(listJobsUrl);
37
+ if (Array.isArray(res.data) && res.data.length > 0) {
38
+ spinner.succeed(`Retrieved ${res.data.length} executions`);
39
+ (0, utils_1.writeLineSeparator)();
40
+ res.data.forEach((execution) => {
41
+ for (const [key, value] of Object.entries(execution)) {
42
+ console.log(`${chalk_1.default.bold([key])}: ${value}`);
43
+ }
44
+ (0, utils_1.writeLineSeparator)();
45
+ });
46
+ }
47
+ return;
48
+ }
49
+ catch (error) {
50
+ spinner.fail();
51
+ (0, utils_1.handleCommandError)(listJobExecutionsCommand, error);
52
+ }
53
+ }));
54
+ if (process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL === 'true') {
55
+ listJobExecutionsCommand.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire job runner url with a custom value'));
56
+ }
57
+ return listJobExecutionsCommand;
58
+ };
59
+ exports.default = createListJobExecutionsCommand;
@@ -0,0 +1,66 @@
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 chalk_1 = __importDefault(require("chalk"));
18
+ const logSpy = jest.spyOn(global.console, 'log');
19
+ describe('listJobExecutions', () => {
20
+ it('correctly lists the job executions', () => __awaiter(void 0, void 0, void 0, function* () {
21
+ process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL = 'true';
22
+ (0, nock_1.default)('http://localhost:9999')
23
+ .get('/executions')
24
+ .reply(200, [
25
+ {
26
+ context: 'dev',
27
+ id: 'd0aab852-365e-42de-a642-eac11bb95ccc',
28
+ jobName: 'simple-job',
29
+ status: 'successfully-completed',
30
+ timeFinished: '2023-06-23T01:36:48.345Z',
31
+ timeQueued: '2023-06-23T01:36:44.792Z',
32
+ timeStarted: '2023-06-23T01:36:44.792Z',
33
+ type: 'jobExecution',
34
+ },
35
+ {
36
+ context: 'dev',
37
+ id: 'e7e8de7c-2c5d-4a78-81d9-76c856ed6a85',
38
+ jobName: 'simple-job',
39
+ status: 'successfully-completed',
40
+ timeFinished: '2023-06-23T01:34:24.669Z',
41
+ timeQueued: '2023-06-23T01:34:23.627Z',
42
+ timeStarted: '2023-06-23T01:34:23.627Z',
43
+ type: 'jobExecution',
44
+ },
45
+ ]);
46
+ const program = (0, listJobExecutions_1.default)();
47
+ yield program.parseAsync([
48
+ 'node',
49
+ 'dxp-cli',
50
+ 'job-runner',
51
+ 'listJobExecutions',
52
+ '-t',
53
+ 'myTenant',
54
+ '-ou',
55
+ 'http://localhost:9999',
56
+ ]);
57
+ const opts = program.opts();
58
+ expect(opts.tenant).toEqual('myTenant');
59
+ expect(opts.overrideUrl).toEqual('http://localhost:9999');
60
+ expect(logSpy).toHaveBeenCalled();
61
+ expect(logSpy).toHaveBeenCalledTimes(19);
62
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('status')}: successfully-completed`);
63
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('jobName')}: simple-job`);
64
+ expect(logSpy).toHaveBeenCalledWith(chalk_1.default.cyan('------------------------------'));
65
+ }));
66
+ });
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const createTerminateJobCommand: () => Command;
3
+ export default createTerminateJobCommand;
@@ -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 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 deploy to. 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
+ .configureOutput({
29
+ outputError(str, write) {
30
+ write(chalk_1.default.red(str));
31
+ },
32
+ })
33
+ .action((jobName, executionId, options) => __awaiter(void 0, void 0, void 0, function* () {
34
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(terminateJobCommand);
35
+ const spinner = (0, ora_1.default)('Terminating job').start();
36
+ console.log('');
37
+ try {
38
+ const apiService = new ApiService_1.ApiService(utils_1.validateAxiosStatus);
39
+ const terminateJobUrl = `${yield (0, utils_1.buildJobRunnerUrl)(options.tenant, options.overrideUrl)}/executions/terminate`;
40
+ const res = yield apiService.client.post(terminateJobUrl, {
41
+ jobName: jobName,
42
+ id: executionId,
43
+ });
44
+ for (const [key, value] of Object.entries(res.data)) {
45
+ console.log(`${chalk_1.default.bold([key])}: ${value}`);
46
+ }
47
+ spinner.succeed('Job terminated');
48
+ return;
49
+ }
50
+ catch (error) {
51
+ spinner.fail();
52
+ (0, utils_1.handleCommandError)(terminateJobCommand, error);
53
+ }
54
+ }));
55
+ if (process.env.ENABLE_OVERRIDE_JOB_RUNNER_URL === 'true') {
56
+ terminateJobCommand.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire job runner url with a custom value'));
57
+ }
58
+ return terminateJobCommand;
59
+ };
60
+ exports.default = createTerminateJobCommand;
@@ -0,0 +1,59 @@
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
+ '-t',
41
+ 'myTenant',
42
+ '-ou',
43
+ 'http://localhost:9999',
44
+ ]);
45
+ const opts = program.opts();
46
+ const args = program.args;
47
+ expect(args[0]).toEqual('simple-job');
48
+ expect(args[1]).toEqual('907fc4e5-8b4a-4e47-bab0-e95e45385347');
49
+ expect(opts.tenant).toEqual('myTenant');
50
+ expect(opts.overrideUrl).toEqual('http://localhost:9999');
51
+ expect(logSpy).toHaveBeenCalledTimes(11);
52
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('status')}: terminated`);
53
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('jobName')}: simple-job`);
54
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('id')}: simple-job-d6a418eb-dd63-4594-b299-07410ccd30d5`);
55
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('context')}: dev`);
56
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('timeFinished')}: 2023-06-23T01:49:09.433Z`);
57
+ expect(logSpy).toHaveBeenCalledWith(`${chalk_1.default.bold('version')}: 1.0.1`);
58
+ }));
59
+ });
@@ -0,0 +1,6 @@
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 writeLineSeparator(): void;
6
+ export declare function validateAxiosStatus(status: number): boolean;
@@ -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
+ exports.validateAxiosStatus = exports.writeLineSeparator = exports.buildJobRunnerUrl = exports.throwErrorIfNotLoggedIn = exports.handleCommandError = void 0;
16
+ const chalk_1 = __importDefault(require("chalk"));
17
+ const ApplicationConfig_1 = require("../ApplicationConfig");
18
+ const axios_1 = __importDefault(require("axios"));
19
+ const ApplicationStore_1 = require("../ApplicationStore");
20
+ function handleCommandError(command, error) {
21
+ var _a, _b;
22
+ if (axios_1.default.isAxiosError(error)) {
23
+ command.error(chalk_1.default.red(`${error.message}: ${(_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message}`));
24
+ }
25
+ else {
26
+ if (!!process.env.DEBUG && error.stack) {
27
+ command.error(error.stack);
28
+ }
29
+ if (error.message) {
30
+ command.error(chalk_1.default.red(error.message));
31
+ }
32
+ else {
33
+ command.error(chalk_1.default.red('An unknown error occurred'));
34
+ }
35
+ }
36
+ }
37
+ exports.handleCommandError = handleCommandError;
38
+ function throwErrorIfNotLoggedIn(command) {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ if (!(yield (0, ApplicationStore_1.getApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie))) {
41
+ command.error(chalk_1.default.red('You must login to interact with the job runner. See `dxp-next auth login`'));
42
+ }
43
+ });
44
+ }
45
+ exports.throwErrorIfNotLoggedIn = throwErrorIfNotLoggedIn;
46
+ function buildJobRunnerUrl(tenantID, overrideUrl) {
47
+ return __awaiter(this, void 0, void 0, function* () {
48
+ if (!overrideUrl) {
49
+ const existingConfig = yield (0, ApplicationConfig_1.fetchApplicationConfig)(tenantID);
50
+ return `${existingConfig.baseUrl}/__dxp/${existingConfig.region}/job-runner/${existingConfig.tenant}`;
51
+ }
52
+ else {
53
+ return overrideUrl;
54
+ }
55
+ });
56
+ }
57
+ exports.buildJobRunnerUrl = buildJobRunnerUrl;
58
+ function writeLineSeparator() {
59
+ console.log(chalk_1.default.cyan('------------------------------'));
60
+ }
61
+ exports.writeLineSeparator = writeLineSeparator;
62
+ function validateAxiosStatus(status) {
63
+ return status < 400;
64
+ }
65
+ exports.validateAxiosStatus = validateAxiosStatus;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,74 @@
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 exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {
20
+ return undefined;
21
+ }); // prevent process exit on error
22
+ const stderrSpy = jest.spyOn(process.stderr, 'write');
23
+ const logSpy = jest.spyOn(global.console, 'log');
24
+ beforeEach(() => {
25
+ jest.resetAllMocks();
26
+ });
27
+ describe('handleCommandError', () => {
28
+ it('correctly displays the console logs for command error', () => __awaiter(void 0, void 0, void 0, function* () {
29
+ const command = new commander_1.Command();
30
+ const message = 'Something bad happened';
31
+ (0, utils_1.handleCommandError)(command, new Error(message));
32
+ expect(stderrSpy).toHaveBeenCalledTimes(1);
33
+ console.log(stderrSpy.mock.calls);
34
+ // read the mock call strings directly otherwise colours cause test failures with .toEqual()
35
+ expect(stderrSpy.mock.calls[0][0]).toContain(message);
36
+ }));
37
+ it('correctly displays the console logs for axios error', () => __awaiter(void 0, void 0, void 0, function* () {
38
+ const command = new commander_1.Command();
39
+ const message = 'Something bad happened';
40
+ const responseMessage = 'I am an error response';
41
+ (0, utils_1.handleCommandError)(command, new axios_1.AxiosError(message, '500', undefined, undefined, {
42
+ data: { message: responseMessage },
43
+ }));
44
+ expect(stderrSpy).toHaveBeenCalledTimes(1);
45
+ // read the mock call strings directly otherwise colours cause test failures with .toEqual()
46
+ expect(stderrSpy.mock.calls[0][0]).toContain(`${message}: ${responseMessage}`);
47
+ }));
48
+ it('correctly displays the console logs for error without a message', () => __awaiter(void 0, void 0, void 0, function* () {
49
+ const command = new commander_1.Command();
50
+ (0, utils_1.handleCommandError)(command, new Error());
51
+ expect(stderrSpy).toHaveBeenCalledTimes(1);
52
+ // read the mock call strings directly otherwise colours cause test failures with .toEqual()
53
+ expect(stderrSpy.mock.calls[0][0]).toContain('An unknown error occurred');
54
+ }));
55
+ });
56
+ describe('writeLineSeparator', () => {
57
+ it('correctly displays the console logs for line separator', () => __awaiter(void 0, void 0, void 0, function* () {
58
+ (0, utils_1.writeLineSeparator)();
59
+ expect(logSpy).toHaveBeenCalledTimes(1);
60
+ expect(logSpy).toHaveBeenCalledWith(chalk_1.default.cyan('------------------------------'));
61
+ }));
62
+ });
63
+ describe('validateAxiosStatus', () => {
64
+ it('correctly validates the status', () => __awaiter(void 0, void 0, void 0, function* () {
65
+ expect((0, utils_1.validateAxiosStatus)(200)).toBe(true);
66
+ expect((0, utils_1.validateAxiosStatus)(400)).toBe(false);
67
+ }));
68
+ });
69
+ describe('buildJobRunnerUrl', () => {
70
+ it('correctly builds the url with override set ', () => __awaiter(void 0, void 0, void 0, function* () {
71
+ const url = yield (0, utils_1.buildJobRunnerUrl)(undefined, 'http://localhost:9999/someTenant');
72
+ expect(url).toBe('http://localhost:9999/someTenant');
73
+ }));
74
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squiz/dxp-cli-next",
3
- "version": "5.5.1",
3
+ "version": "5.6.0-develop.2",
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.22.0",
42
+ "@squiz/component-cli-lib": "^1.39.1-alpha.7",
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",