Skip to content

Commit b1909c8

Browse files
committed
feat: report command, refactor, mso updates
1 parent ef592ef commit b1909c8

File tree

10 files changed

+328
-138
lines changed

10 files changed

+328
-138
lines changed

messages/data-seeding.report.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# summary
2+
3+
View the status of a data seeding job
4+
5+
# description
6+
7+
View the status of a data seeding job that has already been initiated or completed
8+
9+
# examples
10+
11+
- Display the status of a specific data seeding job
12+
<%= config.bin %> <%= command.id %> --job-id="[XXXX-YYYY-ZZZZ-AAAA]"
13+
14+
- Display the status of a the most recent data seeding job
15+
<%= config.bin %> <%= command.id %> --use-most-recent
16+
# flags.job-id.summary
17+
18+
ID of a specific data seeding job.
19+
20+
# flags.use-most-recent.summary
21+
22+
View status of most recent data seeding job.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"bugs": "https://github.com/forcedotcom/cli/issues",
77
"dependencies": {
88
"@oclif/core": "^4",
9-
"@oclif/multi-stage-output": "^0.3.4",
9+
"@oclif/multi-stage-output": "^0.4.0",
1010
"@salesforce/core": "^8.2.7",
1111
"@salesforce/kit": "^3.2.1",
1212
"@salesforce/sf-plugins-core": "^11.3.3",
@@ -201,4 +201,4 @@
201201
},
202202
"exports": "./lib/index.js",
203203
"type": "module"
204-
}
204+
}

src/commands/data-seeding/generate.ts

Lines changed: 33 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,12 @@
88
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
99
import { Messages, PollingClient, SfError, StatusResult } from '@salesforce/core';
1010
import { Duration } from '@salesforce/kit';
11-
import { initiateDataSeed, pollSeedStatus, PollSeedResponse } from '../../utils/api.js'
12-
import { getSeedGenerateMso } from '../../utils/mso.js';
11+
import { initiateDataSeed, pollSeedStatus, PollSeedResponse } from '../../utils/api.js';
12+
import { getSeedGenerateMso, getSeedGenerateStage as getStage } from '../../utils/mso.js';
13+
import { DataSeedingGenerateResult } from '../../utils/types.js';
1314

