Add repoID in listBuildroots and create repoinfo command

Add repoID param in listBuildroots and show result in repoInfo
Create new command repoinfo which provides equivalent info as repoInfo
Add number of buildroots related to repo in repoinfo page

Fixes: https://pagure.io/koji/issue/2549
This commit is contained in:
Jana Cupova 2023-02-03 14:34:55 +01:00 committed by Tomas Kopecek
parent a48172924f
commit de192e10f1
10 changed files with 528 additions and 2 deletions

View file

@ -7741,3 +7741,56 @@ def anon_handle_userinfo(goptions, session, args):
print("Number of tasks: %d" % tasks.result)
print("Number of builds: %d" % builds.result)
print('')
def anon_handle_repoinfo(goptions, session, args):
"[info] Print basic information about a repo"
usage = "usage: %prog repoinfo [options] <repo-id> [<repo-id> ...]"
parser = OptionParser(usage=get_usage_str(usage))
parser.add_option("--buildroots", action="store_true",
help="Prints list of buildroot IDs")
(options, args) = parser.parse_args(args)
if len(args) < 1:
parser.error("Please specify a repo ID")
ensure_connection(session, goptions)
kojipath = koji.PathInfo(topdir=goptions.topurl)
with session.multicall() as m:
result = [m.repoInfo(repo_id, strict=False) for repo_id in args]
for repo_id, repoinfo in zip(args, result):
rinfo = repoinfo.result
if not rinfo:
warn("No such repo: %s\n" % repo_id)
continue
print('ID: %s' % rinfo['id'])
print('Tag ID: %s' % rinfo['tag_id'])
print('Tag name: %s' % rinfo['tag_name'])
print('State: %s' % koji.REPO_STATES[rinfo['state']])
print("Created: %s" % koji.formatTimeLong(rinfo['create_ts']))
print('Created event: %s' % rinfo['create_event'])
url = kojipath.repo(rinfo['id'], rinfo['tag_name'])
print('URL: %s' % url)
if rinfo['dist']:
repo_json = os.path.join(
kojipath.distrepo(rinfo['id'], rinfo['tag_name']), 'repo.json')
else:
repo_json = os.path.join(
kojipath.repo(rinfo['id'], rinfo['tag_name']), 'repo.json')
print('Repo json: %s' % repo_json)
print("Dist repo?: %s" % (rinfo['dist'] and 'yes' or 'no'))
print('Task ID: %s' % rinfo['task_id'])
try:
repo_buildroots = session.listBuildroots(repoID=rinfo['id'])
count_buildroots = len(repo_buildroots)
print('Number of buildroots: %i' % count_buildroots)
if options.buildroots and count_buildroots > 0:
repo_buildroots_id = [repo_buildroot['id'] for repo_buildroot in repo_buildroots]
print('Buildroots ID:')
for r_bldr_id in repo_buildroots_id:
print(' ' * 15 + '%s' % r_bldr_id)
except koji.ParameterError:
# repoID option added in 1.33
if options.buildroots:
warn("--buildroots option is available with hub 1.33 or newer")

View file

