diff --git a/command-snapshot.json b/command-snapshot.json index 6d2ba735..d5918a66 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -64,11 +64,11 @@ "definitionfile", "installationkey", "installationkeybypass", + "patchversion", "target-hub-org", - "targetdevhubusername", - "patchversion" + "targetdevhubusername" ], - "flagChars": ["f", "k", "m", "p", "s", "v", "w", "x", "a"], + "flagChars": ["a", "f", "k", "m", "p", "s", "v", "w", "x"], "flags": [ "api-version", "build-instance", @@ -79,11 +79,11 @@ "json", "loglevel", "package", + "patch-version", "seed-metadata", "target-dev-hub", "verbose", - "wait", - "patch-version" + "wait" ], "plugin": "@salesforce/plugin-packaging" }, @@ -181,6 +181,57 @@ "flags": ["api-version", "flags-dir", "json", "loglevel", "target-dev-hub", "verbose"], "plugin": "@salesforce/plugin-packaging" }, + { + "alias": [], + "command": "package:push-upgrade:abort", + "flagAliases": [], + "flagChars": ["i", "v"], + "flags": ["api-version", "flags-dir", "json", "push-request-id", "target-dev-hub"], + "plugin": "@salesforce/plugin-packaging" + }, + { + "alias": ["force:package:push-upgrade:list"], + "command": "package:push-upgrade:list", + "flagAliases": ["apiversion", "scheduledlastdays", "target-hub-org", "targetdevhubusername"], + "flagChars": ["l", "p", "s", "v"], + "flags": [ + "api-version", + "flags-dir", + "json", + "package", + "scheduled-last-days", + "show-push-migrations-only", + "status", + "target-dev-hub" + ], + "plugin": "@salesforce/plugin-packaging" + }, + { + "alias": ["force:package:push-upgrade:report"], + "command": "package:push-upgrade:report", + "flagAliases": ["apiversion", "pushrequestid", "target-hub-org", "targetdevhubusername"], + "flagChars": ["i", "v"], + "flags": ["api-version", "flags-dir", "json", "loglevel", "push-request-id", "target-dev-hub"], + "plugin": "@salesforce/plugin-packaging" + }, + { + "alias": [], + "command": "package:push-upgrade:schedule", + "flagAliases": ["apiversion"], + "flagChars": ["f", "l", "p", "t", "v"], + "flags": [ + "api-version", + "flags-dir", + "json", + "migrate-to-2gp", + "org-file", + "org-list", + "package", + "start-time", + "target-dev-hub" + ], + "plugin": "@salesforce/plugin-packaging" + }, { "alias": ["force:package:uninstall"], "command": "package:uninstall", @@ -231,7 +282,6 @@ "releasenotesurl", "skipancestorcheck", "skipvalidation", - "asyncvalidation", "target-hub-org", "targetdevhubusername", "uninstallscript", @@ -243,6 +293,7 @@ "flagChars": ["a", "b", "c", "d", "e", "f", "j", "k", "n", "p", "r", "s", "t", "v", "w", "x"], "flags": [ "api-version", + "async-validation", "branch", "build-instance", "code-coverage", @@ -261,7 +312,6 @@ "releasenotes-url", "skip-ancestor-check", "skip-validation", - "async-validation", "tag", "target-dev-hub", "uninstall-script", diff --git a/messages/package_pushupgrade_abort.md b/messages/package_pushupgrade_abort.md new file mode 100644 index 00000000..e02a3043 --- /dev/null +++ b/messages/package_pushupgrade_abort.md @@ -0,0 +1,51 @@ +# summary + +Abort a package push upgrade that has been scheduled. Only push upgrade requests with a status of Created or Pending can be aborted. + +# description + +Specify the request ID for which you want abort the request. If applicable, the command displays errors related to the request. + +To show all requests in the org, run "<%= config.bin %> package pushupgrade list --package 033...". + +# examples + +- Cancel the specified package push upgrade request with the specified ID; uses your default Dev Hub org: + + <%= config.bin %> <%= command.id %> --push-request-id 0DV... + +- Cancel the specified package push upgrade request in the Dev Hub org with username devhub@example.com: + + <%= config.bin %> <%= command.id %> --push-request-id 0DV... --target-dev-hub devhub@example.com + +# flags.push-request-id.summary + +ID of the package push request (starts with 0DV). This ID is returned after the package push-upgrade schedule command completes successfully. + +# flags.target-dev-hub.summary + +Username or alias of the Dev Hub org. + +# flags.target-dev-hub.description + +Overrides the value of the target-dev-hub configuration variable, if set. + +# error.invalid-push-request-id-owner + +Can’t abort package push upgrade request. The specified push upgrade ID is associated with a package in a different Dev Hub org. Retry this command in the context of the Dev Hub org that owns the package. + +# error.invalid-push-request-id + +Can’t abort package push upgrade request. The specified push upgrade ID isn’t valid. Check the ID (starts with 0DV) and retry the command. + +# error.invalid-push-request-status + +Can’t abort package push upgrade request with status '${pushRequest.Status}'. Only push upgrade requests with a status of 'Created' or 'Pending' can be cancelled. + +# status + +Status + +# output + +Scheduled push upgrade ID [%s] was cancelled. diff --git a/messages/package_pushupgrade_list.md b/messages/package_pushupgrade_list.md new file mode 100644 index 00000000..c710cf36 --- /dev/null +++ b/messages/package_pushupgrade_list.md @@ -0,0 +1,61 @@ +# summary + +Lists the status of push upgrade requests for a given package. + +# description + +Shows the details of each request to create a push upgrade in the Dev Hub org. + +All filter parameters are applied using the AND logical operator (not OR). + +To get information about a specific request, run "sf package pushupgrade report" and supply the request ID. + +# flags.package.summary + +Package ID (starts with 033) of the package that you want push upgrade information for. + +# flags.scheduled-last-days.summary + +Number of days in the past for which to display the list of push upgrade requests that were scheduled. Used to filter the list output to only recently scheduled push upgrades. + +# flags.status.summary + +Status used to filter the list output Valid values are: Created, Canceled, Pending, In Progress, Failed, or Succeeded + +# flags.show-push-migrations-only.summary + +Display only push upgrade requests for package migrations. + +# examples + +- List all package push upgrade requests in the specified Dev Hub org: + + <%= config.bin %> <%= command.id %> --package 033xyz --target-dev-hub myHub + +- List all package push upgrade requests in the specified Dev Hub org scheduled in the last 30 days: + + <%= config.bin %> <%= command.id %> --package 033xyz --scheduled-last-days 30 --target-dev-hub myHub + +- List all package push upgrade with a status Succeeded: + + <%= config.bin %> <%= command.id %> --package 033xyz –-status Succeeded + +- List all package push upgrade with a status Failed: + + <%= config.bin %> <%= command.id %> --package 033xyz –-status Failed + +# id + +ID + +# status + +Status + +# package-id + +Package Id + +# packageVersionId + +Package Version Id diff --git a/messages/package_pushupgrade_report.md b/messages/package_pushupgrade_report.md new file mode 100644 index 00000000..64eba686 --- /dev/null +++ b/messages/package_pushupgrade_report.md @@ -0,0 +1,27 @@ +# summary + +Retrieve the status of a package push upgrade. + +# description + +Specify the request ID for which you want to view details. If applicable, the command displays errors related to the request. + +To show all requests in the org, run "<%= config.bin %> package pushupgrade list". + +# examples + +- Retrieve details about the package push upgrade with the specified ID; uses your default Dev Hub org: + + <%= config.bin %> <%= command.id %> --push-request-id 0DV... + +- Retrieve details about the specified package push request in the Dev Hub org with username devhub@example.com: + + <%= config.bin %> <%= command.id %> --push-request-id 0DV... --target-dev-hub devhub@example.com + +# flags.push-request-id.summary + +ID of the package push request (starts with 0DV). This ID is returned after the package push-upgrade schedule command completes successfully. + +# truncatedErrors + +To see all errors, run: %s data query -q "SELECT ErrorMessage FROM PackagePushError WHERE PackagePushJob.PackagePushRequestId='%s'" diff --git a/messages/package_pushupgrade_schedule.md b/messages/package_pushupgrade_schedule.md new file mode 100644 index 00000000..cfef625d --- /dev/null +++ b/messages/package_pushupgrade_schedule.md @@ -0,0 +1,109 @@ +# summary + +Schedule a package push upgrade. + +# description + +Represents a push upgrade request for upgrading a package in one or many orgs from one version to another version. +To initiate a push upgrade for an unlocked or second-generation managed package, the Create and Update Second-Generation Packages user permission is required. +For second-generation managed packages, the push upgrade feature is available only for packages that have passed AppExchange security review. To enable push upgrades for your managed package, log a support case in the Salesforce Partner Community. +For unlocked packages, push upgrades are enabled by default. + +Use the -–migrate-to-2GP flag to indicate you’re installing a converted second-generation managed package into an org that has the first-generation managed package version of that package installed. + +# flags.target-dev-hub.summary + +Username or alias of the Dev Hub org. + +# flags.target-dev-hub.description + +Overrides the value of the target-dev-hub configuration variable, if set. + +# flags.package.summary + +ID (starts with 04t) of the package version that the package is being upgraded to. The package version must be an active, non-beta package version. + +# flags.start-time.summary + +Date and time (UTC) when the push upgrade is processed. Set to the earliest time that you want Salesforce to attempt to start the upgrade. + +# flags.start-time.description + +Scheduled push upgrades begin as soon as resources are available on the Salesforce instance, which is either at or after the start time you specify. In certain scenarios, the push upgrade starts a few hours after the scheduled start time. + +As a best practice, schedule push upgrades at off-peak hours like 1:00 AM Saturday. +If you don't specify this flag, the push upgrade is scheduled to run as soon as resources are available on the Salesforce instance. + +# flags.org-file.summary + +Filename of the CSV file that contains the list of orgs that need the package upgrade. + +# flags.org-file.description + +The file must contain one org per line. The org ID must be the only value in each row. +All listed orgs must have a package version installed in their org that is lower than the package version you specified for the --package-version flag. + +# flags.org-list.summary + +Comma-separated list of subscriber org IDs that need the package upgrade. + +# flags.migrate-to-2gp.summary + +Upgrade from a first-generation managed package (1GP) to a second-generation managed package (2GP). Required when you’re pushing a 2GP package to orgs with the 1GP version installed. + +# error.invalid-package-version + +Invalid package version. + +# error.empty-org-list + +Can’t schedule the package push upgrade. The +org file you specified is empty. Review the file you specified, and retry this command. + +# error.empty-org-input + +There are no org Ids. + +# error.invalid-org-file + +Can’t schedule the package push upgrade. The org file you specified is invalid. The org file must be a CSV file, and each row can contain only one org ID. Review and update your org file and retry this command. + +# error.invalid-org-input + +Can’t schedule the package push upgrade. One or more of the orgs IDs you specified in the org list is an invalid org ID. Review the list of orgs you specified, and retry this command + +# error.no-org-file-or-org-list-input + +Can’t schedule the package push upgrade. You must specify either a list of orgs, or a file containing the list of orgs to be upgraded. Retry this command using either --org-list or --org-file flag and include the required details. + +# examples + +- Schedule a push upgrade that initiates at a specified time: + <%= config.bin %> <%= command.id %> --package 04txyz --start-time "2024-12-06T21:00:00" --org-file upgrade-orgs.csv + +- Schedule a push upgrade that initiates as soon as possible: + <%= config.bin %> <%= command.id %> --package 04txyz --org-file upgrade-orgs.csv + +- Schedule a push migration from a 1GP package to a 2GP package: + <%= config.bin %> <%= command.id %> --migrate-to-2gp --package 04txyz --start-time "2024-12-06T21:00:00" --org-file upgrade-orgs.csv --target-dev-hub myHub + +# id + +ID + +# status + +Status + +# package-id + +Package Id + +# packageVersionId + +Package Version Id + +# output + +Push upgrade has been scheduled. To check the status of this push upgrade, use push upgrade request ID [%s] with either "package push-upgrade list" or "package push-upgrade report". +Orgs scheduled for push upgrade: {%s} diff --git a/package.json b/package.json index 2ed40daf..12bfad65 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "@oclif/core": "^4", "@salesforce/core": "^8.11.1", "@salesforce/kit": "^3.2.3", - "@salesforce/packaging": "^4.5.0", + "@salesforce/packaging": "^4.6.0", "@salesforce/sf-plugins-core": "^12.2.2", "chalk": "^5.4.1" }, diff --git a/schemas/package-push__upgrade-abort.json b/schemas/package-push__upgrade-abort.json new file mode 100644 index 00000000..6dbe8714 --- /dev/null +++ b/schemas/package-push__upgrade-abort.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/PackagePushUpgradeAbortResult", + "definitions": { + "PackagePushUpgradeAbortResult": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/schemas/package-push__upgrade-list.json b/schemas/package-push__upgrade-list.json new file mode 100644 index 00000000..b262cba3 --- /dev/null +++ b/schemas/package-push__upgrade-list.json @@ -0,0 +1,77 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/PackagePushRequestListResultArr", + "definitions": { + "PackagePushRequestListResultArr": { + "type": "array", + "items": { + "$ref": "#/definitions/PackagePushRequestListResult" + } + }, + "PackagePushRequestListResult": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "PackageVersionId": { + "type": "string" + }, + "PackageVersion": { + "type": "object", + "properties": { + "Name": { + "type": "string" + }, + "MajorVersion": { + "type": "string" + }, + "MinorVersion": { + "type": "string" + } + }, + "required": [ + "Name", + "MajorVersion", + "MinorVersion" + ], + "additionalProperties": false + }, + "Status": { + "type": "string" + }, + "ScheduledStartTime": { + "type": "string" + }, + "StartTime": { + "type": "string" + }, + "EndTime": { + "type": "string" + }, + "OrgsScheduled": { + "type": "number" + }, + "OrgsUpgradeSucceeded": { + "type": "number" + }, + "OrgsUpgradeFailed": { + "type": "number" + } + }, + "required": [ + "Id", + "PackageVersionId", + "PackageVersion", + "Status", + "ScheduledStartTime", + "StartTime", + "EndTime", + "OrgsScheduled", + "OrgsUpgradeSucceeded", + "OrgsUpgradeFailed" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/schemas/package-push__upgrade-report.json b/schemas/package-push__upgrade-report.json new file mode 100644 index 00000000..a096eaf0 --- /dev/null +++ b/schemas/package-push__upgrade-report.json @@ -0,0 +1,106 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/ReportCommandResult", + "definitions": { + "ReportCommandResult": { + "anyOf": [ + { + "$ref": "#/definitions/PackagePushRequestReportResult" + }, + { + "type": "null" + } + ] + }, + "PackagePushRequestReportResult": { + "type": "object", + "properties": { + "PackageVersion": { + "type": "object", + "properties": { + "MetadataPackage": { + "type": "object", + "properties": { + "Name": { + "type": "string" + }, + "NamespacePrefix": { + "type": "string" + } + }, + "required": [ + "Name", + "NamespacePrefix" + ], + "additionalProperties": false + }, + "MetadataPackageId": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "MajorVersion": { + "type": "string" + }, + "MinorVersion": { + "type": "string" + } + }, + "required": [ + "MetadataPackage", + "MetadataPackageId", + "Name", + "MajorVersion", + "MinorVersion" + ], + "additionalProperties": false + }, + "Id": { + "type": "string" + }, + "PackageVersionId": { + "type": "string" + }, + "Status": { + "type": "string" + }, + "ScheduledStartTime": { + "type": [ + "string", + "null" + ] + }, + "StartTime": { + "type": [ + "string", + "null" + ] + }, + "EndTime": { + "type": [ + "string", + "null" + ] + }, + "DurationSeconds": { + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "PackageVersion", + "Id", + "PackageVersionId", + "Status", + "ScheduledStartTime", + "StartTime", + "EndTime", + "DurationSeconds" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/schemas/package-push__upgrade-schedule.json b/schemas/package-push__upgrade-schedule.json new file mode 100644 index 00000000..b3dbd4fd --- /dev/null +++ b/schemas/package-push__upgrade-schedule.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/PackagePushScheduleResult", + "definitions": { + "PackagePushScheduleResult": { + "type": "object", + "properties": { + "PushRequestId": { + "type": "string" + }, + "ScheduledStartTime": { + "type": "string" + }, + "Status": { + "type": "string" + } + }, + "required": [ + "PushRequestId", + "Status" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/src/commands/package/push-upgrade/abort.ts b/src/commands/package/push-upgrade/abort.ts new file mode 100644 index 00000000..3a00823b --- /dev/null +++ b/src/commands/package/push-upgrade/abort.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import { Flags, SfCommand } from '@salesforce/sf-plugins-core'; +import { Messages } from '@salesforce/core'; +import { PackagePushUpgrade } from '@salesforce/packaging'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_pushupgrade_abort'); + +export type PackagePushUpgradeAbortResult = { + success: boolean; +}; + +export class PackagePushUpgradeAbortCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly flags = { + 'target-dev-hub': Flags.requiredHub(), + 'api-version': Flags.orgApiVersion(), + 'push-request-id': Flags.salesforceId({ + length: 'both', + char: 'i', + summary: messages.getMessage('flags.push-request-id.summary'), + required: true, + startsWith: '0DV', + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackagePushUpgradeAbortCommand); + const connection = flags['target-dev-hub'].getConnection(flags['api-version']); + + const packagePushRequestOptions = { packagePushRequestId: flags['push-request-id'] }; + + const result: boolean = await PackagePushUpgrade.abort(connection, packagePushRequestOptions); + + if (result) { + this.log(messages.getMessage('output', [flags['push-request-id']])); + } + + return { success: result }; + } +} diff --git a/src/commands/package/push-upgrade/list.ts b/src/commands/package/push-upgrade/list.ts new file mode 100644 index 00000000..4f1f65ca --- /dev/null +++ b/src/commands/package/push-upgrade/list.ts @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +import { Flags, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { Messages, Logger } from '@salesforce/core'; +import { PackagePushRequestListResult, PackagePushUpgrade } from '@salesforce/packaging'; +import { requiredHubFlag } from '../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_pushupgrade_list'); + +type PackagePushStatus = 'Created' | 'Cancelled' | 'Pending' | 'In Progress' | 'Failed' | 'Succeeded'; +export type PackagePushRequestListResultArr = PackagePushRequestListResult[]; + +export class PackagePushRequestListCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly aliases = ['force:package:push-upgrade:list']; + public static readonly flags = { + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + package: Flags.string({ + char: 'p', + summary: messages.getMessage('flags.package.summary'), + required: true, + }), + 'scheduled-last-days': Flags.integer({ + char: 'l', + deprecateAliases: true, + aliases: ['scheduledlastdays'], + summary: messages.getMessage('flags.scheduled-last-days.summary'), + }), + status: Flags.custom({ + options: ['Created', 'Cancelled', 'Pending', 'In Progress', 'Failed', 'Succeeded'], + })({ + char: 's', + summary: messages.getMessage('flags.status.summary'), + }), + 'show-push-migrations-only': Flags.boolean({ + summary: messages.getMessage('flags.show-push-migrations-only.summary'), + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackagePushRequestListCommand); + const logger = await Logger.child(this.constructor.name); + const hubOrg = flags['target-dev-hub']; + const connection = hubOrg.getConnection(flags['api-version']); + const scheduledLastDays = flags['scheduled-last-days']; + + if (scheduledLastDays !== undefined) { + if (isNaN(scheduledLastDays) || scheduledLastDays <= 0) { + throw new Error('Invalid value for --scheduled-last-days. It must be a positive integer.'); + } + } + + logger.debug(`Querying PackagePushRequest records from org ${hubOrg.getOrgId()}`); + + const results: PackagePushRequestListResultArr = await PackagePushUpgrade.list(connection, { + packageId: flags.package, + status: flags.status as PackagePushStatus | undefined, + scheduledLastDays, + isMigration: flags['show-push-migrations-only'], + }); + + if (results.length === 0) { + this.warn('No results found'); + } else { + const data = await Promise.all( + results.map(async (record: PackagePushRequestListResult) => { + const packagePushRequestId = record?.Id; + + const packagePushRequestOptions = { packagePushRequestId }; + + const totalNumOrgs = await PackagePushUpgrade.getTotalJobs(connection, packagePushRequestOptions); + + const numOrgsUpgradedFail = await PackagePushUpgrade.getFailedJobs(connection, packagePushRequestOptions); + + const numOrgsUpgradedSuccess = await PackagePushUpgrade.getSucceededJobs( + connection, + packagePushRequestOptions + ); + + const pv = record?.PackageVersion; + const packageVersionNumber = + pv?.MajorVersion != null && pv?.MinorVersion != null ? `${pv.MajorVersion}.${pv.MinorVersion}` : undefined; + + return { + Id: record?.Id, + PackageVersionId: record?.PackageVersionId, + PackageVersionName: pv?.Name, + PackageVersionNumber: packageVersionNumber, + + Status: record?.Status, + + ScheduledStartTime: record?.ScheduledStartTime, + + StartTime: record?.StartTime, + + EndTime: record?.EndTime, + + NumOrgsScheduled: totalNumOrgs, + + NumOrgsUpgradedFail: numOrgsUpgradedFail, + + NumOrgsUpgradedSuccess: numOrgsUpgradedSuccess, + }; + }) + ); + + this.table({ data }); + } + return results; + } +} diff --git a/src/commands/package/push-upgrade/report.ts b/src/commands/package/push-upgrade/report.ts new file mode 100644 index 00000000..caecd67d --- /dev/null +++ b/src/commands/package/push-upgrade/report.ts @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2025, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +import { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { Messages, Logger } from '@salesforce/core'; +import chalk from 'chalk'; + +import { + PackagePushUpgrade, + PackagePushRequestReportResult, + PackagePushRequestReportJobFailuresResult, +} from '@salesforce/packaging'; +import { requiredHubFlag } from '../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_pushupgrade_report'); +const ERROR_LIMIT = 12; + +export type ReportCommandResult = PackagePushRequestReportResult | null; + +export class PackagePushUpgradeReportCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly deprecateAliases = true; + public static readonly aliases = ['force:package:push-upgrade:report']; + public static readonly flags = { + loglevel, + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + 'push-request-id': Flags.salesforceId({ + length: 'both', + deprecateAliases: true, + aliases: ['pushrequestid'], + char: 'i', + summary: messages.getMessage('flags.push-request-id.summary'), + required: true, + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackagePushUpgradeReportCommand); + const logger = await Logger.child(this.constructor.name); + const hubOrg = flags['target-dev-hub']; + const connection = hubOrg.getConnection(flags['api-version']); + + const packagePushRequestOptions = { packagePushRequestId: flags['push-request-id'] }; + + logger.debug( + `Querying PackagePushRequestReport records from org ${hubOrg?.getOrgId()} using PackagePushRequest ID: ${ + packagePushRequestOptions.packagePushRequestId + }` + ); + + const records: PackagePushRequestReportResult[] = await PackagePushUpgrade.report( + connection, + packagePushRequestOptions + ); + + if (records?.length === 1) { + const record: PackagePushRequestReportResult = records[0]; + + logger.debug(`Found PackagePushRequestReport record: ${record?.Id}`); + + const totalJobs: number = await PackagePushUpgrade.getTotalJobs(connection, packagePushRequestOptions); + + let failedJobs = 0; + let succeededJobs = 0; + let jobFailureReasons: PackagePushRequestReportJobFailuresResult[] | undefined; + + if (record?.Status === 'Succeeded' || record?.Status === 'Failed' || record?.Status === 'In Progress') { + logger.debug(`PushRequest Status is ${record.Status}, getting job details.`); + + failedJobs = await PackagePushUpgrade.getFailedJobs(connection, packagePushRequestOptions); + + succeededJobs = await PackagePushUpgrade.getSucceededJobs(connection, packagePushRequestOptions); + + jobFailureReasons = await PackagePushUpgrade.getJobFailureReasons(connection, packagePushRequestOptions); + } + this.display(record, totalJobs, succeededJobs, failedJobs, jobFailureReasons); + return record; + } + this.warn('No results found'); + return null; + } + + private display( + record: PackagePushRequestReportResult, + totalJobs: number, + succeededJobs: number, + failedJobs: number, + jobFailureReasons?: PackagePushRequestReportJobFailuresResult[] + ): void { + const data = [ + { + name: 'Package Name', + + value: record.PackageVersion.MetadataPackage.Name, + }, + { + name: 'Package Version Name', + + value: record.PackageVersion.Name, + }, + { + name: 'Package Version', + + value: record.PackageVersion.MajorVersion + '.' + record.PackageVersion.MinorVersion, + }, + { + name: 'Namespace', + + value: record.PackageVersion.MetadataPackage.NamespacePrefix, + }, + { + name: 'Package Id', + + value: record.PackageVersion.MetadataPackageId, + }, + { + name: 'Package Version Id', + + value: record.PackageVersionId, + }, + { + name: 'Package Push Request Id', + + value: record.Id, + }, + { + name: 'Status', + + value: record.Status, + }, + { + name: 'Scheduled Start Time', + + value: record.ScheduledStartTime, + }, + { + name: 'Start Time', + + value: record.StartTime, + }, + { + name: 'End Time', + + value: record.EndTime, + }, + { + name: 'Duration Seconds', + + value: record.DurationSeconds, + }, + { + name: '# Orgs Scheduled', + value: totalJobs, + }, + { + name: '# Orgs Upgrade Succeeded', + value: succeededJobs, + }, + { + name: '# Orgs Upgrade Failed', + value: failedJobs, + }, + ]; + + this.table({ data }); + + if (jobFailureReasons?.length) { + this.log(''); + const errors: string[] = []; + jobFailureReasons.slice(0, ERROR_LIMIT).forEach((error: PackagePushRequestReportJobFailuresResult) => { + errors.push(`(${errors.length + 1}) ${error.ErrorMessage}`); + }); + this.styledHeader(chalk.red('Errors')); + this.warn(errors.join('\n')); + + if (jobFailureReasons?.length > ERROR_LIMIT) { + this.warn(messages.getMessage('truncatedErrors', [this.config.bin, record.Id])); + } + } + } +} diff --git a/src/commands/package/push-upgrade/schedule.ts b/src/commands/package/push-upgrade/schedule.ts new file mode 100644 index 00000000..560e091a --- /dev/null +++ b/src/commands/package/push-upgrade/schedule.ts @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import * as fs from 'node:fs/promises'; +import { Flags, SfCommand, orgApiVersionFlagWithDeprecations } from '@salesforce/sf-plugins-core'; +import { Messages, SfError, Logger } from '@salesforce/core'; +import { PackagePushScheduleResult, PackagePushUpgrade } from '@salesforce/packaging'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_pushupgrade_schedule'); + +export class PackagePushScheduleCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly flags = { + 'target-dev-hub': Flags.requiredHub({ + char: 'v', + summary: messages.getMessage('flags.target-dev-hub.summary'), + description: messages.getMessage('flags.target-dev-hub.description'), + required: true, + }), + 'api-version': orgApiVersionFlagWithDeprecations, + package: Flags.salesforceId({ + char: 'p', + length: 'both', + startsWith: '04t', + summary: messages.getMessage('flags.package.summary'), + required: true, + }), + 'start-time': Flags.string({ + char: 't', + summary: messages.getMessage('flags.start-time.summary'), + description: messages.getMessage('flags.start-time.description'), + }), + 'org-list': Flags.string({ + char: 'l', + summary: messages.getMessage('flags.org-list.summary'), + exclusive: ['org-file'], + }), + 'org-file': Flags.file({ + char: 'f', + summary: messages.getMessage('flags.org-file.summary'), + description: messages.getMessage('flags.org-file.description'), + exists: true, + exclusive: ['org-list'], + }), + 'migrate-to-2gp': Flags.boolean({ + summary: messages.getMessage('flags.migrate-to-2gp.summary'), + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackagePushScheduleCommand); + const logger = await Logger.child(this.constructor.name); + let orgList: string[] = []; + + if (flags['org-file']) { + logger.debug(`Reading org list from file: ${flags['org-file']}`); + orgList = await readOrgFile(flags['org-file']); + } else if (flags['org-list']) { + logger.debug('Using org list from input flag.'); + orgList = getOrgListFromInput(flags['org-list']); + } else { + throw new SfError(messages.getMessage('error.no-org-file-or-org-list-input')); + } + + const conn = flags['target-dev-hub'].getConnection(flags['api-version']); + + const startTime = flags['start-time']; + const isMigration = flags['migrate-to-2gp']; + + const result: PackagePushScheduleResult = await PackagePushUpgrade.schedule( + conn, + flags.package, + startTime, + orgList, + isMigration + ); + + this.log(messages.getMessage('output', [result?.PushRequestId, orgList.join(', ')])); + + return result; + } +} + +async function readOrgFile(filePath: string): Promise { + try { + const fileContent = await fs.readFile(filePath, 'utf-8'); + const orgIds = fileContent.split(/\r?\n/).filter((id) => id.trim().length > 0); + + return orgIds.filter((id: string) => /^00D[a-zA-Z0-9]{12}$/.test(id)); + } catch (error) { + throw new SfError(messages.getMessage('error.invalid-org-file')); + } +} + +function getOrgListFromInput(orgInput: string): string[] { + try { + if (orgInput.length === 0) { + throw new SfError(messages.getMessage('error.empty-org-input')); + } + + const orgList = orgInput.split(',').map((org) => org.trim()); + + return orgList.filter((org) => org.length > 0); + } catch (error) { + throw new SfError(messages.getMessage('error.invalid-org-input')); + } +} diff --git a/src/commands/package/version/list.ts b/src/commands/package/version/list.ts index cca99d3d..32d24ac7 100644 --- a/src/commands/package/version/list.ts +++ b/src/commands/package/version/list.ts @@ -140,14 +140,15 @@ export class PackageVersionListCommand extends SfCommand (project ? project.getAliasesFromPackageId(id) : id)).flat(); const AliasStr = project ? (aliases.length > 0 ? aliases.join() : '') : ''; - // set Ancestor display values - let ancestorVersion: string | undefined; + // Calculate AncestorId value without modifying record + let computedAncestorId = record.AncestorId; + let computedAncestorVersion: string | undefined; if (record.AncestorId) { - ancestorVersion = ancestorVersionsMap?.get(record.AncestorId); + computedAncestorVersion = ancestorVersionsMap?.get(record.AncestorId); } else if (containerOptionsMap.get(record.Package2Id) !== 'Managed') { // display N/A if package is unlocked - ancestorVersion = 'N/A'; - record.AncestorId = 'N/A'; + computedAncestorVersion = 'N/A'; + computedAncestorId = 'N/A'; // Use computed variable } function getCodeCoverage(): string { @@ -203,8 +204,8 @@ export class PackageVersionListCommand extends SfCommand { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let logStub: sinon.SinonStub; + let abortStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + + logStub = $$.SANDBOX.stub(SfCommand.prototype, 'log'); + + abortStub = $$.SANDBOX.stub(PackagePushUpgrade, 'abort'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should pass the right parameters to the library', async () => { + const pushRequestId = '0DVxx0000004CCG'; + const cmd = new PackagePushUpgradeAbortCommand(['-i', pushRequestId, '-v', testOrg.username], config); + + abortStub.resolves(true); + const res = await cmd.run(); + + expect(res.success).to.be.true; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(abortStub.calledOnce).to.be.true; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(logStub.callCount).to.equal(1); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(logStub.args[0]).to.deep.equal([`Scheduled push upgrade ID [${pushRequestId}] was cancelled.`]); + }); + + it('should throw an error if push-request-id is missing', async () => { + const cmd = new PackagePushUpgradeAbortCommand(['-v', 'test@hub.org'], config); + try { + await cmd.run(); + } catch (err) { + const error = err as Error; + expect(error.name).to.equal('Error'); + expect(error.message).to.include('Missing required flag push-request-id'); + } + }); + + it('should throw an error if push-request status is not "Created" or "Pending" or is missing', async () => { + abortStub.rejects(new Error('Abortion is only allowed for "Created" or "Pending" statuses.')); + const cmd = new PackagePushUpgradeAbortCommand(['-i', '0DVxx0000004CCG', '-v', 'test@hub.org'], config); + + try { + await cmd.run(); + } catch (err) { + const error = err as Error; + const msg = 'Abortion is only allowed for "Created" or "Pending" statuses.'; + expect(error.name).to.equal('Error'); + expect(error.message).to.include(msg); + } + }); +}); diff --git a/test/commands/package/packagePushUpgradeList.test.ts b/test/commands/package/packagePushUpgradeList.test.ts new file mode 100644 index 00000000..6cca244a --- /dev/null +++ b/test/commands/package/packagePushUpgradeList.test.ts @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import * as sinon from 'sinon'; +import { expect } from 'chai'; +import { env } from '@salesforce/kit'; +import { PackagePushUpgrade, PackagePushRequestListResult } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import { PackagePushRequestListCommand } from '../../../src/commands/package/push-upgrade/list.js'; + +const pushUpgradeListSuccess: PackagePushRequestListResult[] = [ + { + Id: '0Af0M000000AxuqSAC', + PackageVersionId: '04t0M000000AxuqSAC', + PackageVersion: { + Name: 'VersionName', + MajorVersion: '1', + MinorVersion: '1', + }, + Status: 'Success', + ScheduledStartTime: '2024-01-02T00:00:00.000Z', + StartTime: '2024-01-02T00:01:00.000Z', + EndTime: '2024-01-02T00:10:00.000Z', + OrgsScheduled: 2, + OrgsUpgradeFailed: 0, + OrgsUpgradeSucceeded: 2, + }, +]; + +describe('package:pushupgrade:list - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let listStub: sinon.SinonStub; + let getTotalJobsStub: sinon.SinonStub; + let getFailedJobsStub: sinon.SinonStub; + let getSucceededJobsStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + listStub = $$.SANDBOX.stub(PackagePushUpgrade, 'list'); + + getTotalJobsStub = $$.SANDBOX.stub(PackagePushUpgrade, 'getTotalJobs'); + + getFailedJobsStub = $$.SANDBOX.stub(PackagePushUpgrade, 'getFailedJobs'); + + getSucceededJobsStub = $$.SANDBOX.stub(PackagePushUpgrade, 'getSucceededJobs'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should list the push upgrade requests', async () => { + const packageId = 'dummyPackageId'; + const cmd = new PackagePushRequestListCommand(['-v', testOrg.username, '--package', packageId], config); + + listStub.resolves(pushUpgradeListSuccess); + + getTotalJobsStub.resolves(3); + + getFailedJobsStub.resolves(1); + + getSucceededJobsStub.resolves(2); + + const envSpy = $$.SANDBOX.spy(env, 'setBoolean').withArgs('SF_APPLY_REPLACEMENTS_ON_CONVERT', true); + + await cmd.run(); + + expect(envSpy.calledOnce).to.equal(false); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.warn.calledOnce).to.be.false; + }); + + it('should handle no results found', async () => { + const packageId = 'dummyPackageId'; + const cmd = new PackagePushRequestListCommand(['-v', testOrg.username, '--package', packageId], config); + + listStub.resolves([]); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.warn.calledOnce).to.be.true; + }); + + it('should filter by is-migration flag', async () => { + const packageId = '033XXXXXXXXXXXXXXX'; + const cmdArgs = ['--target-dev-hub', testOrg.username, '--package', packageId, '--show-push-migrations-only']; + const cmd = new PackagePushRequestListCommand(cmdArgs, config); + + listStub.resolves(pushUpgradeListSuccess); + getTotalJobsStub.resolves(2); + getFailedJobsStub.resolves(0); + getSucceededJobsStub.resolves(2); + + await cmd.run(); + + expect(listStub.calledOnce).to.be.true; + + const listArgs = listStub.firstCall.args; + expect(listArgs[1]).to.deep.include({ + packageId, + isMigration: true, + status: undefined, + scheduledLastDays: undefined, + }); + + expect(sfCommandStubs.table.calledOnce).to.be.true; + expect(sfCommandStubs.warn.calledOnce).to.be.false; + }); +}); diff --git a/test/commands/package/packagePushUpgradeReport.test.ts b/test/commands/package/packagePushUpgradeReport.test.ts new file mode 100644 index 00000000..9354d96f --- /dev/null +++ b/test/commands/package/packagePushUpgradeReport.test.ts @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import { Config } from '@oclif/core'; +import { TestContext } from '@salesforce/core/testSetup'; +import { expect } from 'chai'; +import { PackagePushUpgrade, PackagePushRequestReportResult } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import { PackagePushUpgradeReportCommand } from '../../../src/commands/package/push-upgrade/report.js'; + +const pushUpgradeReportSuccess: PackagePushRequestReportResult[] = [ + { + PackageVersion: { + MetadataPackage: { + Name: 'PackageName', + NamespacePrefix: 'Namespace', + }, + MetadataPackageId: '0330M000000Axuq', + Name: 'VersionName', + MajorVersion: '1', + MinorVersion: '1', + }, + PackageVersionId: '04t0M000000AxuqSAC', + Id: '0DVxx0000004CCG', + Status: 'Created', + DurationSeconds: 60, + ScheduledStartTime: '2024-01-02T00:00:00.000Z', + StartTime: '2024-01-02T00:01:00.000Z', + EndTime: '2024-01-02T00:10:00.000Z', + }, +]; + +describe('package:pushupgrade:report - tests', () => { + const $$ = new TestContext(); + let sfCommandStubs: ReturnType; + let reportStub: sinon.SinonStub; + let getTotalJobsStub: sinon.SinonStub; + let getFailedJobsStub: sinon.SinonStub; + let getSucceededJobsStub: sinon.SinonStub; + let getJobFailureReasonsStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + reportStub = $$.SANDBOX.stub(PackagePushUpgrade, 'report'); + + getTotalJobsStub = $$.SANDBOX.stub(PackagePushUpgrade, 'getTotalJobs'); + + getFailedJobsStub = $$.SANDBOX.stub(PackagePushUpgrade, 'getFailedJobs'); + + getSucceededJobsStub = $$.SANDBOX.stub(PackagePushUpgrade, 'getSucceededJobs'); + + getJobFailureReasonsStub = $$.SANDBOX.stub(PackagePushUpgrade, 'getJobFailureReasons'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should report the push upgrade request', async () => { + const cmd = new PackagePushUpgradeReportCommand(['-i', '0DVxx0000004EXTGA2', '-v', 'test@hub.org'], config); + + reportStub.resolves(pushUpgradeReportSuccess); + + getTotalJobsStub.resolves(3); + + getFailedJobsStub.resolves(1); + + getSucceededJobsStub.resolves(2); + + getJobFailureReasonsStub.resolves([]); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.warn.calledOnce).to.be.false; + }); + + it('should handle no results found', async () => { + const cmd = new PackagePushUpgradeReportCommand(['-i', '0DVxx0000004EXTGA2', '-v', 'test@hub.org'], config); + + reportStub.resolves([]); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.warn.calledOnce).to.be.true; + }); + + it('should handle errors during report', async () => { + const cmd = new PackagePushUpgradeReportCommand(['-i', '0DVxx0000004EXTGA2', '-v', 'test@hub.org'], config); + + reportStub.rejects(new Error('Report error')); + try { + await cmd.run(); + // If cmd.run() resolves, this line will be reached, and the test should fail. + expect.fail('Expected cmd.run() to reject, but it resolved.'); + } catch (err) { + // Assert that an error was indeed thrown + expect(err).to.be.an.instanceof(Error); + // Assert the error message matches + expect((err as Error).message).to.equal('Report error'); + } + }); +}); diff --git a/test/commands/package/packagePushUpgradeSchedule.test.ts b/test/commands/package/packagePushUpgradeSchedule.test.ts new file mode 100644 index 00000000..08773c09 --- /dev/null +++ b/test/commands/package/packagePushUpgradeSchedule.test.ts @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import * as sinon from 'sinon'; +import { expect } from 'chai'; +import { PackagePushUpgrade, PackagePushScheduleResult } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import { PackagePushScheduleCommand } from '../../../src/commands/package/push-upgrade/schedule.js'; + +const pushReq: PackagePushScheduleResult = { + PushRequestId: 'mockPushJobId', + ScheduledStartTime: '2023-01-01T00:00:00Z', + Status: 'Scheduled', +}; + +describe('package:pushupgrade:schedule - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let scheduleStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + scheduleStub = $$.SANDBOX.stub(PackagePushUpgrade, 'schedule'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should schedule the push upgrade with org input', async () => { + const cmdArgsOrg = [ + '-p', + '04tXXXXXXXXXXXXXXX', + '-v', + testOrg.username, + '--start-time', + '2023-01-01T00:00:00Z', + '--org-list', + '00Dxx0000001gEREAY,00Dxx0000001gFAEA0', + ]; + const cmd = new PackagePushScheduleCommand(cmdArgsOrg, config); + + scheduleStub.resolves(pushReq); + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.log.calledOnce).to.be.true; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(scheduleStub.calledOnce).to.be.true; + }); + + it('should schedule the push migration with --migrate-to-2gp flag', async () => { + const packageId = '04tXXXXXXXXXXXXXXX'; + const startTime = '2024-01-01T00:00:00Z'; + const orgList = ['00Dxx0000001gEREAY', '00Dxx0000001gFAEA0']; + const cmdArgs = [ + '--package', + packageId, + '--target-dev-hub', + testOrg.username, + '--start-time', + startTime, + '--org-list', + orgList.join(','), + '--migrate-to-2gp', // Add the migration flag + ]; + const cmd = new PackagePushScheduleCommand(cmdArgs, config); + + scheduleStub.resolves(pushReq); + const result = await cmd.run(); + expect(result).to.deep.equal(pushReq); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.log.calledOnce).to.be.true; + expect(scheduleStub.calledOnce).to.be.true; + + // Verify the arguments passed to the schedule function + const scheduleArgs = scheduleStub.firstCall.args; + expect(scheduleArgs[1]).to.equal(packageId); // 2nd arg: packageId + expect(scheduleArgs[2]).to.equal(startTime); // 3rd arg: startTime + expect(scheduleArgs[3]).to.deep.equal(orgList); // 4th arg: orgList + expect(scheduleArgs[4]).to.equal(true); // 5th arg: isMigration + }); +}); diff --git a/test/commands/package/packageVersion.nut.ts b/test/commands/package/packageVersion.nut.ts index 9fe2164a..9e71a327 100644 --- a/test/commands/package/packageVersion.nut.ts +++ b/test/commands/package/packageVersion.nut.ts @@ -512,14 +512,14 @@ describe('package:version:*', () => { pkg.versionNumber = sortedVersions[0].toString(); pkg.versionName = 'v1'; pjson.set('packageDirectories', [pkg]); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + aliases = Object.fromEntries([ ...pvRecords.map((pv: PackageVersionQueryResult, index) => [ `${pv.Package2.Name}@${versions[index].toString()}`, pv.SubscriberPackageVersionId, ]), [ancestryPkgName, pvRecords[0].Package2Id], - ]); + ]) as { [alias: string]: string }; pjson.set('packageAliases', aliases); pjson.set('namespace', pvRecords[0].Package2.NamespacePrefix); pjson.writeSync(); diff --git a/yarn.lock b/yarn.lock index 4b7f8598..cca54fdd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1742,13 +1742,13 @@ dependencies: "@salesforce/ts-types" "^2.0.12" -"@salesforce/packaging@^4.5.0": - version "4.5.0" - resolved "https://registry.yarnpkg.com/@salesforce/packaging/-/packaging-4.5.0.tgz#05b9bb10c2f4aef4db272d5f98be2d11bfaeef54" - integrity sha512-gIwDkkX+XNR5gAqP/sfbF6lmZuC75dndTd4GjYhqlkvcWMCNIJyB8hTj72KlHz3dK8cGoicOeZWuqxX+ZRpGqA== +"@salesforce/packaging@^4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@salesforce/packaging/-/packaging-4.6.0.tgz#ae30f6593da66d32b451c879d1eec23dcf664161" + integrity sha512-DAt37E6C0KeVbkIZEiplN6vmqQ5NB58TSYAk6LjX6+ZbvSV4lnBc4mSCDcErmqCn5mWW3fdPvxL8FlyYhmpL4g== dependencies: "@jsforce/jsforce-node" "^3.6.5" - "@salesforce/core" "^8.8.5" + "@salesforce/core" "^8.11.1" "@salesforce/kit" "^3.2.3" "@salesforce/schemas" "^1.9.0" "@salesforce/source-deploy-retrieve" "^12.16.9" @@ -2229,21 +2229,7 @@ "@smithy/types" "^4.2.0" tslib "^2.6.2" -"@smithy/signature-v4@^5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-5.0.2.tgz#363854e946fbc5bc206ff82e79ada5d5c14be640" - integrity sha512-Mz+mc7okA73Lyz8zQKJNyr7lIcHLiPYp0+oiqiMNc/t7/Kf2BENs5d63pEj7oPqdjaum6g0Fc8wC78dY1TgtXw== - dependencies: - "@smithy/is-array-buffer" "^4.0.0" - "@smithy/protocol-http" "^5.1.0" - "@smithy/types" "^4.2.0" - "@smithy/util-hex-encoding" "^4.0.0" - "@smithy/util-middleware" "^4.0.2" - "@smithy/util-uri-escape" "^4.0.0" - "@smithy/util-utf8" "^4.0.0" - tslib "^2.6.2" - -"@smithy/signature-v4@^5.1.0": +"@smithy/signature-v4@^5.0.2", "@smithy/signature-v4@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-5.1.0.tgz#2c56e5b278482b04383d84ea2c07b7f0a8eb8f63" integrity sha512-4t5WX60sL3zGJF/CtZsUQTs3UrZEDO2P7pEaElrekbLqkWPYkgqNW1oeiNYC6xXifBnT9dVBOnNQRvOE9riU9w==