Merge pull request #3 from damien-list/master
[git-mirror.git] / github-add-hooks.py
1 #!/usr/bin/python3
2 import random, string, argparse, os.path, subprocess, shutil
3 import requests, json
4 from git_mirror import *
5
6 def random_string(length):
7     alphabet = string.digits + string.ascii_letters
8     r = random.SystemRandom()
9     result = ""
10     for i in range(length):
11         result += r.choice(alphabet)
12     return result
13
14 def generate_ssh_key(name, bits):
15     subprocess.check_call(["ssh-keygen", "-f", name, "-C", name, "-b", str(bits), "-q", "-N", ""])
16
17 def add_deploy_key(key_name, repo_owner, repo_name, access_token):
18     url = "https://api.github.com/repos/{owner}/{repo}/keys".format(owner=repo_owner, repo=repo_name)
19     data = { 'title': os.path.basename(key_name), 'key': open(key_name+".pub").read() }
20     r = requests.post(url, data=json.dumps(data), headers = {"Authorization": "token {token}".format(token=access_token)})
21     if r.status_code >= 300:
22         raise Exception(str(json.loads(r.content.decode('utf-8'))))
23     
24 def add_web_hook(webhook_url, hmac_secret, repo_owner, repo_name, access_token):
25     url = 'https://api.github.com/repos/{owner}/{repo}/hooks'.format(owner=repo_owner, repo=repo_name)
26     data = {
27         'name': "web",
28         'active': True,
29         'events': ['push'],
30         'config': {
31             'url': webhook_url,
32             'content_type': "json",
33             'secret': hmac_secret,
34         }
35     }
36     r = requests.post(url, data=json.dumps(data), headers = {"Authorization": "token {token}".format(token=access_token)})
37     if r.status_code >= 300:
38         raise Exception(str(json.loads(r.content.decode('utf-8'))))
39
40 # get config and user arguments
41 conf = read_config()
42 parser = argparse.ArgumentParser(description='Update and build a bunch of stuff')
43 parser.add_argument("-o", "--owner",
44                     dest="owner",
45                     help="The username of the owner of this hook on GitHub")
46 parser.add_argument("-e", "--email",
47                     dest="email",
48                     help="An email address that gets notified in case of trouble with the hook")
49 parser.add_argument("-l", "--local",
50                     dest="local",
51                     help="The local directory of the repository")
52 parser.add_argument("-n", "--name",
53                     dest="name", default=None,
54                     help="The name of the repository on GitHub (defaults to the basename of the local directory)")
55 args = parser.parse_args()
56 args.local = os.path.abspath(args.local)
57 assert os.path.isdir(args.local), "Local repository has to be a directory"
58 if args.name is None:
59     args.name = os.path.basename(args.local)
60     if args.name.endswith(".git"):
61         args.name = args.name[:-4]
62 hmac_secret = random_string(64)
63 ssh_deploy_key = os.path.join(os.path.expanduser('~/.ssh'), args.name+"-github")
64 github_token = conf['DEFAULT']['github-token']
65 webhook_url = conf['DEFAULT']['webhook-url']
66
67 # append to the configuration (after making a backup)
68 shutil.copy(config_file, config_file+".bak")
69 with open(config_file, 'a') as f:
70     f.write('\n[{}]\n'.format(args.name))
71     f.write('owner={}\n'.format(args.email))
72     f.write('local={}\n'.format(args.local))
73     f.write('deploy-key={}\n'.format(os.path.basename(ssh_deploy_key)))
74     f.write('hmac-secret={}\n'.format(hmac_secret))
75     f.write('mirror-github=git@github.com:{}/{}.git\n'.format(args.owner, args.name))
76
77 try:
78     generate_ssh_key(ssh_deploy_key, 4*1024)
79     add_deploy_key(ssh_deploy_key, args.owner, args.name, github_token)
80     add_web_hook(webhook_url+"?repository="+args.name, hmac_secret, args.owner, args.name, github_token)
81     print("Done! Your GitHub repository is set up.\nRemember to configure the git-mirror hook for the local repository {}, e.g. in your gitolite configuration!".format(args.local))
82 except Exception as E:
83     shutil.copy(config_file+".bak", config_file)
84     raise
85