diff --git a/.gitignore b/.gitignore index 9edda3c..737fa13 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .mypy_cache coverage.xml htmlcov +__pycache__ diff --git a/README.md b/README.md index 4f99775..3392da6 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,19 @@ Add a JSON webhook with `?formatter=github`, and put the `API_KEY` as secret Add a webhook with an URL ending with `?formatter=grafana&key=API_KEY` +### For Gitlab + +At a group level, Gitlab does not permit to setup webhooks. A workaround consists to use Google +Chat or Microsoft Teams notification integration with a custom URL (Gitlab does not check if the url begins with the normal url of the service). + +#### Google Chat + +Add a Google Chat integration with an URL ending with `?formatter=gitlab_gchat&key=API_KEY` + +#### Microsoft Teams + +Add a Microsoft Teams integration with an URL ending with `?formatter=gitlab_teams&key=API_KEY` + ## Test room [#matrix-webhook:tetaneutral.net](https://matrix.to/#/!DPrUlnwOhBEfYwsDLh:matrix.org) diff --git a/matrix_webhook/formatters.py b/matrix_webhook/formatters.py index c59249e..d1d0519 100644 --- a/matrix_webhook/formatters.py +++ b/matrix_webhook/formatters.py @@ -1,5 +1,7 @@ """Formatters for matrix webhook.""" +import re + def grafana(data, headers): """Pretty-print a grafana notification.""" @@ -30,3 +32,29 @@ def github(data, headers): data["body"] = "notification from github" data["digest"] = headers["X-Hub-Signature-256"].replace("sha256=", "") return data + + +def gitlab_gchat(data, headers): + """Pretty-print a gitlab notification preformatted for Google Chat.""" + data["body"] = re.sub("<(.*?)\\|(.*?)>", "[\\2](\\1)", data["body"], re.MULTILINE) + return data + + +def gitlab_teams(data, headers): + """Pretty-print a gitlab notification preformatted for Microsoft Teams.""" + body = [] + for section in data["sections"]: + if "text" in section.keys(): + text = section["text"].split("\n\n") + text = ["* " + t for t in text] + body.append("\n" + " \n".join(text)) + elif all( + k in section.keys() + for k in ("activityTitle", "activitySubtitle", "activityText") + ): + text = section["activityTitle"] + " " + section["activitySubtitle"] + " → " + text += section["activityText"] + body.append(text) + + data["body"] = " \n".join(body) + return data diff --git a/tests/example_gitlab_gchat.json b/tests/example_gitlab_gchat.json new file mode 100644 index 0000000..bd400a0 --- /dev/null +++ b/tests/example_gitlab_gchat.json @@ -0,0 +1 @@ +{"text":"John Doe pushed to branch \u003chttps://gitlab.com/jdoe/test/commits/master|master\u003e of \u003chttps://gitlab.com/jdoe/test|John Doe / test\u003e (\u003chttps://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e|Compare changes\u003e)\n\u003chttps://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213650d6c009db0471361e|3517b06c\u003e: Merge branch 'prod' into 'master' - John Doe\n\n\u003chttps://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f391eb8de3ac4fcc6fc1d|1f661795\u003e: Merge branch 'revert-a827b196' into 'prod' - John Doe\n\n\u003chttps://gitlab.com/jdoe/test/-/commit/b76004b20503d4d506e51a670de095cc063e4707|b76004b2\u003e: Merge branch 'revert-a827b196' into 'master' - John Doe"} diff --git a/tests/example_gitlab_teams.json b/tests/example_gitlab_teams.json new file mode 100644 index 0000000..63d5e5d --- /dev/null +++ b/tests/example_gitlab_teams.json @@ -0,0 +1 @@ +{"sections":[{"activityTitle":"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits/master)","activitySubtitle":"in [John Doe / test](https://gitlab.com/jdoe/test)","activityText":"[Compare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e)","activityImage":"https://secure.gravatar.com/avatar/80\u0026d=identicon"},{"text":"[3517b06c](https://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213650d6c009db0471361e): Merge branch 'prod' into 'master' - John Doe\n\n[1f661795](https://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f391eb8de3ac4fcc6fc1d): Merge branch 'revert-a827b196' into 'prod' - John Doe\n\n[b76004b2](https://gitlab.com/jdoe/test/-/commit/b76004b20503d4d506e51a670de095cc063e4707): Merge branch 'revert-a827b196' into 'master' - John Doe"}],"title":"John Doe / test","summary":"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits/master) of [John Doe / test](https://gitlab.com/jdoe/test) ([Compare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e))"} diff --git a/tests/test_gitlab_gchat.py b/tests/test_gitlab_gchat.py new file mode 100644 index 0000000..2328789 --- /dev/null +++ b/tests/test_gitlab_gchat.py @@ -0,0 +1,54 @@ +""" +Test module for gitlab "google chat" formatter. + +""" + +import unittest + +import httpx +import nio + +from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL + + +class GitlabGchatFormatterTest(unittest.IsolatedAsyncioTestCase): + """Gitlab "google chat" formatter test class.""" + + async def test_gitlab_gchat_body(self): + """Send a markdown message, and check the result.""" + messages = [] + client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) + + await client.login(MATRIX_PW) + room = await client.room_create() + + with open("tests/example_gitlab_gchat.json") as f: + example_gitlab_gchat_request = f.read() + self.assertEqual( + httpx.post( + f"{BOT_URL}/{room.room_id}", + params={"formatter": "gitlab_gchat", "key": KEY}, + content=example_gitlab_gchat_request, + ).json(), + {"status": 200, "ret": "OK"}, + ) + + sync = await client.sync() + messages = await client.room_messages(room.room_id, sync.next_batch) + await client.close() + + message = messages.chunk[0] + self.assertEqual(message.sender, FULL_ID) + self.assertEqual( + message.body, + "John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits/m" + + "aster) of [John Doe / test](https://gitlab.com/jdoe/test) ([Compare chan" + + "ges](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095" + + "cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e))\n[3517b06c](http" + + "s://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213650d6c009db047136" + + "1e): Merge branch 'prod' into 'master' - John Doe\n\n[1f661795](https://" + + "gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f391eb8de3ac4fcc6fc1d):" + + " Merge branch 'revert-a827b196' into 'prod' - John Doe\n\n[b76004b2](htt" + + "ps://gitlab.com/jdoe/test/-/commit/b76004b20503d4d506e51a670de095cc063e4" + + "707): Merge branch 'revert-a827b196' into 'master' - John Doe", + ) diff --git a/tests/test_gitlab_teams.py b/tests/test_gitlab_teams.py new file mode 100644 index 0000000..eee89e5 --- /dev/null +++ b/tests/test_gitlab_teams.py @@ -0,0 +1,55 @@ +""" +Test module for gitlab "teams" formatter. + +""" + +import unittest + +import httpx +import nio + +from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL + + +class GitlabTeamsFormatterTest(unittest.IsolatedAsyncioTestCase): + """Gitlab "teams" formatter test class.""" + + async def test_gitlab_teams_body(self): + """Send a markdown message, and check the result.""" + messages = [] + client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) + + await client.login(MATRIX_PW) + room = await client.room_create() + + with open("tests/example_gitlab_teams.json") as f: + example_gitlab_teams_request = f.read() + self.assertEqual( + httpx.post( + f"{BOT_URL}/{room.room_id}", + params={"formatter": "gitlab_teams", "key": KEY}, + content=example_gitlab_teams_request, + ).json(), + {"status": 200, "ret": "OK"}, + ) + + sync = await client.sync() + messages = await client.room_messages(room.room_id, sync.next_batch) + await client.close() + + message = messages.chunk[0] + self.assertEqual(message.sender, FULL_ID) + self.assertEqual( + message.body, + "John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits" + + "/master) in [John Doe / test](https://gitlab.com/jdoe/test) \u2192 [Com" + + "pare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e5" + + "1a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e) \n\n*" + + " [3517b06c](https://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213" + + "650d6c009db0471361e): Merge branch 'prod' into 'master' - John Doe \n*" + + " [1f661795](https://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f3" + + "91eb8de3ac4fcc6fc1d): Merge branch 'revert-a827b196' into 'prod' - John" + + " Doe \n* [b76004b2](https://gitlab.com/jdoe/test/-/commit/b76004b20503" + + "d4d506e51a670de095cc063e4707): Merge branch 'revert-a827b196' into 'mas" + + "ter' - John Doe", + )