diff options
-rw-r--r-- | labbot/__main__.py | 11 | ||||
-rw-r--r-- | labbot/addons/approve-merge.py | 12 | ||||
-rw-r--r-- | labbot/addons/merge-label.py | 54 | ||||
-rw-r--r-- | labbot/addons/merge-stable.py | 26 | ||||
-rw-r--r-- | labbot/bot.py | 7 | ||||
-rw-r--r-- | labbot/config.py | 87 |
6 files changed, 157 insertions, 40 deletions
diff --git a/labbot/__main__.py b/labbot/__main__.py index fdd2537..39d8842 100644 --- a/labbot/__main__.py +++ b/labbot/__main__.py @@ -3,6 +3,7 @@ import logging from typing import List from importlib import import_module import json +import shutil import labbot.bot import labbot.config @@ -98,5 +99,15 @@ def list_instances(): for ins in labbot.config.list_instances(): print(f"- {ins}") +@main.command(name="remove", help="Remove an instance") +@click.argument('name') +@click.option('--yes', is_flag=True, expose_value=False, + prompt='Are you sure you want to remove the instance?') +def remove_instance(name): + try: + shutil.rmtree(labbot.config.instance_config_dir(name)) + except FileNotFoundError: + print("Instance not found") + if __name__ == "__main__": main()
\ No newline at end of file diff --git a/labbot/addons/approve-merge.py b/labbot/addons/approve-merge.py index 9b10ef6..9c6eceb 100644 --- a/labbot/addons/approve-merge.py +++ b/labbot/addons/approve-merge.py @@ -4,10 +4,16 @@ is reached. """ import logging +from labbot.config import Config + log = logging.getLogger(__name__) -required_approval_count = 2 +config = Config(__name__) +config.set_global_data( + required_approval_count = 2 +) +@config.config_decorator() async def merge_label_hook(event, gl, *args, **kwargs): title = event.object_attributes["title"] state = event.object_attributes["state"] @@ -24,12 +30,12 @@ async def merge_label_hook(event, gl, *args, **kwargs): approval_count = len(data["approved_by"]) - if approval_count >= required_approval_count: + if approval_count >= config["required_approval_count"]: if merge_status == "can_be_merged": await gl.put(merge_url) else: log.debug(f"Cannot merge !{iid} because of its merge_status `{merge_status}`") def setup(bot): + config.setup(__name__, bot.name) bot.register_merge_hook(merge_label_hook) - pass
\ No newline at end of file diff --git a/labbot/addons/merge-label.py b/labbot/addons/merge-label.py index a978388..746e236 100644 --- a/labbot/addons/merge-label.py +++ b/labbot/addons/merge-label.py @@ -7,29 +7,34 @@ import os import re import logging -log = logging.getLogger(__name__) - - -title_regex = r"^(?:#|)(\d+)\s*" -word_regex = r"^#(\d+)$" -relation_keywords = [ - "related" -] -relation_distance = 2 +from labbot.config import Config -state_label = { - "closed": "In Progress", - "opened": "Code-Review", - "merged": "C-R Bestanden", -} - -# Extra labels that the bot will check for before acting -act_labels = [ - "Sprint", - "Testing", - "TestingFailed", -] +log = logging.getLogger(__name__) +config = Config(__name__) +config.set_global_data( + title_regex = r"^(?:#|)(\d+)\s*", + word_regex = r"^#(\d+)$", + + relation_keywords = [ + "related" + ], + relation_distance = 2, + + state_label = { + "closed": "In Progress", + "opened": "Code-Review", + "merged": "C-R Bestanden", + }, + + act_labels = [ + "Sprint", + "Testing", + "TestingFailed", + ] +) + +@config.config_decorator() async def merge_label_hook(event, gl, *args, **kwargs): title = event.object_attributes["title"] description = event.object_attributes["description"] @@ -75,7 +80,7 @@ async def merge_label_hook(event, gl, *args, **kwargs): has_label = False issue_data = await gl.getitem(base_url) for label in issue_data["labels"]: - if label in act_labels or label in state_label.values(): + if label in act_labels or label in config["state_label"].values(): has_label = True break @@ -83,10 +88,10 @@ async def merge_label_hook(event, gl, *args, **kwargs): log.debug(f"Issue #{issue} does not have a relevant label") continue - delete_labels = act_labels + list(state_label.values()) + delete_labels = act_labels + list(config["state_label"].values()) try: - label = state_label[state] + label = config["state_label"][state] if label in delete_labels: delete_labels.remove(label) @@ -103,4 +108,5 @@ async def merge_label_hook(event, gl, *args, **kwargs): log.exception("Unknown state") def setup(bot) -> None: + config.setup(__name__, bot.name) bot.register_merge_hook(merge_label_hook) diff --git a/labbot/addons/merge-stable.py b/labbot/addons/merge-stable.py index d395160..f8e0ced 100644 --- a/labbot/addons/merge-stable.py +++ b/labbot/addons/merge-stable.py @@ -6,13 +6,18 @@ branch relation is figured out by looking at related merge requests import logging -log = logging.getLogger(__name__) +from labbot.config import Config +log = logging.getLogger(__name__) -stable_branch = "main" -staging_branch = "staging" -merge_label = "Release" +config = Config() +config.set_global_data( + stable_branch = "main", + staging_branch = "staging", + merge_label = "Release", +) +@config.config_decorator() async def issue_update_hook(event, gl, *args, **kwargs): issue_id = event.object_attributes["iid"] issue_url = f"/projects/{event.project_id}/issues/{issue_id}" @@ -20,14 +25,14 @@ async def issue_update_hook(event, gl, *args, **kwargs): branches = {} - if merge_label in issue_data["labels"]: + if config["merge_label"] in issue_data["labels"]: async for merge_data in gl.getiter(f"{issue_url}/related_merge_requests"): source_branch = merge_data["source_branch"] target_branch = merge_data["target_branch"] merge_id = merge_data["iid"] # we only want staging merges - if target_branch != staging_branch: + if target_branch != config["staging_branch"]: continue if not source_branch in branches: @@ -44,7 +49,7 @@ async def issue_update_hook(event, gl, *args, **kwargs): async for merge_data in gl.getiter(merge_url, params={ "source_branch": branch, - "target_branch": stable_branch + "target_branch": config["stable_branch"] }): if merge_data["state"] == "opened": merge_exists = True @@ -55,11 +60,12 @@ async def issue_update_hook(event, gl, *args, **kwargs): merge_string = ", ".join(merge) await gl.post(merge_url, data={ "source_branch": branch, - "target_branch": stable_branch, - "title": f"[stable] Merge `{branch}` into `{stable_branch}`", + "target_branch": config["stable_branch"], + "title": f"[stable] Merge `{branch}` into `{config['stable_branch']}`", "description": f"Related to #{issue_id} \n \nStaging Merges: \n{merge_string}" }) def setup(bot) -> None: - bot.register_issue_hook(issue_update_hook)
\ No newline at end of file + config.setup(__name__, bot.name) + bot.register_issue_hook(issue_update_hook) diff --git a/labbot/bot.py b/labbot/bot.py index 6781196..ef13978 100644 --- a/labbot/bot.py +++ b/labbot/bot.py @@ -79,6 +79,7 @@ class Bot: self.register(func, "Deployment Hook", *args, **kwargs) - def run(self, *args, **kwargs) -> None: - log.info(f"Started {self.name}") - self.instance.run(*args, print=False, **kwargs)
\ No newline at end of file + def run(self, **kwargs) -> None: + kwargs["print"] = False + log.info(f"Started {self.name} under :{kwargs['port']}") + self.instance.run(**kwargs) diff --git a/labbot/config.py b/labbot/config.py index f3da425..07c4d48 100644 --- a/labbot/config.py +++ b/labbot/config.py @@ -2,9 +2,96 @@ import os import json from typing import List, Dict, Any from appdirs import user_config_dir # type: ignore +from functools import wraps CONFIG_FILE = "config.json" +class Config: + def __init__(self, conf_name=None, name=None): + self.conf_name = conf_name + self.name = name + + self.settings = { + "GLOBAL": {}, + "GROUP": {}, + "PROJECT": {}, + } + self.group_id = None + self.project_id = None + + if self.conf_name and self.name: + self.setup(self.conf_name, self.name) + + def setup(self, conf_name, name): + instance_path = instance_config_dir(name) + if conf_name.endswith(".json"): + conf_name = conf_name[:-5] + + if conf_name == "config": + raise ValueError("Config cannot be named config") + + self.conf_name = conf_name + self.name = name + + try: + global_data = self.settings.get("GLOBAL", {}) + + self.settings = json.load( + open(os.path.join(instance_path, f"{conf_name}.json"))) + + # write the hardcoded config data ontop of the loaded data + self.settings["GLOBAL"].update(global_data) + except (IOError, ValueError): + pass + + def __getitem__(self, key): + try: + return self.settings["PROJECT"][str(self.project_id)][key] + except KeyError: + try: + return self.settings["GROUP"][str(self.group_id)][key] + except KeyError: + return self.settings["GLOBAL"][key] + + def save(self): + instance_path = instance_config_dir(self.name) + conf_path = os.path.join(instance_path, f"{self.conf_name}.json") + + with open(conf_path, "w") as f: + json.dump(self.settings, f) + + def config_decorator(self, **dkwargs): + def decorator(func): + @wraps(func) + async def wrapper(*args, **kwargs): + + full_kwargs = kwargs.copy() + full_kwargs.update(zip(func.__code__.co_varnames, args)) + try: + event = full_kwargs["event"] + self.project_id = event.project_id + except KeyError: + pass + + try: + return await func(*args, **kwargs) + finally: + self.group_id = None + self.project_id = None + self.save() + + return wrapper + return decorator + + def set_global_data(self, **kwargs): + self.settings["GLOBAL"] = kwargs + + def set_group_data(self, group_id, **kwargs): + self.settings["GROUP"][group_id] = kwargs + + def set_project_data(self, project_id, **kwargs): + self.settings["PROJECT"][project_id] = kwargs + def list_instances() -> List[str]: instances = [] with os.scandir(config_dir()) as it: |