@ -5586,7 +5586,7 @@ def get_channel(channelInfo, strict=False):
def query_buildroots(hostID=None, tagID=None, state=None, rpmID=None, archiveID=None, taskID=None,
buildrootID=None, queryOpts=None):
buildrootID=None, repoID=None, queryOpts=None):
"""Return a list of matching buildroots
Optional args:
@ -5688,6 +5688,18 @@ def query_buildroots(hostID=None, tagID=None, state=None, rpmID=None, archiveID=
if not candidate_buildroot_ids:
return _applyQueryOpts([], queryOpts)
if repoID:
query = QueryProcessor(columns=['buildroot_id'], tables=['standard_buildroot'],
clauses=['repo_id = %(repoID)i'], opts={'asList': True},
values=locals())
result = set(query.execute())
if candidate_buildroot_ids:
candidate_buildroot_ids &= result
else:
candidate_buildroot_ids = result
if not candidate_buildroot_ids:
return _applyQueryOpts([], queryOpts)
if candidate_buildroot_ids:
candidate_buildroot_ids = list(candidate_buildroot_ids)
clauses.append('buildroot.id IN %(candidate_buildroot_ids)s')

View file

@ -117,6 +117,7 @@ info commands:
list-untagged List untagged builds
list-volumes List storage volumes
mock-config Create a mock config
repoinfo Print basic information about a repo
rpminfo Print basic information about an RPM
show-groups Show groups data for a tag
taginfo Print basic information about a tag

View file

@ -0,0 +1,264 @@
from __future__ import absolute_import
import unittest
import mock
import six
import tempfile
from koji_cli.commands import anon_handle_repoinfo
import koji
from . import utils
class TestRepoinfo(utils.CliTestCase):
def __vm(self, result):
m = koji.VirtualCall('mcall_method', [], {})
if isinstance(result, dict) and result.get('faultCode'):
m._result = result
else:
m._result = (result,)
return m
def setUp(self):
# Show long diffs in error output...
self.maxDiff = None
self.options = mock.MagicMock()
self.options.debug = False
self.session = mock.MagicMock()
self.session.getAPIVersion.return_value = koji.API_VERSION
self.ensure_connection = mock.patch('koji_cli.commands.ensure_connection').start()
self.tempdir = tempfile.mkdtemp()
self.error_format = """Usage: %s repoinfo [options] <repo-id> [<repo-id> ...]
(Specify the --help global option for a list of other help options)
%s: error: {message}
""" % (self.progname, self.progname)
self.repo_id = '123'
self.multi_broots = [
{'id': 1101, 'repo_id': 101, 'tag_name': 'tag_101', 'arch': 'x86_64'},
{'id': 1111, 'repo_id': 111, 'tag_name': 'tag_111', 'arch': 'x86_64'},
{'id': 1121, 'repo_id': 121, 'tag_name': 'tag_121', 'arch': 'x86_64'}
]
def tearDown(self):
mock.patch.stopall()
@mock.patch('koji.formatTimeLong', return_value='Thu, 01 Jan 2000')
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('sys.stdout', new_callable=six.StringIO)
def test_repoinfo_valid_not_dist_repo_with_buildroot_opt(self, stdout, stderr, formattimelong):
repoinfo = {'external_repo_id': 1, 'id': self.repo_id, 'tag_id': 11,
'tag_name': 'test-tag', 'state': 1, 'create_ts': 1632914520.353734,
'create_event': 999, 'dist': False, 'task_id': 555}
self.options.topurl = 'https://www.domain.local'
mcall = self.session.multicall.return_value.__enter__.return_value
mcall.repoInfo.return_value = self.__vm(repoinfo)
self.session.listBuildroots.return_value = self.multi_broots
arguments = [self.repo_id, '--buildroots']
rv = anon_handle_repoinfo(self.options, self.session, arguments)
url = '{}/repos/test-tag/123'.format(self.options.topurl)
repo_json = '{}/repos/test-tag/123/repo.json'.format(self.options.topurl)
expected = """ID: %s
Tag ID: %d
Tag name: %s
State: %s
Created: Thu, 01 Jan 2000
Created event: %d
URL: %s
Repo json: %s
Dist repo?: no
Task ID: %d
Number of buildroots: 3
Buildroots ID:
1101
1111
1121
""" % (self.repo_id, repoinfo['tag_id'], repoinfo['tag_name'],
koji.REPO_STATES[repoinfo['state']], repoinfo['create_event'], url, repo_json,
repoinfo['task_id'])
actual = stdout.getvalue()
self.assertMultiLineEqual(actual, expected)
actual = stderr.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
self.assertEqual(rv, None)
self.ensure_connection.assert_called_once_with(self.session, self.options)
self.session.multicall.assert_called_once()
self.session.repoInfo.assert_not_called()
self.session.listBuildroots.assert_called_once_with(repoID=self.repo_id)
@mock.patch('koji.formatTimeLong', return_value='Thu, 01 Jan 2000')
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('sys.stdout', new_callable=six.StringIO)
def test_repoinfo_valid_dist_repo(self, stdout, stderr, formattimelong):
repoinfo = {'external_repo_id': 1, 'id': self.repo_id, 'tag_id': 11,
'tag_name': 'test-tag', 'state': 1, 'create_ts': 1632914520.353734,
'create_event': 999, 'dist': True, 'task_id': 555}
mcall = self.session.multicall.return_value.__enter__.return_value
mcall.repoInfo.return_value = self.__vm(repoinfo)
self.session.listBuildroots.return_value = self.multi_broots
self.options.topurl = 'https://www.domain.local'
arguments = [self.repo_id]
rv = anon_handle_repoinfo(self.options, self.session, arguments)
url = '{}/repos/test-tag/123'.format(self.options.topurl)
repo_json = '{}/repos-dist/test-tag/123/repo.json'.format(self.options.topurl)
expected = """ID: %s
Tag ID: %d
Tag name: %s
State: %s
Created: Thu, 01 Jan 2000
Created event: %d
URL: %s
Repo json: %s
Dist repo?: yes
Task ID: %d
Number of buildroots: 3
""" % (self.repo_id, repoinfo['tag_id'], repoinfo['tag_name'],
koji.REPO_STATES[repoinfo['state']], repoinfo['create_event'], url, repo_json,
repoinfo['task_id'])
actual = stdout.getvalue()
self.assertMultiLineEqual(actual, expected)
actual = stderr.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
self.assertEqual(rv, None)
self.ensure_connection.assert_called_once_with(self.session, self.options)
self.session.multicall.assert_called_once()
self.session.repoInfo.assert_not_called()
self.session.listBuildroots.assert_called_once_with(repoID=self.repo_id)
@mock.patch('koji.formatTimeLong', return_value='Thu, 01 Jan 2000')
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('sys.stdout', new_callable=six.StringIO)
def test_repoinfo_valid_buildroot_not_available_on_hub(self, stdout, stderr, formattimelong):
repoinfo = {'external_repo_id': 1, 'id': self.repo_id, 'tag_id': 11,
'tag_name': 'test-tag', 'state': 1, 'create_ts': 1632914520.353734,
'create_event': 999, 'dist': False, 'task_id': 555}
self.options.topurl = 'https://www.domain.local'
mcall = self.session.multicall.return_value.__enter__.return_value
mcall.repoInfo.return_value = self.__vm(repoinfo)
self.session.listBuildroots.side_effect = koji.ParameterError
arguments = [self.repo_id, '--buildroots']
rv = anon_handle_repoinfo(self.options, self.session, arguments)
url = '{}/repos/test-tag/123'.format(self.options.topurl)
repo_json = '{}/repos/test-tag/123/repo.json'.format(self.options.topurl)
expected = """ID: %s
Tag ID: %d
Tag name: %s
State: %s
Created: Thu, 01 Jan 2000
Created event: %d
URL: %s
Repo json: %s
Dist repo?: no
Task ID: %d
""" % (self.repo_id, repoinfo['tag_id'], repoinfo['tag_name'],
koji.REPO_STATES[repoinfo['state']], repoinfo['create_event'], url, repo_json,
repoinfo['task_id'])
actual = stdout.getvalue()
self.assertMultiLineEqual(actual, expected)
actual = stderr.getvalue()
expecter_warn = "--buildroots option is available with hub 1.33 or newer\n"
self.assertMultiLineEqual(actual, expecter_warn)
self.assertEqual(rv, None)
self.ensure_connection.assert_called_once_with(self.session, self.options)
self.session.multicall.assert_called_once()
self.session.repoInfo.assert_not_called()
self.session.listBuildroots.assert_called_once_with(repoID=self.repo_id)
@mock.patch('koji.formatTimeLong', return_value='Thu, 01 Jan 2000')
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('sys.stdout', new_callable=six.StringIO)
def test_repoinfo_valid_without_buildroot_not_available_on_hub(
self, stdout, stderr, formattimelong):
repoinfo = {'external_repo_id': 1, 'id': self.repo_id, 'tag_id': 11,
'tag_name': 'test-tag', 'state': 1, 'create_ts': 1632914520.353734,
'create_event': 999, 'dist': False, 'task_id': 555}
self.options.topurl = 'https://www.domain.local'
mcall = self.session.multicall.return_value.__enter__.return_value
mcall.repoInfo.return_value = self.__vm(repoinfo)
self.session.listBuildroots.side_effect = koji.ParameterError
arguments = [self.repo_id]
rv = anon_handle_repoinfo(self.options, self.session, arguments)
url = '{}/repos/test-tag/123'.format(self.options.topurl)
repo_json = '{}/repos/test-tag/123/repo.json'.format(self.options.topurl)
expected = """ID: %s
Tag ID: %d
Tag name: %s
State: %s
Created: Thu, 01 Jan 2000
Created event: %d
URL: %s
Repo json: %s
Dist repo?: no
Task ID: %d
""" % (self.repo_id, repoinfo['tag_id'], repoinfo['tag_name'],
koji.REPO_STATES[repoinfo['state']], repoinfo['create_event'], url, repo_json,
repoinfo['task_id'])
actual = stdout.getvalue()
self.assertMultiLineEqual(actual, expected)
actual = stderr.getvalue()
expecter_warn = ""
self.assertMultiLineEqual(actual, expecter_warn)
self.assertEqual(rv, None)
self.ensure_connection.assert_called_once_with(self.session, self.options)
self.session.multicall.assert_called_once()
self.session.repoInfo.assert_not_called()
self.session.listBuildroots.assert_called_once_with(repoID=self.repo_id)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
def test_repoinfo__not_exist_repo(self, stderr, stdout):
mcall = self.session.multicall.return_value.__enter__.return_value
mcall.repoInfo.return_value = self.__vm(None)
arguments = [self.repo_id]
rv = anon_handle_repoinfo(self.options, self.session, arguments)
actual = stderr.getvalue()
expected = "No such repo: %s\n\n" % self.repo_id
self.assertMultiLineEqual(actual, expected)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
self.assertEqual(rv, None)
self.ensure_connection.assert_called_once_with(self.session, self.options)
self.session.multicall.assert_called_once()
self.session.repoInfo.assert_not_called()
self.session.listBuildroots.assert_not_called()
def test_repoinfo_without_args(self):
arguments = []
# Run it and check immediate output
self.assert_system_exit(
anon_handle_repoinfo,
self.options, self.session, arguments,
stderr=self.format_error_message('Please specify a repo ID'),
stdout='',
activate_session=None,
exit_code=2)
# Finally, assert that things were called as we expected.
self.ensure_connection.assert_not_called()
self.session.repoInfo.assert_not_called()
self.session.listBuildroots.assert_not_called()
def test_repoinfo_help(self):
self.assert_help(
anon_handle_repoinfo,
"""Usage: %s repoinfo [options] <repo-id> [<repo-id> ...]
(Specify the --help global option for a list of other help options)
Options:
-h, --help show this help message and exit
--buildroots Prints list of buildroot IDs
""" % self.progname)
if __name__ == '__main__':
unittest.main()

View file

@ -46,7 +46,7 @@ class TestUserinfo(utils.CliTestCase):
self.assert_console_message(stderr, expected)
@mock.patch('sys.stderr', new_callable=StringIO)
def test_userinfo_non_exist_tag(self, stderr):
def test_userinfo_non_exist_user(self, stderr):
expected_warn = "No such user: %s\n\n" % self.user
mcall = self.session.multicall.return_value.__enter__.return_value

View file

@ -0,0 +1,71 @@
import unittest
import mock
import kojihub
QP = kojihub.QueryProcessor
class TestQueryBuildroots(unittest.TestCase):
def getQuery(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = self.query_execute
self.queries.append(query)
return query
def setUp(self):
self.QueryProcessor = mock.patch('kojihub.kojihub.QueryProcessor',
side_effect=self.getQuery).start()
self.repo_references = mock.patch('kojihub.kojihub.repo_references').start()
self.queries = []
self.query_execute = mock.MagicMock()
def test_query_buildroots(self):
self.query_execute.side_effect = [[7], [7], [7], []]
self.repo_references.return_value = [{'id': 7, 'host_id': 1, 'create_event': 333,
'state': 1}]
kojihub.query_buildroots(hostID=1, tagID=2, state=1, rpmID=3, archiveID=4, taskID=5,
buildrootID=7, repoID=10)
self.assertEqual(len(self.queries), 4)
query = self.queries[0]
self.assertEqual(query.tables, ['buildroot_listing'])
self.assertEqual(query.columns, ['buildroot_id'])
self.assertEqual(query.clauses, ['rpm_id = %(rpmID)i'])
self.assertEqual(query.joins, None)
query = self.queries[1]
self.assertEqual(query.tables, ['buildroot_archives'])
self.assertEqual(query.columns, ['buildroot_id'])
self.assertEqual(query.clauses, ['archive_id = %(archiveID)i'])
self.assertEqual(query.joins, None)
query = self.queries[2]
self.assertEqual(query.tables, ['standard_buildroot'])
self.assertEqual(query.columns, ['buildroot_id'])
self.assertEqual(query.clauses, ['task_id = %(taskID)i'])
self.assertEqual(query.joins, None)
query = self.queries[3]
self.assertEqual(query.tables, ['standard_buildroot'])
self.assertEqual(query.columns, ['buildroot_id'])
self.assertEqual(query.clauses, ['repo_id = %(repoID)i'])
self.assertEqual(query.joins, None)
def test_query_buildroots_some_params_as_list(self):
kojihub.query_buildroots(state=[1], buildrootID=[7])
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['buildroot'])
self.assertEqual(query.clauses, ['buildroot.id IN %(buildrootID)s',
'standard_buildroot.state IN %(state)s'])
self.assertEqual(query.joins,
['LEFT OUTER JOIN standard_buildroot ON '
'standard_buildroot.buildroot_id = buildroot.id',
'LEFT OUTER JOIN content_generator ON '
'buildroot.cg_id = content_generator.id',
'LEFT OUTER JOIN host ON host.id = standard_buildroot.host_id',
'LEFT OUTER JOIN repo ON repo.id = standard_buildroot.repo_id',
'LEFT OUTER JOIN tag ON tag.id = repo.tag_id',
'LEFT OUTER JOIN events AS create_events ON '
'create_events.id = standard_buildroot.create_event',
'LEFT OUTER JOIN events AS retire_events ON '
'standard_buildroot.retire_event = retire_events.id',
'LEFT OUTER JOIN events AS repo_create ON '
'repo_create.id = repo.create_event'])

View file

@ -0,0 +1,97 @@
#import koji
#from kojiweb import util
#attr _PASSTHROUGH = ['repoID', 'order', 'state']
#include "includes/header.chtml"
<h4>Buildroots in repo <a href="repoinfo?repoID=$repoID">$repoID</a></h4>
<table class="data-list">
<tr>
<td colspan="5">
<table class="nested">
<tr><td>
<strong>State</strong>:
</td><td>
<select name="state" class="filterlist" onchange="javascript: window.location = 'buildroots?state=' + this.value + '$util.passthrough_except($self, 'state')';">
<option value="all">all</option>
#for $stateOpt in ['INIT', 'WAITING', 'BUILDING', 'EXPIRED']
<option value="$koji.BR_STATES[$stateOpt]" #if $state == $koji.BR_STATES[$stateOpt] then 'selected="selected"' else ''#>$stateOpt.lower()</option>
#end for
</select>
</table>
</td>
</tr>
<tr>
<td class="paginate" colspan="5">
#if $len($buildrootPages) > 1
<form class="pageJump" action="">
Page:
<select onchange="javascript: window.location = 'builds?start=' + this.value * $buildrootRange + '$util.passthrough_except($self)';">
#for $pageNum in $buildrootPages
<option value="$pageNum"#if $pageNum == $buildrootCurrentPage then ' selected="selected"' else ''#>#echo $pageNum + 1#</option>
#end for
</select>
</form>
#end if
#if $buildrootStart > 0
<a href="builds?start=#echo $buildrootStart - $buildrootRange #$util.passthrough_except($self)">&lt;&lt;&lt;</a>
#end if
#if $totalBuildroots != 0
<strong>Buildroots #echo $buildrootStart + 1 # through #echo $buildrootStart + $buildrootCount # of $totalBuildroots</strong>
#end if
#if $buildrootStart + $buildrootCount < $totalBuildroots
<a href="builds?start=#echo $buildrootStart + $buildrootRange#$util.passthrough_except($self)">&gt;&gt;&gt;</a>
#end if
</td>
</tr>
<tr class="list-header">
<th><a href="buildroots?order=$util.toggleOrder($self, 'id')$util.passthrough_except($self, 'order')">BuildrootID</a> $util.sortImage($self, 'id')</th>
<th><a href="buildroots?order=$util.toggleOrder($self, 'repo_id')$util.passthrough_except($self, 'order')">Repo ID</a> $util.sortImage($self, 'repo_id')</th>
<th><a href="buildroots?order=$util.toggleOrder($self, 'task_id')$util.passthrough_except($self, 'order')">Task ID</a> $util.sortImage($self, 'task_id')</th>
<th><a href="buildroots?order=$util.toggleOrder($self, 'tag_name')$util.passthrough_except($self, 'order')">Tag name</a> $util.sortImage($self, 'tag_name')</th>
<th><a href="buildroots?order=$util.toggleOrder($self, 'state')$util.passthrough_except($self, 'order')">State</a> $util.sortImage($self, 'state')</th>
</tr>
#if $len($buildroots) > 0
#for $buildroot in $buildroots
<tr class="$util.rowToggle($self)">
<td><a href="buildrootinfo?buildrootID=$buildroot.id">$buildroot.id</a></td>
<td><a href="repoinfo?repoID=$buildroot.repo_id">$buildroot.repo_id</a></td>
<td><a href="taskinfo?taskID=$buildroot.task_id">$buildroot.task_id</a></td>
<td><a href="taginfo?tagID=$buildroot.tag_id">$util.escapeHTML($buildroot.tag_name)</a></td>
#set $stateName = $util.brStateName($buildroot.state)
<td class="$stateName">$util.brStateImage($buildroot.state)</td>
</tr>
#end for
#else
<tr class="row-odd">
<td colspan="5">No buildroots</td>
</tr>
#end if
<tr>
<td class="paginate" colspan="5">
#if $len($buildrootPages) > 1
<form class="pageJump" action="">
Page:
<select onchange="javascript: window.location = 'builds?start=' + this.value * $buildrootRange + '$util.passthrough_except($self)';">
#for $pageNum in $buildrootPages
<option value="$pageNum"#if $pageNum == $buildrootCurrentPage then ' selected="selected"' else ''#>#echo $pageNum + 1#</option>
#end for
</select>
</form>
#end if
#if $buildrootStart > 0
<a href="builds?start=#echo $buildrootStart - $buildrootRange #$util.passthrough_except($self)">&lt;&lt;&lt;</a>
#end if
#if $totalBuildroots != 0
<strong>Buildroots #echo $buildrootStart + 1 # through #echo $buildrootStart + $buildrootCount # of $totalBuildroots</strong>
#end if
#if $buildrootStart + $buildrootCount < $totalBuildroots
<a href="builds?start=#echo $buildrootStart + $buildrootRange#$util.passthrough_except($self)">&gt;&gt;&gt;</a>
#end if
</td>
</tr>
</table>
#include "includes/footer.chtml"

View file

@ -2659,6 +2659,8 @@ def repoinfo(environ, repoID):
else:
values['repo_json'] = os.path.join(
pathinfo.repo(repo_info['id'], repo_info['tag_name']), 'repo.json')
num_buildroots = len(server.listBuildroots(repoID=repoID)) or 0
values['numBuildroots'] = num_buildroots
return _genHTML(environ, 'repoinfo.chtml')
@ -2692,3 +2694,21 @@ def activesessiondelete(environ, sessionID):
server.logout(session_id=sessionID)
_redirect(environ, 'activesession')
def buildroots(environ, repoID=None, order='id', start=None, state=None):
values = _initValues(environ, 'Buildroots', 'buildroots')
server = _getServer(environ)
values['repoID'] = repoID
values['order'] = order
if state == 'all':
state = None
elif state is not None:
state = int(state)
values['state'] = state
kojiweb.util.paginateMethod(server, values, 'listBuildroots',
kw={'repoID': repoID, 'state': state}, start=start,
dataName='buildroots', prefix='buildroot', order=order)
return _genHTML(environ, 'buildroots.chtml')

View file

@ -20,6 +20,7 @@
<tr><th>Repo json</th><td><a href="$repo_json">repo.json</a></td></tr>
#end if
<tr><th>Dist repo?</th><td class="$str($repo.dist).lower()">#if $repo.dist then 'yes' else 'no'#</td></tr>
<tr><th>Number of buildroots: </th><td><a href="buildroots?repoID=$repo.id">$numBuildroots</a></td></tr>
</table>
#else
Repo $repo_id not found.

View file

@ -433,6 +433,13 @@ def brStateName(stateID):
return koji.BR_STATES[stateID].lower()
def brStateImage(stateID):
"""Return an IMG tag that loads an icon appropriate for
the given state"""
name = brStateName(stateID)
return imageTag(name)
def brLabel(brinfo):
if brinfo['br_type'] == koji.BR_TYPES['STANDARD']:
return '%(tag_name)s-%(id)i-%(repo_id)i' % brinfo