Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion command-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@
"version-description",
"version-name",
"version-number",
"wait"
"wait",
"generate-pkg-zip"
],
"plugin": "@salesforce/plugin-packaging"
},
Expand Down
6 changes: 5 additions & 1 deletion messages/package_version_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,13 @@ 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.

# flags.generate-pkg-zip.summary

Generate a package ZIP file that you can use for debugging or to examine the package contents.

# flags.skip-ancestor-check.summary

Overrides ancestry requirements, which allows you to specify a package ancestor that isn’t the highest released package version.
Override ancestry requirements, which allows you to specify a package ancestor that isn’t the highest released package version.

# flags.post-install-url.summary

Expand Down
4 changes: 4 additions & 0 deletions src/commands/package/version/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ export class PackageVersionCreateCommand extends SfCommand<PackageVersionCommand
default: false,
exclusive: ['skip-validation'],
}),
'generate-pkg-zip': Flags.boolean({
summary: messages.getMessage('flags.generate-pkg-zip.summary'),
default: false,
}),
tag: Flags.string({
char: 't',
summary: messages.getMessage('flags.tag.summary'),
Expand Down
136 changes: 136 additions & 0 deletions test/commands/package/packageVersionCreateManaged.nut.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright 2026, Salesforce, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as fs from 'node:fs';
import * as path from 'node:path';
import { expect } from 'chai';
import { execCmd, TestSession } from '@salesforce/cli-plugins-testkit';
import { Org, SfProject } from '@salesforce/core';
import { Duration } from '@salesforce/kit';
import { PackageVersionCreateRequestResult } from '@salesforce/packaging';
import { FileDownloadEntry } from '../../../src/commands/package/version/retrieve.js';

let packageName: string;
let devHubOrg: Org;

describe('package:version:create with managed package (--generate-pkg-zip)', () => {
let session: TestSession;
let managedPackageId: string;

before('setup managed package', async function () {
// TODO: Remove once 260 is released to instance the CI dev hub is running on
this.skip();
this.timeout(Duration.minutes(5).milliseconds);

session = await TestSession.create({
devhubAuthStrategy: 'AUTO',
project: { name: 'managed-pkg-test' },
});

devHubOrg = await Org.create({ aliasOrUsername: session.hubOrg.username });

// Query for existing managed package
const existingPkgQuery = `
SELECT Id, Name, NamespacePrefix
FROM Package2
WHERE ContainerOptions = 'Managed'
AND IsDeprecated = false
AND Name = 'pnhmanaged'
LIMIT 1
`;
const existingPkgRecords = (
await devHubOrg
.getConnection()
.tooling.query<{ Id: string; Name: string; NamespacePrefix: string }>(existingPkgQuery)
).records;

managedPackageId = existingPkgRecords[0].Id;

// Create minimal source structure for a custom object
const objectName = 'TestObject__c';
const objectDir = path.join(session.project.dir, 'force-app', 'main', 'default', 'objects', objectName);
fs.mkdirSync(objectDir, { recursive: true });

fs.writeFileSync(
path.join(objectDir, `${objectName}.object-meta.xml`),
`<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<deploymentStatus>Deployed</deploymentStatus>
<label>Test Object</label>
<nameField>
<label>Test Object Name</label>
<type>Text</type>
</nameField>
<pluralLabel>Test Objects</pluralLabel>
<sharingModel>ReadWrite</sharingModel>
</CustomObject>`
);

// Configure the project for the managed package
const project = await SfProject.resolve(session.project.dir);
const projectJson = project.getSfProjectJson();
const namespacePrefix = existingPkgRecords[0].NamespacePrefix;
packageName = existingPkgRecords[0].Name;

const packageDirectory = {
path: 'force-app',
package: existingPkgRecords[0].Name,
versionNumber: '1.0.0.NEXT',
ancestorVersion: 'NONE',
versionName: 'v1',
default: true,
};

projectJson.set('packageDirectories', [packageDirectory]);
projectJson.set('packageAliases', { [packageName]: managedPackageId });
projectJson.set('namespace', namespacePrefix);
projectJson.writeSync();
});

after(async () => {
await session?.clean();
});

it('should create a managed package version with --generate-pkg-zip flag and retrieve the metadata', async function () {
this.timeout(Duration.minutes(25).milliseconds);

const createResult = execCmd<PackageVersionCreateRequestResult>(
`package:version:create --package ${packageName} --wait 20 -x --generate-pkg-zip --version-description "Test pkg zip" --json --skip-ancestor-check`,
{ ensureExitCode: 0, timeout: Duration.minutes(20).milliseconds }
).jsonOutput?.result;

// Debug: verify the flag was actually set
const pvcRequestId = createResult?.Id;
const verifyQuery = `SELECT Id, IsDevUsePkgZipRequested FROM Package2VersionCreateRequest WHERE Id = '${pvcRequestId}'`;
const verifyResult = await devHubOrg
.getConnection()
.tooling.query<{ Id: string; IsDevUsePkgZipRequested: boolean }>(verifyQuery);
// eslint-disable-next-line no-console
console.log('IsDevUsePkgZipRequested:', verifyResult.records[0]?.IsDevUsePkgZipRequested);

expect(createResult?.Status).to.equal('Success');
const subscriberPkgVersionId = createResult?.SubscriberPackageVersionId;
expect(subscriberPkgVersionId).to.match(/04t.{15}/);

const retrieveOutputDir = 'pkg-zip-test-output';
const retrieveResult = execCmd<FileDownloadEntry[]>(
`package:version:retrieve --package ${subscriberPkgVersionId} --output-dir ${retrieveOutputDir} --json`,
{ ensureExitCode: 0 }
).jsonOutput?.result;

expect(retrieveResult).to.be.an('array');
expect(retrieveResult?.length).to.be.greaterThan(0);
});
});
37 changes: 17 additions & 20 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -879,15 +879,7 @@
"@smithy/types" "^4.12.0"
tslib "^2.6.2"

"@aws-sdk/types@^3.222.0":
version "3.957.0"
resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.957.0.tgz#06e899503028bdb8c655aa11a9a01f562882f361"
integrity sha512-wzWC2Nrt859ABk6UCAVY/WYEbAd7FjkdrQL6m24+tfmWYDNRByTJ9uOgU/kw9zqLCAwb//CPvrJdhqjTznWXAg==
dependencies:
"@smithy/types" "^4.11.0"
tslib "^2.6.2"

"@aws-sdk/types@^3.973.0":
"@aws-sdk/types@^3.222.0", "@aws-sdk/types@^3.973.0":
version "3.973.0"
resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.973.0.tgz#4e7428dbaac37797a81339f646f40f41cc22a1fe"
integrity sha512-jYIdB7a7jhRTvyb378nsjyvJh1Si+zVduJ6urMNGpz8RjkmHZ+9vM2H07XaIB2Cfq0GhJRZYOfUCH8uqQhqBkQ==
Expand Down Expand Up @@ -2031,16 +2023,16 @@
terminal-link "^3.0.0"

"@salesforce/source-deploy-retrieve@^12.31.9":
version "12.31.10"
resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.31.10.tgz#612886356d81c87eb9053bbc9173546556fd5f36"
integrity sha512-kUdJicJUd3/lzNQOvDW1Sc5iBl8PVv2Tz7L59YA/Le0fzZCYM72oyKwdbl/f6kc+MzJpMVia2+AxrvVZir8oJw==
version "12.31.9"
resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.31.9.tgz#69592e0b1564157fce8b7c66b33412460fa62b6e"
integrity sha512-UVRmLVl+Es1jLGnSx4G2xxTNHR7L6v5uzOpBFbg1ADMOQ4b1v8cDwZO9noJa9xAG+MLJJ7zDkcqywgFxU/3mmQ==
dependencies:
"@salesforce/core" "^8.24.0"
"@salesforce/kit" "^3.2.4"
"@salesforce/ts-types" "^2.0.12"
"@salesforce/types" "^1.6.0"
fast-levenshtein "^3.0.0"
fast-xml-parser "^5.3.4"
fast-xml-parser "^4.5.3"
got "^11.8.6"
graceful-fs "^4.2.11"
ignore "^5.3.2"
Expand Down Expand Up @@ -2568,13 +2560,6 @@
"@smithy/util-stream" "^4.5.10"
tslib "^2.6.2"

"@smithy/types@^4.11.0":
version "4.11.0"
resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.11.0.tgz#c02f6184dcb47c4f0b387a32a7eca47956cc09f1"
integrity sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA==
dependencies:
tslib "^2.6.2"

"@smithy/types@^4.12.0":
version "4.12.0"
resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.12.0.tgz#55d2479080922bda516092dbf31916991d9c6fee"
Expand Down Expand Up @@ -4782,6 +4767,13 @@ fast-xml-parser@5.2.5:
dependencies:
strnum "^2.1.0"

fast-xml-parser@^4.5.3:
version "4.5.3"
resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz#c54d6b35aa0f23dc1ea60b6c884340c006dc6efb"
integrity sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==
dependencies:
strnum "^1.1.1"

fast-xml-parser@^5.3.4:
version "5.3.4"
resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-5.3.4.tgz#06f39aafffdbc97bef0321e626c7ddd06a043ecf"
Expand Down Expand Up @@ -8376,6 +8368,11 @@ strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==

strnum@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.1.2.tgz#57bca4fbaa6f271081715dbc9ed7cee5493e28e4"
integrity sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==

strnum@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/strnum/-/strnum-2.1.1.tgz#cf2a6e0cf903728b8b2c4b971b7e36b4e82d46ab"
Expand Down