Skip to content

Commit dd488a3

Browse files
committed
fix: better error reporting and more tests
1 parent 89057b6 commit dd488a3

File tree

6 files changed

+73
-35
lines changed

6 files changed

+73
-35
lines changed

messages/deploy.metadata.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Overrides your default org.
7878

7979
# flags.metadata.summary
8080

81-
Metadata component names to deploy. Wildcards ( * ) supported as long as you use quotes, such as 'ApexClass:MyClass*'
81+
Metadata component names to deploy. Wildcards ( _ ) supported as long as you use quotes, such as 'ApexClass:MyClass_'
8282

8383
# flags.test-level.summary
8484

@@ -219,6 +219,15 @@ No local changes to deploy.
219219

220220
- To see conflicts and ignored files, run "%s project deploy preview" with any of the manifest, directory, or metadata flags.
221221

222+
# error.InvalidDeployId
223+
224+
Invalid deploy ID: %s for org: %s
225+
226+
# error.InvalidDeployId.actions
227+
228+
- Ensure the deploy ID is correct.
229+
- Ensure the target-org username or alias is correct.
230+
222231
# flags.junit.summary
223232

224233
Output JUnit test results.

src/commands/project/deploy/report.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import { Messages, Org, SfProject } from '@salesforce/core';
99
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
1010
import { ComponentSet, DeployResult, MetadataApiDeploy } from '@salesforce/source-deploy-retrieve';
11-
import { buildComponentSet, DeployOptions } from '../../../utils/deploy';
11+
import { buildComponentSet } from '../../../utils/deploy';
1212
import { DeployProgress } from '../../../utils/progressBar';
1313
import { DeployCache } from '../../../utils/deployCache';
1414
import { DeployReportResultFormatter } from '../../../formatters/deployReportResultFormatter';
@@ -73,7 +73,7 @@ export default class DeployMetadataReport extends SfCommand<DeployResultJson> {
7373
const [{ flags }, cache] = await Promise.all([this.parse(DeployMetadataReport), DeployCache.create()]);
7474
const jobId = cache.resolveLatest(flags['use-most-recent'], flags['job-id'], false);
7575

76-
const deployOpts = cache.get(jobId) ?? ({} as DeployOptions & { isMdapi: boolean });
76+
const deployOpts = cache.get(jobId) ?? {};
7777
const waitDuration = flags['wait'];
7878
const org = flags['target-org'] ?? (await Org.create({ aliasOrUsername: deployOpts['target-org'] }));
7979

@@ -105,8 +105,15 @@ export default class DeployMetadataReport extends SfCommand<DeployResultJson> {
105105
});
106106

107107
const getDeployResult = async (): Promise<DeployResult> => {
108-
const deployStatus = await mdapiDeploy.checkStatus();
109-
return new DeployResult(deployStatus, componentSet);
108+
try {
109+
const deployStatus = await mdapiDeploy.checkStatus();
110+
return new DeployResult(deployStatus, componentSet);
111+
} catch (error) {
112+
if (error instanceof Error && error.name === 'sf:INVALID_CROSS_REFERENCE_KEY') {
113+
throw deployMessages.createError('error.InvalidDeployId', [jobId, org.getUsername()]);
114+
}
115+
throw error;
116+
}
110117
};
111118

112119
let result: DeployResult;

