Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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_'
Comment thread
shetzel marked this conversation as resolved.
Outdated

# 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