Trac 0.11: Building your own custom workflow

So after much procrastination and Christmas food and presents I've finally got around to writing about custom workflows in Trac 0.11.
Previously, I talked about the workflow-parser and the ini files in the contrib/workflow folder. Hopefully, you'll have had a chance to grab these and have a look at them and generate some of the diagrams using GraphVis.
Now I'm going to have a look at the contents of an ini file and talking about how you build your own workflow.I guess the first thing to mention is that trac workflows are build around actions and moving from one state to another, rather than around states and the actions that can be performed in that state. For instance, you want to assign a new ticket to someone. The action is "assign" the states are "new" and "assigned". The workflow for this action would be:

assign = new -> assigned

Say you also have a "deferred" state and you want to assign that ticket to someone, this workflow entry would become:

assign = new,deferred -> assigned

This forms the basis of building your workflows. There are two states that have hard-coded functionality within trac. These are "new" and "closed" - All new tickets are given a status of "new" when its first created and all tickets need a "closed" state to show tickets as closed in reports. All other states are assumed to be "active".
An action that is worth a mention now is "leave", that will also lead me into action operations. "leave" is a useful action to have. It allows you to add comments, attachments etc. to a ticket without actually changing the state of a ticket.

view plain print about
1leave = * -&gt; *<br />
2leave.operations = leave_status<br />
3leave.default = 1<br />

The operations attribute means is that all states are able to leave the status of a ticket unchanged when saving any changes to a ticket.
You'll notice that the leave action above has an operations and a default attribute added to it. There are actually a few more attributes that you can add to an action. These are:

  • name
  • default
  • operations
  • permissions

The "name" attribute allows you to specify a english name for for action, so if you have an action called say "resolve_accepted", then you can use " = resolve" to make "resolve" be the text that is actually displayed for the action in Trac.
The "default" attribute allows you to specify the order in which actions are displayed in Trac. If not specified, "default" is set to 0 (zero).
The "operations" attribute allows you to specify an operation that will be allowed or performed when this action is taken.
The available operations are: (Taken from the trac wiki)

  • del_owner -- Clear the owner field.
  • set_owner -- Sets the owner to the selected or entered owner.
    • actionname.set_owner may optionally be set to a comma delimited list or a single value.
  • set_owner_to_self -- Sets the owner to the logged in user.
  • del_resolution -- Clears the resolution field
  • set_resolution -- Sets the resolution to the selected value.
    • actionname.set_resolution may optionally be set to a comma delimited list or a single value.
      view plain print about
      2resolve_new = new -&gt; closed<br /> = resolve<br />
      4resolve_new.operations = set_resolution<br />
      5resolve_new.permissions = TICKET_MODIFY<br />
      6resolve_new.set_resolution = invalid,wontfix<br />
  • leave_status -- Displays "leave as <current status>" and makes no change to the ticket.

The "permissions" attribute is a comma delimited list of permissions that are required to perform that action. The example above shows the "resolve" action needing the trac permission "TICKET_MODIFY" for a user to be able to perform this action. NOTE: Permissions must be in UPPERCASE.
So lets put that all together into a very simple workflow.

view plain print about
1leave = * -&gt; *<br />
2leave.operations = leave_status<br />
3leave.default = 1<br />
4accept = new,accepted -&gt; accepted<br />
5accept.permissions = TICKET_MODIFY<br />
6accept.operations = set_owner_to_self<br />
7resolve = new,accepted -&gt; closed<br />
8resolve.permissions = TICKET_MODIFY<br />
9resolve.operations = set_resolution<br />
Hopefully that should give you the basis to build your own more complex workflows.
I've attached a more complex workflow for you to download that including a QA phase, as well as a "defer" and "more info required" route, which looks like this: QA Workflow Image Just as a final note; I mentioned in an entry about Mylyn that Mylyn doesn't seem to show up the custom workflow actions correctly. I haven't had a chance to investigate this properly, but it may be that you need to specify the action.set_resolution explicitly for them to work correctly. As I say though, I haven't had a chance to investigate this properly yet. Some time soon I hope.

I'm going to start to look at this at work next week I think as we defo need a QA Stage, in our tickets.

Just one note dude, the text in your Code Blocks are way to small to read any chance you could up date your CSS to make them a little easier to read. Some of us don't have 20/20 vision anymore :)
# Posted By Big Mad Kev | 3/13/08 9:39 PM
Where's the attachment?
# Posted By Tom | 8/6/08 3:04 AM

Sorry for the slow response. I had a problem with comment notifications which is now resolved.

You can find the attachment here :
# Posted By Stephen Moretti | 9/8/08 11:01 PM
just wondering if you got anywhere with Mylyn not displaying custom actions correctly?


# Posted By Paul BH | 10/16/08 12:00 AM
Hi Paul,

Sorry - no...
Its been a while since I looked and, as it happens, an update for Mylyn in Ganymede came down this morning, so I did look.

It appears that the query builder correctly finds all the status points for custom workflows, but the ticket viewer/editor still doesn't display the additional action non-standard actions.

This is probably something to do with the XMLRPC plugin, as opposed to Mylyn and the XMLRPC plugin hasn't been changed in quite some time.
# Posted By Stephen Moretti | 10/16/08 1:53 PM