From b4ba04698b8a9fa5461dcb9f39656e9753e52215 Mon Sep 17 00:00:00 2001
From: Jake Yip <jake.yip@ardc.edu.au>
Date: Thu, 8 Jun 2023 15:03:01 +1000
Subject: [PATCH] Allow multiple `--remove-tag` in `project set`

The help text for this arg says 'repeat option to delete multiple tags'.
Fix to reflect what docs says.

Also add missing test for this argument.

Change-Id: Ib1069ce7a441c1ff10d2dca05095eb6bf53e7fb6
---
 openstackclient/identity/v3/tag.py            |  5 ++-
 .../tests/unit/identity/v3/test_project.py    | 31 +++++++++++++++++--
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/openstackclient/identity/v3/tag.py b/openstackclient/identity/v3/tag.py
index 60cfb4be9b..7a93218667 100644
--- a/openstackclient/identity/v3/tag.py
+++ b/openstackclient/identity/v3/tag.py
@@ -113,6 +113,7 @@ def add_tag_option_to_parser_for_set(parser, resource_name):
     )
     parser.add_argument(
         '--remove-tag',
+        action='append',
         metavar='<tag>',
         default=[],
         help=_(
@@ -128,9 +129,7 @@ def update_tags_in_args(parsed_args, obj, args):
         args['tags'] = []
         obj.tags = []
     if parsed_args.remove_tag:
-        if parsed_args.remove_tag in obj.tags:
-            obj.tags.remove(parsed_args.remove_tag)
-        args['tags'] = list(set(obj.tags))
+        args['tags'] = list(set(obj.tags) - set(parsed_args.remove_tag))
         return
     if parsed_args.tags:
         args['tags'] = list(set(obj.tags).union(set(parsed_args.tags)))
diff --git a/openstackclient/tests/unit/identity/v3/test_project.py b/openstackclient/tests/unit/identity/v3/test_project.py
index d5d3bb1f91..70608c44e9 100644
--- a/openstackclient/tests/unit/identity/v3/test_project.py
+++ b/openstackclient/tests/unit/identity/v3/test_project.py
@@ -947,7 +947,7 @@ class TestProjectList(TestProject):
 class TestProjectSet(TestProject):
     domain = identity_fakes.FakeDomain.create_one_domain()
     project = identity_fakes.FakeProject.create_one_project(
-        attrs={'domain_id': domain.id}
+        attrs={'domain_id': domain.id, 'tags': ['tag1', 'tag2', 'tag3']}
     )
 
     def setUp(self):
@@ -1127,13 +1127,38 @@ class TestProjectSet(TestProject):
 
         result = self.cmd.take_action(parsed_args)
 
-        # Set expected values
-        kwargs = {'name': 'qwerty', 'tags': ['foo']}
+        # Set expected values. new tag is added to original tags for update.
+        kwargs = {
+            'name': 'qwerty',
+            'tags': list(set(['tag1', 'tag2', 'tag3', 'foo'])),
+        }
         # ProjectManager.update(project, name=, domain=, description=,
         #                       enabled=, **kwargs)
         self.projects_mock.update.assert_called_with(self.project.id, **kwargs)
         self.assertIsNone(result)
 
+    def test_project_remove_tags(self):
+        arglist = [
+            '--remove-tag',
+            'tag1',
+            '--remove-tag',
+            'tag2',
+            self.project.name,
+        ]
+        verifylist = [
+            ('enable', False),
+            ('disable', False),
+            ('project', self.project.name),
+            ('remove_tag', ['tag1', 'tag2']),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        result = self.cmd.take_action(parsed_args)
+
+        kwargs = {'tags': list(set(['tag3']))}
+        self.projects_mock.update.assert_called_with(self.project.id, **kwargs)
+        self.assertIsNone(result)
+
     def test_project_set_with_immutable_option(self):
         arglist = [
             '--domain',