Skip to content

Commit

Permalink
🐛 Fix Issue with Modules Koans (#399)
Browse files Browse the repository at this point in the history
* 🐛 Avoid error on missing module folder

 - This is an expected case for Modules to be missing in the user folder
   so just check the path and avoid searching it if it doesn't exist yet

* 🐛 Explicitly import required modules
 - Check script required modules & import them prior to invoking Pester

* 🐛 Fix Show-Karma parameter sets

 - Sets prevented use of -(Include)Module with -Contemplate :(

* 🐛 Fix errors

* 🐛 remove misplaced alias

* 🐛 Make sure module params are added to get

* 🐛 Improve handling for modules

Added handling to Get-Karma to ensure Update-PSKoan copies
module files when module params are specified.

* 🐛 Fix Invoke-Koan functionality

 - Fix edge case where PSKoans is not on PSModulePath.
 - Copy PSModulePath and PSKoans path into new runspace.
 - Propagate errors from runspace to current session in case of errors.

* 🎨 Indentation fix

* 🐛 Fix Unix issue

 - Apparently Import-Module fails to recognise Unix fully qualified path

* ✨ Add debugging script

* ✅ Update Show-Karma tests

* 🐛 Fix null path with -Module and -Contemplate

* 🚧 Add format generation to debug script
  • Loading branch information
vexx32 committed Jul 5, 2020
1 parent 247dcc1 commit 94faddd
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 57 deletions.
32 changes: 10 additions & 22 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,19 @@
"version": "0.2.0",
"configurations": [
{
"name": "PowerShell Launch Current File",
"name": "PowerShell Launch Script",
"type": "PowerShell",
"request": "launch",
"script": "${file}",
"args": [],
"cwd": "${file}"
},
{
"name": "PowerShell Launch Current File in Temporary Console",
"type": "PowerShell",
"request": "launch",
"script": "${file}",
"args": [],
"cwd": "${file}",
"createTemporaryIntegratedConsole": true
"script": "./Start-DebugSession.ps1",
"cwd": "${workspaceFolder}"
},
{
"name": "PowerShell Launch Current File w/Args Prompt",
"name": "PowerShell: Launch Current File",
"type": "PowerShell",
"request": "launch",
"script": "${file}",
"args": [
"${command:SpecifyScriptArgs}"
],
"cwd": "${file}"
},
{
"name": "PowerShell Attach to Host Process",
"type": "PowerShell",
"request": "attach"
},
{
"name": "PowerShell Interactive Session",
"type": "PowerShell",
Expand All @@ -47,6 +29,12 @@
"type": "PowerShell",
"request": "attach",
"processId": "current"
},
{
"name": "PowerShell Attach to Host Process",
"type": "PowerShell",
"request": "attach",
"runspaceId": 1
}
]
}
48 changes: 40 additions & 8 deletions PSKoans/Private/Invoke-Koan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,57 @@
)
end {
try {
$Requirements = [System.Management.Automation.Language.Parser]::ParseFile(
$ParameterSplat.Script,
[ref]$null,
[ref]$null
).Ast.ScriptRequirements

$Script = {
param( $Params )
param( $Params, $RequiredModules, $PSKoansPath, $PSModulePath )

[System.Collections.Generic.HashSet[string]] $ModulePaths = @(
$PSModulePath -split [System.IO.Path]::PathSeparator
$env:PSModulePath -split [System.IO.Path]::PathSeparator
)

$env:PSModulePath = $ModulePaths -join [System.IO.Path]::PathSeparator

Get-Module $PSKoansPath -ListAvailable | Import-Module
foreach ($module in $RequiredModules) {
Import-Module $module
}

. ([scriptblock]::Create('using module PSKoans'))
Invoke-Pester @Params
}

$Thread = [powershell]::Create()
$Thread.AddScript($Script) > $null
$Thread.AddArgument($ParameterSplat) > $null
$Runspace = [powershell]::Create()
$Runspace.AddScript($Script) > $null
$Runspace.AddParameter('Params', $ParameterSplat) > $null
$Runspace.AddParameter('PSKoansPath', $MyInvocation.MyCommand.Module.ModuleBase) > $null
$Runspace.AddParameter('PSModulePath', $env:PSModulePath) > $null

$Status = $Thread.BeginInvoke()
if ($Requirements.RequiredModules) {
$Runspace.AddParameter('RequiredModules', $Requirements.RequiredModules)
}

$Status = $Runspace.BeginInvoke()

do { Start-Sleep -Milliseconds 1 } until ($Status.IsCompleted)

$Thread.EndInvoke($Status)
$Result = $Runspace.EndInvoke($Status)

if ($Runspace.HadErrors) {
# These will be errors outside the test itself; better propagate them upwards.
foreach ($errorItem in $Runspace.Streams.Error) {
$PSCmdlet.WriteError($errorItem)
}
}

$Result
}
finally {
$Thread.Dispose()
$Runspace.Dispose()
}
}
}
30 changes: 28 additions & 2 deletions PSKoans/Public/Get-Karma.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
'ListKoans' {
Get-PSKoan @GetParams
}
"Default" {
default {
Write-Verbose 'Sorting koans...'
try {
$SortedKoanList = Get-PSKoan @GetParams
Expand All @@ -46,6 +46,17 @@
$PSCmdlet.ThrowTerminatingError($_)
}

foreach ($item in $IncludeModule) {
if ($SortedKoanList.Where{ $_.Module -notlike $item }.Count -eq 0) {
$warningString = @(
"Koans for a module name matching '$item' were not found in your user directory."
"Please run Update-PSKoan -Module $item to ensure those modules are present."
) -join ' '

Write-Warning $warningString
}
}

Write-Verbose "Koan files retrieved: $($SortedKoanList.Count)"
Write-Verbose 'Counting koans...'
[int]$TotalKoans = $SortedKoanList | Measure-Koan
Expand All @@ -68,9 +79,24 @@
$PSCmdlet.ThrowTerminatingError( (New-PSKoanErrorRecord @ErrorDetails) )
}

if ($Module) {
# No koans were found because modules aren't copied by default.
Update-PSKoan -Module $Module -Confirm:$false
Get-Karma @PSBoundParameters

return
}

# Something's wrong; possibly a koan folder from older versions, or a folder exists but has no files
$Modules = if ($IncludeModule) {
@{ IncludeModule = $IncludeModule }
}
else {
@{ }
}

Write-Warning 'No koans found in your koan directory. Initiating full reset...'
Update-PSKoan -Confirm:$false
Update-PSKoan -Confirm:$false @Modules
Get-Karma @PSBoundParameters # Re-call ourselves with the same parameters

return # Skip the rest of the function
Expand Down
24 changes: 15 additions & 9 deletions PSKoans/Public/Get-PSKoan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,31 @@ function Get-PSKoan {
'Module' { Join-Path -Path $script:ModuleRoot -ChildPath 'Koans' }
}

if ($pscmdlet.ParameterSetName -eq 'ListModules') {
$moduleList = Join-Path -Path $ParentPath -ChildPath 'Modules' |
Get-ChildItem -Directory |
Select-Object -ExpandProperty Name
if ($PSCmdlet.ParameterSetName -eq 'ListModules') {
$modulesPath = Join-Path -Path $ParentPath -ChildPath 'Modules'

return $moduleList
if (Test-Path $modulesPath) {
$modulesPath |
Get-ChildItem -Directory |
Select-Object -ExpandProperty Name
}

return
}

$KoanDirectories = switch ($pscmdlet.ParameterSetName) {
$KoanDirectories = switch ($PSCmdlet.ParameterSetName) {
'IncludeModule' {
$Module = $IncludeModule
Get-ChildItem $ParentPath -Exclude Modules -Directory
}
{ $Module } {
$ModuleRegex = ConvertFrom-WildcardPattern -Pattern $Module

Join-Path -Path $ParentPath -ChildPath 'Modules' |
Get-ChildItem -Directory |
Where-Object { $_.Name -match $ModuleRegex }
$modulesPath = Join-Path -Path $ParentPath -ChildPath 'Modules'
if (Test-Path $modulesPath) {
Get-ChildItem $modulesPath -Directory |
Where-Object { $_.Name -match $ModuleRegex }
}
}
}

Expand Down
31 changes: 23 additions & 8 deletions PSKoans/Public/Show-Karma.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,43 @@ function Show-Karma {
[Alias('Invoke-PSKoans', 'Test-Koans', 'Get-Enlightenment', 'Meditate', 'Clear-Path', 'Measure-Karma')]
param(
[Parameter(ParameterSetName = 'ListKoans')]
[Parameter(ParameterSetName = 'ListKoans-ModuleOnly')]
[Parameter(ParameterSetName = 'ListKoans-IncludeModule')]
[Parameter(ParameterSetName = 'ModuleOnly')]
[Parameter(ParameterSetName = 'IncludeModule')]
[Parameter(ParameterSetName = 'OpenFile')]
[Parameter(ParameterSetName = 'OpenFile-ModuleOnly')]
[Parameter(ParameterSetName = 'OpenFile-IncludeModule')]
[Parameter(ParameterSetName = 'Default')]
[Alias('Koan', 'File')]
[SupportsWildcards()]
[string[]]
$Topic,

[Parameter(Mandatory, ParameterSetName = 'ModuleOnly')]
[Parameter(ParameterSetName = 'ListKoans')]
[Parameter(Mandatory, ParameterSetName = 'ListKoans-ModuleOnly')]
[Parameter(Mandatory, ParameterSetName = 'OpenFile-ModuleOnly')]
[SupportsWildcards()]
[string[]]
$Module,

[Parameter(Mandatory, ParameterSetName = 'IncludeModule')]
[Parameter(Mandatory, ParameterSetName = 'ListKoans-IncludeModule')]
[Parameter(Mandatory, ParameterSetName = 'OpenFile-IncludeModule')]
[SupportsWildcards()]
[string[]]
$IncludeModule,

[Parameter(Mandatory, ParameterSetName = 'ListKoans')]
[Parameter(Mandatory, ParameterSetName = 'ListKoans-ModuleOnly')]
[Parameter(Mandatory, ParameterSetName = 'ListKoans-IncludeModule')]
[Alias('ListKoans', 'ListTopics')]
[switch]
$List,

[Parameter(Mandatory, ParameterSetName = 'OpenFile')]
[Parameter(Mandatory, ParameterSetName = 'OpenFile-ModuleOnly')]
[Parameter(Mandatory, ParameterSetName = 'OpenFile-IncludeModule')]
[Alias('Meditate')]
[switch]
$Contemplate,
Expand All @@ -55,13 +66,13 @@ function Show-Karma {

$GetParams = @{ }
switch ($PSCmdlet.ParameterSetName) {
'IncludeModule' { $GetParams['IncludeModule'] = $IncludeModule }
'ModuleOnly' { $GetParams['Module'] = $Module }
{ $_ -match 'IncludeModule$' } { $GetParams['IncludeModule'] = $IncludeModule }
{ $_ -match 'ModuleOnly$' } { $GetParams['Module'] = $Module }
{ $PSBoundParameters.ContainsKey('Topic') } { $GetParams['Topic'] = $Topic }
}

switch ($PSCmdlet.ParameterSetName) {
'ListKoans' {
{ $_ -match '^ListKoans' } {
Get-PSKoan @GetParams
}
'OpenFolder' {
Expand All @@ -86,7 +97,7 @@ function Show-Karma {
$KoanLocation | Invoke-Item
}
}
'OpenFile' {
{ $_ -match '^OpenFile' } {
# If there is no cached data, we need to call Get-Karma to populate it
if (-not $script:CurrentTopic -or ($Topic -and $script:CurrentTopic.Name -notlike $Topic)) {
try {
Expand All @@ -99,7 +110,12 @@ function Show-Karma {
}

$Editor = Get-PSKoanSetting -Name Editor
$FilePath = (Get-PSKoan -Topic $script:CurrentTopic.Name -Scope User).Path
$KoanParams = @{
Topic = $script:CurrentTopic.Name
IncludeModule = @( $Module; $IncludeModule )
Scope = 'User'
}
$FilePath = (Get-PSKoan @KoanParams).Path
$LineNumber = $script:CurrentTopic.CurrentLine

$Arguments = switch ($Editor) {
Expand Down Expand Up @@ -140,8 +156,7 @@ function Show-Karma {
try {
Get-Karma @GetParams |
Format-Custom @FormatParams |
Out-String |
Write-Host
Out-Host
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
Expand Down
11 changes: 11 additions & 0 deletions Start-DebugSession.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
$env:PSModulePath = $(
@(
$env:PSModulePath -split [System.IO.Path]::PathSeparator
$PSScriptRoot
) | Select-Object -Unique
) -join [System.IO.Path]::PathSeparator

& $PSScriptRoot/PSKoans.ezformat.ps1
Import-Module $PSScriptRoot/PSKoans

### Enter code to test below
16 changes: 8 additions & 8 deletions Tests/Functions/Public/Show-Karma.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Describe 'Show-Karma' {

Context 'Default Behaviour' {
BeforeAll {
Mock Write-Host { }
Mock Out-Host { }
Mock Get-Karma -ModuleName 'PSKoans' {
[PSCustomObject]@{
PSTypeName = 'PSKoans.Result'
Expand All @@ -50,7 +50,7 @@ Describe 'Show-Karma' {
}

It 'should write the formatted output to host' {
Assert-MockCalled Write-Host
Assert-MockCalled Out-Host
}

It 'should call Get-Karma to examine the koans' {
Expand All @@ -60,7 +60,7 @@ Describe 'Show-Karma' {

Context 'With All Koans Completed' {
BeforeAll {
Mock Write-Host { }
Mock Out-Host { }
Mock Get-Karma -ModuleName 'PSKoans' {
[PSCustomObject]@{
PSTypeName = 'PSKoans.CompleteResult'
Expand All @@ -80,7 +80,7 @@ Describe 'Show-Karma' {
Context 'With -ClearScreen Switch' {
BeforeAll {
Mock Clear-Host { }
Mock Write-Host { }
Mock Out-Host { }
Mock Get-Karma -ModuleName 'PSKoans' {
[PSCustomObject]@{
PSTypeName = 'PSKoans.Result'
Expand Down Expand Up @@ -109,7 +109,7 @@ Describe 'Show-Karma' {
}

It 'should display the rendered output' {
Assert-MockCalled Write-Host
Assert-MockCalled Out-Host
}

It 'should Invoke-Pester on each of the koans' {
Expand All @@ -119,7 +119,7 @@ Describe 'Show-Karma' {

Context 'With Nonexistent Koans Folder / No Koans Found' {
BeforeAll {
Mock Write-Host { }
Mock Out-Host { }
Mock Get-PSKoan -ModuleName 'PSKoans' { }
Mock Update-PSKoan -ModuleName 'PSKoans' { throw 'Prevent recursion' }
Mock Write-Warning
Expand Down Expand Up @@ -174,7 +174,7 @@ Describe 'Show-Karma' {

Context 'With -Topic Parameter' {
BeforeAll {
Mock Write-Host { }
Mock Out-Host { }
Mock Get-Karma -MockWith {
[PSCustomObject]@{
PSTypeName = 'PSKoans.Result'
Expand Down Expand Up @@ -204,7 +204,7 @@ Describe 'Show-Karma' {
Context 'With All Koans in a Single Topic Completed' {
BeforeAll {
Mock Format-Custom { $InputObject.Complete }
Mock Write-Host { }
Mock Out-Host { }
Mock Get-Karma -ModuleName 'PSKoans' {
[PSCustomObject]@{
PSTypeName = 'PSKoans.CompleteResult'
Expand Down

0 comments on commit 94faddd

Please sign in to comment.