changeset 195:bd6234ed6ac5

Allow deletion of build configurations from the web interface. Closes #27.
author cmlenz
date Mon, 12 Sep 2005 17:48:15 +0000
parents 8dbddcd0ef00
children b5f7d8a4035e
files bitten/model.py bitten/tests/model.py bitten/trac_ext/templates/bitten_config.cs bitten/trac_ext/tests/web_ui.py bitten/trac_ext/web_ui.py
diffstat 5 files changed, 156 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/model.py
+++ b/bitten/model.py
@@ -41,6 +41,29 @@
 
     exists = property(fget=lambda self: self._old_name is not None)
 
+    def delete(self, db=None):
+        """Remove a build configuration and all dependent objects from the
+        database."""
+        assert self.exists, 'Cannot delete non-existing configuration'
+        if not db:
+            db = self.env.get_db_cnx()
+            handle_ta = True
+        else:
+            handle_ta = False
+
+        for platform in TargetPlatform.select(self.env, self.name, db=db):
+            platform.delete(db=db)
+
+        for build in Build.select(self.env, config=self.name, db=db):
+            build.delete(db=db)
+
+        cursor = db.cursor()
+        cursor.execute("DELETE FROM bitten_config WHERE name=%s", (self.name,))
+
+        if handle_ta:
+            db.commit()
+        self._old_name = None
+
     def insert(self, db=None):
         """Insert a new configuration into the database."""
         assert not self.exists, 'Cannot insert existing configuration'
@@ -340,8 +363,6 @@
         else:
             handle_ta = False
 
-        assert self.status == self.PENDING, 'Only pending builds can be deleted'
-
         for step in BuildStep.select(self.env, build=self.id):
             step.delete(db=db)
 
--- a/bitten/tests/model.py
+++ b/bitten/tests/model.py
@@ -10,7 +10,8 @@
 import unittest
 
 from trac.test import EnvironmentStub
-from bitten.model import BuildConfig, TargetPlatform, Build, BuildStep, BuildLog
+from bitten.model import BuildConfig, TargetPlatform, Build, BuildStep, \
+                         BuildLog, schema
 
 
 class BuildConfigTestCase(unittest.TestCase):
@@ -19,7 +20,7 @@
         self.env = EnvironmentStub()
         db = self.env.get_db_cnx()
         cursor = db.cursor()
-        for table in BuildConfig._schema:
+        for table in schema:
             for stmt in db.to_sql(table):
                 cursor.execute(stmt)
         db.commit()
@@ -87,7 +88,7 @@
                          cursor.fetchone())
         self.assertEqual(None, cursor.fetchone())
 
