Repository: tonybaloney/wily

Issue:
Allow report to only display revisions that have changes
Reports can have many lines with zero changes or "not found", adding a lot of noise.

**Describe the solution you'd like**
I'd like to be able to generate reports that omit those, in a similar way to the `graph` command.

I have working code for this, will submit a PR so we can discuss implementation (while desirability is still undecided).

Discussion:

Patch:
diff --git a/src/wily/__main__.py b/src/wily/__main__.py
index 6f08850..48b12cd 100644
--- a/src/wily/__main__.py
+++ b/src/wily/__main__.py
@@ -252,8 +252,16 @@ def rank(ctx, path, metric, revision, limit, desc, threshold):
     "--output",
     help=_("Output report to specified HTML path, e.g. reports/out.html"),
 )
+@click.option(
+    "-c",
+    "--changes/--all",
+    default=False,
+    help=_("Only show revisions that have changes"),
+)
 @click.pass_context
-def report(ctx, file, metrics, number, message, format, console_format, output):
+def report(
+    ctx, file, metrics, number, message, format, console_format, output, changes
+):
     """Show metrics for a given file."""
     config = ctx.obj["CONFIG"]
 
@@ -284,6 +292,7 @@ def report(ctx, file, metrics, number, message, format, console_format, output):
         include_message=message,
         format=ReportFormat[format],
         console_format=console_format,
+        changes_only=changes,
     )
 
 
diff --git a/src/wily/commands/report.py b/src/wily/commands/report.py
index 28fd47a..5ce834c 100644
--- a/src/wily/commands/report.py
+++ b/src/wily/commands/report.py
@@ -30,6 +30,7 @@ def report(
     include_message=False,
     format=ReportFormat.CONSOLE,
     console_format=None,
+    changes_only=False,
 ):
     """
     Show information about the cache and runtime.
@@ -57,6 +58,9 @@ def report(
 
     :param console_format: Grid format style for tabulate
     :type  console_format: ``str``
+
+    :param changes_only: Only report revisions where delta != 0
+    :type  changes_only: ``bool``
     """
     metrics = sorted(metrics)
     logger.debug("Running report command")
@@ -97,6 +101,7 @@ def report(
         history = state.index[archiver].revisions[:n][::-1]
         last = {}
         for rev in history:
+            deltas = []
             vals = []
             for meta in metric_metas:
                 try:
@@ -134,26 +139,29 @@ def report(
                         k = f"{val}"
                 except KeyError as e:
                     k = f"Not found {e}"
+                    delta = 0
+                deltas.append(delta)
                 vals.append(k)
-            if include_message:
-                data.append(
-                    (
-                        format_revision(rev.revision.key),
-                        rev.revision.message[:MAX_MESSAGE_WIDTH],
-                        rev.revision.author_name,
-                        format_date(rev.revision.date),
-                        *vals,
+            if not changes_only or any(deltas):
+                if include_message:
+                    data.append(
+                        (
+                            format_revision(rev.revision.key),
+                            rev.revision.message[:MAX_MESSAGE_WIDTH],
+                            rev.revision.author_name,
+                            format_date(rev.revision.date),
+                            *vals,
+                        )
                     )
-                )
-            else:
-                data.append(
-                    (
-                        format_revision(rev.revision.key),
-                        rev.revision.author_name,
-                        format_date(rev.revision.date),
-                        *vals,
+                else:
+                    data.append(
+                        (
+                            format_revision(rev.revision.key),
+                            rev.revision.author_name,
+                            format_date(rev.revision.date),
+                            *vals,
+                        )
                     )
-                )
     descriptions = [meta["title"] for meta in metric_metas]
     if include_message:
         headers = (_("Revision"), _("Message"), _("Author"), _("Date"), *descriptions)


Test patch:
diff --git a/test/integration/test_report.py b/test/integration/test_report.py
index 571c1b4..cdc85d3 100644
--- a/test/integration/test_report.py
+++ b/test/integration/test_report.py
@@ -112,6 +112,20 @@ def test_report_with_message_and_n(builddir):
     assert "Not found" not in result.stdout
 
 
+def test_report_changes_only(builddir):
+    """
+    Test that report works when only displaying changes
+    """
+    runner = CliRunner()
+    result = runner.invoke(
+        main.cli, ["--path", builddir, "report", _path, "raw.multi", "-c"]
+    )
+    assert result.exit_code == 0, result.stdout
+    assert "basic test" not in result.stdout
+    assert "remove line" not in result.stdout
+    assert "Not found" not in result.stdout
+
+
 def test_report_high_metric(builddir):
     """
     Test that report works with a build on a metric expecting high values