Repository: reanahub/reana-client

Issue:
cli: list --show-deleted-runs
**Current behaviour**

The `reana-client` is showing all runs by default, included deleted ones:

```console
$ reana-client list
NAME                                RUN_NUMBER   CREATED               STARTED               ENDED                 STATUS
root6-roofit-yadage-kubernetes      1            2022-06-01T15:07:49   2022-06-01T15:08:02   2022-06-01T15:09:10   finished
root6-roofit-snakemake-kubernetes   1            2022-06-01T15:06:58   2022-06-01T15:07:11   2022-06-01T15:07:41   deleted
root6-roofit-serial-kubernetes      1            2022-06-01T15:06:18   2022-06-01T15:06:30   2022-06-01T15:06:49   finished
root6-roofit-cwl-kubernetes         1            2022-06-01T15:05:37   2022-06-01T15:05:55   2022-06-01T15:06:11   finished
```

**Expected behaviour**

In https://github.com/reanahub/reana-ui/issues/218 we are switching to exclude deleted runs from Web UI by default:

![show-deleted-runs](https://user-images.githubusercontent.com/517546/171824706-8f1015cd-f366-4134-bca5-c84f81e2d547.png)

The toggle will be "off" by default and deleted runs won't be shown by default to the Web users.

This issue is about doing the same change for CLI users.

We can achieve the same UX by introducing a new option for the `list` command:

```console
$ reana-client list --show-deleted-runs
```

so that Web UI and CLI UI would behave fully consistently.

**Notes**

**(1)** Note that the new option `--show-deleted-runs` would work orthogonally alongside `--include-progress` and `--include-workspace-size`  options, since `--show-...` would operate on rows and `-include-...` would operate on columns of the output matrix.

**(2)** Note that we may need to take care about `--filter status=deleted` and how this would play with `--show-deleted-runs`. In Web UI, we solved it by not allowing the former until the latter is flipped. We can do the same here.

**(3)** Note that this is seemingly bringing the old `reana-client` behaviour back, before we switched to showing deleted runs by default, see https://github.com/reanahub/reana-ui/issues/218 for the past motivations. However, I think that these concerns can be addressed by doing two more changes:

- in CLI, `reana-client delete` would include by default also the workspace.
- in Web UI, we won't allow to "untick" option to preserve workspace in the following screenshot:

![delete-also](https://user-images.githubusercontent.com/517546/171824240-d026f80b-1b52-409b-aca7-36d1e7993273.png)

In this way, the deletion of a workflow runs would always trigger the deletion of its workspace. If we give enough warnings to the user prior to performing deletions, I think that this should do. I cannot think of a use case where one would like to "delete" a run but "preserve" its workspace; it seems contradictory. I think we can afford removing this option.

Discussion:

Patch:
diff --git a/AUTHORS.rst b/AUTHORS.rst
index a0ebe2e..e592e55 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -19,3 +19,4 @@ The list of contributors in alphabetical order:
 - `Rokas Maciulaitis <https://orcid.org/0000-0003-1064-6967>`_
 - `Sinclert Perez <https://www.linkedin.com/in/sinclert>`_
 - `Tibor Simko <https://orcid.org/0000-0001-7202-5803>`_
+- `Vladyslav Moisieienkov <https://orcid.org/0000-0001-9717-0775>`_
diff --git a/CHANGES.rst b/CHANGES.rst
index 6c970db..71e6c7f 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -6,6 +6,8 @@ Version 0.9.0 (UNRELEASED)
 
 - Adds support for ``.reanaignore`` during file upload. Files that match ``.reanaignore`` will not be uploaded.
 - Adds support for ``.gitignore`` during file upload. Files that match ``.gitignore`` will not be uploaded.
+- Changes ``list`` to hide deleted workflows by default.
+- Changes ``list`` command to allow displaying deleted workflows via ``--all`` and ``--show-deleted-runs`` options.
 - Changes REANA specification loading and validation functionality by porting some of the logic to ``reana-commons``.
 - Fixes ``validate --environment`` command to detect illegal white space characters in image names.
 
diff --git a/reana_client/cli/utils.py b/reana_client/cli/utils.py
index 271baab..2cafbcd 100644
--- a/reana_client/cli/utils.py
+++ b/reana_client/cli/utils.py
@@ -12,7 +12,7 @@ import json
 import os
 import shlex
 import sys
-from typing import Callable, NoReturn, Optional, Union
+from typing import Callable, NoReturn, Optional, List, Tuple, Union
 
 import click
 
@@ -165,7 +165,7 @@ def parse_format_parameters(_format):
         )
 
 
-def parse_filter_parameters(filters, filter_names):
+def parse_filter_parameters(filters, filter_names) -> Tuple[List[str], str]:
     """Return parsed filter parameters."""
     try:
         status_filters = []
diff --git a/reana_client/cli/workflow.py b/reana_client/cli/workflow.py
index 2e0b07d..e33cbcc 100644
--- a/reana_client/cli/workflow.py
+++ b/reana_client/cli/workflow.py
@@ -96,8 +96,8 @@ def workflow_execution_group(ctx):
 @click.option(
     "--all",
     "show_all",
-    count=True,
-    default=True,
+    is_flag=True,
+    default=False,
     help="Show all workflows including deleted ones.",
 )
 @click.option(
@@ -135,11 +135,18 @@ def workflow_execution_group(ctx):
     default=None,
     help="Include size information of the workspace.",
 )
+@click.option(
+    "--show-deleted-runs",
+    "show_deleted_runs",
+    is_flag=True,
+    default=False,
+    help="Include deleted workflows in the output.",
+)
 @add_access_token_options
 @add_pagination_options
 @check_connection
 @click.pass_context
-def workflow_workflows(  # noqa: C901
+def workflows_list(  # noqa: C901
     ctx,
     workflow,
     sessions,
@@ -155,6 +162,7 @@ def workflow_workflows(  # noqa: C901
     filters,
     include_progress,
     include_workspace_size,
+    show_deleted_runs: bool,
 ):  # noqa: D301
     """List all workflows and sessions.
 
@@ -176,11 +184,19 @@ def workflow_workflows(  # noqa: C901
         logging.debug("{param}: {value}".format(param=p, value=ctx.params[p]))
     type = "interactive" if sessions else "batch"
 
-    status_filter = None
+    status_filter = RUN_STATUSES.copy()
+    if not show_deleted_runs and not show_all:
+        status_filter.remove("deleted")
+
     search_filter = None
     if filters:
         filter_names = ["name", "status"]
-        status_filter, search_filter = parse_filter_parameters(filters, filter_names)
+        provided_status_filter, search_filter = parse_filter_parameters(
+            filters, filter_names
+        )
+        if provided_status_filter:
+            status_filter = provided_status_filter
+
     if _format:
         parsed_format_filters = parse_format_parameters(_format)
     try:
@@ -219,8 +235,6 @@ def workflow_workflows(  # noqa: C901
         data = []
         for workflow in response:
             workflow["size"] = workflow["size"][human_readable_or_raw]
-            if workflow["status"] == "deleted" and not show_all:
-                continue
             name, run_number = get_workflow_name_and_run_number(workflow["name"])
             workflow["name"] = name
             workflow["run_number"] = run_number


Test patch:
diff --git a/tests/test_cli_workflows.py b/tests/test_cli_workflows.py
index 5625619..dd1059e 100644
--- a/tests/test_cli_workflows.py
+++ b/tests/test_cli_workflows.py
@@ -9,6 +9,7 @@
 """REANA client workflow tests."""
 
 import json
+from typing import List
 
 import pytest
 import yaml
@@ -18,6 +19,7 @@ from pytest_reana.test_utils import make_mock_api_client
 from reana_commons.config import INTERACTIVE_SESSION_TYPES
 
 from reana_client.api.client import create_workflow_from_json
+from reana_client.config import RUN_STATUSES
 from reana_client.cli import cli
 from reana_client.utils import get_workflow_status_change_msg
 
@@ -80,6 +82,38 @@ def test_workflows_server_ok():
             assert message in result.output
 
 
+@pytest.mark.parametrize(
+    "cli_options,expected_status_filter",
+    [
+        ([], [status for status in RUN_STATUSES if status != "deleted"]),
+        (["--show-deleted-runs"], RUN_STATUSES),
+        (["--all"], RUN_STATUSES),
+        (["--filter", "status=deleted"], ["deleted"]),
+        (["--filter", "status=finished", "--show-deleted-runs"], ["finished"]),
+        (["--filter", "status=finished", "--all"], ["finished"]),
+        (
+            ["--filter", "name=myworkflow"],
+            [status for status in RUN_STATUSES if status != "deleted"],
+        ),
+        (["--filter", "name=myworkflow", "--show-deleted-runs"], RUN_STATUSES),
+        (["--filter", "name=myworkflow", "--all"], RUN_STATUSES),
+    ],
+)
+def test_deleted_workflows(cli_options: List[str], expected_status_filter: List[str]):
+    """Test whatever deleted workflows are displayed correctly depending on options and filters."""
+    # we do not care what response is in this case
+    response = {"items": []}
+    env = {"REANA_SERVER_URL": "localhost"}
+    reana_token = "000000"
+    runner = CliRunner(env=env)
+    with runner.isolation():
+        with patch("reana_client.api.client.get_workflows") as mock_get_workflows:
+            mock_get_workflows.return_value = response
+            runner.invoke(cli, ["list", "-t", reana_token] + cli_options)
+            kwargs = mock_get_workflows.call_args.kwargs
+            assert kwargs["status"] == expected_status_filter
+
+
 def test_workflows_sorting():
     """Test workflows sorting."""
     response = {