Repository :
http://git.fedorahosted.org/cgit/copr.git
On branch : master
---------------------------------------------------------------
commit ee25496f02524816e1a5d077daffc5413c865626
Author: Richard Marko <rmarko(a)fedoraproject.org>
Date: Sun Jan 12 22:31:48 2014 +0100
add build deletion
Signed-off-by: Richard Marko <rmarko(a)fedoraproject.org>
---------------------------------------------------------------
backend/actions.py | 62 +++++++++++++++++---
coprs_frontend/coprs/logic/builds_logic.py | 19 ++++++
.../templates/coprs/detail/_builds_forms.html | 8 +++
.../templates/coprs/detail/_builds_table.html | 5 +-
.../coprs/views/coprs_ns/coprs_builds.py | 18 ++++++
.../test_views/test_coprs_ns/test_coprs_builds.py | 39 ++++++++++++
6 files changed, 142 insertions(+), 9 deletions(-)
diff --git a/backend/actions.py b/backend/actions.py
index b2bb6ab..11451cc 100644
--- a/backend/actions.py
+++ b/backend/actions.py
@@ -4,6 +4,9 @@ import os.path
import shutil
import time
+from mockremote import createrepo
+
+
class Action(object):
""" Object to send data back to fronted """
@@ -21,15 +24,57 @@ class Action(object):
""" Handle action (other then builds) - like rename or delete of
project """
result = Bunch()
result.id = self.data['id']
- if self.data['action_type'] == 0: # delete
- self.event("Action delete")
- project = self.data['old_value']
- path = os.path.normpath(self.destdir + '/' + project)
- if os.path.exists(path):
- self.event('Removing %s' % path)
- shutil.rmtree(path)
+ if self.data['action_type'] == 0: # delete
+ if self.data['object_type'] == 'copr':
+ self.event("Action delete copr")
+ project = self.data['old_value']
+ path = os.path.normpath(self.destdir + '/' + project)
+ if os.path.exists(path):
+ self.event('Removing copr %s' % path)
+ shutil.rmtree(path)
+
+ elif self.data['object_type'] == 'build':
+ self.event("Action delete build")
+ project = self.data['old_value']
+ packages = map(lambda x:
+ os.path.basename(x).replace('.src.rpm',
''),
+ self.data['new_value'].split())
+
+ path = os.path.join(self.destdir, project)
+
+ self.event("Packages to delete {0}".format('
'.join(packages)))
+ self.event("Copr path {0}".format(path))
+
+ for chroot in os.listdir(path):
+ self.event("In chroot {0}".format(chroot))
+ altered = False
+
+ for pkg in packages:
+ pkg_path = os.path.join(path, chroot, pkg)
+ if os.path.isdir(pkg_path):
+ self.event('Removing build {0}'.format(pkg_path))
+ shutil.rmtree(pkg_path)
+ altered = True
+ else:
+ self.event('Package {0} dir not found in chroot {1}'
+ .format(pkg, chroot))
+
+ if altered:
+ self.event("Running createrepo")
+ rc, out, err = createrepo(os.path.join(path, chroot))
+ if err.strip():
+ self.event("Error making local repo:
{0}".format(err))
+
+ log_path = os.path.join(
+ path, chroot,
+ 'build-{0}.log'.format(self.data['object_id']))
+
+ if os.path.isfile(log_path):
+ self.event("Removing log {0}".format(log_path))
+ os.unlink(log_path)
+
result.job_ended_on = time.time()
- result.result = 1 # success
+ result.result = 1 # success
elif self.data['action_type'] == 1: # rename
self.event("Action rename")
old_path = os.path.normpath(self.destdir + '/',
self.data['old_value'])
@@ -46,5 +91,6 @@ class Action(object):
result.job_ended_on = time.time()
elif self.data['action_type'] == 2: # legal-flag
self.event("Action legal-flag: ignoring")
+
if 'result' in result:
self.frontend_callback.post_to_frontend( {'actions': [result]} )
diff --git a/coprs_frontend/coprs/logic/builds_logic.py
b/coprs_frontend/coprs/logic/builds_logic.py
index acdcf9c..4881ab6 100644
--- a/coprs_frontend/coprs/logic/builds_logic.py
+++ b/coprs_frontend/coprs/logic/builds_logic.py
@@ -3,6 +3,7 @@ import time
from coprs import db
from coprs import exceptions
from coprs import models
+from coprs import helpers
from coprs import signals
from coprs.logic import coprs_logic
@@ -126,3 +127,21 @@ class BuildsLogic(object):
if build.user_id != user.id:
raise exceptions.InsufficientRightsException('You can only cancel your
own builds.')
build.canceled = True
+
+ @classmethod
+ def delete_build(cls, user, build):
+ if build.user_id != user.id:
+ raise exceptions.InsufficientRightsException('You can only delete your
own builds.')
+
+ action = models.Action(action_type=helpers.ActionTypeEnum('delete'),
+ object_type='build',
+ object_id=build.id,
+ old_value='{0}/{1}'.format(build.copr.owner.name,
+ build.copr.name),
+ new_value=build.pkgs,
+ created_on=int(time.time()))
+
+ db.session.add(action)
+ for build_chroot in build.build_chroots:
+ db.session.delete(build_chroot)
+ db.session.delete(build)
diff --git a/coprs_frontend/coprs/templates/coprs/detail/_builds_forms.html
b/coprs_frontend/coprs/templates/coprs/detail/_builds_forms.html
index 4e81f3a..b7c7b0d 100644
--- a/coprs_frontend/coprs/templates/coprs/detail/_builds_forms.html
+++ b/coprs_frontend/coprs/templates/coprs/detail/_builds_forms.html
@@ -35,3 +35,11 @@
</form>
{% endif %}
{% endmacro %}
+
+{% macro copr_build_delete_form(build) %}
+ {% if build.ended_on %}
+ <form action="{{ url_for('coprs_ns.copr_delete_build',
username=build.copr.owner.name, coprname=build.copr.name, build_id=build.id)}}"
method="post">
+ <input type="submit" value="Delete">
+ </form>
+ {% endif %}
+{% endmacro %}
diff --git a/coprs_frontend/coprs/templates/coprs/detail/_builds_table.html
b/coprs_frontend/coprs/templates/coprs/detail/_builds_table.html
index f65d7ed..a70b53c 100644
--- a/coprs_frontend/coprs/templates/coprs/detail/_builds_table.html
+++ b/coprs_frontend/coprs/templates/coprs/detail/_builds_table.html
@@ -1,4 +1,4 @@
-{% from "coprs/detail/_builds_forms.html" import copr_build_cancel_form,
copr_build_repeat_form %}
+{% from "coprs/detail/_builds_forms.html" import copr_build_cancel_form,
copr_build_repeat_form, copr_build_delete_form %}
{% macro builds_table(builds) %}
{% if builds %}
@@ -29,6 +29,9 @@
{% if g.user and g.user.can_build_in(copr) %}
{{ copr_build_repeat_form(build) }}
{% endif %}
+ {% if g.user and g.user == build.user %}
+ {{ copr_build_delete_form(build) }}
+ {% endif %}
<div>
{% if build.results %}
<h2>Results: </h2><a href="{{ build.results
}}">{{ build.results }}</a>
diff --git a/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
b/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
index 109a9f5..561fa61 100644
--- a/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
+++ b/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
@@ -109,3 +109,21 @@ def copr_repeat_build(username, coprname, build_id):
flask.flash('Build was resubmitted')
return flask.redirect(flask.url_for('coprs_ns.copr_builds', username =
username, coprname = coprname))
+
+
+@coprs_ns.route('/<username>/<coprname>/delete_build/<int:build_id>/',
methods=['POST'])
+@login_required
+def copr_delete_build(username, coprname, build_id):
+ build = builds_logic.BuildsLogic.get(build_id).first()
+ if not build:
+ return page_not_found('Build with id {0} does not
exist.'.format(build_id))
+ try:
+ builds_logic.BuildsLogic.delete_build(flask.g.user, build)
+ except exceptions.InsufficientRightsException as e:
+ flask.flash(str(e))
+ else:
+ db.session.commit()
+ flask.flash('Build was deleted')
+
+ return flask.redirect(flask.url_for('coprs_ns.copr_builds',
+ username=username, coprname=coprname))
diff --git a/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
b/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
index dc66562..c690833 100644
--- a/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
+++ b/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
@@ -57,3 +57,42 @@ class TestCoprCancelBuild(CoprsTestCase):
data = {},
follow_redirects = True)
assert self.models.Build.query.first().canceled is False
+
+
+class TestCoprDeleteBuild(CoprsTestCase):
+ @TransactionDecorator('u1')
+ def test_copr_build_submitter_can_delete_build(self, f_users, f_coprs,
f_mock_chroots, f_builds, f_db):
+ self.db.session.add_all([self.u1, self.c1, self.b1])
+ pkgs = 'one two three'
+ self.b1.pkgs = pkgs
+ r = self.test_client.post(
+ '/coprs/{0}/{1}/delete_build/{2}/'.format(self.u1.name,
+ self.c1.name, self.b1.id),
+ data={},
+ follow_redirects=True)
+
+ assert 'Build was deleted' in r.data
+ b = (self.models.Build.query.filter(
+ self.models.Build.id == self.b1.id)
+ .first())
+ assert b is None
+ act = self.models.Action.query.first()
+ assert act.object_type == 'build'
+ assert act.old_value == 'user1/foocopr'
+ assert act.new_value == pkgs
+
+ @TransactionDecorator('u2')
+ def test_copr_build_non_submitter_cannot_delete_build(self, f_users, f_coprs,
f_mock_chroots, f_builds, f_db):
+ self.db.session.add_all([self.u1, self.c1, self.b1])
+ r = self.test_client.post(
+ '/coprs/{0}/{1}/delete_build/{2}/'.format(self.u1.name,
+ self.c1.name, self.b1.id),
+ data={},
+ follow_redirects=True)
+
+ assert 'delete your own builds' in r.data
+ b = (self.models.Build.query.filter(
+ self.models.Build.id == self.b1.id)
+ .first())
+
+ assert b is not None