1415
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
1516
const messages = Messages.loadMessages('@salesforce/plugin-data-seeding', 'data-seeding.generate');
16-
17-
export type DataSeedingGenerateResult = {
18-
dataSeedingJob: string;
19-
jobId: string;
20-
startTime?: string;
21-
endTime?: string;
22-
sourceOrg: string;
23-
targetOrg: string;
24-
status?: string;
25-
};
2617
export default class DataSeedingGenerate extends SfCommand<DataSeedingGenerateResult> {
2718
public static readonly summary = messages.getMessage('summary');
2819
public static readonly description = messages.getMessage('description');
@@ -62,18 +53,22 @@ export default class DataSeedingGenerate extends SfCommand<DataSeedingGenerateRe
6253

6354
public async run(): Promise<DataSeedingGenerateResult> {
6455
const { flags } = await this.parse(DataSeedingGenerate);
65-
const {
66-
async,
67-
'config-file': configFile,
68-
'source-org': sourceOrg,
69-
'target-org': targetOrg,
70-
wait
71-
} = flags;
56+
const { async, 'config-file': configFile, 'source-org': sourceOrg, 'target-org': targetOrg, wait } = flags;
7257

7358
const { request_id: jobId } = await initiateDataSeed(configFile);
7459

7560
if (!jobId) throw new Error('Failed to receive job id');
7661

62+
const buildResponse = (response: PollSeedResponse): DataSeedingGenerateResult => ({
63+
dataSeedingJob: 'generate',
64+
jobId,
65+
startTime: response?.execution_start_time,
66+
endTime: response?.execution_end_time,
67+
sourceOrg,
68+
targetOrg,
69+
status: response.status,
70+
});
71+
7772
// TODO: Cache the jobId so that it can be used by the `--use-most-recent` flag
7873

7974
if (wait && !async) {
@@ -83,57 +78,45 @@ export default class DataSeedingGenerate extends SfCommand<DataSeedingGenerateRe
8378
const options: PollingClient.Options = {
8479
poll: async (): Promise<StatusResult> => {
8580
const response = await pollSeedStatus(jobId);
86-
mso.goto(response.step);
8781

88-
mso.updateData({
82+
mso.goto(getStage(response.step), {
8983
startTime: response.execution_start_time,
9084
endTime: response.execution_end_time,
91-
status: response.status
92-
})
93-
94-
const completed = response.status === 'Completed'
95-
const failed = response.status === 'Failed';
96-
97-
if (completed) mso.stop();
98-
if (failed) {
99-
const err = new SfError(`Data seeding job failed on step: ${response.step}\nLog Text: ${response.log_text}`);
100-
mso.stop(err);
101-
throw err;
102-
}
85+
status: response.status,
86+
});
10387

10488
return {
105-
completed: completed || failed,
89+
completed: response.status === 'Completed' || response.status === 'Failed',
10690
payload: response,
10791
};
10892
},
10993
frequency: Duration.seconds(1),
110-
timeout: wait
94+
timeout: wait,
11195
};
11296

11397
try {
11498
const client = await PollingClient.create(options);
11599
const pollResult: PollSeedResponse = await client.subscribe();
116100

117-
return {
118-
dataSeedingJob: 'generate',
119-
jobId,
120-
startTime: pollResult?.execution_start_time,
121-
endTime: pollResult?.execution_end_time,
122-
sourceOrg,
123-
targetOrg,
124-
status: pollResult.status
101+
if (pollResult.status === 'Failed') {
102+
mso.error();
103+
throw new SfError(`Data seeding job failed on step: ${pollResult.step}\nLog Text: ${pollResult.log_text}`);
104+
} else {
105+
mso.stop();
125106
}
107+
108+
return buildResponse(pollResult);
126109
} catch (e) {
127110
const err = SfError.wrap(e as Error);
128111

129112
if (err.message.includes('The client has timed out')) {
130113
mso.updateData({ status: 'Client Timeout' });
131-
132114
err.actions = [
133115
'- Increase the value of the "--wait" flag',
134-
`- Check the status with: sf data-seeding report -i ${jobId}`
116+
`- Check the status with: sf data-seeding report -i ${jobId}`,
135117
];
136118
}
119+
137120
mso.stop();
138121
throw err;
139122
}
@@ -143,33 +126,21 @@ export default class DataSeedingGenerate extends SfCommand<DataSeedingGenerateRe
143126
const mso = getSeedGenerateMso({
144127
jsonEnabled: this.jsonEnabled(),
145128
showElapsedTime: false,
146-
showStageTime: false
129+
showStageTime: false,
147130
});
148131

149-
mso.goto(response.step);
150-
151-
mso.updateData({
132+
mso.goto(getStage(response.step), {
152133
jobId,
153134
sourceOrg,
154135
targetOrg,
155136
startTime: response.execution_start_time,
156-
status: 'Initiated'
157-
})
137+
status: 'Initiated',
138+
});
158139

159140
mso.stop();
160-
161-
this.log('Data seeding process has been initiated\n');
162141
this.log(`- Check the status with: sf data-seeding report -i ${jobId}`);
163142

164-
return {
165-
dataSeedingJob: 'generate',
166-
jobId,
167-
startTime: response?.execution_start_time,
168-
endTime: response?.execution_end_time,
169-
sourceOrg,
170-
targetOrg,
171-
status: response.status
172-
};
143+
return buildResponse(response);
173144
}
174145
}
175146
}

src/commands/data-seeding/report.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2023, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
8+
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
9+
import { Messages, SfError } from '@salesforce/core';
10+
import { pollSeedStatus } from '../../utils/api.js';
11+
import { getSeedGenerateMso, getSeedGenerateStage as getStage } from '../../utils/mso.js';
12+
import { DataSeedingReportResult } from '../../utils/types.js';
13+
14+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
15+
const messages = Messages.loadMessages('@salesforce/plugin-data-seeding', 'data-seeding.report');
16+
17+
// TEMP failure (Querying Source Org): 9258aae5-e9b0-4c73-a340-962d299b71bd
18+
// TEMP failure (Populating Target Org): 0aab5c70-069d-48f5-aa0d-157f745c5dfe
19+
20+
export default class DataSeedingReport extends SfCommand<DataSeedingReportResult> {
21+
public static readonly summary = messages.getMessage('summary');
22+
public static readonly description = messages.getMessage('description');
23+
public static readonly examples = messages.getMessages('examples');
24+
25+
public static readonly flags = {
26+
'job-id': Flags.string({
27+
summary: messages.getMessage('flags.job-id.summary'),
28+
char: 'i',
29+
exclusive: ['use-most-recent'],
30+
}),
31+
'use-most-recent': Flags.boolean({
32+
summary: messages.getMessage('flags.use-most-recent.summary'),
33+
char: 'r',
34+
exclusive: ['job-id'],
35+
}),
36+
};
37+
38+
public async run(): Promise<DataSeedingReportResult> {
39+
const { flags } = await this.parse(DataSeedingReport);
40+
41+
const jobId = flags['job-id'] ?? 'getMostRecentJobIdFromCache()';
42+
43+
const response = await pollSeedStatus(jobId);
44+
45+
const mso = getSeedGenerateMso({
46+
jsonEnabled: this.jsonEnabled(),
47+
showElapsedTime: false,
48+
showStageTime: false,
49+
});
50+
51+
mso.goto(getStage(response.step), {
52+
jobId,
53+
startTime: response.execution_start_time,
54+
endTime: response.execution_end_time,
55+
status: response.status,
56+
});
57+
58+
switch (response.status) {
59+
case 'Completed':
60+
mso.stop();
61+
break;
62+
// The 'current' status will be implemented in a future mso update
63+
// case 'In Progress':
64+
// mso.stop('current');
65+
// break;
66+
case 'Failed':
67+
mso.error();
68+
throw new SfError(`Failed on step: ${response.step}\nLog Text: ${response.log_text}`);
69+
default:
70+
mso.stop();
71+
}
72+
73+
return {
74+
dataSeedingJob: 'generate',
75+
jobId,
76+
startTime: response.execution_start_time,
77+
endTime: response.execution_end_time,
78+
status: response.status,
79+
};
80+
}
81+
}

src/utils/api.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import FormData from 'form-data';
1212
import { SfError, Logger } from '@salesforce/core';
1313

1414
export type SeedResponse = {
15-
'request_id': string;
16-
}
15+
request_id: string;
16+
};
1717

