From 602c2423cc1072f109dd0ecaf387fe0110798eec Mon Sep 17 00:00:00 2001 From: InValidFire Date: Sat, 20 Aug 2022 16:07:54 +0000 Subject: [PATCH] Add /branch command (#1) This PR adds a /branch command with the following spec: `/branch switch ` - switch to the specified branch, only if it exists. `/branch get` - get the name of the current branch. With the addition of these two commands, it will greatly speed up the development and testing process. Other Changes: - Removed git_dev status - /book now displays the uploaded image on all prompts - added a private option to /book to keep confirmation emails from being shared if desired - now runs `git fetch` before gathering git info when running /info Reviewed-on: https://gitdab.com/InValidFire/radical-bot/pulls/1 --- ext/libcal.py | 40 +++++++++++++-------- ext/system.py | 99 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 98 insertions(+), 41 deletions(-) diff --git a/ext/libcal.py b/ext/libcal.py index 6d9b8c2..141e53d 100644 --- a/ext/libcal.py +++ b/ext/libcal.py @@ -15,17 +15,19 @@ from lib.ocr import get_room_data, NoMatchException plugin = lightbulb.Plugin("LibCal") config = load_config() + def add_rooms_to_embed(room_list: list[Room], embed: hikari.Embed): for room in room_list: embed.add_field(room.get_time_str(), room.number) + class BookingConfirmationView(miru.View): - def __init__(self, *, timeout: Optional[float] = 120, autodefer: bool = True, room_list: list[Room] = [], image: Resource | None = None) -> None: + def __init__(self, *, timeout: Optional[float] = 120, autodefer: bool = True, + room_list: list[Room] = [], image: Resource | None = None, private: bool = False + ) -> None: self.room_list = room_list - if image is not None: - self.image = image - else: - self.image = None + self.image = image + self.private = private super().__init__(timeout=timeout, autodefer=autodefer) @miru.button(label="Yes", style=hikari.ButtonStyle.SUCCESS) @@ -33,25 +35,32 @@ class BookingConfirmationView(miru.View): gcal = GoogleCalendarAPI() for room in self.room_list: await gcal.create_event(room.number, room.start_time, room.end_time) - embed = hikari.Embed(title="Rooms Booked!") - add_rooms_to_embed(self.room_list, embed) - await ctx.edit_response(embed=embed, components=[]) + embed = hikari.Embed(title="Rooms Booked!") + add_rooms_to_embed(self.room_list, embed) + embed.set_image(self.image) + await ctx.edit_response(embed=embed, components=[]) - thread_embed = hikari.Embed(title="Rooms were booked!") - thread_embed.set_author(name=ctx.user.username, icon=ctx.user.avatar_url) + thread_embed = hikari.Embed(title="Rooms were booked!") + thread_embed.set_author( + name=ctx.user.username, icon=ctx.user.avatar_url) + if not self.private: thread_embed.set_image(self.image) - add_rooms_to_embed(self.room_list, thread_embed) - await ctx.app.rest.create_message(config.discord_study_room_thread, embed=thread_embed) + add_rooms_to_embed(self.room_list, thread_embed) + await ctx.app.rest.create_message(config.discord_study_room_thread, embed=thread_embed) self.stop() @miru.button(label="No", style=hikari.ButtonStyle.DANGER) async def cancel_button(self, button: miru.Button, ctx: miru.Context) -> None: embed = hikari.Embed(title="Aborted!") + add_rooms_to_embed(self.room_list, embed) + embed.set_image(self.image) await ctx.edit_response(embed=embed, components=[]) self.stop() + @plugin.command @lightbulb.option("img", "image to check for events", type=hikari.Attachment, required=True) +@lightbulb.option("private", "if private, the bot will not share confirmation e-mails.", type=bool, default=False) @lightbulb.command("book", "add room bookings to Google Calendar", ephemeral=True) @lightbulb.implements(lightbulb.SlashCommand) async def book(ctx: lightbulb.Context) -> None: @@ -61,7 +70,9 @@ async def book(ctx: lightbulb.Context) -> None: add_rooms_to_embed(room_list, response) response.title = "Room Bookings" response.description = "Are the booking(s) correct?" - view = BookingConfirmationView(room_list=room_list, image=ctx.options.img) + response.set_image(ctx.options.img) + view = BookingConfirmationView( + room_list=room_list, image=ctx.options.img, private=ctx.options.private) resp = await ctx.respond(response, components=view.build()) view.start(await resp.message()) @@ -70,7 +81,8 @@ async def book(ctx: lightbulb.Context) -> None: async def book_error_handler(event: lightbulb.CommandErrorEvent): print("ERROR TYPE:", type(event.exception)) if isinstance(event.exception.__cause__, NoMatchException): - embed = hikari.Embed(title="Huh, I can't read that", description="Could you try another picture?") + embed = hikari.Embed(title="Huh, I can't read that", + description="Could you try another picture?") await event.context.respond(embed=embed) else: embed = hikari.Embed( diff --git a/ext/system.py b/ext/system.py index 1723e58..5e14498 100644 --- a/ext/system.py +++ b/ext/system.py @@ -9,32 +9,41 @@ config = load_config() plugin = lightbulb.Plugin("SystemPlugin") + async def create_subprocess(*args): proc = await asyncio.create_subprocess_exec(*args, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE - ) + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) stdout, _ = await proc.communicate() return stdout.decode("utf-8").strip() + async def get_git_latest_commit_id(): return await create_subprocess("git", "rev-parse", "--short", "HEAD") + async def get_git_branch(): return await create_subprocess("git", "rev-parse", "--abbrev-ref", "HEAD") + async def get_git_remote(): remote = await create_subprocess("git", "branch", "-vv") - return remote.split("[")[1].split("]")[0] + for line in remote.split("\n"): + if "*" in line: + return line.split("[")[1].split("]")[0] + async def get_git_head_diff_branch(branch: str) -> str: # diff HEAD to remote return await create_subprocess("git", "diff", "head", branch) + async def get_git_index_diff_branch(branch: str) -> str: # diff index to remote return await create_subprocess("git", "diff", branch) + async def get_git_commits_ahead_behind(branch: str, remote: str) -> tuple[int, int]: # commits ahead/behind remote output = await create_subprocess("git", "rev-list", "--left-right", "--count", branch+"..."+remote) @@ -42,71 +51,107 @@ async def get_git_commits_ahead_behind(branch: str, remote: str) -> tuple[int, i commits_behind = int(output.split()[1]) return commits_ahead, commits_behind -async def get_git_dev(remote: str, branch: str) -> bool: - # dev environment tests - if await get_git_head_diff_branch(remote) != "": # difference between HEAD and remote - return True - elif config.git_branch != branch: # branch has been changed - return True - elif await get_git_index_diff_branch(remote) != "": # difference between index and remote - return True - elif (await get_git_commits_ahead_behind(branch, remote))[0] > 0: # ahead in commits + +async def get_git_update(branch, remote) -> bool: + commits_behind, _ = await get_git_commits_ahead_behind(branch, remote) + if commits_behind > 0: return True return False -async def get_git_update(dev_status: bool, branch, remote) -> bool: - commits_behind, _ = await get_git_commits_ahead_behind(branch, remote) - if not dev_status and commits_behind > 0: - return True - return False async def get_git_status() -> dict: output = {} output["commit_id"] = await get_git_latest_commit_id() output["branch"] = await get_git_branch() output["remote"] = await get_git_remote() - output["dev"] = await get_git_dev(output['remote'], output['branch']) - output['update'] = await get_git_update(output['dev'], output['branch'], output['remote']) + output['update'] = await get_git_update(output['branch'], output['remote']) return output + @plugin.command @lightbulb.command("ping", "pong!", ephemeral=True) @lightbulb.implements(lightbulb.SlashCommand) async def ping(ctx: lightbulb.Context) -> None: embed = hikari.Embed(title="Pong!", - description=f"latency: {round(ctx.bot.heartbeat_latency * 1000, ndigits=2)}ms" - ) + description=f"latency: {round(ctx.bot.heartbeat_latency * 1000, ndigits=2)}ms" + ) await ctx.respond(embed) + @plugin.command @lightbulb.add_checks(lightbulb.owner_only) @lightbulb.command("update", "update the bot!", ephemeral=True) @lightbulb.implements(lightbulb.SlashCommand) async def update(ctx: lightbulb.Context) -> None: - if (await get_git_status())['dev'] is False: - await create_subprocess("git", "pull") + await create_subprocess("git", "pull") embed = hikari.Embed(title="Restarting", - description="Restarting to load an update!" - ) + description="Restarting to load an update!" + ) await ctx.respond(embed) await ctx.bot.close() + +@plugin.command +@lightbulb.add_checks(lightbulb.owner_only) +@lightbulb.command("branch", "get or set the working branch the bot uses.") +@lightbulb.implements(lightbulb.SlashCommandGroup) +async def branch_group(ctx: lightbulb.Context) -> None: + pass # SlashCommandGroup body code isn't run + + +@branch_group.child +@lightbulb.add_checks(lightbulb.owner_only) +@lightbulb.command("get", "get the current branch", ephemeral=True) +@lightbulb.implements(lightbulb.SlashSubCommand) +async def branch_get(ctx: lightbulb.Context) -> None: + output = await create_subprocess("git", "rev-parse", "--symbolic-full-name", "--abbrev-ref", "HEAD") + embed = hikari.Embed(title="Current Branch", + description=f"Currently on branch '{output}'") + await ctx.respond(embed=embed) + + +@branch_group.child +@lightbulb.add_checks(lightbulb.owner_only) +@lightbulb.option("name", "name of the branch", type=str, required=True) +@lightbulb.command("switch", "switch branches", ephemeral=True) +@lightbulb.implements(lightbulb.SlashSubCommand) +async def branch_switch(ctx: lightbulb.Context) -> None: + embed = hikari.Embed(title="Restarting", + description="Restarting to switch branches!" + ) + output = await create_subprocess("git", "switch", ctx.options.name) + if "invalid reference" in output: # parsing output allows us more specificity. + embed.title = "Branch does not exist." + embed.description = "Please check your spelling." + await ctx.respond(embed) + return + elif "Already on" in output: + embed.title = f"Already on branch '{ctx.options.branch}'" + embed.description = "Just double checking, I presume?" + await ctx.respond(embed) + return + await ctx.respond(embed) + await ctx.bot.close() + + @plugin.command @lightbulb.command("info", "get bot information such as the version, and repository link.", ephemeral=True) @lightbulb.implements(lightbulb.SlashCommand) async def info(ctx: lightbulb.Context) -> None: + await create_subprocess("git", "fetch") # updates with remote git_status = await get_git_status() embed = hikari.Embed(title="About Me!") embed.add_field("Git Repository", config.git_url) embed.add_field("Version", git_status['commit_id'], inline=True) embed.add_field("Branch", git_status['branch'], inline=True) embed.add_field("Remote", git_status['remote'], inline=True) - embed.add_field("In Dev-Env?", git_status['dev']) embed.add_field("Needs Update?", git_status['update']) await ctx.respond(embed) + def load(bot: lightbulb.BotApp): bot.add_plugin(plugin) + def unload(bot: lightbulb.BotApp): bot.remove_plugin(plugin)