Automatically tag latest commit deployed

As we continue working and increasing our Salesforce projects, even the dynamic deployments can grow a lot between releases (around 1 month of development). So the build at the beginning of the release may take 5 to 10 minutes to deploy and run the specific tests, but by the end of the deployment it may be taking up to 3 hours (deploying almost 10k components and running 8k unit tests). In order to be able to keep a more “decent” build time we came with the idea of build only the things that changed since the last successful deployment. Bamboo doesn’t have something like this out of the box so I created a simple script that runs at the end of the build (after Salesforce returns a successful message) and creates a tag on the last commit that was deployed. I also updated the script that generates the package to be deployed in order to pick up from that last tag instead of the hard-coded commit. By doing this we are having an average build time of 20 minutes. The key here is to keep your branch up to date with the latest changes and run the builds often, so even if you didn’t merge anything from your side today, you still deploy what the other teams did, and tomorrow when you merge and run your build you will be deploying only your changes.
Let’s take a look at the script:

#/usr/bin/env bash

# $PLANKEY ${bamboo.planKey}

# $REVISION ${bamboo.planRepository.revision}

# $PLANNAME ${bamboo.planName}

# $BUILDNUMBER ${bamboo.buildNumber}

# $REPOSITORYURL ${bamboo.planRepository.repositoryUrl}

# $BBPASSWORD ${bamboo_bitbucket_password}

function usage() { echo "Usage: $0 -k  -r  -n  -b  -u  -p " 1>&2; exit 1; }

while getopts :k:r:n:b:u:p option

do

case "${option}"

in

k) PLANKEY=${OPTARG};;

r) REVISION=${OPTARG};;

n) PLANNAME=${OPTARG};;

b) BUILDNUMBER=${OPTARG};;

u) REPOSITORYURL=${OPTARG};;

p) BBPASSWORD=${OPTARG};;

*) usage;; # Invalid argument

esac

done

if [[ -z "${BBPASSWORD// }" ]]

then

BBPASSWORD=${bamboo_bitbucket_password}

fi

echo creating tag for commit: $REVISION

DATE=`date '+%Y%m%d%H%M%S'`

TAGNAME="$PLANKEY-$DATE"

echo final tag name: $TAGNAME

echo creating repo to create and push tag

ACTUALURL=$REPOSITORYURL

USERNAME=[username]

PASSWORD=$BBPASSWORD

REPOURL=${ACTUALURL#*https://}

REPOURL="https://"$USERNAME:$PASSWORD@$REPOURL

git remote add central2 $REPOURL

git config --global user.email [email address]

git config --global user.name $USERNAME

git config --global push.default simple

echo deleting previous tags

if [[ ! -z "${PLANKEY// }" ]]

then

echo finding if there is a tag

echo tags: `git tag -l --sort=v:refname $PLANKEY* | head -n -1`

TEMP=`git tag -l --sort=v:refname $PLANKEY* | head -n -1`

printf "\n"

if [[ ! -z "${TEMP// }" ]]

then

for tag in `git tag -l --sort=v:refname $PLANKEY* | head -n -1`

do

git tag -d $tag

git push central2 :refs/tags/$tag

done

fi

fi

echo pushing new tag

git tag $TAGNAME -m "$PLANNAME build number $BUILDNUMBER passed build." $REVISION

git push central2 $TAGNAME

git ls-remote --exit-code --tags central2 $BUILDNUMBER

git remote remove central2

As you can see the script is pretty simple and straight forward. There are some key things to take into account do. Bamboo doesn’t have a way to pass the connection created to a repository, so you need to create one inside the script. That’s what this piece is:

echo creating repo to create and push tag

ACTUALURL=$REPOSITORYURL

USERNAME=[username]

PASSWORD=$BBPASSWORD

REPOURL=${ACTUALURL#*https://}

REPOURL="https://"$USERNAME:$PASSWORD@$REPOURL

git remote add central2 $REPOURL

git config --global user.email [email address]

git config --global user.name $USERNAME

git config --global push.default simple

As you can see I had to even create one with a different name (central2) to prevent having conflicts. And just in case at the end we remove it:

git remote remove central2

The following step is to basically delete all the existing tags related to this plan, as we don’t want any of the previous one, but the last one (just in case). This helps keep the repo cleaner from non-useful tags:

echo deleting previous tags

if [[ ! -z "${PLANKEY// }" ]]

then

echo finding if there is a tag

echo tags: `git tag -l --sort=v:refname $PLANKEY* | head -n -1`

TEMP=`git tag -l --sort=v:refname $PLANKEY* | head -n -1`

printf "\n"

if [[ ! -z "${TEMP// }" ]]

then

for tag in `git tag -l --sort=v:refname $PLANKEY* | head -n -1`

do

git tag -d $tag

git push central2 :refs/tags/$tag

done

fi

fi

And then we create the tag we want and push it back to the repo:

echo creating tag for commit: $REVISION

DATE=`date '+%Y%m%d%H%M%S'`

TAGNAME="$PLANKEY-$DATE"

echo final tag name: $TAGNAME

echo pushing new tag

git tag $TAGNAME -m "$PLANNAME build number $BUILDNUMBER passed build." $REVISION

git push central2 $TAGNAME

git ls-remote --exit-code --tags central2 $BUILDNUMBER

git remote remove central2

And then the changes we did to our script that generates the package dynamically. First we added a new parameter to pass the pattern that the tag names follow for that plan:

# Read command line args

while getopts :l:p:t:v option

do

case "${option}"

in

l) LCOMMIT=${OPTARG};;

p) PREVRSA=${OPTARG};;

t) TAGNAME=${OPTARG};;

v) VERBOSE=1;;

*) usage;; # Invalid argument

esac

done

And then we check if the tag exists to use the latest one, if not we still use the commit that was sent as a parameter:

if [[ ! -z "${TAGNAME// }" ]]

then

echo finding if there is a tag

# git tag -l

echo tags: `git tag -l $TAGNAME*`

TEMP=`git tag -l $TAGNAME*`

printf "\n"

if [[ ! -z "${TEMP// }" ]]

then

LASTTAG=`git tag -l --sort=-v:refname $TAGNAME* | head -1`

echo last tag: $LASTTAG

printf "\n"

# git show mylabel --pretty=format:"%H" --quiet

echo git show $LASTTAG --pretty=format:\"%H\" --quiet

TAGCOMMIT=`git show $LASTTAG --pretty=format:\"%H\" --quiet | tail -n1`

echo tag commit found: $TAGCOMMIT

TAGCOMMIT="${TAGCOMMIT%\"}"

TAGCOMMIT="${TAGCOMMIT#\"}"

echo trimming commit: $TAGCOMMIT

fi

fi

if [[ ! -z "${TAGCOMMIT// }" ]]

then

echo found tag commit and going to use it

PREVRSA=$TAGCOMMIT

echo commit to use: $PREVRSA

fi