Apply black
This commit is contained in:
parent
8e77a9a676
commit
f5b5bc8743
1 changed files with 67 additions and 65 deletions
132
gogsmaker.py
132
gogsmaker.py
|
@ -33,24 +33,24 @@ class GitError(Exception):
|
||||||
|
|
||||||
|
|
||||||
def get_hook(url):
|
def get_hook(url):
|
||||||
''' Get the hook matching an URL, or raise UnmonitoredRepository '''
|
""" Get the hook matching an URL, or raise UnmonitoredRepository """
|
||||||
for hook in settings.HOOKS:
|
for hook in settings.HOOKS:
|
||||||
if hook['url'] == url:
|
if hook["url"] == url:
|
||||||
return hook
|
return hook
|
||||||
raise UnmonitoredRepository
|
raise UnmonitoredRepository
|
||||||
|
|
||||||
|
|
||||||
def repo_path(hook):
|
def repo_path(hook):
|
||||||
''' Get the path at which the hook's repo is cloned '''
|
""" Get the path at which the hook's repo is cloned """
|
||||||
return os.path.join(settings.CLONE_ROOT, hook['name'])
|
return os.path.join(settings.CLONE_ROOT, hook["name"])
|
||||||
|
|
||||||
|
|
||||||
def subprocess_run(command, **kwargs):
|
def subprocess_run(command, **kwargs):
|
||||||
''' Run subprocess with default arguments '''
|
""" Run subprocess with default arguments """
|
||||||
args = {
|
args = {
|
||||||
'check': True,
|
"check": True,
|
||||||
'stdout': subprocess.DEVNULL,
|
"stdout": subprocess.DEVNULL,
|
||||||
'stderr': subprocess.PIPE,
|
"stderr": subprocess.PIPE,
|
||||||
}
|
}
|
||||||
args.update(kwargs)
|
args.update(kwargs)
|
||||||
|
|
||||||
|
@ -58,64 +58,62 @@ def subprocess_run(command, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
class MakeWorker(Thread):
|
class MakeWorker(Thread):
|
||||||
''' A make job '''
|
""" A make job """
|
||||||
|
|
||||||
def __init__(self, hook):
|
def __init__(self, hook):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.hook = hook
|
self.hook = hook
|
||||||
self.name = 'makeworker-{}'.format(hook['name'])
|
self.name = "makeworker-{}".format(hook["name"])
|
||||||
self.path = repo_path(hook)
|
self.path = repo_path(hook)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
''' Run the make job '''
|
""" Run the make job """
|
||||||
try:
|
try:
|
||||||
subprocess_run(['make', '-C', self.path, '--']
|
subprocess_run(["make", "-C", self.path, "--"] + self.hook["targets"])
|
||||||
+ self.hook['targets'])
|
|
||||||
except subprocess.CalledProcessError as error:
|
except subprocess.CalledProcessError as error:
|
||||||
logging.error(
|
logging.error(
|
||||||
("Hook %s: make failed with status %s. "
|
("Hook %s: make failed with status %s. " "Error output:\n%s\n"),
|
||||||
"Error output:\n%s\n"),
|
self.hook["name"],
|
||||||
self.hook['name'],
|
|
||||||
error.returncode,
|
error.returncode,
|
||||||
error.stderr.decode('utf-8'))
|
error.stderr.decode("utf-8"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def update_repo(hook, clone_url):
|
def update_repo(hook, clone_url):
|
||||||
''' Update (or clone) the given repository. May raise GitError. '''
|
""" Update (or clone) the given repository. May raise GitError. """
|
||||||
path = repo_path(hook)
|
path = repo_path(hook)
|
||||||
if os.path.isdir(os.path.join(path, '.git')): # Repo is already cloned
|
if os.path.isdir(os.path.join(path, ".git")): # Repo is already cloned
|
||||||
try:
|
try:
|
||||||
subprocess_run(['git', '-C', path, 'reset', '--hard']
|
subprocess_run(["git", "-C", path, "reset", "--hard"]) # Just in case.
|
||||||
) # Just in case.
|
subprocess_run(["git", "-C", path, "pull"])
|
||||||
subprocess_run(['git', '-C', path, 'pull'])
|
|
||||||
except subprocess.CalledProcessError as error:
|
except subprocess.CalledProcessError as error:
|
||||||
logging.error(
|
logging.error(
|
||||||
("Hook %s: git failed with status %s. "
|
("Hook %s: git failed with status %s. " "Error output:\n%s\n"),
|
||||||
"Error output:\n%s\n"),
|
hook["name"],
|
||||||
hook['name'],
|
|
||||||
error.returncode,
|
error.returncode,
|
||||||
error.stderr.decode('utf-8'))
|
error.stderr.decode("utf-8"),
|
||||||
raise GitError("Cannot pull {}".format(hook['name']))
|
)
|
||||||
|
raise GitError("Cannot pull {}".format(hook["name"]))
|
||||||
|
|
||||||
else: # Repo is to be cloned
|
else: # Repo is to be cloned
|
||||||
try:
|
try:
|
||||||
subprocess_run(['mkdir', '-p', path])
|
subprocess_run(["mkdir", "-p", path])
|
||||||
subprocess_run(['git', 'clone', clone_url, path], check=True)
|
subprocess_run(["git", "clone", clone_url, path], check=True)
|
||||||
except subprocess.CalledProcessError as error:
|
except subprocess.CalledProcessError as error:
|
||||||
logging.error(
|
logging.error(
|
||||||
("Hook %s: git failed cloning with status %s. "
|
("Hook %s: git failed cloning with status %s. " "Error output:\n%s"),
|
||||||
"Error output:\n%s"),
|
hook["name"],
|
||||||
hook['name'],
|
|
||||||
error.returncode,
|
error.returncode,
|
||||||
error.stderr.decode('utf-8'))
|
error.stderr.decode("utf-8"),
|
||||||
|
)
|
||||||
raise GitError("Cannot clone {}".format(clone_url))
|
raise GitError("Cannot clone {}".format(clone_url))
|
||||||
|
|
||||||
|
|
||||||
def check_signature(received_sig, hook, payload):
|
def check_signature(received_sig, hook, payload):
|
||||||
''' Check Gogs signature '''
|
""" Check Gogs signature """
|
||||||
digest = hmac.new(hook['secret'].encode('utf-8'),
|
digest = hmac.new(
|
||||||
msg=payload,
|
hook["secret"].encode("utf-8"), msg=payload, digestmod=sha256
|
||||||
digestmod=sha256).hexdigest()
|
).hexdigest()
|
||||||
return hmac.compare_digest(digest, received_sig)
|
return hmac.compare_digest(digest, received_sig)
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,51 +123,53 @@ def gogs_payload(required):
|
||||||
def wrapped(*args, **kwargs):
|
def wrapped(*args, **kwargs):
|
||||||
payload = request.json
|
payload = request.json
|
||||||
if payload is None:
|
if payload is None:
|
||||||
return 'Expected json\n', 415
|
return "Expected json\n", 415
|
||||||
|
|
||||||
for field in required + ['repository/html_url']:
|
for field in required + ["repository/html_url"]:
|
||||||
path = field.split('/')
|
path = field.split("/")
|
||||||
explore = payload
|
explore = payload
|
||||||
for section in path:
|
for section in path:
|
||||||
if section not in explore:
|
if section not in explore:
|
||||||
return (
|
return (
|
||||||
'Invalid json: missing {}\n'.format(
|
"Invalid json: missing {}\n".format("/".join(path)),
|
||||||
'/'.join(path)),
|
400,
|
||||||
400)
|
)
|
||||||
explore = explore[section]
|
explore = explore[section]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hook = get_hook(payload['repository']['html_url'])
|
hook = get_hook(payload["repository"]["html_url"])
|
||||||
except UnmonitoredRepository:
|
except UnmonitoredRepository:
|
||||||
return 'Unmonitored repository\n', 403
|
return "Unmonitored repository\n", 403
|
||||||
|
|
||||||
if not settings.DEBUG:
|
if not settings.DEBUG:
|
||||||
received_sig = request.headers['X-Gogs-Signature']
|
received_sig = request.headers["X-Gogs-Signature"]
|
||||||
payload_raw = request.data
|
payload_raw = request.data
|
||||||
if not check_signature(received_sig, hook, payload_raw):
|
if not check_signature(received_sig, hook, payload_raw):
|
||||||
return 'Invaild signature\n', 403
|
return "Invaild signature\n", 403
|
||||||
|
|
||||||
return fct(payload, hook, *args, **kwargs)
|
return fct(payload, hook, *args, **kwargs)
|
||||||
|
|
||||||
return wrapped
|
return wrapped
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['POST'])
|
@app.route("/", methods=["POST"])
|
||||||
@gogs_payload(['repository/clone_url'])
|
@gogs_payload(["repository/clone_url"])
|
||||||
def view_root(payload, hook):
|
def view_root(payload, hook):
|
||||||
clone_url = payload['repository']['clone_url']
|
clone_url = payload["repository"]["clone_url"]
|
||||||
if 'clone_url' in hook:
|
if "clone_url" in hook:
|
||||||
clone_url = hook['clone_url']
|
clone_url = hook["clone_url"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
update_repo(hook, clone_url)
|
update_repo(hook, clone_url)
|
||||||
except GitError as error:
|
except GitError as error:
|
||||||
return 'Git error: {}\n'.format(error), 500
|
return "Git error: {}\n".format(error), 500
|
||||||
|
|
||||||
worker = MakeWorker(hook)
|
worker = MakeWorker(hook)
|
||||||
worker.start()
|
worker.start()
|
||||||
|
|
||||||
return 'OK\n', 200
|
return "OK\n", 200
|
||||||
|
|
||||||
|
|
||||||
@app.before_first_request # FIXME this should be run on startup...
|
@app.before_first_request # FIXME this should be run on startup...
|
||||||
|
@ -179,28 +179,30 @@ def startup_actions():
|
||||||
|
|
||||||
|
|
||||||
def setup_logger():
|
def setup_logger():
|
||||||
''' Setup the default logger '''
|
""" Setup the default logger """
|
||||||
coloredlogs.install(
|
coloredlogs.install(
|
||||||
fmt="%(asctime)s [%(levelname)s] %(message)s",
|
fmt="%(asctime)s [%(levelname)s] %(message)s",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def check_settings():
|
def check_settings():
|
||||||
''' Check the supplied settings '''
|
""" Check the supplied settings """
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
logging.warning('GogsMaker is running in DEBUG MODE, this is '
|
logging.warning(
|
||||||
'unsuitable for production environments!')
|
"GogsMaker is running in DEBUG MODE, this is "
|
||||||
|
"unsuitable for production environments!"
|
||||||
|
)
|
||||||
|
|
||||||
required_keys = ['name', 'url', 'targets', 'secret']
|
required_keys = ["name", "url", "targets", "secret"]
|
||||||
for hook_id, hook in enumerate(settings.HOOKS):
|
for hook_id, hook in enumerate(settings.HOOKS):
|
||||||
for key in required_keys:
|
for key in required_keys:
|
||||||
if key not in hook:
|
if key not in hook:
|
||||||
if key == 'name':
|
if key == "name":
|
||||||
descr = '#{}'.format(hook_id)
|
descr = "#{}".format(hook_id)
|
||||||
else:
|
else:
|
||||||
descr = '{} (#{})'.format(hook['name'], hook_id)
|
descr = "{} (#{})".format(hook["name"], hook_id)
|
||||||
|
|
||||||
logging.critical(('Configuration error: hook %s lacks '
|
logging.critical(
|
||||||
'attribute %s.'),
|
("Configuration error: hook %s lacks " "attribute %s."), descr, key
|
||||||
descr, key)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
Loading…
Reference in a new issue