git-backup.py (5383B) - raw


      1 #!/usr/bin/env python3
      2 # Copyright (C) 2019 Oscar Benedito
      3 #
      4 # This program is free software: you can redistribute it and/or modify
      5 # it under the terms of the GNU Affero General Public License as
      6 # published by the Free Software Foundation, either version 3 of the
      7 # License, or (at your option) any later version.
      8 #
      9 # This program is distributed in the hope that it will be useful,
     10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 # GNU Affero General Public License for more details.
     13 #
     14 # You should have received a copy of the GNU Affero General Public License
     15 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
     16 
     17 import datetime
     18 import json
     19 import os
     20 import sys
     21 import git
     22 import requests
     23 
     24 
     25 ENV_GITLAB_TOKEN = "GITLAB_TOKEN"
     26 ENV_GITHUB_TOKEN = "GITHUB_TOKEN"
     27 ENV_CUSTOM_REPOSITORIES_PATH = "CUSTOM_REPOSITORIES_PATH"
     28 ENV_TARGET_DIR = "TARGET_DIR"
     29 
     30 
     31 def backup_gitlab(token):
     32     def get_repositories_data_gitlab(url, page):
     33         response = requests.get(url + "&page=" + str(page))
     34         return response.json()
     35 
     36     url = "https://gitlab.com/api/v4/projects?private_token=" + token + "&per_page=100&membership=true"
     37     page = 1
     38     repositories = get_repositories_data_gitlab(url, page)
     39 
     40     backup_data["sites"]["gitlab.com"] = []
     41     while len(repositories) != 0:
     42         for repository in repositories:
     43             clone_dir = "repositories/gitlab.com/" + repository["path_with_namespace"]
     44             print("gitlab.com/" + repository["path_with_namespace"])
     45             if os.path.isdir(clone_dir):
     46                 git.cmd.Git(clone_dir).fetch()
     47             else:
     48                 os.system("git clone --mirror " + repository["ssh_url_to_repo"] + " " + clone_dir)
     49             backup_data["sites"]["gitlab.com"].append(
     50                 {
     51                     "name": repository["name"],
     52                     "description": repository["description"],
     53                     "path": repository["path_with_namespace"],
     54                     "clone_url": repository["ssh_url_to_repo"],
     55                 }
     56             )
     57         page += 1
     58         repositories = get_repositories_data_gitlab(url, page)
     59 
     60 
     61 def backup_github(token):
     62     def get_repositories_data_github(url, token, page):
     63         headers = {"Authorization": "token " + token}
     64         response = requests.get(url + "?page=" + str(page), headers=headers)
     65         return response.json()
     66 
     67     url = "https://api.github.com/user/repos"
     68     page = 1
     69     repositories = get_repositories_data_github(url, token, page)
     70 
     71     backup_data["sites"]["github.com"] = []
     72     while len(repositories) != 0:
     73         for repository in repositories:
     74             clone_dir = "repositories/github.com/" + repository["full_name"]
     75             print("github.com/" + repository["full_name"])
     76             if os.path.isdir(clone_dir):
     77                 git.cmd.Git(clone_dir).fetch()
     78             else:
     79                 os.system("git clone --mirror " + repository["ssh_url"] + " " + clone_dir)
     80             backup_data["sites"]["github.com"].append(
     81                 {
     82                     "name": repository["name"],
     83                     "description": repository["description"],
     84                     "path": repository["full_name"],
     85                     "clone_url": repository["ssh_url"],
     86                 }
     87             )
     88         page += 1
     89         repositories = get_repositories_data_github(url, token, page)
     90 
     91 
     92 def backup_custom_repositories(repositories):
     93     for repository in repositories:
     94         clone_dir = "repositories/" + repository["host"] + "/" + repository["path"]
     95         print(repository["host"] + "/" + repository["path"])
     96         if os.path.isdir(clone_dir):
     97             git.cmd.Git(clone_dir).fetch()
     98         else:
     99             os.system("git clone --mirror " + repository["clone_url"] + " " + clone_dir)
    100         if repository["host"] not in backup_data["sites"]:
    101             backup_data["sites"][repository["host"]] = []
    102         backup_data["sites"][repository["host"]].append(
    103             {
    104                 "name": repository["name"],
    105                 "description": repository["description"],
    106                 "path": repository["path"],
    107                 "clone_url": repository["clone_url"],
    108             }
    109         )
    110 
    111 
    112 def main():
    113     try:
    114         os.makedirs(os.environ.get(ENV_TARGET_DIR), exist_ok=True)
    115         os.chdir(os.environ.get(ENV_TARGET_DIR))
    116     except Exception as e:
    117         print(f"Failed to create directory due to error: {e}", file=sys.stderr)
    118         return
    119 
    120     backup_data["time"] = str(datetime.datetime.now())
    121     backup_data["sites"] = {}
    122 
    123     token = os.environ.get(ENV_GITLAB_TOKEN)
    124     if token:
    125         backup_gitlab(token)
    126 
    127     token = os.environ.get(ENV_GITHUB_TOKEN)
    128     if token:
    129         backup_github(token)
    130 
    131     custom_repositories_path = os.environ.get(ENV_CUSTOM_REPOSITORIES_PATH)
    132     if custom_repositories_path:
    133         try:
    134             with open(custom_repositories_path, "r") as f:
    135                 repositories = json.load(f)
    136             backup_custom_repositories(repositories)
    137         except FileNotFoundError:
    138             print("Error: File " + custom_repositories_path + " not found", file=sys.stderr)
    139 
    140     with open("backup_data.json", "w", encoding="utf-8") as output_file:
    141         json.dump(backup_data, output_file, ensure_ascii=False)
    142         output_file.close()
    143 
    144 
    145 backup_data = {}
    146 main()