Friday, September 30, 2011

Trac and Kanban - Redux

Hello there!

Since my last post before summer, the number of total visits has gone from 2000 to over 7000! One of the reasons for this was the  Trac and Kanban post, where I breifly describe how to use a Trac wiki page as a basic kanban board. (The main reason is this Stack Overflow question which asks for a bit more, such as drag-n-drop and the like.)

We'we worked with this for half a year now, and it still feels like a good thing. So good, actually, that I simply had to improve it a bit.

Trac and Kanban, v2.0

Mainly I now use the "format=table" option to get a table, which means we get color for the priority, we can show who is owning the item and what resolution it had (duplicate/invalid/worksforme/wontfix, etc) where suitable.

It looks like this (with no one working on anything at the moment, but you get the idea):


This could be even better if Trac supported sorting on several ticket fields, but that is not possible with 0.12. There is a ticket and patch available on the Trac home site, but I haven't tried it ... yet.


Code review

For the confused, note that I still use two custom fields for post-commit code review "reviewed_by" and "has_review_issues".

I will probably change the boolean review_issues to a checkbox that better handles the states and workflow for code review:

  • not_reviewed
  • reviewed_with_issues
  • review_issues_fixed
  • reviewed_and_approved

A custom TicketChangeListener could then manage the has_issues to issues_fixed transition, so that it's automatically visible that the code has changed.

Automatic subpage/dashboard lists 

The second new thing I've discovered and deployed is the TitleIndex macro, to simply list show all sub pages for a single wiki page. Since we have all the dashboards under Dashboard/ProductNameX.Y pages, it's easy to list them all using [[TitleIndex(Dashboard/ProductName,hideprefix)]] on a product's "home" wiki page.

Old/completed milestones could then be moved to DashboardOld container so that they're still there, but does not clutter the "current and upcoming milestones/sprints" list.

Limit right column to last two weeks

Adding modified=2weeksago.. to the queries for closed tickets makes the dashboard work over long time, since older (closed) tickets are not modified and thus removed from the table after some time.

This really helps with using the system in a "pure" Kanban setting, without sprints or milestones. It's also useful to keep a current status view during longer milestones with 100+ tickets.

Wiki code

The wiki page above was generated from the following code:

This is the ticket dashboard for **[milestone:"Orsync 1.0"]**
([/query?milestone=Orsync+1.0&status=new&status=reopened&status=testable&status=accepted&order=priority&col=id&col=summary&col=status&col=type&col=priority&col=milestone&col=component open tickets])
-- [wiki:Orcamp/FeatureList current feature list]

Create new
[/newticket?milestone=Orsync+1.0&component=Apps/Orsync&type=defect defect],
[/newticket?milestone=Orsync+1.0&component=Apps/Orsync&type=enhancement enhancement],
[/newticket?milestone=Orsync+1.0&component=Apps/Orsync&type=suggestion suggestion],
[/newticket?milestone=Orsync+1.0&component=Apps/Orsync&type=change change],
[/newticket?milestone=Orsync+1.0&component=Apps/Orsync&type=task task],
[/newticket?milestone=Orsync+1.0&component=Apps/Orsync&type=demo demo] or
[/newticket?milestone=Orsync+1.0&component=Apps/Orsync generic] ticket.

{{{
#!div style="float:left; margin-right:1em; width:30%"

= Open Tickets =

Total: [[TicketQuery(status=new|reopened,type!=suggestion,milestone=Orsync 1.0,format=count)]]
([[TicketQuery(status=new|reopened,type=suggestion,milestone=Orsync 1.0,format=count)]])

== New & Reopened ==

[[TicketQuery(format=table,col=summary|type,status=reopened|new,type!=suggestion,milestone=Orsync 1.0,group=priority,order=type)]]

== Suggestions ==

[[TicketQuery(group=priority,status=new|reopened,type=suggestion,milestone=Orsync 1.0)]]

}}}
{{{
#!div style="float:left; margin-right:1em; width:30%"

= Work In Progress =

Total:
[[TicketQuery(status=accepted,order=priority,group=owner,milestone=Orsync 1.0,format=count)]]
([[TicketQuery(status=accepted|testable,milestone=Orsync 1.0,format=count)]])

== Started ==

[[TicketQuery(status=accepted,group=owner,order=priority,format=table,col=summary|type|owner,milestone=Orsync 1.0)]]

== Unreviewed tickets ==

[[TicketQuery(review_issues!=1,reviewed=,status=testable,group=owner,order=priority,format=table,col=summary|type|owner,milestone=Orsync 1.0)]]

== Reviewed tickets with issues ==

[[TicketQuery(review_issues=1,status=testable,group=owner,order=priority,format=table,col=summary|type|owner,milestone=Orsync 1.0)]]

== Ready for Test ==

[[TicketQuery(review_issues=1,status=testable,group=developertest,order=priority,format=table,col=summary|type,milestone=Orsync 1.0)]]



}}}
{{{
#!div style="float:left; margin-right:1em; width:30%"


= Closed Tickets =

Total: [[TicketQuery(status=closed,resolution=fixed,milestone=Orsync 1.0,format=count)]] 

([[TicketQuery(status=closed,resolution!=fixed,milestone=Orsync 1.0,format=count)]])

== Fixed tickets (last two weeks) ==

[[TicketQuery(status=closed,format=table,col=summary|type,resolution=fixed,order=priority,desc=1,milestone=Orsync 1.0,modified=2weeksago..)]]

== Denied tickets 
(last two weeks) ==

[[TicketQuery(status=closed,resolution=wontfix|worksforme,format=table,col=summary|type|resolution,order=priority,desc=1,milestone=Orsync 1.0
,modified=2weeksago..)]]

== Invalid/duplicate/other 
(last two weeks) ==

[[TicketQuery(status=closed,resolution!=fixed|wontfix|worksforme,format=table,col=summary|type|resolution,order=priority,desc=1,milestone=Orsync 1.0
,modified=2weeksago..)]]


}}}

{{{
#!div style="clear:both"
}}}




There you go. Hope it helps!

11 comments :

Anonymous said...

I implemented this on our trac instance and was incredibly impressed. Our workflow is a bit different, since we use milestones as project titles and need to see everything together, so I made milestone a column, removed it from the query, and added a duration limit for closed tickets so they eventually fall off on their own (after two weeks, we generally don't need to see them in the kanban view).

All in all though, thanks much! You seriously improved our workflow with this.

Macke said...

I'm happy to hear that it helped!

You have a good point about duration limit for closed tickets. We've had some long-running milestones and it's become a bit of an issue that the tickets keep piling up at the right side.

(for some reason, I didn't get notified about you comment, hence the late reply.. :)

Anonymous said...

We just built an extremely usable Kanban system from the code and ideas here.

I was surprised at how simple the setup was. In about an hour our entire Trac system looked like it had always been set up for Kanban.

Anonymous said...
This comment has been removed by a blog administrator.
Unknown said...

Hi, great post!
Get many ideas for tracking our tickets.

Do you know how can I query for tickets and aggregate columns like a summatory?
We use two custom columns for tickets to indicate resolution time, and I want to see the total of a query matching tickets. It's possible?

Thanks.

Macke said...

@Ripador: Not sure you can summarize stuff like that with the plain TracQuery macro.

Sounds like you have to write your own, perhaps extend the existing TracQuery macro in python.

You might also be able to cobble something togehter in javascript, and compute the total in the webbrowser. It's possible to extend Trac's HTML output in many ways.

Sero said...

Hi!
Thanks for this nice tutorial.
But i am a newbie with it and getting error:

Error: Macro TicketQuery(review_issues!=1,reviewed=,status=testable,group=owner,order=priority,format=table,col=summary|type|owner,milestone=M3 - AEGIS3) failed
no such column: t.review_issues

Can somone please help me with this issue? Am i missing some plugins here?

THanks
Sero

Unknown said...

"review_issues" is a custom field for the tickets. You have to create it in the trac admin, or remove it from the query.

Sero said...

Hi!
Thanks for quick feedback!

If i go:

https://xxx.xxx.xxx/admin/tracini/ticket
cannot find that field nor option to create new one?
What have i missing ... Trac version is 11.5

Unknown said...

Hi Sero,
you have to create the custom fields in the trac.ini file, for example:

[ticket-custom]
review_issues = checkbox
review_issues.label = Reviewed
review_issues.value = 0

Sero said...

Unfortunately i don't have rights to change trac.ini file but have admin rights to change trac settings.

From the left frame i can see trac.ini and below lots of attributes. Between them there is "ticket" attribute. But after clicking on it cannot add nothing i can see only some default vaules in it :(
Thanks!

Brgds,
S.