make cli and hub to support remove-extra for edit-tag
This commit is contained in:
parent
120ee07d24
commit
75d07f6d01
4 changed files with 409 additions and 8 deletions
6
cli/koji
6
cli/koji
|
|
@ -4886,6 +4886,8 @@ def handle_edit_tag(options, session, args):
|
|||
parser.add_option("--no-include-all", action="store_true", help=_("Do not include all packages in this tag when generating Maven repos"))
|
||||
parser.add_option("-x", "--extra", action="append", default=[], metavar="key=value",
|
||||
help=_("Set tag extra option"))
|
||||
parser.add_option("-r", "--remove-extra", action="append", default=[], metavar="key",
|
||||
help=_("Remove tag extra option"))
|
||||
(options, args) = parser.parse_args(args)
|
||||
if len(args) != 1:
|
||||
parser.error(_("Please specify a name for the tag"))
|
||||
|
|
@ -4920,8 +4922,10 @@ def handle_edit_tag(options, session, args):
|
|||
value = arg_filter(value)
|
||||
extra[key] = value
|
||||
opts['extra'] = extra
|
||||
if options.remove_extra:
|
||||
opts['remove_extra'] = options.remove_extra
|
||||
#XXX change callname
|
||||
session.editTag2(tag,**opts)
|
||||
session.editTag2(tag, **opts)
|
||||
|
||||
def handle_lock_tag(options, session, args):
|
||||
"[admin] Lock a tag"
|
||||
|
|
|
|||
|
|
@ -2976,7 +2976,8 @@ def edit_tag(tagInfo, **kwargs):
|
|||
maven_support: whether Maven repos should be generated for the tag
|
||||
maven_include_all: include every build in this tag (including multiple
|
||||
versions of the same package) in the Maven repo
|
||||
extra: extra tag parameters (dictionary)
|
||||
extra: add or update extra tag parameters (dictionary)
|
||||
remove_extra: remove extra tag parameters (list)
|
||||
"""
|
||||
|
||||
context.session.assertPerm('admin')
|
||||
|
|
@ -3014,8 +3015,8 @@ def _edit_tag(tagInfo, **kwargs):
|
|||
#new name is taken
|
||||
raise koji.GenericError("Name %s already taken by tag %s" % (name, id))
|
||||
update = """UPDATE tag
|
||||
SET name = %(name)s
|
||||
WHERE id = %(tagID)i"""
|
||||
SET name = %(name)s
|
||||
WHERE id = %(tagID)i"""
|
||||
_dml(update, values)
|
||||
|
||||
#check for changes
|
||||
|
|
@ -3038,13 +3039,18 @@ def _edit_tag(tagInfo, **kwargs):
|
|||
|
||||
# handle extra data
|
||||
if 'extra' in kwargs:
|
||||
# check whether one key is both in extra and remove_extra
|
||||
if 'remove_extra' in kwargs:
|
||||
for removed in kwargs['remove_extra']:
|
||||
if removed in kwargs['extra']:
|
||||
raise koji.GenericError("Can not both add/update and remove tag-extra: '%s'" % removed)
|
||||
for key in kwargs['extra']:
|
||||
value = kwargs['extra'][key]
|
||||
if key not in tag['extra'] or tag['extra'] != value:
|
||||
if key not in tag['extra'] or tag['extra'][key] != value:
|
||||
data = {
|
||||
'tag_id' : tag['id'],
|
||||
'key' : key,
|
||||
'value' : json.dumps(kwargs['extra'][key]),
|
||||
'tag_id': tag['id'],
|
||||
'key': key,
|
||||
'value': json.dumps(kwargs['extra'][key]),
|
||||
}
|
||||
# revoke old entry, if any
|
||||
update = UpdateProcessor('tag_extra', values=data, clauses=['tag_id = %(tag_id)i', 'key=%(key)s'])
|
||||
|
|
@ -3055,6 +3061,21 @@ def _edit_tag(tagInfo, **kwargs):
|
|||
insert.make_create()
|
||||
insert.execute()
|
||||
|
||||
# handle remove_extra data
|
||||
if 'remove_extra' in kwargs:
|
||||
ne = [e for e in kwargs['remove_extra'] if e not in tag['extra']]
|
||||
if ne:
|
||||
raise koji.GenericError("Tag: %s doesn't have extra: %s" % (tag['name'], ', '.join(ne)))
|
||||
for key in kwargs['remove_extra']:
|
||||
data = {
|
||||
'tag_id': tag['id'],
|
||||
'key': key,
|
||||
}
|
||||
# revoke old entry
|
||||
update = UpdateProcessor('tag_extra', values=data, clauses=['tag_id = %(tag_id)i', 'key=%(key)s'])
|
||||
update.make_revoke()
|
||||
update.execute()
|
||||
|
||||
|
||||
def old_edit_tag(tagInfo, name, arches, locked, permissionID, extra=None):
|
||||
"""Edit information for an existing tag."""
|
||||
|
|
|
|||
180
tests/test_cli/test_edit_tag.py
Normal file
180
tests/test_cli/test_edit_tag.py
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
import unittest
|
||||
|
||||
import StringIO as stringio
|
||||
|
||||
import os
|
||||
|
||||
import sys
|
||||
|
||||
import mock
|
||||
|
||||
from mock import call
|
||||
|
||||
import loadcli
|
||||
|
||||
cli = loadcli.cli
|
||||
|
||||
progname = os.path.basename(sys.argv[0]) or 'koji'
|
||||
|
||||
|
||||
class TestEditTag(unittest.TestCase):
|
||||
# Show long diffs in error output...
|
||||
maxDiff = None
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.activate_session')
|
||||
def test_handle_edit_tag(self, activate_session_mock, stdout):
|
||||
tag = 'tag'
|
||||
arches = 'arch1 arch2'
|
||||
perm = 'perm'
|
||||
locked = True
|
||||
rename = 'tag2'
|
||||
maven_support = True
|
||||
maven_include_all = True
|
||||
extra = {'extraA': 'A', 'extraB': True}
|
||||
remove_extra = ['extraC', 'extraD']
|
||||
args = [tag]
|
||||
args.append('--arches=' + arches)
|
||||
args.append('--perm=' + perm)
|
||||
args.append('--lock')
|
||||
args.append('--rename=' + rename)
|
||||
args.append('--maven-support')
|
||||
args.append('--include-all')
|
||||
for k, x in extra.iteritems():
|
||||
args.append('-x')
|
||||
args.append(k + '=' + str(x))
|
||||
for r in remove_extra:
|
||||
args.append('-r')
|
||||
args.append(r)
|
||||
opts = {'arches': arches,
|
||||
'perm': perm,
|
||||
'locked': locked,
|
||||
'name': rename,
|
||||
'maven_support': maven_support,
|
||||
'maven_include_all': maven_include_all,
|
||||
'extra': extra,
|
||||
'remove_extra': remove_extra}
|
||||
options = mock.MagicMock()
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
|
||||
# Run it and check immediate output
|
||||
# args: tag --arches='arch1 arch2' --perm --lock
|
||||
# --rename=tag2 --maven-support --include-all
|
||||
# -x extraA=A -x extraB=True -r extraC -r extraD
|
||||
# expected: success
|
||||
rv = cli.handle_edit_tag(options, session, args)
|
||||
actual = stdout.getvalue()
|
||||
expected = ''
|
||||
self.assertMultiLineEqual(actual, expected)
|
||||
# Finally, assert that things were called as we expected.
|
||||
activate_session_mock.assert_called_once_with(session)
|
||||
session.editTag2.assert_called_once_with(tag, **opts)
|
||||
self.assertEqual(rv, None)
|
||||
|
||||
stdout.seek(0)
|
||||
stdout.truncate()
|
||||
session.reset_mock()
|
||||
activate_session_mock.reset_mock()
|
||||
args = [tag]
|
||||
args.append('--no-perm')
|
||||
args.append('--unlock')
|
||||
args.append('--no-maven-support')
|
||||
args.append('--no-include-all')
|
||||
opts = {'perm_id': None,
|
||||
'locked': not locked,
|
||||
'maven_support': not maven_support,
|
||||
'maven_include_all': not maven_include_all}
|
||||
# Run it and check immediate output
|
||||
# args: tag --no-perm --unlock --no-maven-support --no-include-all
|
||||
# expected: success
|
||||
rv = cli.handle_edit_tag(options, session, args)
|
||||
actual = stdout.getvalue()
|
||||
expected = ''
|
||||
self.assertMultiLineEqual(actual, expected)
|
||||
# Finally, assert that things were called as we expected.
|
||||
activate_session_mock.assert_called_once_with(session)
|
||||
session.editTag2.assert_called_once_with(tag, **opts)
|
||||
self.assertEqual(rv, None)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('sys.stderr', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.activate_session')
|
||||
def test_handle_edit_tag_help(self, activate_session_mock, stderr, stdout):
|
||||
args = ['--help']
|
||||
options = mock.MagicMock()
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
|
||||
# Run it and check immediate output
|
||||
# args: --help
|
||||
# expected: failed, help info shows
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
cli.handle_edit_tag(options, session, args)
|
||||
actual_stdout = stdout.getvalue()
|
||||
actual_stderr = stderr.getvalue()
|
||||
expected_stdout = """Usage: %s edit-tag [options] name
|
||||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
--arches=ARCHES Specify arches
|
||||
--perm=PERM Specify permission requirement
|
||||
--no-perm Remove permission requirement
|
||||
--lock Lock the tag
|
||||
--unlock Unlock the tag
|
||||
--rename=RENAME Rename the tag
|
||||
--maven-support Enable creation of Maven repos for this tag
|
||||
--no-maven-support Disable creation of Maven repos for this tag
|
||||
--include-all Include all packages in this tag when generating Maven
|
||||
repos
|
||||
--no-include-all Do not include all packages in this tag when
|
||||
generating Maven repos
|
||||
-x key=value, --extra=key=value
|
||||
Set tag extra option
|
||||
-r key, --remove-extra=key
|
||||
Remove tag extra option
|
||||
""" % progname
|
||||
expected_stderr = ''
|
||||
self.assertMultiLineEqual(actual_stdout, expected_stdout)
|
||||
self.assertMultiLineEqual(actual_stderr, expected_stderr)
|
||||
# Finally, assert that things were called as we expected.
|
||||
activate_session_mock.assert_not_called()
|
||||
session.editTag2.assert_not_called()
|
||||
self.assertEqual(cm.exception.code, 0)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('sys.stderr', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.activate_session')
|
||||
def test_handle_edit_tag_no_arg(self, activate_session_mock, stderr, stdout):
|
||||
args = []
|
||||
options = mock.MagicMock()
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
|
||||
# Run it and check immediate output
|
||||
# args: --help
|
||||
# expected: failed, help info shows
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
cli.handle_edit_tag(options, session, args)
|
||||
actual_stdout = stdout.getvalue()
|
||||
actual_stderr = stderr.getvalue()
|
||||
expected_stdout = ''
|
||||
expected_stderr = """Usage: %(progname)s edit-tag [options] name
|
||||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
%(progname)s: error: Please specify a name for the tag
|
||||
""" % {'progname': progname}
|
||||
self.assertMultiLineEqual(actual_stdout, expected_stdout)
|
||||
self.assertMultiLineEqual(actual_stderr, expected_stderr)
|
||||
# Finally, assert that things were called as we expected.
|
||||
activate_session_mock.assert_not_called()
|
||||
session.editTag2.assert_not_called()
|
||||
self.assertEqual(cm.exception.code, 2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
196
tests/test_hub/test_edit_tag.py
Normal file
196
tests/test_hub/test_edit_tag.py
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
import mock
|
||||
import unittest
|
||||
|
||||
import koji
|
||||
import kojihub
|
||||
|
||||
UP = kojihub.UpdateProcessor
|
||||
IP = kojihub.InsertProcessor
|
||||
|
||||
|
||||
class TestEditTag(unittest.TestCase):
|
||||
def getInsert(self, *args, **kwargs):
|
||||
insert = IP(*args, **kwargs)
|
||||
insert.execute = mock.MagicMock()
|
||||
self.inserts.append(insert)
|
||||
return insert
|
||||
|
||||
def getUpdate(self, *args, **kwargs):
|
||||
update = UP(*args, **kwargs)
|
||||
update.execute = mock.MagicMock()
|
||||
self.updates.append(update)
|
||||
return update
|
||||
|
||||
def setUp(self):
|
||||
self.InsertProcessor = mock.patch('kojihub.InsertProcessor',
|
||||
side_effect=self.getInsert).start()
|
||||
self.inserts = []
|
||||
self.UpdateProcessor = mock.patch('kojihub.UpdateProcessor',
|
||||
side_effect=self.getUpdate).start()
|
||||
self.updates = []
|
||||
self._dml = mock.patch('kojihub._dml').start()
|
||||
self._singleValue = mock.patch('kojihub._singleValue').start()
|
||||
self.get_tag = mock.patch('kojihub.get_tag').start()
|
||||
self.get_perm_id = mock.patch('kojihub.get_perm_id').start()
|
||||
self.context = mock.patch('kojihub.context').start()
|
||||
# It seems MagicMock will not automatically handle attributes that
|
||||
# start with "assert"
|
||||
self.context.session.assertLogin = mock.MagicMock()
|
||||
|
||||
def tearDown(self):
|
||||
mock.patch.stopall()
|
||||
|
||||
def test_maven_disable(self):
|
||||
self.context.opts.get.return_value = False
|
||||
with self.assertRaises(koji.GenericError):
|
||||
kojihub._edit_tag('tag', maven_support=True)
|
||||
with self.assertRaises(koji.GenericError):
|
||||
kojihub._edit_tag('tag', maven_include_all=False)
|
||||
self.context.opts.get.return_value = True
|
||||
kojihub._edit_tag('tag', maven_support=True)
|
||||
self.get_tag.assert_called_once()
|
||||
|
||||
def test_edit(self):
|
||||
self.get_tag.return_value = {'id': 333,
|
||||
'perm_id': 1,
|
||||
'name': 'tag',
|
||||
'arches': 'arch1 arch3',
|
||||
'locked': False,
|
||||
'maven_support': False,
|
||||
'maven_include_all': False,
|
||||
'extra': {'exA': 1,
|
||||
'exC': 3,
|
||||
'exD': 4}}
|
||||
self._singleValue.return_value = None
|
||||
self.context.event_id = 42
|
||||
self.context.session.user_id = 23
|
||||
# no1 invoke
|
||||
kwargs = {
|
||||
'perm': None,
|
||||
'name': 'newtag',
|
||||
'arches': 'arch1 arch2',
|
||||
'locked': True,
|
||||
'maven_support': True,
|
||||
'maven_include_all': True,
|
||||
'extra': {'exB': [None, 1, 'text', {'dict': 'val'}, (1, 2)]},
|
||||
'remove_extra': ['exC']
|
||||
}
|
||||
kojihub._edit_tag('tag', **kwargs)
|
||||
|
||||
self.get_perm_id.assert_not_called()
|
||||
self._dml.assert_called_with("""UPDATE tag
|
||||
SET name = %(name)s
|
||||
WHERE id = %(tagID)i""", {'name': 'newtag', 'tagID': 333})
|
||||
|
||||
# check the insert/update
|
||||
self.assertEqual(len(self.updates), 3)
|
||||
self.assertEqual(len(self.inserts), 2)
|
||||
values = {
|
||||
'arches': 'arch1 arch2',
|
||||
'locked': True,
|
||||
'maven_include_all': True,
|
||||
'maven_support': True,
|
||||
'perm_id': None,
|
||||
'id': 333,
|
||||
'name': 'tag',
|
||||
'extra': {'exA': 1, 'exC': 3, 'exD': 4}
|
||||
}
|
||||
revoke_data = {
|
||||
'revoke_event': 42,
|
||||
'revoker_id': 23
|
||||
}
|
||||
revoke_rawdata = {'active': 'NULL'}
|
||||
update = self.updates[0]
|
||||
self.assertEqual(update.table, 'tag_config')
|
||||
self.assertEqual(update.values, values)
|
||||
self.assertEqual(update.data, revoke_data)
|
||||
self.assertEqual(update.rawdata, revoke_rawdata)
|
||||
self.assertEqual(update.clauses, ['tag_id = %(id)i', 'active = TRUE'])
|
||||
|
||||
data = {
|
||||
'create_event': 42,
|
||||
'creator_id': 23,
|
||||
'arches': 'arch1 arch2',
|
||||
'locked': True,
|
||||
'maven_include_all': True,
|
||||
'maven_support': True,
|
||||
'perm_id': None,
|
||||
'tag_id': 333,
|
||||
}
|
||||
insert = self.inserts[0]
|
||||
self.assertEqual(insert.table, 'tag_config')
|
||||
self.assertEqual(insert.data, data)
|
||||
self.assertEqual(insert.rawdata, {})
|
||||
|
||||
values = {
|
||||
'key': 'exB',
|
||||
'value': '[null, 1, "text", {"dict": "val"}, [1, 2]]',
|
||||
'tag_id': 333,
|
||||
}
|
||||
|
||||
update = self.updates[1]
|
||||
self.assertEqual(update.table, 'tag_extra')
|
||||
self.assertEqual(update.values, values)
|
||||
self.assertEqual(update.data, revoke_data)
|
||||
self.assertEqual(update.rawdata, revoke_rawdata)
|
||||
self.assertEqual(update.clauses, ['tag_id = %(tag_id)i', 'key=%(key)s', 'active = TRUE'])
|
||||
|
||||
data = {
|
||||
'create_event': 42,
|
||||
'creator_id': 23,
|
||||
'key': 'exB',
|
||||
'value': '[null, 1, "text", {"dict": "val"}, [1, 2]]',
|
||||
'tag_id': 333,
|
||||
}
|
||||
|
||||
insert = self.inserts[1]
|
||||
self.assertEqual(insert.table, 'tag_extra')
|
||||
self.assertEqual(insert.data, data)
|
||||
self.assertEqual(insert.rawdata, {})
|
||||
|
||||
values = {
|
||||
'key': 'exC',
|
||||
'tag_id': 333,
|
||||
}
|
||||
|
||||
update = self.updates[2]
|
||||
self.assertEqual(update.table, 'tag_extra')
|
||||
self.assertEqual(update.values, values)
|
||||
self.assertEqual(update.data, revoke_data)
|
||||
self.assertEqual(update.rawdata, revoke_rawdata)
|
||||
self.assertEqual(update.clauses, ['tag_id = %(tag_id)i', 'key=%(key)s', 'active = TRUE'])
|
||||
|
||||
# no2 invoke
|
||||
kwargs = {
|
||||
'extra': {'exC': 'text'},
|
||||
'remove_extra': ['exC']
|
||||
}
|
||||
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
kojihub._edit_tag('tag', **kwargs)
|
||||
self.assertEqual(cm.exception.args[0], 'Can not both add/update and remove tag-extra: \'exC\'')
|
||||
|
||||
# no3 invoke
|
||||
kwargs = {
|
||||
'remove_extra': ['exE']
|
||||
}
|
||||
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
kojihub._edit_tag('tag', **kwargs)
|
||||
self.assertEqual(cm.exception.args[0], "Tag: tag doesn't have extra: exE")
|
||||
|
||||
# no4 invoke
|
||||
self.get_perm_id.reset_mock()
|
||||
self.get_perm_id.return_value = 99
|
||||
self._singleValue.reset_mock()
|
||||
self._singleValue.return_value = 2
|
||||
|
||||
kwargs = {
|
||||
'perm': 'admin',
|
||||
'name': 'newtag',
|
||||
}
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
kojihub._edit_tag('tag', **kwargs)
|
||||
self.get_perm_id.assert_called_once()
|
||||
self._singleValue.assert_called_once()
|
||||
self.assertEqual(cm.exception.args[0], 'Name newtag already taken by tag 2')
|
||||
Loading…
Add table
Add a link
Reference in a new issue