diff --git a/Pipfile b/Pipfile index 52a7718..8b39412 100644 --- a/Pipfile +++ b/Pipfile @@ -19,6 +19,7 @@ PyYAML = "==5.3" wolframalpha = "*" Mastodon-py = "*" pycups = "*" +pygithub = "*" [dev-packages] pylint = "*" diff --git a/README.md b/README.md index bf99965..815fab1 100644 --- a/README.md +++ b/README.md @@ -451,6 +451,30 @@ SVG files are printed as text currently, avoid printing them. This module is disabled by default. +### Github based hackerspace asset management + +This module was written for asset (machines, tasks and todo) management with +GitHub issues and labels. + +Create labels to github that represent machines (M: ) and spaces (S: ). +When creating issues, assign machine and/or space labels for them. +For example, if a wood lathe is broken, create issue with labels +"M: Wood lathe" and "S: Wood working room". + +Usage: + +* !ghproj setrepo [repository] - Set repository for this room (room admin only) +* !ghproj repo - Shows which repository this room tracks +* !ghproj rmrepo - Remove repository from this room (room admin only) +* !ghproj machines - List machine statuses for this room +* !ghproj spaces - List statuses of spaces + +Repository name must be in format TampereHacklab/Inventaario - you can +use this as a example to see how the labels work. + +In future this might be used as general purpose project management +module. PR's welcome! + ## Bot setup * Create a Matrix user diff --git a/modules/ghproj.py b/modules/ghproj.py new file mode 100644 index 0000000..cf545f3 --- /dev/null +++ b/modules/ghproj.py @@ -0,0 +1,101 @@ +from github import Github + +from modules.common.module import BotModule + + +class MatrixModule(BotModule): + def __init__(self, name): + super().__init__(name) + self.repo_rooms = dict() + self.machine_prefix = "M: " + self.space_prefix = "S: " + + async def matrix_message(self, bot, room, event): + args = event.body.split() + args.pop(0) + + if len(args) == 1: + if args[0] == 'rmrepo': + bot.must_be_admin(room, event) + del self.repo_rooms[room.room_id] + await bot.send_text(room, 'Github repo removed from this room.') + bot.save_settings() + return + if args[0] == 'repo': + await bot.send_text(room, f'Github repo for this room is {self.repo_rooms.get(room.room_id, "not set")}.') + return + if args[0] == 'machines': + reponame = self.repo_rooms.get(room.room_id, None) + if reponame: + await self.get_machine_status(bot, room, reponame, self.machine_prefix) + else: + await bot.send_text(room, f'No github repo set for this room. Use setrepo to set it.') + return + if args[0] == 'spaces': + reponame = self.repo_rooms.get(room.room_id, None) + if reponame: + await self.get_machine_status(bot, room, reponame, self.space_prefix) + else: + await bot.send_text(room, f'No github repo set for this room. Use setrepo to set it.') + return + + if len(args) == 2: + if args[0] == 'setrepo': + bot.must_be_admin(room, event) + + reponame = args[1] + self.logger.info(f'Adding repo {reponame} to room id {room.room_id}') + + self.repo_rooms[room.room_id] = reponame + await bot.send_text(room, f'Github repo {reponame} set to this room.') + bot.save_settings() + return + + await bot.send_text(room, 'Unknown command') + + async def get_machine_status(self, bot, room, reponame, prefix): + g = Github() + repo = g.get_repo(reponame) + open_issues = repo.get_issues(state='open') + labels = repo.get_labels() + machine_status = dict() + working_machines = [] + for label in labels: + if prefix in label.name: + machine_name = label.name[len(prefix):] + machine_status[machine_name] = [] + for issue in open_issues: + if label in issue.labels: + machine_status[machine_name].append(issue) + if not machine_status[machine_name]: + working_machines.append(machine_name) + del machine_status[machine_name] + + text_out = reponame + ":\n" + html_out = f'{reponame}:
' + for machine in machine_status.keys(): + text_out = text_out + f'{machine}: ' + html_out = html_out + f'🚧 {machine}: ' + for issue in machine_status[machine]: + text_out = text_out + f'{issue.title} ({issue.html_url}) ' + html_out = html_out + f'{issue.title} ' + text_out = text_out + f'\n' + html_out = html_out + f'
' + + text_out = text_out + " OK : " + ', '.join(working_machines) + html_out = html_out + " OK ☑️ " + ', '.join(working_machines) + await bot.send_html(room, html_out, text_out) + + + def help(self): + return 'Github hacklab asset management' + + def get_settings(self): + data = super().get_settings() + data["repo_rooms"] = self.repo_rooms + return data + + def set_settings(self, data): + super().set_settings(data) + if data.get("repo_rooms"): + self.repo_rooms = data["repo_rooms"]