Skip to content

Instantly share code, notes, and snippets.

@jeffdonthemic
Last active August 15, 2023 14:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeffdonthemic/eec37b3980fcb1af7e80ddd58f4bcf7e to your computer and use it in GitHub Desktop.
Save jeffdonthemic/eec37b3980fcb1af7e80ddd58f4bcf7e to your computer and use it in GitHub Desktop.
Salesforce 2GP Packaging CLI
source 'https://rubygems.org'
gem 'restforce', '~> 6.2.2'
gem 'thor'
require 'restforce'
require 'stringio'
require 'thor'
# INSTRUCTIONS
# 1. Place both files in a new directory
# 2. Install the ruby gems:
# > bundle
# Display the list of commands:
# > thor list
# thor packaging:subscribers # Returns all subscriber orgs filtered by an optional package version id
# thor packaging:subscribers_count # Returns the number of subscriber orgs filtered by an optional package version id
# thor packaging:upgrade # Upgrades all subscriber orgs or a specific subsciber org with a specific Package Version - ex: thor packaging:upgrade PACKAGE_VERSION_ID --org_id ORG_ID
# thor packaging:upgrade_status # Displays the status of PACKAGE_PUSH_REQUEST_ID and optionally the individual jobs - ex: thor packaging:upgrade_status PACKAGE_PUSH_REQUEST_ID --show_jobs
# thor packaging:versions # Returns all package versions
# COMMAND HELP
# > thor help packaging:upgrade
# Usage:
# thor packaging:upgrade
#
# Options:
# [--org-id=ORG_ID] # The Id of the subscriber org to be upgraded.
#
# Upgrades all subscriber orgs or a specific subsciber org with a specific Package Version - ex: thor packaging:upgrade PACKAGE_VERSION_ID --org_id ORG_ID
# UPGRADE DOCS: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/push_upgrade_use_api.htm?q=packageversion
# WARNING: Push upgrades have not been testing for >2000 subscriber orgs.
class Packaging < Thor
org = JSON.parse(`sfdx org display --json`)
if org['result']['username'] != 'YOUR_DEVHUB_ORG_USERNAME'
abort "Aborted! The DevHub org is not the default sfdx user. Run: sf config set defaultusername=YOUR_DEVHUB_ORG_USERNAME"
end
@@client = Restforce.new(
oauth_token: org['result']['accessToken'],
instance_url: org['result']['instanceUrl'],
api_version: '57.0'
)
desc "upgrade_status", "Displays the status of PACKAGE_PUSH_REQUEST_ID and optionally the individual jobs - ex: thor packaging:upgrade_status PACKAGE_PUSH_REQUEST_ID --show_jobs"
method_option :show_jobs, :desc => "Displays the individual jobs' status"
def upgrade_status(package_push_request_id)
status = @@client.query("SELECT DurationSeconds,EndTime,Id,PackageVersionId,ScheduledStartTime,StartTime,Status FROM PackagePushRequest WHERE ID = '#{package_push_request_id}'")
puts 'PACKAGE PUSH REQUEST'
puts '-----------------------'
puts "Status: #{status.first.Status}"
puts "ScheduledStartTime: #{status.first.ScheduledStartTime}"
puts "StartTime: #{status.first.StartTime}"
puts "EndTime: #{status.first.EndTime}"
puts "DurationSeconds: #{status.first.DurationSeconds}"
puts "PackageVersionId: #{status.first.PackageVersionId}"
puts '-----------------------'
if options[:show_jobs]
jobs = @@client.query("SELECT DurationSeconds,EndTime,Id,StartTime,Status,SubscriberOrganizationKey FROM PackagePushJob WHERE PackagePushRequestId = '#{package_push_request_id}'")
puts ''
puts 'INDIVIDUAL SUBSCRIBER ORG JOBS'
puts '-----------------------'
jobs.each do |v|
puts "SubscriberOrganizationKey: #{v.SubscriberOrganizationKey}"
puts "Status: #{v.Status}"
puts "DurationSeconds: #{v.DurationSeconds}"
puts "StartTime: #{v.StartTime}"
puts "EndTime: #{v.EndTime}"
puts '-----------------------'
end
end
end
desc "upgrade", "Upgrades all subscriber orgs or a specific subsciber org with a specific Package Version - ex: thor packaging:upgrade PACKAGE_VERSION_ID --org_id ORG_ID"
method_option :org_id, :desc => "The Id of the subscriber org to be upgraded."
def upgrade(package_version_id)
# check that the org is available for upgrade
if options[:org_id]
subscribers = @@client.query("SELECT OrgKey FROM PackageSubscriber WHERE OrgKey = '#{options[:org_id]}' AND MetadataPackageVersionId != '#{package_version_id}'")
org_count = subscribers.count
else
subscribers = @@client.query("SELECT OrgKey FROM PackageSubscriber WHERE MetadataPackageVersionId != '#{package_version_id}'")
org_count = subscribers.count
end
if org_count > 0
request_id = @@client.create('PackagePushRequest', PackageVersionId: package_version_id)
# upgrade one specific org
if options[:org_id]
puts "Upgrading Org Id: #{options[:org_id]}"
@@client.create('PackagePushJob', PackagePushRequestId: request_id, SubscriberOrganizationKey: options[:org_id])
# upgrade all orgs not on the package version
else
puts "Upgrading #{subscribers.count} orgs"
subscribers.each do |s|
@@client.create('PackagePushJob', PackagePushRequestId: request_id, SubscriberOrganizationKey: s.OrgKey)
end
end
# update the package push request to start the deployment
@@client.update('PackagePushRequest', Id: request_id, Status: 'Pending')
puts "Package Push Request #{request_id} started for #{org_count} subscriber org(s). Check the status with: thor packaging:upgrade_status #{request_id} --show_jobs"
else
puts 'No orgs found to upgrade.'
end
end
desc "versions", "Returns all package versions"
def versions
versions = @@client.query("SELECT Id,MajorVersion,MetadataPackageId,MinorVersion,Name,PatchVersion,ReleaseState FROM MetadataPackageVersion ORDER BY SystemModstamp")
puts '-----------------------'
versions.each do |v|
puts "Name: #{v.Name}"
puts "MetadataPackageId: #{v.MetadataPackageId}"
puts "MajorVersion: #{v.MajorVersion}"
puts "MinorVersion: #{v.MinorVersion}"
puts "PatchVersion: #{v.PatchVersion}"
puts "ReleaseState: #{v.ReleaseState}"
puts '-----------------------'
end
end
desc "subscribers", "Returns all subscriber orgs filtered by an optional package version id"
method_option :package_version_id, :aliases => :p, :desc => "Filter subscriber orgs by installed pacakge."
def subscribers
q = "SELECT Id,InstalledStatus,MetadataPackageId,MetadataPackageVersionId,OrgKey FROM PackageSubscriber WHERE OrgStatus != 'Inactive'"
if options[:package_version_id]
q << " AND MetadataPackageVersionId = '#{options[:package_version_id]}'"
end
subscribers = @@client.query(q)
puts '-----------------------'
subscribers.each do |o|
puts "InstalledStatus: #{o.InstalledStatus}"
puts "MetadataPackageVersionId: #{o.MetadataPackageVersionId}"
puts "Org ID: #{o.OrgKey}"
puts '-----------------------'
end
puts "#{subscribers.count} subscriber orgs"
end
desc "subscribers_count", "Returns the number of subscriber orgs filtered by an optional package version id"
method_option :package_version_id, :aliases => :p, :desc => "Filter subscriber orgs by installed pacakge."
def subscribers_count
q = "SELECT count() FROM PackageSubscriber WHERE OrgStatus != 'Inactive'"
if options[:package_version_id]
q << " AND MetadataPackageVersionId = '#{options[:package_version_id]}'"
end
subscribers = @@client.query(q)
pp subscribers.count
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment