Skip to content

Commit

Permalink
fix: better error reporting and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
shetzel committed Sep 26, 2023
1 parent 89057b6 commit dd488a3
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 35 deletions.
11 changes: 10 additions & 1 deletion messages/deploy.metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Overrides your default org.

# flags.metadata.summary

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

# flags.test-level.summary

Expand Down Expand Up @@ -219,6 +219,15 @@ No local changes to deploy.

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

# error.InvalidDeployId

Invalid deploy ID: %s for org: %s

# error.InvalidDeployId.actions

- Ensure the deploy ID is correct.
- Ensure the target-org username or alias is correct.

# flags.junit.summary

Output JUnit test results.
Expand Down
15 changes: 11 additions & 4 deletions src/commands/project/deploy/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { Messages, Org, SfProject } from '@salesforce/core';
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { ComponentSet, DeployResult, MetadataApiDeploy } from '@salesforce/source-deploy-retrieve';
import { buildComponentSet, DeployOptions } from '../../../utils/deploy';
import { buildComponentSet } from '../../../utils/deploy';
import { DeployProgress } from '../../../utils/progressBar';
import { DeployCache } from '../../../utils/deployCache';
import { DeployReportResultFormatter } from '../../../formatters/deployReportResultFormatter';
Expand Down Expand Up @@ -73,7 +73,7 @@ export default class DeployMetadataReport extends SfCommand<DeployResultJson> {
const [{ flags }, cache] = await Promise.all([this.parse(DeployMetadataReport), DeployCache.create()]);
const jobId = cache.resolveLatest(flags['use-most-recent'], flags['job-id'], false);

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

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

const getDeployResult = async (): Promise<DeployResult> => {
const deployStatus = await mdapiDeploy.checkStatus();
return new DeployResult(deployStatus, componentSet);
try {
const deployStatus = await mdapiDeploy.checkStatus();
return new DeployResult(deployStatus, componentSet);
} catch (error) {
if (error instanceof Error && error.name === 'sf:INVALID_CROSS_REFERENCE_KEY') {
throw deployMessages.createError('error.InvalidDeployId', [jobId, org.getUsername()]);
}
throw error;
}
};

let result: DeployResult;
Expand Down
10 changes: 8 additions & 2 deletions src/formatters/deployReportResultFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@ export class DeployReportResultFormatter extends DeployResultFormatter {
ux.table(response, { key: {}, value: {} }, { title: tableHeader('Deploy Info'), 'no-truncate': true });

const opts = Object.entries(this.flags).reduce<Array<{ key: string; value: unknown }>>((result, [key, value]) => {
if (key === 'timestamp') return result;
if (key === 'target-org')
if (key === 'timestamp') {
return result;
}
if (key === 'target-org') {
return result.concat({ key: 'target-org', value: this.flags['target-org']?.getUsername() });
}
if (key === 'wait') {
return result.concat({ key: 'wait', value: `${this.flags['wait']?.quantity} minutes` });
}
return result.concat({ key, value });
}, []);
ux.log();
Expand Down
3 changes: 2 additions & 1 deletion src/formatters/deployResultFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as fs from 'fs';
import { ux } from '@oclif/core';
import { DeployResult, FileResponse, FileResponseFailure, RequestStatus } from '@salesforce/source-deploy-retrieve';
import { Org, SfError, Lifecycle } from '@salesforce/core';
import { ensureArray } from '@salesforce/kit';
import { Duration, ensureArray } from '@salesforce/kit';
import {
CodeCoverageResult,
CoverageReporter,
Expand Down Expand Up @@ -45,6 +45,7 @@ export class DeployResultFormatter extends TestResultsFormatter implements Forma
junit: boolean;
'results-dir': string;
'target-org': Org;
wait: Duration;
}>
) {
super(result, flags);
Expand Down
43 changes: 29 additions & 14 deletions test/commands/deploy/metadata/report-mdapi.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,26 @@
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

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

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

before(async () => {
testkit = await SourceTestkit.create({
repository: 'https://github.com/salesforcecli/sample-project-multiple-packages.git',
nut: __filename,
scratchOrgs: [{ duration: 1, alias: orgAlias, config: join('config', 'project-scratch-def.json') }],
});
await testkit.convert({
args: '--source-dir force-app --output-dir mdapiOut',
args: `--source-dir force-app --output-dir ${mdSourceDir}`,
json: true,
exitCode: 0,
});
Expand All @@ -31,7 +37,7 @@ describe('deploy metadata report NUTs with source-dir', () => {
describe('--use-most-recent', () => {
it('should report most recently started deployment', async () => {
await testkit.execute<DeployResultJson>('project deploy start', {
args: '--metadata-dir mdapiOut --async',
args: `--metadata-dir ${mdSourceDir} --async`,
json: true,
exitCode: 0,
});
Expand All @@ -42,40 +48,49 @@ describe('deploy metadata report NUTs with source-dir', () => {
exitCode: 0,
});
assert(deploy?.result);
expect(deploy.result.success).to.equal(true);
expect([RequestStatus.Pending, RequestStatus.Succeeded, RequestStatus.InProgress]).includes(deploy.result.status);
});
});

it.skip('should report most recently started deployment without specifying the flag', async () => {
await testkit.execute<DeployResultJson>('project deploy start', {
args: '--metadata-dir mdapiOut --async',
describe('--job-id', () => {
it('should report the provided job id', async () => {
const first = await testkit.execute<DeployResultJson>('project deploy start', {
args: `--metadata-dir ${mdSourceDir} --async`,
json: true,
exitCode: 0,
});

const deploy = await testkit.execute<DeployResultJson>('project deploy report', {
args: `--job-id ${first?.result.id}`,
json: true,
exitCode: 0,
});
assert(deploy?.result);
expect(deploy.result.success).to.equal(true);
expect([RequestStatus.Pending, RequestStatus.Succeeded, RequestStatus.InProgress]).includes(deploy.result.status);
expect(deploy.result.id).to.equal(first?.result.id);
});
});

describe('--job-id', () => {
it('should report the provided job id', async () => {
it('should report from specified target-org and job-id without deploy cache', async () => {
const first = await testkit.execute<DeployResultJson>('project deploy start', {
args: '--metadata-dir mdapiOut --async',
args: `--metadata-dir ${mdSourceDir} --async --target-org ${orgAlias}`,
json: true,
exitCode: 0,
});

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

const deploy = await testkit.execute<DeployResultJson>('project deploy report', {
args: `--job-id ${first?.result.id}`,
args: `--job-id ${first?.result.id} --target-org ${orgAlias} --wait 9`,
json: true,
exitCode: 0,
});
assert(deploy?.result);
expect(deploy.result.success).to.equal(true);
expect(deploy.result.status).to.equal(RequestStatus.Succeeded);
expect(deploy.result.id).to.equal(first?.result.id);
await testkit.expect.filesToBeDeployed(['force-app/**/*'], ['force-app/test/**/*']);
});
});
});
26 changes: 13 additions & 13 deletions test/commands/deploy/metadata/report.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

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

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

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

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

0 comments on commit dd488a3

Please sign in to comment.