Merge pull request 'allow all org members to automerge' (#118) from Mic92-main into main
All checks were successful
checks / test (push) Successful in 32s

Reviewed-on: #118
This commit is contained in:
Mic92 2023-11-16 14:44:27 +00:00
commit 178e4d1dd4
9 changed files with 43 additions and 52 deletions

View File

@ -1,11 +0,0 @@
name: build
on:
pull_request:
push:
branches: main
jobs:
test:
runs-on: nix
steps:
- uses: actions/checkout@v3
- run: nix flake check -L

View File

@ -8,4 +8,4 @@ jobs:
runs-on: nix
steps:
- uses: actions/checkout@v3
- run: nix run --refresh github:Mic92/nix-fast-build/ae50c356c2f9e790f3d9d8e00bfa9f4b54f49bdd
- run: nix run --refresh github:Mic92/nix-fast-build -- --no-nom

View File

@ -14,17 +14,7 @@
while sleep 10; do
${self.packages.${pkgs.system}.clan-merge}/bin/clan-merge \
--bot-name clan-bot \
--allowed-users \
clan-bot \
hsjobeki \
DavHau \
lassulus \
Mic92 \
Qubasa \
--repos\
clan-infra \
clan-core \
clan-homepage
--repos clan-infra clan-core clan-homepage
done
'';
};

View File

@ -9,6 +9,10 @@
};
};
# trust our own cache
nix.settings.trusted-substituters = [ "https://cache.clan.lol" ];
nix.settings.trusted-public-keys = [ "cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28=" ];
services.nginx.virtualHosts."cache.clan.lol" = {
forceSSL = true;
enableACME = true;

View File

@ -11,6 +11,7 @@
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMxZ3Av30M6Sh6NU1mnCskB16bYtNP8vskc/+ud0AU1C ssh-homepage-key"
];
isSystemUser = true;
shell = "/run/current-system/sw/bin/bash";
group = "www";
};
users.groups.www = { };

View File

