|
| 1 | +#!/bin/bash |
| 2 | +# A simple script to backup an organization's GitHub repositories. |
| 3 | +# source: https://gist.github.com/darktim/5582423 |
| 4 | +# modified to fix a few issues and exceptions |
| 5 | + |
| 6 | +GHBU_BACKUP_DIR=${GHBU_BACKUP_DIR-"github-backups"} # where to place the backup files |
| 7 | +GHBU_ORG=${GHBU_ORG-"<CHANGE-ME>"} # the GitHub organization whose repos will be backed up |
| 8 | +GHBU_UNAME=${GHBU_UNAME-"<CHANGE-ME>"} # the username of a GitHub account (to use with the GitHub API) |
| 9 | +GHBU_PASSWD=${GHBU_PASSWD-"<CHANGE-ME>"} # the password for that account |
| 10 | +GHBU_GITHOST=${GHBU_GITHOST-"<CHANGE-ME>.github.com"} # the GitHub hostname (see notes) |
| 11 | +GHBU_PRUNE_OLD=${GHBU_PRUNE_OLD-true} # when `true`, old backups will be deleted |
| 12 | +GHBU_PRUNE_AFTER_N_DAYS=${GHBU_PRUNE_AFTER_N_DAYS-3} # the min age (in days) of backup files to delete |
| 13 | +GHBU_SILENT=${GHBU_SILENT-false} # when `true`, only show error messages |
| 14 | +GHBU_API=${GHBU_API-"https://api.github.com"} # base URI for the GitHub API |
| 15 | +GHBU_GIT_CLONE_CMD="git clone --quiet --mirror git@${GHBU_GITHOST}:" # base command to use to clone GitHub repos |
| 16 | + |
| 17 | +TSTAMP=$(date "+%Y%m%d-%H%M") |
| 18 | + |
| 19 | +# The function `check` will exit the script if the given command fails. |
| 20 | +function check { |
| 21 | + "$@" |
| 22 | + status=$? |
| 23 | + if [ $status -ne 0 ]; then |
| 24 | + echo "ERROR: Encountered error (${status}) while running the following:" >&2 |
| 25 | + echo " *" >&2 |
| 26 | + echo " (at line ${BASH_LINENO[0]} of file $0.)" >&2 |
| 27 | + echo " Aborting." >&2 |
| 28 | + exit $status |
| 29 | + fi |
| 30 | +} |
| 31 | + |
| 32 | +# The function `tgz` will create a gzipped tar archive of the specified file ($1) and then remove the original |
| 33 | +# the option -P omits the error message tar: Removing leading '/' from member names |
| 34 | +function tgz { |
| 35 | + check tar zcPf "$1".tar.gz "$1" && check rm -rf "$1" |
| 36 | +} |
| 37 | + |
| 38 | +$GHBU_SILENT || (echo "" && echo "=== INITIALIZING ===" && echo "") |
| 39 | + |
| 40 | +$GHBU_SILENT || echo "Using backup directory $GHBU_BACKUP_DIR" |
| 41 | +check mkdir -p "$GHBU_BACKUP_DIR" |
| 42 | + |
| 43 | +$GHBU_SILENT || echo "Fetching list of repositories for ${GHBU_ORG}..." |
| 44 | +# cycling through pages as github API limits entries to 30/100 per page... |
| 45 | +PAGE=0 |
| 46 | +while true; do |
| 47 | + let PAGE++ |
| 48 | + $GHBU_SILENT || echo "getting page ${PAGE}" |
| 49 | + REPOLIST_TMP=$(check curl --silent -u "$GHBU_UNAME":"$GHBU_PASSWD" "${GHBU_API}"/orgs/"${GHBU_ORG}"/repos\?page="${PAGE}"\&per_page=90 -q -k | grep "\"full_name\"" | cut -d'/' -f2 | sed -e 's/",//g') |
| 50 | + if [ -z "${REPOLIST_TMP}" ]; then break; fi |
| 51 | + REPOLIST="${REPOLIST} ${REPOLIST_TMP}" |
| 52 | +done |
| 53 | + |
| 54 | + |
| 55 | +$GHBU_SILENT || echo "found $(echo "$REPOLIST" | wc -w) repositories." |
| 56 | + |
| 57 | + |
| 58 | +$GHBU_SILENT || (echo "" && echo "=== BACKING UP ===" && echo "") |
| 59 | + |
| 60 | +for REPO in $REPOLIST; do |
| 61 | + $GHBU_SILENT || echo "Backing up ${GHBU_ORG}/${REPO}" |
| 62 | + check "${GHBU_GIT_CLONE_CMD}""${GHBU_ORG}"/"${REPO}".git "${GHBU_BACKUP_DIR}"/"${GHBU_ORG}"-"${REPO}"-"${TSTAMP}".git && tgz "${GHBU_BACKUP_DIR}"/"${GHBU_ORG}"-"${REPO}"-"${TSTAMP}".git |
| 63 | + |
| 64 | + $GHBU_SILENT || echo "Backing up ${GHBU_ORG}/${REPO}.wiki (if any)" |
| 65 | + "${GHBU_GIT_CLONE_CMD}""${GHBU_ORG}"/"${REPO}".wiki.git "${GHBU_BACKUP_DIR}"/"${GHBU_ORG}"-"${REPO}".wiki-"${TSTAMP}".git 2>/dev/null && tgz "${GHBU_BACKUP_DIR}"/"${GHBU_ORG}"-"${REPO}".wiki-"${TSTAMP}".git |
| 66 | + |
| 67 | + $GHBU_SILENT || echo "Backing up ${GHBU_ORG}/${REPO} issues" |
| 68 | + check curl --silent -u "$GHBU_UNAME":"$GHBU_PASSWD" "${GHBU_API}"/repos/"${GHBU_ORG}"/"${REPO}"/issues -q > "${GHBU_BACKUP_DIR}"/"${GHBU_ORG}"-"${REPO}".issues-"${TSTAMP}" && tgz "${GHBU_BACKUP_DIR}"/"${GHBU_ORG}"-"${REPO}".issues-"${TSTAMP}" |
| 69 | +done |
| 70 | + |
| 71 | +if $GHBU_PRUNE_OLD; then |
| 72 | + $GHBU_SILENT || (echo "" && echo "=== PRUNING ===" && echo "") |
| 73 | + $GHBU_SILENT || echo "Pruning backup files ${GHBU_PRUNE_AFTER_N_DAYS} days old or older." |
| 74 | + $GHBU_SILENT || echo "Found $(find "$GHBU_BACKUP_DIR" -name '*.tar.gz' -mtime +"$GHBU_PRUNE_AFTER_N_DAYS" | wc -l) files to prune." |
| 75 | + find "$GHBU_BACKUP_DIR" -name '*.tar.gz' -mtime +"$GHBU_PRUNE_AFTER_N_DAYS" -exec rm -fv {} > /dev/null \; |
| 76 | +fi |
| 77 | + |
| 78 | +$GHBU_SILENT || (echo "" && echo "=== DONE ===" && echo "") |
| 79 | +$GHBU_SILENT || (echo "GitHub backup completed." && echo "") |
| 80 | +ACT SAVE READ SHARE FOLLOW |
0 commit comments