source: mergebot/trunk/mergebot/ticket_actions.py @ 17

Last change on this file since 17 was 17, checked in by retracile, 15 years ago

Mergebot: redesigned implementation. Still has rough edges.

File size: 4.7 KB
Line 
1import socket
2import time
3from subprocess import check_call
4
5from genshi.builder import tag
6
7from trac.core import implements, Component
8from trac.ticket.api import ITicketActionController
9from trac.ticket.default_workflow import ConfigurableTicketWorkflow
10from trac.web.chrome import add_warning
11
12from BranchActor import BranchActor
13from RebranchActor import RebranchActor
14from MergeActor import MergeActor
15from CheckMergeActor import CheckMergeActor
16from action_logic import is_branchable, is_rebranchable, is_mergeable, is_checkmergeable
17
18class MergebotActionController(Component):
19    """Support branching and merging operations for tickets.
20    """
21    implements(ITicketActionController)
22
23    # ITicketActionController
24    def get_ticket_actions(self, req, ticket):
25        controller = ConfigurableTicketWorkflow(self.env)
26        mergebot_operations = self._get_available_operations(req, ticket)
27        if mergebot_operations:
28            actions_we_handle = controller.get_actions_by_operation_for_req(req,
29                ticket, 'mergebot')
30        else:
31            actions_we_handle = []
32        return actions_we_handle
33
34    def get_all_status(self):
35        return []
36
37    def render_ticket_action_control(self, req, ticket, action):
38        actions = ConfigurableTicketWorkflow(self.env).actions
39        label = actions[action]['name']
40        hint = ''
41
42        control_id = action + '_mergebot_op'
43        mergebot_operations = self._get_available_operations(req, ticket)
44
45        # TODO: allow the configuration to specify a sub-set of permitted
46        # mergebot actions
47        #self.config.get('ticket-workflow', action + '.mergebot')
48
49        self.env.log.debug('render_ticket_action_control ops: %s', mergebot_operations)
50        selected_value = req.args.get(control_id) or mergebot_operations[0]
51        control = tag.select([tag.option(option, selected=(option == selected_value or None)) for option in mergebot_operations], name=control_id, id=control_id)
52
53        return (label, control, hint)
54
55
56    def get_ticket_changes(self, req, ticket, action):
57        control_id = action + '_mergebot_op'
58        selected_value = req.args.get(control_id)
59        add_warning(req, 'Mergebot operation %s will be triggered' % selected_value)
60        return {}
61
62    def daemon_address(self):
63        host = self.env.config.get('mergebot', 'listen.ip')
64        port = self.env.config.getint('mergebot', 'listen.port')
65        return (host, port)
66
67    def start_daemon(self):
68        check_call(['mergebotdaemon', self.env.path])
69        time.sleep(1) # bleh
70
71    def _daemon_cmd(self, cmd):
72        self.log.debug('Sending mergebotdaemon: %r' % cmd)
73        try:
74            info_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
75            info_socket.connect(self.daemon_address())
76        except socket.error, e:
77            # if we're refused, try starting the daemon and re-try
78            if e and e[0] == 111:
79                self.log.debug('connection to mergebotdaemon refused, trying to start mergebotdaemon')
80                self.start_daemon()
81            self.log.debug('Resending mergebotdaemon: %r' % cmd)
82            info_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
83            info_socket.connect(self.daemon_address())
84        info_socket.sendall(cmd)
85        self.log.debug('Reading mergebotdaemon response')
86        raw = info_socket.recv(4096)
87        info_socket.close()
88        self.log.debug('Reading mergebotdaemon response was %r' % raw)
89        return raw
90
91    def apply_action_side_effects(self, req, ticket, action):
92        self.log.info('applying mergebot side effect for ticket %s on action %s' % (ticket.id, action))
93        control_id = action + '_mergebot_op'
94        selected_value = req.args.get(control_id)
95
96        result = self._daemon_cmd('ADD %s %s %s %s %s\n\QUIT\n' % (ticket.id, selected_value, ticket['component'], ticket['version'], req.authname or 'anonymous'))
97        if 'OK' not in result:
98            add_warning(req, result) # adding warnings in this method doesn't seem to work
99
100    def _get_available_operations(self, req, ticket):
101        mergebot_ops = []
102        if req.perm.has_permission("MERGEBOT_BRANCH"):
103            if is_branchable(ticket):
104                mergebot_ops.append('branch')
105            if is_rebranchable(ticket):
106                mergebot_ops.append('rebranch')
107        if is_checkmergeable(ticket) and req.perm.has_permission('MERGEBOT_VIEW'):
108            mergebot_ops.append('checkmerge')
109        if ticket['version'].startswith("#"):
110            may_merge = req.perm.has_permission("MERGEBOT_MERGE_TICKET")
111        else:
112            may_merge = req.perm.has_permission("MERGEBOT_MERGE_RELEASE")
113        if may_merge and is_mergeable(ticket):
114            mergebot_ops.append('merge')
115        return mergebot_ops
Note: See TracBrowser for help on using the repository browser.