adding json export for spack blame (#23417)
I would like to be able to export (and save and then load programatically) spack blame metadata, so this commit adds a spack blame --json argument, along with developer docs for it Signed-off-by: vsoch <vsoch@users.noreply.github.com> Co-authored-by: vsoch <vsoch@users.noreply.github.com>
This commit is contained in:
parent
b44bb952eb
commit
3cef5663d8
@ -867,6 +867,50 @@ just like you would with the normal ``python`` command.
|
||||
|
||||
.. _cmd-spack-url:
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^^
|
||||
``spack blame``
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Spack blame is a way to quickly see contributors to packages or files
|
||||
in the spack repository. You should provide a target package name or
|
||||
file name to the command. Here is an example asking to see contributions
|
||||
for the package "python":
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack blame python
|
||||
LAST_COMMIT LINES % AUTHOR EMAIL
|
||||
2 weeks ago 3 0.3 Mickey Mouse <cheddar@gmouse.org>
|
||||
a month ago 927 99.7 Minnie Mouse <swiss@mouse.org>
|
||||
|
||||
2 weeks ago 930 100.0
|
||||
|
||||
|
||||
By default, you will get a table view (shown above) sorted by date of contribution,
|
||||
with the most recent contribution at the top. If you want to sort instead
|
||||
by percentage of code contribution, then add ``-p``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack blame -p python
|
||||
|
||||
|
||||
And to see the git blame view, add ``-g`` instead:
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack blame -g python
|
||||
|
||||
|
||||
Finally, to get a json export of the data, add ``--json``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack blame --json python
|
||||
|
||||
|
||||
^^^^^^^^^^^^^
|
||||
``spack url``
|
||||
^^^^^^^^^^^^^
|
||||
|
@ -5,11 +5,13 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.lang import pretty_date
|
||||
from llnl.util.filesystem import working_dir
|
||||
from llnl.util.tty.colify import colify_table
|
||||
import spack.util.spack_json as sjson
|
||||
|
||||
import spack.paths
|
||||
import spack.repo
|
||||
@ -33,12 +35,57 @@ def setup_parser(subparser):
|
||||
view_group.add_argument(
|
||||
'-g', '--git', dest='view', action='store_const', const='git',
|
||||
help='show git blame output instead of summary')
|
||||
subparser.add_argument(
|
||||
"--json", action="store_true", default=False,
|
||||
help="output blame as machine-readable json records")
|
||||
|
||||
subparser.add_argument(
|
||||
'package_or_file', help='name of package to show contributions for, '
|
||||
'or path to a file in the spack repo')
|
||||
|
||||
|
||||
def print_table(rows, last_mod, total_lines, emails):
|
||||
"""
|
||||
Given a set of rows with authors and lines, print a table.
|
||||
"""
|
||||
table = [['LAST_COMMIT', 'LINES', '%', 'AUTHOR', 'EMAIL']]
|
||||
for author, nlines in rows:
|
||||
table += [[
|
||||
pretty_date(last_mod[author]),
|
||||
nlines,
|
||||
round(nlines / float(total_lines) * 100, 1),
|
||||
author,
|
||||
emails[author]]]
|
||||
|
||||
table += [[''] * 5]
|
||||
table += [[pretty_date(max(last_mod.values())), total_lines, '100.0'] +
|
||||
[''] * 3]
|
||||
|
||||
colify_table(table)
|
||||
|
||||
|
||||
def dump_json(rows, last_mod, total_lines, emails):
|
||||
"""
|
||||
Dump the blame as a json object to the terminal.
|
||||
"""
|
||||
result = {}
|
||||
authors = []
|
||||
for author, nlines in rows:
|
||||
authors.append({
|
||||
"last_commit": pretty_date(last_mod[author]),
|
||||
"lines": nlines,
|
||||
"percentage": round(nlines / float(total_lines) * 100, 1),
|
||||
"author": author,
|
||||
"email": emails[author]
|
||||
})
|
||||
|
||||
result['authors'] = authors
|
||||
result["totals"] = {"last_commit": pretty_date(max(last_mod.values())),
|
||||
"lines": total_lines, "percentage": "100.0"}
|
||||
|
||||
sjson.dump(result, sys.stdout)
|
||||
|
||||
|
||||
def blame(parser, args):
|
||||
# make sure this is a git repo
|
||||
if not spack_is_git_repo():
|
||||
@ -96,18 +143,10 @@ def blame(parser, args):
|
||||
else: # args.view == 'percent'
|
||||
rows = sorted(counts.items(), key=lambda t: t[1], reverse=True)
|
||||
|
||||
# Dump as json
|
||||
if args.json:
|
||||
dump_json(rows, last_mod, total_lines, emails)
|
||||
|
||||
# Print a nice table with authors and emails
|
||||
table = [['LAST_COMMIT', 'LINES', '%', 'AUTHOR', 'EMAIL']]
|
||||
for author, nlines in rows:
|
||||
table += [[
|
||||
pretty_date(last_mod[author]),
|
||||
nlines,
|
||||
round(nlines / float(total_lines) * 100, 1),
|
||||
author,
|
||||
emails[author]]]
|
||||
|
||||
table += [[''] * 5]
|
||||
table += [[pretty_date(max(last_mod.values())), total_lines, '100.0'] +
|
||||
[''] * 3]
|
||||
|
||||
colify_table(table)
|
||||
else:
|
||||
print_table(rows, last_mod, total_lines, emails)
|
||||
|
@ -6,6 +6,7 @@
|
||||
import pytest
|
||||
|
||||
from llnl.util.filesystem import working_dir
|
||||
import spack.util.spack_json as sjson
|
||||
|
||||
import spack.paths
|
||||
import spack.cmd
|
||||
@ -44,6 +45,29 @@ def test_blame_file(mock_packages):
|
||||
assert 'EMAIL' in out
|
||||
|
||||
|
||||
def test_blame_json(mock_packages):
|
||||
"""Ensure that we can output json as a blame."""
|
||||
with working_dir(spack.paths.prefix):
|
||||
out = blame('--json', 'mpich')
|
||||
|
||||
# Test loading the json, and top level keys
|
||||
loaded = sjson.load(out)
|
||||
assert "authors" in out
|
||||
assert "totals" in out
|
||||
|
||||
# Authors should be a list
|
||||
assert len(loaded['authors']) > 0
|
||||
|
||||
# Each of authors and totals has these shared keys
|
||||
keys = ["last_commit", "lines", "percentage"]
|
||||
for key in keys:
|
||||
assert key in loaded['totals']
|
||||
|
||||
# But authors is a list of multiple
|
||||
for key in keys + ["author", "email"]:
|
||||
assert key in loaded['authors'][0]
|
||||
|
||||
|
||||
def test_blame_by_git(mock_packages, capfd):
|
||||
"""Sanity check the blame command to make sure it works."""
|
||||
with capfd.disabled():
|
||||
|
@ -384,7 +384,7 @@ _spack_arch() {
|
||||
_spack_blame() {
|
||||
if $list_options
|
||||
then
|
||||
SPACK_COMPREPLY="-h --help -t --time -p --percent -g --git"
|
||||
SPACK_COMPREPLY="-h --help -t --time -p --percent -g --git --json"
|
||||
else
|
||||
_all_packages
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user