diff --git a/notify.py b/notify.py index 3bc0c46..c979cbd 100755 --- a/notify.py +++ b/notify.py @@ -9,7 +9,7 @@ from matrix_client.client import MatrixClient # Not going to care for specifics like the underscore. # Generally match !anything:example.com with unicode support. -room_pattern = re.compile(r'^!\w+:[\w\-.]+$') +room_pattern = re.compile(r"^!\w+:[\w\-.]+$") def send_message(cfg, args): @@ -17,11 +17,13 @@ def send_message(cfg, args): client.login(username=cfg["matrix"]["username"], password=cfg["matrix"]["password"]) room = client.join_room(room_id_or_alias=args.channel) - if 'html' in args: + if "html" in args: body = None if len(args.text) == 0 else str(args.text) room.send_html(html=args.html, body=body, msgtype=args.type) else: - room.client.api.send_message(room_id=room.room_id, text_content=args.text, msgtype=args.type) + room.client.api.send_message( + room_id=room.room_id, text_content=args.text, msgtype=args.type + ) def main(): @@ -33,15 +35,25 @@ def main(): username: ... password: "..." """ - with open("config.yml", 'r') as ymlfile: + with open("config.yml", "r") as ymlfile: cfg = yaml.safe_load(ymlfile) - parser = argparse.ArgumentParser(description='Notify a matrix channel.') - parser.add_argument('-c', '--channel', required=True, help='the channel to send the message to') - parser.add_argument('-t', '--type', required=False, help='the msgtype', - choices=('m.text', 'm.notice'), default='m.text') - parser.add_argument('text', help='the text message to send to the channel') - parser.add_argument('html', nargs='?', help='the html message to send to the channel') + parser = argparse.ArgumentParser(description="Notify a matrix channel.") + parser.add_argument( + "-c", "--channel", required=True, help="the channel to send the message to" + ) + parser.add_argument( + "-t", + "--type", + required=False, + help="the msgtype", + choices=("m.text", "m.notice"), + default="m.text", + ) + parser.add_argument("text", help="the text message to send to the channel") + parser.add_argument( + "html", nargs="?", help="the html message to send to the channel" + ) args = parser.parse_args() if room_pattern.fullmatch(args.channel) is None: diff --git a/wmn.py b/wmn.py index 6b2c1bb..c26a200 100644 --- a/wmn.py +++ b/wmn.py @@ -15,11 +15,13 @@ application = app # Not going to care for specifics like the underscore. # Generally match room alias or id [!#]anything:example.com with unicode support. -room_pattern = re.compile(r'^[!#]\w+:[\w\-.]+$') +room_pattern = re.compile(r"^[!#]\w+:[\w\-.]+$") # prometheus has to many sub-second digits in their timestamp, # so we get rid of nanoseconds here -promtime_to_isotime_pattern = re.compile(r'([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2})(\.[0-9]{6})?(?:[0-9]{3})?(Z|[+-][0-9]{2}:[0-9]{2})') +promtime_to_isotime_pattern = re.compile( + r"([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2})(\.[0-9]{6})?(?:[0-9]{3})?(Z|[+-][0-9]{2}:[0-9]{2})" +) """ config.yml Example: @@ -30,37 +32,58 @@ matrix: username: ... password: "..." """ -with open("config.yml", 'r') as ymlfile: +with open("config.yml", "r") as ymlfile: cfg = yaml.safe_load(ymlfile) def check_token(header_field: str): token = request.headers.get(header_field) - if token != cfg['secret']: - print('check_token failed, because token did not match', file=sys.stderr, flush=True) + if token != cfg["secret"]: + print( + "check_token failed, because token did not match", + file=sys.stderr, + flush=True, + ) abort(401) def get_a_room(): - if 'channel' not in request.args: - print('get_a_room failed, because channel was not in request args', file=sys.stderr, flush=True) + if "channel" not in request.args: + print( + "get_a_room failed, because channel was not in request args", + file=sys.stderr, + flush=True, + ) abort(400) - room = request.args.get('channel') + room = request.args.get("channel") # sanitize input if room_pattern.fullmatch(room) is None: - print('get_a_room failed, because channel', room, 'did not match room pattern', room_pattern, file=sys.stderr, flush=True) + print( + "get_a_room failed, because channel", + room, + "did not match room pattern", + room_pattern, + file=sys.stderr, + flush=True, + ) abort(400) return room def get_msg_type(): - if 'msgtype' not in request.args: + if "msgtype" not in request.args: return "m.notice" - msgtype = request.args.get('msgtype') + msgtype = request.args.get("msgtype") if msgtype in ["m.text", "m.notice"]: return msgtype else: - print('get_msg_type failed, because msgtype', msgtype, 'is not known', file=sys.stderr, flush=True) + print( + "get_msg_type failed, because msgtype", + msgtype, + "is not known", + file=sys.stderr, + flush=True, + ) abort(400) @@ -74,13 +97,13 @@ def iter_first_line(string: str): def shorten(string: str, max_len: int = 80, appendix: str = "..."): if len(string) > max_len: - return string[:max_len - len(appendix)] + appendix + return string[: max_len - len(appendix)] + appendix else: return string def matrix_error(error: MatrixRequestError): - print('matrix_error was called with', error, file=sys.stderr) + print("matrix_error was called with", error, file=sys.stderr) traceback.print_exception(MatrixRequestError, error, error.__traceback__) print(file=sys.stderr, flush=True) # see Flask.make_response, this will be interpreted as (body, status) @@ -88,7 +111,7 @@ def matrix_error(error: MatrixRequestError): def process_gitlab_request(): - check_token('X-Gitlab-Token') + check_token("X-Gitlab-Token") msgtype = get_msg_type() room = get_a_room() gitlab_event = request.headers.get("X-Gitlab-Event") @@ -99,7 +122,9 @@ def process_gitlab_request(): try: client = MatrixClient(cfg["matrix"]["server"]) - client.login(username=cfg["matrix"]["username"], password=cfg["matrix"]["password"]) + client.login( + username=cfg["matrix"]["username"], password=cfg["matrix"]["password"] + ) room = client.join_room(room_id_or_alias=room) except MatrixRequestError as e: @@ -109,7 +134,12 @@ def process_gitlab_request(): return sorted(commits, key=lambda commit: commit["timestamp"]) def extract_commit_info(commit): - msg = shorten(next(iter_first_line(commit["message"]), "$EMPTY_COMMIT_MESSAGE - impossibruh")) + msg = shorten( + next( + iter_first_line(commit["message"]), + "$EMPTY_COMMIT_MESSAGE - impossibruh", + ) + ) url = commit["url"] return msg, url @@ -120,14 +150,22 @@ def process_gitlab_request(): else: to_str = f" to {project_name}" - commit_messages = list(map(extract_commit_info, sort_commits_by_time(request.json["commits"]))) - html_commits = "\n".join((f'
Build {build_name} on project {project_name} complete: " - f"{result_type}, " - f"{len(changes)} commits
\n" - "" + (f"Build {build_name} on project {project_name} complete: " + f'{result_type}, ' + f"{len(changes)} commits
\n" + "" + + ( + f"{html_message}
" if html_message else "" return ( " \n".join(filter(bool, [title, severity, description, alert_daterange])), - html_message + html_message, ) try: client = MatrixClient(cfg["matrix"]["server"]) - client.login(username=cfg["matrix"]["username"], password=cfg["matrix"]["password"]) + client.login( + username=cfg["matrix"]["username"], password=cfg["matrix"]["password"] + ) room = client.join_room(room_id_or_alias=room) try: - for body, html in map(extract_alert_message, request.json.get("alerts", [])): + for body, html in map( + extract_alert_message, request.json.get("alerts", []) + ): if html and body: room.send_html(html=html, body=body, msgtype=msgtype) elif body: @@ -325,13 +401,13 @@ def process_prometheus_request(): return "", 204 -@app.route('/matrix', methods=("POST",)) +@app.route("/matrix", methods=("POST",)) def notify(): - if 'X-Gitlab-Token' in request.headers: + if "X-Gitlab-Token" in request.headers: return process_gitlab_request() - elif 'X-Jenkins-Token' in request.headers: + elif "X-Jenkins-Token" in request.headers: return process_jenkins_request() - elif 'type' in request.args and request.args.get('type') == "prometheus": + elif "type" in request.args and request.args.get("type") == "prometheus": return process_prometheus_request() else: return "Cannot determine the request's webhook cause", 400