matrix-bot: Working private room join and better message
This commit is contained in:
@@ -70,13 +70,6 @@ def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
|
|||||||
default="https://git.clan.lol",
|
default="https://git.clan.lol",
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"--trigger-labels",
|
|
||||||
help="The labels that trigger the bot",
|
|
||||||
default=["needs-review"],
|
|
||||||
nargs="+",
|
|
||||||
)
|
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@@ -106,7 +99,6 @@ def main() -> None:
|
|||||||
url=args.gitea_url,
|
url=args.gitea_url,
|
||||||
owner=args.repo_owner,
|
owner=args.repo_owner,
|
||||||
repo=args.repo_name,
|
repo=args.repo_name,
|
||||||
trigger_labels=args.trigger_labels,
|
|
||||||
access_token=os.getenv("GITEA_ACCESS_TOKEN"),
|
access_token=os.getenv("GITEA_ACCESS_TOKEN"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ import logging
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import json
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from nio import (
|
from nio import (
|
||||||
AsyncClient,
|
AsyncClient,
|
||||||
JoinResponse,
|
JoinResponse,
|
||||||
JoinedMembersResponse,
|
|
||||||
MatrixRoom,
|
MatrixRoom,
|
||||||
RoomMessageText,
|
RoomMessageText,
|
||||||
)
|
)
|
||||||
@@ -17,15 +16,14 @@ from matrix_bot.gitea import (
|
|||||||
GiteaData,
|
GiteaData,
|
||||||
PullState,
|
PullState,
|
||||||
fetch_pull_requests,
|
fetch_pull_requests,
|
||||||
fetch_repo_labels,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from .locked_open import read_locked_file, write_locked_file
|
from .locked_open import read_locked_file, write_locked_file
|
||||||
from .matrix import MatrixData, send_message
|
from .matrix import MatrixData, get_room_members, send_message
|
||||||
|
|
||||||
|
|
||||||
async def message_callback(room: MatrixRoom, event: RoomMessageText) -> None:
|
async def message_callback(room: MatrixRoom, event: RoomMessageText) -> None:
|
||||||
print(
|
log.debug(
|
||||||
f"Message received in room {room.display_name}\n"
|
f"Message received in room {room.display_name}\n"
|
||||||
f"{room.user_name(event.sender)} | {event.body}"
|
f"{room.user_name(event.sender)} | {event.body}"
|
||||||
)
|
)
|
||||||
@@ -40,40 +38,51 @@ async def bot_run(
|
|||||||
# If you made a new room and haven't joined as that user, you can use
|
# If you made a new room and haven't joined as that user, you can use
|
||||||
room: JoinResponse = await client.join(matrix.room)
|
room: JoinResponse = await client.join(matrix.room)
|
||||||
|
|
||||||
users: JoinedMembersResponse = await client.joined_members(room.room_id)
|
if not room.transport_response.ok:
|
||||||
|
log.error("This can happen if the room doesn't exist or the bot isn't invited")
|
||||||
|
raise Exception(f"Failed to join room {room}")
|
||||||
|
|
||||||
if not users.transport_response.ok:
|
# Get the members of the room
|
||||||
raise Exception(f"Failed to get users {users}")
|
users = await get_room_members(client, room)
|
||||||
|
|
||||||
for user in users.members:
|
|
||||||
print(f"User: {user.user_id} {user.display_name}")
|
|
||||||
|
|
||||||
labels = await fetch_repo_labels(gitea, http)
|
|
||||||
label_ids: list[int] = []
|
|
||||||
for label in labels:
|
|
||||||
if label["name"] in gitea.trigger_labels:
|
|
||||||
label_ids.append(label["id"])
|
|
||||||
|
|
||||||
|
# Fetch the pull requests
|
||||||
tstart = time.time()
|
tstart = time.time()
|
||||||
pulls = await fetch_pull_requests(gitea, http, limit=50, state=PullState.ALL)
|
pulls = await fetch_pull_requests(gitea, http, limit=50, state=PullState.ALL)
|
||||||
|
|
||||||
|
# Read the last updated pull request
|
||||||
last_updated_path = Path("last_updated.json")
|
last_updated_path = Path("last_updated.json")
|
||||||
last_updated = read_locked_file(last_updated_path)
|
last_updated = read_locked_file(last_updated_path)
|
||||||
|
|
||||||
|
# Check if the pull request is mergeable and needs review
|
||||||
|
# and if the pull request is newer than the last updated pull request
|
||||||
for pull in pulls:
|
for pull in pulls:
|
||||||
if pull["requested_reviewers"] and pull["mergeable"]:
|
requested_reviewers = pull["requested_reviewers"]
|
||||||
|
if requested_reviewers and pull["mergeable"]:
|
||||||
if last_updated == {}:
|
if last_updated == {}:
|
||||||
last_updated = pull
|
last_updated = pull
|
||||||
elif pull["updated_at"] < last_updated["updated_at"]:
|
elif pull["updated_at"] < last_updated["updated_at"]:
|
||||||
last_updated = pull
|
last_updated = pull
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
log.info(f"Pull request {pull['title']} needs review")
|
|
||||||
message = f"Pull request {pull['title']} needs review\n{pull['html_url']}"
|
|
||||||
await send_message(client, room, message, user_ids=["@qubasa:gchq.icu"])
|
|
||||||
|
|
||||||
|
# Check if the requested reviewers are in the room
|
||||||
|
requested_reviewers = [r["login"].lower() for r in requested_reviewers]
|
||||||
|
ping_users = []
|
||||||
|
for user in users:
|
||||||
|
if user.display_name.lower() in requested_reviewers:
|
||||||
|
ping_users.append(user.user_id)
|
||||||
|
|
||||||
|
# Send a message to the room and mention the users
|
||||||
|
log.info(f"Pull request {pull['title']} needs review")
|
||||||
|
message = (
|
||||||
|
f"Review Requested:\n<code>{pull['title']}</code>\n{pull['html_url']}"
|
||||||
|
)
|
||||||
|
await send_message(client, room, message, user_ids=ping_users)
|
||||||
|
|
||||||
|
# Write the new last updated pull request
|
||||||
write_locked_file(last_updated_path, last_updated)
|
write_locked_file(last_updated_path, last_updated)
|
||||||
|
|
||||||
|
# Time taken
|
||||||
tend = time.time()
|
tend = time.time()
|
||||||
tdiff = round(tend - tstart)
|
tdiff = round(tend - tstart)
|
||||||
log.debug(f"Time taken: {tdiff}s")
|
log.debug(f"Time taken: {tdiff}s")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import logging
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@@ -15,7 +15,6 @@ class GiteaData:
|
|||||||
owner: str
|
owner: str
|
||||||
repo: str
|
repo: str
|
||||||
access_token: str | None = None
|
access_token: str | None = None
|
||||||
trigger_labels: list[str] = field(default_factory=list)
|
|
||||||
|
|
||||||
|
|
||||||
def endpoint_url(gitea: GiteaData, endpoint: str) -> str:
|
def endpoint_url(gitea: GiteaData, endpoint: str) -> str:
|
||||||
|
|||||||
@@ -10,11 +10,7 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
curr_dir = Path(__file__).parent
|
curr_dir = Path(__file__).parent
|
||||||
|
|
||||||
from nio import (
|
from nio import AsyncClient, ClientConfig, ProfileGetAvatarResponse, RoomMessageText
|
||||||
AsyncClient,
|
|
||||||
ProfileGetAvatarResponse,
|
|
||||||
RoomMessageText,
|
|
||||||
)
|
|
||||||
|
|
||||||
from matrix_bot.bot import bot_run, message_callback
|
from matrix_bot.bot import bot_run, message_callback
|
||||||
from matrix_bot.matrix import set_avatar, upload_image
|
from matrix_bot.matrix import set_avatar, upload_image
|
||||||
@@ -24,8 +20,13 @@ async def bot_main(
|
|||||||
matrix: MatrixData,
|
matrix: MatrixData,
|
||||||
gitea: GiteaData,
|
gitea: GiteaData,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# Setup client configuration to handle encryption
|
||||||
|
client_config = ClientConfig(
|
||||||
|
encryption_enabled=False,
|
||||||
|
)
|
||||||
|
|
||||||
log.info(f"Connecting to {matrix.server} as {matrix.user}")
|
log.info(f"Connecting to {matrix.server} as {matrix.user}")
|
||||||
client = AsyncClient(matrix.server, matrix.user)
|
client = AsyncClient(matrix.server, matrix.user, config=client_config)
|
||||||
client.add_event_callback(message_callback, RoomMessageText)
|
client.add_event_callback(message_callback, RoomMessageText)
|
||||||
|
|
||||||
log.info(await client.login(matrix.password))
|
log.info(await client.login(matrix.password))
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from nio import (
|
from nio import (
|
||||||
AsyncClient,
|
AsyncClient,
|
||||||
|
JoinedMembersResponse,
|
||||||
JoinResponse,
|
JoinResponse,
|
||||||
ProfileSetAvatarResponse,
|
ProfileSetAvatarResponse,
|
||||||
|
RoomMember,
|
||||||
RoomSendResponse,
|
RoomSendResponse,
|
||||||
UploadResponse,
|
UploadResponse,
|
||||||
)
|
)
|
||||||
@@ -33,6 +35,14 @@ async def set_avatar(client: AsyncClient, mxc_url: str) -> None:
|
|||||||
from nio import AsyncClient
|
from nio import AsyncClient
|
||||||
|
|
||||||
|
|
||||||
|
async def get_room_members(client: AsyncClient, room: JoinResponse) -> list[RoomMember]:
|
||||||
|
users: JoinedMembersResponse = await client.joined_members(room.room_id)
|
||||||
|
|
||||||
|
if not users.transport_response.ok:
|
||||||
|
raise Exception(f"Failed to get users {users}")
|
||||||
|
return users.members
|
||||||
|
|
||||||
|
|
||||||
async def send_message(
|
async def send_message(
|
||||||
client: AsyncClient,
|
client: AsyncClient,
|
||||||
room: JoinResponse,
|
room: JoinResponse,
|
||||||
|
|||||||
Reference in New Issue
Block a user