Repository :
http://git.fedorahosted.org/cgit/copr.git
On branch : master
---------------------------------------------------------------
commit 78e2557a2b5c10cd915a7125fa09d58a358dd838
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Wed Feb 4 18:10:24 2015 +0100
[copr] monitor page redone: show version for each chroot
---------------------------------------------------------------
frontend/copr-frontend.spec | 1 +
frontend/coprs_frontend/coprs/logic/api_logic.py | 37 ++++++++--
.../coprs_frontend/coprs/logic/builds_logic.py | 70 +++++++++++--------
frontend/coprs_frontend/coprs/static/copr.css | 14 ++--
frontend/coprs_frontend/coprs/templates/api.html | 8 +-
.../coprs/templates/coprs/detail/monitor.html | 30 +++++----
.../coprs/views/coprs_ns/coprs_builds.py | 3 +
.../tests/test_logic/test_builds_logic.py | 2 +-
.../test_views/test_coprs_ns/test_coprs_builds.py | 34 ++++++----
9 files changed, 123 insertions(+), 76 deletions(-)
diff --git a/frontend/copr-frontend.spec b/frontend/copr-frontend.spec
index ab2acba..cd50598 100644
--- a/frontend/copr-frontend.spec
+++ b/frontend/copr-frontend.spec
@@ -167,6 +167,7 @@ service httpd condrestart
%ghost %{_sharedstatedir}/copr/data/copr.db
%defattr(644, copr-fe, copr-fe, 755)
+%dir %{_var}/log/copr
%ghost %{_var}/log/copr/*.log
%defattr(600, copr-fe, copr-fe, 700)
diff --git a/frontend/coprs_frontend/coprs/logic/api_logic.py
b/frontend/coprs_frontend/coprs/logic/api_logic.py
index 19c98c2..93c7568 100644
--- a/frontend/coprs_frontend/coprs/logic/api_logic.py
+++ b/frontend/coprs_frontend/coprs/logic/api_logic.py
@@ -49,12 +49,33 @@ class MonitorWrapper(object):
BuildWrapper(build).to_dict()
for build in self.monitor_data["builds"]
]
- out["packages"] = [
- {
- "pkg_name": pkg[0],
- "pkg_version": pkg[1],
- "results": dict(zip(chroots, pkg[2]))
- }
- for pkg in self.monitor_data["packages"]
- ]
+
+ packages_fixed = []
+ for (pkg_name, results_by_chroot) in self.monitor_data["packages"]:
+ results = {}
+ for chroot_name, (build_id, status, pkg_version, _) in zip(chroots,
results_by_chroot):
+ if status is None or pkg_version is None:
+ results[chroot_name] = None
+ else:
+ results[chroot_name] = dict(build_id=build_id,
+ status=status,
+ pkg_version=pkg_version)
+
+ packages_fixed.append({
+ "pkg_name": pkg_name,
+ "pkg_version": None, # legacy
+ "results": results
+ })
+
+ out["packages"] = packages_fixed
+ #
+ # [
+ # {
+ # "pkg_name": pkg_name,
+ # "pkg_version": None, # legacy
+ # "results": dict(zip(chroots, results_by_chroot))
+ # }
+ # for (pkg_name, results_by_chroot)
+ # in self.monitor_data["packages"]
+ # ]
return out
diff --git a/frontend/coprs_frontend/coprs/logic/builds_logic.py
b/frontend/coprs_frontend/coprs/logic/builds_logic.py
index a6a50f6..8283d5e 100644
--- a/frontend/coprs_frontend/coprs/logic/builds_logic.py
+++ b/frontend/coprs_frontend/coprs/logic/builds_logic.py
@@ -1,5 +1,7 @@
+from collections import defaultdict
import json
import os
+import pprint
import time
from sqlalchemy import or_
from sqlalchemy import and_
@@ -15,6 +17,8 @@ from coprs.constants import DEFAULT_BUILD_TIMEOUT, MAX_BUILD_TIMEOUT
from coprs.logic import coprs_logic
from coprs.logic import users_logic
+log = app.logger
+
class BuildsLogic(object):
@@ -264,7 +268,7 @@ class BuildsLogic(object):
@classmethod
def get_multiply_by_copr(cls, copr):
- """ Get collection of builds in copr
+ """ Get collection of builds in copr sorted by build_id
descending
:arg copr: object of copr
"""
@@ -278,50 +282,55 @@ class BuildsMonitorLogic(object):
@classmethod
def get_monitor_data(cls, copr):
+ # builds are sorted by build id descending
builds = BuildsLogic.get_multiply_by_copr(copr).all()
- # please don"t waste time trying to decipher this
- # the only reason why this is necessary is non-existent
- # database design
- #
- # loop goes through builds trying to approximate
- # per-package results based on previous builds
- # - it can"t determine build results if build contains
- # more than one package as this data is not available
-
chroots = set(chroot.name for chroot in copr.active_chroots)
- latest_build = None
if builds:
latest_build = builds[0]
- chroots.union([chroot.name for chroot
- in latest_build.build_chroots])
+ chroots.union([chroot.name for chroot in latest_build.build_chroots])
+ else:
+ latest_build = None
chroots = sorted(chroots)
- out = []
- packages = []
- for build in builds:
- chroot_results = dict(
- [(chroot.name, chroot.state) for chroot in build.build_chroots])
- build_results = []
- for chroot_name in chroots:
- if chroot_name in chroot_results:
- results = chroot_results[chroot_name]
- else:
- results = None
+ # { pkg_name -> { chroot -> (build_id, pkg_version, status) }}
+ build_result_by_pkg_chroot = defaultdict(lambda: defaultdict(lambda: None))
- build_results.append((build.id, results, chroot_name))
+ # collect information about pkg version and build states
+ for build in builds:
+ chroot_results = {chroot.name: chroot.state for chroot in
build.build_chroots}
for pkg_url in build.pkgs.split():
pkg = os.path.basename(pkg_url)
pkg_name = helpers.parse_package_name(pkg)
- if pkg_name in out:
- continue
+ for chroot_name, state in chroot_results.items():
+ # set only latest version/state
+ if build_result_by_pkg_chroot[pkg_name][chroot_name] is None:
+ build_result_by_pkg_chroot[pkg_name][chroot_name] = (build.id,
build.pkg_version, state)
+
+ # "transpose" data to present build status per package
+ packages = []
+ for pkg_name, chroot_dict in build_result_by_pkg_chroot.items():
+ br = []
+ try:
+ latest_build_id = max([build_id for build_id, pkg_version, state
+ in chroot_dict.values()])
+ except ValueError:
+ latest_build_id = None
+
+ for chroot_name in chroots:
+ chroot_result = chroot_dict.get(chroot_name)
+ if chroot_result:
+ build_id, pkg_version, state = chroot_result
+ br.append((build_id, state, pkg_version, chroot_name))
+ else:
+ br.append((latest_build_id, None, None, chroot_name))
+
+ packages.append((pkg_name, br))
- packages.append((pkg_name, build.pkg_version, build_results))
- out.append(pkg_name)
- packages.sort()
+ packages.sort()
result = {
"builds": builds,
@@ -329,4 +338,5 @@ class BuildsMonitorLogic(object):
"packages": packages,
"latest_build": latest_build,
}
+ app.logger.debug("Monitor data: \n{}".format(pprint.pformat(result)))
return result
diff --git a/frontend/coprs_frontend/coprs/static/copr.css
b/frontend/coprs_frontend/coprs/static/copr.css
index d78df1e..71fbdf5 100644
--- a/frontend/coprs_frontend/coprs/static/copr.css
+++ b/frontend/coprs_frontend/coprs/static/copr.css
@@ -394,31 +394,31 @@ tr.build-row-skipped {
color: black;
}
-.build-pending {
+.build-pending,.build-pending>a {
color: #55b;
}
-.build-starting {
+.build-starting,.build-starting>a {
color: #c84;
}
-.build-running {
+.build-running,.build-running>a {
color: #c84;
}
-.build-succeeded {
+.build-succeeded,.build-succeeded>a {
color: #272;
}
-.build-skipped {
+.build-skipped,.build-skipped>a {
color: #272;
}
-.build-failed {
+.build-failed,.build-failed>a {
color: #c44;
}
-.build-cancelled {
+.build-cancelled,.build-cancelled>a {
color: #666;
}
diff --git a/frontend/coprs_frontend/coprs/templates/api.html
b/frontend/coprs_frontend/coprs/templates/api.html
index a38c389..4e5bd2e 100644
--- a/frontend/coprs_frontend/coprs/templates/api.html
+++ b/frontend/coprs_frontend/coprs/templates/api.html
@@ -240,11 +240,11 @@ copr_url = {{ ('https://' +
config['PUBLIC_COPR_HOSTNAME'])| fix_url_https_front
"packages": [
{
"pkg_name": "python-copr-client",
- "pkg_version": "1.43",
+ "pkg_version": null, # not used anymore
"results": {
- "epel-5-x86_64": [9578, "failed"],
- "epel-7-x86_64": [9578, "failed"],
- "fedora-20-x86_64": [9578, "skipped"]
+ "epel-5-x86_64": {"build_id": 9578, "status":
"failed", "pkg_version": "1.2-1.fc20"],
+ "epel-7-x86_64": {"build_id": 9578, "status":
"failed", "pkg_version": "1.2-1.fc20"],
+ "fedora-20-x86_64": null # this chroot was never build,
}
}
]
diff --git a/frontend/coprs_frontend/coprs/templates/coprs/detail/monitor.html
b/frontend/coprs_frontend/coprs/templates/coprs/detail/monitor.html
index 168a9b9..3ce2642 100644
--- a/frontend/coprs_frontend/coprs/templates/coprs/detail/monitor.html
+++ b/frontend/coprs_frontend/coprs/templates/coprs/detail/monitor.html
@@ -13,7 +13,7 @@
<tr></tr>
<tr>
<th rowspan="2">Package</th>
- <th rowspan="2">Version</th>
+ <!--<th rowspan="2">Version</th>-->
{% for i, chroot in oses %}
<th colspan="{{i}}">
{{ chroot|capitalize }}
@@ -27,26 +27,30 @@
</th>
{% endfor %}
</tr>
- {% for package, version, states in packages %}
+ {% for package, states_by_chroot in packages %}
<tr>
<td>{{ package }}</td>
- <td>
- {% if version: %}
- {{ version }}
- {% else %}
- -
- {% endif %}
- </td>
- {% for build_id, state, chroot in states %}
- <td class="centered build-{{ state }}">
+ {% for build_id, state, pkg_version, chroot in states_by_chroot %}
+ <td class="centered">
{% if state %}
- {{ state }}
+ <a class="build-{{ state }}"
+ href="{{ url_for('coprs_ns.copr_build',
+ username=copr.owner.name,
+ coprname=copr.name,
+ build_id=build_id) }}">
+ {{ state }}
+ </a> <br />
+ {% if pkg_version %}
+ <small> {{ pkg_version }} </small>
+ {% endif %}
{% else %}
+ {% if build_id %}
<a href="{{ url_for('coprs_ns.copr_repeat_build',
username=copr.owner.name,
coprname=copr.name,
build_id=build_id,
- chroot=chroot) }}">resubmit</a>
+ chroot=chroot) }}">new build</a>
+ {% endif %}
{% endif %}
</td>
{% endfor %}
diff --git a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
index 35ebc0b..fe076f4 100644
--- a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
+++ b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
@@ -189,6 +189,9 @@ def copr_repeat_build(username, coprname, build_id, page=1):
return page_not_found(
"Copr {0}/{1} does not exist.".format(username, coprname))
+ if not flask.g.user.can_build_in(build.copr):
+ flask.flash("You are not allowed to repeat this build.")
+
form = forms.BuildFormFactory.create_form_cls(copr.active_chroots)(
pkgs=build.pkgs, enable_net=build.enable_net,
)
diff --git a/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
b/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
index ef43cd0..055978a 100644
--- a/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
+++ b/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
@@ -50,7 +50,7 @@ class TestBuildsLogic(CoprsTestCase):
def test_monitor_logic(self, f_users, f_coprs, f_mock_chroots_many,
f_build_many_chroots, f_db):
copr = self.c1
md = BuildsMonitorLogic.get_monitor_data(copr)
- results = md["packages"][-1][2]
+ results = md["packages"][-1][-1]
mchroots = md["chroots"]
for chr, res in zip(mchroots, results):
diff --git a/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
b/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
index 6a72158..393b00e 100644
--- a/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
+++ b/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
@@ -145,7 +145,7 @@ class TestCoprDeleteBuild(CoprsTestCase):
class TestCoprRepeatBuild(CoprsTestCase):
@TransactionDecorator("u1")
- def test_copr_build_chroots_subset_preserved_on_build_repeat(
+ def test_copr_build_basic_build_repeat(
self, f_users, f_coprs, f_mock_chroots_many, f_db):
self.b_few_chroots = models.Build(
id=2345,
@@ -181,15 +181,19 @@ class TestCoprRepeatBuild(CoprsTestCase):
data={},
follow_redirects=True)
- assert "Build was resubmitted" in r.data
+ assert r.status_code == 200
+ assert self.b_few_chroots.pkgs in r.data
+ assert "Adding Build for user1/foocopr" in r.data
- new_build = self.models.Build.query.filter(
- self.models.Build.id != 2345).first()
+ # TODO: maybe test, that only failed chroots are selected
- expected_build_chroots_name_set = set(self.status_by_chroot.keys())
- result_build_chroots_name_set = set([c.name for c in new_build.chroots])
-
- assert result_build_chroots_name_set == expected_build_chroots_name_set
+ # new_build = self.models.Build.query.filter(
+ # self.models.Build.id != 2345).first()
+ #
+ # expected_build_chroots_name_set = set(self.status_by_chroot.keys())
+ # result_build_chroots_name_set = set([c.name for c in new_build.chroots])
+ #
+ # assert result_build_chroots_name_set == expected_build_chroots_name_set
@TransactionDecorator("u1")
def test_copr_build_submitter_can_repeat_build(self, f_users,
@@ -207,10 +211,12 @@ class TestCoprRepeatBuild(CoprsTestCase):
data={},
follow_redirects=True)
- assert "Build was resubmitted" in r.data
- assert len(self.models.Build.query
- .filter(self.models.Build.pkgs == pkgs)
- .all()) == 2
+ assert "Adding Build for user1/foocopr" in r.data
+ assert r.status_code == 200
+ # assert "Build was resubmitted" in r.data
+ # assert len(self.models.Build.query
+ # .filter(self.models.Build.pkgs == pkgs)
+ # .all()) == 2
@TransactionDecorator("u2")
def test_copr_build_non_submitter_cannot_repeat_build(self, f_users,
@@ -225,4 +231,6 @@ class TestCoprRepeatBuild(CoprsTestCase):
data={},
follow_redirects=True)
- assert "t have permissions to build" in r.data
+ # import ipdb; ipdb.set_trace()
+ assert "You are not allowed to repeat this build." in r.data
+