#!/bin/bash # civicrmrebase.sh # version 0.9.1 # Michael McMahon and Andrew # License: AGPLv3 # Based on https://gluestick.office.fsf.org/hosts/services/civicrm/upgrading/ # This script aids the CiviCRM upgrade procedure. This script rebases our # changes onto the latest tag and then packages the changes into a tarball. # To run this script, and follow these steps: # # 0. Boot Trisquel open a terminal, and connect to the FSF VPN. # 1. Create a build directory to save your civicrm builds. # mkdir -p ~/builds/fsf/civicrm && cd ~/builds/fsf/civicrm # 2. Place this script in that directory. # 3. Edit this file and set your first name to the my_name variable with # all lowercase letters. # 3. Run this script with: # bash civicrmrebase.sh # 4. Follow all prompts and continue with the workflow found at # https://gluestick.office.fsf.org/hosts/services/civicrm/upgrading/ # # To skip pushing changes to other machines (vcs or crmserver4d), use the # ```--dry-run``` argument like so: # bash civicrmrebase.sh --dry-run # Variables my_name=michael # Initialization checks # Check for /bin/bash. if [ "$BASH_VERSION" = '' ]; then echo "You are not using bash." echo "Use this syntax instead:" echo "sudo bash bluearchive.sh" exit 1 fi # Check networking # https://unix.stackexchange.com/questions/190513/shell-scripting-proper-way-to- # check-for-internet-connectivity echo Checking network... if ping -q -c 1 -W 1 fsf.org >/dev/null; then echo "The network is up." else echo "The network is down." echo "Check connection and restart script!" exit 1 fi # Log all stdout to logfile with date. logfile=/tmp/$(date +%Y%m%d-%H%M).log exec &> >(tee -a "$logfile") echo "Starting logfile as $logfile..." echo \ echo "User is set to $my_name. If you are not $my_name, stop the script now" echo "with CTRL+c. Edit this script, and replace $my_name with your name, and" echo "rerun the script." echo \ if [[ $1 != "--dry-run" ]]; then echo "--dry-run is disabled! External changes will be made!" echo "If this is not your intention, stop the script now with CTRL+c" echo "and run again with this syntax: bash civicrmrebase.sh --dry-run" else echo "--dry-run is enabled. No external changes will be made." fi echo \ # Clone civicrm-core from vcs.fsf.org if ls -d ./civicrm-core 1> /dev/null 2>&1; then echo "civicrm-core folder found!" echo "Remove this directory?" ls -d ./civicrm-core | xargs -p -n1 rm -r fi echo "Cloning our civicrm-core repo..." git clone git@vcs.fsf.org:civicrm-core.git cd civicrm-core # Add upstream echo "Adding upstream..." git remote add upstream https://github.com/civicrm/civicrm-core.git echo "Fetching upstream..." git fetch upstream # Extract tag and branch information echo "Latest upstream tag version:" tag=$(git tag --sort=-committerdate | head -n 1) # To manually upgrade to a different version, hardcode tag. Comment above and uncomment below. # tag=5.19.4 echo $tag # Explanation: # git tag --sort=-committerdate | head -n 1 # List all tags starting with the most recent. # Print 1st line # Output example: 5.17.0 cd .. # Check for previous attempts if ls -d ./*$tag 1> /dev/null 2>&1; then echo "Interactively removing folders that match $tag..." echo "Remove these directories?" ls -d ./*$tag | xargs -p -n1 rm -r fi echo "Renaming folder civicrm-core-$tag..." mv civicrm-core civicrm-core-$tag cd civicrm-core-$tag # UNUSED # echo "Latest upstream branch:" # git branch -a --sort=-committerdate | head -n 1 | sed 's/ remotes\///' # Explanation: # git branch -a --sort=-committerdate | sed -n '2p;3q' | sed 's/ remotes\///' # List all branches starting with the most recent. # Print 2nd line (faster than head -n 2 | tail -n 1). # Remove blankspace and remotes from the beginning. echo "Latest production branch:" pbranchfsf=$(git branch -a --sort=-committerdate | grep 'fsf$' | head -n 1 | sed 's/ remotes\///') echo $pbranchfsf # Explanation: # git branch -a --sort=-committerdate | grep 'fsf$' | head -n 1 | sed 's/ remotes\///' # List all branches starting with the most recent. # Print only lines that end with `fsf`. # Print first line. # Remove blankspace and `remotes/` from the beginning. # Output example: origin/5.16.3-fsf echo "Creating production branch variable..." pbranch=$(echo $pbranchfsf | sed 's/origin\///' | sed 's/-fsf//') echo $pbranch echo \ # Same as git branch -a --sort=-committerdate | grep 'fsf$' | head -n 1 | sed 's/ remotes\/origin\///' | sed 's/-fsf//' # Output example: 5.16.3 # Check if latest tag and latest production branch are the same. if [ "$pbranch" = "$tag" ]; then echo "You are currently using the latest tag in produciton!" echo "Script is exiting..." exit 1 fi # List commits between updates echo "Abbreviated commit lines between tag $pbranch and tag $tag..." git --no-pager log $pbranch..$tag --pretty=oneline --abbrev-commit echo \ # Prepare work branch git checkout $tag echo "Creating temp branch..." git checkout -b $tag-fsf-$my_name-attempt-a # Rebase echo "Ready to start rebasing!" echo "Our rebase command:" echo "git rebase --onto $tag-fsf-$my_name-attempt-a $pbranch $pbranchfsf" # DEBUG - Use this line with hard values instead of the following line to force # a merge conflict. # git rebase --onto $tag-fsf-$my_name-attempt-a 4.6.29 origin/4.6.29-fsf git rebase --onto $tag-fsf-$my_name-attempt-a $pbranch $pbranchfsf echo \ # If a merge conflict occurs, open a prompt to manually handle the conflicts. if [ $(tail -n 5 $logfile | grep -e skip -e continue -e abort | wc -l) -gt 2 ]; then echo "A merge conflict occurred, resolve and follow directions." echo "Run 'meld .' without quotes to visually view conflicts with a GUI." echo "Run 'exit' without quotes to continue with the script." bash else echo "A merge conflict did not occur! This simplifies things." fi # TODO Feature Request # If running dry-run as a cronjob, notifying whether there is a merge conflict # or not would be useful. This would require a change in logic. # Applying changes to a new branch name echo "Creating new branch $tag-fsf-$my_name-attempt-0..." git checkout -b $tag-fsf-$my_name-attempt-0 echo "Removing temp branch..." git branch -d $tag-fsf-$my_name-attempt-a echo \ # List differences between upstream and the rebased changes echo "Differences between upstream tag $tag and our new" echo "branch $tag-fsf-$my_name-attempt-0..." git --no-pager diff $tag $tag-fsf-$my_name-attempt-0 echo \ # Push attempt branch to VCS if [[ $1 != "--dry-run" ]]; then echo "Pushing branch $tag-fsf-$my_name-attempt-0 to origin..." git push -u origin $tag-fsf-$my_name-attempt-0 else echo "Skipping git push..." fi echo "Creating new branch $tag-fsf..." git branch $tag-fsf # Push fsf branch to VCS # If multiple people are attempting, comment this section out and review with # git diff between the attempt branches. if [[ $1 != "--dry-run" ]]; then echo "Pushing branch $tag-fsf to origin..." git push -u origin $tag-fsf else echo "Skipping git push..." fi # Creating live branch echo "Creating new branch live-$tag..." git branch live-$tag echo "NOTE: live-$tag is not pushed through this script." # Packaging echo "Leaving directory..." cd .. echo "Creating packaging directory civicrm-pkg-$tag..." mkdir -p civicrm-pkg-$tag cd civicrm-pkg-$tag echo "Downloading latest tarball..." if [ ! -f "civicrm-$tag-drupal.tar.gz" ]; then wget -q https://download.civicrm.org/civicrm-$tag-drupal.tar.gz fi echo "Extracting tarball..." tar xzf civicrm-$tag-drupal.tar.gz echo "Overlaying our code on top the upstream tarball..." rsync -avrSPX ../civicrm-core-$tag/* civicrm/ echo "Ensuring that civicrm/civicrm directory does not exist..." if [ -d "civicrm/civicrm" ]; then echo "The directory civicrm/civicrm exists!" exit 1 fi # Add the trustcommerceIPN.php script from the live branch if [ -d "tc-ipn-receiver" ]; then echo "Removing tc-ipn-receiver folder..." rm -fr tc-ipn-receiver fi echo "Cloning tc-ipn-receiver..." git clone git@vcs.fsf.org:tc-ipn-receiver.git cd tc-ipn-receiver echo "Changing to live branch..." git checkout live git pull echo "Copying trustcommerceIPN.php to civicrm/CRM/Core/Payment/..." cd .. cp tc-ipn-receiver/trustcommerceIPN.php civicrm/CRM/Core/Payment/ echo "Creating the tarball..." tar czf civicrm-${tag}_fsf.tar.gz civicrm # Push the package to crmserver4d if [[ $1 != "--dry-run" ]]; then echo "Uploading the package to crmserver4d..." scp civicrm-${tag}_fsf.tar.gz root@crmserver4d.fsf.org:/root/ else echo "Skipping this command, due to dry-run:" echo " scp civicrm-${tag}_fsf.tar.gz root@crmserver4d.fsf.org:/root/" fi # Logfile maintenance echo "Shrinking the logfile..." sed -i -E 's/.{37}0:00:00 //g' $logfile # rsync transfer speed/estimates echo "Copying $logfile to the civicrm-pkg-$tag directory..." cp $logfile . echo \ # Instructions to continue echo "Script is complete! Double check the" echo "civicrm-pkg-$tag/$(echo $logfile | sed 's/\/tmp\///') file" echo "before applying changes. Once verified, continue following the" echo "workflow at https://gluestick.office.fsf.org/hosts/services/civicrm/upgrading/" echo "by testing in the development server."