Add /branch command #1

Merged
InValidFire merged 12 commits from test into main 2022-08-20 16:07:54 +00:00
2 changed files with 98 additions and 41 deletions

View file

@ -15,17 +15,19 @@ from lib.ocr import get_room_data, NoMatchException
plugin = lightbulb.Plugin("LibCal") plugin = lightbulb.Plugin("LibCal")
config = load_config() config = load_config()
def add_rooms_to_embed(room_list: list[Room], embed: hikari.Embed): def add_rooms_to_embed(room_list: list[Room], embed: hikari.Embed):
for room in room_list: for room in room_list:
embed.add_field(room.get_time_str(), room.number) embed.add_field(room.get_time_str(), room.number)
class BookingConfirmationView(miru.View): 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 self.room_list = room_list
if image is not None:
self.image = image self.image = image
else: self.private = private
self.image = None
super().__init__(timeout=timeout, autodefer=autodefer) super().__init__(timeout=timeout, autodefer=autodefer)
@miru.button(label="Yes", style=hikari.ButtonStyle.SUCCESS) @miru.button(label="Yes", style=hikari.ButtonStyle.SUCCESS)
@ -35,10 +37,13 @@ class BookingConfirmationView(miru.View):
await gcal.create_event(room.number, room.start_time, room.end_time) await gcal.create_event(room.number, room.start_time, room.end_time)
embed = hikari.Embed(title="Rooms Booked!") embed = hikari.Embed(title="Rooms Booked!")
add_rooms_to_embed(self.room_list, embed) add_rooms_to_embed(self.room_list, embed)
embed.set_image(self.image)
await ctx.edit_response(embed=embed, components=[]) await ctx.edit_response(embed=embed, components=[])
thread_embed = hikari.Embed(title="Rooms were booked!") thread_embed = hikari.Embed(title="Rooms were booked!")
thread_embed.set_author(name=ctx.user.username, icon=ctx.user.avatar_url) thread_embed.set_author(
name=ctx.user.username, icon=ctx.user.avatar_url)
if not self.private:
thread_embed.set_image(self.image) thread_embed.set_image(self.image)
add_rooms_to_embed(self.room_list, 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) await ctx.app.rest.create_message(config.discord_study_room_thread, embed=thread_embed)
@ -47,11 +52,15 @@ class BookingConfirmationView(miru.View):
@miru.button(label="No", style=hikari.ButtonStyle.DANGER) @miru.button(label="No", style=hikari.ButtonStyle.DANGER)
async def cancel_button(self, button: miru.Button, ctx: miru.Context) -> None: async def cancel_button(self, button: miru.Button, ctx: miru.Context) -> None:
embed = hikari.Embed(title="Aborted!") 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=[]) await ctx.edit_response(embed=embed, components=[])
self.stop() self.stop()
@plugin.command @plugin.command
@lightbulb.option("img", "image to check for events", type=hikari.Attachment, required=True) @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.command("book", "add room bookings to Google Calendar", ephemeral=True)
@lightbulb.implements(lightbulb.SlashCommand) @lightbulb.implements(lightbulb.SlashCommand)
async def book(ctx: lightbulb.Context) -> None: 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) add_rooms_to_embed(room_list, response)
response.title = "Room Bookings" response.title = "Room Bookings"
response.description = "Are the booking(s) correct?" 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()) resp = await ctx.respond(response, components=view.build())
view.start(await resp.message()) view.start(await resp.message())
@ -70,7 +81,8 @@ async def book(ctx: lightbulb.Context) -> None:
async def book_error_handler(event: lightbulb.CommandErrorEvent): async def book_error_handler(event: lightbulb.CommandErrorEvent):
print("ERROR TYPE:", type(event.exception)) print("ERROR TYPE:", type(event.exception))
if isinstance(event.exception.__cause__, NoMatchException): 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) await event.context.respond(embed=embed)
else: else:
embed = hikari.Embed( embed = hikari.Embed(

View file

@ -9,6 +9,7 @@ config = load_config()
plugin = lightbulb.Plugin("SystemPlugin") plugin = lightbulb.Plugin("SystemPlugin")
async def create_subprocess(*args): async def create_subprocess(*args):
proc = await asyncio.create_subprocess_exec(*args, proc = await asyncio.create_subprocess_exec(*args,
stdout=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
@ -17,24 +18,32 @@ async def create_subprocess(*args):
stdout, _ = await proc.communicate() stdout, _ = await proc.communicate()
return stdout.decode("utf-8").strip() return stdout.decode("utf-8").strip()
async def get_git_latest_commit_id(): async def get_git_latest_commit_id():
return await create_subprocess("git", "rev-parse", "--short", "HEAD") return await create_subprocess("git", "rev-parse", "--short", "HEAD")
async def get_git_branch(): async def get_git_branch():
return await create_subprocess("git", "rev-parse", "--abbrev-ref", "HEAD") return await create_subprocess("git", "rev-parse", "--abbrev-ref", "HEAD")
async def get_git_remote(): async def get_git_remote():
remote = await create_subprocess("git", "branch", "-vv") 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: async def get_git_head_diff_branch(branch: str) -> str:
# diff HEAD to remote # diff HEAD to remote
return await create_subprocess("git", "diff", "head", branch) return await create_subprocess("git", "diff", "head", branch)
async def get_git_index_diff_branch(branch: str) -> str: async def get_git_index_diff_branch(branch: str) -> str:
# diff index to remote # diff index to remote
return await create_subprocess("git", "diff", branch) return await create_subprocess("git", "diff", branch)
async def get_git_commits_ahead_behind(branch: str, remote: str) -> tuple[int, int]: async def get_git_commits_ahead_behind(branch: str, remote: str) -> tuple[int, int]:
# commits ahead/behind remote # commits ahead/behind remote
output = await create_subprocess("git", "rev-list", "--left-right", "--count", branch+"..."+remote) output = await create_subprocess("git", "rev-list", "--left-right", "--count", branch+"..."+remote)
@ -42,33 +51,23 @@ async def get_git_commits_ahead_behind(branch: str, remote: str) -> tuple[int, i
commits_behind = int(output.split()[1]) commits_behind = int(output.split()[1])
return commits_ahead, commits_behind return commits_ahead, commits_behind
async def get_git_dev(remote: str, branch: str) -> bool:
# dev environment tests async def get_git_update(branch, remote) -> bool:
if await get_git_head_diff_branch(remote) != "": # difference between HEAD and remote commits_behind, _ = await get_git_commits_ahead_behind(branch, remote)
return True if commits_behind > 0:
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
return True return True
return False 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: async def get_git_status() -> dict:
output = {} output = {}
output["commit_id"] = await get_git_latest_commit_id() output["commit_id"] = await get_git_latest_commit_id()
output["branch"] = await get_git_branch() output["branch"] = await get_git_branch()
output["remote"] = await get_git_remote() output["remote"] = await get_git_remote()
output["dev"] = await get_git_dev(output['remote'], output['branch']) output['update'] = await get_git_update(output['branch'], output['remote'])
output['update'] = await get_git_update(output['dev'], output['branch'], output['remote'])
return output return output
@plugin.command @plugin.command
@lightbulb.command("ping", "pong!", ephemeral=True) @lightbulb.command("ping", "pong!", ephemeral=True)
@lightbulb.implements(lightbulb.SlashCommand) @lightbulb.implements(lightbulb.SlashCommand)
@ -78,12 +77,12 @@ async def ping(ctx: lightbulb.Context) -> None:
) )
await ctx.respond(embed) await ctx.respond(embed)
@plugin.command @plugin.command
@lightbulb.add_checks(lightbulb.owner_only) @lightbulb.add_checks(lightbulb.owner_only)
@lightbulb.command("update", "update the bot!", ephemeral=True) @lightbulb.command("update", "update the bot!", ephemeral=True)
@lightbulb.implements(lightbulb.SlashCommand) @lightbulb.implements(lightbulb.SlashCommand)
async def update(ctx: lightbulb.Context) -> None: 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", embed = hikari.Embed(title="Restarting",
description="Restarting to load an update!" description="Restarting to load an update!"
@ -91,22 +90,68 @@ async def update(ctx: lightbulb.Context) -> None:
await ctx.respond(embed) await ctx.respond(embed)
await ctx.bot.close() 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 @plugin.command
@lightbulb.command("info", "get bot information such as the version, and repository link.", ephemeral=True) @lightbulb.command("info", "get bot information such as the version, and repository link.", ephemeral=True)
@lightbulb.implements(lightbulb.SlashCommand) @lightbulb.implements(lightbulb.SlashCommand)
async def info(ctx: lightbulb.Context) -> None: async def info(ctx: lightbulb.Context) -> None:
await create_subprocess("git", "fetch") # updates with remote
git_status = await get_git_status() git_status = await get_git_status()
embed = hikari.Embed(title="About Me!") embed = hikari.Embed(title="About Me!")
embed.add_field("Git Repository", config.git_url) embed.add_field("Git Repository", config.git_url)
embed.add_field("Version", git_status['commit_id'], inline=True) embed.add_field("Version", git_status['commit_id'], inline=True)
embed.add_field("Branch", git_status['branch'], inline=True) embed.add_field("Branch", git_status['branch'], inline=True)
embed.add_field("Remote", git_status['remote'], 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']) embed.add_field("Needs Update?", git_status['update'])
await ctx.respond(embed) await ctx.respond(embed)
def load(bot: lightbulb.BotApp): def load(bot: lightbulb.BotApp):
bot.add_plugin(plugin) bot.add_plugin(plugin)
def unload(bot: lightbulb.BotApp): def unload(bot: lightbulb.BotApp):
bot.remove_plugin(plugin) bot.remove_plugin(plugin)