-    def test_config_update_name(self):
+    def test_update_name(self):
         db = self.env.get_db_cnx()
         cursor = db.cursor()
         cursor.execute("INSERT INTO bitten_config (name,path,label,active) "
@@ -114,6 +115,23 @@
         config.name = None
         self.assertRaises(AssertionError, config.update)
 
+    def test_delete(self):
+        db = self.env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.execute("INSERT INTO bitten_config (name,path,label,active) "
+                       "VALUES (%s,%s,%s,%s)", ('test', 'trunk', 'Test', 0))
+
+        config = BuildConfig.fetch(self.env, 'test')
+        config.delete()
+        self.assertEqual(False, config.exists)
+
+        cursor.execute("SELECT * FROM bitten_config WHERE name=%s", ('test',))
+        self.assertEqual(None, cursor.fetchone())
+
+    def test_delete_non_existing(self):
+        config = BuildConfig(self.env, 'test')
+        self.assertRaises(AssertionError, config.delete)
+
 
 class TargetPlatformTestCase(unittest.TestCase):
 
--- a/bitten/trac_ext/templates/bitten_config.cs
+++ b/bitten/trac_ext/templates/bitten_config.cs
@@ -77,6 +77,16 @@
     </div><?cs
    /if ?><?cs
 
+ elif:page.mode == 'delete_config' ?>
+  <p><strong>Are you sure you want to delete the build configuration "<?cs
+    var:config.name ?>?</strong></p>
+  <p>This will also delete all builds performed for that configuration.</p>
+  <form action="" method="POST"><div class="buttons">
+   <input type="hidden" name="action" value="delete" />
+   <input type="submit" name="cancel" value="Cancel" />
+   <input type="submit" value="Delete configuration" />
+  </div></form><?cs
+
   elif:page.mode == 'view_config' ?><?cs
    if:config.can_modify ?><form id="prefs" method="post" class="activation"><?cs
     if:!config.active ?><div class="help">This build configuration is currently
@@ -113,13 +123,15 @@
     /each ?>
    </div><?cs
 
-   if:config.can_modify ?>
-    <div class="buttons">
-     <form method="get" action=""><div>
-      <input type="hidden" name="action" value="edit" />
-      <input type="submit" value="Edit configuration" />
-     </div></form>
-    </div><?cs
+   if:config.can_modify || config.can_delete ?><div class="buttons"><?cs
+    if:config.can_modify ?><form method="get" action=""><div>
+     <input type="hidden" name="action" value="edit" />
+     <input type="submit" value="Edit configuration" />
+    </div></form><?cs /if ?><?cs
+    if:config.can_delete ?><form method="get" action=""><div>
+     <input type="hidden" name="action" value="delete" />
+     <input type="submit" value="Delete configuration" />
+    </div></form><?cs /if ?><?cs
    /if ?><?cs
    if:len(config.platforms) ?>
     <table class="listing" id="builds"><thead><tr>
--- a/bitten/trac_ext/tests/web_ui.py
+++ b/bitten/trac_ext/tests/web_ui.py
@@ -43,7 +43,6 @@
         PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW')
         req = Mock(Request, cgi_location='', path_info='/build', args={},
                    hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -56,7 +55,6 @@
         PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN')
         req = Mock(Request, cgi_location='', path_info='/build', args={},
                    hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -72,13 +70,13 @@
         PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW')
         req = Mock(Request, cgi_location='', path_info='/build/test', args={},
                    hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
         module.process_request(req)
 
         self.assertEqual('view_config', req.hdf['page.mode'])
+        self.assertEqual('0', req.hdf.get('build.config.can_delete', '0'))
         self.assertEqual('0', req.hdf.get('build.config.can_modify', '0'))
 
     def test_view_config_admin(self):
@@ -89,12 +87,12 @@
         PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN')
         req = Mock(Request, cgi_location='', path_info='/build/test', args={},
                    hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
         module.process_request(req)
 
+        self.assertEqual('1', req.hdf.get('config.can_delete'))
         self.assertEqual('1', req.hdf.get('config.can_modify'))
 
     def test_new_config(self):
@@ -102,7 +100,6 @@
         req = Mock(Request, cgi_location='', path_info='/build',
                    args={'action': 'new'}, hdf=HDFWrapper(),
                    perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -121,7 +118,6 @@
                    perm=PermissionCache(self.env, 'joe'),
                    args={'action': 'new', 'name': 'test', 'path': 'test/trunk',
                          'label': 'Test', 'description': 'Bla bla'})
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -145,7 +141,6 @@
                    redirect=redirect, hdf=HDFWrapper(),
                    perm=PermissionCache(self.env, 'joe'),
                    args={'action': 'new', 'cancel': '1', 'name': 'test'})
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -154,6 +149,66 @@
 
         self.assertEqual(None, BuildConfig.fetch(self.env, 'test'))
 
+    def test_delete_config(self):
+        config = BuildConfig(self.env)
+        config.name = 'test'
+        config.insert()
+
+        PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN')
+        req = Mock(Request, cgi_location='', path_info='/build/test',
+                   args={'action': 'delete'}, hdf=HDFWrapper(),
+                   perm=PermissionCache(self.env, 'joe'))
+
+        module = BuildConfigController(self.env)
+        assert module.match_request(req)
+        module.process_request(req)
+
+        self.assertEqual('delete_config', req.hdf['page.mode'])
+
+    def test_delete_config_submit(self):
+        config = BuildConfig(self.env)
+        config.name = 'test'
+        config.insert()
+
+        PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN')
+        redirected_to = []
+        def redirect(url):
+            redirected_to.append(url)
+            raise RequestDone
+        req = Mock(Request, method='POST', cgi_location='',
+                   path_info='/build/test', redirect=redirect, hdf=HDFWrapper(),
+                   perm=PermissionCache(self.env, 'joe'),
+                   args={'action': 'delete'})
+
+        module = BuildConfigController(self.env)
+        assert module.match_request(req)
+        self.assertRaises(RequestDone, module.process_request, req)
+        self.assertEqual('/trac.cgi/build', redirected_to[0])
+
+        self.assertEqual(None, BuildConfig.fetch(self.env, 'test'))
+
+    def test_edit_config_cancel(self):
+        config = BuildConfig(self.env)
+        config.name = 'test'
+        config.insert()
+
+        PermissionSystem(self.env).grant_permission('joe', 'BUILD_ADMIN')
+        redirected_to = []
+        def redirect(url):
+            redirected_to.append(url)
+            raise RequestDone
+        req = Mock(Request, method='POST', cgi_location='',
+                   path_info='/build/test', redirect=redirect, hdf=HDFWrapper(),
+                   perm=PermissionCache(self.env, 'joe'),
+                   args={'action': 'delete', 'cancel': ''})
+
+        module = BuildConfigController(self.env)
+        assert module.match_request(req)
+        self.assertRaises(RequestDone, module.process_request, req)
+        self.assertEqual('/trac.cgi/build/test', redirected_to[0])
+
+        self.assertEqual(True, BuildConfig.fetch(self.env, 'test').exists)
+
     def test_edit_config(self):
         config = BuildConfig(self.env)
         config.name = 'test'
@@ -163,7 +218,6 @@
         req = Mock(Request, cgi_location='', path_info='/build/test',
                    args={'action': 'edit'}, hdf=HDFWrapper(),
                    perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -186,7 +240,6 @@
                    perm=PermissionCache(self.env, 'joe'),
                    args={'action': 'edit', 'name': 'foo', 'path': 'test/trunk',
                          'label': 'Test',  'description': 'Bla bla'})
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -214,8 +267,7 @@
         req = Mock(Request, method='POST', cgi_location='',
                    path_info='/build/test', redirect=redirect, hdf=HDFWrapper(),
                    perm=PermissionCache(self.env, 'joe'),
-                   args={'action': 'edit', 'cancel': '1'})
-        req.hdf['htdocs_location'] = '/htdocs'
+                   args={'action': 'edit', 'cancel': ''})
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -231,7 +283,6 @@
         req = Mock(Request, cgi_location='', path_info='/build/test',
                    args={'action': 'edit', 'new': '1'},
                    hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -253,7 +304,6 @@
                    path_info='/build/test', redirect=redirect,
                    args={'action': 'new', 'name': 'Test'}, hdf=HDFWrapper(),
                    perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -272,9 +322,8 @@
             raise RequestDone
         req = Mock(Request, method='POST', cgi_location='',
                    path_info='/build/test', redirect=redirect,
-                   args={'action': 'new', 'cancel': '1'}, hdf=HDFWrapper(),
+                   args={'action': 'new', 'cancel': ''}, hdf=HDFWrapper(),
                    perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -295,7 +344,6 @@
         req = Mock(Request, cgi_location='', path_info='/build/test',
                    args={'action': 'edit', 'platform': platform.id},
                    hdf=HDFWrapper(), perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -323,7 +371,6 @@
                    args={'action': 'edit', 'platform': platform.id,
                          'name': 'Test'},
                    perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
@@ -348,9 +395,8 @@
         req = Mock(Request, method='POST', cgi_location='',
                    path_info='/build/test', redirect=redirect, hdf=HDFWrapper(),
                    args={'action': 'edit', 'platform': platform.id,
-                         'cancel': '1'},
+                         'cancel': ''},
                    perm=PermissionCache(self.env, 'joe'))
-        req.hdf['htdocs_location'] = '/htdocs'
 
         module = BuildConfigController(self.env)
         assert module.match_request(req)
--- a/bitten/trac_ext/web_ui.py
+++ b/bitten/trac_ext/web_ui.py
@@ -100,6 +100,8 @@
             if config:
                 if action == 'new':
                     self._do_create_platform(req, config)
+                elif action == 'delete':
+                    self._do_delete_config(req, config)
                 else:
                     platform_id = req.args.get('platform')
                     if platform_id:
@@ -118,7 +120,9 @@
                     self._do_create_config(req)
         else:
             if config:
-                if action == 'edit':
+                if action == 'delete':
+                    self._render_config_confirm(req, config)
+                elif action == 'edit':
                     platform_id = req.args.get('platform')
                     if platform_id:
                         platform = TargetPlatform.fetch(self.env,
@@ -166,6 +170,19 @@
 
         req.redirect(self.env.href.build(config.name))
 
+    def _do_delete_config(self, req, config_name):
+        """Save changes to a build configuration."""
+        req.perm.assert_permission('BUILD_DELETE')
+
+        if 'cancel' in req.args:
+            req.redirect(self.env.href.build(config_name))
+
+        config = BuildConfig.fetch(self.env, config_name)
+        assert config, 'Build configuration "%s" does not exist' % config_name
+
+        config.delete()
+        req.redirect(self.env.href.build())
+
     def _do_save_config(self, req, config_name):
         """Save changes to a build configuration."""
         req.perm.assert_permission('BUILD_MODIFY')
@@ -288,7 +305,8 @@
             'name': config.name, 'label': config.label, 'path': config.path,
             'active': config.active, 'description': description,
             'browser_href': self.env.href.browser(config.path),
-            'can_modify': req.perm.has_permission('BUILD_MODIFY')
+            'can_modify': req.perm.has_permission('BUILD_MODIFY'),
+            'can_delete': req.perm.has_permission('BUILD_DELETE')
         }
         req.hdf['page.mode'] = 'view_config'
 
@@ -321,6 +339,14 @@
         except TracError, e:
             self.log.error('Error accessing repository info', exc_info=True)
 
+    def _render_config_confirm(self, req, config_name):
+        req.perm.assert_permission('BUILD_DELETE')
+        config = BuildConfig.fetch(self.env, config_name)
+        req.hdf['title'] = 'Delete Build Configuration "%s"' \
+                           % escape(config.label or config.name)
+        req.hdf['config'] = {'name': config.name}
+        req.hdf['page.mode'] = 'delete_config'
+
     def _render_config_form(self, req, config_name=None):
         config = BuildConfig.fetch(self.env, config_name)
         if config:
Copyright (C) 2012-2017 Edgewall Software