From b30e919816aa3c6941299dd2f0002ec486bfce76 Mon Sep 17 00:00:00 2001 From: DavHau Date: Wed, 26 Jul 2023 11:17:26 +0200 Subject: [PATCH 1/5] init: clan-merge --- flake.nix | 1 + pkgs/clan-merge/.envrc | 1 + pkgs/clan-merge/.gitignore | 12 +++ pkgs/clan-merge/clan_merge/__init__.py | 126 +++++++++++++++++++++++++ pkgs/clan-merge/default.nix | 60 ++++++++++++ pkgs/clan-merge/flake-module.nix | 11 +++ pkgs/clan-merge/pyproject.toml | 58 ++++++++++++ pkgs/clan-merge/shell.nix | 44 +++++++++ pkgs/clan-merge/tests/test_cli.py | 95 +++++++++++++++++++ 9 files changed, 408 insertions(+) create mode 100644 pkgs/clan-merge/.envrc create mode 100644 pkgs/clan-merge/.gitignore create mode 100644 pkgs/clan-merge/clan_merge/__init__.py create mode 100644 pkgs/clan-merge/default.nix create mode 100644 pkgs/clan-merge/flake-module.nix create mode 100644 pkgs/clan-merge/pyproject.toml create mode 100644 pkgs/clan-merge/shell.nix create mode 100644 pkgs/clan-merge/tests/test_cli.py diff --git a/flake.nix b/flake.nix index 0b2eed6..d6a92fb 100644 --- a/flake.nix +++ b/flake.nix @@ -39,6 +39,7 @@ ./targets/flake-module.nix ./modules/flake-module.nix ./pkgs/flake-module.nix + ./pkgs/clan-merge/flake-module.nix ]; perSystem = { pkgs, inputs', ... }: { treefmt = { diff --git a/pkgs/clan-merge/.envrc b/pkgs/clan-merge/.envrc new file mode 100644 index 0000000..d8dab5e --- /dev/null +++ b/pkgs/clan-merge/.envrc @@ -0,0 +1 @@ +use flake .#clan-merge diff --git a/pkgs/clan-merge/.gitignore b/pkgs/clan-merge/.gitignore new file mode 100644 index 0000000..d999462 --- /dev/null +++ b/pkgs/clan-merge/.gitignore @@ -0,0 +1,12 @@ +.direnv +result* + +# python +__pycache__ +.coverage +.mypy_cache +.pytest_cache +.pythonenv +.reports +.ruff_cache +htmlcov diff --git a/pkgs/clan-merge/clan_merge/__init__.py b/pkgs/clan-merge/clan_merge/__init__.py new file mode 100644 index 0000000..11f8cb1 --- /dev/null +++ b/pkgs/clan-merge/clan_merge/__init__.py @@ -0,0 +1,126 @@ +import argparse +import json +import urllib.request +from os import environ +from typing import Optional + + +def load_token() -> str: + GITEA_TOKEN_FILE = environ.get("GITEA_TOKEN_FILE", default=None) + assert GITEA_TOKEN_FILE is not None + with open(GITEA_TOKEN_FILE, "r") as f: + return f.read().strip() + + +def is_ci_green(pr: dict) -> bool: + print("Checking CI status for PR " + str(pr["id"])) + url = ( + "https://git.clan.lol/api/v1/repos/clan/" + + pr["base"]["repo"]["name"] + + "/commits/" + + pr["head"]["sha"] + + "/status" + ) + response = urllib.request.urlopen(url) + data = json.loads(response.read()) + # check for all commit statuses to have status "success" + for status in data["statuses"]: + if status["status"] != "success": + return False + return True + + +def decide_merge(pr: dict, allowed_users: list[str]) -> bool: + if ( + pr["user"]["login"] in allowed_users + and pr["mergeable"] is True + and not pr["title"].startswith("WIP:") + and pr["state"] == "open" + and is_ci_green(pr) + ): + return True + return False + + +# python equivalent for: curl -X 'GET' https://git.clan.lol/api/v1/repos/clan/{repo}/pulls +def list_prs(repo: str) -> list: + url = "https://git.clan.lol/api/v1/repos/clan/" + repo + "/pulls" + response = urllib.request.urlopen(url) + data = json.loads(response.read()) + return data + + +def list_prs_to_merge(prs: list, allowed_users: list[str]) -> list: + prs_to_merge = [] + for pr in prs: + if decide_merge(pr, allowed_users) is True: + prs_to_merge.append(pr) + return prs_to_merge + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Merge PRs on clan.lol") + # parse a list of allowed users + parser.add_argument( + "--allowed-users", + nargs="+", + help="list of users allowed to merge", + required=True, + ) + # parse list of repository names for which to merge PRs + parser.add_argument( + "--repos", + nargs="+", + help="list of repositories for which to merge PRs", + required=True, + ) + # option for dry run + parser.add_argument( + "--dry-run", + action="store_true", + help="dry run", + ) + return parser.parse_args() + + +def clan_merge( + args: Optional[argparse.Namespace] = None, gitea_token: Optional[str] = None +) -> None: + if gitea_token is None: + gitea_token = load_token() + if args is None: + args = parse_args() + allowed_users = args.allowed_users + repos = args.repos + dry_run = args.dry_run + for repo in repos: + prs = list_prs(repo) + prs_to_merge = list_prs_to_merge(prs, allowed_users) + for pr in prs_to_merge: + url = ( + "https://git.clan.lol/api/v1/repos/clan/" + + repo + + "/pulls/" + + str(pr["number"]) + + "/merge" + + f"?token={gitea_token}" + ) + if dry_run is True: + print( + f"Would merge PR {pr['number']} in repo {repo} from user {pr['user']['login']}" + ) + else: + print("Merging PR " + str(pr["id"])) + data = dict( + Do="merge", + ) + data_encoded = json.dumps(data).encode("utf8") + print(data) + req = urllib.request.Request( + url, data=data_encoded, headers={"Content-Type": "application/json"} + ) + urllib.request.urlopen(req) + + +if __name__ == "__main__": + clan_merge() diff --git a/pkgs/clan-merge/default.nix b/pkgs/clan-merge/default.nix new file mode 100644 index 0000000..30f2327 --- /dev/null +++ b/pkgs/clan-merge/default.nix @@ -0,0 +1,60 @@ +{ pkgs ? import { } +, lib ? pkgs.lib +, python3 ? pkgs.python3 +, ruff ? pkgs.ruff +, runCommand ? pkgs.runCommand +, +}: +let + pyproject = builtins.fromTOML (builtins.readFile ./pyproject.toml); + name = pyproject.project.name; + + src = lib.cleanSource ./.; + + dependencies = lib.attrValues { + # inherit (python3.pkgs) + # some-package + # ; + }; + + devDependencies = lib.attrValues { + inherit (pkgs) ruff; + inherit (python3.pkgs) + black + mypy + pytest + pytest-cov + setuptools + wheel + ; + }; + + package = python3.pkgs.buildPythonPackage { + inherit name src; + format = "pyproject"; + nativeBuildInputs = [ + python3.pkgs.setuptools + ]; + propagatedBuildInputs = + dependencies + ++ [ ]; + passthru.tests = { inherit check; }; + passthru.devDependencies = devDependencies; + }; + + checkPython = python3.withPackages (_ps: devDependencies ++ dependencies); + + check = runCommand "${name}-check" { } '' + cp -r ${src} ./src + chmod +w -R ./src + cd src + export PYTHONPATH=. + echo -e "\x1b[32m## run mypy\x1b[0m" + ${checkPython}/bin/mypy . + echo -e "\x1b[32m## run pytest\x1b[0m" + ${checkPython}/bin/pytest + touch $out + ''; + +in +package diff --git a/pkgs/clan-merge/flake-module.nix b/pkgs/clan-merge/flake-module.nix new file mode 100644 index 0000000..8623e16 --- /dev/null +++ b/pkgs/clan-merge/flake-module.nix @@ -0,0 +1,11 @@ +{ + perSystem = { pkgs, ... }: + let + package = pkgs.callPackage ./default.nix { inherit pkgs; }; + in + { + packages.clan-merge = package; + checks.clan-merge = package.tests.check; + devShells.clan-merge = import ./shell.nix { inherit pkgs; }; + }; +} diff --git a/pkgs/clan-merge/pyproject.toml b/pkgs/clan-merge/pyproject.toml new file mode 100644 index 0000000..4fd507d --- /dev/null +++ b/pkgs/clan-merge/pyproject.toml @@ -0,0 +1,58 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +include = ["clan_merge*"] + +[project] +name = "clan_merge" +description = "cLAN internal merge bot for gitea" +dynamic = ["version"] +scripts = {clan-merge = "clan_merge:clan_merge"} + +[tool.pytest.ini_options] +addopts = "--cov . --cov-report term --cov-report=html:.reports/html --no-cov-on-fail" + +[tool.mypy] +python_version = "3.10" +warn_redundant_casts = true +disallow_untyped_calls = true +disallow_untyped_defs = true +no_implicit_optional = true + +[[tool.mypy.overrides]] +module = "setuptools.*" +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = "pytest.*" +ignore_missing_imports = true + +[tool.ruff] +line-length = 88 + +select = ["E", "F", "I"] +ignore = [ "E501" ] + +[tool.black] +line-length = 88 +target-version = ['py310'] +include = '\.pyi?$' +exclude = ''' +/( + \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + # The following are specific to Black, you probably don't want those. + | blib2to3 + | tests/data + | profiling +)/ +''' diff --git a/pkgs/clan-merge/shell.nix b/pkgs/clan-merge/shell.nix new file mode 100644 index 0000000..1c003e7 --- /dev/null +++ b/pkgs/clan-merge/shell.nix @@ -0,0 +1,44 @@ +{ pkgs ? import { } }: +let + lib = pkgs.lib; + python3 = pkgs.python3; + package = import ./default.nix { + inherit lib pkgs python3; + }; + pythonWithDeps = python3.withPackages ( + ps: + package.propagatedBuildInputs + ++ package.devDependencies + ++ [ + ps.pip + ] + ); + checkScript = pkgs.writeScriptBin "check" '' + nix build -f . tests -L "$@" + ''; + devShell = pkgs.mkShell { + packages = [ + pkgs.ruff + pythonWithDeps + ]; + # sets up an editable install and add enty points to $PATH + shellHook = '' + tmp_path=$(realpath ./.pythonenv) + repo_root=$(realpath .) + rm -rf $tmp_path + mkdir -p "$tmp_path/${pythonWithDeps.sitePackages}" + + ${pythonWithDeps.interpreter} -m pip install \ + --quiet \ + --disable-pip-version-check \ + --no-index \ + --no-build-isolation \ + --prefix "$tmp_path" \ + --editable $repo_root + + export PATH="$tmp_path/bin:${checkScript}/bin:$PATH" + export PYTHONPATH="$repo_root:$tmp_path/${pythonWithDeps.sitePackages}" + ''; + }; +in +devShell diff --git a/pkgs/clan-merge/tests/test_cli.py b/pkgs/clan-merge/tests/test_cli.py new file mode 100644 index 0000000..3621468 --- /dev/null +++ b/pkgs/clan-merge/tests/test_cli.py @@ -0,0 +1,95 @@ +import pytest + +import clan_merge + + +def test_no_args(capsys: pytest.CaptureFixture) -> None: + # handle EsystemExit via pytest.raises + with pytest.raises(SystemExit): + clan_merge.clan_merge(gitea_token="") + captured = capsys.readouterr() + assert captured.err.startswith("usage:") + + +def test_decide_merge_allowed(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(clan_merge, "is_ci_green", lambda x: True) + allowed_users = ["foo"] + pr = dict( + id=1, + user=dict(login="foo"), + title="Some PR Title", + mergeable=True, + state="open", + ) + assert clan_merge.decide_merge(pr, allowed_users) is True + + +def test_decide_merge_not_allowed(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(clan_merge, "is_ci_green", lambda x: True) + allowed_users = ["foo"] + pr1 = dict( + id=1, + user=dict(login="bar"), + title="Some PR Title", + mergeable=True, + state="open", + ) + pr2 = dict( + id=1, + user=dict(login="foo"), + title="WIP: xyz", + mergeable=True, + state="open", + ) + pr3 = dict( + id=1, + user=dict(login="foo"), + title="Some PR Title", + mergeable=False, + state="open", + ) + pr4 = dict( + id=1, + user=dict(login="foo"), + title="Some PR Title", + mergeable=True, + state="closed", + ) + assert clan_merge.decide_merge(pr1, allowed_users) is False + assert clan_merge.decide_merge(pr2, allowed_users) is False + assert clan_merge.decide_merge(pr3, allowed_users) is False + assert clan_merge.decide_merge(pr4, allowed_users) is False + + +def test_list_prs_to_merge(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(clan_merge, "is_ci_green", lambda x: True) + prs = [ + dict( + id=1, + base=dict(repo=dict(name="repo1")), + head=dict(sha="1234567890"), + user=dict(login="foo"), + state="open", + title="PR 1", + mergeable=True, + ), + dict( + id=2, + base=dict(repo=dict(name="repo1")), + head=dict(sha="1234567890"), + user=dict(login="foo"), + state="open", + title="WIP: xyz", + mergeable=True, + ), + dict( + id=3, + base=dict(repo=dict(name="repo1")), + head=dict(sha="1234567890"), + user=dict(login="bar"), + state="open", + title="PR 2", + mergeable=True, + ), + ] + assert clan_merge.list_prs_to_merge(prs, ["foo"]) == [prs[0]] From 5ce983c8ffd1e5ce8fba7bc34e7e0fcb538d4c34 Mon Sep 17 00:00:00 2001 From: DavHau Date: Wed, 26 Jul 2023 12:25:04 +0200 Subject: [PATCH 2/5] clan-merge: deploy on web01 --- modules/web01/clan-merge.nix | 24 ++++++++++++++++++++++++ modules/web01/default.nix | 11 ++++++----- targets/web01/secrets.yaml | 5 +++-- 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 modules/web01/clan-merge.nix diff --git a/modules/web01/clan-merge.nix b/modules/web01/clan-merge.nix new file mode 100644 index 0000000..513125e --- /dev/null +++ b/modules/web01/clan-merge.nix @@ -0,0 +1,24 @@ +{ config, self, pkgs, ... }: { + + sops.secrets.merge-bot-gitea-token = {}; + + # service to for automatic merge bot + systemd.services.clan-merge = { + description = "Merge clan.lol PRs automatically"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + environment = { GITEA_TOKEN_FILE = "%d/GITEA_TOKEN_FILE"; }; + serviceConfig = { + LoadCredential = [ "GITEA_TOKEN_FILE:${config.sops.secrets.merge-bot-gitea-token.path}" ]; + Restart = "on-failure"; + DynamicUser = true; + }; + script = '' + while sleep 10; do + ${self.packages.${pkgs.system}.clan-merge}/bin/clan-merge \ + --allowed-users DavHau lassulus mic92 \ + --repos clan-core + done + ''; + }; +} diff --git a/modules/web01/default.nix b/modules/web01/default.nix index 59ee238..ff34edb 100644 --- a/modules/web01/default.nix +++ b/modules/web01/default.nix @@ -1,11 +1,12 @@ { imports = [ - ./homepage.nix - ./gitea - ./postfix.nix - ./harmonia.nix - ./dendrite.nix ./borgbackup.nix + ./clan-merge.nix + ./dendrite.nix + ./gitea + ./harmonia.nix + ./homepage.nix + ./postfix.nix ../zerotier ../zerotier/ctrl.nix ]; diff --git a/targets/web01/secrets.yaml b/targets/web01/secrets.yaml index e3da316..76e385c 100644 --- a/targets/web01/secrets.yaml +++ b/targets/web01/secrets.yaml @@ -11,6 +11,7 @@ harmonia-key: ENC[AES256_GCM,data:pZObqfbLogp0DYs47Tg2STKT9HptPSiP4sgcf31FD68PKS matrix-server-key: ENC[AES256_GCM,data:0148ezOFk8jX5KPQPCG0jQK9ajSfe/iOdUqlvys5/M8DrIwPXH9GzrkknwH+l8kF9ViTRDC/q5md8J2bj3/FBR/RW4rwjDrYx9cBEFm8wjHrywUlwON8kNKtj9ycJmXgtRyCrVGv7sBmODy0ZC5ZfWbhIQh6xWBkX2/rsSh4zwi/1PoHLpOO3u4=,iv:IwHPDi1E3R9LAY/seGpvx1U+N8mB9NMrUjLg4KMA1UA=,tag:pwRJ/CqkFN2eedrnMAaj2w==,type:str] registration-secret: ENC[AES256_GCM,data:EvPearZAxxb2irZFYgvy/tFA72h+IABuzwCbvy94IYR0eoHjuYw6GBde8CNUWG4SUiwyXJr4v438o/YThDhehsZ/cZFjg2o=,iv:ogN4/Iia5Zl95a3HP1KZoy86K8LyBFYw50cZUpkDNQo=,tag:5wU2OrNi7b5gWPfFZcGLjg==,type:str] gitea-actions-runner: ENC[AES256_GCM,data:JKXAa7J1V3GH8lp3UtHTBmiezJlqxX1ItHLE7UcaIeNFQH8We2imaOMVftMpVCeXTpRX,iv:W9+4wH4asw3+w28i5om0OcJFHrABC85bhjhbgGWEs8E=,tag:Rf9XBeiEoJ1Pt8Z1TDIyJA==,type:str] +merge-bot-gitea-token: ENC[AES256_GCM,data:ULHcaNSYJwMVeeEq4bSiRcVRuUkE9fFUV0AkWW1wM0yHQtD+dmo1GcQ=,iv:dujDWGZ+seoVN8Eez1w3tUuMpGeOHtNLMaa+f2hOpAo=,tag:WoDTsZegC6rrbh7ygWSk+A==,type:str] sops: kms: [] gcp_kms: [] @@ -53,8 +54,8 @@ sops: TGk4dUlwcE9XWWIzZE1nQXdXcWY0V0kKJi5yXdrsEOP4Z8K6k/sPA7yadNPKQtzo Iyt//Y+Y7n55KwuO8Doogu42SiVTUhHDICM9lezQmcugFqCoh3Lk4A== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-07-21T13:58:56Z" - mac: ENC[AES256_GCM,data:GD2lZplaOjw2vRYYAIFydFK1NndJRv5MeXNHDCr/H7G5t8jnO2XstOuUYLhzqO1lpL2dRi4vc+B0UuM6jS3mzUkUqfV201qQ4MxDnViYxgNRk+7XuVaM940yw4UwUJQA2IN7C9EOU/xmYRqpvHFWptjrGFkEnBEVChKncqpen4k=,iv:Zn9i3Y7pkz5OsGHeOi2VBuF2Ha0dUDbDJl+BhXKMgaI=,tag:azmGDxfkQ9P49QTQBxdjSQ==,type:str] + lastmodified: "2023-07-26T09:49:19Z" + mac: ENC[AES256_GCM,data:sAJcUwJeVCXwNXmWUJrP0L1UcjoYDqErW2mBTRC3yoUOVtbVdZnLkswO0PARWruOqMBKXkIH/SqeiLyJ7HLIsobBzFoUNQ6TgjmP0OHf4Qbo/5sSDVA95qK1ZCgK93uKSEfG0WUvJLqfOKUEdBUgPUqJ58RM2VOWU21liccaG+A=,iv:u6lStYbzZsOWd5rsZXKs0XCAbQTFsPrnXLqO27i/Qt0=,tag:JeYtuP1zztsy4FUB1kzcWw==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.7.3 From aea65f90aeeea721cabc6711624240739c411340 Mon Sep 17 00:00:00 2001 From: DavHau Date: Wed, 26 Jul 2023 12:36:53 +0200 Subject: [PATCH 3/5] clan-merge: fix format --- modules/web01/clan-merge.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/web01/clan-merge.nix b/modules/web01/clan-merge.nix index 513125e..f0af57d 100644 --- a/modules/web01/clan-merge.nix +++ b/modules/web01/clan-merge.nix @@ -1,6 +1,6 @@ { config, self, pkgs, ... }: { - sops.secrets.merge-bot-gitea-token = {}; + sops.secrets.merge-bot-gitea-token = { }; # service to for automatic merge bot systemd.services.clan-merge = { From 5c9c1f15186a001482b56915162ea201a9da9d70 Mon Sep 17 00:00:00 2001 From: DavHau Date: Wed, 26 Jul 2023 14:33:36 +0200 Subject: [PATCH 4/5] clan-merge: require bot assigned --- modules/web01/clan-merge.nix | 3 ++- pkgs/clan-merge/clan_merge/__init__.py | 17 ++++++++++---- pkgs/clan-merge/tests/test_cli.py | 31 +++++++++++++++++++++----- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/modules/web01/clan-merge.nix b/modules/web01/clan-merge.nix index f0af57d..a5b3199 100644 --- a/modules/web01/clan-merge.nix +++ b/modules/web01/clan-merge.nix @@ -17,7 +17,8 @@ while sleep 10; do ${self.packages.${pkgs.system}.clan-merge}/bin/clan-merge \ --allowed-users DavHau lassulus mic92 \ - --repos clan-core + --repos clan-core \ + --bot-name clan-bot done ''; }; diff --git a/pkgs/clan-merge/clan_merge/__init__.py b/pkgs/clan-merge/clan_merge/__init__.py index 11f8cb1..65984b2 100644 --- a/pkgs/clan-merge/clan_merge/__init__.py +++ b/pkgs/clan-merge/clan_merge/__init__.py @@ -30,12 +30,14 @@ def is_ci_green(pr: dict) -> bool: return True -def decide_merge(pr: dict, allowed_users: list[str]) -> bool: +def decide_merge(pr: dict, allowed_users: list[str], bot_name: str) -> bool: if ( pr["user"]["login"] in allowed_users and pr["mergeable"] is True and not pr["title"].startswith("WIP:") and pr["state"] == "open" + # check if bot is assigned + and any(reviewer["login"] == bot_name for reviewer in pr["assignees"]) and is_ci_green(pr) ): return True @@ -50,10 +52,10 @@ def list_prs(repo: str) -> list: return data -def list_prs_to_merge(prs: list, allowed_users: list[str]) -> list: +def list_prs_to_merge(prs: list, allowed_users: list[str], bot_name: str) -> list: prs_to_merge = [] for pr in prs: - if decide_merge(pr, allowed_users) is True: + if decide_merge(pr, allowed_users, bot_name) is True: prs_to_merge.append(pr) return prs_to_merge @@ -67,6 +69,12 @@ def parse_args() -> argparse.Namespace: help="list of users allowed to merge", required=True, ) + # option for bot-name + parser.add_argument( + "--bot-name", + help="name of the bot", + required=True, + ) # parse list of repository names for which to merge PRs parser.add_argument( "--repos", @@ -93,9 +101,10 @@ def clan_merge( allowed_users = args.allowed_users repos = args.repos dry_run = args.dry_run + bot_name = args.bot_name for repo in repos: prs = list_prs(repo) - prs_to_merge = list_prs_to_merge(prs, allowed_users) + prs_to_merge = list_prs_to_merge(prs, allowed_users, bot_name) for pr in prs_to_merge: url = ( "https://git.clan.lol/api/v1/repos/clan/" diff --git a/pkgs/clan-merge/tests/test_cli.py b/pkgs/clan-merge/tests/test_cli.py index 3621468..a2b0ae9 100644 --- a/pkgs/clan-merge/tests/test_cli.py +++ b/pkgs/clan-merge/tests/test_cli.py @@ -14,14 +14,16 @@ def test_no_args(capsys: pytest.CaptureFixture) -> None: def test_decide_merge_allowed(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(clan_merge, "is_ci_green", lambda x: True) allowed_users = ["foo"] + bot_name = "some-bot-name" pr = dict( id=1, user=dict(login="foo"), title="Some PR Title", mergeable=True, state="open", + assignees=[dict(login=bot_name)], ) - assert clan_merge.decide_merge(pr, allowed_users) is True + assert clan_merge.decide_merge(pr, allowed_users, bot_name=bot_name) is True def test_decide_merge_not_allowed(monkeypatch: pytest.MonkeyPatch) -> None: @@ -33,6 +35,7 @@ def test_decide_merge_not_allowed(monkeypatch: pytest.MonkeyPatch) -> None: title="Some PR Title", mergeable=True, state="open", + assignees=[dict(login="foo")], ) pr2 = dict( id=1, @@ -40,6 +43,7 @@ def test_decide_merge_not_allowed(monkeypatch: pytest.MonkeyPatch) -> None: title="WIP: xyz", mergeable=True, state="open", + assignees=[dict(login="foo")], ) pr3 = dict( id=1, @@ -47,6 +51,7 @@ def test_decide_merge_not_allowed(monkeypatch: pytest.MonkeyPatch) -> None: title="Some PR Title", mergeable=False, state="open", + assignees=[dict(login="foo")], ) pr4 = dict( id=1, @@ -54,15 +59,26 @@ def test_decide_merge_not_allowed(monkeypatch: pytest.MonkeyPatch) -> None: title="Some PR Title", mergeable=True, state="closed", + assignees=[dict(login="foo")], ) - assert clan_merge.decide_merge(pr1, allowed_users) is False - assert clan_merge.decide_merge(pr2, allowed_users) is False - assert clan_merge.decide_merge(pr3, allowed_users) is False - assert clan_merge.decide_merge(pr4, allowed_users) is False + pr5 = dict( + id=1, + user=dict(login="foo"), + title="Some PR Title", + mergeable=True, + state="open", + assignees=[dict(login="clan-bot")], + ) + assert clan_merge.decide_merge(pr1, allowed_users, bot_name="some-bot") is False + assert clan_merge.decide_merge(pr2, allowed_users, bot_name="some-bot") is False + assert clan_merge.decide_merge(pr3, allowed_users, bot_name="some-bot") is False + assert clan_merge.decide_merge(pr4, allowed_users, bot_name="some-bot") is False + assert clan_merge.decide_merge(pr5, allowed_users, bot_name="some-bot") is False def test_list_prs_to_merge(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(clan_merge, "is_ci_green", lambda x: True) + bot_name = "some-bot-name" prs = [ dict( id=1, @@ -72,6 +88,7 @@ def test_list_prs_to_merge(monkeypatch: pytest.MonkeyPatch) -> None: state="open", title="PR 1", mergeable=True, + assignees=[dict(login=bot_name)], ), dict( id=2, @@ -81,6 +98,7 @@ def test_list_prs_to_merge(monkeypatch: pytest.MonkeyPatch) -> None: state="open", title="WIP: xyz", mergeable=True, + assignees=[dict(login=bot_name)], ), dict( id=3, @@ -90,6 +108,7 @@ def test_list_prs_to_merge(monkeypatch: pytest.MonkeyPatch) -> None: state="open", title="PR 2", mergeable=True, + assignees=[dict(login=bot_name)], ), ] - assert clan_merge.list_prs_to_merge(prs, ["foo"]) == [prs[0]] + assert clan_merge.list_prs_to_merge(prs, ["foo"], bot_name=bot_name) == [prs[0]] From 7aa949d1df990739d3344f031411b3860f0d55f6 Mon Sep 17 00:00:00 2001 From: DavHau Date: Wed, 26 Jul 2023 14:34:13 +0200 Subject: [PATCH 5/5] clan-merge: enable for all repos --- modules/web01/clan-merge.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/web01/clan-merge.nix b/modules/web01/clan-merge.nix index a5b3199..7b7a0cf 100644 --- a/modules/web01/clan-merge.nix +++ b/modules/web01/clan-merge.nix @@ -17,7 +17,7 @@ while sleep 10; do ${self.packages.${pkgs.system}.clan-merge}/bin/clan-merge \ --allowed-users DavHau lassulus mic92 \ - --repos clan-core \ + --repos clan-infra clan-core clan-homepage \ --bot-name clan-bot done '';