From 27687227a3fec59753aed51d2ad3fe909aa5dd27 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Wed, 24 Oct 2018 01:24:48 -0400 Subject: [PATCH 1/6] Fix #32 InitializeBuild and tests --- Source/Private/InitializeBuild.ps1 | 37 ++++++++++++++----------- Source/Public/Build-Module.ps1 | 10 +++++-- Tests/Private/InitializeBuild.Tests.ps1 | 18 +++++++++--- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/Source/Private/InitializeBuild.ps1 b/Source/Private/InitializeBuild.ps1 index 22156db..8a7adbb 100644 --- a/Source/Private/InitializeBuild.ps1 +++ b/Source/Private/InitializeBuild.ps1 @@ -22,15 +22,8 @@ function InitializeBuild { $Invocation = $(Get-Variable MyInvocation -Scope 1 -ValueOnly) ) # NOTE: This reads the parameter values from Build-Module! - $ParameterValues = @{} - foreach($parameter in $Invocation.MyCommand.Parameters.GetEnumerator()) { - $key = $parameter.Key - if($null -ne ($value = Get-Variable -Name $key -ValueOnly -ErrorAction Ignore )) { - if($value -ne ($null -as $parameter.Value.ParameterType)) { - $ParameterValues[$key] = $value - } - } - } + # BUG BUG: needs to prioritize build.psd1 values over build-module *defaults*, but user-provided parameters over build.psd1 values + Write-Debug "Initializing build variables" $ModuleSource = ResolveModuleSource $SourcePath Push-Location $ModuleSource -StackName Build-Module @@ -44,6 +37,20 @@ function InitializeBuild { # Read a build.psd1 configuration file for default parameter values $BuildInfo = Import-Metadata -Path (Join-Path $ModuleSource [Bb]uild.psd1) # Combine the defaults with parameter values + $ParameterValues = @{} + foreach ($parameter in $Invocation.MyCommand.Parameters.GetEnumerator()) { + $key = $parameter.Key + # set if it doesn't exist, overwrite if the value is bound as a parameter + if (!$BuildInfo.ContainsKey($key) -or $Invocation.BoundParameters.ContainsKey($key)) { + if ($null -ne ($value = Get-Variable -Name $key -ValueOnly -ErrorAction Ignore )) { + if ($value -ne ($null -as $parameter.Value.ParameterType)) { + Write-Debug " $key = $value" + $ParameterValues[$key] = $value + } + } + } + } + $BuildInfo = $BuildInfo | Update-Object $ParameterValues # Make sure the Path is set and points at the actual manifest @@ -63,14 +70,12 @@ function InitializeBuild { # Update the ModuleManifest with our build configuration $ModuleInfo = Update-Object -InputObject $ModuleInfo -UpdateObject $BuildInfo - # Ensure OutputDirectory + # Ensure the OutputDirectory makes sense if (!$ModuleInfo.OutputDirectory) { - $OutputRoot = if($OutputRoot = Split-Path $ModuleSource) { $OutputRoot } else { $ModuleSource} - $OutputDirectory = Join-Path $OutputRoot "$($ModuleInfo.Version)" - Add-Member -Input $ModuleInfo -Type NoteProperty -Name OutputDirectory -Value $OutputDirectory -Force - } elseif (![IO.Path]::IsPathRooted($ModuleInfo.OutputDirectory)) { - $OutputRoot = if($OutputRoot = Split-Path $ModuleSource) { $OutputRoot } else { $ModuleSource} - $OutputDirectory = Join-Path $OutputRoot $ModuleInfo.OutputDirectory + # The assumption here is that the "source" is a subdirectory of the project root (next to, for instance "tests" and "docs") + # If there's no output directory specified (or a relative path) we want to output within the project root, not the "source" + $OutputRoot = if($OutputRoot = Split-Path $ModuleSource) { $OutputRoot } else { $ModuleSource } + $OutputDirectory = Join-Path $OutputRoot "Output" Add-Member -Input $ModuleInfo -Type NoteProperty -Name OutputDirectory -Value $OutputDirectory -Force } diff --git a/Source/Public/Build-Module.ps1 b/Source/Public/Build-Module.ps1 index fbe2795..0dc44f1 100644 --- a/Source/Public/Build-Module.ps1 +++ b/Source/Public/Build-Module.ps1 @@ -55,9 +55,12 @@ function Build-Module { [string]$SourcePath = $(Get-Location -PSProvider FileSystem), # Where to build the module. - # Defaults to a version number folder, adjacent to the module folder + # Defaults to an \output folder, adjacent to the "SourcePath" folder [Alias("Destination")] - [string]$OutputDirectory, + [string]$OutputDirectory = "Output", + + # If set (true) adds a folder named after the version number to the OutputDirectory + [switch]$VersionedOutputDirectory, # Semantic version, like 1.0.3-beta01+sha.22c35ffff166f34addc49a3b80e622b543199cc5 # If the SemVer has metadata (after a +), then the full Semver will be added to the ReleaseNotes @@ -142,6 +145,9 @@ function Build-Module { # Push into the module source (it may be a subfolder) $ModuleInfo = InitializeBuild $SourcePath + Write-Progress "Building $($ModuleInfo.Name)" -Status "Use -Verbose for more information" + Write-Verbose "Building $($ModuleInfo.Name)" + # Output file names $OutputDirectory = $ModuleInfo.OutputDirectory $RootModule = Join-Path $OutputDirectory "$($ModuleInfo.Name).psm1" diff --git a/Tests/Private/InitializeBuild.Tests.ps1 b/Tests/Private/InitializeBuild.Tests.ps1 index 8c80110..cf29f88 100644 --- a/Tests/Private/InitializeBuild.Tests.ps1 +++ b/Tests/Private/InitializeBuild.Tests.ps1 @@ -2,7 +2,12 @@ Describe "InitializeBuild" { Mock ResolveModuleSource -ModuleName ModuleBuilder { $SourcePath } Mock ResolveModuleManifest -ModuleName ModuleBuilder { "TestDrive:\Source\MyModule.psd1" } Mock Push-Location -ModuleName ModuleBuilder {} - Mock Import-Metadata -ModuleName ModuleBuilder { @{Path = "MyModule.psd1"} } + Mock Import-Metadata -ModuleName ModuleBuilder { + @{ + Path = "MyModule.psd1" + SourceDirectories = "Classes", "Public" + } + } #Mock Update-Object -ModuleName ModuleBuilder { $InputObject } Mock Get-Variable -ParameterFilter { $Name -eq "MyInvocation" @@ -33,6 +38,8 @@ Describe "InitializeBuild" { New-Item "TestDrive:\Source\" -Type Directory $Result = InModuleScope -ModuleName ModuleBuilder { + [CmdletBinding()] + param( $SourceDirectories = @("Enum", "Classes", "Private", "Public") ) InitializeBuild -SourcePath TestDrive:\Source\ } @@ -63,7 +70,8 @@ Describe "InitializeBuild" { It "Returns the ModuleInfo combined with an OutputDirectory and Path" { $Result.ModuleBase | Should -be "TestDrive:\Source\" $Result.Path | Should -be "TestDrive:\Source\MyModule.psd1" - $Result.OutputDirectory | Should -be "TestDrive:\1.0.0" + $Result.OutputDirectory | Should -be "TestDrive:\Output" + $Result.SourceDirectories | Should -be @("Classes", "Public") } } @@ -105,7 +113,8 @@ Describe "InitializeBuild" { It "Treats the output path as relative to the (parent of the) ModuleSource" { $Result.ModuleBase | Should -be "TestDrive:\Source\" $Result.Path | Should -be "TestDrive:\Source\MyModule.psd1" - $Result.OutputDirectory | Should -be "TestDrive:\.\Output" + # Note that Build-Module will call ResolveOutputFolder with this, so the relative path here is ok + $Result.OutputDirectory | Should -be ".\Output" } } @@ -153,7 +162,8 @@ Describe "InitializeBuild" { It "Treats the output path as relative to the (parent of the) ModuleSource" { $Result.ModuleBase | Should -be "TestDrive:\" $Result.Path | Should -be "TestDrive:\MyModule.psd1" - $Result.OutputDirectory | Should -be "TestDrive:\.\Output" + # Note that Build-Module will call ResolveOutputFolder with this, so the relative path here is ok + $Result.OutputDirectory | Should -be ".\Output" } } } \ No newline at end of file From 72eb13ddc06587bc85a8aeb839516f02c7a80314 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Wed, 24 Oct 2018 01:26:27 -0400 Subject: [PATCH 2/6] Fix output path #31 --- Source/Private/InitializeBuild.ps1 | 12 ++--- Source/Private/ResolveOutputFolder.ps1 | 28 +++++++++++ Source/Public/Build-Module.ps1 | 19 ++++---- Source/build.psd1 | 2 + Tests/Private/ResolveOutputFolder.Tests.ps1 | 53 +++++++++++++++++++++ 5 files changed, 99 insertions(+), 15 deletions(-) create mode 100644 Source/Private/ResolveOutputFolder.ps1 create mode 100644 Tests/Private/ResolveOutputFolder.Tests.ps1 diff --git a/Source/Private/InitializeBuild.ps1 b/Source/Private/InitializeBuild.ps1 index 8a7adbb..8130ae3 100644 --- a/Source/Private/InitializeBuild.ps1 +++ b/Source/Private/InitializeBuild.ps1 @@ -70,13 +70,11 @@ function InitializeBuild { # Update the ModuleManifest with our build configuration $ModuleInfo = Update-Object -InputObject $ModuleInfo -UpdateObject $BuildInfo - # Ensure the OutputDirectory makes sense - if (!$ModuleInfo.OutputDirectory) { - # The assumption here is that the "source" is a subdirectory of the project root (next to, for instance "tests" and "docs") - # If there's no output directory specified (or a relative path) we want to output within the project root, not the "source" - $OutputRoot = if($OutputRoot = Split-Path $ModuleSource) { $OutputRoot } else { $ModuleSource } - $OutputDirectory = Join-Path $OutputRoot "Output" - Add-Member -Input $ModuleInfo -Type NoteProperty -Name OutputDirectory -Value $OutputDirectory -Force + # Ensure the OutputDirectory makes sense (it's never blank anymore) + if (![IO.Path]::IsPathRooted($ModuleInfo.OutputDirectory)) { + # Relative paths are relative to the build.psd1 now + $OutputDirectory = Join-Path $ModuleSource $ModuleInfo.OutputDirectory + $ModuleInfo.OutputDirectory = $OutputDirectory } $ModuleInfo diff --git a/Source/Private/ResolveOutputFolder.ps1 b/Source/Private/ResolveOutputFolder.ps1 new file mode 100644 index 0000000..7b13bb7 --- /dev/null +++ b/Source/Private/ResolveOutputFolder.ps1 @@ -0,0 +1,28 @@ +function ResolveOutputFolder { + [CmdletBinding()] + param( + # Where to build the module. + # Defaults to an \output folder, adjacent to the "SourcePath" folder + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [string]$OutputDirectory, + + # If set (true) adds a folder named after the version number to the OutputDirectory + [Parameter(ValueFromPipelineByPropertyName)] + [switch]$VersionedOutputDirectory, + + # specifies the module version for use in the output path if -VersionedOutputDirectory is true + [Parameter(ValueFromPipelineByPropertyName)] + [Alias("ModuleVersion")] + [string]$Version + ) + process { + Write-Verbose "Resolve OutputDirectory path: $OutputDirectory" + # Make sure the OutputDirectory exists (assumes we're in the module source directory) + $OutputDirectory = New-Item $OutputDirectory -ItemType Directory -Force | Convert-Path + if ($VersionedOutputDirectory -and $OutputDirectory.TrimEnd("/\") -notmatch "\d+\.\d+\.\d+$") { + $OutputDirectory = New-Item (Join-Path $OutputDirectory $Version) -ItemType Directory -Force | Convert-Path + Write-Verbose "Added ModuleVersion to OutputDirectory path: $OutputDirectory" + } + $OutputDirectory + } +} \ No newline at end of file diff --git a/Source/Public/Build-Module.ps1 b/Source/Public/Build-Module.ps1 index 0dc44f1..d9ebb12 100644 --- a/Source/Public/Build-Module.ps1 +++ b/Source/Public/Build-Module.ps1 @@ -55,9 +55,9 @@ function Build-Module { [string]$SourcePath = $(Get-Location -PSProvider FileSystem), # Where to build the module. - # Defaults to an \output folder, adjacent to the "SourcePath" folder + # Defaults to an ..\output folder (adjacent to the "SourcePath" folder) [Alias("Destination")] - [string]$OutputDirectory = "Output", + [string]$OutputDirectory = "..\Output", # If set (true) adds a folder named after the version number to the OutputDirectory [switch]$VersionedOutputDirectory, @@ -149,18 +149,21 @@ function Build-Module { Write-Verbose "Building $($ModuleInfo.Name)" # Output file names - $OutputDirectory = $ModuleInfo.OutputDirectory + $OutputDirectory = $ModuleInfo | ResolveOutputFolder $RootModule = Join-Path $OutputDirectory "$($ModuleInfo.Name).psm1" $OutputManifest = Join-Path $OutputDirectory "$($ModuleInfo.Name).psd1" - - Write-Progress "Building $($ModuleInfo.Name)" -Status "Use -Verbose for more information" - Write-Verbose "Building $($ModuleInfo.Name)" Write-Verbose "Output to: $OutputDirectory" + Wait-Debugger if ($Target -match "Clean") { Write-Verbose "Cleaning $OutputDirectory" - if (Test-Path $OutputDirectory) { - Remove-Item $OutputDirectory -Recurse -Force + if (Test-Path $OutputDirectory -PathType Leaf) { + throw "Unable to build. There is a file in the way at $OutputDirectory" + } + if (Test-Path $OutputDirectory -PathType Container) { + if (Get-ChildItem $OutputDirectory\*) { + Remove-Item $OutputDirectory\* -Recurse -Force + } } if ($Target -notmatch "Build") { return # No build, just cleaning diff --git a/Source/build.psd1 b/Source/build.psd1 index 0a75ab2..f50fb76 100644 --- a/Source/build.psd1 +++ b/Source/build.psd1 @@ -1,3 +1,5 @@ @{ Path = "ModuleBuilder.psd1" + OutputDirectory = "..\" + VersionedOutputDirectory = $true } \ No newline at end of file diff --git a/Tests/Private/ResolveOutputFolder.Tests.ps1 b/Tests/Private/ResolveOutputFolder.Tests.ps1 new file mode 100644 index 0000000..f7f8ad5 --- /dev/null +++ b/Tests/Private/ResolveOutputFolder.Tests.ps1 @@ -0,0 +1,53 @@ +Describe "ResolveOutputFolder" { + Import-Module ModuleBuilder -DisableNameChecking -Verbose:$False + + Context "Given an OutputDirectory only" { + + $Result = InModuleScope -ModuleName ModuleBuilder { + ResolveOutputFolder -OutputDirectory TestDrive:\Output + } + + It "Creates the Output directory" { + $Result | Should -Be "TestDrive:\Output" + $Result | Should -Exist + } + } + + Context "Given an OutputDirectory and ModuleVersion but no switch" { + + $Result = InModuleScope -ModuleName ModuleBuilder { + ResolveOutputFolder -OutputDirectory TestDrive:\Output -ModuleVersion "1.0.0" + } + + It "Creates the Output directory" { + "TestDrive:\Output" | Should -Exist + } + + It "Returns the Output directory" { + $Result | Should -Be "TestDrive:\Output" + } + + It "Does not creates children in Output" { + Get-ChildItem $Result | Should -BeNullOrEmpty + } + } + + Context "Given an OutputDirectory, ModuleVersion and switch" { + + $Result = InModuleScope -ModuleName ModuleBuilder { + ResolveOutputFolder -OutputDirectory TestDrive:\Output -ModuleVersion "1.0.0" -VersionedOutput + } + + It "Creates the Output directory" { + "TestDrive:\Output" | Should -Exist + } + + It "Creates the version directory" { + "TestDrive:\Output\1.0.0" | Should -Exist + } + + It "Returns the Output directory" { + $Result | Should -Be "TestDrive:\Output\1.0.0" + } + } +} From 46fcfd2066cfed8c93c8d5c9d8a16005664db347 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Tue, 30 Oct 2018 13:04:10 -0400 Subject: [PATCH 3/6] Allow builds which produce no psm1 --- Source/Private/SetModuleContent.ps1 | 1 + Source/Public/Build-Module.ps1 | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Private/SetModuleContent.ps1 b/Source/Private/SetModuleContent.ps1 index 4ceca3d..0594b1e 100644 --- a/Source/Private/SetModuleContent.ps1 +++ b/Source/Private/SetModuleContent.ps1 @@ -20,6 +20,7 @@ function SetModuleContent { # The FIRST and LAST items can be text content instead of file paths. [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias("PSPath", "FullName")] + [AllowEmptyCollection()] [string[]]$SourceFile, # The working directory (allows relative paths for other values) diff --git a/Source/Public/Build-Module.ps1 b/Source/Public/Build-Module.ps1 index d9ebb12..19f3ff9 100644 --- a/Source/Public/Build-Module.ps1 +++ b/Source/Public/Build-Module.ps1 @@ -154,7 +154,6 @@ function Build-Module { $OutputManifest = Join-Path $OutputDirectory "$($ModuleInfo.Name).psd1" Write-Verbose "Output to: $OutputDirectory" - Wait-Debugger if ($Target -match "Clean") { Write-Verbose "Cleaning $OutputDirectory" if (Test-Path $OutputDirectory -PathType Leaf) { From 82a1341fd9de09eed6009a7a15323caca6cc61c7 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 2 Nov 2018 02:13:35 -0400 Subject: [PATCH 4/6] Fix test cases --- Source/Private/InitializeBuild.ps1 | 2 +- Tests/Private/InitializeBuild.Tests.ps1 | 22 +++++++-- Tests/Private/ResolveOutputFolder.Tests.ps1 | 6 +-- Tests/Public/Build-Module.Tests.ps1 | 50 +++++++++++---------- 4 files changed, 48 insertions(+), 32 deletions(-) diff --git a/Source/Private/InitializeBuild.ps1 b/Source/Private/InitializeBuild.ps1 index 8130ae3..6f5d439 100644 --- a/Source/Private/InitializeBuild.ps1 +++ b/Source/Private/InitializeBuild.ps1 @@ -41,7 +41,7 @@ function InitializeBuild { foreach ($parameter in $Invocation.MyCommand.Parameters.GetEnumerator()) { $key = $parameter.Key # set if it doesn't exist, overwrite if the value is bound as a parameter - if (!$BuildInfo.ContainsKey($key) -or $Invocation.BoundParameters.ContainsKey($key)) { + if (!$BuildInfo.ContainsKey($key) -or ($Invocation.BoundParameters -and $Invocation.BoundParameters.ContainsKey($key))) { if ($null -ne ($value = Get-Variable -Name $key -ValueOnly -ErrorAction Ignore )) { if ($value -ne ($null -as $parameter.Value.ParameterType)) { Write-Debug " $key = $value" diff --git a/Tests/Private/InitializeBuild.Tests.ps1 b/Tests/Private/InitializeBuild.Tests.ps1 index cf29f88..ca1b8cf 100644 --- a/Tests/Private/InitializeBuild.Tests.ps1 +++ b/Tests/Private/InitializeBuild.Tests.ps1 @@ -19,6 +19,7 @@ Describe "InitializeBuild" { Target = @{ParameterType = "string"} SourcePath = @{ParameterType = "string"} SourceDirectories = @{ParameterType = "string[]"} + OutputDirectory = @{ParameterType = "string"} } } } @@ -39,7 +40,7 @@ Describe "InitializeBuild" { $Result = InModuleScope -ModuleName ModuleBuilder { [CmdletBinding()] - param( $SourceDirectories = @("Enum", "Classes", "Private", "Public") ) + param( $SourceDirectories = @("Enum", "Classes", "Private", "Public"), $OutputDirectory = "..\Output") InitializeBuild -SourcePath TestDrive:\Source\ } @@ -70,7 +71,10 @@ Describe "InitializeBuild" { It "Returns the ModuleInfo combined with an OutputDirectory and Path" { $Result.ModuleBase | Should -be "TestDrive:\Source\" $Result.Path | Should -be "TestDrive:\Source\MyModule.psd1" - $Result.OutputDirectory | Should -be "TestDrive:\Output" + + Push-Location TestDrive:\ + New-Item $Result.OutputDirectory -ItemType Directory -Force | Resolve-Path -Relative | Should -be ".\Output" + Pop-Location $Result.SourceDirectories | Should -be @("Classes", "Public") } } @@ -107,6 +111,9 @@ Describe "InitializeBuild" { } $Result = InModuleScope -ModuleName ModuleBuilder { + [CmdletBinding()] + param( $SourceDirectories = @("Enum", "Classes", "Private", "Public"), $OutputDirectory = "..\Output") + InitializeBuild -SourcePath TestDrive:\Source\ } @@ -114,7 +121,9 @@ Describe "InitializeBuild" { $Result.ModuleBase | Should -be "TestDrive:\Source\" $Result.Path | Should -be "TestDrive:\Source\MyModule.psd1" # Note that Build-Module will call ResolveOutputFolder with this, so the relative path here is ok - $Result.OutputDirectory | Should -be ".\Output" + Push-Location TestDrive:\ + New-Item $Result.OutputDirectory -ItemType Directory -Force | Resolve-Path -Relative | Should -be ".\Source\Output" + Pop-Location } } @@ -156,6 +165,9 @@ Describe "InitializeBuild" { } } $Result = InModuleScope -ModuleName ModuleBuilder { + [CmdletBinding()] + param( $SourceDirectories = @("Enum", "Classes", "Private", "Public"), $OutputDirectory = "..\Output") + InitializeBuild -SourcePath TestDrive:\ } @@ -163,7 +175,9 @@ Describe "InitializeBuild" { $Result.ModuleBase | Should -be "TestDrive:\" $Result.Path | Should -be "TestDrive:\MyModule.psd1" # Note that Build-Module will call ResolveOutputFolder with this, so the relative path here is ok - $Result.OutputDirectory | Should -be ".\Output" + Push-Location TestDrive:\ + New-Item $Result.OutputDirectory -ItemType Directory -Force | Resolve-Path -Relative | Should -be ".\Output" + Pop-Location } } } \ No newline at end of file diff --git a/Tests/Private/ResolveOutputFolder.Tests.ps1 b/Tests/Private/ResolveOutputFolder.Tests.ps1 index f7f8ad5..a1c4333 100644 --- a/Tests/Private/ResolveOutputFolder.Tests.ps1 +++ b/Tests/Private/ResolveOutputFolder.Tests.ps1 @@ -8,7 +8,7 @@ Describe "ResolveOutputFolder" { } It "Creates the Output directory" { - $Result | Should -Be "TestDrive:\Output" + $Result | Should -Be (Convert-Path "TestDrive:\Output") $Result | Should -Exist } } @@ -24,7 +24,7 @@ Describe "ResolveOutputFolder" { } It "Returns the Output directory" { - $Result | Should -Be "TestDrive:\Output" + $Result | Should -Be (Convert-Path "TestDrive:\Output") } It "Does not creates children in Output" { @@ -47,7 +47,7 @@ Describe "ResolveOutputFolder" { } It "Returns the Output directory" { - $Result | Should -Be "TestDrive:\Output\1.0.0" + $Result | Should -Be (Convert-Path "TestDrive:\Output\1.0.0") } } } diff --git a/Tests/Public/Build-Module.Tests.ps1 b/Tests/Public/Build-Module.Tests.ps1 index 0f1bde5..69c5962 100644 --- a/Tests/Public/Build-Module.Tests.ps1 +++ b/Tests/Public/Build-Module.Tests.ps1 @@ -64,7 +64,7 @@ Describe "Build-Module" { Mock Update-Metadata -ModuleName ModuleBuilder {} Mock InitializeBuild -ModuleName ModuleBuilder { # These are actually all the values that we need - @{ + [PSCustomObject]@{ OutputDirectory = "TestDrive:\1.0.0" Name = "MyModule" ModuleBase = "TestDrive:\MyModule\" @@ -74,8 +74,14 @@ Describe "Build-Module" { } } + Mock New-Item { [IO.FileInfo]"TestDrive:\1.0.0" } -Parameter { + $Path -eq "TestDrive:\1.0.0" -and + $ItemType -eq "Directory" -and + $Force -eq $true + } -ModuleName ModuleBuilder + Mock Test-Path {$True} -Parameter {$Path -eq "TestDrive:\1.0.0"} -ModuleName ModuleBuilder - Mock Remove-Item {} -Parameter {$Path -eq "TestDrive:\1.0.0"} -ModuleName ModuleBuilder + Mock Remove-Item {} -Parameter {$Path.StartsWith((Convert-Path "TestDrive:\1.0.0"))} -ModuleName ModuleBuilder Mock Set-Location {} -ModuleName ModuleBuilder Mock Copy-Item {} -ModuleName ModuleBuilder @@ -83,11 +89,6 @@ Describe "Build-Module" { [IO.FileInfo]$(Join-Path $(Convert-Path "TestDrive:\") "MyModule\Public\Get-MyInfo.ps1") } -ModuleName ModuleBuilder - Mock New-Item {} -Parameter { - $Path -eq "TestDrive:\1.0.0" -and - $ItemType -eq "Directory" -and - $Force -eq $true - } -ModuleName ModuleBuilder try { Build-Module @@ -133,7 +134,7 @@ Describe "Build-Module" { Mock Update-Metadata -ModuleName ModuleBuilder {} Mock InitializeBuild -ModuleName ModuleBuilder { # These are actually all the values that we need - @{ + [PSCustomObject]@{ OutputDirectory = "TestDrive:\1.0.0" Name = "MyModule" ModuleBase = "TestDrive:\MyModule\" @@ -143,6 +144,12 @@ Describe "Build-Module" { } } + Mock New-Item { [IO.FileInfo]"TestDrive:\1.0.0" } -Parameter { + $Path -eq "TestDrive:\1.0.0" -and + $ItemType -eq "Directory" -and + $Force -eq $true + } -ModuleName ModuleBuilder + Mock Test-Path {$True} -Parameter {$Path -eq "TestDrive:\1.0.0"} -ModuleName ModuleBuilder Mock Remove-Item {} -Parameter {$Path -eq "TestDrive:\1.0.0"} -ModuleName ModuleBuilder Mock Set-Location {} -ModuleName ModuleBuilder @@ -156,12 +163,6 @@ Describe "Build-Module" { [PSCustomObject]@{ LastWriteTime = Get-Date } } -ModuleName ModuleBuilder - Mock New-Item {} -Parameter { - $Path -eq "TestDrive:\1.0.0" -and - $ItemType -eq "Directory" -and - $Force -eq $true - } -ModuleName ModuleBuilder - try { Build-Module -Target Build } finally { @@ -177,8 +178,8 @@ Describe "Build-Module" { Assert-MockCalled Get-Item -ModuleName ModuleBuilder -Times 1 } - It "Should not (re)create the OutputDirectory" { - Assert-MockCalled New-Item -ModuleName ModuleBuilder -Times 0 + It "Should always (re)create the OutputDirectory" { + Assert-MockCalled New-Item -ModuleName ModuleBuilder -Times 1 } It "Should not rebuild the source files" { @@ -195,9 +196,10 @@ Describe "Build-Module" { Mock SetModuleContent -ModuleName ModuleBuilder {} Mock Update-Metadata -ModuleName ModuleBuilder {} + Mock InitializeBuild -ModuleName ModuleBuilder { # These are actually all the values that we need - @{ + [PSCustomObject]@{ OutputDirectory = "TestDrive:\$Version" Name = "MyModule" ModuleBase = "TestDrive:\MyModule\" @@ -207,8 +209,14 @@ Describe "Build-Module" { } } + Mock New-Item { [IO.FileInfo]"TestDrive:\$ExpectedVersion" } -Parameter { + $Path -eq "TestDrive:\$ExpectedVersion" -and + $ItemType -eq "Directory" -and + $Force -eq $true + } -ModuleName ModuleBuilder + Mock Test-Path {$True} -Parameter {$Path -eq "TestDrive:\$ExpectedVersion"} -ModuleName ModuleBuilder - Mock Remove-Item {} -Parameter {$Path -eq "TestDrive:\$ExpectedVersion"} -ModuleName ModuleBuilder + Mock Remove-Item {} -Parameter {$Path.StartsWith((Convert-Path "TestDrive:\$ExpectedVersion"))} -ModuleName ModuleBuilder Mock Set-Location {} -ModuleName ModuleBuilder Mock Copy-Item {} -ModuleName ModuleBuilder # Release notes @@ -221,12 +229,6 @@ Describe "Build-Module" { [IO.FileInfo]$(Join-Path $(Convert-Path "TestDrive:\") "MyModule\Public\Get-MyInfo.ps1") } -ModuleName ModuleBuilder - Mock New-Item {} -Parameter { - $Path -eq "TestDrive:\$ExpectedVersion" -and - $ItemType -eq "Directory" -and - $Force -eq $true - } -ModuleName ModuleBuilder - try { Build-Module -SemVer $SemVer } catch { From 8ff455fd6d01945f77b1d8cb7af6502320b63a0b Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Wed, 7 Nov 2018 01:43:44 -0500 Subject: [PATCH 5/6] Update tests, validate missing Prerelease better --- Source/Public/Build-Module.ps1 | 21 +++-- Tests/Public/Build-Module.Tests.ps1 | 117 ++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 8 deletions(-) diff --git a/Source/Public/Build-Module.ps1 b/Source/Public/Build-Module.ps1 index 19f3ff9..ab88c3a 100644 --- a/Source/Public/Build-Module.ps1 +++ b/Source/Public/Build-Module.ps1 @@ -134,12 +134,12 @@ function Build-Module { # BEFORE we InitializeBuild we need to "fix" the version if($PSCmdlet.ParameterSetName -ne "SemanticVersion") { Write-Verbose "Calculate the Semantic Version from the $Version - $Prerelease + $BuildMetadata" - $SemVer = $Version + $SemVer = "$Version" if($Prerelease) { - $SemVer = $Version + '-' + $Prerelease + $SemVer = "$Version-$Prerelease" } if($BuildMetadata) { - $SemVer = $SemVer + '+' + $BuildMetadata + $SemVer = "$SemVer+$BuildMetadata" } } @@ -215,11 +215,16 @@ function Build-Module { Write-Warning "Failed to update version to $Version. $_" } - if ($Prerelease) { - Write-Verbose "Update Manifest at $OutputManifest with Prerelease: $Prerelease" - Update-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.Prerelease -Value $Prerelease - } else { - Update-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.Prerelease -Value "" + if ($null -ne (Get-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.Prerelease -ErrorAction SilentlyContinue)) { + if ($Prerelease) { + Write-Verbose "Update Manifest at $OutputManifest with Prerelease: $Prerelease" + Update-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.Prerelease -Value $Prerelease + } else { + Update-Metadata -Path $OutputManifest -PropertyName PrivateData.PSData.Prerelease -Value "" + } + } elseif($Prerelease) { + Write-Warning ("Cannot set Prerelease in module manifest. Add an empty Prerelease to your module manifest, like:`n" + + ' PrivateData = @{ PSData = @{ Prerelease = "" } }') } if ($BuildMetadata) { diff --git a/Tests/Public/Build-Module.Tests.ps1 b/Tests/Public/Build-Module.Tests.ps1 index 69c5962..991fab8 100644 --- a/Tests/Public/Build-Module.Tests.ps1 +++ b/Tests/Public/Build-Module.Tests.ps1 @@ -296,4 +296,121 @@ Describe "Build-Module" { Pop-Location -StackName BuildModuleTest } + + Context "Setting the version and pre-release" { + # $SemVer = "1.0.0-beta03+sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11" + $SemVer = @{ + Version = "1.0.0" + Prerelease = "beta03" + BuildMetadata = "Sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11" + } + $global:ExpectedVersion = "1.0.0" + Push-Location TestDrive:\ -StackName BuildModuleTest + New-Item -ItemType Directory -Path TestDrive:\MyModule\ -Force + New-Item -ItemType Directory -Path "TestDrive:\$ExpectedVersion\" -Force + + Mock SetModuleContent -ModuleName ModuleBuilder {} + Mock Update-Metadata -ModuleName ModuleBuilder {} + + Mock InitializeBuild -ModuleName ModuleBuilder { + # These are actually all the values that we need + [PSCustomObject]@{ + OutputDirectory = "TestDrive:\$Version" + Name = "MyModule" + ModuleBase = "TestDrive:\MyModule\" + CopyDirectories = @() + Encoding = "UTF8" + PublicFilter = "Public\*.ps1" + } + } + + Mock New-Item { [IO.FileInfo]"TestDrive:\$ExpectedVersion" } -Parameter { + $Path -eq "TestDrive:\$ExpectedVersion" -and + $ItemType -eq "Directory" -and + $Force -eq $true + } -ModuleName ModuleBuilder + + Mock Test-Path {$True} -Parameter {$Path -eq "TestDrive:\$ExpectedVersion"} -ModuleName ModuleBuilder + Mock Remove-Item {} -Parameter {$Path.StartsWith((Convert-Path "TestDrive:\$ExpectedVersion"))} -ModuleName ModuleBuilder + Mock Set-Location {} -ModuleName ModuleBuilder + Mock Copy-Item {} -ModuleName ModuleBuilder + # Release notes + Mock Get-Metadata { "First Release" } -ModuleName ModuleBuilder + Mock Join-Path { + [IO.Path]::Combine($Path, $ChildPath) + } -ModuleName ModuleBuilder + + Mock Get-ChildItem { + [IO.FileInfo]$(Join-Path $(Convert-Path "TestDrive:\") "MyModule\Public\Get-MyInfo.ps1") + } -ModuleName ModuleBuilder + + try { + Build-Module @SemVer + } catch { + Pop-Location -StackName BuildModuleTest + throw + } + + It "Should build to an output folder with the simple version." { + Assert-MockCalled Remove-Item -ModuleName ModuleBuilder + Assert-MockCalled New-Item -ModuleName ModuleBuilder + } + + It "Should update the module version to the simple version." { + Assert-MockCalled Update-Metadata -ModuleName ModuleBuilder -ParameterFilter { + $PropertyName -eq "ModuleVersion" -and $Value -eq $ExpectedVersion + } + } + It "Should update the module pre-release version" { + Assert-MockCalled Update-Metadata -ModuleName ModuleBuilder -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.Prerelease" -and $Value -eq "beta03" + } + } + It "When there are simple release notes, it should insert a line with the module name and full semver" { + Assert-MockCalled Update-Metadata -ModuleName ModuleBuilder -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and + $Value -eq "MyModule v$($SemVer.Version)-$($SemVer.Prerelease)+$($SemVer.BuildMetadata)`nFirst Release" + } + } + + It "When there's no release notes, it should insert the module name and full semver" { + # If there's no release notes, but it was left uncommented + Mock Get-Metadata { "" } -ModuleName ModuleBuilder + + try { + Build-Module @SemVer + } catch { + Pop-Location -StackName BuildModuleTest + throw + } + + Assert-MockCalled Update-Metadata -ModuleName ModuleBuilder -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and + $Value -eq "MyModule v$($SemVer.Version)-$($SemVer.Prerelease)+$($SemVer.BuildMetadata)" + } + } + + It "When there's a prefix empty line, it should insert the module name and full semver the same way" { + # If there's no release notes, but it was left uncommented + Mock Get-Metadata { " + Multi-line Release Notes + With a prefix carriage return" } -ModuleName ModuleBuilder + + try { + Build-Module @SemVer + } catch { + Pop-Location -StackName BuildModuleTest + throw + } + + Assert-MockCalled Update-Metadata -ModuleName ModuleBuilder -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq " + MyModule v$($SemVer.Version)-$($SemVer.Prerelease)+$($SemVer.BuildMetadata) + Multi-line Release Notes + With a prefix carriage return" + } + } + + Pop-Location -StackName BuildModuleTest + } } \ No newline at end of file From 680b5f9266f02184c5fc18bb4b3a4b6432f5c8cb Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Wed, 7 Nov 2018 23:49:48 -0500 Subject: [PATCH 6/6] Fix tests for WindowsPowerShell --- Tests/Public/Build-Module.Tests.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/Public/Build-Module.Tests.ps1 b/Tests/Public/Build-Module.Tests.ps1 index 991fab8..4d2b5ce 100644 --- a/Tests/Public/Build-Module.Tests.ps1 +++ b/Tests/Public/Build-Module.Tests.ps1 @@ -74,7 +74,7 @@ Describe "Build-Module" { } } - Mock New-Item { [IO.FileInfo]"TestDrive:\1.0.0" } -Parameter { + Mock New-Item { [IO.FileInfo](Join-Path (Convert-Path "TestDrive:\") "1.0.0") } -Parameter { $Path -eq "TestDrive:\1.0.0" -and $ItemType -eq "Directory" -and $Force -eq $true @@ -144,7 +144,7 @@ Describe "Build-Module" { } } - Mock New-Item { [IO.FileInfo]"TestDrive:\1.0.0" } -Parameter { + Mock New-Item { [IO.FileInfo](Join-Path (Convert-Path "TestDrive:\") "1.0.0")} -Parameter { $Path -eq "TestDrive:\1.0.0" -and $ItemType -eq "Directory" -and $Force -eq $true @@ -209,7 +209,7 @@ Describe "Build-Module" { } } - Mock New-Item { [IO.FileInfo]"TestDrive:\$ExpectedVersion" } -Parameter { + Mock New-Item { [IO.FileInfo](Join-Path (Convert-Path "TestDrive:\") $ExpectedVersion) } -Parameter { $Path -eq "TestDrive:\$ExpectedVersion" -and $ItemType -eq "Directory" -and $Force -eq $true @@ -324,7 +324,7 @@ Describe "Build-Module" { } } - Mock New-Item { [IO.FileInfo]"TestDrive:\$ExpectedVersion" } -Parameter { + Mock New-Item { [IO.FileInfo](Join-Path (Convert-Path "TestDrive:\") $ExpectedVersion) } -Parameter { $Path -eq "TestDrive:\$ExpectedVersion" -and $ItemType -eq "Directory" -and $Force -eq $true