diff --git a/NEWS b/NEWS index bd1a44de..37f06129 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,5 @@ 0.164 - - + - add support for approved requests (requires OBS 2.10) 0.163 - add sendsysrq command (requires OBS 2.10) diff --git a/osc/commandline.py b/osc/commandline.py index 90a9ffc9..e2236244 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -2130,6 +2130,9 @@ Please submit there instead, or use --nodevelproject to force direct submission. the actual submit process. That would normally be a server-side copy of the source package to the target package. + "approve" marks a requests in "review" state as approved. This request will get accepted + automatically when the last review got accepted. + "checkout" will checkout the request's source package ("submit" requests only). "priorize" change the prioritity of a request to either "critical", "important", "moderate" or "low" @@ -2153,6 +2156,8 @@ Please submit there instead, or use --nodevelproject to force direct submission. osc request [show] [-d] [-b] ID osc request accept [-m TEXT] ID + osc request approve [-m TEXT] ID + osc request cancelapprove [-m TEXT] ID osc request decline [-m TEXT] ID osc request revoke [-m TEXT] ID osc request reopen [-m TEXT] ID @@ -2199,7 +2204,8 @@ Please submit there instead, or use --nodevelproject to force direct submission. if args[0] == 'help': return self.do_help(['help', 'request']) - cmds = ['list', 'ls', 'log', 'show', 'decline', 'reopen', 'clone', 'accept', 'approvenew', 'wipe', 'setincident', 'supersede', 'revoke', 'checkout', 'co', 'priorize'] + cmds = ['list', 'ls', 'log', 'show', 'decline', 'reopen', 'clone', 'accept', 'approve', 'cancelapproval', + 'approvenew', 'wipe', 'setincident', 'supersede', 'revoke', 'checkout', 'co', 'priorize'] if subcmd != 'review' and args[0] not in cmds: raise oscerr.WrongArgs('Unknown request action %s. Choose one of %s.' \ % (args[0], ', '.join(cmds))) @@ -2259,7 +2265,8 @@ Please submit there instead, or use --nodevelproject to force direct submission. elif cmd == 'priorize': reqid = args[0] priority = args[1] - elif cmd in ['log', 'add', 'show', 'decline', 'reopen', 'clone', 'accept', 'wipe', 'revoke', 'checkout', 'co']: + elif cmd in ['log', 'add', 'show', 'decline', 'reopen', 'clone', 'accept', 'wipe', 'revoke', 'checkout', + 'co', 'approve', 'cancelapproval']: reqid = args[0] # clone all packages from a given request @@ -2267,6 +2274,13 @@ Please submit there instead, or use --nodevelproject to force direct submission. # should we force a message? print('Cloned packages are available in project: %s' % clone_request(apiurl, reqid, opts.message)) + # approve request + elif cmd == 'approve' or cmd == 'cancelapproval': + query = { 'cmd': cmd } + url = makeurl(apiurl, ['request', reqid], query) + r = http_POST(url, data=opts.message) + print(ET.parse(r).getroot().get('code')) + # change incidents elif cmd == 'setincident': query = { 'cmd': 'setincident', 'incident': incident } diff --git a/osc/core.py b/osc/core.py index 52a0dba9..f506da23 100644 --- a/osc/core.py +++ b/osc/core.py @@ -2586,6 +2586,7 @@ class RequestState(AbstractState): self.name = state_node.get('name') self.who = state_node.get('who') self.when = state_node.get('when') + self.approver = state_node.get('approver') if state_node.find('description') is None: # OBS 2.6 has it always, before it did not exist self.description = state_node.get('description') @@ -2595,7 +2596,7 @@ class RequestState(AbstractState): self.comment = state_node.find('comment').text.strip() def get_node_attrs(self): - return ('name', 'who', 'when') + return ('name', 'who', 'when', 'approver') def get_comment(self): return self.comment @@ -2943,7 +2944,10 @@ class Request: def list_view(self): """return "list view" format""" import textwrap - lines = ['%6s State:%-10s By:%-12s When:%-19s' % (self.reqid, self.state.name, self.state.who, self.state.when)] + status = self.state.name + if self.state.name == 'review' and self.state.approver: + status += "(approved)" + lines = ['%6s State:%-10s By:%-12s When:%-19s' % (self.reqid, status, self.state.who, self.state.when)] tmpl = ' %(type)-16s %(source)-50s %(target)s' for action in self.actions: lines.append(tmpl % self.format_action(action)) @@ -2967,6 +2971,8 @@ class Request: lines.append(' *** This request will get automatically accepted after '+self.accept_at+' ! ***\n') if self.priority in [ 'critical', 'important' ] and self.state.name in [ 'new', 'review' ]: lines.append(' *** This request has classified as '+self.priority+' ! ***\n') + if self.state.approver and self.state.name == 'review': + lines.append(' *** This request got approved by '+self.state.approver+'. It will get automatically accepted after last review got accepted! ***\n') for action in self.actions: tmpl = ' %(type)-13s %(source)s %(target)s' diff --git a/tests/request_fixtures/test_read_request2.xml b/tests/request_fixtures/test_read_request2.xml index 16033791..5aa983e4 100644 --- a/tests/request_fixtures/test_read_request2.xml +++ b/tests/request_fixtures/test_read_request2.xml @@ -11,7 +11,7 @@ - + review start diff --git a/tests/test_request.py b/tests/test_request.py index 5746cea0..96b5ba40 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -341,6 +341,7 @@ class TestRequest(OscTestCase): self.assertEqual(r.state.name, 'accepted') self.assertEqual(r.state.when, '2010-12-27T01:36:29') self.assertEqual(r.state.who, 'user1') + self.assertEqual(r.state.approver, None) self.assertEqual(r.state.comment, '') self.assertEqual(r.statehistory[0].when, '2010-12-13T13:02:03') self.assertEqual(r.statehistory[0].who, 'creator') @@ -373,6 +374,7 @@ class TestRequest(OscTestCase): self.assertTrue(r.actions[1].tgt_package is None) self.assertEqual(r.state.name, 'review') self.assertEqual(r.state.when, '2010-12-27T01:36:29') + self.assertEqual(r.state.approver, 'someone') self.assertEqual(r.state.who, 'abc') self.assertEqual(r.state.comment, '') self.assertEqual(r.reviews[0].state, 'new')