diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java index bb573fcb34b..58255849ada 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java @@ -468,11 +468,17 @@ protected void handleTagCommand() { newTagEntity(url, ignore, metalake, name, tags).handle(); } } else if (CommandActions.REMOVE.equals(command)) { - String property = line.getOptionValue(GravitinoOptions.PROPERTY); - if (property != null) { - newRemoveTagProperty(url, ignore, metalake, getOneTag(tags), property).handle(); + boolean isTag = line.hasOption(GravitinoOptions.TAG); + if (!isTag) { + boolean force = line.hasOption(GravitinoOptions.FORCE); + newRemoveAllTags(url, ignore, metalake, name, force).handle(); } else { - newUntagEntity(url, ignore, metalake, name, tags).handle(); + String property = line.getOptionValue(GravitinoOptions.PROPERTY); + if (property != null) { + newRemoveTagProperty(url, ignore, metalake, getOneTag(tags), property).handle(); + } else { + newUntagEntity(url, ignore, metalake, name, tags).handle(); + } } } else if (CommandActions.PROPERTIES.equals(command)) { newListTagProperties(url, ignore, metalake, getOneTag(tags)).handle(); diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java index 47150fe8c36..71457a1269b 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java @@ -73,6 +73,7 @@ import org.apache.gravitino.cli.commands.MetalakeAudit; import org.apache.gravitino.cli.commands.MetalakeDetails; import org.apache.gravitino.cli.commands.OwnerDetails; +import org.apache.gravitino.cli.commands.RemoveAllTags; import org.apache.gravitino.cli.commands.RemoveCatalogProperty; import org.apache.gravitino.cli.commands.RemoveFilesetProperty; import org.apache.gravitino.cli.commands.RemoveMetalakeProperty; @@ -481,6 +482,11 @@ protected RemoveTagProperty newRemoveTagProperty( return new RemoveTagProperty(url, ignore, metalake, tag, property); } + protected RemoveAllTags newRemoveAllTags( + String url, boolean ignore, String metalake, FullName name, boolean force) { + return new RemoveAllTags(url, ignore, metalake, name, force); + } + protected ListTagProperties newListTagProperties( String url, boolean ignore, String metalake, String tag) { return new ListTagProperties(url, ignore, metalake, tag); diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveAllTags.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveAllTags.java new file mode 100644 index 00000000000..69f3bb7f0f1 --- /dev/null +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveAllTags.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.gravitino.cli.commands; + +import org.apache.gravitino.Catalog; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.Schema; +import org.apache.gravitino.cli.AreYouSure; +import org.apache.gravitino.cli.ErrorMessages; +import org.apache.gravitino.cli.FullName; +import org.apache.gravitino.client.GravitinoClient; +import org.apache.gravitino.exceptions.NoSuchCatalogException; +import org.apache.gravitino.exceptions.NoSuchMetalakeException; +import org.apache.gravitino.exceptions.NoSuchSchemaException; +import org.apache.gravitino.exceptions.NoSuchTableException; +import org.apache.gravitino.rel.Table; + +/* Removes all the tags of an entity. */ +public class RemoveAllTags extends Command { + + protected String metalake; + protected FullName name; + protected final boolean force; + + /** + * Removes all the tags of an entity + * + * @param url The URL of the Gravitino server. + * @param ignoreVersions If true don't check the client/server versions match. + * @param metalake The name of the metalake. + * @param name The name of the entity. + * @param force Force operation. + */ + public RemoveAllTags( + String url, boolean ignoreVersions, String metalake, FullName name, boolean force) { + super(url, ignoreVersions); + this.metalake = metalake; + this.name = name; + this.force = force; + } + + @Override + public void handle() { + if (!AreYouSure.really(force)) { + return; + } + String entity = "unknown"; + String[] tags = new String[0]; + try { + + GravitinoClient client = buildClient(metalake); + // TODO fileset and topic + if (name.hasTableName()) { + String catalog = name.getCatalogName(); + String schema = name.getSchemaName(); + String table = name.getTableName(); + Table gTable = + client + .loadCatalog(catalog) + .asTableCatalog() + .loadTable(NameIdentifier.of(schema, table)); + tags = gTable.supportsTags().listTags(); + if (tags.length > 0) { + gTable.supportsTags().associateTags(null, tags); + } + entity = table; + } else if (name.hasSchemaName()) { + String catalog = name.getCatalogName(); + String schema = name.getSchemaName(); + Schema gSchema = client.loadCatalog(catalog).asSchemas().loadSchema(schema); + tags = gSchema.supportsTags().listTags(); + if (tags.length > 0) { + gSchema.supportsTags().associateTags(null, tags); + } + entity = schema; + } else if (name.hasCatalogName()) { + String catalog = name.getCatalogName(); + Catalog gCatalog = client.loadCatalog(catalog); + tags = gCatalog.supportsTags().listTags(); + if (tags.length > 0) { + gCatalog.supportsTags().associateTags(null, tags); + } + entity = catalog; + } + } catch (NoSuchMetalakeException err) { + System.err.println(ErrorMessages.UNKNOWN_METALAKE); + return; + } catch (NoSuchCatalogException err) { + System.err.println(ErrorMessages.UNKNOWN_CATALOG); + return; + } catch (NoSuchSchemaException err) { + System.err.println(ErrorMessages.UNKNOWN_SCHEMA); + return; + } catch (NoSuchTableException err) { + System.err.println(ErrorMessages.UNKNOWN_TABLE); + return; + } catch (Exception exp) { + System.err.println(exp.getMessage()); + return; + } + + if (tags.length > 0) { + System.out.println( + entity + " removed tags " + String.join(",", tags) + " now tagged with nothing"); + } else { + System.out.println(entity + " has no tags"); + } + } +} diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestTagCommands.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestTagCommands.java index ebf87bbba8e..58beb02a8d8 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestTagCommands.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestTagCommands.java @@ -35,6 +35,7 @@ import org.apache.gravitino.cli.commands.ListAllTags; import org.apache.gravitino.cli.commands.ListEntityTags; import org.apache.gravitino.cli.commands.ListTagProperties; +import org.apache.gravitino.cli.commands.RemoveAllTags; import org.apache.gravitino.cli.commands.RemoveTagProperty; import org.apache.gravitino.cli.commands.SetTagProperty; import org.apache.gravitino.cli.commands.TagDetails; @@ -307,6 +308,30 @@ void testListTagPropertiesCommand() { verify(mockListProperties).handle(); } + @Test + void testDeleteAllTagCommand() { + RemoveAllTags mockRemoveAllTags = mock(RemoveAllTags.class); + when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true); + when(mockCommandLine.hasOption(GravitinoOptions.TAG)).thenReturn(false); + when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo"); + when(mockCommandLine.hasOption(GravitinoOptions.FORCE)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog.schema.table"); + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.TAG, CommandActions.REMOVE)); + doReturn(mockRemoveAllTags) + .when(commandLine) + .newRemoveAllTags( + eq(GravitinoCommandLine.DEFAULT_URL), + eq(false), + eq("metalake_demo"), + any(FullName.class), + eq(true)); + commandLine.handleCommandLine(); + verify(mockRemoveAllTags).handle(); + } + @Test void testUpdateTagCommentCommand() { UpdateTagComment mockUpdateComment = mock(UpdateTagComment.class); diff --git a/docs/cli.md b/docs/cli.md index 5324d9f016f..47d3ad121c8 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -596,6 +596,12 @@ gcli tag set --name catalog_postgres.hr --tag tagA tagB gcli tag remove --name catalog_postgres.hr --tag tagA tagB ``` +#### Remove all tags from an entity + +```bash +gcli tag remove --name catalog_postgres.hr +``` + #### List all tags on an entity ```bash