aboutsummaryrefslogtreecommitdiff
path: root/github_sync.sh
diff options
context:
space:
mode:
Diffstat (limited to 'github_sync.sh')
-rwxr-xr-xgithub_sync.sh132
1 files changed, 132 insertions, 0 deletions
diff --git a/github_sync.sh b/github_sync.sh
new file mode 100755
index 0000000..1426aa5
--- /dev/null
+++ b/github_sync.sh
@@ -0,0 +1,132 @@
+#!/bin/bash
+
+# reposync.sh
+# Syncs a folder to GitHub
+
+# required setup:
+# - different user for script (no specific name needed) and git access (git)
+#
+# Usage:
+# reposync.sh <CONFIG FILE>
+#
+# Config file:
+# Sourcable bash script setting the variables:
+# USERNAME GitHub Username
+# TOKEN Password or Token
+# REPO_DIR Directory on the filesystem
+# PRIVATE Treat repositories as private (true/false)
+
+ARGV=($@)
+ARGC=${#ARGV[@]}
+
+API_BASE="https://api.github.com"
+
+# ['name']='ssh_url' # name with .git suffix
+declare -A GH_REPOS
+
+function url_inject_credentials() {
+ sed -n -e "s/^\(https:\/\/\)\(.*\)$/\1$USERNAME:$TOKEN@\2/p"
+}
+
+function curl_wrapper() {
+ local CURL_RETURN
+ CURL_RETURN=$( curl -s -w "%{http_code}" $@ ; exit $? )
+ local RET=$?
+ [ $RET -ne 0 ] && >&2 echo cURL code $RET && return 1
+
+ head -n -1 <<< "$CURL_RETURN"
+
+ local HTTP_CODE=$(tail -n 1 <<< "$CURL_RETURN")
+ [ $HTTP_CODE -ge 300 ] && >&2 echo HTTP Code $HTTP_CODE && return 1
+
+ return 0
+}
+
+# create new repository for $USERNAME
+# 1: name
+function github_create_repo() {
+ [ -z "$TOKEN" ] && >&2 echo TOKEN not set. No write access. && exit 1
+
+ local JSON_RETURN
+ JSON_RETURN=$(curl_wrapper -X POST -H "Content-Type: application/json" -u $USERNAME:$TOKEN \
+ -d "{\"name\":\"$1\",\"private\":$PRIVATE}" "$API_BASE/user/repos"; exit $? )
+ [ $? -ne 0 ] && exit 1
+
+ echo "$JSON_RETURN"
+
+ GH_REPOS[$1.git]=$(jq -r ".clone_url" <<< "$JSON_RETURN" | url_inject_credentials )
+}
+
+function github_update_repo_list() {
+ GH_REPOS=()
+
+ local CURL_USER=""
+ [ ! -z "$TOKEN" ] && CURL_USER="-u $USERNAME:$TOKEN"
+
+ local VISIBILITY=""
+ [ "$PRIVATE" = "true" ] && VISIBILITY="private" || VISIBILITY="public"
+
+ local JSON_REPOS
+ JSON_REPOS=$(curl_wrapper -u $USERNAME:$TOKEN \
+ "$API_BASE/user/repos?visibility=$VISIBILITY"; exit $?)
+ [ $? -ne 0 ] && jq ".message" <<< "$JSON_REPOS" && exit 1
+
+ GH_REPOS_COUNT=$(jq ". | length" <<< "$JSON_REPOS")
+
+ for (( i=0; i<$GH_REPOS_COUNT; i++ )); do
+ name="$(jq -r ".[$i].name" <<< "$JSON_REPOS" ).git"
+ GH_REPOS[$name]=$(jq -r ".[$i].clone_url" <<< "$JSON_REPOS" | url_inject_credentials )
+ done
+}
+
+[ ! -f "$1" ] && echo Config file not found && exit 1
+
+source "$1"
+
+[ -z "$USERNAME" -o -z "$TOKEN" ] && echo GitHub credentials config error. && exit 1
+
+[ ! -d "$REPO_DIR" ] && echo Repo directory does not exist. && exit 1
+
+[ "$PRIVATE" != "true" ] && PRIVATE=false
+
+github_update_repo_list
+
+LOCAL_REPOS=( $(for repo in $(ls -d $REPO_DIR/*.git/ 2> /dev/null); do basename $repo; done ) )
+
+TO_CLONE=( $(comm -23 <(printf "%s\n" "${!GH_REPOS[@]}" | sort) \
+ <(printf "%s\n" "${LOCAL_REPOS[@]}" | sort) ) )
+TO_CREATE=( $(comm -13 <(printf "%s\n" "${!GH_REPOS[@]}" | sort) \
+ <(printf "%s\n" "${LOCAL_REPOS[@]}" | sort) ) )
+TO_PUSH=( $(comm -12 <(printf "%s\n" "${!GH_REPOS[@]}" | sort) \
+ <(printf "%s\n" "${LOCAL_REPOS[@]}" | sort) ) )
+
+echo TO CLONE
+printf "%s\n" "${TO_CLONE[@]}"
+echo
+echo TO CREATE
+printf "%s\n" "${TO_CREATE[@]}"
+echo
+echo TO PUSH
+printf "%s\n" "${TO_PUSH[@]}"
+
+echo
+
+for repo in "${TO_CLONE[@]}"; do
+ sudo -u git git clone --bare \
+ "${GH_REPOS[$repo]}" "$REPO_DIR/$repo"
+done
+
+for repo in "${TO_CREATE[@]}"; do
+ github_create_repo ${repo%.git}
+
+ [ -z "${GH_REPOS[$repo]}" ] && echo No clone_URL? && continue
+
+ git -C "$REPO_DIR/$repo" push "${GH_REPOS[$repo]}"
+done
+
+for repo in "${TO_PUSH[@]}"; do
+ git -C "$REPO_DIR/$repo" push "${GH_REPOS[$repo]}"
+done
+
+echo
+echo Done.