Skip to content

Commit

Permalink
- osc.cli.review: added initial version of the "review" command
Browse files Browse the repository at this point in the history
  • Loading branch information
marcus-h committed Aug 17, 2012
1 parent c74d9ad commit 161514a
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 0 deletions.
Empty file added osc/cli/review/__init__.py
Empty file.
132 changes: 132 additions & 0 deletions osc/cli/review/review.py
@@ -0,0 +1,132 @@
"""Provides various functions for the "review" command."""

import logging

from osc.util.xpath import XPathBuilder
from osc.remote import Request
from osc.search import find_request
from osc.cli.util.env import edit_message
from osc.cli.request.request import AbstractRequestController, SHOW_TEMPLATE


def logger():
"""Returns a logging.Logger object."""
return logging.getLogger(__name__)


class ReviewController(AbstractRequestController):
"""Concrete ReviewController."""

@classmethod
def list(cls, renderer, tgt_project, tgt_package, info):
"""Lists requests for the given project and package.
project and package might be None.
"""
super(ReviewController, cls).list(renderer, tgt_project,
tgt_package, info)

@classmethod
def change_review_state(cls, renderer, reqid, method, message, info,
supersede_id=None):
"""Changes the state of a review.
method is the method which is called on the
retrieved request object.
If message is None $EDITOR is opened.
"""
request = Request.find(reqid)
review = cls._find_review(request, info)
if review is not None:
cls._change_request_state(renderer, request, method, message,
info, supersede_id, review)

@classmethod
def add(cls, renderer, reqid, message, info):
"""Adds a new review to a request."""
request = Request.find(reqid)
if message is None:
message = edit_message()
kwargs = {'comment': message, 'by_user': info.user,
'by_group': info.group}
if info.package:
kwargs['by_project'] = info.package[0].project
kwargs['by_package'] = info.package[0].package
elif info.project is not None:
kwargs['by_project'] = info.project
request.add_review(**kwargs)
renderer.render(SHOW_TEMPLATE, request=request)

@classmethod
def _find_review(cls, request, info):
"""Returns a review or None."""
xpb = XPathBuilder(context_item=True)
_, xp = cls._build_by_predicate(xpb, info, [])
logger().debug(xp.tostring())
reviews = request.findall(xp.tostring())
if reviews:
return reviews[0]
return None

@classmethod
def _build_by_predicate(cls, xpb, info, states):
"""Builds a by_<kind> predicate.
States is a list of states or the empty list.
Returns a two tuple. The first element indicates whether
a at least one by_ predicate was build
"""
by_kind = False
xp = xpb.dummy()
if info.user is not None:
pred = xpb.attr('by_user') == info.user
xp = xp | cls._add_states(xpb, pred, states)
by_kind = True
if info.group is not None:
pred = xpb.attr('by_group') == info.group
xp = xp | cls._add_states(xpb, pred, states)
by_kind = True
if info.project is not None:
pred = xpb.attr('by_project') == info.project
xp = xp | cls._add_states(xpb, pred, states)
by_kind = True
if info.package:
# info.package is a list
pred = ((xpb.attr('by_project') == info.package[0].project)
& (xpb.attr('by_package') == info.package[0].package))
xp = xp | cls._add_states(xpb, pred, states)
by_kind = True
return by_kind, xp

@classmethod
def _add_states(cls, xpb, pred, states):
"""Adds states to the existing predicate pred.
states is a list of states or the empty list.
"""
st_pred = xpb.dummy()
for state in states:
st_pred = st_pred | (xpb.attr('state') == state)
return xpb.review[pred & st_pred.parenthesize()]

@classmethod
def _find_requests(cls, tgt_project, tgt_package, info):
"""Returns a collection of requests."""
xpb = XPathBuilder()
xp = xpb.dummy()
by_kind, xp = cls._build_by_predicate(xpb, info, info.state)
if not by_kind:
xp = cls._add_states(xpb, xpb.dummy(), info.state)
xp = (xpb.state.attr('name') == 'review') & xp.parenthesize()
if tgt_project is not None:
xp = xp & (xpb.action.target.attr('project') == tgt_project)
if tgt_package is not None:
xp = xp & (xpb.action.target.attr('package') == tgt_package)
logger().debug(xp.tostring())
res = find_request(xp=xp, apiurl=info.apiurl)
collection = [r for r in res]
return collection
107 changes: 107 additions & 0 deletions osc/cli/review/ui.py
@@ -0,0 +1,107 @@
"""Defines the review command."""

from osc.cli.cli import OscCommand, call
from osc.cli.description import CommandDescription, Option
from osc.cli.review.review import ReviewController


class Review(CommandDescription, OscCommand):
"""Show and modify reviews."""
cmd = 'review'
opt_user = Option('U', 'user', 'use by_user', sub=True)
opt_group = Option('G', 'group', 'use by_group', sub=True)
opt_project = Option('P', 'project', 'use by_project', sub=True)
opt_package = Option('p', 'package', 'use by_package', sub=True,
oargs='project/package', nargs=1, default=[])


class ReviewList(CommandDescription, Review):
"""List reviews.
By default only requests with state review will be listed.
Examples:
osc review list api://
osc review list api://project
osc review list api://project/package
"""
cmd = 'list'
args = 'api://tgt_project?/tgt_package?'
opt_state = Option('s', 'state',
('list only requests which have a review with state '
'STATE'),
choices=['new', 'accepted', 'revoked', 'declined'],
action='append', default=['new'])
func = call(ReviewController.list)


class ReviewAccept(CommandDescription, Review):
"""Accept a specific review.
If no message is specified $EDITOR is opened.
Example:
osc review accept api://reqid [--message MESSAGE] --user <user>
"""
cmd = 'accept'
args = 'api://reqid'
opt_message = Option('m', 'message', 'specify a message')
mutex_req_group = [Review.opt_user, Review.opt_group, Review.opt_project,
Review.opt_package]
func = call(ReviewController.change_review_state)
func_defaults = {'method': 'accept'}


class ReviewDecline(CommandDescription, Review):
"""Decline a specific review.
If no message is specified $EDITOR is opened.
Example:
osc review decline api://reqid [--message MESSAGE] --user <user>
"""
cmd = 'decline'
args = 'api://reqid'
opt_message = Option('m', 'message', 'specify a message')
mutex_req_group = [Review.opt_user, Review.opt_group, Review.opt_project,
Review.opt_package]
func = call(ReviewController.change_review_state)
func_defaults = {'method': 'decline'}


class ReviewRevoke(CommandDescription, Review):
"""Revoke a specific review.
If no message is specified $EDITOR is opened.
Example:
osc review revoke api://reqid [--message MESSAGE] --user <user>
"""
cmd = 'revoke'
args = 'api://reqid'
opt_message = Option('m', 'message', 'specify a message')
mutex_req_group = [Review.opt_user, Review.opt_group, Review.opt_project,
Review.opt_package]
func = call(ReviewController.change_review_state)
func_defaults = {'method': 'revoke'}


class ReviewAdd(CommandDescription, Review):
"""Add a new review to the request.
If no message is specified $EDITOR is opened.
Example:
osc review add api://reqid [--message MESSAGE] --user <user>
"""
cmd = 'add'
args = 'api://reqid'
opt_message = Option('m', 'message', 'specify a message')
mutex_req_group = [Review.opt_user, Review.opt_group, Review.opt_project,
Review.opt_package]
func = call(ReviewController.add)

0 comments on commit 161514a

Please sign in to comment.