From db5b75848c999a529f849e6e7f09b1cb1d7cb060 Mon Sep 17 00:00:00 2001 From: Gareth Bragg Date: Fri, 16 Feb 2024 15:51:22 +0000 Subject: [PATCH 1/4] Red: Extend tests to expect range data for DF and LT --- Tests/FourKeyMetrics.Tests.ps1 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Tests/FourKeyMetrics.Tests.ps1 b/Tests/FourKeyMetrics.Tests.ps1 index d87e34a..141d771 100644 --- a/Tests/FourKeyMetrics.Tests.ps1 +++ b/Tests/FourKeyMetrics.Tests.ps1 @@ -41,8 +41,12 @@ Describe 'Get-BucketedMetricsForPeriod' { It 'should return an empty set of metrics' { $bucketedMetrics.Releases | Should -Be "0" # Explicitly provide zero releases $bucketedMetrics.DeploymentFrequencyDays | Should -Be $null + $bucketedMetrics.DeploymentFrequencyLow | Should -Be $null + $bucketedMetrics.DeploymentFrequencyHigh | Should -Be $null $bucketedMetrics.MttrHours | Should -Be $null $bucketedMetrics.LeadTimeDays | Should -Be $null + $bucketedMetrics.LeadTimeLow | Should -Be $null + $bucketedMetrics.LeadTimeHigh | Should -Be $null $bucketedMetrics.FailRate | Should -Be $null $bucketedMetrics.EndDate | Should -Be $endDate } @@ -68,8 +72,12 @@ Describe 'Get-BucketedMetricsForPeriod' { $bucketedMetrics.Releases | Should -Be "1" # Explicitly provide one release $bucketedMetrics.DeploymentFrequencyDays | Should -Be "14" # Only 1 release, so the deployment frequency should be the same as the release interval + $bucketedMetrics.DeploymentFrequencyHigh | Should -Be "14" + $bucketedMetrics.DeploymentFrequencyLow | Should -Be "14" $bucketedMetrics.MttrHours | Should -Be $null # No recoveries in the provided dataset $bucketedMetrics.LeadTimeDays | Should -Be "1" # Release has a lead time of one day + $bucketedMetrics.LeadTimeLow | Should -Be "1" + $bucketedMetrics.LeadTimeHigh | Should -Be "1" $bucketedMetrics.FailRate | Should -Be "0" # No failures $bucketedMetrics.EndDate | Should -Be $endDate } @@ -118,8 +126,12 @@ Describe 'Get-BucketedMetricsForPeriod' { It 'should calculate the correct bucketed metrics' { $bucketedMetrics.Releases | Should -Be "2" # Explicitly provide two releases $bucketedMetrics.DeploymentFrequencyDays | Should -Be "2.5" # Release intervals were 1 and 4, so average is 2.5 + $bucketedMetrics.DeploymentFrequencyLow | Should -Be "1" + $bucketedMetrics.DeploymentFrequencyHigh | Should -Be "4" $bucketedMetrics.MttrHours | Should -Be 96 # Single recovery took four whole days $bucketedMetrics.LeadTimeDays | Should -Be "1" # Both releases have a lead time of one day + $bucketedMetrics.LeadTimeLow | Should -Be "1" + $bucketedMetrics.LeadTimeHigh | Should -Be "1" $bucketedMetrics.FailRate | Should -Be "0.5" # One of two releases was a failure $bucketedMetrics.EndDate | Should -Be $endDate } From 339df4f28d7a4ea15b1b787248c3c95584b66eb8 Mon Sep 17 00:00:00 2001 From: Gareth Bragg Date: Fri, 16 Feb 2024 15:54:17 +0000 Subject: [PATCH 2/4] GREEN: Make the tests pass --- Public/FourKeyMetrics.ps1 | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Public/FourKeyMetrics.ps1 b/Public/FourKeyMetrics.ps1 index b36e5be..ceedd35 100644 --- a/Public/FourKeyMetrics.ps1 +++ b/Public/FourKeyMetrics.ps1 @@ -250,14 +250,22 @@ function Get-BucketedMetricsForPeriod($releaseMetrics, $endDate) { if ($releaseCount -gt 0){ $deploymentFrequencyDays = ($releaseMetrics | ForEach-Object {$_.Interval.TotalDays} | Measure-Object -Average).Average; + $deploymentFrequencyLow = ($releaseMetrics | ForEach-Object {$_.Interval.TotalDays} | Measure-Object -Minimum).Minimum; + $deploymentFrequencyHigh = ($releaseMetrics | ForEach-Object {$_.Interval.TotalDays} | Measure-Object -Maximum).Maximum; $failRate = $failedreleaseCount / $releaseCount - $leadTimes = $releaseMetrics | Where-Object {$null -ne $_.CommitAges } | % { $_.CommitAges }; - $leadTimeMedian = Get-Median($leadTimes) + $leadTimes = $releaseMetrics | Where-Object {$null -ne $_.CommitAges } | ForEach-Object { $_.CommitAges }; + $leadTimeMedian = Get-Median($leadTimes) + $leadTimeLow = ($leadTimes | ForEach-Object {$_.TotalDays} | Measure-Object -Minimum).Minimum; + $leadTimeHigh = ($leadTimes | ForEach-Object {$_.TotalDays}| Measure-Object -Maximum).Maximum } else { $deploymentFrequencyDays = $null; + $deploymentFrequencyLow = $null; + $deploymentFrequencyHigh = $null; $failRate = $null; $leadTimeMedian = $null; + $leadTimeLow = $null; + $leadTimeHigh = $null; } if ($failedreleaseCount -gt 0){ @@ -272,8 +280,12 @@ function Get-BucketedMetricsForPeriod($releaseMetrics, $endDate) { EndDate = $endDate Releases = $releaseCount; DeploymentFrequencyDays = $deploymentFrequencyDays; + DeploymentFrequencyLow = $deploymentFrequencyLow; + DeploymentFrequencyHigh = $deploymentFrequencyHigh; MttrHours = $mttrAverage; LeadTimeDays = $leadTimeMedian; + LeadTimeLow = $leadTimeLow; + LeadTimeHigh = $leadTimeHigh; FailRate = $failRate; } } @@ -345,7 +357,7 @@ function global:New-FourKeyMetricsReport { } function ConvertTo-JsonWithJavascript($period){ - "[new Date($(DateTimeToTimestamp($period.EndDate))), $(ValueOrNull($period.DeploymentFrequencyDays)), $(ValueOrNull($period.LeadTimeDays)), $(ValueOrNull($period.FailRate)), $(ValueOrNull($period.MttrHours))]" + "[new Date($(DateTimeToTimestamp($period.EndDate))), $(ValueOrNull($period.DeploymentFrequencyDays)), $(ValueOrNull($period.DeploymentFrequencyLow)), $(ValueOrNull($period.DeploymentFrequencyHigh)), $(ValueOrNull($period.LeadTimeDays)), $(ValueOrNull($period.LeadTimeLow)), $(ValueOrNull($period.LeadTimeHigh)), $(ValueOrNull($period.FailRate)), $(ValueOrNull($period.MttrHours))]" } function ValueOrNull($value) From 72be8af248d2f2839a5307ef86fcb079c30ba64a Mon Sep 17 00:00:00 2001 From: Gareth Bragg Date: Fri, 16 Feb 2024 15:54:39 +0000 Subject: [PATCH 3/4] Pull new values into report --- Public/FourKeyMetricsTemplate.html | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/Public/FourKeyMetricsTemplate.html b/Public/FourKeyMetricsTemplate.html index 1cdaa6d..6802a29 100644 --- a/Public/FourKeyMetricsTemplate.html +++ b/Public/FourKeyMetricsTemplate.html @@ -16,7 +16,11 @@ var data = new google.visualization.DataTable(); data.addColumn("date", "EndDate"); data.addColumn("number", "Deployment Frequency"); + data.addColumn({type:"number", id:"i0", role:'interval'}); + data.addColumn({type:"number", id:"i1", role:'interval'}); data.addColumn("number", "Delivery Lead Time"); + data.addColumn({type:"number", id:"i0", role:'interval'}); + data.addColumn({type:"number", id:"i1", role:'interval'}); data.addColumn("number", "Change Failure Rate"); data.addColumn("number", "Mean Time to Recovery"); @@ -30,20 +34,22 @@ ]); const charts = [ - [1, "deploy-freq", "Days", "#336dc2"], - [2, "lead-time", "Days", "#128024"], - [3, "fail-rate", "Percent", "#c00", "percent"], - [4, "mttr", "Hours", "#fc9003"] + [1, 2, 3, "deploy-freq", "Days", "#336dc2"], + [4, 5, 6, "lead-time", "Days", "#128024"], + [7, 7, 7, "fail-rate", "Percent", "#c00", "percent"], + [8, 8, 8, "mttr", "Hours", "#fc9003"] ]; - + charts.forEach(c => { - const [colIndex, elementId, vAxisTitle, color, format] = c; + const [colIndex, lowColIndex, highColIndex, elementId, vAxisTitle, color, format] = c; var dataView = new google.visualization.DataView(data); - dataView.setColumns([0, colIndex]); - var chart = new google.visualization.LineChart( + dataView.setColumns([0, colIndex, lowColIndex, highColIndex]); + + var chart = new google.visualization.ComboChart( document.getElementById(elementId).getElementsByClassName("content")[0] ); + chart.draw(dataView, { vAxis: { title: vAxisTitle, format, minValue: 0, maxValue: 1 }, legend: { position: "none" }, @@ -52,7 +58,12 @@ pointSize: 6, trendlines: { 0: { pointSize: 0 }}, interpolateNulls: true, - hAxis: {minValue: REPORTSTARTDATE_PLACEHOLDER, maxValue: REPORTENDDATE_PLACEHOLDER} + hAxis: {minValue: REPORTSTARTDATE_PLACEHOLDER, maxValue: REPORTENDDATE_PLACEHOLDER}, + curveType: 'function', + interval: { + 'i0': { style:'area', color: color}, + 'i1': { style:'area', color: color} + } }); }); } From 28c9ea5e2160ec16e4d19700ce0dd774cb978cc9 Mon Sep 17 00:00:00 2001 From: Gareth Bragg Date: Fri, 16 Feb 2024 15:56:25 +0000 Subject: [PATCH 4/4] Make the tests a little stricter --- Tests/FourKeyMetrics.Tests.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/FourKeyMetrics.Tests.ps1 b/Tests/FourKeyMetrics.Tests.ps1 index 141d771..ac37c29 100644 --- a/Tests/FourKeyMetrics.Tests.ps1 +++ b/Tests/FourKeyMetrics.Tests.ps1 @@ -104,7 +104,7 @@ Describe 'Get-BucketedMetricsForPeriod' { ToDate = [DateTime]"2019-05-21" Interval = New-Timespan -D 4; IsFix = $true; - CommitAges = @(New-Timespan -H 24); + CommitAges = @(New-Timespan -H 12); } $releaseOne = [PSCustomObject]@{ @@ -114,7 +114,7 @@ Describe 'Get-BucketedMetricsForPeriod' { ToDate = [DateTime]"2019-05-17" Interval = New-Timespan -D 1; IsFix = $false; - CommitAges = @(New-Timespan -H 24); + CommitAges = @(New-Timespan -H 36); } $releases = @($releaseTwo, $releaseOne) @@ -130,8 +130,8 @@ Describe 'Get-BucketedMetricsForPeriod' { $bucketedMetrics.DeploymentFrequencyHigh | Should -Be "4" $bucketedMetrics.MttrHours | Should -Be 96 # Single recovery took four whole days $bucketedMetrics.LeadTimeDays | Should -Be "1" # Both releases have a lead time of one day - $bucketedMetrics.LeadTimeLow | Should -Be "1" - $bucketedMetrics.LeadTimeHigh | Should -Be "1" + $bucketedMetrics.LeadTimeLow | Should -Be "0.5" + $bucketedMetrics.LeadTimeHigh | Should -Be "1.5" $bucketedMetrics.FailRate | Should -Be "0.5" # One of two releases was a failure $bucketedMetrics.EndDate | Should -Be $endDate }