Setting up Salesforce’s CICD using GIT and Jenkins
@CICD @Salesforce @Jenkins @GIT
Objective:
I am tracking various metadata in GIT and need to deploy only the components that were changed but not to redeploy all the metadata from master branch.
Solution:
There could be various options to implement this requirement. I followed a custom route to write a shell script that compares GIT branches (stage vs master) and generates package.xml and a folder “DEPLOY” where only changed components are placed in there. Finally deploys only changed metadata from “DEPLOY” folder.
This script works and was written quickly to fulfill my ask. Feel free to modify based on your requirement.
# =================================================
# Create helper functions
# =================================================
function copy_file_from_branch {
local branch_name="$1"
local file_name="$2"
#echo "==================in copy start=========================================="
#echo "$file_name"
#echo "====================in copy end========================================"
local dir_name="$(dirname "$file_name")"
if [ ! -d "$dir_name" ]; then
mkdir -p "$dir_name"
fi
#if class or trigger then add meta file
local cls="src/classes/"
local mtd="-meta.xml"
local trig="src/triggers/"
local aur="src/aura/"
statR="src/staticresources/"
#Add classes
if test "${file_name#*$cls}" != "$file_name"
then
if test "${file_name#*$mtd}" != "$file_name"
then
echo "do nothing"
else
git show "$branch_name":"$file_name" > "$file_name"
git show "$branch_name":"$file_name-meta.xml" > "$file_name-meta.xml"
fi
fi
#Add Trigger
if test "${file_name#*$trig}" != "$file_name"
then
if test "${file_name#*$mtd}" != "$file_name"
then
echo "do nothing"
else
git show "$branch_name":"$file_name" > "$file_name"
git show "$branch_name":"$file_name-meta.xml" > "$file_name-meta.xml"
fi
fi
#Add AuraDefinitionBundle
if test "${file_name#*$aur}" != "$file_name"
then
if test "${file_name#*$mtd}" != "$file_name"
then
echo "do nothing"
else
git show "$branch_name":"$file_name" > "$file_name"
fi
fi
#Add StaticResource
if test "${file_name#*$statR}" != "$file_name"
then
if test "${file_name#*$mtd}" != "$file_name"
then
echo "do nothing"
else
git show "$branch_name":"$file_name" > "$file_name"
git show "$branch_name":"$file_name-meta.xml" > "$file_name-meta.xml"
fi
fi
#for now dont copy all
#git show "$branch_name":"$file_name" > "$file_name"
}
function create_directory {
local dir_name="$1"
local branch_src="$2"
local branch_dest="$3"
local diff_filter="$4"
local files=""
local i=""
local output="${dir_name}_${branch_src//[^a-zA-Z0-9]/}_to_${branch_dest//[^a-zA-Z0-9]/}.txt"
local packa="package.xml"
metalist=""
cls="src/classes/"
trig="src/triggers/"
aur="src/aura/"
statR="src/staticresources/"
# Create our directory for storing the files
mkdir "$dir_name"
cd "$dir_name"
#Fetch branches
#git checkout pre_prod
#git checkout sales_bau
# Get file list from git
files="$(git diff "origin/$branch_dest" "origin/$branch_src" --name-only --diff-filter="$diff_filter")"
# Loop through file list, grabbing each file from the
# correct branch in git, and writing it to disk
#echo "$files" | while read line; do
while read line
do
copy_file_from_branch "origin/$branch_src" "${line}"
echo "${line}"
echo "$cls"
if test "${line#*$cls}" != "$line"
then
metalist=$metalist","$cls
else
if test "${line#*$trig}" != "$line"
then
metalist=$metalist","$trig
else
if test "${line#*$aur}" != "$line"
then
metalist=$metalist","$aur
else
if test "${line#*$statR}" != "$line"
then
metalist=$metalist","$statR
fi
fi
fi
fi
done <<< "$files"
echo "$metalist"
cd src
#Now create package.xml
if [[ "$dir_name" == "DEPLOY" ]]
then
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" >> "$packa"
echo "<Package xmlns=\"http://soap.sforce.com/2006/04/metadata\">" >> "$packa"
echo "$metalist"
#To add class
if test "${metalist#*$cls}" != "$metalist"
then
echo "<types>" >> "$packa"
echo "<members>*</members>" >> "$packa"
echo "<name>ApexClass</name>" >> "$packa"
echo "</types>" >> "$packa"
fi
#To add trigger
if test "${metalist#*$trig}" != "$metalist"
then
echo "<types>" >> "$packa"
echo "<members>*</members>" >> "$packa"
echo "<name>ApexTrigger</name>" >> "$packa"
echo "</types>" >> "$packa"
fi
#To add AuraDefinitionBundle
if test "${metalist#*$aur}" != "$metalist"
then
echo "<types>" >> "$packa"
echo "<members>*</members>" >> "$packa"
echo "<name>AuraDefinitionBundle</name>" >> "$packa"
echo "</types>" >> "$packa"
fi
#To add StaticResource
if test "${metalist#*$statR}" != "$metalist"
then
echo "<types>" >> "$packa"
echo "<members>*</members>" >> "$packa"
echo "<name>StaticResource</name>" >> "$packa"
echo "</types>" >> "$packa"
fi
echo "<version>41.0</version>" >> "$packa"
echo "</Package>" >> "$packa"
fi
#End
# Now move back to the main directory, and write
# some diagnostic info
cd ..
cd ..
echo "============================================================" >> "$output"
echo "==== CONTENTS OF $dir_name DIRECTORY:" >> "$output"
echo "============================================================" >> "$output"
echo "" >> "$output"
git diff "$branch_dest" "$branch_src" --shortstat --diff-filter="$diff_filter" >> "$output"
echo "" >> "$output"
git diff "$branch_dest" "$branch_src" --numstat --diff-filter="$diff_filter" >> "$output"
echo "" >> "$output"
git diff "$branch_dest" "$branch_src" --dirstat --diff-filter="$diff_filter" >> "$output"
echo "" >> "$output"
git diff "$branch_dest" "$branch_src" --dirstat-by-file --diff-filter="$diff_filter" >> "$output"
echo "" >> "$output"
echo "============================================================" >> "$output"
echo "==== INFO WITH NO DIFF FILTERS APPLIED:" >> "$output"
echo "============================================================" >> "$output"
echo "" >> "$output"
git diff "$branch_dest" "$branch_src" --shortstat >> "$output"
echo "" >> "$output"
git diff "$branch_dest" "$branch_src" --numstat >> "$output"
echo "" >> "$output"
git diff "$branch_dest" "$branch_src" --dirstat >> "$output"
echo "" >> "$output"
git diff "$branch_dest" "$branch_src" --dirstat-by-file >> "$output"
echo "" >> "$output"
git diff "$branch_dest" "$branch_src" --name-status >> "$output"
echo "" >> "$output"
}
# =================================================
# Get User Input, and create new directories
# =================================================
# Get the build directory name
echo "Input the name of the build directory:"
dir_build="src_build"
#read dir_build
#dir_build=${dir_build//[^a-zA-Z0-9]/}
# Exit immediately if our build directory already exists
#if [ -d "$dir_build" ]; then
# echo "Exiting because our build directory: " $dir_build " already exists."
# exit
#fi
#git diff my_test2 my_test --name-only --diff-filter="M"
# Get the source branch name
echo "Input the name of the source/deployment branch:"
#read branch_src
branch_src="Stage"
# Get the destination branch name
echo "Input the name of the destination/restore branch:"
#read branch_dest
branch_dest="Master"
#git checkout "$branch_src"
#git checkout "$branch_dest"
# Make our main build directory, and move there
if [ -d "$dir_build" ]; then
#printf '%s\n' "Removing Lock ($DIR)"
rm -rf "$dir_build"
fi
mkdir $dir_build
cd $dir_build
# Create our DEPLOY and RESTORE directories
create_directory "DEPLOY" "$branch_src" "$branch_dest" "MA"
#create_directory "RESTORE" "$branch_dest" "$branch_src" "M"
exit