Skip to content

Commit

Permalink
Merge pull request #687 from salesforcecli/mradul/managed-packaging/W…
Browse files Browse the repository at this point in the history
…-15103954/async-validation

feat: async validation for package version create
  • Loading branch information
shetzel authored Jun 18, 2024
2 parents 30da563 + f01c925 commit 2b961dc
Show file tree
Hide file tree
Showing 14 changed files with 173 additions and 30 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ Create a package version in the Dev Hub org.
```
USAGE
$ sf package version create -v <value> [--json] [--flags-dir <value>] [--api-version <value>] [-b <value>] [-c |
--skip-validation] [-f <value>] [-k <value>] [-x] [-p <value>] [-d <value>] [--post-install-script <value>]
--skip-validation | --async-validation] [-f <value>] [-k <value>] [-x] [-p <value>] [-d <value>] [--post-install-script <value>]
[--post-install-url <value>] [--releasenotes-url <value>] [--skip-ancestor-check] [-t <value>] [--uninstall-script
<value>] [-e <value>] [-a <value>] [-n <value>] [-w <value>] [--language <value>] [--verbose]
Expand Down Expand Up @@ -554,6 +554,7 @@ FLAGS
that isn’t the highest released package version.
--skip-validation Skip validation during package version creation; you can’t promote unvalidated
package versions.
--async-validation Return a new package version before completing package validations.
--uninstall-script=<value> Uninstall script name; applies to managed packages only.
--verbose Display verbose command output.
Expand Down Expand Up @@ -602,6 +603,9 @@ EXAMPLES
$ sf package version create --path common --installation-key password123 --skip-validation
Create a package version and perform package validations asynchronously:
$ sf package version create --path common --installation-key password123 --async-validation
FLAG DESCRIPTIONS
-c, --code-coverage
Expand Down Expand Up @@ -652,6 +656,12 @@ FLAG DESCRIPTIONS
versions. Skipping validation can suppress important errors that can surface at a later stage. You can specify skip
validation or code coverage, but not both. Code coverage is calculated during validation.
--async-validation Return a new package version before completing package validations.
Specifying async validation returns the package version earlier in the process, allowing you to install and test
the new version right away. If your development team is using continuous integration (CI) scripts, async validation
can reduce your overall CI run time.
--uninstall-script=<value> Uninstall script name; applies to managed packages only.
The uninstall script is an Apex class within this package that is run in the installing org after uninstallations of
Expand Down
2 changes: 2 additions & 0 deletions command-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@
"releasenotesurl",
"skipancestorcheck",
"skipvalidation",
"asyncvalidation",
"target-hub-org",
"targetdevhubusername",
"uninstallscript",
Expand Down Expand Up @@ -258,6 +259,7 @@
"releasenotes-url",
"skip-ancestor-check",
"skip-validation",
"async-validation",
"tag",
"target-dev-hub",
"uninstall-script",
Expand Down
18 changes: 18 additions & 0 deletions messages/package_version_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ We don’t calculate code coverage for org-dependent unlocked packages, or for p

<%= config.bin %> <%= command.id %> --path common --installation-key password123 --skip-validation

- Create a package version and perform package validations asynchronously:

<%= config.bin %> <%= command.id %> --path common --installation-key password123 --async-validation

# flags.package.summary

ID (starts with 0Ho) or alias of the package to create a version of.
Expand Down Expand Up @@ -129,6 +133,14 @@ Skips validation of dependencies, package ancestors, and metadata during package

Skipping validation suppresses errors that usually surface during package version creation. Instead, these errors surface at a later stage, such as installation or post-installation. If you encounter errors that are difficult to debug, retry package version creation without the --skip-validation parameter.

# flags.async-validation.summary

Return a new package version before completing package validations.

# flags.async-validation.description

Specifying async validation returns the package version earlier in the process, allowing you to install and test the new version right away. If your development team is using continuous integration (CI) scripts, async validation can reduce your overall CI run time.

# flags.skip-ancestor-check.summary

Overrides ancestry requirements, which allows you to specify a package ancestor that isn’t the highest released package version.
Expand Down Expand Up @@ -199,6 +211,12 @@ Version create.

%d minutes remaining until timeout. Create version status: %s

# packageVersionCreatePerformingValidations

The validations for this package version are in progress, but you can now begin testing this package version.
To determine whether all package validations completed successfully, run sf package version create report and review the Async Validation Status.
Async validated package versions can be promoted only if all validations completed successfully.

# packageVersionCreateFinalStatus

Create version status: %s
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"bugs": "https://github.com/forcedotcom/cli/issues",
"dependencies": {
"@oclif/core": "^4",
"@salesforce/core": "^7.3.8",
"@salesforce/kit": "^3.1.0",
"@salesforce/packaging": "^3.5.16",
"@salesforce/core": "^7.4.1",
"@salesforce/kit": "^3.1.6",
"@salesforce/packaging": "^3.7.1",
"@salesforce/sf-plugins-core": "^11.1.0",
"chalk": "^5.3.0"
},
Expand Down
3 changes: 2 additions & 1 deletion schemas/package-convert.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@
"VerifyingFeaturesAndSettings",
"VerifyingDependencies",
"VerifyingMetadata",
"FinalizingPackageVersion"
"FinalizingPackageVersion",
"PerformingValidations"
]
}
}
Expand Down
3 changes: 2 additions & 1 deletion schemas/package-version-create-list.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@
"VerifyingFeaturesAndSettings",
"VerifyingDependencies",
"VerifyingMetadata",
"FinalizingPackageVersion"
"FinalizingPackageVersion",
"PerformingValidations"
]
}
}
Expand Down
3 changes: 2 additions & 1 deletion schemas/package-version-create-report.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@
"VerifyingFeaturesAndSettings",
"VerifyingDependencies",
"VerifyingMetadata",
"FinalizingPackageVersion"
"FinalizingPackageVersion",
"PerformingValidations"
]
}
}
Expand Down
3 changes: 2 additions & 1 deletion schemas/package-version-create.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
"VerifyingFeaturesAndSettings",
"VerifyingDependencies",
"VerifyingMetadata",
"FinalizingPackageVersion"
"FinalizingPackageVersion",
"PerformingValidations"
]
}
}
Expand Down
3 changes: 3 additions & 0 deletions schemas/package-version-report.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@
"ValidationSkipped": {
"type": "boolean"
},
"ValidatedAsync": {
"type": "boolean"
},
"Name": {
"type": "string"
},
Expand Down
23 changes: 21 additions & 2 deletions src/commands/package/version/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,13 @@ export class PackageVersionCreateCommand extends SfCommand<PackageVersionCommand
summary: messages.getMessage('flags.skip-validation.summary'),
description: messages.getMessage('flags.skip-validation.description'),
default: false,
exclusive: ['code-coverage'],
exclusive: ['code-coverage', 'async-validation'],
}),
'async-validation': Flags.boolean({
summary: messages.getMessage('flags.async-validation.summary'),
description: messages.getMessage('flags.async-validation.description'),
default: false,
exclusive: ['skip-validation'],
}),
tag: Flags.string({
char: 't',
Expand Down Expand Up @@ -193,7 +199,8 @@ export class PackageVersionCreateCommand extends SfCommand<PackageVersionCommand
// no async methods
// eslint-disable-next-line @typescript-eslint/require-await
async (data: PackageVersionCreateReportProgress) => {
if (data.Status !== Package2VersionStatus.success && data.Status !== Package2VersionStatus.error) {
if (data.Status !== Package2VersionStatus.success && data.Status !== Package2VersionStatus.error && data.Status !== Package2VersionStatus.performingValidations
) {
const status = messages.getMessage('packageVersionCreateWaitingStatus', [
data.remainingWaitTime.minutes,
data.Status,
Expand Down Expand Up @@ -251,6 +258,18 @@ export class PackageVersionCreateCommand extends SfCommand<PackageVersionCommand
throw messages.createError('multipleErrors', [
result.Error?.map((e: string, i) => `${os.EOL}(${i + 1}) ${e}`).join(''),
]);
case Package2VersionStatus.performingValidations:
this.log(messages.getMessage('packageVersionCreatePerformingValidations'));
this.log(
messages.getMessage(Package2VersionStatus.success, [
result.Id,
result.SubscriberPackageVersionId,
INSTALL_URL_BASE.toString(),
result.SubscriberPackageVersionId,
this.config.bin,
])
);
break;
case Package2VersionStatus.success:
this.log(
messages.getMessage(result.Status, [
Expand Down
11 changes: 11 additions & 0 deletions test/commands/package/packageVersion.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ describe('package:version:*', () => {
expect(result).to.match(/Run "sfd?x? package:version:create:report -i 08c.{15}" to query for status\./);
});

it('should create a new package version with async-validation', () => {
const result = execCmd(
`package:version:create --package ${pkgName} -x --async-validation --version-description "Initial version"`,
{ ensureExitCode: 0 }
).shellOutput.stdout;
// eslint-disable-next-line no-console
console.log(result);
expect(result).to.include("Package version creation request status is '");
expect(result).to.match(/Run "sfd?x? package:version:create:report -i 08c.{15}" to query for status\./);
});

// package:version:create --wait --json is tested in versionPromoteUpdate.nut.ts
it('should create a new package version and wait (human)', () => {
const result = execCmd(
Expand Down
31 changes: 31 additions & 0 deletions test/commands/package/packageVersionCreate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,37 @@ describe('package:version:create - tests', () => {
]);
});

it('should create a new package version with async validation', async () => {
createStub = $$.SANDBOX.stub(PackageVersion, 'create');
createStub.resolves(pkgVersionCreateSuccessResult);
const envSpy = $$.SANDBOX.spy(env, 'setBoolean').withArgs('SF_APPLY_REPLACEMENTS_ON_CONVERT', true);

const cmd = new PackageVersionCreateCommand(
['-p', '05i3i000000Gmj6XXX', '-v', 'test@hub.org', '-x', '--async-validation'],
config
);
stubSpinner(cmd);
const res = await cmd.run();
expect(envSpy.calledOnce).to.equal(true);
expect(res).to.deep.equal({
Branch: undefined,
CreatedBy: '0053i000001ZIyGAAW',
CreatedDate: '2022-11-03 09:46',
Error: [],
HasMetadataRemoved: false,
Id: '08c3i000000fylgAAA',
Package2Id: '0Ho3i000000TNHYCA4',
Package2VersionId: '05i3i000000fxw1AAA',
Status: 'Success',
SubscriberPackageVersionId: '04t3i000002eya2AAA',
Tag: undefined,
});
expect(logStub.callCount).to.equal(1);
expect(logStub.args[0]).to.deep.equal([
`Successfully created the package version [08c3i000000fylgAAA]. Subscriber Package Version Id: 04t3i000002eya2AAA${os.EOL}Package Installation URL: https://login.salesforce.com/packaging/installPackage.apexp?p0=04t3i000002eya2AAA${os.EOL}As an alternative, you can use the "sf package:install" command.`,
]);
});

