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