From 820881d15ec6bfa0f639536eeb296885e3756e84 Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Thu, 2 Feb 2017 23:46:45 -0800 Subject: [PATCH 01/10] Added unit test --- Tests/Unit.Tests.ps1 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Tests/Unit.Tests.ps1 b/Tests/Unit.Tests.ps1 index a67ea43..0ea483b 100644 --- a/Tests/Unit.Tests.ps1 +++ b/Tests/Unit.Tests.ps1 @@ -18,6 +18,12 @@ Describe "Basic unit tests" -Tags Build { it "Creates an Object" { {[ScriptLine]::New()} | Should Not Throw } + it "ToString()" { + {[ScriptLine]::New().toString()} | Should Not Throw + } + it "Creates an Object" { + {[ScriptLine]::New().AddExecutionTime(1)} | Should Not Throw + } } Context "Class: ScriptProfiler" { @@ -25,7 +31,9 @@ Describe "Basic unit tests" -Tags Build { it "Creates an Object" { {[ScriptProfiler]::New()} | Should Not Throw } + it "Start()" { + {[ScriptProfiler]::Start()} | Should Not Throw + } } } - } \ No newline at end of file From 17d2c57382e1badc22a34d3a78d7811aaf4e22cd Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Fri, 3 Feb 2017 00:16:08 -0800 Subject: [PATCH 02/10] Added Chronometer lcass --- Chronometer/Classes/Chronometer.ps1 | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Chronometer/Classes/Chronometer.ps1 diff --git a/Chronometer/Classes/Chronometer.ps1 b/Chronometer/Classes/Chronometer.ps1 new file mode 100644 index 0000000..42644c1 --- /dev/null +++ b/Chronometer/Classes/Chronometer.ps1 @@ -0,0 +1,10 @@ +class Chronometer +{ + [hashtable]$FileMap = @{} + + [void]AddFile([string[]]$Path) + { + + } + +} \ No newline at end of file From f532089adaa9d4c56637c8692f97ea22d75523ae Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Fri, 3 Feb 2017 00:48:30 -0800 Subject: [PATCH 03/10] Refactoring --- Chronometer/Classes/Chronometer.ps1 | 70 +++++++++++++++++++++++++- Chronometer/Public/Get-Chronometer.ps1 | 38 ++------------ 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/Chronometer/Classes/Chronometer.ps1 b/Chronometer/Classes/Chronometer.ps1 index 42644c1..43386d1 100644 --- a/Chronometer/Classes/Chronometer.ps1 +++ b/Chronometer/Classes/Chronometer.ps1 @@ -1,10 +1,76 @@ class Chronometer { [hashtable]$FileMap = @{} + $Breakpoint = @() - [void]AddFile([string[]]$Path) + [void]AddBreakpoint([string[]]$Path) { + foreach($file in (Resolve-Path $Path -ea 0)) + { + $script = [MonitoredScript]@{Path=$file.Path} + $lines = $script.SetScript($file) + $this.fileMap[$file.Path] = $script + + $breakpointParam = @{ + Script = $file + Line = (1..$lines) + Action = {[ScriptProfiler]::RecordExecution( $_) } + } + $this.breakPoint += Set-PSBreakpoint @breakpointParam + } + } + + [void]ClearBreakpoint() + { + Remove-PSBreakpoint $this.Breakpointbreakpoint + } + + [void] AddExecution([hashtable]$Execution) + { + $this.FileMap[$Execution.Breakpoint.Script].AddExecution($Execution) + } +} + +class MonitoredScript +{ + [string]$Path + [System.Collections.ArrayList]$Line + + $lastNode = $null + $lastRecord = $null + + MonitoredScript() + { + $this.Line = [System.Collections.ArrayList]::New() + } + + [int] SetScript([string]$Path) + { + Get-Content -Path $Path | %{ $this.Line.Add( [ScriptLine]@{text=$_})} + return $this.Line.Count() + } + + [void] AddExecution([hashtable]$node) + { + $record = $this.Line[$node.Breakpoint.Line-1] + $record.LineNumber = $node.Breakpoint.Line - 1 + + if($this.lastNode) + { + $duration = $node.ElapsedMilliseconds - $this.lastNode.ElapsedMilliseconds + } + else + { + $duration = $node.ElapsedMilliseconds + } + + if($this.lastRecord) + { + $this.lastRecord.AddExecutionTime($duration) + } + + $this.lastRecord = $record + $this.lastNode = $node } - } \ No newline at end of file diff --git a/Chronometer/Public/Get-Chronometer.ps1 b/Chronometer/Public/Get-Chronometer.ps1 index a57d7ca..b5bcadb 100644 --- a/Chronometer/Public/Get-Chronometer.ps1 +++ b/Chronometer/Public/Get-Chronometer.ps1 @@ -21,47 +21,17 @@ function Get-Chronometer $ScriptBlock ) - $breakPoint = @() - $fileMap = @{} - - foreach($file in (Resolve-Path $Path -ea 0)) - { - $fileMap[$file.Path] = @( Get-Content -Path $file | %{[ScriptLine]@{text=$_;path=$file.path}}) - - $lines = $fileMap[$file.Path].count - $breakPoint += Set-PSBreakpoint -Script $file -Line (1..$lines) -Action {[ScriptProfiler]::RecordExecution( $_) } - } + $Chronometer = [Chronometer]::New() + $breakPoint = $Chronometer.AddBreakpoint($Path) [ScriptProfiler]::Start() [void] $ScriptBlock.Invoke() - Remove-PSBreakpoint $breakpoint - - #$fileMap | ConvertTo-Json - + $Chronometer.ClearBreakpoint() foreach($node in [ScriptProfiler]::Queue.GetEnumerator()) { - $record = $fileMap[$node.Breakpoint.Script][$node.Breakpoint.Line-1] - $record.LineNumber = $node.Breakpoint.Line - 1 - - if($lastNode) - { - $duration = $node.ElapsedMilliseconds - $lastNode.ElapsedMilliseconds - } - else - { - $duration = $node.ElapsedMilliseconds - } - - - if($lastRecord) - { - $lastRecord.AddExecutionTime($duration) - } - - $lastRecord = $record - $lastNode = $node + $Chronometer.AddExecution($node) } foreach($script in $fileMap.Keys) From af7e4143cc975f0b1b6315b95f29df023cdaf8fc Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Sat, 4 Feb 2017 20:53:08 -0800 Subject: [PATCH 04/10] reworked class importing, passing pester tests skip ci --- Chronometer/Classes/Chronometer.ps1 | 14 +++++++++++--- Chronometer/chronometer.psm1 | 25 ++++++++++++++++++------- Tests/Help.Tests.ps1 | 3 ++- Tests/Project.Tests.ps1 | 14 +++++++++++++- Tests/Unit.Tests.ps1 | 5 +++-- 5 files changed, 47 insertions(+), 14 deletions(-) diff --git a/Chronometer/Classes/Chronometer.ps1 b/Chronometer/Classes/Chronometer.ps1 index 43386d1..94ad8ed 100644 --- a/Chronometer/Classes/Chronometer.ps1 +++ b/Chronometer/Classes/Chronometer.ps1 @@ -23,12 +23,20 @@ class Chronometer [void]ClearBreakpoint() { - Remove-PSBreakpoint $this.Breakpointbreakpoint + if($this.Breakpoint -ne $null -and $this.Breakpoint.count -gt 0) + { + Remove-PSBreakpoint -Breakpoint $this.Breakpoint + } + } [void] AddExecution([hashtable]$Execution) { - $this.FileMap[$Execution.Breakpoint.Script].AddExecution($Execution) + $script = $Execution.Breakpoint.Script + if($this.FileMap.ContainsKey($script)) + { + $this.FileMap[$script].AddExecution($Execution) + } } } @@ -48,7 +56,7 @@ class MonitoredScript [int] SetScript([string]$Path) { Get-Content -Path $Path | %{ $this.Line.Add( [ScriptLine]@{text=$_})} - return $this.Line.Count() + return $this.Line.Count } [void] AddExecution([hashtable]$node) diff --git a/Chronometer/chronometer.psm1 b/Chronometer/chronometer.psm1 index 3b06336..f63a722 100644 --- a/Chronometer/chronometer.psm1 +++ b/Chronometer/chronometer.psm1 @@ -1,9 +1,23 @@ #Requires -Version 5.0 +[cmdletbinding()] +param() -Write-Verbose "Importing Functions" +Write-Verbose $PSScriptRoot +Write-Verbose 'Import Classes in order because of dependencies' +$classList = @( + 'ScriptLine', + 'ScriptProfiler', + 'Chronometer' +) -# Import everything in sub folders folder -foreach($folder in @('classes', 'private', 'public','includes')) +foreach($class in $classList) +{ + Write-Verbose " Class: $class" + . "$psscriptroot\classes\$class.ps1" +} + +Write-Verbose 'Import everything in sub folders folder' +foreach($folder in @('private', 'public','includes')) { $root = Join-Path -Path $PSScriptRoot -ChildPath $folder if(Test-Path -Path $root) @@ -13,12 +27,9 @@ foreach($folder in @('classes', 'private', 'public','includes')) # dot source each file $files | where-Object{ $_.name -NotLike '*.Tests.ps1'} | - ForEach-Object{Write-Verbose $_.name; . $_.FullName} + ForEach-Object{Write-Verbose $_.basename; . $_.FullName} } } Export-ModuleMember -function (Get-ChildItem -Path "$PSScriptRoot\public\*.ps1").basename -# Hack for my build system that had a conflit with the keyword node -New-Alias -Name 'DiGraph' -Value 'Graph' -ErrorAction SilentlyContinue -Export-ModuleMember -Alias 'DiGraph' diff --git a/Tests/Help.Tests.ps1 b/Tests/Help.Tests.ps1 index 6f4d3fb..7a61ead 100644 --- a/Tests/Help.Tests.ps1 +++ b/Tests/Help.Tests.ps1 @@ -2,9 +2,10 @@ $projectRoot = Resolve-Path "$PSScriptRoot\.." $moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psm1") $moduleName = Split-Path $moduleRoot -Leaf -Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force Describe "Help tests for $moduleName" -Tags Build { + + Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force $functions = Get-Command -Module $moduleName $help = $functions | %{Get-Help $_.name} diff --git a/Tests/Project.Tests.ps1 b/Tests/Project.Tests.ps1 index 5ed72b3..c12f8bd 100644 --- a/Tests/Project.Tests.ps1 +++ b/Tests/Project.Tests.ps1 @@ -4,7 +4,7 @@ $moduleName = Split-Path $moduleRoot -Leaf Describe "General project validation: $moduleName" -Tags Build { - $scripts = Get-ChildItem $projectRoot -Include *.ps1,*.psm1,*.psd1 -Recurse + $scripts = Get-ChildItem $projectRoot -Include *.ps1,*.psm1,*.psd1 -Recurse | where fullname -notmatch 'classes' # TestCases are splatted to the script so we need hashtables $testCase = $scripts | Foreach-Object{@{file=$_}} @@ -19,6 +19,18 @@ Describe "General project validation: $moduleName" -Tags Build { $errors.Count | Should Be 0 } + It "Classes are valid" { + $classes = Get-ChildItem $projectRoot -Include *.ps1,*.psm1,*.psd1 -Recurse | where fullname -match 'classes' + + # Must be imported togehter incase they depend on each other + $contents = Get-Content -Path $classes.FullName | Out-String + + $errors = $null + $null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors) + $errors.Count | Should Be 0 + } + + It "Module '$moduleName' can import cleanly" { {Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force } | Should Not Throw } diff --git a/Tests/Unit.Tests.ps1 b/Tests/Unit.Tests.ps1 index 0ea483b..ecb61cc 100644 --- a/Tests/Unit.Tests.ps1 +++ b/Tests/Unit.Tests.ps1 @@ -2,12 +2,13 @@ $projectRoot = Resolve-Path "$PSScriptRoot\.." $moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") $moduleName = Split-Path $moduleRoot -Leaf -Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force - Describe "Basic unit tests" -Tags Build { + + Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force Context "Function: Get-Chronometer" { it "Does not throw" { + # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} {Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {"Test"} } | Should Not Throw } } From 1b836300015303cffdd9383117c9d4ff466e46c9 Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Sat, 4 Feb 2017 23:18:43 -0800 Subject: [PATCH 05/10] Everything is stable again. Some refactoring work is still in progress !deploy --- Chronometer/Classes/Chronometer.ps1 | 10 +++++++-- Chronometer/Public/Get-Chronometer.ps1 | 30 +++++++++++++++----------- README.md | 3 ++- Tests/Unit.Tests.ps1 | 8 ++++++- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/Chronometer/Classes/Chronometer.ps1 b/Chronometer/Classes/Chronometer.ps1 index 94ad8ed..159ffe2 100644 --- a/Chronometer/Classes/Chronometer.ps1 +++ b/Chronometer/Classes/Chronometer.ps1 @@ -35,9 +35,15 @@ class Chronometer $script = $Execution.Breakpoint.Script if($this.FileMap.ContainsKey($script)) { + # Each script tracks it's own execution times $this.FileMap[$script].AddExecution($Execution) } } + + [MonitoredScript[]] GetResults() + { + return $this.FileMap.Values + } } class MonitoredScript @@ -45,8 +51,8 @@ class MonitoredScript [string]$Path [System.Collections.ArrayList]$Line - $lastNode = $null - $lastRecord = $null + hidden $lastNode = $null + hidden $lastRecord = $null MonitoredScript() { diff --git a/Chronometer/Public/Get-Chronometer.ps1 b/Chronometer/Public/Get-Chronometer.ps1 index b5bcadb..bc95fa2 100644 --- a/Chronometer/Public/Get-Chronometer.ps1 +++ b/Chronometer/Public/Get-Chronometer.ps1 @@ -22,23 +22,29 @@ function Get-Chronometer ) $Chronometer = [Chronometer]::New() - $breakPoint = $Chronometer.AddBreakpoint($Path) - [ScriptProfiler]::Start() - [void] $ScriptBlock.Invoke() + Write-Verbose "Setting breapoints" + $Chronometer.AddBreakpoint($Path) - $Chronometer.ClearBreakpoint() - - foreach($node in [ScriptProfiler]::Queue.GetEnumerator()) + if($Chronometer.breakPoint -ne $null) { - $Chronometer.AddExecution($node) - } + Write-Verbose "Executing Script" + [ScriptProfiler]::Start() + [void] $ScriptBlock.Invoke() - foreach($script in $fileMap.Keys) - { - foreach($line in $fileMap[$script]) + Write-Verbose "Clearing Breapoints" + $Chronometer.ClearBreakpoint() + + Write-Verbose "Processing data" + foreach($node in [ScriptProfiler]::Queue.GetEnumerator()) { - Write-Output $line + $Chronometer.AddExecution($node) } + + Write-Output $Chronometer.GetResults() + } + else + { + Write-Warning "Parsing files did not result in any breakpoints" } } diff --git a/README.md b/README.md index c18dda7..5360d69 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ Provide a script file and a command to execute. $path = myscript.ps1 Get-Chronometer -Path $path -Script {. .\myscript.ps1} -OutVariable report - $report.ToString() + $report.line | % tostring + The user experience is important to me but I am working on the core logic right now. I will loop back to make it more intuitive and simple to use. ## Things to know diff --git a/Tests/Unit.Tests.ps1 b/Tests/Unit.Tests.ps1 index ecb61cc..81d9a4f 100644 --- a/Tests/Unit.Tests.ps1 +++ b/Tests/Unit.Tests.ps1 @@ -3,7 +3,7 @@ $moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") $moduleName = Split-Path $moduleRoot -Leaf Describe "Basic unit tests" -Tags Build { - + Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -force Context "Function: Get-Chronometer" { @@ -11,6 +11,12 @@ Describe "Basic unit tests" -Tags Build { # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} {Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {"Test"} } | Should Not Throw } + + it "Executes a script and gives results" { + # Get-Chronometer -Path ScratchFiles\example.ps1 -Script {"Test"} + $results = Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {. "$PSScriptRoot\..\ScratchFiles\example.ps1"} + $results | Should Not BeNullOrEmpty + } } InModuleScope $moduleName { From baa544d9245d11fa0c403b58d0bbe00c24a5c793 Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Sun, 5 Feb 2017 00:00:58 -0800 Subject: [PATCH 06/10] reworked some files skip ci --- Chronometer/Classes/Chronometer.ps1 | 42 --------------------- Chronometer/Classes/MonitoredScript.ps1 | 49 +++++++++++++++++++++++++ Chronometer/chronometer.psm1 | 1 + Tests/Unit.Tests.ps1 | 8 ++++ 4 files changed, 58 insertions(+), 42 deletions(-) create mode 100644 Chronometer/Classes/MonitoredScript.ps1 diff --git a/Chronometer/Classes/Chronometer.ps1 b/Chronometer/Classes/Chronometer.ps1 index 159ffe2..fe867df 100644 --- a/Chronometer/Classes/Chronometer.ps1 +++ b/Chronometer/Classes/Chronometer.ps1 @@ -46,45 +46,3 @@ class Chronometer } } -class MonitoredScript -{ - [string]$Path - [System.Collections.ArrayList]$Line - - hidden $lastNode = $null - hidden $lastRecord = $null - - MonitoredScript() - { - $this.Line = [System.Collections.ArrayList]::New() - } - - [int] SetScript([string]$Path) - { - Get-Content -Path $Path | %{ $this.Line.Add( [ScriptLine]@{text=$_})} - return $this.Line.Count - } - - [void] AddExecution([hashtable]$node) - { - $record = $this.Line[$node.Breakpoint.Line-1] - $record.LineNumber = $node.Breakpoint.Line - 1 - - if($this.lastNode) - { - $duration = $node.ElapsedMilliseconds - $this.lastNode.ElapsedMilliseconds - } - else - { - $duration = $node.ElapsedMilliseconds - } - - if($this.lastRecord) - { - $this.lastRecord.AddExecutionTime($duration) - } - - $this.lastRecord = $record - $this.lastNode = $node - } -} \ No newline at end of file diff --git a/Chronometer/Classes/MonitoredScript.ps1 b/Chronometer/Classes/MonitoredScript.ps1 new file mode 100644 index 0000000..c2c04d7 --- /dev/null +++ b/Chronometer/Classes/MonitoredScript.ps1 @@ -0,0 +1,49 @@ +class MonitoredScript +{ + [string]$Path + [System.Collections.Generic.List[ScriptLine]]$Line + + hidden $lastNode = $null + hidden $lastRecord = $null + + [float]$ExecutionTime = 0 + [int]$LinesOfCode = 0 + + MonitoredScript() + { + $this.Line =New-Object 'System.Collections.Generic.List[ScriptLine]' + } + + [int] SetScript([string]$Path) + { + Get-Content -Path $Path | %{ $this.Line.Add( [ScriptLine]@{text=$_;path=$path})} + $this.LinesOfCode = $this.Line.Count + return $this.LinesOfCode + } + + [void] AddExecution([hashtable]$node) + { + # Line numbers start at 1 but the array starts at 0 + $lineNumber = $node.Breakpoint.Line - 1 + $record = $this.Line[$lineNumber] + $record.LineNumber = $lineNumber + + if($this.lastNode) + { + $duration = $node.ElapsedMilliseconds - $this.lastNode.ElapsedMilliseconds + } + else + { + $duration = $node.ElapsedMilliseconds + } + + if($this.lastRecord) + { + $this.lastRecord.AddExecutionTime($duration) + $this.ExecutionTime += $duration + } + + $this.lastRecord = $record + $this.lastNode = $node + } +} \ No newline at end of file diff --git a/Chronometer/chronometer.psm1 b/Chronometer/chronometer.psm1 index f63a722..19d1b5c 100644 --- a/Chronometer/chronometer.psm1 +++ b/Chronometer/chronometer.psm1 @@ -7,6 +7,7 @@ Write-Verbose 'Import Classes in order because of dependencies' $classList = @( 'ScriptLine', 'ScriptProfiler', + 'MonitoredScript', 'Chronometer' ) diff --git a/Tests/Unit.Tests.ps1 b/Tests/Unit.Tests.ps1 index 81d9a4f..ece0505 100644 --- a/Tests/Unit.Tests.ps1 +++ b/Tests/Unit.Tests.ps1 @@ -42,5 +42,13 @@ Describe "Basic unit tests" -Tags Build { {[ScriptProfiler]::Start()} | Should Not Throw } } + + Context "Class: MonitoredScript" { + {[MonitoredScript]::New()} | Should Not Throw + } + + Context "Class: MonitoredScript" { + {[MonitoredScript]::SetScript("$projectRoot\scratchfiles\example.ps1")} | Should Not Throw + } } } \ No newline at end of file From 8d98ecac3b44078524efe8f9ba048dfb789b0ec5 Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Sun, 5 Feb 2017 00:58:49 -0800 Subject: [PATCH 07/10] Added help comments to Format command --- Chronometer/Private/Write-ScriptLine.ps1 | 29 +++++++++++++ Chronometer/Public/Format-Chronometer.ps1 | 50 ++++++++++++++++++++++ Chronometer/chronometer.psd1 | Bin 4294 -> 4342 bytes ScratchFiles/example.ps1 | 5 ++- 4 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 Chronometer/Private/Write-ScriptLine.ps1 create mode 100644 Chronometer/Public/Format-Chronometer.ps1 diff --git a/Chronometer/Private/Write-ScriptLine.ps1 b/Chronometer/Private/Write-ScriptLine.ps1 new file mode 100644 index 0000000..217728c --- /dev/null +++ b/Chronometer/Private/Write-ScriptLine.ps1 @@ -0,0 +1,29 @@ + +function Write-ScriptLine +{ + param( + [scriptline] + $line, + $WarningAt = [int]::MaxValue, + $ErrorAt = [int]::MaxValue + ) + + if($line) + { + $Color = 'Green' + if($line.HitCount -eq 0) + { + $Color = 'Gray' + } + elseif($line.Average -ge $ErrorAt) + { + $Color = 'Red' + } + elseif($line.Average -ge $WarningAt) + { + $Color = 'Yellow' + } + + Write-Host $line.toString() -ForegroundColor $Color + } +} \ No newline at end of file diff --git a/Chronometer/Public/Format-Chronometer.ps1 b/Chronometer/Public/Format-Chronometer.ps1 new file mode 100644 index 0000000..f12be7e --- /dev/null +++ b/Chronometer/Public/Format-Chronometer.ps1 @@ -0,0 +1,50 @@ +function Format-Chronometer +{ + <# + .Description + Generates a report from a Chronometer + + .Example + $script = ls C:\workspace\PSGraph\PSGraph -Recurse -Filter *.ps1 + $resultes = Get-Chronometer -Path $script.fullname -ScriptBlock {Invoke-Pester C:\workspace\PSGraph} + $results | Format-Chronometer -WarnAt 20 -ErrorAt 200 + #> + [cmdletbinding()] + param( + # This is a MonitoredScript object from Get-Chronometer + [Parameter( + ValueFromPipeline=$true + )] + [MonitoredScript[]] + $InputObject, + + # If the average time of a command is more than this, the output is yellow + [int] + $WarningAt = 20, + + #If the average time of a comamand is more than this, the output is red + [int] + $ErrorAt = 200 + ) + + begin { + $green = @{ForgroundColor='green'} + $grey = @{ForgroundColor='grey'} + $yellow = @{ForgroundColor='grey'} + $yellow = @{ForgroundColor='grey'} + $yellow = @{ForgroundColor='grey'} + } + process + { + foreach($script in $InputObject) + { + Write-Host '' + Write-Host "Script: $($script.Path)" -ForegroundColor Green + Write-Host "Execution Time: $($script.ExecutionTime)" -ForegroundColor Green + foreach($line in $script.line) + { + Write-ScriptLine $line -WarningAt $WarningAt -ErrorAt $ErrorAt + } + } + } +} diff --git a/Chronometer/chronometer.psd1 b/Chronometer/chronometer.psd1 index 73e6e5c7cb7bfff09f4920bf33ab5c02e2c4ed25..066b559315876a25acd09ca1c2bc4bcb8fcf6027 100644 GIT binary patch delta 53 zcmX@6_)T$x0u!UrW<{n#R%QnVjmZ<)l?8Pe)EV3u@)?R4av2gCN*Ht}zvmNYR%g)M JyqR5?698!i42A#z delta 27 jcmeyScuaAF0u!U*W<{n#*2&Y@l_tjtaBP0V&cz7;fKCWw diff --git a/ScratchFiles/example.ps1 b/ScratchFiles/example.ps1 index fab56a3..47b3502 100644 --- a/ScratchFiles/example.ps1 +++ b/ScratchFiles/example.ps1 @@ -10,7 +10,8 @@ foreach($n in 1..10) "test string" sleep -Milliseconds 3 } + sleep -Milliseconds 12 -sleep -Milliseconds 5 +sleep -Milliseconds 120 +$test = 1+1 $test = 1+1 -$test = 1+1 \ No newline at end of file From d5d510dd891e0a209b09b29557851c3f1ee3f94a Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Sun, 5 Feb 2017 01:06:38 -0800 Subject: [PATCH 08/10] Added unit test for format command --- Tests/Unit.Tests.ps1 | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Tests/Unit.Tests.ps1 b/Tests/Unit.Tests.ps1 index ece0505..3f91f90 100644 --- a/Tests/Unit.Tests.ps1 +++ b/Tests/Unit.Tests.ps1 @@ -19,6 +19,18 @@ Describe "Basic unit tests" -Tags Build { } } + Context "Function: Format-Chronometer" { + + it "Does not throw" { + {$null | Format-Chronometer } | Should Not Throw + } + + it "Can process a result object without throwing" { + $results = Get-Chronometer -Path $PSScriptRoot\..\ScratchFiles\example.ps1 -Script {. "$PSScriptRoot\..\ScratchFiles\example.ps1"} + $results | Format-Chronometer *>&1 | Should Not BeNullOrEmpty + } + } + InModuleScope $moduleName { Context "Class: ScriptLine" { @@ -44,11 +56,15 @@ Describe "Basic unit tests" -Tags Build { } Context "Class: MonitoredScript" { - {[MonitoredScript]::New()} | Should Not Throw + it "Creates an object" { + {[MonitoredScript]::New()} | Should Not Throw + } + + it "SetScript()" { + $monitor = [MonitoredScript]::New() + {$monitor.SetScript("$projectRoot\scratchfiles\example.ps1")} | Should Not Throw + } } - Context "Class: MonitoredScript" { - {[MonitoredScript]::SetScript("$projectRoot\scratchfiles\example.ps1")} | Should Not Throw - } } } \ No newline at end of file From 28106861815afa2a6a80b89bb4b4090c4f821e04 Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Sun, 5 Feb 2017 01:11:46 -0800 Subject: [PATCH 09/10] Updated readme skip ci --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5360d69..791061f 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Place the Chronometer folder into your `$PSModulePath`. I will publish to the Po Provide a script file and a command to execute. $path = myscript.ps1 - Get-Chronometer -Path $path -Script {. .\myscript.ps1} -OutVariable report - $report.line | % tostring + $Chronometer = Get-Chronometer -Path $path -Script {. .\myscript.ps1} + $Chronometer | % tostring | Format-Chronometer The user experience is important to me but I am working on the core logic right now. I will loop back to make it more intuitive and simple to use. From 1d047b5f140c71774453b4b2de57baaeb2850ca1 Mon Sep 17 00:00:00 2001 From: KevinMarquette Date: Sun, 5 Feb 2017 01:19:55 -0800 Subject: [PATCH 10/10] Fixed unit testissue with build ssytem --- Tests/Unit.Tests.ps1 | 4 +++- psake.ps1 | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Tests/Unit.Tests.ps1 b/Tests/Unit.Tests.ps1 index 3f91f90..3d2b475 100644 --- a/Tests/Unit.Tests.ps1 +++ b/Tests/Unit.Tests.ps1 @@ -61,8 +61,10 @@ Describe "Basic unit tests" -Tags Build { } it "SetScript()" { + pushd $projectRoot $monitor = [MonitoredScript]::New() - {$monitor.SetScript("$projectRoot\scratchfiles\example.ps1")} | Should Not Throw + {$monitor.SetScript(".\scratchfiles\example.ps1")} | Should Not Throw + popd } } diff --git a/psake.ps1 b/psake.ps1 index b51af94..cf732c6 100644 --- a/psake.ps1 +++ b/psake.ps1 @@ -33,7 +33,7 @@ Task Init { Task UnitTests -Depends Init { $lines 'Running quick unit tests to fail early if there is an error' - $TestResults = Invoke-Pester -Path $ProjectRoot\Tests\*unit* -PassThru -Tag Build -Show Failed + $TestResults = Invoke-Pester -Path $ProjectRoot\Tests\*unit* -PassThru -Tag Build if($TestResults.FailedCount -gt 0) { @@ -47,7 +47,7 @@ Task Test -Depends UnitTests { "`n`tSTATUS: Testing with PowerShell $PSVersion" # Gather test results. Store them in a variable and file - $TestResults = Invoke-Pester -Path $ProjectRoot\Tests -PassThru -OutputFormat NUnitXml -OutputFile "$ProjectRoot\$TestFile" -Tag Build -Show Failed + $TestResults = Invoke-Pester -Path $ProjectRoot\Tests -PassThru -OutputFormat NUnitXml -OutputFile "$ProjectRoot\$TestFile" -Tag Build # In Appveyor? Upload our tests! #Abstract this into a function? If($ENV:BHBuildSystem -eq 'AppVeyor')