#4437 Add an option to pagure-admin to delete a project
Merged a year ago by pingou. Opened a year ago by pingou.

file modified
+1 -1

@@ -21,7 +21,7 @@ 

  RUN cd / \

      && git clone -b $BRANCH $REPO \

      && chmod +x /pagure/dev/containers/runtests_py3.sh \

-     && sed -i -e "s|\['alembic',|\['alembic-3',|" /pagure/tests/test_alembic.py

+     && sed -i -e 's|\["alembic",|\["alembic-3",|' /pagure/tests/test_alembic.py

  

  # Install all the requirements from the spec file and replace the macro

  # %{python_pkgversion} by '3' which thus installs all the py3 version of

file modified
+68

@@ -387,6 +387,32 @@ 

      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 @@ 

      # 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_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.

  

file modified
+146

@@ -1548,5 +1548,151 @@ 

          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)