@ -1,6 +1,7 @@
import argparse
import json
import urllib.request
import urllib.error
from os import environ
from typing import Optional
@ -37,11 +38,23 @@ def is_ci_green(pr: dict) -> bool:
return False
return True
def is_org_member(user: str, token: str) -> bool:
url = "https://git.clan.lol/api/v1/orgs/clan/members/" + user + f"?token={token}"
try:
urllib.request.urlopen(url)
return True
except urllib.error.HTTPError as e:
if e.code == 404:
return False
else:
raise
def decide_merge(pr: dict, allowed_users: list[str], bot_name: str) -> bool:
def merge_allowed(pr: dict, bot_name: str, token: str) -> bool:
assignees = pr["assignees"] if pr["assignees"] else []
if (
pr["user"]["login"] in allowed_users
is_org_member(pr["user"]["login"], token)
and pr["mergeable"] is True
and not pr["title"].startswith("WIP:")
and pr["state"] == "open"
@ -61,10 +74,10 @@ def list_prs(repo: str) -> list:
return data
def list_prs_to_merge(prs: list, allowed_users: list[str], bot_name: str) -> list:
def list_prs_to_merge(prs: list, bot_name: str, gitea_token: str) -> list:
prs_to_merge = []
for pr in prs:
if decide_merge(pr, allowed_users, bot_name) is True:
if merge_allowed(pr, bot_name, gitea_token):
prs_to_merge.append(pr)
return prs_to_merge
@ -72,12 +85,6 @@ def list_prs_to_merge(prs: list, allowed_users: list[str], bot_name: str) -> lis
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,
)
# option for bot-name
parser.add_argument(
"--bot-name",
@ -107,13 +114,12 @@ def clan_merge(
gitea_token = load_token()
if args is None:
args = parse_args()
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, bot_name)
prs_to_merge = list_prs_to_merge(prs, bot_name, gitea_token)
for pr in prs_to_merge:
url = (
"https://git.clan.lol/api/v1/repos/clan/"

View File

@ -13,7 +13,7 @@ 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"]
monkeypatch.setattr(clan_merge, "is_org_member", lambda y, x: True)
bot_name = "some-bot-name"
pr = dict(
id=1,
@ -23,12 +23,12 @@ def test_decide_merge_allowed(monkeypatch: pytest.MonkeyPatch) -> None:
state="open",
assignees=[dict(login=bot_name)],
)
assert clan_merge.decide_merge(pr, allowed_users, bot_name=bot_name) is True
assert clan_merge.merge_allowed(pr, bot_name=bot_name, token="test") 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"]
monkeypatch.setattr(clan_merge, "is_org_member", lambda y, x: True)
pr1 = dict(
id=1,
user=dict(login="bar"),
@ -69,15 +69,16 @@ def test_decide_merge_not_allowed(monkeypatch: pytest.MonkeyPatch) -> None:
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
assert not clan_merge.merge_allowed(pr1, bot_name="some-bot", token="test")
assert not clan_merge.merge_allowed(pr2, bot_name="some-bot", token="test")
assert not clan_merge.merge_allowed(pr3, bot_name="some-bot", token="test")
assert not clan_merge.merge_allowed(pr4, bot_name="some-bot", token="test")
assert not clan_merge.merge_allowed(pr5, bot_name="some-bot", token="test")
def test_list_prs_to_merge(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(clan_merge, "is_ci_green", lambda x: True)
monkeypatch.setattr(clan_merge, "is_org_member", lambda user, x: user == "foo")
bot_name = "some-bot-name"
prs = [
dict(
@ -111,4 +112,4 @@ def test_list_prs_to_merge(monkeypatch: pytest.MonkeyPatch) -> None:
assignees=[dict(login=bot_name)],
),
]
assert clan_merge.list_prs_to_merge(prs, ["foo"], bot_name=bot_name) == [prs[0]]
assert clan_merge.list_prs_to_merge(prs, bot_name=bot_name, gitea_token="test") == [prs[0]]

View File

@ -1,5 +1,5 @@
{
"data": "ENC[AES256_GCM,data:JPpo0Pg3v7SuwfbQITVDuxju05NCgMbf1NxxLN00GYGsw86lpJRBVKg=,iv:4GUI+PRE2tan3fJqnJGvKe8L6o2+2G5uZhm0yafkWOE=,tag:9kKvlkeK3uvlSYBzwZLBWA==,type:str]",
"data": "ENC[AES256_GCM,data:sP9gs+/oRZiArQUHrHOYkd3GdrmBGzdreNhcR24OOrFOLzrK2EMl7+o=,iv:SE/wO2VWePHqyTM55paLLPRBWGXxN9Z1M9C9wfmePZs=,tag:mn3dQfNqc6/wLDl6tkIbAg==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
@ -27,10 +27,10 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxSFJyQlM0aGNqb0VZUmp0\nUndtTGJiR3lTQ0xSZG1KZWFKaE9qZjlaUXpVCjROUzA5NzZQNTJ5K1huekk2Z0Er\naUsrOStXVlJXOWJKbE1ISzhycDZDdHMKLS0tIFd4OTV1dU9Ya05KOUo4dktSMGJ2\nWXhMNHB5aVRGZFJqZUEvQWdvdmFBSjAKz3fZcUjBDbzrWnAZcS0naFb+4X8LB3vY\nJogBV7lPCo/1H/ZJZPPNXWl0wuiePHB/Rt7fuHAn2PEOilP7tCkkYA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2023-08-09T10:59:21Z",
"mac": "ENC[AES256_GCM,data:2L0I52HpklPTnWl2rQkK8PLEJjss/PMeqWGudxiIZt6u5RDdRycia6NZKKt7iCwUoHyvQQVMUDmSLjc4r+xDCL3EyORWoX3UMBDdn7yZHVH4VogW4t6c3RG/r2kuxS23xWTwnV70tQzXZ4YeR6/JyR0pc7+qOhwB318HBBfiIdE=,iv:cjTV9o38KcAoa4tm/Wh/uJpRSxA5MUIeNrPiWsCmTJs=,tag:MD1bcma7T4cJOr+thUvlCA==,type:str]",
"lastmodified": "2023-11-16T13:52:56Z",
"mac": "ENC[AES256_GCM,data:zXKoEYd+qo9rpFfo5S1HmjOrp8rJTg9CM+Y4vUoiBPG9LtTWWTpImRGjR2wjHZquO75cnupgRNV/RwDBxUjcIdkpPg0AdXLTIX+rjb/6e8Wifsj+uOwJKyAOOI8dz6Aq5IyD2d3b0m+iadOeo20rU/B65nnpN8l2BUPyq1YNOHE=,iv:OhH0BCZWm9vtwvjmT4GvVJXn7ekCpwSKofVF58gOStU=,tag:ZNFKnU7EcH58bw/iOTIN/w==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.7.3"
"version": "3.8.1"
}
}

View File

@ -1,5 +1,5 @@
{
"data": "ENC[AES256_GCM,data:bEu3iLvQfNmAnpKOYLHViFJkxa9QYr5sX941Y2uiUHZXyK+kld7UDrA=,iv:qOFwSzInoCD0ctChHGpplX8Fo2PwvGSd8xewxiqwzDs=,tag:SvghYrsfSt/rNdYPGjg2Ug==,type:str]",
"data": "ENC[AES256_GCM,data:9np4k4rwmHU85dEAmzBbDTewQdo/qfZKAl1sh6L22VvB5aFFr6Mcbvs=,iv:gKKzr0VuwIvoU1KP+trN7pDb3ZPiFqBpygVdW7hSywo=,tag:/+zOagOtsHcBBk5N0sEY7g==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
@ -27,10 +27,10 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNVXFhN1V3YkRvdkRJQnN0\ndVNOY09DVmc2T25mdFJkUjQraVF1MFQrMGlnCjZqZ2Q0WG1YeTF5ZCtHNXhUS2x5\nV0hadkZZanZwYXV1MHBOKzJHOWFyQW8KLS0tIHRCeDFyZUgwRWgwUG45THZtMFpx\nZjhDcEVCVXVPQnVWOGJaWnl5NFVDUFUKD0fJ62m+7KUK9tsWRulCUINm6VXjzkne\nMpfM/OQuR97ohBYY4BXgJCC1KAduEjonEMkP/0j12p3XRU9/ZlT4gA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2023-08-09T10:59:21Z",
"mac": "ENC[AES256_GCM,data:v996pu7bI6rPcTpq3L3HsOAQenrJml1sR4j4WbzTubHePNsJNXJ2He5e1nFYLP4inU6Edtu6/KIJFpz6FkdcQVSW+2izByzh87bG26FpCqRQKpbN7wvLwBE5d12n1yX8Ck23oI0Bm3hc2wk11e0ngQg2Ngfa6MDinGvcnXUSJtQ=,iv:6Kx2OObbDW4h2NGoGjE/nlYAvdGzu3nD+L3FpKhcHDw=,tag:hnK10FS5h7sMiggJmv5qjw==,type:str]",
"lastmodified": "2023-11-16T13:44:37Z",
"mac": "ENC[AES256_GCM,data:tSxb17SZhN5dTw7R7PwHUpdNXqKOqt3/V+bJamvSGAjvfoxY0OUnFFwUNR8Cr7IRUcl2m4Y288fmQ74YcyXQd9emkpTppauybf5AobNsTht6BxyPOFPXAk2V70WmvM75Mt6vm6Xq319YNAF9n8kTQJuwVYfxQxCn8slQNL/eiS0=,iv:MFvDKLE/2zq5lZmwZ+IxPGmHzWWmmIzOLIg5oUoYcjU=,tag:pqJmOgrIDoVc3kj5t6zyZA==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.7.3"
"version": "3.8.1"
}
}