it('should report multiple errors', async () => {
createStub = $$.SANDBOX.stub(PackageVersion, 'create');
createStub.resolves(pkgVersionCreateErrorResult);
Expand Down
45 changes: 45 additions & 0 deletions test/commands/package/packageVersionCreateReport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,23 @@ const pkgVersionCreateSuccessResult: PackageVersionCreateRequestResult = {
CreatedBy: '0053i000001ZIyGAAW',
};

const pkgVersionCreateSuccessResultAsyncValidation: PackageVersionCreateRequestResult = {
Id: '08c3i000000fylgAAA',
Status: Package2VersionStatus.success,
Package2Id: '0Ho3i000000TNHYCA4',
Package2VersionId: '05i3i000000fxw1AAA',
SubscriberPackageVersionId: '04t3i000002eya2AAA',
// @ts-ignore
Tag: null,
// @ts-ignore
Branch: null,
Error: [],
CreatedDate: '2022-11-03 09:46',
HasMetadataRemoved: false,
CreatedBy: '0053i000001ZIyGAAW',
ValidatedAsync: true,
};

describe('package:version:create:report - tests', () => {
const $$ = new TestContext();
const testOrg = new MockTestOrgData();
Expand Down Expand Up @@ -116,6 +133,34 @@ describe('package:version:create:report - tests', () => {
expect(styledHeaderStub.callCount).to.equal(1);
});

it('should report on a new package version with async validation', async () => {
createStatusStub = $$.SANDBOX.stub(PackageVersion, 'getCreateStatus');
createStatusStub.resolves(pkgVersionCreateSuccessResultAsyncValidation);
const res = await new PackageVersionCreateReportCommand(
['-i', '08c3i000000fyoVAAQ', '-v', 'test@hub.org'],
config
).run();

expect(res).to.deep.equal([
{
Branch: null,
CreatedBy: '0053i000001ZIyGAAW',
CreatedDate: '2022-11-03 09:46',
Error: [],
HasMetadataRemoved: false,
Id: '08c3i000000fylgAAA',
Package2Id: '0Ho3i000000TNHYCA4',
Package2VersionId: '05i3i000000fxw1AAA',
Status: 'Success',
SubscriberPackageVersionId: '04t3i000002eya2AAA',
Tag: null,
ValidatedAsync: true,
},
]);
expect(tableStub.callCount).to.equal(1);
expect(styledHeaderStub.callCount).to.equal(1);
});

it('should report multiple errors', async () => {
createStatusStub = $$.SANDBOX.stub(PackageVersion, 'getCreateStatus');
createStatusStub.resolves(pkgVersionCreateErrorResult);
Expand Down
40 changes: 20 additions & 20 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1478,7 +1478,7 @@
strip-ansi "6.0.1"
ts-retry-promise "^0.8.0"

"@salesforce/core@^7.0.0", "@salesforce/core@^7.3.1", "@salesforce/core@^7.3.5", "@salesforce/core@^7.3.6", "@salesforce/core@^7.3.8", "@salesforce/core@^7.4.1":
"@salesforce/core@^7.0.0", "@salesforce/core@^7.3.1", "@salesforce/core@^7.3.12", "@salesforce/core@^7.3.6", "@salesforce/core@^7.4.1":
version "7.4.1"
resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-7.4.1.tgz#7c37623f6a89c199bf12cd6dc28d89bc950914ef"
integrity sha512-ccYs7uL4GYjdOcc44trfRnaz69kG0jU0aoT0qjPkIel8oVOyEoXaoDCG0A+2diqmicDp5uWK0pNs+tdWNj2mcQ==
Expand Down Expand Up @@ -1546,19 +1546,19 @@
dependencies:
"@salesforce/ts-types" "^2.0.10"

"@salesforce/packaging@^3.5.16":
version "3.5.16"
resolved "https://registry.yarnpkg.com/@salesforce/packaging/-/packaging-3.5.16.tgz#24ca1c0c15b8416f038de5ae136a2ede396c02bf"
integrity sha512-9dQoO7RSXPEfjZkZBQg3eqNUH8lJwc4voXkVFILZpeqbPVp2z20fLBppsiuVjpDG+AQl7boKGcUr8zjJAiOk0g==
"@salesforce/packaging@^3.7.1":
version "3.7.1"
resolved "https://registry.yarnpkg.com/@salesforce/packaging/-/packaging-3.7.1.tgz#079745eceef4cee98a23792b39c1f3a962ef8669"
integrity sha512-MbY8bh5pXgjO8XyVW1zAeXrmIVl3vJZMeicnzKMJ8H91CWMlkAVAorvAlQf23VcJXapXzr3PvfzWNwQy1r4xLw==
dependencies:
"@jsforce/jsforce-node" "^3.2.0"
"@salesforce/core" "^7.3.6"
"@salesforce/kit" "^3.1.1"
"@salesforce/schemas" "^1.7.0"
"@salesforce/source-deploy-retrieve" "^11.4.3"
"@salesforce/core" "^7.4.1"
"@salesforce/kit" "^3.1.6"
"@salesforce/schemas" "^1.9.0"
"@salesforce/source-deploy-retrieve" "^11.6.5"
"@salesforce/ts-types" "^2.0.9"
"@salesforce/types" "^1.1.0"
fast-xml-parser "^4.3.6"
fast-xml-parser "^4.4.0"
globby "^11"
graphology "^0.25.4"
graphology-traversal "^0.3.1"
Expand All @@ -1585,7 +1585,7 @@
resolved "https://registry.yarnpkg.com/@salesforce/prettier-config/-/prettier-config-0.0.3.tgz#ba648d4886bb38adabe073dbea0b3a91b3753bb0"
integrity sha512-hYOhoPTCSYMDYn+U1rlEk16PoBeAJPkrdg4/UtAzupM1mRRJOwEPMG1d7U8DxJFKuXW3DMEYWr2MwAIBDaHmFg==

"@salesforce/schemas@^1.7.0", "@salesforce/schemas@^1.9.0":
"@salesforce/schemas@^1.9.0":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@salesforce/schemas/-/schemas-1.9.0.tgz#ba477a112653a20b4edcf989c61c57bdff9aa3ca"
integrity sha512-LiN37zG5ODT6z70sL1fxF7BQwtCX9JOWofSU8iliSNIM+WDEeinnoFtVqPInRSNt8I0RiJxIKCrqstsmQRBNvA==
Expand Down Expand Up @@ -1621,12 +1621,12 @@
"@salesforce/ts-types" "^2.0.9"
chalk "^5.3.0"

"@salesforce/source-deploy-retrieve@^11.4.3":
version "11.4.3"
resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-11.4.3.tgz#57ff91f5f0021804b268002362a695489f34ac5a"
integrity sha512-/WFSqf+yTO3kNM41r/duVEHGH2Eq18lavX/o/yA0hJEmxAYBV7Olv6JIMnbly8hZQo7LoX/nE0LnNK3JYphZQQ==
"@salesforce/source-deploy-retrieve@^11.6.5":
version "11.6.8"
resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-11.6.8.tgz#c50e2dbf921048451ee614bb4cb6089c8799b756"
integrity sha512-Z3/ehMn3ioUW50rVGcMIw+X6wqcD9Pgab626AxmGwjfPXeZhesuiV/qSuK7Y+yLmNmdNLoXbK10JsC28v1ObTA==
dependencies:
"@salesforce/core" "^7.3.5"
"@salesforce/core" "^7.3.12"
"@salesforce/kit" "^3.1.1"
"@salesforce/ts-types" "^2.0.9"
fast-levenshtein "^3.0.0"
Expand Down Expand Up @@ -3988,10 +3988,10 @@ fast-xml-parser@4.2.5:
dependencies:
strnum "^1.0.5"

fast-xml-parser@^4.3.6:
version "4.3.6"
resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.3.6.tgz#190f9d99097f0c8f2d3a0e681a10404afca052ff"
integrity sha512-M2SovcRxD4+vC493Uc2GZVcZaj66CCJhWurC4viynVSTvrpErCShNcDz1lAho6n9REQKvL/ll4A4/fw6Y9z8nw==
fast-xml-parser@^4.3.6, fast-xml-parser@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz#341cc98de71e9ba9e651a67f41f1752d1441a501"
integrity sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==
dependencies:
strnum "^1.0.5"

Expand Down

0 comments on commit 2b961dc

Please sign in to comment.