You’ve probably seen the curl command shown below in many articles online.
curl -u admin:admin -F file=@"name of zip file" -F name="name of package" -F force=true -F install=true http://localhost:4505/crx/packmgr/service.jsp
It allows you to upload and install a package to an AEM server, and can also be used in builds within Jenkins to deploy a package after the maven build completes.
In this post, I will walk through a script that will do this for us in a cleaner manner. This script will fail if the package deployment fails or if the AEM server returns anything but 200.
I added comments everywhere to make this easier to understand, but if anything is unclear, please let me know in the comment section!
The Process
The script:
#!/bin/bash # Doc HELP_TEXT=" A shell script to install packages to AEM Params: -f, --file The zip file to instal (cannot be used with -m, --module param) -m, --module The folder name of maven module that produces a zip package (cannot be used with -f, --file param) -h, --host The instance host -p, --port The instance port -u, --user The user name to use for auth Password should be set via env variable: CRX_PASSWORD Set from env variable, default to 'admin' Other variables you can set via environment variables: CRX_USER Set via user argument above, defaults to 'admin' CRX_PORT Set via port argument above, defaults to '4502' CRX_HOST Set via host argument above, defaults to 'localhost' " # if the first arg is "--help", "help" or "-h" print help message and exit if [ $1 = "--help" ] || [ $1 = "help" ] || [ $1 = "-h" ]; then printf "$HELP_TEXT" exit 1 fi # parse params as per: https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash while [[ $# -gt 0 ]] do key="$1" case $key in # parse file argument -f|--file) FILE="$2" shift # past argument shift # past value ;; # parse file argument -m|--module) MVN_MODULE="$2" shift # past argument shift # past value ;; # parse host argument -h|--host) CRX_HOST="$2" shift # past argument shift # past value ;; # parse port argument -p|--port) CRX_PORT="$2" shift # past argument shift # past value ;; # parse user argument -u|--user) CRX_USER="$2" shift # past argument shift # past value ;; # unknown option *) echo "WARNING: unknown option: $1" shift # past argument ;; esac done # use defaults if param was not passed CRX_USER="${CRX_USER:-admin}" CRX_PASSWORD="${CRX_PASSWORD:-admin}" # password should be passed as an env variable CRX_HOST="${CRX_HOST:-localhost}" CRX_PORT="${CRX_PORT:-4502}" # If an module folder name is passed, use that to find the zip package to install if [ ! -z "$MVN_MODULE" ] then if [ -d "$MVN_MODULE" ] then ZIP_PATTERN="$MVN_MODULE/target/*.zip" ZIP_PACKAGES=( $ZIP_PATTERN ) FILE="${ZIP_PACKAGES[0]}" else echo "ERROR: The module folder: $MVN_MODULE does not exist}" exit 1 fi else echo "INFO: no module param was passed. Using file param if exists" fi # sets INSTALL_COMMAND, first arg is the password setInstallCommand(){ # --fai : https://curl.haxx.se/docs/manpage.html#-f fails on server error # -u : user:password for basic auth # -F force=true : force install # -F install=true : install after upload # -F strict=true : fails if package fails to deploy eval "INSTALL_COMMAND='curl --fail -u $CRX_USER:$1 -F file=@$FILE -F name=$FILE -F force=true -F install=true -F strict=true http://$CRX_HOST:$CRX_PORT/crx/packmgr/service.jsp'" } # print command that will be executed, sub password with "*****" setInstallCommand "*****" echo "Executing command: $INSTALL_COMMAND" # Execute command setInstallCommand "$CRX_PASSWORD" eval "$INSTALL_COMMAND"
Copy the code and paste it into a file
Let’s call it:
deploy.sh
Make it executable
chmod +x deploy.sh
Now, let’s explore what we can do with it
(You should first copy paste it into the root of your AEM project):
Run ./deploy help
to view the help message and all available params.
A shell script to install packages to AEM Params: -f, --file The zip file to instal (cannot be used with -m, --module param) -m, --module The folder name of maven module that produces a zip package (cannot be used with -f, --file param) -h, --host The instance host -p, --port The instance port -u, --user The user name to use for auth Password should be set via env variable: CRX_PASSWORD Set from env variable, default to 'admin' Other variables you can set via environment variables: CRX_USER Set via user argument above, defaults to 'admin' CRX_PORT Set via port argument above, defaults to '4502' CRX_HOST Set via host argument above, defaults to 'localhost'
Let’s say you want to deploy the UI.apps package after the build is done on your local machine running at localhost:4502:
./deploy.sh -m ui.apps
Now let’s say you want to deploy it to your local publisher:
./deploy.sh -m ui.apps -p 4503
Wait a sec! What just happened there??
We specified that the maven module via “-m ui.apps” the deploy script will go to the folder `ui.apps/target` and pick the first .zip file it finds and deploy that. Remember that this assumes that your module produces one package, as is often the case.
OK, now let’s say you want to deploy a very specific package in a very specific location in your repo: “packages/my-favorite-package.zip”. You can use -f for that:
./deploy.sh -f packages/my-favorite-package.zip
Now let’s move to Jenkins (or your favorite CD). Things get a little interesting here. You have a secret password and you don’t want to share it with everyone who can see the build. Fear not! You can use secret environment variables!
There are a few ways to do this, which I won’t get into. You can refer to this and this and many others to see how you can bind a password to an environment variable. In our case, the goal is to bind your password to CRX_PASSWORD
environment variable.
Note: you can also specify the username, host and port via CRX_USER, CRX_HOST and CRX_PORT respectively.
Now in your Jenkins build, you can add a post-build script that looks like:
./deploy.sh -m ui.apps -u adminusername -h dev-author.mycompany.com -p 4502
If you have more than one module that produces packages, you can keep calling the deploy script. For example, if you want to deploy both ui.apps and ui.content packages to both your author and publish instance:
./deploy.sh -m ui.apps -u adminusername -h dev-author.mycompany.com -p 4502 ./deploy.sh -m ui.apps -u adminusername -h dev-publish.mycompany.com -p 4503 ./deploy.sh -m ui.content -u adminusername -h dev-author.mycompany.com -p 4502 ./deploy.sh -m ui.content -u adminusername -h dev-publish.mycompany.com -p 4503
Hopefully, this helps make your next Jenkins build setup easier!
Subscribe for more helpful tips and tricks.