1818
export type PollSeedResponse = {
1919
execution_end_time: string;
@@ -22,7 +22,7 @@ export type PollSeedResponse = {
2222
request_id: string;
2323
status: string;
2424
step: string;
25-
}
25+
};
2626

2727
const baseUrl = process.env.SF_DATA_SEEDING_URL ?? 'https://data-seed-scratchpad5.sfdc-3vx9f4.svc.sfdcfc.net';
2828
const csrfUrl = `${baseUrl}/get-csrf-token`;
@@ -33,17 +33,17 @@ export const getCookieJar = async (): Promise<CookieJar> => {
3333
const cookieJar = new CookieJar();
3434
await got(csrfUrl, { cookieJar });
3535
return cookieJar;
36-
}
36+
};
3737

3838
export const getCsrfToken = (cookieJar: CookieJar): string => {
3939
const csrfToken = cookieJar.getCookiesSync(csrfUrl).find((cookie) => cookie.key === 'csrf_token')?.value;
40-
if (!csrfToken) throw new SfError('Failed to obtain CSRF token')
40+
if (!csrfToken) throw new SfError('Failed to obtain CSRF token');
4141

4242
return csrfToken;
43-
}
43+
};
4444

4545
export const initiateDataSeed = async (config: string): Promise<SeedResponse> => {
46-
const cookieJar = await getCookieJar()
46+
const cookieJar = await getCookieJar();
4747
const csrf = getCsrfToken(cookieJar);
4848

4949
const form = new FormData();
@@ -66,14 +66,21 @@ export const initiateDataSeed = async (config: string): Promise<SeedResponse> =>
6666
}
6767

6868
return JSON.parse(response.body);
69-
}
69+
};
7070

7171
export const pollSeedStatus = async (jobId: string): Promise<PollSeedResponse> => {
7272
const logger = await Logger.child('PollSeedStatus');
73-
const body: PollSeedResponse = await got.get(`${pollUrl}/${jobId}`).json();
7473

75-
if (!body) throw new SfError('Polling endpoint failed to return a response');
76-
logger.debug(body);
74+
// NOTE: This could be updated to use .json() instead of JSON.parse once the Error response is changed to be JSON
75+
const response = await got.get(`${pollUrl}/${jobId}`, { throwHttpErrors: false });
76+
77+
if (response.statusCode !== 200) {
78+
// This endpoint returns debugger output... dont print body
79+
throw new SfError(`Failed to poll data seeding status for ${jobId}`);
80+
}
81+
82+
const json = JSON.parse(response.body);
83+
logger.debug(json);
7784

78-
return body;
79-
}
85+
return json;
86+
};

0 commit comments

Comments
 (0)