From 5874031bfdc8f873c2a6275cf49ae1dab1ca06d4 Mon Sep 17 00:00:00 2001 From: James Truher Date: Mon, 25 Jul 2022 12:05:59 -0700 Subject: [PATCH 1/2] Support creating a single file with Export-CrescendoCommand This is a fix for issue 155. Add tests for new functionality. --- .../src/Microsoft.PowerShell.Crescendo.psd1 | 2 +- .../src/Microsoft.PowerShell.Crescendo.psm1 | 74 +++++++++++++-- .../test/ExportCrescendoCommand.Tests.ps1 | 95 +++++++++++++++++++ 3 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 Microsoft.PowerShell.Crescendo/test/ExportCrescendoCommand.Tests.ps1 diff --git a/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psd1 b/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psd1 index a8d6b00..bbc50ee 100644 --- a/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psd1 +++ b/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psd1 @@ -8,7 +8,7 @@ RootModule = 'Microsoft.PowerShell.Crescendo.psm1' # Version number of this module. -ModuleVersion = '1.0.0' +ModuleVersion = '1.1.0' # ID used to uniquely identify this module GUID = '2dd09744-1ced-4636-a8ce-09a0bf0e566a' diff --git a/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1 b/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1 index 3d1f957..8b50b54 100644 --- a/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1 +++ b/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1 @@ -621,30 +621,88 @@ function New-CrescendoCommand { } function Export-CrescendoCommand { - [CmdletBinding(SupportsShouldProcess=$true)] + [CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName="MultipleFile")] param ( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)] [Command[]]$command, - [Parameter()][string]$targetDirectory = "." + [Parameter(ParameterSetName="MultipleFile")][string]$targetDirectory = ".", + [Parameter(ParameterSetName="SingleFile", Mandatory=$true)][string]$fileName = "", + [Parameter(ParameterSetName="SingleFile")][switch]$Force ) + BEGIN + { + if ( $PSCmdlet.ParameterSetName -eq "SingleFile") { + $commandConfigurations = @() + $outputFile = Get-Item -Path $filename -ErrorAction Ignore + + if ( @($outputFile).Count -gt 1) { + throw ("'$fileName' must resolve to a single file") + } + + # output file does not exist + if ( ! $outputFile ) { + $outputFile = $fileName + } + else { + # check to see if the path is a directory + if ( $outputFile.PSIsContainer ) { + throw ("'$fileName' is a directory, it must resolve to a single file") + } + if ( $Force ) { + $outputFile.Delete() + } + else { + throw ("File '$fileName' already exists. Use -Force to overwrite") + } + } + } + } + PROCESS { foreach($crescendoCommand in $command) { - if($PSCmdlet.ShouldProcess($crescendoCommand)) { - $fileName = "{0}-{1}.crescendo.json" -f $crescendoCommand.Verb, $crescendoCommand.Noun - $exportPath = Join-Path $targetDirectory $fileName - $crescendoCommand.ExportConfigurationFile($exportPath) - + if($PSCmdlet.ShouldProcess($crescendoCommand.FunctionName)) { + if ($PSCmdlet.ParameterSetName -eq "MultipleFile") { + $fileName = "{0}-{1}.crescendo.json" -f $crescendoCommand.Verb, $crescendoCommand.Noun + $exportPath = Join-Path $targetDirectory $fileName + $crescendoCommand.ExportConfigurationFile($exportPath) + } + else { + $commandConfigurations += $crescendoCommand + } } } } + + END + { + # there's nothing to do for this parameter set. + if ($PSCmdlet.ParameterSetName -eq "MultipleFile") { + return + } + + # now save all the command configurations to a single file. + $multiConfiguration = [System.Collections.Specialized.OrderedDictionary]::new() + $multiConfiguration.Add('$schema', 'https://aka.ms/PowerShell/Crescendo/Schemas/2022-06') + $multiConfiguration.Add('commands', $commandConfigurations) + $sOptions = [System.Text.Json.JsonSerializerOptions]::new() + $sOptions.WriteIndented = $true + $sOptions.MaxDepth = 10 + $sOptions.IgnoreNullValues = $true + $text = [System.Text.Json.JsonSerializer]::Serialize($multiConfiguration, $sOptions) + if ($PSCmdlet.ShouldProcess($outputFile)) { + Set-Content -LiteralPath $outputFile -Value $text + } + } } function Import-CommandConfiguration { [CmdletBinding()] -param ([Parameter(Position=0,Mandatory=$true)][string]$file) +param ( + [Parameter(Position=0,Mandatory=$true)][string]$file + ) $options = [System.Text.Json.JsonSerializerOptions]::new() # this dance is to support multiple configurations in a single file # The deserializer doesn't seem to support creating [command[]] diff --git a/Microsoft.PowerShell.Crescendo/test/ExportCrescendoCommand.Tests.ps1 b/Microsoft.PowerShell.Crescendo/test/ExportCrescendoCommand.Tests.ps1 new file mode 100644 index 0000000..86478ee --- /dev/null +++ b/Microsoft.PowerShell.Crescendo/test/ExportCrescendoCommand.Tests.ps1 @@ -0,0 +1,95 @@ +Describe "Export-CrescendoCommand tests" { + BeforeAll { + $assetDir = Join-Path -Path $PSScriptRoot -ChildPath "../Samples" + $configurationSet = Get-ChildItem -Path $assetDir -Filter "Docker*" | + ForEach-Object { $_.FullName } | + Sort-Object + $commands = $configurationSet | ForEach-Object { Import-CommandConfiguration $_ } + $commandNames = $commands.FunctionName | Sort-Object + $expectedFilenames = $commandNames.foreach({"${_}.crescendo.json"}) + $singleCommand = $commands[0] + } + + Context "MultipleFile parameter set" { + BeforeAll { + Export-CrescendoCommand -Command $commands -targetDirectory TestDrive: + $expectedCount = $expectedFilenames.Count + $testCases = $expectedFilenames | Foreach-Object { + @{ file = $_ } + } + } + + It "Correct count of files should be present" { + (Get-ChildItem TestDrive:).Count | Should -Be $expectedCount + } + + It "individual file '' exists" -testCases $testCases { + param ( $file ) + $filePath = Join-Path -Path TestDrive: -ChildPath $file + $filePath | Should -Exist + } + } + + Context "SingleFile parameter set" { + BeforeAll { + $comboCrescendoFile = "TestDrive:combo.crescendo.json" + Export-CrescendoCommand -Command $commands -filename $comboCrescendoFile + $comboJson = Get-Content $comboCrescendoFile | ConvertFrom-Json + $comboCommandNames = $comboJson.Commands.Foreach({"{0}-{1}" -f $_.Verb, $_.Noun}) + $testCases = $comboCommandNames.Foreach({@{ file = $_ }}) + + $singleCrescendoFile = "TestDrive:single.crescendo.json" + Export-CrescendoCommand -Command $singleCommand -filename $singleCrescendoFile + $singleJson = Get-Content $singleCrescendoFile | ConvertFrom-Json + $singleCommandName = $singleCommand.FunctionName + } + + It "file 'TestDrive:combo.crescendo.json' should exist" { + Get-Item $comboCrescendoFile | Should -Exist + } + + It "The file should have the correct count of commands" { + $comboJson.Commands.Count | Should -Be $expectedCount + } + + It "The command '' is found in the configuration" -TestCases $testCases { + param ( $file ) + $file | Should -BeIn $comboCommandNames + } + + It "Single file configuration should exist" { + Get-Item $singleCrescendoFile | Should -Exist + } + + It "The single file configuration should have the correct count of commands" { + $singleJson.Commands.Count | Should -Be 1 + } + + It "The single file configuration should have the correct command" { + $cmdName = $singleJson.Commands[0].Verb + "-" + $singleJson.Commands[0].Noun + $cmdName | Should -Be $singleCommandName + } + + It "If the file exists, an error should be thrown" { + { Export-CrescendoCommand -Command $commands -filename $comboCrescendoFile } | + Should -Throw "File '$comboCrescendoFile' already exists" + } + + It "Force should overwrite the file without error" { + Export-CrescendoCommand -Command $commands[0,1] -filename $comboCrescendoFile -Force + $comboCrescendoFile | Should -Exist + $json = Get-Content $comboCrescendoFile | ConvertFrom-Json + $json.Commands.Count | Should -Be 2 + } + + It "WhatIf should not create a file" { + $whatifFile = "TestDrive:whatif.crescendo.json" + $cmd = New-CrescendoCommand -Noun Get -Verb Thing -OriginalName notexist + Export-CrescendoCommand -Command $cmd -filename $whatifFile -WhatIf + $whatifFile | Should -Not -Exist + } + + } + + +} \ No newline at end of file From 97c51495bc51611f9c20122d2801681cf45b3d27 Mon Sep 17 00:00:00 2001 From: James Truher Date: Mon, 25 Jul 2022 13:41:58 -0700 Subject: [PATCH 2/2] Change to use out-file rather than set content. --- .../src/Microsoft.PowerShell.Crescendo.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1 b/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1 index 8b50b54..d7abc4b 100644 --- a/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1 +++ b/Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1 @@ -692,7 +692,7 @@ function Export-CrescendoCommand { $sOptions.IgnoreNullValues = $true $text = [System.Text.Json.JsonSerializer]::Serialize($multiConfiguration, $sOptions) if ($PSCmdlet.ShouldProcess($outputFile)) { - Set-Content -LiteralPath $outputFile -Value $text + Out-File -LiteralPath $outputFile -InputObject $text } } }