Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions scraper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
'''
import argparse
import os
import re
import subprocess
import tempfile
from bs4 import BeautifulSoup
Expand All @@ -22,6 +21,8 @@
help="HTML file of the workflow page")
parser.add_argument("-o", dest="output", type=str,
help="output file for PNG rendering with mermaid-cli (mmdc in $PATH)")
parser.add_argument("--title", dest="title", action="store_true",
help="include role and type in diagram title")

args = parser.parse_args()
file = args.file
Expand All @@ -32,28 +33,42 @@
always = soup.find("div", {"id": "workflow_form_always"})
rows = always.find_all("tr", class_="-table-border-left")

def get_meta():
'''
Extracts role and type from the filter selects in the HTML.

:return: tuple of (role, type) strings
'''
role_select = soup.find("select", {"name": "role_id"})
role = role_select.find("option", {"selected": "selected"}).text.strip()
type_select = soup.find("select", {"name": "type_id"})
type_ = type_select.find("option", {"selected": "selected"}).text.strip()
return role, type_

def get_status_text():
'''
Extracts a key value pair for each status mentioned in the HTML. As each status does have a
unique ID and each row in a table contains a status, the text can be extracted from the row
and get paired with the old status ID mentioned in the checkbox ID in one of the checkboxes
of the row.

:return: dictionary with status ID as key and status text as value
'''
status_dict = {}
for row in rows:
status_raw = row.find("td", class_="workflow-table--current-status -table-border-right")
status_text = re.sub(r'Alle in Zeile an\/abwählen',r'',status_raw.text.strip()).strip()
status_id = re.findall(r'(status_)(.*)(_[0-9]*_)', row.input['id'])[0][1]
status_cell = row.find("th", class_="workflow-table--current-status")
status_text = status_cell.find("span", class_="Truncate-text").text.strip()
# Use data-old-status from the first checkbox in the row as the status ID
first_checkbox = row.find("input", {"data-checkable-target": "checkbox"})
status_id = first_checkbox["data-old-status"]
status_dict[status_id] = status_text
return status_dict

def get_workflow():
'''
Creates Mermaid formatted lines for each status change in the workflow. Uses the old and new
status information which is part of the ID string of each checkbox.
Creates Mermaid formatted lines for each status change in the workflow. Uses data-old-status
and data-new-status attributes from each checkbox.

:return: list of Mermaid formatted strings for each status change in the workflow
'''
workflow_list = []
Expand All @@ -65,32 +80,35 @@ def get_workflow():
input_field['checked']
except KeyError:
continue
regex_groups = re.findall(r'(status_)([0-9]*)(_)([0-9]*)(_)', input_field['id'])
old_status = regex_groups[0][1]
new_status = regex_groups[0][3]
old_status = input_field['data-old-status']
new_status = input_field['data-new-status']
if old_status == new_status:
continue
workflow_list.append(old_status + ' --> ' + new_status)
return workflow_list

def print_mermaid(status_dict,workflow_list):
def print_mermaid(status_dict,workflow_list,role,type_):
'''
Prints out a Mermaid state diagram for the workflow.
'''
print('```mermaid')
print('stateDiagram-v2')
if role and type_:
print(f' title: {role} - {type_}')
for key, value in status_dict.items():
print(' ' + key + ': ' + value)
for line in workflow_list:
print(' ' + line)
print('```')

def generate_svg(status_dict,workflow_list):
def generate_svg(status_dict,workflow_list,role,type_):
'''
Output a PNG rendering of the workflow with mermaid-cli (requires mmdc in $PATH).
'''
with tempfile.NamedTemporaryFile(delete=False, mode='w') as tmp:
tmp.write('stateDiagram-v2\n')
if role and type_:
tmp.write(f' title: {role} - {type_}\n')
for key, value in status_dict.items():
tmp.write(f' {key}: {value}\n')
for line in workflow_list:
Expand All @@ -102,9 +120,10 @@ def generate_svg(status_dict,workflow_list):
os.remove(tmp.name)

if __name__ == "__main__":
role, type_ = get_meta() if args.title else (None, None)
status = get_status_text()
workflow = get_workflow()
if output is not None:
generate_svg(status,workflow)
generate_svg(status,workflow,role,type_)
else:
print_mermaid(status,workflow)
print_mermaid(status,workflow,role,type_)