aboutsummaryrefslogtreecommitdiff
path: root/github_sync.sh
blob: 61bdd459241b594f96619395011ffd86f1092ece (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/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)
#	LIMIT		Limit syncing to repos specified in LIMIT_TO (true/false)
#	LIMIT_TO	Array of repos to limit syncing to

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) ) )

if [ "$LIMIT" = "true" -a "${#LIMIT_TO[@]}" -gt 0 ]; then
	TO_CLONE=( $(comm -12 <(printf "%s\n" "${LIMIT_TO[@]}" | sort) \
		<(printf "%s\n" "${TO_CLONE[@]}" | sort) ) )

	TO_CREATE=( $(comm -12 <(printf "%s\n" "${LIMIT_TO[@]}" | sort) \
		<(printf "%s\n" "${TO_CREATE[@]}" | sort) ) )

	TO_PUSH=( $(comm -12 <(printf "%s\n" "${LIMIT_TO[@]}" | sort) \
		<(printf "%s\n" "${TO_PUSH[@]}" | sort) ) )
fi

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
	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

	TO_PUSH+=($repo)
done

for repo in "${TO_PUSH[@]}"; do
	git -C "$REPO_DIR/$repo" push --all "${GH_REPOS[$repo]}"
	git -C "$REPO_DIR/$repo" push --tags "${GH_REPOS[$repo]}"
done

echo
echo Done.