Discussion: Using copr for building SCLs
by Bohuslav Kabrda
Hi list,
I'd like to start yet another discussion about some functionality of copr, here it is:
One of nice use cases for copr would be building software collections [1]. These however require modified mock chroot (modified config_opts['root'] and config_opts['chroot_setup_cmd']).
I'm trying to think of a way how to do this:
- We would need to allow users to create their own chroots (or more precisely allow them to do certain modifications).
- We would need to be able to send these chroots from frontend to backend.
- We would need some mechanism for sane naming, so that we can distinguish between builds of collections for different releases and architectures. E.g. ruby193-x86_64 is not enough, we need to also store the information about os name (epel/fedora) and os version (epel 6, fedora 18, ...).
My proposal:
- Use chroot names like ruby193_fedora-18-x86_64.
- Allow users to create these chroots by modifying config_opts['chroot_setup_cmd'] (config_opts['root'] would be autogenerated from the chroot name).
- Store the modified information in the MockChroot table and create these on backend using communication channel proposed in [2] (parts of it already implemented in frontend).
- Allow selecting these on copr creation/modification as more options for mock chroots, by default hidden under some kind of fancy clickable JS dropdown.
Thoughts?
--
Regards,
Bohuslav "Slavek" Kabrda.
[1] https://fedorahosted.org/SoftwareCollections/
[2] https://fedorahosted.org/copr/ticket/8
10 years, 3 months
Repo file generation II. + URL Question
by Tomas Radej
Hi,
I fixed the SQL query, please comment before I push. I also have a
design-related question, if I may.
Currently, the baseurl in the .repo file points to the root of the
repo. However, if a build is done on multiple architectures, will that
work, or do I need a baseurl pointing to that architecture
subdirectory? Based on the answer, I will also implement a link from
the copr overview page to the respective .repo files.
Thank you, TR
Patch:
diff --git a/coprs_frontend/coprs/templates/coprs/coprchroot.repo b/coprs_frontend/coprs/templates/coprs/coprchroot.repo
new file mode 100644
index 0000000..98d79d3
--- /dev/null
+++ b/coprs_frontend/coprs/templates/coprs/coprchroot.repo
@@ -0,0 +1,7 @@
+[{{ copr.owner.name }}-{{ copr.name }}]
+
+name=Copr repo for {{ copr.name }} owned by {{ copr.owner.name }}
+description={{ copr.description }}
+baseurl={{ url }}
+skip_if_unavailable=True
+
diff --git a/coprs_frontend/coprs/views/coprs_ns/coprs_general.py b/coprs_frontend/coprs/views/coprs_ns/coprs_general.py
index 9d5be98..7cc83c5 100644
--- a/coprs_frontend/coprs/views/coprs_ns/coprs_general.py
+++ b/coprs_frontend/coprs/views/coprs_ns/coprs_general.py
@@ -272,3 +272,23 @@ def copr_legal_flag(username, coprname):
db.session.commit()
flask.flash('Admin was noticed about your report and will investigate the copr shortly.')
return flask.redirect(flask.url_for('coprs_ns.copr_detail', username=username, coprname=coprname))
+
+(a)coprs_ns.route('/detail/<username>/<coprname>/<chrootname>.repo', methods = ['GET'])
+def generate_repo_file(username, coprname, chrootname):
+ ''' Generate repo file for a given copr/mock-chroot '''
+ copr = None
+ try:
+ # query.one() is used since it fetches all builds, unlike query.first().
+ copr = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname,
+ with_mock_chroots=True, with_builds=True).one()
+ except sqlalchemy.orm.exc.NoResultFound:
+ return page_not_found('Copr: {0}/{1} does not exist'.format(username, coprname))
+
+ urls = [build.results for build in copr.builds if build.results != None]
+ if not urls:
+ return page_not_found('Repository not initialized: No builds in {0}/{1} have finished.'.format(username, coprname))
+
+ response = flask.make_response(flask.render_template('coprs/coprchroot.repo', copr=copr, url=urls[0]))
+ response.mimetype='text/plain'
+ return response
+
diff --git a/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_general.py b/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_general.py
index 380d59d..e70458b 100644
--- a/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_general.py
+++ b/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_general.py
@@ -1,4 +1,5 @@
import flask
+import pytest
from flexmock import flexmock
@@ -456,3 +457,30 @@ class TestCoprDelete(CoprsTestCase):
assert 'Copr was deleted successfully' not in r.data
assert not self.models.Action.query.first()
assert self.models.Copr.query.filter(self.models.Copr.id==self.c1.id).first()
+
+class TestCoprRepoGeneration(CoprsTestCase):
+ @pytest.fixture
+ def f_custom_builds(self):
+ ''' Custom builds are used in order not to break the default ones '''
+ self.b5 = self.models.Build(copr=self.c1, user=self.u1, chroots='fedora-18-x86_64', submitted_on=9, ended_on=200, results='foo://bar.baz', status=1)
+ self.b6 = self.models.Build(copr=self.c1, user=self.u1, chroots='fedora-18-x86_64', submitted_on=11)
+ self.b7 = self.models.Build(copr=self.c1, user=self.u1, chroots='fedora-18-x86_64', submitted_on=10, ended_on=150, results='foo://bar.baz', status=1)
+
+ self.db.session.add_all([self.b5, self.b6, self.b7])
+
+ def test_fail_on_no_copr(self):
+ r = self.tc.get('/coprs/detail/bogus/copr/name.repo')
+ assert r.status_code == 404
+ assert 'bogus/copr does not exist' in r.data
+
+ def test_fail_on_no_finished_builds(self, f_users, f_coprs, f_mock_chroots, f_db):
+ r = self.tc.get(
+ '/coprs/detail/{0}/{1}/{2}.repo'.format(self.u1.name, self.c1.name,
+ self.c1.mock_chroots[0].chroot_name))
+ assert r.status_code == 404
+ assert 'Repository not initialized' in r.data
+
+ def test_works_on_older_builds(self, f_users, f_coprs, f_mock_chroots, f_custom_builds, f_db):
+ r = self.tc.get('/coprs/detail/{0}/{1}/{2}.repo'.format(self.u1.name, self.c1.name, self.c1.mock_chroots[0].chroot_name))
+ assert r.status_code == 200
+ assert 'baseurl=foo://bar.baz' in r.data
--
Tomas Radej <tradej(a)redhat.com>
10 years, 4 months