Azure DevOps Server repository backup - CloudCommandos/JohnChan GitHub Wiki
This script git clones all repositories in the specified DevOps Server Collections. Trigger this script with a cron-job that runs daily. Make sure to supply the username and apikey. You will also need an SSH key that is accepted by the DevOps Server.
#!/bin/bash
# Make sure the user who runs this script has an SSH key accepted by the DevOps Server
# Settings
devops_server_url="http://your_devops_server_ip_or_domain"
devops_server_username="<Your DevOps Server user account name>"
devops_server_user_apikey="<Get from DevOps Server user account>"
backup_to="./backup_root_folder_name"
## number of latest backup folders to retain (does not include 'latest' folder)
num_retain=3
## Declare collections in which repositories need backup
collections=( CAD CAP8 GIS Others RMS )
curdir=$(pwd)
timenow=$(date '+%Y-%m-%d')
echo -e "Folder name will be ${timenow}"
for collection_name in ${collections[@]}; do
# Get list of projects
echo -e "\n- Getting all projects in collection ${collection_name}"
collection_name=${collection_name// /%20}
collection_name=${collection_name%\"}
collection_name=${collection_name#\"}
projects_query=$(curl -s -u ${devops_server_username}:${devops_server_user_apikey} "${devops_server_url}/${collection_name}/_apis/projects?api-version=5.1")
num_projects=$(echo $projects_query | jq ".value | length")
if [ "$num_projects" != "" ]; then
echo -e "- Collection ${collection_name} has ${num_projects} projects"
for (( idx=0; idx<$num_projects; idx++ )); do
# Get list of repositories in project
project_name=$(echo $projects_query | jq ".value[$idx].name")
echo -e "\n-- Getting all repositories in project ${project_name}"
project_name=${project_name// /%20}
project_name=${project_name%\"}
project_name=${project_name#\"}
repositories_query=$(curl -s -u ${devops_server_username}:${devops_server_user_apikey} "${devops_server_url}/${collection_name}/${project_name}/_apis/git/repositories?api-version=5.1")
num_repositories=$(echo $repositories_query | jq ".value | length")
if [ "$num_repositories" != "" ]; then
echo -e "-- Project ${project_name} has ${num_repositories} repositories"
for (( idx2=0; idx2<$num_repositories; idx2++ )); do
sshUrl=$(echo $repositories_query | jq -r ".value[$idx2].sshUrl")
repository_name=$(echo $repositories_query | jq -r ".value[$idx2].name")
repository_name=${repository_name// /%20}
repository_name=${repository_name%\"}
repository_name=${repository_name#\"}
if [ "$sshUrl" != "" ]; then
mkdir -p "${curdir}/${backup_to}/latest/${collection_name}/${project_name}"
if [ ! -d "${curdir}/${backup_to}/latest/${collection_name}/${project_name}/${repository_name}/.git" ]; then
echo -e "--- Cloning repository ${repository_name}"
cd "${curdir}/${backup_to}/latest/${collection_name}/${project_name}"
git clone $sshUrl "${repository_name}"
else
echo -e "--- Pulling repository ${repository_name}"
cd "${curdir}/${backup_to}/latest/${collection_name}/${project_name}/${repository_name}"
git pull $sshUrl
fi
fi
done
else
echo -e "-- Project ${project_name} has no repository"
fi
done
else
echo -e "- Collection ${collection_name} has no project"
fi
done
# Copy/Merge latest folder into timestamped folder
echo -e "\nSyncing from latest to timestamped folder"
mkdir -p "${curdir}/${backup_to}/${timenow}"
rsync -pavW --progress --delete "${curdir}/${backup_to}/latest/*" "${curdir}/${backup_to}/${timenow}"
echo -e "\nRetain up to ${num_retain} backups"
cd "${curdir}"
folders=( $(ls "$backup_to") )
# Remove 'latest' folder from selection
folders=( "${folders[@]/latest}" )
# sort in descending order
IFS=$'\n' sorted_folders=($(sort -r <<<"${folders[*]}")); unset IFS
# retain specified number of backups
cd "${curdir}/${backup_to}"
for i in ${!sorted_folders[@]}; do
if (( $i >= $num_retain )); then
echo -e "- Removing ${sorted_folders[$i]}"
rm -rf "${sorted_folders[$i]}"
fi
done
echo -e "\nDone!"