src/formatters/deployReportResultFormatter.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,15 @@ export class DeployReportResultFormatter extends DeployResultFormatter {
3232
ux.table(response, { key: {}, value: {} }, { title: tableHeader('Deploy Info'), 'no-truncate': true });
3333

3434
const opts = Object.entries(this.flags).reduce<Array<{ key: string; value: unknown }>>((result, [key, value]) => {
35-
if (key === 'timestamp') return result;
36-
if (key === 'target-org')
35+
if (key === 'timestamp') {
36+
return result;
37+
}
38+
if (key === 'target-org') {
3739
return result.concat({ key: 'target-org', value: this.flags['target-org']?.getUsername() });
40+
}
41+
if (key === 'wait') {
42+
return result.concat({ key: 'wait', value: `${this.flags['wait']?.quantity} minutes` });
43+
}
3844
return result.concat({ key, value });
3945
}, []);
4046
ux.log();

src/formatters/deployResultFormatter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import * as fs from 'fs';
1010
import { ux } from '@oclif/core';
1111
import { DeployResult, FileResponse, FileResponseFailure, RequestStatus } from '@salesforce/source-deploy-retrieve';
1212
import { Org, SfError, Lifecycle } from '@salesforce/core';
13-
import { ensureArray } from '@salesforce/kit';
13+
import { Duration, ensureArray } from '@salesforce/kit';
1414
import {
1515
CodeCoverageResult,
1616
CoverageReporter,
@@ -45,6 +45,7 @@ export class DeployResultFormatter extends TestResultsFormatter implements Forma
4545
junit: boolean;
4646
'results-dir': string;
4747
'target-org': Org;
48+
wait: Duration;
4849
}>
4950
) {
5051
super(result, flags);

test/commands/deploy/metadata/report-mdapi.nut.ts

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,26 @@
55
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
77

8+
import { unlinkSync, existsSync } from 'node:fs';
9+
import { join, resolve } from 'node:path';
810
import { SourceTestkit } from '@salesforce/source-testkit';
911
import { assert, expect } from 'chai';
12+
import { RequestStatus } from '@salesforce/source-deploy-retrieve';
1013
import { DeployResultJson } from '../../../../src/utils/types';
1114

12-
describe('deploy metadata report NUTs with source-dir', () => {
15+
describe('[project deploy report] NUTs with metadata-dir', () => {
1316
let testkit: SourceTestkit;
17+
const mdSourceDir = 'mdapiOut';
18+
const orgAlias = 'reportMdTestOrg2';
1419

1520
before(async () => {
1621
testkit = await SourceTestkit.create({
1722
repository: 'https://github.com/salesforcecli/sample-project-multiple-packages.git',
1823
nut: __filename,
24+
scratchOrgs: [{ duration: 1, alias: orgAlias, config: join('config', 'project-scratch-def.json') }],
1925
});
2026
await testkit.convert({
21-
args: '--source-dir force-app --output-dir mdapiOut',
27+
args: `--source-dir force-app --output-dir ${mdSourceDir}`,
2228
json: true,
2329
exitCode: 0,
2430
});
@@ -31,7 +37,7 @@ describe('deploy metadata report NUTs with source-dir', () => {
3137
describe('--use-most-recent', () => {
3238
it('should report most recently started deployment', async () => {
3339
await testkit.execute<DeployResultJson>('project deploy start', {
34-
args: '--metadata-dir mdapiOut --async',
40+
args: `--metadata-dir ${mdSourceDir} --async`,
3541
json: true,
3642
exitCode: 0,
3743
});
@@ -42,40 +48,49 @@ describe('deploy metadata report NUTs with source-dir', () => {
4248
exitCode: 0,
4349
});
4450
assert(deploy?.result);
45-
expect(deploy.result.success).to.equal(true);
51+
expect([RequestStatus.Pending, RequestStatus.Succeeded, RequestStatus.InProgress]).includes(deploy.result.status);
4652
});
53+
});
4754

48-
it.skip('should report most recently started deployment without specifying the flag', async () => {
49-
await testkit.execute<DeployResultJson>('project deploy start', {
50-
args: '--metadata-dir mdapiOut --async',
55+
describe('--job-id', () => {
56+
it('should report the provided job id', async () => {
57+
const first = await testkit.execute<DeployResultJson>('project deploy start', {
58+
args: `--metadata-dir ${mdSourceDir} --async`,
5159
json: true,
5260
exitCode: 0,
5361
});
54-
5562
const deploy = await testkit.execute<DeployResultJson>('project deploy report', {
63+
args: `--job-id ${first?.result.id}`,
5664
json: true,
5765
exitCode: 0,
5866
});
5967
assert(deploy?.result);
60-
expect(deploy.result.success).to.equal(true);
68+
expect([RequestStatus.Pending, RequestStatus.Succeeded, RequestStatus.InProgress]).includes(deploy.result.status);
69+
expect(deploy.result.id).to.equal(first?.result.id);
6170
});
62-
});
6371

64-
describe('--job-id', () => {
65-
it('should report the provided job id', async () => {
72+
it('should report from specified target-org and job-id without deploy cache', async () => {
6673
const first = await testkit.execute<DeployResultJson>('project deploy start', {
67-
args: '--metadata-dir mdapiOut --async',
74+
args: `--metadata-dir ${mdSourceDir} --async --target-org ${orgAlias}`,
6875
json: true,
6976
exitCode: 0,
7077
});
78+
79+
// delete the cache file so we can verify that reporting just with job-id and org works
80+
const deployCacheFilePath = resolve(testkit.projectDir, join('..', '.sf', 'deploy-cache.json'));
81+
unlinkSync(deployCacheFilePath);
82+
assert(!existsSync(deployCacheFilePath));
83+
7184
const deploy = await testkit.execute<DeployResultJson>('project deploy report', {
72-
args: `--job-id ${first?.result.id}`,
85+
args: `--job-id ${first?.result.id} --target-org ${orgAlias} --wait 9`,
7386
json: true,
7487
exitCode: 0,
7588
});
7689
assert(deploy?.result);
7790
expect(deploy.result.success).to.equal(true);
91+
expect(deploy.result.status).to.equal(RequestStatus.Succeeded);
7892
expect(deploy.result.id).to.equal(first?.result.id);
93+
await testkit.expect.filesToBeDeployed(['force-app/**/*'], ['force-app/test/**/*']);
7994
});
8095
});
8196
});

test/commands/deploy/metadata/report.nut.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
77

8-
import * as fs from 'fs';
9-
import * as path from 'path';
8+
import { unlinkSync, existsSync } from 'node:fs';
9+
import { join, resolve } from 'node:path';
1010
import { SourceTestkit } from '@salesforce/source-testkit';
1111
import { assert, isObject } from '@salesforce/ts-types';
1212
import { expect } from 'chai';
@@ -21,7 +21,7 @@ describe('[project deploy report] NUTs with source-dir', () => {
2121
testkit = await SourceTestkit.create({
2222
repository: 'https://github.com/salesforcecli/sample-project-multiple-packages.git',
2323
nut: __filename,
24-
scratchOrgs: [{ duration: 1, alias: orgAlias, config: path.join('config', 'project-scratch-def.json') }],
24+
scratchOrgs: [{ duration: 1, alias: orgAlias, config: join('config', 'project-scratch-def.json') }],
2525
});
2626
});
2727

@@ -71,9 +71,9 @@ describe('[project deploy report] NUTs with source-dir', () => {
7171
});
7272

7373
// delete the cache file so we can verify that reporting just with job-id and org works
74-
const deployCacheFilePath = path.resolve(testkit.projectDir, path.join('..', '.sf', 'deploy-cache.json'));
75-
fs.unlinkSync(deployCacheFilePath);
76-
assert(!fs.existsSync(deployCacheFilePath));
74+
const deployCacheFilePath = resolve(testkit.projectDir, join('..', '.sf', 'deploy-cache.json'));
75+
unlinkSync(deployCacheFilePath);
76+
assert(!existsSync(deployCacheFilePath));
7777

7878
const deploy = await testkit.execute<DeployResultJson>('project deploy report', {
7979
args: `--job-id ${first?.result.id} --target-org ${orgAlias} --wait 9`,
@@ -97,13 +97,13 @@ describe('[project deploy report] NUTs with source-dir', () => {
9797
json: true,
9898
exitCode: 0,
9999
});
100-
expect(fs.existsSync(path.join(testkit.projectDir, 'test-output-override'))).to.be.true;
101-
expect(fs.existsSync(path.join(testkit.projectDir, 'test-output-override', 'coverage'))).to.be.true;
102-
expect(fs.existsSync(path.join(testkit.projectDir, 'test-output-override', 'coverage', 'html'))).to.be.true;
103-
expect(fs.existsSync(path.join(testkit.projectDir, 'test-output-override', 'coverage', 'text.txt'))).to.be.true;
104-
expect(fs.existsSync(path.join(testkit.projectDir, 'test-output-override', 'junit'))).to.be.true;
105-
expect(fs.existsSync(path.join(testkit.projectDir, 'test-output-override', 'junit', 'junit.xml'))).to.be.true;
106-
expect(fs.existsSync(path.join(testkit.projectDir, 'test-output'))).to.be.false;
100+
expect(existsSync(join(testkit.projectDir, 'test-output-override'))).to.be.true;
101+
expect(existsSync(join(testkit.projectDir, 'test-output-override', 'coverage'))).to.be.true;
102+
expect(existsSync(join(testkit.projectDir, 'test-output-override', 'coverage', 'html'))).to.be.true;
103+
expect(existsSync(join(testkit.projectDir, 'test-output-override', 'coverage', 'text.txt'))).to.be.true;
104+
expect(existsSync(join(testkit.projectDir, 'test-output-override', 'junit'))).to.be.true;
105+
expect(existsSync(join(testkit.projectDir, 'test-output-override', 'junit', 'junit.xml'))).to.be.true;
106+
expect(existsSync(join(testkit.projectDir, 'test-output'))).to.be.false;
107107
assert(isObject(deploy));
108108
await testkit.expect.filesToBeDeployedViaResult(['force-app/**/*'], ['force-app/test/**/*'], deploy.result.files);
109109
});

0 commit comments

Comments
 (0)