Last active
August 20, 2024 18:51
-
-
Save douglascayers/e3a9525729a1b512618adf720e3fbe94 to your computer and use it in GitHub Desktop.
Bash script to create a new managed package version from source control and no maintenance of sfdx-project.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# =========================================================================== # | |
# USAGE | |
# ----- | |
# create-package-version.sh [branchName] | |
# | |
# The $1 argument (optional) indicates the git branch to use. | |
# If not set then script defaults to 'develop' branch. | |
# =========================================================================== # | |
# exit when any command fails | |
set -e | |
log() { | |
echo -e "$1" >&2 | |
echo "" | |
} | |
log_file() { | |
file_name=$1 | |
file_ext=${file_name: -5} | |
# if file is json then prettyprint with jq | |
# else just output the file contents | |
if [ "$file_ext" == ".json" ]; then | |
cat $file_name | jq '.' >&2 | |
else | |
cat $file_name >&2 | |
fi | |
log "" | |
} | |
error() { | |
echo -e "\033[0;31mERROR $@ \033[0m" >&2 | |
exit 1 | |
} | |
cleanupOnExit() { | |
# Undo local file changes, it was only a workaround | |
# due to lack of support for CLI arguments. | |
log "Reverting local file changes script needed to make." | |
git reset --hard >&2 | |
} | |
# When script exits, make sure to call function to cleanup resources. | |
trap cleanupOnExit EXIT | |
# Safety check that any non-committed files | |
# are handled by the author before we clean the directory. | |
# | |
# This finds the names of files that have changed, | |
# then counts them up, then removes any leading whitespace | |
# so we have an actual "number" to compare against. | |
num_diffs=$(git diff --name-only | wc -l | tr -d ' ') | |
log "local file changes=$num_diffs" | |
if [ "$num_diffs" -gt "0" ]; then | |
error "Working directory is not clean. Run 'git status' then commit or undo your changes then try again." | |
fi | |
# This finds the number of local commits yet to be pushed. | |
num_commits=$(git cherry | wc -l | tr -d ' ') | |
log "unpushed commits=$num_commits" | |
if [ "$num_diffs" -gt "0" ] || [ "$num_commits" -gt "0" ]; then | |
error "Working directory has unpushed commits. Either run 'git push' or 'git reset --hard @{u}' then try again." | |
fi | |
# Which git branch to use as the metadata | |
# for the new package version. | |
branch_name=$1 | |
if [ -z "$branch_name" ]; then | |
branch_name=$(git branch --show-current) | |
fi | |
# Pull latest code from branch | |
git checkout $branch_name >&2 | |
git pull >&2 | |
# Remove any local commits that have | |
# not been pushed yet to ensure building | |
# from what's in our remote code repository. | |
git reset --hard @{u} >&2 | |
# Get the short hash of the latest commit | |
# We tag the package version with it | |
# to more easily know what code is in the package | |
head_sha=$(git rev-parse --short HEAD) | |
# Determine the default devhub username | |
cmd="sfdx force:config:get defaultdevhubusername --json" && (log "${cmd}") | |
output=$($cmd) && (echo $output | jq '.' >&2) | |
devhub_username=$(jq -r '.result[0]? | .value // ""' <<< $output) | |
if [ -z "$devhub_username" ]; then | |
error "No default devhub username set. Run 'sfdx force:config:set defaultdevhubusername=YOUR_DEVHUB_ALIAS' then try again." | |
else | |
log "devhub_username=$devhub_username" | |
fi | |
# Check for default package directory in sfdx-project.json | |
if [ -z "$package_name" ]; then | |
log "No package_name environment variable set, will use default package directory in sfdx-project.json." | |
log_file "sfdx-project.json" | |
package_name=$(cat sfdx-project.json | jq -r '.packageDirectories[]? | select(.default==true) | .package // ""') | |
fi | |
# Check for any package directory in sfdx-project.json | |
if [ -z "$package_name" ]; then | |
log "No default package directory found, will use first package directory in sfdx-project.json." | |
log_file "sfdx-project.json" | |
package_name=$(cat sfdx-project.json | jq -r '.packageDirectories? | .[0] | .package // ""') | |
fi | |
# Giving up | |
if [ -z "$package_name" ]; then | |
error "Package name not specified. Set the package_name environment variable or specify a default package directory in sfdx-project.json." | |
else | |
log "package_name=$package_name" | |
fi | |
# Retrieve package id for package name | |
cmd="sfdx force:package:list --targetdevhubusername $devhub_username --json" && (log "${cmd}") | |
output=$($cmd) && (echo $output | jq '.' >&2) | |
package_id=$(jq --arg package_name "$package_name" -r '.result[] | select(.Name == $package_name) | .Id // ""' <<< $output) | |
if [ ! $package_id ]; then | |
error "We could not find a package with name '$package_name' owned by '$devhub_username' dev hub org." | |
else | |
log "package_id=$package_id" | |
fi | |
# Calculate next version number. | |
# If the latest package version is released then | |
# we need to increment the major or minor version numbers. | |
cmd="sfdx force:package:version:list --targetdevhubusername $devhub_username --packages $package_id --concise --released --json" && (log "${cmd}") | |
output=$($cmd) && (echo $output | jq '.' >&2) | |
last_package_version=$(jq '.result | sort_by(-.MajorVersion, -.MinorVersion, -.PatchVersion, -.BuildNumber) | .[0] // ""' <<< $output) | |
last_package_version_id=$(jq -r '.Id?' <<< $last_package_version) | |
is_released=$(jq -r '.IsReleased?' <<< $last_package_version) | |
major_version=$(jq -r '.MajorVersion?' <<< $last_package_version) | |
minor_version=$(jq -r '.MinorVersion?' <<< $last_package_version) | |
patch_version=$(jq -r '.PatchVersion?' <<< $last_package_version) | |
build_version=$(jq -r '.BuildVersion?' <<< $last_package_version) | |
if [ "$branch_name" == "master" ]; then | |
major_version=$(($major_version+1)); | |
minor_version=0 | |
patch_version=0 | |
build_version=1 | |
else | |
if [ ! $major_version ]; then major_version=1; fi; | |
if [ ! $minor_version ]; then minor_version=0; fi; | |
if [ ! $patch_version ]; then patch_version=0; fi; | |
if [ "$is_released" == "true" ]; then | |
minor_version=$(($minor_version+1)); | |
build_version=1 | |
else | |
build_version=$(($build_version+1)); | |
fi; | |
fi; | |
version_number=$major_version.$minor_version.$patch_version.$build_version | |
log "version_number=$version_number" | |
log "last_package_version_id=$last_package_version_id" | |
# Update the 'ancestorId' property of the default package directory | |
# in sfdx-project.json because as of Winter '20 it's not able to | |
# be specified via the force:package:version:create CLI command. | |
project_json=$(jq --arg last_package_version_id "$last_package_version_id" --arg package_name "$package_name" --arg version_number "$version_number" '(.packageDirectories[] | select(.package == $package_name) | .versionNumber) |= $version_number | (.packageDirectories[] | select(.package == $package_name) | .ancestorId) |= $last_package_version_id' < sfdx-project.json) && (echo $project_json > sfdx-project.json) | |
log_file "sfdx-project.json" | |
# Create a new package version | |
cmd="sfdx force:package:version:create --targetdevhubusername $devhub_username --package $package_id --versionnumber $version_number --installationkeybypass --codecoverage --branch $branch_name --tag $head_sha --wait 10 --json" | |
package_definition_file="config/${package_name// /-}.json" | |
if [ -f "$package_definition_file" ]; then | |
# The org definition file when package version is created | |
log "Found org definition file for package version creation: $package_definition_file" | |
log_file "$package_definition_file" | |
cmd="$cmd --definitionfile $package_definition_file" | |
else | |
log "Didn't find an org definition file at $package_definition_file, will not use --definitionfile flag." | |
fi; | |
log "${cmd}" | |
output=$($cmd) && (echo $output | jq '.' >&2) | |
subscriber_package_version_id=$(jq -r '.result.SubscriberPackageVersionId?' <<< $output) | |
if [ ! $subscriber_package_version_id ]; then | |
error "Unable to determine the generated subscriber package version id." | |
else | |
log "subscriber_package_version_id=$subscriber_package_version_id" | |
fi | |
# Promote package version so that we can | |
# easily upgrade it in orgs with prior versions installed. | |
# Otherwise, we have to uninstall beta package versions first. | |
# Also, only promoted package versions can be installed in production. | |
cmd="sfdx force:package:version:promote --targetdevhubusername $devhub_username --package $subscriber_package_version_id --noprompt --json" && (log "${cmd}") | |
output=$($cmd) && (echo $output | jq '.' >&2) | |
# Display new package version details | |
cmd="sfdx force:package:version:report --targetdevhubusername $devhub_username --package $subscriber_package_version_id --verbose --json" && (log "${cmd}") | |
output=$($cmd) && (echo $output | jq '.' >&2) | |
log "Run 'sfdx force:package:install --package $subscriber_package_version_id --noprompt --publishwait 10 --wait 10 --targetusername YOUR_ALIAS' to install this package version." | |
# Return the package version id by echoing it to stdout | |
echo $subscriber_package_version_id |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment