diff --git a/README.md b/README.md
index 815fab1..2ad48c4 100644
--- a/README.md
+++ b/README.md
@@ -451,30 +451,42 @@ SVG files are printed as text currently, avoid printing them.
This module is disabled by default.
-### Github based hackerspace asset management
+### Github based asset management
-This module was written for asset (machines, tasks and todo) management with
-GitHub issues and labels.
+This module was written for asset (machines, tasks and todo) management by
+mis-using GitHub issues and labels. It has been designed to be used with hackerspace
+environment but can be extended to any purpose.
-Create labels to github that represent machines (M: ) and spaces (S: ).
-When creating issues, assign machine and/or space labels for them.
+#### Github project setup
+
+* Create labels to github that represent for example different machines and spaces.
+You can create any number of them.
+* Define label colors for each type of asset. These are called domains in this module.
+For example set all machine labels to be #B60205 and space labels to be #0E8A16. These
+can be easily picked from color chooser.
+* Edit the repository description and add a json block describing the
+label domains and their colors. For example:
+
+```
+Hackerspace machines, todo and stuff. domains={ "machines": "#B60205", "spaces" : "#0E8A16"}
+```
+
+Make sure you type the description on one line - this is a silly Github limitation.
+
+* 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".
+"Wood lathe" and "Wood working room".
-Usage:
+#### 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
+* !ghproj [domain] - List machine statuses in this domain
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
index cf545f3..1093a96 100644
--- a/modules/ghproj.py
+++ b/modules/ghproj.py
@@ -1,14 +1,75 @@
from github import Github
+import re
+import json
from modules.common.module import BotModule
+# Helper class with reusable code for github project stuff
+class GithubProject:
+ def get_domains(description):
+ p = re.compile('domains=\{.*\}')
+ matches = json.loads(p.findall(description)[0][8:])
+ return matches
+
+ def get_domain(reponame, domain):
+ g = Github()
+ repo = g.get_repo(reponame)
+ domains = GithubProject.get_domains(repo.description)
+ if(not len(domains)):
+ return None, None
+ domain_color = domains.get(domain, None)
+ if not domain_color:
+ return None, None
+
+ open_issues = repo.get_issues(state='open')
+ domain_labels = []
+ labels = repo.get_labels()
+ for label in labels:
+ if label.color == domain_color[1:]:
+ domain_labels.append(label)
+
+ domain_issues = dict()
+ domain_ok = []
+ for label in domain_labels:
+ label_issues = []
+ for issue in open_issues:
+ if label in issue.labels:
+ label_issues.append(issue)
+ if len(label_issues):
+ domain_issues[label.name] = label_issues
+ else:
+ domain_ok.append(label.name)
+
+ return domain_issues, domain_ok
+
+ def domain_to_string(reponame, issues, ok):
+ text_out = reponame + ":\n"
+ for label in issues.keys():
+ text_out = text_out + f'{label}: '
+ for issue in issues[label]:
+ # todo: add {issue.html_url} when URL previews can be disabled
+ text_out = text_out + f'[{issue.title}] '
+ text_out = text_out + f'\n'
+
+ text_out = text_out + " OK : " + ', '.join(ok)
+ return text_out
+
+ def domain_to_html(reponame, issues, ok):
+ html_out = f'{reponame}:
'
+ for label in issues.keys():
+ html_out = html_out + f'🚧 {label}: '
+ for issue in issues[label]:
+ # todo: add {issue.html_url} when URL previews can be disabled
+ html_out = html_out + f'[{issue.title}] '
+ html_out = html_out + f'
'
+
+ html_out = html_out + " OK ☑️ " + ', '.join(ok)
+ return html_out
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()
@@ -24,20 +85,18 @@ class MatrixModule(BotModule):
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)
+
+ domain = args[0]
+ reponame = self.repo_rooms.get(room.room_id, None)
+ if reponame:
+ issues, ok = GithubProject.get_domain(reponame, domain)
+ if issues or ok:
+ await self.send_domain_status(bot, room, reponame, issues, ok)
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
+ await bot.send_text(room, f'No labels with domain {domain} found.')
+ 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':
@@ -53,42 +112,14 @@ class MatrixModule(BotModule):
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)
+ async def send_domain_status(self, bot, room, reponame, issues, ok):
+ text_out = GithubProject.domain_to_string(reponame, issues, ok)
+ html_out = GithubProject.domain_to_html(reponame, issues, ok)
await bot.send_html(room, html_out, text_out)
def help(self):
- return 'Github hacklab asset management'
+ return 'Github asset management'
def get_settings(self):
data = super().get_settings()