diff --git a/pagure/cli/admin.py b/pagure/cli/admin.py index 7afa5af..583e591 100644 --- a/pagure/cli/admin.py +++ b/pagure/cli/admin.py @@ -387,6 +387,32 @@ def _parser_ensure_project_hooks(subparser): local_parser.set_defaults(func=do_ensure_project_hooks) +def _parser_delete_project(subparser): + """ Set up the CLI argument parser for the delete-project action. + + :arg subparser: an argparse subparser allowing to have action's specific + arguments + + """ + local_parser = subparser.add_parser( + "delete-project", help="Delete the project specified" + ) + local_parser.add_argument( + "--user", help="User of the project (to use only on forks)" + ) + local_parser.add_argument( + "project", + help="Project to update (as namespace/project if there " + "is a namespace)", + ) + local_parser.add_argument( + "action_user", + help="Username of the user doing the action (ie: deleting the " + "project)", + ) + local_parser.set_defaults(func=do_delete_project) + + def parse_arguments(args=None): """ Set-up the argument parsing. """ parser = argparse.ArgumentParser( @@ -442,6 +468,9 @@ def parse_arguments(args=None): # ensure-project-hooks _parser_ensure_project_hooks(subparser) + # delete-project + _parser_delete_project(subparser) + return parser.parse_args(args) @@ -708,6 +737,45 @@ def do_create_admin_token(args): ) +def do_delete_project(args): + """ Delete a project. + + :arg args: the argparse object returned by ``parse_arguments()``. + + """ + _log.debug("project: %s", args.project) + _log.debug("user: %s", args.user) + _log.debug("user deleting: %s", args.action_user) + + # Validate users + pagure.lib.query.get_user(session, args.user) + pagure.lib.query.get_user(session, args.action_user) + + # Get the project + project = _get_project(args.project, user=args.user) + + if project is None: + raise pagure.exceptions.PagureException( + "No project found with: %s" % args.project + ) + + print( + "Are you sure you want to delete: %s?\n This cannot be undone!" + % project.fullname + ) + if not _ask_confirmation(): + return + + pagure.lib.tasks.delete_project( + namespace=project.namespace, + name=project.name, + user=project.user.user if project.is_fork else None, + action_user=args.action_user, + ) + session.commit() + print("Project deleted") + + def do_get_watch_status(args): """ Get the watch status of an user on a project. diff --git a/tests/test_pagure_admin.py b/tests/test_pagure_admin.py index a8254db..ec2890c 100644 --- a/tests/test_pagure_admin.py +++ b/tests/test_pagure_admin.py @@ -1548,5 +1548,151 @@ class PagureBlockUserTests(tests.Modeltests): self.assertIsNotNone(user.refuse_sessions_before) +class PagureAdminDeleteProjectTests(tests.Modeltests): + """ Tests for pagure-admin delete-project """ + + populate_db = False + + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureAdminDeleteProjectTests, self).setUp() + pagure.cli.admin.session = self.session + + # Create the user pingou + item = pagure.lib.model.User( + user="pingou", + fullname="PY C", + password="foo", + default_email="bar@pingou.com", + ) + self.session.add(item) + item = pagure.lib.model.UserEmail(user_id=1, email="bar@pingou.com") + self.session.add(item) + + # Create two projects for the user pingou + item = pagure.lib.model.Project( + user_id=1, # pingou + name="test", + description="namespaced test project", + hook_token="aaabbbeee", + namespace="somenamespace", + ) + self.session.add(item) + + item = pagure.lib.model.Project( + user_id=1, # pingou + name="test", + description="Test project", + hook_token="aaabbbccc", + namespace=None, + ) + self.session.add(item) + + self.session.commit() + + # Make the imported pagure use the correct db session + pagure.cli.admin.session = self.session + + def test_delete_project_unknown_project(self): + """ Test the read-only function of pagure-admin on an unknown + project. + """ + + args = munch.Munch( + {"project": "foob", "user": None, "action_user": "pingou"} + ) + with self.assertRaises(pagure.exceptions.PagureException) as cm: + pagure.cli.admin.do_delete_project(args) + self.assertEqual(cm.exception.args[0], "No project found with: foob") + + def test_delete_project_invalid_project(self): + """ Test the read-only function of pagure-admin on an invalid + project. + """ + + args = munch.Munch( + {"project": "fo/o/b", "user": None, "action_user": "pingou"} + ) + with self.assertRaises(pagure.exceptions.PagureException) as cm: + pagure.cli.admin.do_delete_project(args) + self.assertEqual( + cm.exception.args[0], + 'Invalid project name, has more than one "/": fo/o/b', + ) + + @patch("pagure.cli.admin._ask_confirmation", MagicMock(return_value=True)) + def test_delete_project(self): + """ Test the read-only function of pagure-admin to get status of + a non-namespaced project. + """ + + args = munch.Munch( + {"project": "test", "user": None, "action_user": "pingou"} + ) + with tests.capture_output() as output: + pagure.cli.admin.do_delete_project(args) + output = output.getvalue() + self.assertEqual( + "Are you sure you want to delete: test?\n" + " This cannot be undone!\n" + "Project deleted\n", + output, + ) + + @patch("pagure.cli.admin._ask_confirmation", MagicMock(return_value=True)) + def test_delete_project_namespace(self): + """ Test the read-only function of pagure-admin to get status of + a namespaced project. + """ + + args = munch.Munch( + { + "project": "somenamespace/test", + "user": None, + "action_user": "pingou", + } + ) + with tests.capture_output() as output: + pagure.cli.admin.do_delete_project(args) + output = output.getvalue() + self.assertEqual( + "Are you sure you want to delete: somenamespace/test?\n" + " This cannot be undone!\n" + "Project deleted\n", + output, + ) + + @patch("pagure.cli.admin._ask_confirmation", MagicMock(return_value=True)) + def test_delete_project_namespace_changed(self): + """ Test the read-only function of pagure-admin to set the status of + a namespaced project. + """ + + # Before + projects = pagure.lib.query.search_projects(self.session) + self.assertEqual(len(projects), 2) + + args = munch.Munch( + { + "project": "somenamespace/test", + "user": None, + "action_user": "pingou", + } + ) + with tests.capture_output() as output: + pagure.cli.admin.do_delete_project(args) + output = output.getvalue() + self.assertEqual( + "Are you sure you want to delete: somenamespace/test?\n" + " This cannot be undone!\n" + "Project deleted\n", + output, + ) + + # After + projects = pagure.lib.query.search_projects(self.session) + self.assertEqual(len(projects), 1) + + if __name__ == "__main__": unittest.main(verbosity=2)