Skip to content

Commit 8dc5ce8

Browse files
committed
Add better feedback and reduce noise in the event of one or more modules unable to load.
1 parent 37acd44 commit 8dc5ce8

File tree

2 files changed

+100
-25
lines changed

2 files changed

+100
-25
lines changed

Source/Convert-HelpToHtmlTree.ps1

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -318,13 +318,13 @@ function Convert-HelpToHtmlTree
318318
$namespaceSummary = @{}
319319
$modules = @{}
320320

321-
$Namespaces | % { $modules[$_] = Import-AllModules $_ }
321+
$Namespaces | % { $modules[$_] = @(Import-AllModules $_) }
322322

323323
# Process in a separate loop from above so all modules are loaded first
324324
# in case they are referenced in documentation links
325-
$Namespaces | % { $namespaceSummary[$_] = Process-Namespace $_ $modules }
325+
$Namespaces | % { $namespaceSummary[$_] = Process-Namespace $_ $modules[$_] }
326326

327-
$modules.Keys | % { Remove-AllModules $modules[$_] }
327+
$modules.Keys | % { Remove-AllModules $_ $modules[$_] }
328328

329329
$emptyNamespaces = $modules.Keys | Where { !$modules[$_] }
330330
if ($emptyNamespaces) {
@@ -363,20 +363,29 @@ function GlobExpandNamespaceArgument($nsArgument)
363363
function Import-AllModules($namespace)
364364
{
365365
$namespaceDir = Join-Path $moduleRoot $namespace
366-
$modules = Get-ChildItem $namespaceDir |
366+
$modules = @(Get-ChildItem $namespaceDir |
367367
where { $_.PsIsContainer } |
368-
select -ExpandProperty Name
368+
select -ExpandProperty Name)
369+
$validModules = @()
369370
$modules |
370371
% {
371-
if (! (Import-ModuleUnlessDocGeneratorItself $namespace $_))
372-
{ [void](Handle-MissingValue "Cannot load $_ module") }
372+
try {
373+
[void](Import-ModuleUnlessDocGeneratorItself $namespace $_)
374+
$validModules += $_
375+
}
376+
catch {
377+
$errRecord = $_
378+
[void](Handle-MissingValue $errRecord.Exception.Message)
379+
}
373380
}
374-
return $modules
381+
write-Host "Imported $($validModules.count) out of $($modules.count) modules for namespace '$namespace'"
382+
return $validModules
375383
}
376384

377-
function Remove-AllModules($modules)
385+
function Remove-AllModules($namespace, $nsModules)
378386
{
379-
$modules |
387+
write-Host "Removing $($nsModules.count) modules for namespace '$namespace'"
388+
$nsModules |
380389
% { Remove-ModuleUnlessDocGeneratorItself $_ }
381390
}
382391

@@ -417,7 +426,7 @@ function Add-ItemToContentsList(
417426
$script:itemList += $item
418427
}
419428

420-
function Process-Namespace($namespace, $modules)
429+
function Process-Namespace($namespace, $nsModules)
421430
{
422431
Write-Host "Namespace: $namespace"
423432
$script:moduleSummary = @{}
@@ -426,8 +435,8 @@ function Process-Namespace($namespace, $modules)
426435

427436
# ??Possible Pester bug requires this conditional wrapper that is not
428437
# otherwise needed (when the module list is empty).
429-
if ($modules[$namespace]) {
430-
$modules[$namespace] | % { Process-Module $namespace $_ $title}
438+
if ($nsModules) {
439+
$nsModules | % { Process-Module $namespace $_ $title}
431440
}
432441

433442
Add-ItemToContentsList $namespace "namespace" -itemUrl "index.html"
@@ -733,7 +742,7 @@ function Import-ModuleUnlessDocGeneratorItself($namespace, $moduleName)
733742
Remove-Module $moduleName -ErrorAction SilentlyContinue
734743

735744
$modulePath = $moduleRoot, $namespace, $moduleName, "$moduleName.psd1" -join '\'
736-
Import-Module $modulePath -force
745+
Import-Module $modulePath -Force -ErrorAction Stop
737746
return ! (!$?)
738747
}
739748

Tests/DocTreeGenerator.Tests.ps1

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ $content
929929
Mock Generate-ContentsPage
930930

931931
It 'Imports each module in a namespace before building' {
932-
Mock Import-AllModules { $script:sequence += 'import'; return 'm1' }
932+
Mock Import-AllModules -MockWith { $script:sequence += 'import'; return 'm1' } -ParameterFilter { $namespace -eq 'ns1' }
933933
Mock Remove-AllModules { $script:sequence += 'remove' }
934934
Mock Process-Module { $script:sequence += 'process' }
935935
Mock GlobExpandNamespaceArgument { $nsArgument }
@@ -941,7 +941,7 @@ $content
941941
}
942942

943943
It 'Removes each module in a namespace after building' {
944-
Mock Import-AllModules { $script:sequence += 'import'; return 'm1' }
944+
Mock Import-AllModules -MockWith { $script:sequence += 'import'; return 'm1' } -ParameterFilter { $namespace -eq 'ns1' }
945945
Mock Remove-AllModules { $script:sequence += 'remove' }
946946
Mock Process-Module { $script:sequence += 'process' }
947947
Mock GlobExpandNamespaceArgument { $nsArgument }
@@ -954,7 +954,7 @@ $content
954954

955955
It 'Processes each module in a single namespace' {
956956
$moduleNames = 'm1','m2'
957-
Mock Import-AllModules { return $moduleNames }
957+
Mock Import-AllModules -MockWith { $moduleNames } -ParameterFilter { $namespace -eq 'ns1' }
958958
Mock Remove-AllModules { $script:sequence += 'remove' }
959959
Mock Process-Module { $script:sequence += 'process' }
960960
Mock GlobExpandNamespaceArgument { $nsArgument }
@@ -972,8 +972,6 @@ $content
972972
'nspace1' = $ns1Modules
973973
'nspace2' = $ns2Modules
974974
}
975-
# problem getting this to work!
976-
# Mock Import-AllModules -MockWith { return $namespaces[$namespace] }
977975
Mock Import-AllModules -MockWith { $ns1Modules } -ParameterFilter { $namespace -eq 'nspace1' }
978976
Mock Import-AllModules -MockWith { $ns2Modules } -ParameterFilter { $namespace -eq 'nspace2' }
979977
Mock Remove-AllModules { $script:sequence += 'remove' }
@@ -989,7 +987,7 @@ $content
989987
}
990988

991989
It 'WARNS about no namespaces when supplied argument does not resolve to path' {
992-
Mock Import-AllModules
990+
Mock Import-AllModules -ParameterFilter { $namespace -eq 'unknownNamespace' }
993991
Mock Remove-AllModules
994992
Mock Process-Module
995993
Mock GlobExpandNamespaceArgument { return @() }
@@ -998,7 +996,7 @@ $content
998996
}
999997

1000998
It 'Does NOT warn about no namespaces when supplied argument resolves to path' {
1001-
Mock Import-AllModules { return 'm1' }
999+
Mock Import-AllModules -MockWith { 'm1' } -ParameterFilter { $namespace -eq 'ns1' }
10021000
Mock Remove-AllModules
10031001
Mock GlobExpandNamespaceArgument { $nsArgument }
10041002
# emulate real Process-Module with respect to generating warning
@@ -1008,7 +1006,7 @@ $content
10081006
}
10091007

10101008
It 'WARNS about no modules when single namespace dir has none' {
1011-
Mock Import-AllModules { @() }
1009+
Mock Import-AllModules -MockWith { @() } -ParameterFilter { $namespace -eq 'ns1' }
10121010
Mock Remove-AllModules
10131011
Mock GlobExpandNamespaceArgument { $nsArgument }
10141012
Mock Process-Module { $script:moduleCount++ }
@@ -1018,7 +1016,7 @@ $content
10181016

10191017
It 'WARNS about no modules when one of several namespace dirs has none' {
10201018
Mock Import-AllModules { @() } -ParameterFilter { $namespace -eq 'ns2' }
1021-
Mock Import-AllModules { 'm1','m2' }
1019+
Mock Import-AllModules { 'm1','m2' } -ParameterFilter { $namespace -in 'ns1','ns3' }
10221020
Mock Remove-AllModules
10231021
Mock GlobExpandNamespaceArgument { $nsArgument }
10241022
Mock Process-Module { $script:moduleCount++ }
@@ -1028,7 +1026,7 @@ $content
10281026

10291027
It 'WARNS about no modules when multiple namespace dirs have none' {
10301028
Mock Import-AllModules { @() } -ParameterFilter { $namespace -in 'ns2','ns4' }
1031-
Mock Import-AllModules { 'm1','m2' }
1029+
Mock Import-AllModules { 'm1','m2' } -ParameterFilter { $namespace -in 'ns1','ns3' }
10321030
Mock Remove-AllModules
10331031
Mock GlobExpandNamespaceArgument { $nsArgument }
10341032
Mock Process-Module { $script:moduleCount++ }
@@ -1037,14 +1035,82 @@ $content
10371035
}
10381036

10391037
It 'Does NOT warn about no modules when modules present' {
1040-
Mock Import-AllModules { 'm1' }
1038+
Mock Import-AllModules -MockWith { 'm1' } -ParameterFilter { $namespace -eq 'ns1' }
10411039
Mock Remove-AllModules
10421040
Mock GlobExpandNamespaceArgument { $nsArgument }
10431041
Mock Process-Module { $script:moduleCount++ }
10441042
Convert-HelpToHtmlTree -Namespaces 'ns1'
10451043
Assert-MockCalled Handle-MissingValue 0 -scope It
10461044
}
10471045

1046+
It 'Returns multiple modules that loaded without error' {
1047+
Mock Get-ChildItem { @(
1048+
(New-Object PSObject -Property @{ name = 'badModule'; PsIsContainer = $true }),
1049+
(New-Object PSObject -Property @{ name = 'm1'; PsIsContainer = $true }),
1050+
(New-Object PSObject -Property @{ name = 'm2'; PsIsContainer = $true })
1051+
) }
1052+
Mock Import-ModuleUnlessDocGeneratorItself { throw "bad module" } -ParameterFilter { $moduleName -eq 'badModule' }
1053+
Mock Import-ModuleUnlessDocGeneratorItself
1054+
Mock Remove-AllModules
1055+
Mock GlobExpandNamespaceArgument { $nsArgument }
1056+
Mock Process-Module
1057+
Convert-HelpToHtmlTree -Namespaces 'ns5'
1058+
Assert-MockCalled Handle-MissingValue 1 { $message -match 'bad module' } -scope It
1059+
Assert-MockCalled Remove-AllModules 1 { $nsModules -contains 'm1' } -scope It
1060+
Assert-MockCalled Remove-AllModules 1 { $nsModules -contains 'm2' } -scope It
1061+
Assert-MockCalled Remove-AllModules 1 { $nsModules -notcontains 'badModule' } -scope It
1062+
Assert-MockCalled Remove-AllModules 1 { $nsModules.Count -eq 2 } -scope It
1063+
}
1064+
1065+
It 'Returns single module out of multiple modules that loaded without error' {
1066+
Mock Get-ChildItem { @(
1067+
(New-Object PSObject -Property @{ name = 'badM1'; PsIsContainer = $true }),
1068+
(New-Object PSObject -Property @{ name = 'badM2'; PsIsContainer = $true }),
1069+
(New-Object PSObject -Property @{ name = 'm1'; PsIsContainer = $true })
1070+
) }
1071+
Mock Import-ModuleUnlessDocGeneratorItself { throw "bad module" } -ParameterFilter { $moduleName -match 'bad' }
1072+
Mock Import-ModuleUnlessDocGeneratorItself
1073+
Mock Remove-AllModules
1074+
Mock GlobExpandNamespaceArgument { $nsArgument }
1075+
Mock Process-Module
1076+
Convert-HelpToHtmlTree -Namespaces 'ns5'
1077+
Assert-MockCalled Handle-MissingValue 1 { $message -match 'bad module' } -scope It
1078+
Assert-MockCalled Remove-AllModules 1 { $nsModules -contains 'm1' } -scope It
1079+
Assert-MockCalled Remove-AllModules 1 { $nsModules -notcontains 'badM1' } -scope It
1080+
Assert-MockCalled Remove-AllModules 1 { $nsModules -notcontains 'badM2' } -scope It
1081+
Assert-MockCalled Remove-AllModules 1 { $nsModules.Count -eq 1 } -scope It
1082+
}
1083+
1084+
It 'Returns sole module that loaded without error' {
1085+
Mock Get-ChildItem { @(
1086+
(New-Object PSObject -Property @{ name = 'm1'; PsIsContainer = $true })
1087+
) }
1088+
Mock Import-ModuleUnlessDocGeneratorItself { throw "bad module" } -ParameterFilter { $moduleName -match 'bad' }
1089+
Mock Import-ModuleUnlessDocGeneratorItself
1090+
Mock Remove-AllModules
1091+
Mock GlobExpandNamespaceArgument { $nsArgument }
1092+
Mock Process-Module
1093+
Convert-HelpToHtmlTree -Namespaces 'ns5'
1094+
Assert-MockCalled Handle-MissingValue 0 { $message -match 'bad module' } -scope It
1095+
Assert-MockCalled Remove-AllModules 1 { $nsModules -contains 'm1' } -scope It
1096+
Assert-MockCalled Remove-AllModules 1 { $nsModules.Count -eq 1 } -scope It
1097+
}
1098+
1099+
It 'Returns no modules when sole module has error' {
1100+
Mock Get-ChildItem { @(
1101+
(New-Object PSObject -Property @{ name = 'badModule'; PsIsContainer = $true })
1102+
) }
1103+
Mock Import-ModuleUnlessDocGeneratorItself { throw "bad module" } -ParameterFilter { $moduleName -match 'bad' }
1104+
Mock Import-ModuleUnlessDocGeneratorItself
1105+
Mock Remove-AllModules
1106+
Mock GlobExpandNamespaceArgument { $nsArgument }
1107+
Mock Process-Module
1108+
Convert-HelpToHtmlTree -Namespaces 'ns5'
1109+
Assert-MockCalled Handle-MissingValue 1 { $message -match 'bad module' } -scope It
1110+
Assert-MockCalled Remove-AllModules 1 { $nsModules -notcontains 'badModule' } -scope It
1111+
Assert-MockCalled Remove-AllModules 1 { $nsModules.Count -eq 0 } -scope It
1112+
}
1113+
10481114
}
10491115

10501116
}

0 commit comments

Comments
 (0)