From cf0336fe6f77a931a22619103314f79b07fb11e4 Mon Sep 17 00:00:00 2001 From: Scott Alfter Date: Thu, 7 Dec 2023 21:21:35 -0800 Subject: [PATCH] initial commit --- .gitignore | 1 + Dockerfile | 4 ++++ README.md | 39 +++++++++++++++++++++++++++++++++++++++ all_repos.py | 8 ++++++++ prep.sh | 11 +++++++++++ update.sh | 11 +++++++++++ 6 files changed, 74 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100755 all_repos.py create mode 100755 prep.sh create mode 100755 update.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2271f1a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM alpine +RUN apk add --no-cache git py3-pip bash openssh && pip install --break-system-packages python-gitlab +COPY all_repos.py update.sh prep.sh /root/ +ENTRYPOINT /root/prep.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2c2553 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +gitlab-repo-sync +================ + +I'm running my own GitLab instance at home, but I'm less than enthused about +the way GitLab handles backups. I'd previously used Duplicity to back up a +directory full of bare Git repos to cloud storage, with a monthly full backup +and daily incremental backups. This doesn't mesh too well with the way GitLab +does backups; as near as I can tell, the incremental backups end up being as +close to full backups as makes no difference. + +This package allows you to mirror your GitLab repos into a directory of bare +Git repos that can more easily be backed up. + +If you're running this on bare metal, you only need all_repos.py and +update.sh. You'll need to set a couple of environment variables: + +* ```URL```: the URL of your GitLab instance (might also work with gitlab.com, + but this is untested) +* ```APIKEY```: the API key for the GitLab account you want to sync + +You might also want to tweak the second line in update.sh to point to the +directory where you want the repos to be stored. + +Since my GitLab server and Duplicity backups are running on a container host, +I've also bundled this up so that you can easily use it there. In that case, +you can invoke it with something like this: + +```docker run -it --rm -v /home/salfter/git:/git -v /home/salfter/.ssh:/ssh -e URL=https://gitlab.alfter.us -e APIKEY=[REDACTED] -e UID=1000 -e GID=1000 salfter/gitlab-repo-sync``` + +Let's break down what's happening within: + +* ```-v /home/salfter/git:/git```: The directory where you want your repos to + go gets mapped to /git. +* ```-v /home/salfter/.ssh:/ssh```: The directory with the SSH key you use + with your GitLab server needs to be mapped to /ssh. +* ```-e URL=https://gitlab.alfter.us -e APIKEY=[REDACTED]```: These are set + as described above. +* ```-e UID=1000 -e GID=1000```: Set the user and group IDs to match the owner + of your bare-repo directory. diff --git a/all_repos.py b/all_repos.py new file mode 100755 index 0000000..975c3ab --- /dev/null +++ b/all_repos.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +import gitlab +import sys + +gl=gitlab.Gitlab(url=sys.argv[1], private_token=sys.argv[2]) +projects=gl.projects.list(get_all=True) +for p in projects: + print(p.ssh_url_to_repo) diff --git a/prep.sh b/prep.sh new file mode 100755 index 0000000..75fab95 --- /dev/null +++ b/prep.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +cd /root +addgroup -g $GID user +adduser -u $UID -G user -D -s /bin/bash user +cp -r /ssh ~user/.ssh +chown -R user:user ~user/.ssh +cp update.sh all_repos.py ~user/ +echo "export URL=\"$URL\"" >>~user/.bash_profile +echo "export APIKEY=\"$APIKEY\"" >>~user/.bash_profile +chown user:user ~user/.bash_profile +su -l user -c 'source ~/.bash_profile && ~user/update.sh' diff --git a/update.sh b/update.sh new file mode 100755 index 0000000..4426a63 --- /dev/null +++ b/update.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +cd /git +for i in $(~/all_repos.py "$URL" "$APIKEY") +do + if [ -e $(basename $i) ] + then + (cd $(basename $i) && git fetch --all) + else + git clone --bare $i + fi +done