Changeset 2199

Show
Ignore:
Timestamp:
04/26/07 15:39:48 (1 year ago)
Author:
sambloomquist
Message:

ScrumBurndownPlugin:

refs #1248, #1219

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • scrumburndownplugin/burndown/burndown.py

    r2062 r2199  
    1010 
    1111import time 
     12import datetime 
    1213import sys 
    1314 
     
    2122class BurndownComponent(Component): 
    2223    implements(IEnvironmentSetupParticipant, INavigationContributor, 
    23                     IRequestHandler, ITemplateProvider, IPermissionRequestor
     24                    IRequestHandler, ITemplateProvider, IPermissionRequestor, ITicketChangeListener
    2425     
    2526    #--------------------------------------------------------------------------- 
     
    3031 
    3132    def environment_needs_upgrade(self, db): 
     33        self.log.debug('burndown plugin - environment needs upgrade') 
    3234        needsUpgrade = False 
    3335         
     
    112114        for s in sqlMilestone: 
    113115            cursor.execute(s) 
     116             
     117    #--------------------------------------------------------------------------- 
     118    # ITicketChangeListener methods 
     119    #--------------------------------------------------------------------------- 
     120     
     121    def ticket_created(self, ticket): 
     122        update_burndown_data() 
     123         
     124    def ticket_changed(self, ticket, comment, author, old_values): 
     125        update_burndown_data() 
     126         
     127    def ticket_deleted(self, ticket): 
     128        update_burndown_data() 
    114129 
    115130    #--------------------------------------------------------------------------- 
     
    117132    #--------------------------------------------------------------------------- 
    118133    def get_active_navigation_item(self, req): 
    119         return 'burndown' 
    120                  
     134        if re.search('/burndown', req.path_info): 
     135            return "burndown" 
     136        else: 
     137            return "" 
     138 
    121139    def get_navigation_items(self, req): 
    122         yield 'mainnav', 'burndown', Markup('<a href="%s">Burndown</a>', self.env.href.burndown()) 
    123          
     140        if req.perm.has_permission("BURNDOWN_VIEW"): 
     141            yield 'mainnav', 'burndown', Markup('<a href="%s">Burndown</a>', self.env.href.burndown()) 
     142 
    124143    #--------------------------------------------------------------------------- 
    125144    # IPermissionRequestor methods 
     
    170189         
    171190        if req.args.has_key('start'): 
    172             self.startMilestone(db, selected_milestone) 
     191            self.start_milestone(db, selected_milestone) 
    173192        else: 
    174193            req.hdf['draw_graph'] = True 
    175             req.hdf['burndown_data'] = self.getBurndownData(db, selected_milestone, components, selected_component) # this will be a list of (id, hours_remaining) tuples 
     194            req.hdf['burndown_data'] = self.get_burndown_data(db, selected_milestone, components, selected_component) # this will be a list of (id, hours_remaining) tuples 
    176195         
    177196        add_stylesheet(req, 'hw/css/burndown.css') 
    178197        return 'burndown.cs', None 
    179198         
    180     def getBurndownData(self, db, selected_milestone, components, selected_component): 
     199    def get_burndown_data(self, db, selected_milestone, components, selected_component): 
    181200        cursor = db.cursor() 
    182201         
     
    214233        return burndown_data 
    215234         
    216     def startMilestone(self, db, milestone): 
     235    def start_milestone(self, db, milestone): 
    217236        cursor = db.cursor() 
    218237        cursor.execute("SELECT started FROM milestone WHERE name = '%s'" % milestone) 
     
    250269        from pkg_resources import resource_filename 
    251270        return [('hw', resource_filename(__name__, 'htdocs'))] 
     271 
     272 
     273    #------------------------------------------------------------------------ 
     274    # update_burndown_data 
     275    #  - add up the hours remaining for the open tickets for each open milestone and put the sums into the burndown table 
     276    #------------------------------------------------------------------------ 
     277    def update_burndown_data(): 
     278        is_weekly = BoolOption('burndown', 'is_weekly', False, """Boolean for whether the unit of time for the burndown chart is a week or a day.""") 
     279         
     280        db = self.env.get_db_cnx() 
     281        cursor = db.cursor() 
     282         
     283        # today's date 
     284        if is_weekly: 
     285            today = datetime.date.today() 
     286            today_year = today.strftime("%Y") 
     287            today_week = today.strftime("%W") 
     288             
     289            # make sure that there isn't already an entry for this week in the burndown table 
     290            cursor.execute("SELECT id FROM burndown WHERE week = '%s' and year = '%s'" % (today_week, today_year)) 
     291        else: 
     292            today = format_date(int(time.time())) 
     293             
     294            # make sure that there isn't already an entry for today in the burndown table 
     295            cursor.execute("SELECT id FROM burndown WHERE date = '%s'" % today) 
     296             
     297        row = cursor.fetchone() 
     298        needs_update = False 
     299        if row: 
     300            print >> sys.stderr, 'update_burndown_data has already been run - update needed' 
     301            needs_update = True 
     302        else: 
     303            print >> sys.stderr, 'first run of update_burndown_data - insert needed' 
     304         
     305        # get arrays of the various components and milestones in the trac environment 
     306        cursor.execute("SELECT name AS comp FROM component") 
     307        components = cursor.fetchall() 
     308        cursor.execute("SELECT name, started, completed FROM milestone") 
     309        milestones = cursor.fetchall() 
     310         
     311        for mile in milestones: 
     312            if mile[1] and not mile[2]: # milestone started, but not completed 
     313                for comp in components: 
     314                    sqlSelect =     "SELECT est.value AS estimate, ts.value AS spent "\ 
     315                                        "FROM ticket t "\ 
     316                                        "    LEFT OUTER JOIN ticket_custom est ON (t.id = est.ticket AND est.name = 'estimatedhours') "\ 
     317                                        "    LEFT OUTER JOIN ticket_custom ts ON (t.id = ts.ticket AND ts.name = 'totalhours') "\ 
     318                                        "WHERE t.component = '%s' AND t.milestone = '%s'"\ 
     319                                        "    AND status IN ('new', 'assigned', 'reopened') " 
     320                    cursor.execute(sqlSelect % (comp[0], mile[0])) 
     321                 
     322                    rows = cursor.fetchall() 
     323                    hours = 0 
     324                    estimate = 0 
     325                    spent = 0 
     326                    if rows: 
     327                        for estimate, spent in rows: 
     328                            if not estimate: 
     329                                estimate = 0 
     330                            if not spent: 
     331                                spent = 0 
     332                         
     333                            hours += float(estimate) - float(spent) 
     334                     
     335                    if needs_update: 
     336                        if is_weekly: 
     337                            cursor.execute("UPDATE burndown SET hours_remaining = '%f' WHERE week = '%s' AND year = '%s' AND milestone_name = '%s'"\ 
     338                                            "AND component_name = '%s'" % (hours, today_week, today_year, mile[0], comp[0])) 
     339                        else: 
     340                            cursor.execute("UPDATE burndown SET hours_remaining = '%f' WHERE date = '%s' AND milestone_name = '%s'"\ 
     341                                            "AND component_name = '%s'" % (hours, today, mile[0], comp[0])) 
     342                    else: 
     343                        if is_weekly: 
     344                            cursor.execute("INSERT INTO burndown(id,component_name, milestone_name, week, year, hours_remaining) "\ 
     345                                            "    VALUES(NULL,'%s','%s','%s','%s',%f)" % (comp[0], mile[0], today_week, today_year, hours)) 
     346                        else: 
     347                            cursor.execute("INSERT INTO burndown(id,component_name, milestone_name, date, hours_remaining) "\ 
     348                                            "    VALUES(NULL,'%s','%s','%s',%f)" % (comp[0], mile[0], today, hours)) 
     349                                          
     350        db.commit() 
  • scrumburndownplugin/burndown/templates/burndown.cs

    r2056 r2199  
    66</div> 
    77 
    8 <form action="<?cs var:burndown.href ?>" method="post"> 
     8<form action="<?cs var:burndown.href ?>" method="get"> 
    99    <label for="selected_milestone">Select milestone:</label> 
    1010    <select id="selected_milestone" name="selected_milestone"> 
  • scrumburndownplugin/setup.py

    r2062 r2199  
    22 
    33PACKAGE = 'TracBurndown' 
    4 VERSION = '01.07.10' # the last two decimals are meant to signify the Trac version 
     4VERSION = '01.08.10' # the last two decimals are meant to signify the Trac version 
    55 
    66setup(name=PACKAGE,