Skip to content

Instantly share code, notes, and snippets.

@douglascayers
Last active February 22, 2021 02:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save douglascayers/e3a9525729a1b512618adf720e3fbe94 to your computer and use it in GitHub Desktop.
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
#!/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