Repository: meltano/meltano

Issue:
feat: Cloud CLI - enable filtering of schedule history by `deployment` and `result`
* ~~`meltano cloud history --name=<>`~~ Covered by https://github.com/meltano/meltano/pull/7467

* `meltano cloud history --deployment=<>`

* `meltano cloud history --result=[Success|Failed|Running]`


Discussion:
@tayloramurphy does `name` refer to the schedule name?

If so, there's https://github.com/meltano/meltano/pull/7467 for that at least.
@edgarrmondragon it does - I've updated my comment

Resolving patch:
diff --git a/src/cloud-cli/meltano/cloud/cli/history/client.py b/src/cloud-cli/meltano/cloud/cli/history/client.py
--- a/src/cloud-cli/meltano/cloud/cli/history/client.py
+++ b/src/cloud-cli/meltano/cloud/cli/history/client.py
@@ -24,6 +24,8 @@ async def get_execution_history(
         self,
         *,
         schedule: str | None = None,
+        deployment: str | None = None,
+        result: str | None = None,
         page_size: int | None = None,
         page_token: str | None = None,
         start_time: datetime.datetime | None = None,
@@ -32,6 +34,8 @@ async def get_execution_history(
 
         Args:
             schedule: The name of the schedule to get the history for.
+            deployment: The name of the deployment to get the history for.
+            result: The result to filter on.
             page_size: The number of executions to return.
             page_token: The page token to use for pagination.
             start_time: The start time to use for filtering.
@@ -46,12 +50,14 @@ async def get_execution_history(
             "page_size": page_size,
             "page_token": page_token,
             "schedule": schedule,
+            "deployment": deployment,
+            "result": result,
             "start_time": start_time.isoformat() if start_time else None,
         }
 
         async with self.authenticated():
             url = (
-                "/history/v1/"
+                "/jobs/v1/"
                 f"{self.config.tenant_resource_key}/"
                 f"{self.config.internal_project_id}"
             )
@@ -73,6 +79,8 @@ async def get_history_list(
         config: MeltanoCloudConfig,
         *,
         schedule_filter: str | None,
+        deployment_filter: str | None,
+        result_filter: str | None,
         start_time: datetime.datetime | None,
         limit: int,
     ) -> list[CloudExecution]:
@@ -81,6 +89,8 @@ async def get_history_list(
         Args:
             config: The meltano config to use
             schedule_filter: Used to filter the history by schedule name.
+            environment_filter: Used to filter the history by environment name.
+            result_filter: Used to filter the history by result.
             start_time: Used to filter the history by start time.
             limit: The maximum number of history items to return.
 
@@ -95,6 +105,8 @@ async def get_history_list(
             while True:
                 response = await client.get_execution_history(
                     schedule=schedule_filter,
+                    deployment=deployment_filter,
+                    result=result_filter,
                     page_size=page_size,
                     page_token=page_token,
                     start_time=start_time,
diff --git a/src/cloud-cli/meltano/cloud/cli/history/command.py b/src/cloud-cli/meltano/cloud/cli/history/command.py
--- a/src/cloud-cli/meltano/cloud/cli/history/command.py
+++ b/src/cloud-cli/meltano/cloud/cli/history/command.py
@@ -47,7 +47,7 @@ def convert(
         return value
 
 
-def _schedule_arg_to_glob(
+def _arg_to_glob_filter(
     schedule: str | None,
     schedule_prefix: str | None,
     schedule_contains: str | None,
@@ -102,6 +102,27 @@ def _schedule_arg_to_glob(
     required=False,
     help="Match schedules that contain the specified string.",
 )
+@click.option(
+    "--deployment",
+    required=False,
+    help="Match deployments by this exact name.",
+)
+@click.option(
+    "--deployment-prefix",
+    required=False,
+    help="Match deployments that start with the specified string.",
+)
+@click.option(
+    "--deployment-contains",
+    required=False,
+    help="Match deployments that contain the specified string.",
+)
+@click.option(
+    "--result",
+    required=False,
+    type=click.Choice(["success", "failed", "running"]),
+    help="Match executions by result.",
+)
 @click.option(
     "--limit",
     required=False,
@@ -136,21 +157,32 @@ async def history(
     schedule: str | None,
     schedule_prefix: str | None,
     schedule_contains: str | None,
+    deployment: str | None,
+    deployment_prefix: str | None,
+    deployment_contains: str | None,
+    result: str | None,
     limit: int,
     output_format: str,
     lookback: datetime.timedelta | None,
 ) -> None:
     """Get a Meltano project execution history in Meltano Cloud."""
-    schedule_filter = _schedule_arg_to_glob(
+    schedule_filter = _arg_to_glob_filter(
         schedule,
         schedule_prefix,
         schedule_contains,
     )
+    deployment_filter = _arg_to_glob_filter(
+        deployment,
+        deployment_prefix,
+        deployment_contains,
+    )
 
     now = datetime.datetime.now(tz=utils.UTC)
     items = await HistoryClient.get_history_list(
         context.config,
         schedule_filter=schedule_filter,
+        deployment_filter=deployment_filter,
+        result_filter=result,
         limit=limit,
         start_time=now - lookback if lookback else None,
     )


Test patch:
diff --git a/src/cloud-cli/tests/cli/test_history.py b/src/cloud-cli/tests/cli/test_history.py
--- a/src/cloud-cli/tests/cli/test_history.py
+++ b/src/cloud-cli/tests/cli/test_history.py
@@ -94,7 +94,7 @@ class TestHistoryCommand:
 
     @pytest.fixture()
     def path(self, tenant_resource_key: str, internal_project_id: str) -> str:
-        return f"/history/v1/{tenant_resource_key}/{internal_project_id}"
+        return f"/jobs/v1/{tenant_resource_key}/{internal_project_id}"
 
     @pytest.fixture()
     def response_body(self) -> dict:
@@ -215,6 +215,36 @@ def test_filter_schedule(
 
         assert result.exit_code == 0
 
+    def test_multiple_filters(
+        self,
+        path: str,
+        config: MeltanoCloudConfig,
+        response_body: dict,
+        httpserver: HTTPServer,
+    ):
+        httpserver.expect_oneshot_request(
+            path,
+            query_string={
+                "page_size": "10",
+                "schedule": "gitlab_el",
+                "deployment": "ci*",
+                "result": "failed",
+            },
+        ).respond_with_json(response_body)
+        result = CliRunner().invoke(
+            cli,
+            (
+                "--config-path",
+                config.config_path,
+                "history",
+                "--schedule=gitlab_el",
+                "--deployment-prefix=ci",
+                "--result=failed",
+            ),
+        )
+
+        assert result.exit_code == 0
+
     @freeze_time(datetime.datetime(2023, 5, 20, tzinfo=UTC))
     @pytest.mark.parametrize(
         ("lookback", "expected_start_time"),