From 7846326e24ef03135dc1bafc666b63b5ed32c857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Corr=C3=AAa=20da=20Silva=20Sanches?= Date: Wed, 9 May 2018 01:36:09 -0300 Subject: [PATCH] implementing github markdown output meant to be used on github pull-requests (likely automated by Marc Foley's tooling for onboarding fonts into the google/fonts git repo) (issue #1754) --- .../commands/check_specification.py | 80 ++++++++++++++++++- Lib/fontbakery/reporters/serialize.py | 5 ++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/Lib/fontbakery/commands/check_specification.py b/Lib/fontbakery/commands/check_specification.py index b61bdc1290..5109da77c0 100644 --- a/Lib/fontbakery/commands/check_specification.py +++ b/Lib/fontbakery/commands/check_specification.py @@ -26,6 +26,7 @@ , FAIL , STARTSECTION , ENDSECTION + , Status ) log_levels = OrderedDict((s.name,s) for s in sorted(( @@ -100,6 +101,10 @@ def log_levels_get(key): metavar= 'JSON_FILE', help='Write a json formatted report to JSON_FILE.') + argument_parser.add_argument('--ghmarkdown', default=False, type=argparse.FileType('w'), + metavar= 'MD_FILE', + help='Write a GitHub-Markdown formatted report to MD_FILE.') + iterargs = sorted(specification.iterargs.keys()) def commandline_unicode_arg(bytestring): @@ -259,7 +264,8 @@ def main(specification=None, values=None): ) reporters = [tr.receive] - if args.json: + + if args.json or args.ghmarkdown: sr = SerializeReporter(runner=runner, collect_results_by=args.gather_by) reporters.append(sr.receive) distribute_generator(runner.run(), reporters) @@ -268,6 +274,78 @@ def main(specification=None, values=None): import json json.dump(sr.getdoc(), args.json, sort_keys=True, indent=4) + if args.ghmarkdown: + data = sr.getdoc() + from random import randint + pass_emoticon = [":croissant:", + ":cake:", + ":doughnut:", + ":bread:"][randint(0, 3)] + def emoticon(name): + return {'ERROR': ':broken_heart:', + 'FAIL': ':fire:', + 'WARN': ':warning:', + 'INFO': ':information_source:', + 'SKIP': ':zzz:', + 'PASS': pass_emoticon, + }[name] + + def html5_collapsible(summary, details): + return """ +
+ {} +{} +
+ """.format(summary, details) + + def log_md(log): + return " * **{}:** {}\n".format(log["status"], log["message"]) + + def check_md(check): + checkid = check["key"][1].split(":")[1].split(">")[0] + + logs = "".join(map(log_md, check["logs"])) + github_search_url = ("[{}](https://github.com/googlefonts/fontbakery/" + "search?q={})").format(checkid, checkid) + return html5_collapsible("{} {}: {}".format(emoticon(check["result"]), + check["result"], + check["description"]), + "\n* {}\n{}".format(github_search_url, + logs)) + summary_table = ("### Summary\n\n" + "| {} ERROR | {} FAIL | {} WARN | {} SKIP | {} INFO | {} PASS |\n" + "").format(*[emoticon(k) for k in ["ERROR","FAIL","WARN","SKIP","INFO","PASS"]]) + \ + ("|:-----:|:----:|:----:|:----:|:----:|:----:|\n" + "| {} | {} | {} | {} | {} | {} |\n" + "").format(*[data["result"][k] for k in ["ERROR","FAIL","WARN","SKIP","INFO","PASS"]]) + checks = {} + family_checks = [] + for section in data["sections"]: + for check in section["checks"]: + if args.loglevels and (args.loglevels[0] > Status(check["result"])): + continue + + if check["key"][2] == (): # That's a family check! + family_checks.append(check) + else: + key = os.path.basename(check["filename"]) + if key not in checks: + checks[key] = [] + checks[key].append(check) + + family_checks.sort(key=lambda c: c["result"]) + md = html5_collapsible("[{}] Family checks".format(len(family_checks)), + "".join(map(check_md, family_checks)) + "
") + + for filename in checks.keys(): + checks[filename].sort(key=lambda c: c["result"]) + md += html5_collapsible("[{}] {}".format(len(checks[filename]), + filename), + "".join(map(check_md, checks[filename])) + "
") + + md += "\n" + summary_table + args.ghmarkdown.write(md) + # Fail and error let the command fail return 1 if tr.worst_check_status in (ERROR, FAIL) else 0 diff --git a/Lib/fontbakery/reporters/serialize.py b/Lib/fontbakery/reporters/serialize.py index 5ac74fa73c..3ee80c99c6 100644 --- a/Lib/fontbakery/reporters/serialize.py +++ b/Lib/fontbakery/reporters/serialize.py @@ -96,6 +96,11 @@ def _register(self, event): item['clustered']['value'] = value self._set_metadata(identity, item) + if check: + item['description'] = check.description + if item["key"][2] != (): + item['filename'] = self.runner.get_iterarg(*item["key"][2][0]) + if status in (END, ENDSECTION): item['result'] = message # is a Counter if status == ENDCHECK: