Refactored Github asset management code, changed to use domains and color-coded labels. See README for updated info.

This commit is contained in:
Ville Ranki 2021-02-07 23:43:37 +02:00
parent 090ccc3011
commit a84db65d93
2 changed files with 102 additions and 59 deletions

View File

@ -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

View File

@ -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'<b>{reponame}:</b> <br/>'
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'<br/>'
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,17 +85,15 @@ 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':
domain = args[0]
reponame = self.repo_rooms.get(room.room_id, None)
if reponame:
await self.get_machine_status(bot, room, reponame, self.machine_prefix)
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)
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
@ -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'<b>{reponame}:</b> <br/>'
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'<a href="{issue.html_url}">{issue.title}</a> '
text_out = text_out + f'\n'
html_out = html_out + f'<br/>'
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()