{"id":568,"date":"2018-02-15T20:30:05","date_gmt":"2018-02-16T03:30:05","guid":{"rendered":"https:\/\/www.agilefieldbook.com\/?p=568"},"modified":"2021-04-26T10:14:22","modified_gmt":"2021-04-26T16:14:22","slug":"creating-cycle-time-charts-from-tfs","status":"publish","type":"post","link":"https:\/\/www.agilefieldbook.com\/?p=568","title":{"rendered":"Creating Cycle Time Charts from TFS"},"content":{"rendered":"<p>Unfortunately, TFS doesn&#8217;t have ready-made or easily accessible metrics charts like I&#8217;m used to with Jira. There is a lot of clicking and waiting, in my experience. Queries have to be created then assigned to widgets then added to dashboards. Worse, sometimes things I need just aren&#8217;t available. For example, there is no cycle time chart built into TFS. There is <a href=\"https:\/\/docs.microsoft.com\/en-us\/vsts\/report\/dashboards\/widget-catalog\" target=\"_blank\" rel=\"noopener\">a plug-in available for preview<\/a> for VSTS, but as of this posting that plugin won&#8217;t be available for TFS. With Jira, cycle time and other charts are available and easily accessible out of the box.<\/p>\n<p>Sigh. Nonetheless, we go to work with the tools we have. And if need be, we build the tools we need. In this post, I&#8217;ll give a high level description for how to create Cycle Time charts from TFS data using Python. I&#8217;ll leave it as an exercise for the reader to learn the value of cycle time charts and how to best use them.<\/p>\n<p>To make life a little easier, I leveraged the open source (MIT License) <a href=\"https:\/\/github.com\/devopshq\/tfs\" target=\"_blank\" rel=\"noopener\">TFS API Python client<\/a> from the Open DevOps Community. To make it work for generating Cycle Time charts, I suggested a change to the code for accessing revisions. This was added in a subsequent version. For the remainder of this post I&#8217;m going to assume the reader has made themselves familiar with how this library works and resolved any dependencies.<\/p>\n<p>OK, then. Time to roll up our sleeves and get to work.<\/p>\n<p>First, let&#8217;s import a few things.<\/p>\n<pre class=\"theme:solarized-light lang:python decode:true\">import csv\r\nfrom requests_ntlm import HttpNtlmAuth\r\nfrom tfs import TFSAPI\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt<\/pre>\n<p>With that, we&#8217;re ready to make a call to TFS&#8217;s REST API. Again, to make things simple, I create a query in TFS to return the story cards I wish to look at. There are two slices I&#8217;m interested in, the past three and the past eight sprints worth of data. In the next block, I call the three sprint query.<\/p>\n<pre class=\"theme:solarized-light lang:python decode:true\"># Anything in angle brackets \"&lt;&gt;\" is a placeholder for actual values.\r\n# I keep the values in this block in a configuration file and load\r\n# them when the script runs.\r\n\r\nif __name__ == \"__main__\":\r\n\r\n    project = TFSAPI(\"{}\".format(\"&lt;server_url&gt;\"), project=\"&lt;Collection\/Project&gt;\", user=\"&lt;user&gt;\", password=\"&lt;password&gt;\", auth_type=HttpNtlmAuth)\r\n\r\n    query = project.run_query('My Queries\/Last3Sprints')<\/pre>\n<p>With the result set in hand, the script then cycles through each of the returned work items (I&#8217;m interested in stories and bugs only) and analyzes the revision events. In my case, I&#8217;m interested when items first go into &#8220;In Progress,&#8221; when they move to &#8220;In Testing,&#8221; when they move to &#8220;Product Owner Approval,&#8221; and finally when they move to &#8220;Done.&#8221; Your status values may differ. The script is capable of displaying cycle time charts for each phase as well as the overall cycle time from when items first enter &#8220;In Progress&#8221; to when they reach &#8220;Done.&#8221; An example of overall cycle time is included at the end of this post.<\/p>\n<p>When collected, I send that data to a function for creating the chart using matplotlib. I also save aside the chart data in a CSV file to help validate the chart&#8217;s accuracy based on the available data.<\/p>\n<p>It&#8217;s a combination scatter plot (<span style=\"font-family: courier\\new,courier,monospace;\">plt.scatter<\/span>), rolling average (<span style=\"font-family: courier\\new,courier,monospace;\">plt.plot<\/span>), average (<span style=\"font-family: courier\\new,courier,monospace;\">plt.plot<\/span>), and standard deviation (<span style=\"font-family: courier\\new,courier,monospace;\">plt.fill_between<\/span>) of the data points. An example output (click for larger image):<\/p>\n<p><a href=\"https:\/\/www.agilefieldbook.com\/wp-content\/uploads\/2018\/02\/cycle_time_control_chart_total_days.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-581 size-large\" src=\"https:\/\/www.agilefieldbook.com\/wp-content\/uploads\/2018\/02\/cycle_time_control_chart_total_days-1024x219.png\" alt=\"\" width=\"525\" height=\"112\" srcset=\"https:\/\/www.agilefieldbook.com\/wp-content\/uploads\/2018\/02\/cycle_time_control_chart_total_days-1024x219.png 1024w, https:\/\/www.agilefieldbook.com\/wp-content\/uploads\/2018\/02\/cycle_time_control_chart_total_days-300x64.png 300w, https:\/\/www.agilefieldbook.com\/wp-content\/uploads\/2018\/02\/cycle_time_control_chart_total_days-768x164.png 768w\" sizes=\"(max-width: 525px) 100vw, 525px\" \/><\/a><\/p>\n<p>The size variation in data points reflects occurrences of multiple items moving into a status of &#8220;Done&#8221; on the same date, the shaded area is the standard deviation (sample), the blue line is the rolling average, and the orange line is the overall average.<\/p>\n<p>If you are interested in learning more about how to implement this script in your organization, please contact me directly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Unfortunately, TFS doesn&#8217;t have ready-made or easily accessible metrics charts like I&#8217;m used to with Jira. There is a lot of clicking and waiting, in my experience. Queries have to be created then assigned to widgets then added to dashboards. Worse, sometimes things I need just aren&#8217;t available. For example, there is no cycle time &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.agilefieldbook.com\/?p=568\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Creating Cycle Time Charts from TFS&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[10,42,4,43,45],"_links":{"self":[{"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=\/wp\/v2\/posts\/568"}],"collection":[{"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=568"}],"version-history":[{"count":23,"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=\/wp\/v2\/posts\/568\/revisions"}],"predecessor-version":[{"id":1932,"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=\/wp\/v2\/posts\/568\/revisions\/1932"}],"wp:attachment":[{"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=568"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=568"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.agilefieldbook.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=568"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}