From 7fe686f147e1aa631cc69ce49fcf9f8ba8ec79ee Mon Sep 17 00:00:00 2001 From: "georgi.hristov" Date: Thu, 30 Jan 2025 15:08:09 +0000 Subject: [PATCH 1/2] PLAT-1245 - Delete command for Data Studio --- conf/reflect-config.json | 21 ++-- .../tower/cli/commands/DataStudiosCmd.java | 4 +- .../cli/commands/datastudios/DeleteCmd.java | 60 ++++++++++ .../datastudios/DataStudioDeleted.java | 42 +++++++ .../cli/datastudios/DataStudiosCmdTest.java | 111 ++++++++++++++++++ 5 files changed, 230 insertions(+), 8 deletions(-) create mode 100644 src/main/java/io/seqera/tower/cli/commands/datastudios/DeleteCmd.java create mode 100644 src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudioDeleted.java diff --git a/conf/reflect-config.json b/conf/reflect-config.json index 15bd2a69..0c64a755 100644 --- a/conf/reflect-config.json +++ b/conf/reflect-config.json @@ -1160,6 +1160,12 @@ "queryAllDeclaredMethods":true, "methods":[{"name":"","parameterTypes":[] }] }, +{ + "name":"io.seqera.tower.cli.commands.datastudios.DeleteCmd", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "methods":[{"name":"","parameterTypes":[] }] +}, { "name":"io.seqera.tower.cli.commands.datastudios.ListCmd", "allDeclaredFields":true, @@ -1179,13 +1185,13 @@ "methods":[{"name":"","parameterTypes":[] }] }, { - "name":"io.seqera.tower.cli.commands.datastudios.TemplatesCmd", + "name":"io.seqera.tower.cli.commands.datastudios.StopCmd", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "methods":[{"name":"","parameterTypes":[] }] }, { - "name":"io.seqera.tower.cli.commands.datastudios.StopCmd", + "name":"io.seqera.tower.cli.commands.datastudios.TemplatesCmd", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "methods":[{"name":"","parameterTypes":[] }] @@ -1896,25 +1902,25 @@ "queryAllDeclaredConstructors":true }, { - "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosList", + "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosCreated", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true }, { - "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosView", + "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosList", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true }, { - "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosCreated", + "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosTemplatesList", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true }, { - "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosTemplatesList", + "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosView", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true @@ -2691,7 +2697,8 @@ "name":"io.seqera.tower.model.DataStudioCheckpointDto", "allDeclaredFields":true, "queryAllDeclaredMethods":true, - "queryAllDeclaredConstructors":true + "queryAllDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":[] }, {"name":"setAuthor","parameterTypes":["io.seqera.tower.model.StudioUser"] }, {"name":"setDateCreated","parameterTypes":["java.time.OffsetDateTime"] }, {"name":"setDateSaved","parameterTypes":["java.time.OffsetDateTime"] }, {"name":"setId","parameterTypes":["java.lang.Long"] }, {"name":"setName","parameterTypes":["java.lang.String"] }] }, { "name":"io.seqera.tower.model.DataStudioComputeEnvDto", diff --git a/src/main/java/io/seqera/tower/cli/commands/DataStudiosCmd.java b/src/main/java/io/seqera/tower/cli/commands/DataStudiosCmd.java index c23c6c6e..9fe3e793 100644 --- a/src/main/java/io/seqera/tower/cli/commands/DataStudiosCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/DataStudiosCmd.java @@ -18,6 +18,7 @@ package io.seqera.tower.cli.commands; import io.seqera.tower.cli.commands.datastudios.AddCmd; +import io.seqera.tower.cli.commands.datastudios.DeleteCmd; import io.seqera.tower.cli.commands.datastudios.ListCmd; import io.seqera.tower.cli.commands.datastudios.StartAsNewCmd; import io.seqera.tower.cli.commands.datastudios.StartCmd; @@ -36,7 +37,8 @@ AddCmd.class, TemplatesCmd.class, StartAsNewCmd.class, - StopCmd.class + StopCmd.class, + DeleteCmd.class, } ) public class DataStudiosCmd extends AbstractRootCmd { diff --git a/src/main/java/io/seqera/tower/cli/commands/datastudios/DeleteCmd.java b/src/main/java/io/seqera/tower/cli/commands/datastudios/DeleteCmd.java new file mode 100644 index 00000000..d6981d43 --- /dev/null +++ b/src/main/java/io/seqera/tower/cli/commands/datastudios/DeleteCmd.java @@ -0,0 +1,60 @@ +/* + * Copyright 2021-2023, Seqera. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.seqera.tower.cli.commands.datastudios; + +import io.seqera.tower.ApiException; +import io.seqera.tower.cli.commands.global.WorkspaceOptionalOptions; +import io.seqera.tower.cli.exceptions.DataStudioNotFoundException; +import io.seqera.tower.cli.exceptions.TowerException; +import io.seqera.tower.cli.responses.Response; +import io.seqera.tower.cli.responses.datastudios.DataStudioDeleted; +import picocli.CommandLine; + +@CommandLine.Command( + name = "delete", + description = "Delete a data studio." +) +public class DeleteCmd extends AbstractStudiosCmd { + + @CommandLine.Mixin + public WorkspaceOptionalOptions workspace; + + @CommandLine.Mixin + public DataStudioRefOptions dataStudioRefOptions; + + @Override + protected Response exec() throws ApiException { + Long wspId = workspaceId(workspace.workspace); + + try { + String sessionId = getSessionId(dataStudioRefOptions, wspId); + + api().deleteDataStudio(sessionId, wspId); + + return new DataStudioDeleted(sessionId, dataStudioRefOptions.getDataStudioIdentifier(), wspId, workspaceRef(wspId)); + } catch (ApiException e) { + if (e.getCode() == 404) { + throw new DataStudioNotFoundException(dataStudioRefOptions.getDataStudioIdentifier(), workspace.workspace); + } + if (e.getCode() == 403) { + throw new TowerException(String.format("User not entitled to view studio '%s' at %s workspace", dataStudioRefOptions.getDataStudioIdentifier(), workspace.workspace)); + } + throw e; + } + } +} \ No newline at end of file diff --git a/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudioDeleted.java b/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudioDeleted.java new file mode 100644 index 00000000..2dcbb5fa --- /dev/null +++ b/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudioDeleted.java @@ -0,0 +1,42 @@ +/* + * Copyright 2021-2023, Seqera. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.seqera.tower.cli.responses.datastudios; + +import io.seqera.tower.cli.responses.Response; + +public class DataStudioDeleted extends Response { + + public final String sessionId; + public final String userSuppliedStudioIdentifier; + + public final Long workspaceId; + public final String workspaceRef; + + public DataStudioDeleted(String sessionId, String userSuppliedStudioIdentifier, Long workspaceId, String workspaceRef) { + this.sessionId = sessionId; + this.userSuppliedStudioIdentifier = userSuppliedStudioIdentifier; + this.workspaceId = workspaceId; + this.workspaceRef = workspaceRef; + } + + @Override + public String toString() { + return ansi(String.format("%n @|yellow Data Studio %s deleted at %s workspace.|@%n", userSuppliedStudioIdentifier, workspaceRef)); + } + +} diff --git a/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java b/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java index 485d6353..7594c472 100644 --- a/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java +++ b/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java @@ -21,6 +21,7 @@ import io.seqera.tower.cli.BaseCmdTest; import io.seqera.tower.cli.commands.enums.OutputType; import io.seqera.tower.cli.exceptions.MultipleDataLinksFoundException; +import io.seqera.tower.cli.responses.datastudios.DataStudioDeleted; import io.seqera.tower.cli.responses.datastudios.DataStudioStartSubmitted; import io.seqera.tower.cli.responses.datastudios.DataStudiosCreated; import io.seqera.tower.cli.responses.datastudios.DataStudioStopSubmitted; @@ -1102,4 +1103,114 @@ void testStartAsNew(OutputType format, MockServerClient mock) throws JsonProcess """, DataStudioDto.class), "[organization1 / workspace1]")); } + @ParameterizedTest + @EnumSource(OutputType.class) + void testStop(OutputType format, MockServerClient mock) { + + mock.when( + request().withMethod("GET").withPath("/user-info"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("user")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/user/1264/workspaces"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("workspaces/workspaces_list")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("PUT").withPath("/studios/3e8370e7/stop").withQueryStringParameter("workspaceId", "75887156211589"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(json(""" + { + "jobSubmitted": true, + "sessionId": "3e8370e7", + "statusInfo": { + "status": "stopping", + "message": "", + "lastUpdate": "2025-01-22T15:16:11.508692Z" + } + } + """)).withContentType(MediaType.APPLICATION_JSON) + ); + + ExecOut out = exec(format, mock, "studios", "stop", "-w", "75887156211589", "-i" ,"3e8370e7"); + + assertOutput(format, out, new DataStudioStopSubmitted("3e8370e7", "3e8370e7",75887156211589L, + "[organization1 / workspace1]", true)); + } + + @ParameterizedTest + @EnumSource(OutputType.class) + void testStopByName(OutputType format, MockServerClient mock) { + + mock.when( + request().withMethod("GET").withPath("/user-info"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("user")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/user/1264/workspaces"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("workspaces/workspaces_list")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/studios").withQueryStringParameter("workspaceId", "75887156211589"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("datastudios/datastudios_list_response")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("PUT").withPath("/studios/3e8370e7/stop").withQueryStringParameter("workspaceId", "75887156211589"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(json(""" + { + "jobSubmitted": true, + "sessionId": "3e8370e7", + "statusInfo": { + "status": "stopping", + "message": "", + "lastUpdate": "2025-01-22T15:16:11.508692Z" + } + } + """)).withContentType(MediaType.APPLICATION_JSON) + ); + + ExecOut out = exec(format, mock, "studios", "stop", "-w", "75887156211589", "-n" ,"studio-a66d"); + + assertOutput(format, out, new DataStudioStopSubmitted("3e8370e7", "studio-a66d",75887156211589L, + "[organization1 / workspace1]", true)); + } + + @ParameterizedTest + @EnumSource(OutputType.class) + void testDelete(OutputType format, MockServerClient mock) { + + mock.when( + request().withMethod("GET").withPath("/user-info"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("user")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/user/1264/workspaces"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("workspaces/workspaces_list")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("DELETE").withPath("/studios/3e8370e7").withQueryStringParameter("workspaceId", "75887156211589"), exactly(1) + ).respond( + response().withStatusCode(200).withContentType(MediaType.APPLICATION_JSON) + ); + + + ExecOut out = exec(format, mock, "studios", "delete", "-w", "75887156211589", "-i" ,"3e8370e7"); + + assertOutput(format, out, new DataStudioDeleted("3e8370e7", "3e8370e7",75887156211589L, "[organization1 / workspace1]")); + } + } From c8049b0f0436908c06b1aea41ea9964e06dff013 Mon Sep 17 00:00:00 2001 From: "georgi.hristov" Date: Thu, 30 Jan 2025 15:39:57 +0000 Subject: [PATCH 2/2] PLAT-1245 - Tweak reflection config and cleanup unnecessary fields --- conf/reflect-config.json | 6 ++++++ .../io/seqera/tower/cli/commands/datastudios/DeleteCmd.java | 2 +- .../tower/cli/responses/datastudios/DataStudioDeleted.java | 6 +----- .../io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/conf/reflect-config.json b/conf/reflect-config.json index 0c64a755..00774e85 100644 --- a/conf/reflect-config.json +++ b/conf/reflect-config.json @@ -1925,6 +1925,12 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true }, +{ + "name":"io.seqera.tower.cli.responses.datastudios.DataStudioDeleted", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true +}, { "name":"io.seqera.tower.cli.responses.labels.DeleteLabelsResponse", "allDeclaredFields":true, diff --git a/src/main/java/io/seqera/tower/cli/commands/datastudios/DeleteCmd.java b/src/main/java/io/seqera/tower/cli/commands/datastudios/DeleteCmd.java index d6981d43..ff98fc70 100644 --- a/src/main/java/io/seqera/tower/cli/commands/datastudios/DeleteCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/datastudios/DeleteCmd.java @@ -46,7 +46,7 @@ protected Response exec() throws ApiException { api().deleteDataStudio(sessionId, wspId); - return new DataStudioDeleted(sessionId, dataStudioRefOptions.getDataStudioIdentifier(), wspId, workspaceRef(wspId)); + return new DataStudioDeleted(dataStudioRefOptions.getDataStudioIdentifier(), workspaceRef(wspId)); } catch (ApiException e) { if (e.getCode() == 404) { throw new DataStudioNotFoundException(dataStudioRefOptions.getDataStudioIdentifier(), workspace.workspace); diff --git a/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudioDeleted.java b/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudioDeleted.java index 2dcbb5fa..077b7c9d 100644 --- a/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudioDeleted.java +++ b/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudioDeleted.java @@ -21,16 +21,12 @@ public class DataStudioDeleted extends Response { - public final String sessionId; public final String userSuppliedStudioIdentifier; - public final Long workspaceId; public final String workspaceRef; - public DataStudioDeleted(String sessionId, String userSuppliedStudioIdentifier, Long workspaceId, String workspaceRef) { - this.sessionId = sessionId; + public DataStudioDeleted(String userSuppliedStudioIdentifier, String workspaceRef) { this.userSuppliedStudioIdentifier = userSuppliedStudioIdentifier; - this.workspaceId = workspaceId; this.workspaceRef = workspaceRef; } diff --git a/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java b/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java index 7594c472..72c8bd27 100644 --- a/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java +++ b/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java @@ -1210,7 +1210,7 @@ void testDelete(OutputType format, MockServerClient mock) { ExecOut out = exec(format, mock, "studios", "delete", "-w", "75887156211589", "-i" ,"3e8370e7"); - assertOutput(format, out, new DataStudioDeleted("3e8370e7", "3e8370e7",75887156211589L, "[organization1 / workspace1]")); + assertOutput(format, out, new DataStudioDeleted("3e8370e7", "[organization1 / workspace1]")); } }