From b48caf6cb4165c2fb60918494a7a4536aca796b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Maru=C5=A1in?= Date: Wed, 18 Sep 2019 17:23:19 +0200 Subject: [PATCH] saving installation_id from initial installation webhook into Redis --- Makefile | 2 +- release_bot/celery_task.py | 82 ++++++++++++++++++++++++++++++++---- release_bot/configuration.py | 11 ++--- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 10763ac..afb02c9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: test -IMAGE_NAME := marusinm/release-bot +IMAGE_NAME := usercont/release-bot IMAGE_NAME_DEV := usercont/release-bot:dev TEST_IMAGE_NAME := release-bot-tests diff --git a/release_bot/celery_task.py b/release_bot/celery_task.py index 6c26690..a502252 100644 --- a/release_bot/celery_task.py +++ b/release_bot/celery_task.py @@ -15,6 +15,7 @@ from pathlib import Path from os import getenv +import redis from release_bot.celerizer import celery_app from release_bot.exceptions import ReleaseException @@ -30,16 +31,36 @@ def parse_web_hook_payload(webhook_payload): Parse json webhook payload callback :param webhook_payload: json from github webhook """ + db = get_redis_instance() if 'issue' in webhook_payload.keys(): if webhook_payload['action'] == 'opened': - handle_issue(webhook_payload) + handle_issue(webhook_payload, db) elif 'pull_request' in webhook_payload.keys(): if webhook_payload['action'] == 'closed': if webhook_payload['pull_request']['merged'] is True: - handle_pr(webhook_payload) + handle_pr(webhook_payload, db) + elif 'installation' in webhook_payload.keys(): + if webhook_payload['action'] == 'added': # detect new repo installation + installation_id = webhook_payload['installation']['id'] + repositories_added = webhook_payload['repositories_added'] + save_new_installations(installation_id, repositories_added, db) + if webhook_payload['action'] == 'removed': # detect when repo uninstall app + repositories_removed = webhook_payload['repositories_removed'] + delete_installations(repositories_removed, db) -def set_configuration(webhook_payload, issue=True): + +def get_redis_instance(): + db = redis.Redis( + host=getenv("REDIS_SERVICE_HOST", "localhost"), + port=getenv("REDIS_SERVICE_PORT", "6379"), + db=1, # 0 is used by Celery + decode_responses=True, + ) + return db + + +def set_configuration(webhook_payload, db, issue=True): """ Prepare configuration from parsed web hook payload and return ReleaseBot instance with logger :param webhook_payload: payload from web hook @@ -56,6 +77,10 @@ def set_configuration(webhook_payload, issue=True): configuration.github_username = webhook_payload['issue']['user']['login'] else: configuration.github_username = webhook_payload['pull_request']['user']['login'] + + repo_installation_id = db.get(webhook_payload['repository']['full_name']) + configuration.github_app_installation_id = repo_installation_id + configuration.load_configuration() # load the rest of configuration if there is any # create url for github app to enable access over http @@ -66,9 +91,14 @@ def set_configuration(webhook_payload, issue=True): return ReleaseBot(configuration), configuration.logger -def handle_issue(webhook_payload): - """Handler for newly opened issues""" - release_bot, logger = set_configuration(webhook_payload, issue=True) +def handle_issue(webhook_payload, db): + """ + Handler for newly opened issues + :param webhook_payload: json data from webhook + :param db: Redis instance + :return: + """ + release_bot, logger = set_configuration(webhook_payload, db=db, issue=True) logger.info("Resolving opened issue") release_bot.git.pull() @@ -85,9 +115,14 @@ def handle_issue(webhook_payload): logger.error(exc) -def handle_pr(webhook_payload): - """Handler for merged PR""" - release_bot, logger = set_configuration(webhook_payload, issue=False) +def handle_pr(webhook_payload, db): + """ + Handler for merged PR + :param webhook_payload: json data from webhook + :param db: Redis instance + :return: + """ + release_bot, logger = set_configuration(webhook_payload, db=db, issue=False) logger.info("Resolving opened PR") release_bot.git.pull() @@ -105,3 +140,32 @@ def handle_pr(webhook_payload): msg = ''.join(release_bot.github.comment) release_bot.project.pr_comment(release_bot.new_release.pr_number, msg) release_bot.github.comment = [] # clean up + + +def save_new_installations(installation_id, repositories_added, db): + """ + Save repo which installed release-bot github app with it installation id + :param installation_id: installation identifier from initial installation web hook + :param repositories_added: repositories which user choose for release-bot installation + :param db: Redis instance + :return: True if data was saved successfully into Redis + """ + with db.pipeline() as pipe: + for repo in repositories_added: + pipe.set(repo["full_name"], installation_id) + pipe.execute() + return db.save() + + +def delete_installations(repositories_removed, db): + """ + Delete repo from Redis when user uninstall release-bot app from such repo + :param repositories_removed: repositories which user choose to uninstall from the release-bot + :param db: Redis instance + :return: True if data was deleted successfully into Redis + """ + with db.pipeline() as pipe: + for repo in repositories_removed: + pipe.delete(repo["full_name"]) + pipe.execute() + return db.save() diff --git a/release_bot/configuration.py b/release_bot/configuration.py index e400f4a..e7eba2f 100644 --- a/release_bot/configuration.py +++ b/release_bot/configuration.py @@ -200,11 +200,12 @@ def get_project(self): if self.github_app_id: github_cert = Path(self.github_app_cert_path).read_text() - # github token will be used as a credential over http (commit/push) - github_app = GitHubApp(self.github_app_id, self.github_app_cert_path) - self.github_token = github_app.get_installation_access_token( - self.github_app_installation_id - ) + if self.github_app_installation_id: + # github token will be used as a credential over http (commit/push) + github_app = GitHubApp(self.github_app_id, self.github_app_cert_path) + self.github_token = github_app.get_installation_access_token( + self.github_app_installation_id + ) return get_project(url=self.clone_url, custom_instances=[