Adding Cycle Time to your Azure DevOps board using Power Automate

Nick Brown
8 min readJul 14, 2023

The second in a series of three blogs covering how you can add flow metrics directly into your kanban board in Azure DevOps. Part one covered how to add Work Item Age. Part two (this blog) will cover adding Cycle Time and part three will show how to add in your Service Level Expectation…

What do we we mean by Cycle Time?

As per the Kanban Guide:

Cycle Time — the amount of elapsed time between when a work item started and when a work item finished.

The challenge we have in Azure DevOps is that despite information around cycle time being available to populate widgets such as the cycle time chart, it requires again moving away from the board to view on a separate page.

Analytics widgets — Azure DevOps | Microsoft Learn

What would be even better for teams would be getting that information real time, ideally as soon as possible after an item moves to done. Here’s how this can be made possible…

Prerequisites

Similar to the last post, here are some assumptions made in this guidance:

With all those in place — let’s get started!

Adding a ‘Cycle Time’ field to ADO

We need to add a new field into our process template in ADO called Cycle Time. You need also to know the respective work item type(s) you want to do this for. Again, for the purpose of simplicity in this blog we will stick to Product Backlog Item (PBI) as the work item type we will do this for and be using the inheritance of the Scrum process template. Please note, if you are wanting to do this for multiple work item types you will have to repeat this process.

  • Find the PBI work item type in your inherited process work items list
  • Click into it and click ‘New field’
  • Add the Cycle Time field — ensure you specify it as an ‘integer’

If you have followed the previous post and have added a custom Work Item Age field, you’ll want to also implement a work item rule here. This is so that when items that were in progress move to done, we clear the Work Item Age field. You can do this like so:

Now, before automating, let’s briefly recap on how cycle time is calculated…

Understanding how Cycle Time is calculated

From Microsoft’s own documentation, we can see that Cycle Time is calculated from when an item first enters an ‘In Progress’ state category to entering a ‘Completed’ state category.

Source: Cycle Time and Lead Time control charts — Azure DevOps Services | Microsoft Learn

Fortunately for us, when this happens, Microsoft auto-calculates this cycle time, storing it in a column in the database/analytics views known as CycleTimeDays. As mentioned previously, is not the intent of this blog to get into a debate about adding +1 days to an item as there are no instances where an item has taken 0 days to complete.

Ultimately, calculating cycle time this way still aligns with the definition as set out in the kanban guide as it is still “the amount of elapsed time between when a work item started and when a work item finished.”

Time to move on to automation…

Automating the input of Cycle Time on items

Our automation looks slightly different this time as, rather than a scheduled automation, we want this to run any time an item moves to done. Therefore we need to pick an Automated cloud flow in Power Automate:

We are going to call it Cycle Time and our trigger is going to be When a work item is closed:

We will add in our ‘Organization Name’, ‘Project Name’ and ‘Type’. Again, for this instance we are going to be consistent and just use the Product Backlog Item (PBI) type.

Please note, if you are wanting to do this for multiple work item types you will have to repeat the process of adding this field for each work item type.

The closed state field should be auto-populated:

Next we need to add a step for a Delay:

The reason for this is sometimes the calculating of cycle time by Microsoft can be a little slow. All we are going to add in here is a 30 second delay to give enough time for the CycleTimeDays column to be populated:

Following this, we are going to add a Get work item details step:

Here we want to make sure our organization, project and work item type are consistent with our first step. We also want to add in the ‘Id’ field from our first action when a work item is closed:

After this, we want to add in a HTTP step which is where we will pull in the CycleTimeDays for the completed item:

You’ll need to set the method as ‘GET’ and add in the the URL. The first part of the URL (replace ORG and PROJECT with your details) should be:

https://analytics.dev.azure.com/ORG/PROJECT/_odata/v3.0-preview/WorkItems?$filter=WorkItemId%20eq%20

Add in the dynamic content of ‘Id’ from our Get work item details step:

After the Id, add in:

&$select=CycleTimeDays

Which should then look like:

Again, ensure you have added your PAT details in the advanced options:

PAT blurred for obvious reasons!

Next we are going to add a Parse JSON step, where we are going to extract the CycleTimeDays value:

For content you’ll want to choose ‘Body’ and add a schema like so:

{
"type": "object",
"properties": {
"@@odata.context": {
"type": "string"
},
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"CycleTimeDays": {
"type": "number"
}
},
"required": [
"CycleTimeDays"
]
}
}
}
}

Next we need to add an Initialize variable step:

This will serve the purpose of temporarily storing our cycle time before we write it back to the respective work item. Add in the following:

Apply to each is the next step to add in:

Here we will use the ‘value’ from our Parse JSON action as our output from previous steps:

Then we’ll need to add in a Set variable step which is essentially where we are going to pass through our CycleTimeDays in the value field:

Then we need to add a Compose step for rounding our Cycle Time:

Here we need to set an expression of:

if(greaterOrEquals(mod(variables('CycleTimeDays'),1),0.5),formatNumber(variables('CycleTimeDays'),'0'),if(less(mod(variables('CycleTimeDays'),1),0.5),if(equals(mod(variables('CycleTimeDays'),1),0),formatNumber(variables('CycleTimeDays'),'0'),add(int(first(split(string(variables('CycleTimeDays')),'.'))),1)),first(split(string(variables('CycleTimeDays')),'.'))))

The final action is to write this back to Azure DevOps. Here we want to add a step to Update a work item:

Ensure the organization, project and work item type all match our previous steps. We want to choose ‘Id’ from our Get Work Item Details action previously. Click Advanced Options and ensure that Cycle Time is populated with the outputs of our previous step:

Then hit save and the flow is created!

To test if it works, you will need to create a dummy item and move it to your closed state on your board to see if the flow works. With a successful run looking like so:

Making this visible on the kanban board

The final step is to make this visible on the kanban board. To do this we need to go into our board settings and find the respective work item type. Under ‘Additional fields’ you’ll want to add Cycle Time:

Then, when an item moves to done and the flow runs, you will then see the cycle time for your completed items:

Please note — this will not retrospectively update for items that were in a Closed/Done state before this automation was setup. You could however combine the logic of this and the previous blog post to do that :)

Ways you could take it further

Now, teams who are using the board as part of their daily sync/scrum also have the cycle time for completed items visible on the cards themselves. This provides insights around how long items actually took. You could then take this further, for example adding styling rules for any items that took longer than an agreed duration (or a Service Level Expectation — SLE).

This team may choose to do that for anything that took over 10 days:

Which could be the basis for discussing these orange items in a retrospective.

Now you have two of the four flow metrics visible for all in progress and completed items on your board, which is hopefully this is a useful next step for increasing awareness around the flow of work :)

Check out part three which covers how to automate the adding of a Service Level Expectation (SLE) to the kanban board…

--

--