Format-Checklist rewrite (#28)
* reimplemented Format-Checklist to cover more scenarios * bumped version numberformat-checklist-fix
parent
f0d9af1583
commit
d7a5d6eb49
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1"
|
"powershell.scriptAnalysis.settingsPath": "./PSScriptAnalyzerSettings.psd1"
|
||||||
}
|
}
|
|
@ -1,15 +1,15 @@
|
||||||
@{
|
@{
|
||||||
'Rules' = @{
|
'Rules' = @{
|
||||||
'PSAvoidUsingCmdletAliases' = @{
|
'PSAvoidUsingCmdletAliases' = @{
|
||||||
'Whitelist' = @(
|
'Whitelist' = @(
|
||||||
'?',
|
'?',
|
||||||
'%',
|
'%',
|
||||||
'foreach',
|
'foreach',
|
||||||
'group',
|
'group',
|
||||||
'measure',
|
'measure',
|
||||||
'select',
|
'select',
|
||||||
'where'
|
'where'
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,124 +1,124 @@
|
||||||
@{
|
@{
|
||||||
|
|
||||||
# Script module or binary module file associated with this manifest.
|
# Script module or binary module file associated with this manifest.
|
||||||
RootModule = 'src\module.psm1'
|
RootModule = 'src\module.psm1'
|
||||||
|
|
||||||
# Version number of this module.
|
# Version number of this module.
|
||||||
ModuleVersion = '2.2.3'
|
ModuleVersion = '2.2.4'
|
||||||
|
|
||||||
# Supported PSEditions
|
# Supported PSEditions
|
||||||
# CompatiblePSEditions = @()
|
# CompatiblePSEditions = @()
|
||||||
|
|
||||||
# ID used to uniquely identify this module
|
# ID used to uniquely identify this module
|
||||||
GUID = 'c14a3682-ef9f-40ed-9521-ef74b433a755'
|
GUID = 'c14a3682-ef9f-40ed-9521-ef74b433a755'
|
||||||
|
|
||||||
# Author of this module
|
# Author of this module
|
||||||
Author = 'Chris Kuech'
|
Author = 'Chris Kuech'
|
||||||
|
|
||||||
# Company or vendor of this module
|
# Company or vendor of this module
|
||||||
CompanyName = 'Microsoft Corporation'
|
CompanyName = 'Microsoft Corporation'
|
||||||
|
|
||||||
# Copyright statement for this module
|
# Copyright statement for this module
|
||||||
Copyright = '(c) 2018 Microsoft Corporation. All rights reserved.'
|
Copyright = '(c) 2018 Microsoft Corporation. All rights reserved.'
|
||||||
|
|
||||||
# Description of the functionality provided by this module
|
# Description of the functionality provided by this module
|
||||||
Description = 'PowerShell framework for declaratively defining and idempotently imposing system configurations'
|
Description = 'PowerShell framework for declaratively defining and idempotently imposing system configurations'
|
||||||
|
|
||||||
# Minimum version of the Windows PowerShell engine required by this module
|
# Minimum version of the Windows PowerShell engine required by this module
|
||||||
# PowerShellVersion = ''
|
# PowerShellVersion = ''
|
||||||
|
|
||||||
# Name of the Windows PowerShell host required by this module
|
# Name of the Windows PowerShell host required by this module
|
||||||
# PowerShellHostName = ''
|
# PowerShellHostName = ''
|
||||||
|
|
||||||
# Minimum version of the Windows PowerShell host required by this module
|
# Minimum version of the Windows PowerShell host required by this module
|
||||||
# PowerShellHostVersion = ''
|
# PowerShellHostVersion = ''
|
||||||
|
|
||||||
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||||
# DotNetFrameworkVersion = ''
|
# DotNetFrameworkVersion = ''
|
||||||
|
|
||||||
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||||
# CLRVersion = ''
|
# CLRVersion = ''
|
||||||
|
|
||||||
# Processor architecture (None, X86, Amd64) required by this module
|
# Processor architecture (None, X86, Amd64) required by this module
|
||||||
# ProcessorArchitecture = ''
|
# ProcessorArchitecture = ''
|
||||||
|
|
||||||
# Modules that must be imported into the global environment prior to importing this module
|
# Modules that must be imported into the global environment prior to importing this module
|
||||||
# RequiredModules = @()
|
# RequiredModules = @()
|
||||||
|
|
||||||
# Assemblies that must be loaded prior to importing this module
|
# Assemblies that must be loaded prior to importing this module
|
||||||
# RequiredAssemblies = @()
|
# RequiredAssemblies = @()
|
||||||
|
|
||||||
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
|
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
|
||||||
ScriptsToProcess = @(
|
ScriptsToProcess = @(
|
||||||
'src\types.ps1'
|
'src\types.ps1'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Type files (.ps1xml) to be loaded when importing this module
|
# Type files (.ps1xml) to be loaded when importing this module
|
||||||
# TypesToProcess = @()
|
# TypesToProcess = @()
|
||||||
|
|
||||||
# Format files (.ps1xml) to be loaded when importing this module
|
# Format files (.ps1xml) to be loaded when importing this module
|
||||||
# FormatsToProcess = @()
|
# FormatsToProcess = @()
|
||||||
|
|
||||||
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
|
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
|
||||||
# NestedModules = @()
|
# NestedModules = @()
|
||||||
|
|
||||||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||||
FunctionsToExport = @(
|
FunctionsToExport = @(
|
||||||
'Format-CallStack',
|
'Format-CallStack',
|
||||||
'Format-Checklist',
|
'Format-Checklist',
|
||||||
'Invoke-Requirement',
|
'Invoke-Requirement',
|
||||||
'New-Requirement',
|
'New-Requirement',
|
||||||
'Set-Requirement',
|
'Set-Requirement',
|
||||||
'Test-Requirement'
|
'Test-Requirement'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||||
CmdletsToExport = @()
|
CmdletsToExport = @()
|
||||||
|
|
||||||
# Variables to export from this module
|
# Variables to export from this module
|
||||||
VariablesToExport = '*'
|
VariablesToExport = '*'
|
||||||
|
|
||||||
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
||||||
AliasesToExport = @()
|
AliasesToExport = @()
|
||||||
|
|
||||||
# DSC resources to export from this module
|
# DSC resources to export from this module
|
||||||
# DscResourcesToExport = @()
|
# DscResourcesToExport = @()
|
||||||
|
|
||||||
# List of all modules packaged with this module
|
# List of all modules packaged with this module
|
||||||
# ModuleList = @()
|
# ModuleList = @()
|
||||||
|
|
||||||
# List of all files packaged with this module
|
# List of all files packaged with this module
|
||||||
# FileList = @()
|
# FileList = @()
|
||||||
|
|
||||||
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
|
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
|
||||||
PrivateData = @{
|
PrivateData = @{
|
||||||
|
|
||||||
PSData = @{
|
PSData = @{
|
||||||
|
|
||||||
# Tags applied to this module. These help with module discovery in online galleries.
|
# Tags applied to this module. These help with module discovery in online galleries.
|
||||||
# Tags = @()
|
# Tags = @()
|
||||||
|
|
||||||
# A URL to the license for this module.
|
# A URL to the license for this module.
|
||||||
LicenseUri = 'https://github.com/Microsoft/Requirements/blob/master/LICENSE'
|
LicenseUri = 'https://github.com/Microsoft/Requirements/blob/master/LICENSE'
|
||||||
|
|
||||||
# A URL to the main website for this project.
|
# A URL to the main website for this project.
|
||||||
ProjectUri = 'https://github.com/Microsoft/Requirements'
|
ProjectUri = 'https://github.com/Microsoft/Requirements'
|
||||||
|
|
||||||
# A URL to an icon representing this module.
|
# A URL to an icon representing this module.
|
||||||
# IconUri = ''
|
# IconUri = ''
|
||||||
|
|
||||||
# ReleaseNotes of this module
|
# ReleaseNotes of this module
|
||||||
# ReleaseNotes = ''
|
# ReleaseNotes = ''
|
||||||
|
|
||||||
} # End of PSData hashtable
|
} # End of PSData hashtable
|
||||||
|
|
||||||
} # End of PrivateData hashtable
|
} # End of PrivateData hashtable
|
||||||
|
|
||||||
# HelpInfo URI of this module
|
# HelpInfo URI of this module
|
||||||
# HelpInfoURI = ''
|
# HelpInfoURI = ''
|
||||||
|
|
||||||
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
|
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
|
||||||
# DefaultCommandPrefix = ''
|
# DefaultCommandPrefix = ''
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
example.ps1
12
example.ps1
|
@ -2,8 +2,6 @@
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
Import-Module "$PSScriptRoot\Requirements.psd1" -Force
|
Import-Module "$PSScriptRoot\Requirements.psd1" -Force
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$requirements = @(
|
$requirements = @(
|
||||||
@{
|
@{
|
||||||
Name = "Resource 1"
|
Name = "Resource 1"
|
||||||
|
@ -17,6 +15,11 @@ $requirements = @(
|
||||||
Test = { $mySystem -contains 2 }
|
Test = { $mySystem -contains 2 }
|
||||||
Set = { $mySystem.Add(2) | Out-Null; Start-Sleep 1 }
|
Set = { $mySystem.Add(2) | Out-Null; Start-Sleep 1 }
|
||||||
},
|
},
|
||||||
|
@{
|
||||||
|
Name = "Checkpoint"
|
||||||
|
Describe = "Assert before continuing"
|
||||||
|
Test = { $mySystem }
|
||||||
|
},
|
||||||
@{
|
@{
|
||||||
Name = "Resource 3"
|
Name = "Resource 3"
|
||||||
Describe = "Resource 3 is present in the system"
|
Describe = "Resource 3 is present in the system"
|
||||||
|
@ -29,6 +32,11 @@ $requirements = @(
|
||||||
Test = { $mySystem -contains 4 }
|
Test = { $mySystem -contains 4 }
|
||||||
Set = { throw "This should not have been reached!"; Start-Sleep 1 }
|
Set = { throw "This should not have been reached!"; Start-Sleep 1 }
|
||||||
},
|
},
|
||||||
|
@{
|
||||||
|
Name = "Always set"
|
||||||
|
Describe = "Always run the set command"
|
||||||
|
Set = { Start-Sleep 1 }
|
||||||
|
},
|
||||||
@{
|
@{
|
||||||
Name = "Resource 5"
|
Name = "Resource 5"
|
||||||
Describe = "Resource 5 is present in the system"
|
Describe = "Resource 5 is present in the system"
|
||||||
|
|
|
@ -1,9 +1,92 @@
|
||||||
|
|
||||||
using namespace System.Collections.Generic
|
using namespace System.Collections.Generic
|
||||||
|
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "")]
|
||||||
|
Param()
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
."$PSScriptRoot\types.ps1"
|
."$PSScriptRoot\types.ps1"
|
||||||
|
|
||||||
|
function writePending($timestamp, $description) {
|
||||||
|
$symbol = " "
|
||||||
|
$color = "Yellow"
|
||||||
|
$message = "$timestamp [ $symbol ] $description"
|
||||||
|
Write-Host $message -ForegroundColor $color -NoNewline
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeSuccess($timestamp, $description, $clearString) {
|
||||||
|
$symbol = [char]8730
|
||||||
|
$color = "Green"
|
||||||
|
$message = "$timestamp [ $symbol ] $description"
|
||||||
|
Write-Host "`r$clearString" -NoNewline
|
||||||
|
Write-Host "`r$message" -ForegroundColor $color
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeFail($timestamp, $description, $clearString) {
|
||||||
|
$symbol = "X"
|
||||||
|
$color = "Red"
|
||||||
|
$message = "$timestamp [ $symbol ] $description"
|
||||||
|
Write-Host "`r$clearString" -NoNewline
|
||||||
|
Write-Host "`n$message`n" -ForegroundColor $color
|
||||||
|
exit -1
|
||||||
|
}
|
||||||
|
|
||||||
|
$fsm = @{
|
||||||
|
"Test Test Start $false" = {
|
||||||
|
writePending @args
|
||||||
|
@{
|
||||||
|
"Test Test Stop $true" = {
|
||||||
|
writeSuccess @args
|
||||||
|
$fsm
|
||||||
|
}
|
||||||
|
"Test Test Stop $false" = {
|
||||||
|
writeFail @args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"Set Set Start $false" = {
|
||||||
|
writePending @args
|
||||||
|
@{
|
||||||
|
"Set Set Stop $false" = {
|
||||||
|
writeSuccess @args
|
||||||
|
$fsm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"TestSet Test Start $false" = {
|
||||||
|
writePending @args
|
||||||
|
@{
|
||||||
|
"TestSet Test Stop $true" = {
|
||||||
|
writeSuccess @args
|
||||||
|
$fsm
|
||||||
|
}
|
||||||
|
"TestSet Test Stop $false" = {
|
||||||
|
@{
|
||||||
|
"TestSet Set Start $false" = {
|
||||||
|
@{
|
||||||
|
"TestSet Set Stop $false" = {
|
||||||
|
@{
|
||||||
|
"TestSet Validate Start $false" = {
|
||||||
|
@{
|
||||||
|
"TestSet Validate Stop $true" = {
|
||||||
|
writeSuccess @args
|
||||||
|
$fsm
|
||||||
|
}
|
||||||
|
"TestSet Validate Stop $false" = {
|
||||||
|
writeFail @args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Formats Requirement log events as a live-updating checklist
|
Formats Requirement log events as a live-updating checklist
|
||||||
|
@ -11,7 +94,6 @@ $ErrorActionPreference = "Stop"
|
||||||
Uses Write-Host
|
Uses Write-Host
|
||||||
#>
|
#>
|
||||||
function Format-Checklist {
|
function Format-Checklist {
|
||||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "")]
|
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
Param(
|
Param(
|
||||||
# Logged Requirement lifecycle events
|
# Logged Requirement lifecycle events
|
||||||
|
@ -21,62 +103,36 @@ function Format-Checklist {
|
||||||
)
|
)
|
||||||
|
|
||||||
begin {
|
begin {
|
||||||
$lastDescription = ""
|
$previousRequirement = $null
|
||||||
|
$nextFsm = $fsm
|
||||||
}
|
}
|
||||||
|
|
||||||
process {
|
process {
|
||||||
$timestamp = Get-Date -Date $_.Date -Format 'hh:mm:ss'
|
$requirement = $_.Requirement
|
||||||
$description = $_.Requirement.Describe
|
|
||||||
$method, $state, $result = $_.Method, $_.State, $_.Result
|
# build state vector
|
||||||
switch ($method) {
|
$requirementType = ("Test", "Set" | ? { $requirement.$_ }) -join ""
|
||||||
"Test" {
|
$method = $_.Method
|
||||||
switch ($state) {
|
$lifecycleState = $_.State
|
||||||
"Start" {
|
$successResult = [bool]$_.Result
|
||||||
$symbol = " "
|
$stateVector = "$requirementType $method $lifecycleState $successResult"
|
||||||
$color = "Yellow"
|
|
||||||
$message = "$timestamp [ $symbol ] $description"
|
# build transition arguments
|
||||||
Write-Host $message -ForegroundColor $color -NoNewline
|
$timestamp = Get-Date -Date $_.Date -Format "hh:mm:ss"
|
||||||
$lastDescription = $description
|
$description = $requirement.Describe
|
||||||
}
|
$clearString = ' ' * "??:??:?? [ ? ] $($previousRequirement.Describe)".Length
|
||||||
"Stop" {
|
$transitionArgs = @($timestamp, $description, $clearString)
|
||||||
switch ($result) {
|
|
||||||
$true {
|
# transition FSM
|
||||||
$symbol = [char]8730
|
if (-not $nextFsm[$stateVector]) {
|
||||||
$color = "Green"
|
throw @"
|
||||||
$message = "$timestamp [ $symbol ] $description"
|
Format-Checklist has reached an unexpected state '$stateVector'.
|
||||||
Write-Host "`r$(' ' * $lastDescription.Length)" -NoNewline
|
If you are piping the output of Invoke-Requirement directly to this
|
||||||
Write-Host "`r$message" -ForegroundColor $color
|
cmdlet, then this is probably a bug in Format-Checklist.
|
||||||
$lastDescription = $description
|
"@
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"Validate" {
|
|
||||||
switch ($state) {
|
|
||||||
"Stop" {
|
|
||||||
switch ($result) {
|
|
||||||
$true {
|
|
||||||
$symbol = [char]8730
|
|
||||||
$color = "Green"
|
|
||||||
$message = "$timestamp [ $symbol ] $description"
|
|
||||||
Write-Host "`r$(' ' * $lastDescription.Length)" -NoNewline
|
|
||||||
Write-Host "`r$message" -ForegroundColor $color
|
|
||||||
$lastDescription = $description
|
|
||||||
}
|
|
||||||
$false {
|
|
||||||
$symbol = "X"
|
|
||||||
$color = "Red"
|
|
||||||
$message = "$timestamp [ $symbol ] $description"
|
|
||||||
Write-Host "`n$message`n" -ForegroundColor $color
|
|
||||||
$lastDescription = $description
|
|
||||||
exit -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
$nextFsm = &$nextFsm[$stateVector] @transitionArgs
|
||||||
|
$previousRequirement = $requirement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue