From 581d4ca4627c03d5e6eee43f547faaedb0bf2d68 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Thu, 6 Feb 2025 00:47:30 -0500 Subject: [PATCH 01/18] Switch to ModuleFast --- Modules.required.psd1 | 9 +++++++++ RequiredModules.psd1 | 10 ---------- 2 files changed, 9 insertions(+), 10 deletions(-) create mode 100644 Modules.required.psd1 delete mode 100644 RequiredModules.psd1 diff --git a/Modules.required.psd1 b/Modules.required.psd1 new file mode 100644 index 0000000..6001b64 --- /dev/null +++ b/Modules.required.psd1 @@ -0,0 +1,9 @@ +# https://github.com/marketplace/actions/modulefast +@{ + Configuration = ":[1.5.0, 2.0)" + Metadata = ":[1.5.1, 2.0)" + Pester = ":[4.10.1, 5.0)" + ModuleBuilder = ":[3.0.0, 4.0)" + PSScriptAnalyzer = ":[1.21.0, 2.0)" + InvokeBuild = ":[5.10.4, 6.0)" +} diff --git a/RequiredModules.psd1 b/RequiredModules.psd1 deleted file mode 100644 index 109c593..0000000 --- a/RequiredModules.psd1 +++ /dev/null @@ -1,10 +0,0 @@ -# NOTE: follow nuget syntax for versions: https://docs.microsoft.com/en-us/nuget/reference/package-versioning#version-ranges-and-wildcards -@{ - Configuration = "[1.5.0, 2.0)" - Metadata = "[1.5.1, 2.0)" - Pester = "[4.10.1,5.0)" - ModuleBuilder = "[3.0.0, 4.0)" - PSScriptAnalyzer = "[1.21.0,2.0)" - PowerShellGet = "2.0.4" - InvokeBuild = "[5.10.4,6.0)" -} From 0642f33cdeccb2f0a55ee809a4c51bf1db152353 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Mon, 5 Aug 2024 23:10:00 -0400 Subject: [PATCH 02/18] Rewrite the ReadMe. --- ReadMe.md | 64 ++++++++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 0bf11ce..ccf922c 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,66 +1,59 @@ -# The Module Builder Project +# Module Builder - Simplifying Authoring PowerShell (Script) Modules -This project is an attempt by a group of PowerShell MVPs and module authors to: +This module makes it easier to break up your module source into several files for organization, even though you need to ship it as one big psm1 file. -1. Build a common set of [tools for module authoring](#whats-in-the-module-so-far) -2. Encourage a common pattern for [organizing PowerShell module projects](#organizing-your-module) -3. Promote best practices for authoring functions and modules +There are still some issues in Visual Studio Code and PSScriptAnalyzer when authoring modules as multiple files, but if you want to break up your module into multiple files for organization and maintainability, and still need to ship it as one big file for performance and compatibility reasons, this module is for you. -In short, we want to make it easier for people to write great code and produce great modules. +## You should ship your module as one big file! -In service of this goal, we intend to produce: +PowerShell expects script modules to be all in one file. A module in a single `.psm1` script file results in the best performance, natural "script" scope, and full support for classes and "using" statements. -1. Guidance on using the best of the existing tools: dotnet, Pester, PSDepends, etc. -2. Module templates demonstrating best practices for organization -3. Function templates demonstrating best practices for common parameters and error handling -4. ModuleBuilder module - a set of tools for building modules following these best practices +The single file option is particularly important for performance if you are signing your module (or your end users want to be able to code-sign it), because each file's signature must be checked, and each certificate must be checked against CRLs. It's also critical if you are using PowerShell classes (the `using` statement only supports classes defined in the root psm1 file). It's basically required if you want to use module-scope variables to share state between functions in your module. -## The ModuleBuilder module +## What's in the ModuleBuilder module so far? -This module is the main output of the project, consisting of one primary command: `Build-Module` and a few helpers to translate input and output line numbers. It represents the collaboration of several module authors who had each written their own version of these tools for themselves, and have now decided to collaborate on creating a shared tool set. We are each using the patterns and tools that are represented here, and are committed to helping others to succeed at doing so. +This module is the main output of the project, consisting of one primary command: `Build-Module` and a few helpers to translate input and output line numbers so you can trouble-shoot error messages from your module against the source files. -### What's in the module so far - -#### Build-Module +### Build-Module Builds a script module from a source project containing one file per function in `Public` and `Private` folders. The `Build-Module` command is a build task for PowerShell script modules that supports [incremental builds](https://docs.microsoft.com/en-us/visualstudio/msbuild/incremental-builds). -#### Convert-CodeCoverage +### Convert-CodeCoverage Takes the output from `Invoke-Pester -Passthru` run against the build output, and converts the code coverage report to the source lines. -#### ConvertFrom-SourceLineNumber +### ConvertFrom-SourceLineNumber Converts a line number from a source file to the corresponding line number in the built output. -#### ConvertTo-SourceLineNumber +### ConvertTo-SourceLineNumber Converts a line number from the built output to the corresponding file and line number in the source. -#### Convert-Breakpoint +### Convert-Breakpoint Convert any breakpoints on source files to module files _and vice-versa_. ## Organizing Your Module -For best results, you need to organize your module project similarly to how this project is organized. It doesn't have to be exact, because nearly all of our conventions can be overriden, but the module _is_ opinionated, so if you follow the conventions, it should feel wonderfully automatic. +For best results, you need to organize your module project similarly to how this project is organized. It doesn't have to be exact, because you can override nearly all of our conventions, but the module _is_ opinionated, so if you follow the conventions, it should feel wonderfully automatic. -1. Create a `source` folder with a `build.psd1` file and your module manifest in it +1. Create a `source` (or `src`) folder with a `build.psd1` file and your module manifest in it 2. In the `build.psd1` specify the relative **Path** to your module's manifest, e.g. `@{ Path = "ModuleBuilder.psd1" }` 3. In your manifest, make sure a few values are not commented out. You can leave them empty, because they'll be overwritten: - `FunctionsToExport` will be updated with the _file names_ that match the `PublicFilter` - `AliasesToExport` will be updated with the values from `[Alias()]` attributes on commands - `Prerelease` and `ReleaseNotes` in the `PSData` hash table in `PrivateData` -Once you start working on the module, you'll create sub-folders in source, and put script files in them with only **one** function in each file. You should name the files with _the same name_ as the function that's in them -- especially in the public folder, where we use the file name (without the extension) to determine the exported functions. +Once you start working on the module, you'll create sub-folders in source, and put script files in them with only **one** function in each file. You should name the files with _the same name_ as the function that's in them -- especially in the `source\public` folder, where we use the file names to determine the exported functions. -1. By convention, use folders named "Classes" (and/or "Enum"), "Private", and "Public" -2. By convention, the functions in "Public" will be exported from the module (you can override the `PublicFilter`) +1. By convention, use SourceDirectories named "Classes" (and/or "Enum"), "Private", and "Public" +2. By convention, the PublicFilter is all of the functions in the "Public" directory. 3. To force classes to be in a certain order, you can prefix their file names with numbers, like `01-User.ps1` -There are a _lot_ of conventions in `Build-Module`, expressed as default values for its parameters. These defaults are documented in the help for Build-Module. You can override any parameter defaults by adding keys to the `build.psd1` file with your preferences, or by passing the values to the `Build-Module` command directly. +There are a _lot_ of conventions in `Build-Module`, expressed as default values for its parameters. These defaults are documented in the help for Build-Module, and you can override any parameter defaults by adding keys to the `build.psd1` file with your preferences, or by passing the values to the `Build-Module` command directly. So in other words, you can override the default `SourceDirectories` and `PublicFilters` (and any others) by adding them to the `build.psd1` file. ## A note on build tools @@ -102,23 +95,18 @@ cd ModuleBuilder This _should_ work on Windows, Linux, or MacOS. I test the build process on Windows, and in CI we run it in the Linux containers via earthly, and we run the full Pester test suit on all three platforms. -#### The old-fashioned way +## Most recent releases -You _can_ build the module without any additional tools (and without running tests), by using the old `build.ps1` bootstrap script. You'll need to pass a version number in, and if you have [Pester](https://github.com/Pester/Pester) and [PSScriptAnalyzer](https://github.com/PowerShell/PSScriptAnalyzer), you can run the 'test.ps1' script to run the tests. +### 3.2.0 - Script Generators -```powershell -./build.ps1 -Semver 5.0.0-prerelease | Split-Path | Import-Module -Force -./test.ps1 -``` +Script Generators let developers modify their module's source code as it is being built. A generator can create new script functions on the fly, such that whole functions are added to the built module. A generator can also inject boilerplate code like error handling, logging, tracing and timing at build-time, so this code can be maintained once, and be automatically added (and updated) in all the places where it's needed when the module is built. The generators run during the build and can inspect existing functions, data files, or even data from an API, and produce code that is output into the module (and clearly marked as generated). + +### 3.1.0 - Supports help outside the top of script commands -## Changelog +Starting with this release, ModuleBuilder adds an empty line between the `#REGION filename` comment lines it injects, and the content of the files. This allows PowerShell to recognize help comments that are at the top of each file (outside the function block). -### 3.0.0 - Now with better alias support +### 3.0.0 - Better alias support Starting with this release, ModuleBuilder will automatically export aliases from `New-Alias` and `Set-Alias` as well as the `[Alias()]` attributes on commands. This is (probably not) a breaking change, but because it can change the aliases exported by existing modules that use ModuleBuilder, I've bumped the major version number as a precaution (if you're reading this, mission accomplished). Additionally, the `Build-Module` command now _explicitly sorts_ the source files into alphabetical order, to ensure consistent behavior regardless of the native order of the underlying file system. This is technically also a breaking change, but it's unlikely to affect anyone except the people whose builds didn't work on non-Windows systems because of the previous behavior. - -### 3.1.0 - Now allows help outside the top of script commands - -Starting with this release, ModuleBuilder adds an empty line between the `#REGION filename` comment lines it injects, and the content of the files. This allows PowerShell to recognize help comments that are at the top of each file (outside the function block). From 3f148be5481e0b63fc944eab2dda98dca5acc4cb Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Thu, 6 Feb 2025 20:25:08 -0500 Subject: [PATCH 03/18] Switch to ModuleFast --- .github/workflows/dotnet-tools.json | 12 ++++++++++++ Earthfile | 4 ++-- ReadMe.md | 2 +- Modules.required.psd1 => build.requires.psd1 | 0 4 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/dotnet-tools.json rename Modules.required.psd1 => build.requires.psd1 (100%) diff --git a/.github/workflows/dotnet-tools.json b/.github/workflows/dotnet-tools.json new file mode 100644 index 0000000..c11b918 --- /dev/null +++ b/.github/workflows/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "gitversion.tool": { + "version": "5.6.0", + "commands": [ + "dotnet-gitversion" + ] + } + } +} diff --git a/Earthfile b/Earthfile index be47ddf..2a0eae7 100644 --- a/Earthfile +++ b/Earthfile @@ -25,9 +25,9 @@ worker: COPY tasks+tasks/* /Tasks # Dealing with dependencies first allows docker to cache packages for us # So the dependency cach only re-builds when you add a new dependency - COPY RequiredModules.psd1 . + COPY build.requires.psd1 . # COPY *.csproj . - RUN ["pwsh", "-File", "/Tasks/_Bootstrap.ps1", "-RequiredModulesPath", "RequiredModules.psd1"] + RUN ["pwsh", "-File", "/Tasks/_Bootstrap.ps1", "-RequiresPath", "build.requires.psd1"] build: FROM +worker diff --git a/ReadMe.md b/ReadMe.md index ccf922c..156d7bf 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -86,7 +86,7 @@ git clone https://github.com/PoshCode/ModuleBuilder.git git clone https://github.com/PoshCode/Tasks.git ``` -Once you've cloned both, the `Build.build.ps1` script will use the shared [Tasks\_Bootstrap.ps1](https://github.com/PoshCode/Tasks/blob/main/_Bootstrap.ps1) to install the other dependencies (see [RequiredModules.psd1](https://github.com/PoshCode/ModuleBuilder/blob/main/RequiredModules.psd1)), including [dotnet](https://dot.net), and will use [Invoke-Build](https://github.com/nightroman/Invoke-Build) and [Pester](https://github.com/Pester/Pester) to build and test the module. +Once you've cloned both, the `Build.build.ps1` script will use the shared [Tasks\_Bootstrap.ps1](https://github.com/PoshCode/Tasks/blob/main/_Bootstrap.ps1) to install the other dependencies (see [build.requires.psd1](https://github.com/PoshCode/ModuleBuilder/blob/main/build.requires.psd1)), including [dotnet](https://dot.net), and will use [Invoke-Build](https://github.com/nightroman/Invoke-Build) and [Pester](https://github.com/Pester/Pester) to build and test the module. ```powershell cd ModuleBuilder diff --git a/Modules.required.psd1 b/build.requires.psd1 similarity index 100% rename from Modules.required.psd1 rename to build.requires.psd1 From 8618f5e68b7697d9b41ac554b639b04c4da26939 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Thu, 6 Feb 2025 20:26:40 -0500 Subject: [PATCH 04/18] Switch to zyborg/pester-tests-report --- .github/workflows/build.yml | 43 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 94cb4da..d4634eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,11 +52,11 @@ jobs: with: name: PesterTests path: ${{github.workspace}}/Tests - - name: Upload RequiredModules.psd1 + - name: Upload build.requires.psd1 uses: actions/upload-artifact@v4 with: - name: RequiredModules - path: ${{github.workspace}}/RequiredModules.psd1 + name: build.requires.psd1 + path: ${{github.workspace}}/build.requires.psd1 test: needs: build runs-on: ${{ matrix.os }} @@ -75,23 +75,26 @@ jobs: with: name: PesterTests path: PesterTests - - name: Download RequiredModules + - name: Download build.requires.psd1 uses: actions/download-artifact@v4 with: - name: RequiredModules - - - uses: PoshCode/Actions/install-requiredmodules@v1 - - uses: PoshCode/Actions/pester@v1 - with: - codeCoveragePath: Modules/ModuleBuilder - moduleUnderTest: ModuleBuilder - additionalModulePaths: ${{github.workspace}}/Modules - - name: Publish Test Results - uses: zyborg/dotnet-tests-report@v1 + name: build.requires.psd1 + - name: ⚡ Install PowerShell Modules + uses: JustinGrote/ModuleFast-action + - name: Invoke Pester Tests + id: pester + uses: zyborg/pester-tests-report@v1 with: - test_results_path: results.xml - - name: Upload Results - uses: actions/upload-artifact@v2 - with: - name: Pester Results - path: ${{github.workspace}}/*.xml + # include_paths: tests + # exclude_paths: tests/powershell1,tests/powershell2 + # exclude_tags: skip_ci + report_name: module_tests + report_title: My Module Tests + github_token: ${{ secrets.GITHUB_TOKEN }} + - name: dump test results + shell: pwsh + run: | + Write-Host 'Total Tests Executed...: ${{ steps.pester.outputs.total_count }}' + Write-Host 'Total Tests PASSED.....: ${{ steps.pester.outputs.passed_count }}' + Write-Host 'Total Tests FAILED.....: ${{ steps.pester.outputs.failed_count }}' + From e7c84285a341cffb7d0a4bac9b17108e23dfccd7 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Thu, 6 Feb 2025 20:30:07 -0500 Subject: [PATCH 05/18] Try modulefast action --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4634eb..e39e38e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -80,7 +80,7 @@ jobs: with: name: build.requires.psd1 - name: ⚡ Install PowerShell Modules - uses: JustinGrote/ModuleFast-action + uses: JustinGrote/ModuleFast-action@v0.0.1 - name: Invoke Pester Tests id: pester uses: zyborg/pester-tests-report@v1 From b73651dfe2f2689d06d2b476abc0b0a0f4ba4d4b Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Thu, 6 Feb 2025 20:40:14 -0500 Subject: [PATCH 06/18] Replace GitVersion.yaml with a more forgiving version --- GitVersion.yml | 53 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/GitVersion.yml b/GitVersion.yml index c9554fa..882cb9f 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,19 +1,46 @@ -mode: Mainline -assembly-versioning-format: '{Major}.{Minor}.{Patch}.{env:BUILDCOUNT ?? 0}' -assembly-informational-format: '{NuGetVersionV2}+Build.{env:BUILDCOUNT ?? 0}.Date.{CommitDate}.Branch.{env:SAFEBRANCHNAME ?? unknown}.Sha.{Sha}' -major-version-bump-message: '\+?semver:\s?(breaking|major)' -minor-version-bump-message: '\+?semver:\s?(feature|minor)' -patch-version-bump-message: '\+?semver:\s?(fix|patch)' -no-bump-message: '\+?semver:\s?(none|skip)' +mode: mainline +commit-date-format: "yyyyMMddTHHmmss" +assembly-file-versioning-format: "{Major}.{Minor}.{Patch}.{env:GITHUB_RUN_NUMBER ?? 0}" + +# This repo needs to use NuGetVersionV2 for compatibility with PowerShellGallery +assembly-informational-format: "{NuGetVersionV2}+Build.{env:GITHUB_RUN_NUMBER ?? local}.Branch.{EscapedBranchName}.Sha.{Sha}.Date.{CommitDate}" +major-version-bump-message: 'semver:\s?(breaking|major)' +minor-version-bump-message: 'semver:\s?(feature|minor)' +patch-version-bump-message: 'semver:\s?(fix|patch)' +no-bump-message: 'semver:\s?(none|skip)' +commit-message-incrementing: Enabled + branches: - master: + main: + tag: "" # explicitly no tag for main builds + regex: ^main$ increment: Patch - pull-request: + is-mainline: true + tracks-release-branches: true + hotfix: + tag: rc + regex: hotfix(es)?/\d+\.\d+\.\d+ + increment: None + is-release-branch: true + prevent-increment-of-merged-branch-version: true + source-branches: [ "main" ] + release: tag: rc + regex: releases?/\d+\.\d+\.\d+ + increment: None + is-release-branch: true + prevent-increment-of-merged-branch-version: true + source-branches: [ "main" ] + pull-request: + regex: pull/ + tag: pr + tag-number-pattern: '[/-](?\d+)' increment: Patch + source-branches: [ "main", "feature", "release", "hotfix" ] feature: + regex: .*/ + tag: useBranchName + source-branches: [ "main", "feature" ] + track-merge-target: true + tracks-release-branches: true increment: Patch - regex: .*?/ - source-branches: - - master - - feature From ee5a5c99434c0764e42233306404688c4a6d0d79 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Thu, 6 Feb 2025 23:34:38 -0500 Subject: [PATCH 07/18] Upgrade the Pester Tests to 5.x --- Build.build.ps1 | 4 +- Tests/Integration/Source1.Tests.ps1 | 153 ++-- Tests/Private/ConvertToAst.Tests.ps1 | 18 +- Tests/Private/CopyReadMe.Tests.ps1 | 32 +- Tests/Private/GetBuildInfo.Tests.ps1 | 51 +- Tests/Private/GetRelativePath.Tests.ps1 | 62 +- Tests/Private/ImportModuleManifest.Tests.ps1 | 4 +- Tests/Private/InitializeBuild.Tests.ps1 | 48 +- Tests/Private/MoveUsingStatements.Tests.ps1 | 163 ++-- Tests/Private/ParseLineNumber.Tests.ps1 | 2 +- Tests/Private/ResolveOutputFolder.Tests.ps1 | 110 +-- Tests/Private/SetModuleContent.Tests.ps1 | 137 +-- Tests/Public/Build-Module.Tests.ps1 | 888 ++++++++++--------- build.requires.psd1 | 2 +- 14 files changed, 888 insertions(+), 786 deletions(-) diff --git a/Build.build.ps1 b/Build.build.ps1 index 2ecfbdf..6b5738d 100644 --- a/Build.build.ps1 +++ b/Build.build.ps1 @@ -16,8 +16,8 @@ param( # Add the clean task before the default build [switch]$Clean, - # Collect code coverage when tests are run - [switch]$CollectCoverage, + # A minimum code coverage percentage to accept as a double: 0.85 + [double]$RequiredCodeCoverage = 0.85, # Which projects to build [Alias("Projects")] diff --git a/Tests/Integration/Source1.Tests.ps1 b/Tests/Integration/Source1.Tests.ps1 index 63b5bb9..bcb285a 100644 --- a/Tests/Integration/Source1.Tests.ps1 +++ b/Tests/Integration/Source1.Tests.ps1 @@ -2,14 +2,16 @@ . $PSScriptRoot\..\Convert-FolderSeparator.ps1 Describe "When we call Build-Module" -Tag Integration { - $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -Passthru - $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1") + BeforeAll { + $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -Passthru + $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1") + $Metadata = Import-Metadata $Output.Path + } It "Should not put the module's DefaultCommandPrefix into the psm1 as code. Duh!" { $Module | Should -Not -FileContentMatch '^Source$' } - $Metadata = Import-Metadata $Output.Path It "Should update FunctionsToExport in the manifest" { $Metadata.FunctionsToExport | Should -Be @("Get-Source", "Set-Source") @@ -29,14 +31,16 @@ Describe "When we call Build-Module" -Tag Integration { } Describe "Regression test for #55: I can pass SourceDirectories" -Tag Integration, Regression { - $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -SourceDirectories "Private" -Passthru - $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1") + BeforeAll { + $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -SourceDirectories "Private" -Passthru + $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1") + $Metadata = Import-Metadata $Output.Path + } It "Should not put the module's DefaultCommandPrefix into the psm1 as code. Duh!" { $Module | Should -Not -FileContentMatch '^Source$' } - $Metadata = Import-Metadata $Output.Path It "Should not have any FunctionsToExport if SourceDirectories don't match the PublicFilter" { $Metadata.FunctionsToExport | Should -Be @() @@ -80,9 +84,10 @@ Describe "Regression test for #55: I can pass SourceDirectories and PublicFilter } Describe "Regression test for #84: Multiple Aliases per command will Export" -Tag Integration, Regression { - $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -Passthru - - $Metadata = Import-Metadata $Output.Path + BeforeAll { + $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -Passthru + $Metadata = Import-Metadata $Output.Path + } It "Should update AliasesToExport in the manifest" { $Metadata.AliasesToExport | Should -Be @("Get-MyAlias","GS","GSou", "SS", "SSou") @@ -90,17 +95,19 @@ Describe "Regression test for #84: Multiple Aliases per command will Export" -Ta } Describe "Supports building without a build.psd1" -Tag Integration { - Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse - # This is the old build, with a build.psd1 - $Output = Build-Module TestDrive:\Source1\build.psd1 -Passthru - $ManifestContent = Get-Content $Output.Path - $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1")) - Remove-Item (Split-Path $Output.Path) -Recurse + BeforeAll { + Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse + # This is the old build, with a build.psd1 + $Output = Build-Module TestDrive:\Source1\build.psd1 -Passthru + $ManifestContent = Get-Content $Output.Path + $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1")) + Remove-Item (Split-Path $Output.Path) -Recurse - # Then remove the build.psd1 and rebuild it - Remove-Item TestDrive:\Source1\build.psd1 + # Then remove the build.psd1 and rebuild it + Remove-Item TestDrive:\Source1\build.psd1 - $Build = @{ } + $Build = @{ } + } It "No longer fails if there's no build.psd1" { $BuildParameters = @{ @@ -158,17 +165,19 @@ Describe "Supports building without a build.psd1" -Tag Integration { } Describe "Defaults to VersionedOutputDirectory" -Tag Integration { - Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse - # This is the old build, with a build.psd1 - $Output = Build-Module TestDrive:\Source1\build.psd1 -Passthru - $ManifestContent = Get-Content $Output.Path - $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1")) - Remove-Item (Split-Path $Output.Path) -Recurse + BeforeAll { + Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse + # This is the old build, with a build.psd1 + $Output = Build-Module TestDrive:\Source1\build.psd1 -Passthru + $ManifestContent = Get-Content $Output.Path + $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1")) + Remove-Item (Split-Path $Output.Path) -Recurse - # Then remove the build.psd1 and rebuild it - Remove-Item TestDrive:\Source1\build.psd1 + # Then remove the build.psd1 and rebuild it + Remove-Item TestDrive:\Source1\build.psd1 - $Build = @{ } + $Build = @{ } + } It "Builds into a folder with version by default" { $BuildParameters = @{ @@ -207,20 +216,22 @@ Describe "Defaults to VersionedOutputDirectory" -Tag Integration { } Describe "Supports building discovering the module without a build.psd1" -Tag Integration { - Copy-Item $PSScriptRoot\Source1 TestDrive:\source -Recurse + BeforeAll { + Copy-Item $PSScriptRoot\Source1 TestDrive:\source -Recurse - # This is the old build, with a build.psd1 - $Output = Build-Module TestDrive:\source\build.psd1 -Passthru - $ManifestContent = Get-Content $Output.Path - $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1")) - Remove-Item (Split-Path $Output.Path) -Recurse + # This is the old build, with a build.psd1 + $Output = Build-Module TestDrive:\source\build.psd1 -Passthru + $ManifestContent = Get-Content $Output.Path + $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1")) + Remove-Item (Split-Path $Output.Path) -Recurse - # Then remove the build.psd1 and rebuild it - Remove-Item TestDrive:\source\build.psd1 + # Then remove the build.psd1 and rebuild it + Remove-Item TestDrive:\source\build.psd1 - Push-Location -StackName 'IntegrationTest' -Path TestDrive:\ + Push-Location -StackName 'IntegrationTest' -Path TestDrive:\ - $Build = @{ } + $Build = @{ } + } It "No longer fails if there's no build.psd1" { $Build.Output = Build-Module -Passthru @@ -240,13 +251,16 @@ Describe "Supports building discovering the module without a build.psd1" -Tag In $Build.Metadata.FunctionsToExport | Should -Be @("Get-Source", "Set-Source") } - Pop-Location -StackName 'IntegrationTest' + AfterAll { + Pop-Location -StackName 'IntegrationTest' + } } Describe "Regression test for #88 not copying prefix files" -Tag Integration, Regression { - $Output = Build-Module $PSScriptRoot\build.psd1 -Passthru - - $Metadata = Import-Metadata $Output.Path + BeforeAll { + $Output = Build-Module $PSScriptRoot\build.psd1 -Passthru + $Metadata = Import-Metadata $Output.Path + } It "Should update AliasesToExport in the manifest" { $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1") @@ -256,20 +270,22 @@ Describe "Regression test for #88 not copying prefix files" -Tag Integration, Re } Describe "Regression test for #40.2 not copying suffix if prefix" -Tag Integration, Regression { - Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse + BeforeAll { + Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse - New-Item TestDrive:\Source1\_GlobalScope.ps1 -Value '$Global:Module = "Testing"' + New-Item TestDrive:\Source1\_GlobalScope.ps1 -Value '$Global:Module = "Testing"' - $metadata = Import-Metadata TestDrive:\Source1\build.psd1 - $metadata += @{ - Prefix = "./_GlobalScope.ps1" - Suffix = "./_GlobalScope.ps1" - } - $metadata | Export-Metadata TestDrive:\Source1\build.psd1 + $metadata = Import-Metadata TestDrive:\Source1\build.psd1 + $metadata += @{ + Prefix = "./_GlobalScope.ps1" + Suffix = "./_GlobalScope.ps1" + } + $metadata | Export-Metadata TestDrive:\Source1\build.psd1 - $Output = Build-Module TestDrive:\Source1 -Passthru + $Output = Build-Module TestDrive:\Source1 -Passthru - $Metadata = Import-Metadata $Output.Path + $Metadata = Import-Metadata $Output.Path + } It "Should inject the content of the _GlobalScope file at the TOP and BOTTOM" { $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1") @@ -288,10 +304,12 @@ Describe "Regression test for #40.2 not copying suffix if prefix" -Tag Integrati # There's no such thing as a drive root on unix if ($PSVersionTable.Platform -eq "Win32NT") { Describe "Able to build from the drive root" { - $null = New-ModuleManifest "TestDrive:/MyModule.psd1" -ModuleVersion "1.0.0" -Author "Tester" - $null = New-Item "TestDrive:/Public/Test.ps1" -Type File -Value 'MATCHING TEST CONTENT' -Force + BeforeAll { + $null = New-ModuleManifest "TestDrive:/MyModule.psd1" -ModuleVersion "1.0.0" -Author "Tester" + $null = New-Item "TestDrive:/Public/Test.ps1" -Type File -Value 'MATCHING TEST CONTENT' -Force - $Result = Build-Module -SourcePath 'TestDrive:/MyModule.psd1' -Version "1.0.0" -OutputDirectory './output' -Encoding UTF8 -SourceDirectories @('Public') -Target Build -Passthru + $Result = Build-Module -SourcePath 'TestDrive:/MyModule.psd1' -Version "1.0.0" -OutputDirectory './output' -Encoding UTF8 -SourceDirectories @('Public') -Target Build -Passthru + } It "Builds the Module in the designated output folder" { $Result.ModuleBase | Convert-FolderSeparator | Should -Be (Convert-FolderSeparator "TestDrive:/Output/MyModule/1.0.0") @@ -301,20 +319,21 @@ if ($PSVersionTable.Platform -eq "Win32NT") { } Describe "Copies additional items specified in CopyPaths" { + BeforeAll { + $null = New-Item "TestDrive:/build.psd1" -Type File -Force -Value "@{ + SourcePath = 'TestDrive:/MyModule.psd1' + SourceDirectories = @('Public') + OutputDirectory = './output' + CopyPaths = './lib', './MyModule.format.ps1xml' + }" + $null = New-ModuleManifest "TestDrive:/MyModule.psd1" -ModuleVersion "1.0.0" -Author "Tester" + $null = New-Item "TestDrive:/Public/Test.ps1" -Type File -Value 'MATCHING TEST CONTENT' -Force + $null = New-Item "TestDrive:/MyModule.format.ps1xml" -Type File -Value '' -Force + $null = New-Item "TestDrive:/lib/imaginary1.dll" -Type File -Value '1' -Force + $null = New-Item "TestDrive:/lib/subdir/imaginary2.dll" -Type File -Value '2' -Force - $null = New-Item "TestDrive:/build.psd1" -Type File -Force -Value "@{ - SourcePath = 'TestDrive:/MyModule.psd1' - SourceDirectories = @('Public') - OutputDirectory = './output' - CopyPaths = './lib', './MyModule.format.ps1xml' - }" - $null = New-ModuleManifest "TestDrive:/MyModule.psd1" -ModuleVersion "1.0.0" -Author "Tester" - $null = New-Item "TestDrive:/Public/Test.ps1" -Type File -Value 'MATCHING TEST CONTENT' -Force - $null = New-Item "TestDrive:/MyModule.format.ps1xml" -Type File -Value '' -Force - $null = New-Item "TestDrive:/lib/imaginary1.dll" -Type File -Value '1' -Force - $null = New-Item "TestDrive:/lib/subdir/imaginary2.dll" -Type File -Value '2' -Force - - $Result = Build-Module -SourcePath 'TestDrive:/build.psd1' -OutputDirectory './output' -Version '1.0.0' -Passthru -Target Build + $Result = Build-Module -SourcePath 'TestDrive:/build.psd1' -OutputDirectory './output' -Version '1.0.0' -Passthru -Target Build + } It "Copies single files that are in CopyPaths" { (Convert-FolderSeparator $Result.ModuleBase) | Should -Be (Convert-FolderSeparator "$TestDrive/output/MyModule/1.0.0") diff --git a/Tests/Private/ConvertToAst.Tests.ps1 b/Tests/Private/ConvertToAst.Tests.ps1 index 5ccca7e..a53545e 100644 --- a/Tests/Private/ConvertToAst.Tests.ps1 +++ b/Tests/Private/ConvertToAst.Tests.ps1 @@ -2,8 +2,10 @@ Describe "ConvertToAst" { Context "It returns a ParseResult for file paths" { - $ParseResult = InModuleScope ModuleBuilder { - ConvertToAst $PSCommandPath + BeforeAll { + $ParseResult = InModuleScope ModuleBuilder { + ConvertToAst $PSCommandPath + } } It "Returns a ParseResult object" { @@ -22,8 +24,10 @@ Describe "ConvertToAst" { } Context "It parses piped in commands" { - $ParseResult = InModuleScope ModuleBuilder { - Get-Command ConvertToAst | ConvertToAst + BeforeAll { + $ParseResult = InModuleScope ModuleBuilder { + Get-Command ConvertToAst | ConvertToAst + } } It "Returns a ParseResult object with the AST" { @@ -33,8 +37,10 @@ Describe "ConvertToAst" { } Context "It parses piped in modules" { - $ParseResult = InModuleScope ModuleBuilder { - Get-Module ModuleBuilder | ConvertToAst + BeforeAll { + $ParseResult = InModuleScope ModuleBuilder { + Get-Module ModuleBuilder | ConvertToAst + } } It "Returns a ParseResult object with the AST" { diff --git a/Tests/Private/CopyReadMe.Tests.ps1 b/Tests/Private/CopyReadMe.Tests.ps1 index b72bc71..a8aa80e 100644 --- a/Tests/Private/CopyReadMe.Tests.ps1 +++ b/Tests/Private/CopyReadMe.Tests.ps1 @@ -1,6 +1,8 @@ #requires -Module ModuleBuilder Describe "Copy ReadMe" { - . $PSScriptRoot\..\Convert-FolderSeparator.ps1 + BeforeAll { + . $PSScriptRoot\..\Convert-FolderSeparator.ps1 + } Context "There's no ReadMe" { # It should not even call Test-Path @@ -30,32 +32,36 @@ Describe "Copy ReadMe" { } Context "There is a ReadMe" { - # Nothing is actually created when this test runs - Mock New-Item -ModuleName ModuleBuilder - Mock Copy-Item -ModuleName ModuleBuilder + BeforeAll { + # Nothing is actually created when this test runs + Mock New-Item -ModuleName ModuleBuilder + Mock Copy-Item -ModuleName ModuleBuilder - # Test-Path returns true only for the source document - ${global:Test Script Path} = Join-Path $PSScriptRoot CopyReadMe.Tests.ps1 - Mock Test-Path { $Path -eq ${global:Test Script Path} } -ModuleName ModuleBuilder + # Test-Path returns true only for the source document + ${global:Test Script Path} = Join-Path $PSScriptRoot CopyReadMe.Tests.ps1 + Mock Test-Path { $Path -eq ${global:Test Script Path} } -ModuleName ModuleBuilder - Remove-Item TestDrive:\En -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item TestDrive:\En -Recurse -Force -ErrorAction SilentlyContinue - InModuleScope ModuleBuilder { - CopyReadMe -ReadMe ${global:Test Script Path} -Module ModuleBuilder -OutputDirectory TestDrive:\ -Culture "En" + InModuleScope ModuleBuilder { + CopyReadMe -ReadMe ${global:Test Script Path} -Module ModuleBuilder -OutputDirectory TestDrive:\ -Culture "En" + } } It "Creates a language path in the output" { Assert-MockCalled New-Item -ModuleName ModuleBuilder -ParameterFilter { (Convert-FolderSeparator "$Path") -eq (Convert-FolderSeparator "TestDrive:\En") - } + } -Scope Context } It "Copies the readme as about_module.help.txt" { Assert-MockCalled Copy-Item -ModuleName ModuleBuilder -ParameterFilter { (Convert-FolderSeparator $Destination) -eq (Convert-FolderSeparator "TestDrive:\En\about_ModuleBuilder.help.txt") - } + } -Scope Context } - Remove-Item TestDrive:\En -Recurse -Force -ErrorAction SilentlyContinue + AfterAll { + Remove-Item TestDrive:\En -Recurse -Force -ErrorAction SilentlyContinue + } } } diff --git a/Tests/Private/GetBuildInfo.Tests.ps1 b/Tests/Private/GetBuildInfo.Tests.ps1 index ab0ba09..0bb269c 100644 --- a/Tests/Private/GetBuildInfo.Tests.ps1 +++ b/Tests/Private/GetBuildInfo.Tests.ps1 @@ -1,37 +1,40 @@ #requires -Module ModuleBuilder Describe "GetBuildInfo" { - . $PSScriptRoot\..\Convert-FolderSeparator.ps1 + BeforeAll { + . $PSScriptRoot\..\Convert-FolderSeparator.ps1 - Mock Import-Metadata -ModuleName ModuleBuilder { - @{ - #Omitting path to let it resolve [Path = "MyModule.psd1"] - SourceDirectories = "Classes", "Public" + Mock Import-Metadata -ModuleName ModuleBuilder { + @{ + #Omitting path to let it resolve [Path = "MyModule.psd1"] + SourceDirectories = "Classes", "Public" + } } } Context "It collects the initial data" { + BeforeAll { + # use -Force to create the subdirectories + New-Item -Force "TestDrive:\MyModule\Source\build.psd1" -Type File -Value "@{ Path = 'MyModule.psd1' }" + New-ModuleManifest "TestDrive:\MyModule\Source\MyModule.psd1" -Author Tester - # use -Force to create the subdirectories - New-Item -Force "TestDrive:\MyModule\Source\build.psd1" -Type File -Value "@{ Path = 'MyModule.psd1' }" - New-ModuleManifest "TestDrive:\MyModule\Source\MyModule.psd1" -Author Tester - - $Result = InModuleScope -ModuleName ModuleBuilder { + $Result = InModuleScope -ModuleName ModuleBuilder { - # Used to resolve the overridden parameters in $Invocation - $OutputDirectory = '..\ridiculoustestvalue' + # Used to resolve the overridden parameters in $Invocation + $OutputDirectory = '..\ridiculoustestvalue' - GetBuildInfo -BuildManifest TestDrive:\MyModule\Source\build.psd1 -BuildCommandInvocation @{ - MyCommand = @{ - Parameters = @{ - Encoding = @{ParameterType = "string" } - Target = @{ParameterType = "string" } - SourcePath = @{ParameterType = "string" } - SourceDirectories = @{ParameterType = "string[]" } - OutputDirectory = @{ParameterType = "string" } + GetBuildInfo -BuildManifest TestDrive:\MyModule\Source\build.psd1 -BuildCommandInvocation @{ + MyCommand = @{ + Parameters = @{ + Encoding = @{ParameterType = "string" } + Target = @{ParameterType = "string" } + SourcePath = @{ParameterType = "string" } + SourceDirectories = @{ParameterType = "string[]" } + OutputDirectory = @{ParameterType = "string" } + } + } + BoundParameters = @{ + OutputDirectory = '..\ridiculoustestvalue' } - } - BoundParameters = @{ - OutputDirectory = '..\ridiculoustestvalue' } } } @@ -39,7 +42,7 @@ Describe "GetBuildInfo" { It "Parses the build.psd1" { Assert-MockCalled Import-Metadata -ModuleName ModuleBuilder -ParameterFilter { (Convert-FolderSeparator $Path) -eq (Convert-FolderSeparator "TestDrive:\MyModule\Source\build.psd1") - } + } -Scope Context } It "Reads bound parameters from the BuildCommandInvocation" { diff --git a/Tests/Private/GetRelativePath.Tests.ps1 b/Tests/Private/GetRelativePath.Tests.ps1 index e11aae9..086668a 100644 --- a/Tests/Private/GetRelativePath.Tests.ps1 +++ b/Tests/Private/GetRelativePath.Tests.ps1 @@ -1,7 +1,9 @@ #requires -Module ModuleBuilder Describe "GetRelativePath" { - . $PSScriptRoot\..\Convert-FolderSeparator.ps1 - $CommandInfo = InModuleScope ModuleBuilder { Get-Command GetRelativePath } + BeforeAll { + . $PSScriptRoot\..\Convert-FolderSeparator.ps1 + $CommandInfo = InModuleScope ModuleBuilder { Get-Command GetRelativePath } + } Context "All Parameters are mandatory" { @@ -23,34 +25,36 @@ Describe "GetRelativePath" { # I'm not going to bother writing tests for this other than "it's the same as .NET's" if ([System.IO.Path]::GetRelativePath) { Context "The output always matches [System.IO.Path]::GetRelativePath" { - $TestCases = @( - @{ RelativeTo = "G:\Module"; Path = "G:\Module\Source" } - @{ RelativeTo = "G:\Module"; Path = "G:\Module\Source\Public" } - @{ RelativeTo = "G:\Module\Source"; Path = "G:\Module\Output" } - @{ RelativeTo = "G:\Module\Source"; Path = "G:\Module\Output\" } - @{ RelativeTo = "G:\Module\Source\"; Path = "G:\Module\Output\" } - @{ RelativeTo = "G:\Module\Source\"; Path = "G:\Module\Output" } - @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "G:\Modules\MyModule" } - @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "G:\Projects\Modules\MyModule" } - # These ones are backwards, but they still work - @{ RelativeTo = "G:\Module\Source" ; Path = "G:\Module" } - @{ RelativeTo = "G:\Module\Source\Public"; Path = "G:\Module" } - # These are linux-like: - @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder/Source"; } - @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/Output"; } - @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/"; } - # Weird PowerShell Paths - @{ RelativeTo = "TestDrive:/Projects/Modules/ModuleBuilder"; Path = "TestDrive:\Projects" } - @{ RelativeTo = "TestDrive:/Projects/Modules/ModuleBuilder"; Path = "TestDrive:/Projects" } - @{ RelativeTo = "TestDrive:/Projects"; Path = "TestDrive:/Projects/Modules/ModuleBuilder" } - ) - - # On Windows, there's a shortcut when the path points to totally different drive letters: - if ($PSVersionTable.Platform -eq "Win32NT") { - $TestCases += @( - @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "C:\Modules\MyModule" } - @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "F:\Projects\Modules\MyModule" } + BeforeDiscovery { + $TestCases = @( + @{ RelativeTo = "G:\Module"; Path = "G:\Module\Source" } + @{ RelativeTo = "G:\Module"; Path = "G:\Module\Source\Public" } + @{ RelativeTo = "G:\Module\Source"; Path = "G:\Module\Output" } + @{ RelativeTo = "G:\Module\Source"; Path = "G:\Module\Output\" } + @{ RelativeTo = "G:\Module\Source\"; Path = "G:\Module\Output\" } + @{ RelativeTo = "G:\Module\Source\"; Path = "G:\Module\Output" } + @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "G:\Modules\MyModule" } + @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "G:\Projects\Modules\MyModule" } + # These ones are backwards, but they still work + @{ RelativeTo = "G:\Module\Source" ; Path = "G:\Module" } + @{ RelativeTo = "G:\Module\Source\Public"; Path = "G:\Module" } + # These are linux-like: + @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder/Source"; } + @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/Output"; } + @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/"; } + # Weird PowerShell Paths + @{ RelativeTo = "TestDrive:/Projects/Modules/ModuleBuilder"; Path = "TestDrive:\Projects" } + @{ RelativeTo = "TestDrive:/Projects/Modules/ModuleBuilder"; Path = "TestDrive:/Projects" } + @{ RelativeTo = "TestDrive:/Projects"; Path = "TestDrive:/Projects/Modules/ModuleBuilder" } ) + + # On Windows, there's a shortcut when the path points to totally different drive letters: + if ($PSVersionTable.Platform -eq "Win32NT") { + $TestCases += @( + @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "C:\Modules\MyModule" } + @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "F:\Projects\Modules\MyModule" } + ) + } } It "Returns the same result as Path.GetRelativePath for " -TestCases $TestCases { diff --git a/Tests/Private/ImportModuleManifest.Tests.ps1 b/Tests/Private/ImportModuleManifest.Tests.ps1 index 7c7dbf1..71a525a 100644 --- a/Tests/Private/ImportModuleManifest.Tests.ps1 +++ b/Tests/Private/ImportModuleManifest.Tests.ps1 @@ -2,7 +2,9 @@ Describe "ImportModuleManifest" { Context "Mandatory Parameter" { - $CommandInfo = InModuleScope ModuleBuilder { Get-Command ImportModuleManifest } + BeforeAll { + $CommandInfo = InModuleScope ModuleBuilder { Get-Command ImportModuleManifest } + } It 'has a mandatory Path parameter for the PSPath by pipeline' { $Path = $CommandInfo.Parameters['Path'] diff --git a/Tests/Private/InitializeBuild.Tests.ps1 b/Tests/Private/InitializeBuild.Tests.ps1 index b48427e..8731735 100644 --- a/Tests/Private/InitializeBuild.Tests.ps1 +++ b/Tests/Private/InitializeBuild.Tests.ps1 @@ -1,20 +1,23 @@ #requires -Module ModuleBuilder Describe "InitializeBuild" { - . $PSScriptRoot\..\Convert-FolderSeparator.ps1 + BeforeAll { + . $PSScriptRoot\..\Convert-FolderSeparator.ps1 + } Context "It collects the initial data" { + BeforeAll { + # Note that "Path" is an alias for "SourcePath" + New-Item "TestDrive:\build.psd1" -Type File -Force -Value '@{ + Path = ".\Source\MyModule.psd1" + SourceDirectories = @("Classes", "Private", "Public") + }' - # Note that "Path" is an alias for "SourcePath" - New-Item "TestDrive:\build.psd1" -Type File -Force -Value '@{ - Path = ".\Source\MyModule.psd1" - SourceDirectories = @("Classes", "Private", "Public") - }' - - New-Item "TestDrive:\Source\" -Type Directory + New-Item "TestDrive:\Source\" -Type Directory - New-ModuleManifest "TestDrive:\Source\MyModule.psd1" -RootModule "MyModule.psm1" -Author "Test Manager" -ModuleVersion "1.0.0" + New-ModuleManifest "TestDrive:\Source\MyModule.psd1" -RootModule "MyModule.psm1" -Author "Test Manager" -ModuleVersion "1.0.0" - $Result = @{} + $Result = @{} + } It "Handles Build-Module parameters, and the build.psd1 configuration" { Push-Location TestDrive:\ @@ -43,30 +46,33 @@ Describe "InitializeBuild" { Pop-Location $Result.Result | Should -Not -BeOfType [System.Management.Automation.ErrorRecord] } - $Result = $Result.Result # $Result | Format-List * -Force | Out-Host It "Returns the ModuleInfo combined with the BuildInfo" { - $Result.Name | Should -Be "MyModule" - $Result.SourceDirectories | Should -Be @("Classes", "Private", "Public") - (Convert-FolderSeparator $Result.ModuleBase) | Should -Be (Convert-FolderSeparator "TestDrive:\Source") - (Convert-FolderSeparator $Result.SourcePath) | Should -Be (Convert-FolderSeparator "TestDrive:\Source\MyModule.psd1") + $Result.Result.Name | Should -Be "MyModule" + $Result.Result.SourceDirectories | Should -Be @("Classes", "Private", "Public") + + (Convert-FolderSeparator $Result.Result.ModuleBase) + | Should -Be (Convert-FolderSeparator "TestDrive:\Source") + + (Convert-FolderSeparator $Result.Result.SourcePath) + | Should -Be (Convert-FolderSeparator "TestDrive:\Source\MyModule.psd1") } It "Returns default values from the Build Command" { - $Result.OutputDirectory | Should -Be ".\Output" + $Result.Result.OutputDirectory | Should -Be ".\Output" } - It "Returns overriden values from the build manifest" { - $Result.SourceDirectories | Should -Be @("Classes", "Private", "Public") + It "Returns overridden values from the build manifest" { + $Result.Result.SourceDirectories | Should -Be @("Classes", "Private", "Public") } - It "Returns overriden values from parameters" { - $Result.SourcePath | Should -Be (Convert-Path 'TestDrive:\Source\MyModule.psd1') + It "Returns overridden values from parameters" { + $Result.Result.SourcePath | Should -Be (Convert-Path 'TestDrive:\Source\MyModule.psd1') } It "Sets VersionedOutputDirectory FALSE when UnversionedOutputDirectory is TRUE" { - $Result.VersionedOutputDirectory | Should -Be $false + $Result.Result.VersionedOutputDirectory | Should -Be $false } } } diff --git a/Tests/Private/MoveUsingStatements.Tests.ps1 b/Tests/Private/MoveUsingStatements.Tests.ps1 index e2f8f8e..2cf5d73 100644 --- a/Tests/Private/MoveUsingStatements.Tests.ps1 +++ b/Tests/Private/MoveUsingStatements.Tests.ps1 @@ -1,7 +1,10 @@ #requires -Module ModuleBuilder Describe "MoveUsingStatements" { - Context "Necessary Parameters" { + BeforeAll { $CommandInfo = InModuleScope ModuleBuilder { Get-Command MoveUsingStatements } + } + + Context "Necessary Parameters" { It 'has a mandatory AST parameter' { $AST = $CommandInfo.Parameters['AST'] @@ -19,78 +22,79 @@ Describe "MoveUsingStatements" { } Context "Moving Using Statements to the beginning of the file" { - - $MoveUsingStatementsCmd = InModuleScope ModuleBuilder { - $null = Mock Write-Warning { } - { param($RootModule) - ConvertToAst $RootModule | MoveUsingStatements + BeforeAll { + $MoveUsingStatementsCmd = InModuleScope ModuleBuilder { + $null = Mock Write-Warning { } + { param($RootModule) + ConvertToAst $RootModule | MoveUsingStatements + } } - } - $TestCases = @( - @{ - TestCaseName = 'Moves all using statements in `n terminated files to the top' - PSM1File = "function x {`n}`n" + - "using namespace System.IO`n`n" + #UsingMustBeAtStartOfScript - "function y {`n}`n" + - "using namespace System.Drawing" #UsingMustBeAtStartOfScript - ErrorBefore = 2 - ErrorAfter = 0 - }, - @{ - TestCaseName = 'Moves all using statements in`r`n terminated files to the top' - PSM1File = "function x {`r`n}`r`n" + - "USING namespace System.IO`r`n`r`n" + #UsingMustBeAtStartOfScript - "function y {`r`n}`r`n" + - "USING namespace System.Drawing" #UsingMustBeAtStartOfScript - ErrorBefore = 2 - ErrorAfter = 0 - }, - @{ - TestCaseName = 'Prevents duplicate using statements' - PSM1File = "using namespace System.IO`r`n" + #UsingMustBeAtStartOfScript - "function x {`r`n}`r`n`r`n" + - "using namespace System.IO`r`n" + #UsingMustBeAtStartOfScript - "function y {`r`n}`r`n" + - "USING namespace System.IO" #UsingMustBeAtStartOfScript - ExpectedResult = "using namespace System.IO`r`n" + - "#using namespace System.IO`r`n" + - "function x {`r`n}`r`n`r`n" + - "#using namespace System.IO`r`n" + - "function y {`r`n}`r`n" + - "#USING namespace System.IO" - ErrorBefore = 2 - ErrorAfter = 0 - }, - @{ - TestCaseName = 'Does not change the content again if there are no out-of-place using statements' - PSM1File = "using namespace System.IO`r`n`r`n" + - "using namespace System.Drawing`r`n" + - "function x {`r`n}`r`n" + - "function y {`r`n}`r`n" - ErrorBefore = 0 - ErrorAfter = 0 - }, - @{ - TestCaseName = 'Moves using statements even if types are used' - PSM1File = "function x {`r`n}`r`n" + - "using namespace System.IO`r`n`r`n" + #UsingMustBeAtStartOfScript - "function y {`r`n}`r`n" + - "using namespace System.Collections.Generic" + #UsingMustBeAtStartOfScript - "function z { [Dictionary[String,PSObject]]::new() }" #TypeNotFound - ErrorBefore = 3 - ErrorAfter = 0 - }, - @{ - TestCaseName = 'Moves using statements even when there are (other) parse errors' - PSM1File = "using namespace System.IO`r`n`r`n" + - "function x {`r`n}`r`n" + - "using namespace System.Drawing`r`n" + # UsingMustBeAtStartOfScript - "function y {`r`n}`r`n}" # Extra } at the end - ErrorBefore = 2 - ErrorAfter = 1 - } - ) + $TestCases = @( + @{ + TestCaseName = 'Moves all using statements in `n terminated files to the top' + PSM1File = "function x {`n}`n" + + "using namespace System.IO`n`n" + #UsingMustBeAtStartOfScript + "function y {`n}`n" + + "using namespace System.Drawing" #UsingMustBeAtStartOfScript + ErrorBefore = 2 + ErrorAfter = 0 + }, + @{ + TestCaseName = 'Moves all using statements in`r`n terminated files to the top' + PSM1File = "function x {`r`n}`r`n" + + "USING namespace System.IO`r`n`r`n" + #UsingMustBeAtStartOfScript + "function y {`r`n}`r`n" + + "USING namespace System.Drawing" #UsingMustBeAtStartOfScript + ErrorBefore = 2 + ErrorAfter = 0 + }, + @{ + TestCaseName = 'Prevents duplicate using statements' + PSM1File = "using namespace System.IO`r`n" + #UsingMustBeAtStartOfScript + "function x {`r`n}`r`n`r`n" + + "using namespace System.IO`r`n" + #UsingMustBeAtStartOfScript + "function y {`r`n}`r`n" + + "USING namespace System.IO" #UsingMustBeAtStartOfScript + ExpectedResult = "using namespace System.IO`r`n" + + "#using namespace System.IO`r`n" + + "function x {`r`n}`r`n`r`n" + + "#using namespace System.IO`r`n" + + "function y {`r`n}`r`n" + + "#USING namespace System.IO" + ErrorBefore = 2 + ErrorAfter = 0 + }, + @{ + TestCaseName = 'Does not change the content again if there are no out-of-place using statements' + PSM1File = "using namespace System.IO`r`n`r`n" + + "using namespace System.Drawing`r`n" + + "function x {`r`n}`r`n" + + "function y {`r`n}`r`n" + ErrorBefore = 0 + ErrorAfter = 0 + }, + @{ + TestCaseName = 'Moves using statements even if types are used' + PSM1File = "function x {`r`n}`r`n" + + "using namespace System.IO`r`n`r`n" + #UsingMustBeAtStartOfScript + "function y {`r`n}`r`n" + + "using namespace System.Collections.Generic" + #UsingMustBeAtStartOfScript + "function z { [Dictionary[String,PSObject]]::new() }" #TypeNotFound + ErrorBefore = 3 + ErrorAfter = 0 + }, + @{ + TestCaseName = 'Moves using statements even when there are (other) parse errors' + PSM1File = "using namespace System.IO`r`n`r`n" + + "function x {`r`n}`r`n" + + "using namespace System.Drawing`r`n" + # UsingMustBeAtStartOfScript + "function y {`r`n}`r`n}" # Extra } at the end + ErrorBefore = 2 + ErrorAfter = 1 + } + ) + } It '' -TestCases $TestCases { param($TestCaseName, $PSM1File, $ErrorBefore, $ErrorAfter, $ExpectedResult) @@ -123,14 +127,15 @@ Describe "MoveUsingStatements" { } Context "When MoveUsingStatements should do nothing" { - - $MoveUsingStatementsCmd = InModuleScope ModuleBuilder { - $null = Mock Write-Warning {} - $null = Mock Set-Content {} - $null = Mock Write-Debug {} -ParameterFilter { $Message -eq "No using statement errors found." } - - { param($RootModule) - ConvertToAst $RootModule | MoveUsingStatements + BeforeAll { + $MoveUsingStatementsCmd = InModuleScope ModuleBuilder { + $null = Mock Write-Warning {} + $null = Mock Set-Content {} + $null = Mock Write-Debug {} -ParameterFilter { $Message -eq "No using statement errors found." } + + { param($RootModule) + ConvertToAst $RootModule | MoveUsingStatements + } } } diff --git a/Tests/Private/ParseLineNumber.Tests.ps1 b/Tests/Private/ParseLineNumber.Tests.ps1 index 40fa5f2..e0c503c 100644 --- a/Tests/Private/ParseLineNumber.Tests.ps1 +++ b/Tests/Private/ParseLineNumber.Tests.ps1 @@ -45,7 +45,7 @@ Describe "ParseLineNumber" { $Source.SourceLineNumber | Should -Be 14 } - It 'Should get and and line number from errors at the console' { + It 'Should get [ScriptBlock] and [No file] and line number from errors at the console' { $Source = InModuleScope ModuleBuilder { ParseLineNumber "at , : line 1" } $Source.SourceFile | Should -Be "" diff --git a/Tests/Private/ResolveOutputFolder.Tests.ps1 b/Tests/Private/ResolveOutputFolder.Tests.ps1 index 40b95b0..c6f1f87 100644 --- a/Tests/Private/ResolveOutputFolder.Tests.ps1 +++ b/Tests/Private/ResolveOutputFolder.Tests.ps1 @@ -1,59 +1,61 @@ #requires -Module ModuleBuilder Describe "ResolveOutputFolder" { - . $PSScriptRoot\..\Convert-FolderSeparator.ps1 - $CommandInTest = InModuleScope ModuleBuilder { Get-Command ResolveOutputFolder } - filter ToTestDrive { "$_".Replace($TestDrive, "TestDrive:") } + BeforeAll { + . $PSScriptRoot\..\Convert-FolderSeparator.ps1 + $CommandInTest = InModuleScope ModuleBuilder { Get-Command ResolveOutputFolder } + filter ToTestDrive { "$_".Replace($TestDrive, "TestDrive:") } - $TestCases = [Hashtable[]]@( - @{ # Be like Jaykul - Source = "ModuleName/Source" - Output = "ModuleName" - Result = "ModuleName/1.2.3" - Forced = "ModuleName/1.2.3" - } - @{ # Be like azure - Source = "1/s" - Output = "1/b" - Result = "1/b/ModuleName" - Forced = "1/b/ModuleName/1.2.3" - } - @{ # The default option would be Module/Source build to Module/Output - Source = "ModuleName/Source" - Output = "ModuleName/Output" - Result = "ModuleName/Output/ModuleName" - Forced = "ModuleName/Output/ModuleName/1.2.3" - } - @{ # Which is the same even without the common named parent - Source = "Source" - Output = "Output" - Result = "Output/ModuleName" - Forced = "Output/ModuleName/1.2.3" - } - @{ # An edge case, build straight to a modules folder - Source = "ModuleName/Source" - Output = "Modules" - Result = "Modules/ModuleName" - Forced = "Modules/ModuleName/1.2.3" - } - @{ # What if they pass in the correct path ahead of time? - Source = "1/s" - Output = "1/b/ModuleName" - Result = "1/b/ModuleName" - Forced = "1/b/ModuleName/1.2.3" - } - @{ # What if they pass in the correct path ahead of time? - Source = "1/s" - Output = "1/b/ModuleName/1.2.3" - Result = "1/b/ModuleName/1.2.3" - Forced = "1/b/ModuleName/1.2.3" - } - @{ # Super edge case: what if they pass in an incorrectly versioned output path? - Source = "1/s" - Output = "1/b/ModuleName/4.5.6" - Result = "1/b/ModuleName/4.5.6/ModuleName" - Forced = "1/b/ModuleName/4.5.6/ModuleName/1.2.3" - } - ) + $TestCases = [Hashtable[]]@( + @{ # Be like Jaykul + Source = "ModuleName/Source" + Output = "ModuleName" + Result = "ModuleName/1.2.3" + Forced = "ModuleName/1.2.3" + } + @{ # Be like azure + Source = "1/s" + Output = "1/b" + Result = "1/b/ModuleName" + Forced = "1/b/ModuleName/1.2.3" + } + @{ # The default option would be Module/Source build to Module/Output + Source = "ModuleName/Source" + Output = "ModuleName/Output" + Result = "ModuleName/Output/ModuleName" + Forced = "ModuleName/Output/ModuleName/1.2.3" + } + @{ # Which is the same even without the common named parent + Source = "Source" + Output = "Output" + Result = "Output/ModuleName" + Forced = "Output/ModuleName/1.2.3" + } + @{ # An edge case, build straight to a modules folder + Source = "ModuleName/Source" + Output = "Modules" + Result = "Modules/ModuleName" + Forced = "Modules/ModuleName/1.2.3" + } + @{ # What if they pass in the correct path ahead of time? + Source = "1/s" + Output = "1/b/ModuleName" + Result = "1/b/ModuleName" + Forced = "1/b/ModuleName/1.2.3" + } + @{ # What if they pass in the correct path ahead of time? + Source = "1/s" + Output = "1/b/ModuleName/1.2.3" + Result = "1/b/ModuleName/1.2.3" + Forced = "1/b/ModuleName/1.2.3" + } + @{ # Super edge case: what if they pass in an incorrectly versioned output path? + Source = "1/s" + Output = "1/b/ModuleName/4.5.6" + Result = "1/b/ModuleName/4.5.6/ModuleName" + Forced = "1/b/ModuleName/4.5.6/ModuleName/1.2.3" + } + ) + } Context "Build ModuleName" { It "From '' to '' creates ''" -TestCases $TestCases { param($Source, $Output, $Result) @@ -125,7 +127,7 @@ Describe "ResolveOutputFolder" { Output = Convert-FolderSeparator "TestDrive:/ModuleName/" } - { &$CommandInTest @Parameters -Name ModuleName -Target Build -Version 1.2.3 -Force } | Should -throw "There is a file in the way" + { &$CommandInTest @Parameters -Name ModuleName -Target Build -Version 1.2.3 -Force } | Should -throw "*There is a file in the way*" } } } diff --git a/Tests/Private/SetModuleContent.Tests.ps1 b/Tests/Private/SetModuleContent.Tests.ps1 index 33a6a98..684489f 100644 --- a/Tests/Private/SetModuleContent.Tests.ps1 +++ b/Tests/Private/SetModuleContent.Tests.ps1 @@ -1,7 +1,9 @@ Describe "SetModuleContent" { Context "Necessary Parameters" { - $CommandInfo = InModuleScope ModuleBuilder { Get-Command SetModuleContent } + BeforeAll { + $CommandInfo = InModuleScope ModuleBuilder { Get-Command SetModuleContent } + } It "has a mandatory string OutputPath parameter" { $OutputPath = $CommandInfo.Parameters['OutputPath'] @@ -30,37 +32,40 @@ Describe "SetModuleContent" { $Encoding.ParameterType | Should -Be ([String]) $Encoding.Attributes.Where{$_ -is [Parameter]}.Mandatory | Should -Be $False } - - $CommandInfo.Parameters['OutputPath'] + AfterAll { + $CommandInfo.Parameters['OutputPath'] + } } Context "Joining files into one" { - ${global:mock get content index} = 1 + BeforeAll { + ${global:mock get content index} = 1 - Mock Get-Content -ModuleName ModuleBuilder { - "Script Content" - "File $((${global:mock get content index}++))" - "From $Path" - } + Mock Get-Content -ModuleName ModuleBuilder { + "Script Content" + "File $((${global:mock get content index}++))" + "From $Path" + } - Mock Resolve-Path -ModuleName ModuleBuilder { - $path -replace "TestDrive:\\", ".\" - } -ParameterFilter { $Relative } + Mock Resolve-Path -ModuleName ModuleBuilder { + $path -replace "TestDrive:\\", ".\" + } -ParameterFilter { $Relative } - InModuleScope ModuleBuilder { - $Files = "TestDrive:\Private\First.ps1", - "TestDrive:\Private\Second.ps1", - "TestDrive:\Public\Third.ps1" - SetModuleContent -Source $Files -Output TestDrive:\Output.psm1 + InModuleScope ModuleBuilder { + $Files = "TestDrive:\Private\First.ps1", + "TestDrive:\Private\Second.ps1", + "TestDrive:\Public\Third.ps1" + SetModuleContent -Source $Files -Output TestDrive:\Output.psm1 + } } It "Calls get-content on every source file" { - Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\First.ps1" } - Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\Second.ps1" } - Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Public\Third.ps1" } + Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\First.ps1" } -Scope Context + Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\Second.ps1" } -Scope Context + Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Public\Third.ps1" } -Scope Context } It "Copies all three files into the Output" { @@ -77,36 +82,36 @@ Describe "SetModuleContent" { } Context "Supports adding Prefix and Suffix content" { - ${global:mock get content index} = 1 - - Mock Get-Content -ModuleName ModuleBuilder { - "Script Content" - "File $((${global:mock get content index}++))" - "From $Path" - } + BeforeAll { + ${global:mock get content index} = 1 - Mock Resolve-Path -ModuleName ModuleBuilder { - if ($path -match "TestDrive:") { - $path -replace "TestDrive:\\", ".\" - } else { - write-error "$path not found" + Mock Get-Content -ModuleName ModuleBuilder { + "Script Content" + "File $((${global:mock get content index}++))" + "From $Path" } - } -ParameterFilter { $Relative } + Mock Resolve-Path -ModuleName ModuleBuilder { + if ($path -match "TestDrive:") { + $path -replace "TestDrive:\\", ".\" + } + } -ParameterFilter { $Relative } + + InModuleScope ModuleBuilder { + $MostlyFiles = "using module Configuration", + "TestDrive:\Private\First.ps1", + "TestDrive:\Private\Second.ps1", + "TestDrive:\Public\Third.ps1", + "Export-ModuleMember Stuff" - InModuleScope ModuleBuilder { - $Files = "using module Configuration", - "TestDrive:\Private\First.ps1", - "TestDrive:\Private\Second.ps1", - "TestDrive:\Public\Third.ps1", - "Export-ModuleMember Stuff" - SetModuleContent -Source $Files -Output TestDrive:\Output.psm1 + SetModuleContent -Source $MostlyFiles -Output TestDrive:\Output.psm1 + } } It "Calls get-content on every source file" { - Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\First.ps1" } - Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\Second.ps1" } - Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Public\Third.ps1" } + Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\First.ps1" } -Scope Context + Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\Second.ps1" } -Scope Context + Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Public\Third.ps1" } -Scope Context } It "Copies all three files into the Output" { @@ -135,36 +140,36 @@ Describe "SetModuleContent" { } Context "Adds a newline before the content of each script file" { - ${global:mock get content index} = 1 - - Mock Get-Content -ModuleName ModuleBuilder { - "Script Content" - "File $((${global:mock get content index}++))" - "From $Path" - } + BeforeAll { + ${global:mock get content index} = 1 - Mock Resolve-Path -ModuleName ModuleBuilder { - if ($path -match "TestDrive:") { - $path -replace "TestDrive:\\", ".\" - } else { - write-error "$path not found" + Mock Get-Content -ModuleName ModuleBuilder { + "Script Content" + "File $((${global:mock get content index}++))" + "From $Path" } - } -ParameterFilter { $Relative } + Mock Resolve-Path -ModuleName ModuleBuilder { + if ($path -match "TestDrive:") { + $path -replace "TestDrive:\\", ".\" + } + } -ParameterFilter { $Relative } - InModuleScope ModuleBuilder { - $Files = "using module Configuration", - "TestDrive:\Private\First.ps1", - "TestDrive:\Private\Second.ps1", - "TestDrive:\Public\Third.ps1", - "Export-ModuleMember Stuff" - SetModuleContent -Source $Files -Output TestDrive:\Output.psm1 + + InModuleScope ModuleBuilder { + $Files = "using module Configuration", + "TestDrive:\Private\First.ps1", + "TestDrive:\Private\Second.ps1", + "TestDrive:\Public\Third.ps1", + "Export-ModuleMember Stuff" + SetModuleContent -Source $Files -Output TestDrive:\Output.psm1 + } } It "Calls get-content on every source file" { - Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\First.ps1" } - Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\Second.ps1" } - Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Public\Third.ps1" } + Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\First.ps1" } -Scope Context + Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Private\Second.ps1" } -Scope Context + Assert-MockCalled Get-Content -ModuleName ModuleBuilder -ParameterFilter { $Path -eq ".\Public\Third.ps1" } -Scope Context } It "Copies all three files into the Output" { diff --git a/Tests/Public/Build-Module.Tests.ps1 b/Tests/Public/Build-Module.Tests.ps1 index 268e9fe..b5d2e51 100644 --- a/Tests/Public/Build-Module.Tests.ps1 +++ b/Tests/Public/Build-Module.Tests.ps1 @@ -1,14 +1,18 @@ #requires -Module ModuleBuilder Describe "Build-Module" { - . $PSScriptRoot\..\Convert-FolderSeparator.ps1 - $PSDefaultParameterValues = @{ - "Mock:ModuleName" = "ModuleBuilder" - "Assert-MockCalled:ModuleName" = "ModuleBuilder" + BeforeAll { + . $PSScriptRoot\..\Convert-FolderSeparator.ps1 + + $PSDefaultParameterValues = @{ + "Mock:ModuleName" = "ModuleBuilder" + "Assert-MockCalled:ModuleName" = "ModuleBuilder" + } } Context "Parameter Binding" { - - $Parameters = (Get-Command Build-Module).Parameters + BeforeAll { + $Parameters = (Get-Command Build-Module).Parameters + } It "has an optional string parameter for the SourcePath" { $parameters.ContainsKey("SourcePath") | Should -Be $true @@ -16,7 +20,7 @@ Describe "Build-Module" { $parameters["SourcePath"].Attributes.Where{$_ -is [Parameter]}.Mandatory | Should -Be $false } It "throws if the SourcePath doesn't exist" { - { Build-Module -SourcePath TestDrive:/NoSuchPath } | Should -Throw "Source must point to a valid module" + { Build-Module -SourcePath TestDrive:/NoSuchPath } | Should -Throw "*Source must point to a valid module*" } It "has an optional string parameter for the OutputDirectory" { @@ -79,525 +83,565 @@ Describe "Build-Module" { } } - InModuleScope ModuleBuilder { - Mock MoveUsingStatements - Mock SetModuleContent - } - Mock Update-Metadata - Mock Copy-Item - Mock Set-Location - - Mock Join-Path { - [IO.Path]::Combine($Path, $ChildPath) - } - - Mock Get-Metadata { - "First Release" - } - - $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule" + Context "Testing" { + BeforeAll { + InModuleScope ModuleBuilder { + Mock MoveUsingStatements + Mock SetModuleContent + } + Mock Update-Metadata + Mock Copy-Item + Mock Set-Location - Mock New-Item { [IO.DirectoryInfo]("$TestDrive/Output/MyModule") } -Parameter { - (Convert-FolderSeparator "$Path") -eq $Mock_OutputPath -and - $ItemType -eq "Directory" -and $Force - } + Mock Join-Path { + [IO.Path]::Combine($Path, $ChildPath) + } - Mock Test-Path { $True } -Parameter { - (Convert-FolderSeparator "$Path") -eq $Mock_OutputPath -and ($PathType -notin "Any", "Leaf") - } + Mock Get-Metadata { + "First Release" + } - Mock Remove-Item -Parameter { - (Convert-FolderSeparator "$Path") -eq $Mock_OutputPath - } + $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule" - Context "When run without parameters" { - Push-Location TestDrive:/ -StackName BuildModuleTest - New-Item -ItemType Directory -Path TestDrive:/Output/MyModule/1.0.0/ -Force + Mock New-Item { [IO.DirectoryInfo]("$TestDrive/Output/MyModule") } -Parameter { + (Convert-FolderSeparator "$Path") -eq $Mock_OutputPath -and + $ItemType -eq "Directory" -and $Force + } - Mock ConvertToAst { - [PSCustomObject]@{ - PSTypeName = "PoshCode.ModuleBuilder.ParseResults" - ParseErrors = $null - Tokens = $null - AST = { }.AST + Mock Test-Path { $True } -Parameter { + (Convert-FolderSeparator "$Path") -eq $Mock_OutputPath -and ($PathType -notin "Any", "Leaf") } - } - Mock GetCommandAlias { @{'Get-MyInfo' = @('GMI') } } - Mock InitializeBuild { - # These are actually all the values that we need - [PSCustomObject]@{ - OutputDirectory = "TestDrive:/Output" - Name = "MyModule" - Version = [Version]"1.0.0" - Target = "CleanBuild" - ModuleBase = "TestDrive:/MyModule/" - CopyDirectories = @() - Encoding = "UTF8" - PublicFilter = "Public/*.ps1" + + Mock Remove-Item -Parameter { + (Convert-FolderSeparator "$Path") -eq $Mock_OutputPath } } - Mock Push-Location {} - # So it doesn't have to exist - Mock Convert-Path { $Path } - Mock Get-ChildItem { - [IO.FileInfo]"$TestDrive/Output/MyModule/Public/Get-MyInfo.ps1" - } + Context "When run without parameters" { + BeforeAll { + Push-Location TestDrive:/ -StackName BuildModuleTest + New-Item -ItemType Directory -Path TestDrive:/Output/MyModule/1.0.0/ -Force + Mock ConvertToAst { + [PSCustomObject]@{ + PSTypeName = "PoshCode.ModuleBuilder.ParseResults" + ParseErrors = $null + Tokens = $null + AST = { }.AST + } + } + Mock GetCommandAlias { @{'Get-MyInfo' = @('GMI') } } + Mock InitializeBuild { + # These are actually all the values that we need + [PSCustomObject]@{ + OutputDirectory = "TestDrive:/Output" + Name = "MyModule" + Version = [Version]"1.0.0" + Target = "CleanBuild" + ModuleBase = "TestDrive:/MyModule/" + CopyDirectories = @() + Encoding = "UTF8" + PublicFilter = "Public/*.ps1" + } + } - try { - Build-Module - } finally { - Pop-Location -StackName BuildModuleTest - } + Mock Push-Location {} - # NOTE: We're not just clearing output, but the whole folder - It "Should remove the output folder if it exists" { - Assert-MockCalled Remove-Item - } + # So it doesn't have to exist + Mock Convert-Path { $Path } + Mock Get-ChildItem { + [IO.FileInfo]"$TestDrive/Output/MyModule/Public/Get-MyInfo.ps1" + } - It "Should always (re)create the OutputDirectory" { - Assert-MockCalled New-Item - } - It "Should run in the module source folder" { - Assert-MockCalled Push-Location -Parameter { - $Path -eq "TestDrive:/MyModule/" + try { + Build-Module + } finally { + Pop-Location -StackName BuildModuleTest + } } - } - It "Should call ConvertToAst to parse the module" { - Assert-MockCalled ConvertToAst - } + # NOTE: We're not just clearing output, but the whole folder + It "Should remove the output folder if it exists" { + Assert-MockCalled Remove-Item -Scope Context + } - It "Should call MoveUsingStatements to move the using statements, just in case" { - Assert-MockCalled MoveUsingStatements -Parameter { - $AST.Extent.Text -eq "{ }" + It "Should always (re)create the OutputDirectory" { + Assert-MockCalled New-Item -Scope Context } - } - It "Should call SetModuleContent to combine the source files" { - Assert-MockCalled SetModuleContent - } + It "Should run in the module source folder" { + Assert-MockCalled Push-Location -Parameter { + $Path -eq "TestDrive:/MyModule/" + } -Scope Context + } - It "Should call Update-Metadata to set the FunctionsToExport" { - Assert-MockCalled Update-Metadata -Parameter { - $PropertyName -eq "FunctionsToExport" + It "Should call ConvertToAst to parse the module" { + Assert-MockCalled ConvertToAst -Scope Context } - } - It "Should call Update-Metadata to set the AliasesToExport" { - Assert-MockCalled Update-Metadata -Parameter { - $PropertyName -eq "AliasesToExport" + It "Should call MoveUsingStatements to move the using statements, just in case" { + Assert-MockCalled MoveUsingStatements -Parameter { + $AST.Extent.Text -eq "{ }" + } -Scope Context } - } - } - Context "When run without 'Clean' in the target" { - Push-Location TestDrive:/ -StackName BuildModuleTest - New-Item -ItemType Directory -Path TestDrive:/MyModule/Public -Force - New-Item -ItemType File -Path TestDrive:/MyModule/Public/Get-MyInfo.ps1 -Force - Start-Sleep -Milliseconds 200 # to ensure the output is after the input - New-Item -ItemType Directory -Path TestDrive:/1.0.0/ -Force - New-Item -ItemType File -Path TestDrive:/1.0.0/MyModule.psm1 -Force - - Mock InitializeBuild { - # These are actually all the values that we need - [PSCustomObject]@{ - OutputDirectory = "TestDrive:/Output" - Name = "MyModule" - Version = [Version]"1.0.0" - Target = $Target - ModuleBase = "TestDrive:/MyModule/" - CopyDirectories = @() - Encoding = "UTF8" - PublicFilter = "Public/*.ps1" + It "Should call SetModuleContent to combine the source files" { + Assert-MockCalled SetModuleContent -Scope Context } - } - Mock Convert-Path { $Path } + It "Should call Update-Metadata to set the FunctionsToExport" { + Assert-MockCalled Update-Metadata -Parameter { + $PropertyName -eq "FunctionsToExport" + } -Scope Context + } - Mock Get-ChildItem { - [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" + It "Should call Update-Metadata to set the AliasesToExport" { + Assert-MockCalled Update-Metadata -Parameter { + $PropertyName -eq "AliasesToExport" + } -Scope Context + } } - Mock Get-Item { - [PSCustomObject]@{ LastWriteTime = Get-Date } - } + Context "When run without 'Clean' in the target" { + BeforeAll { + $PSDefaultParameterValues = @{ + "Mock:ModuleName" = "ModuleBuilder" + "Assert-MockCalled:ModuleName" = "ModuleBuilder" + } - try { - Build-Module -Target Build - } finally { - Pop-Location -StackName BuildModuleTest - } + Push-Location TestDrive:/ -StackName BuildModuleTest + New-Item -ItemType Directory -Path TestDrive:/MyModule/Public -Force + New-Item -ItemType File -Path TestDrive:/MyModule/Public/Get-MyInfo.ps1 -Force + Start-Sleep -Milliseconds 200 # to ensure the output is after the input + New-Item -ItemType Directory -Path TestDrive:/1.0.0/ -Force + New-Item -ItemType File -Path TestDrive:/1.0.0/MyModule.psm1 -Force + + Mock InitializeBuild { + # These are actually all the values that we need + [PSCustomObject]@{ + OutputDirectory = "TestDrive:/Output" + Name = "MyModule" + Version = [Version]"1.0.0" + Target = "Build" + ModuleBase = "TestDrive:/MyModule/" + CopyDirectories = @() + Encoding = "UTF8" + PublicFilter = "Public/*.ps1" + } + } - # NOTE: We're not just clearing output, but the whole folder - It "Should NOT remove the output folder" { - Assert-MockCalled Remove-Item -Times 0 - } + Mock Convert-Path { $Path } - It "Should check the dates on the output" { - Assert-MockCalled Get-Item -Times 1 - } - - It "Should always (re)create the OutputDirectory" { - Assert-MockCalled New-Item -Times 1 - } + Mock Get-ChildItem { + [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" + } - It "Should not rebuild the source files" { - Assert-MockCalled SetModuleContent -Times 0 - } - } + Mock Get-Item { + [PSCustomObject]@{ LastWriteTime = Get-Date } + } - Context "Setting the version to a SemVer string" { - $SemVer = "1.0.0-beta03+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:/Output/MyModule/$ExpectedVersion" -Force - - Mock ResolveBuildManifest { "TestDrive:/MyModule/build.psd1" } - - Mock GetBuildInfo { - [PSCustomObject]@{ - OutputDirectory = "TestDrive:/Output" - SourcePath = "TestDrive:/MyModule/" - SemVer = $SemVer - Target = $Target - CopyPaths = @() - Encoding = "UTF8" - PublicFilter = "Public/*.ps1" - VersionedOutputDirectory = $true + try { + Build-Module -Target Build + } finally { + Pop-Location -StackName BuildModuleTest + } } - } - Mock ImportModuleManifest { - [PSCustomObject]@{ - Name = "MyModule" - ModuleBase = "TestDrive:/MyModule/" + # NOTE: We're not just clearing output, but the whole folder + It "Should NOT remove the output folder" { + Assert-MockCalled Remove-Item -Times 0 -Scope Context } - } - - $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule/$ExpectedVersion" - Mock Get-ChildItem { - [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" - } - - try { - Build-Module -SemVer $SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } - - It "Should build to an output folder with the simple version." { - Assert-MockCalled Remove-Item - Assert-MockCalled New-Item - } - - It "Should update the module version to the simple version." { - Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "ModuleVersion" -and $Value -eq $ExpectedVersion + It "Should check the dates on the output" { + Assert-MockCalled Get-Item -Times 1 -Scope Context } - } - It "Should update the module pre-release version" { - Assert-MockCalled Update-Metadata -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 -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq "MyModule v$($SemVer)`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 { "" } - try { - Build-Module -SemVer $SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw + It "Should always (re)create the OutputDirectory" { + Assert-MockCalled New-Item -Times 1 -Scope Context } - Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq "MyModule v$SemVer" + It "Should not rebuild the source files" { + Assert-MockCalled SetModuleContent -Times 0 -Scope Context } } - 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" } - - try { - Build-Module -SemVer $SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + Context "Setting the version to a SemVer string" { + BeforeAll { + $SemVer = "1.0.0-beta03+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:/Output/MyModule/$ExpectedVersion" -Force - Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq " - MyModule v$SemVer - Multi-line Release Notes - With a prefix carriage return" - } - } + Mock ResolveBuildManifest { "TestDrive:/MyModule/build.psd1" } - Pop-Location -StackName BuildModuleTest - } + Mock GetBuildInfo { + [PSCustomObject]@{ + OutputDirectory = "TestDrive:/Output" + SourcePath = "TestDrive:/MyModule/" + SemVer = $SemVer ?? "1.0.0-beta03+sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11" + Target = "CleanBuild" + CopyPaths = @() + Encoding = "UTF8" + PublicFilter = "Public/*.ps1" + VersionedOutputDirectory = $true + } + } - 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:/Output/MyModule" -Force - - Mock ResolveBuildManifest { "TestDrive:/MyModule/build.psd1" } - - Mock GetBuildInfo { - [PSCustomObject]@{ - OutputDirectory = "TestDrive:/Output" - SourcePath = "TestDrive:/MyModule/" - Version = "1.0.0" - Prerelease = "beta03" - BuildMetadata = "Sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11" - Target = "CleanBuild" - CopyPaths = @() - Encoding = "UTF8" - PublicFilter = "Public/*.ps1" - } - } + Mock ImportModuleManifest { + [PSCustomObject]@{ + Name = "MyModule" + ModuleBase = "TestDrive:/MyModule/" + } + } - Mock ImportModuleManifest { - [PSCustomObject]@{ - Name = "MyModule" - ModuleBase = "TestDrive:/MyModule/" - } - } + $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule/$ExpectedVersion" - $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule" - Mock Get-ChildItem { - [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" - } + Mock Get-ChildItem { + [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" + } - try { - Build-Module @SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + try { + Build-Module -SemVer $SemVer + } catch { + Pop-Location -StackName BuildModuleTest + throw + } + } - It "Should build to an output folder with the simple version." { - Assert-MockCalled Remove-Item - Assert-MockCalled New-Item - } + It "Should build to an output folder with the simple version." { + Assert-MockCalled Remove-Item -Scope Context + Assert-MockCalled New-Item -Scope Context + } - It "Should update the module version to the simple version." { - Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "ModuleVersion" -and $Value -eq $ExpectedVersion + It "Should update the module version to the simple version." { + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "ModuleVersion" -and $Value -eq $ExpectedVersion + } -Scope Context } - } - It "Should update the module pre-release version" { - Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.Prerelease" -and $Value -eq "beta03" + It "Should update the module pre-release version" { + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.Prerelease" -and $Value -eq "beta03" + } -Scope Context } - } - It "When there are simple release notes, it should insert a line with the module name and full semver" { - Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and - $Value -eq "MyModule v$($SemVer.Version)-$($SemVer.Prerelease)+$($SemVer.BuildMetadata)`nFirst Release" + It "When there are simple release notes, it should insert a line with the module name and full semver" { + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq "MyModule v$($SemVer)`nFirst Release" + } -Scope Context } - } - 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 { "" } + 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 { "" } - try { - Build-Module @SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + try { + Build-Module -SemVer $SemVer + } catch { + Pop-Location -StackName BuildModuleTest + throw + } - Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and - $Value -eq "MyModule v$($SemVer.Version)-$($SemVer.Prerelease)+$($SemVer.BuildMetadata)" + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq "MyModule v$SemVer" + } } - } - 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" } + 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" } - try { - Build-Module @SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + try { + Build-Module -SemVer $SemVer + } catch { + Pop-Location -StackName BuildModuleTest + throw + } - Assert-MockCalled Update-Metadata -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" + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq " + MyModule v$SemVer + Multi-line Release Notes + With a prefix carriage return" + } } - } - - Pop-Location -StackName BuildModuleTest - } - - Context "Setting the version with no pre-release" { - # $SemVer = "1.0.0-beta03+sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11" - $SemVer = @{ - Version = "1.0.0" - 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:/Output/MyModule" -Force - - Mock InitializeBuild { - # These are actually all the values that we need - [PSCustomObject]@{ - OutputDirectory = "TestDrive:/Output" - Name = "MyModule" - Version = [Version]"1.0.0" - Target = $Target - ModuleBase = "TestDrive:/MyModule/" - CopyPaths = @() - Encoding = "UTF8" - PublicFilter = "Public/*.ps1" + AfterAll { + Pop-Location -StackName BuildModuleTest } } - Mock Convert-Path { $Path } - $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule" - Mock Get-ChildItem { - [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" - } + Context "Setting the version and pre-release" { + BeforeAll { + # $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:/Output/MyModule" -Force + + Mock ResolveBuildManifest { "TestDrive:/MyModule/build.psd1" } + + Mock GetBuildInfo { + [PSCustomObject]@{ + OutputDirectory = "TestDrive:/Output" + SourcePath = "TestDrive:/MyModule/" + Version = "1.0.0" + Prerelease = "beta03" + BuildMetadata = "Sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11" + Target = "CleanBuild" + CopyPaths = @() + Encoding = "UTF8" + PublicFilter = "Public/*.ps1" + } + } - try { - Build-Module @SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + Mock ImportModuleManifest { + [PSCustomObject]@{ + Name = "MyModule" + ModuleBase = "TestDrive:/MyModule/" + } + } - It "Should build to an output folder with the simple version." { - Assert-MockCalled Remove-Item - Assert-MockCalled New-Item - } + $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule" + Mock Get-ChildItem { + [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" + } - It "Should update the module version to the simple version." { - Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "ModuleVersion" -and $Value -eq $ExpectedVersion + try { + Build-Module @SemVer + } catch { + Pop-Location -StackName BuildModuleTest + throw + } } - } - It "Should not change the module pre-release value" { - Assert-MockCalled Update-Metadata -Times 0 -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.Prerelease" + + It "Should build to an output folder with the simple version." { + Assert-MockCalled Remove-Item -Scope Context + Assert-MockCalled New-Item -Scope Context } - } - Pop-Location -StackName BuildModuleTest - } + It "Should update the module version to the simple version." { + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "ModuleVersion" -and $Value -eq $ExpectedVersion + } -Scope Context + } + It "Should update the module pre-release version" { + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.Prerelease" -and $Value -eq "beta03" + } -Scope Context + } + It "When there are simple release notes, it should insert a line with the module name and full semver" { + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and + $Value -eq "MyModule v$($SemVer.Version)-$($SemVer.Prerelease)+$($SemVer.BuildMetadata)`nFirst Release" + } -Scope Context + } - Context "Bug #70 Cannot build 1.2.3-pre-release" { - BeforeEach { - Push-Location TestDrive:/ -StackName BuildModuleTest - New-Item -ItemType Directory -Path TestDrive:/MyModule/ -Force - New-Item -ItemType Directory -Path "TestDrive:/$ExpectedVersion/" -Force + 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 { "" } - Mock GetBuildInfo { - # These are actually all the values that we need - [PSCustomObject]@{ - OutputDirectory = "TestDrive:/$Version" - Name = "MyModule" - Version = $Version - PreRelease = $PreRelease - Target = $Target - SourcePath = "TestDrive:/MyModule/" - CopyPaths = @() - Encoding = "UTF8" - PublicFilter = "Public/*.ps1" + try { + Build-Module @SemVer + } catch { + Pop-Location -StackName BuildModuleTest + throw } - } - Mock ImportModuleManifest { - [PSCustomObject]@{ - Name = "MyModule" - ModuleBase = "TestDrive:/MyModule/" + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and + $Value -eq "MyModule v$($SemVer.Version)-$($SemVer.Prerelease)+$($SemVer.BuildMetadata)" } } - $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/MyModule/$ExpectedVersion" + 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" } - Mock Get-ChildItem { - [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" + try { + Build-Module @SemVer + } catch { + Pop-Location -StackName BuildModuleTest + throw + } + + Assert-MockCalled Update-Metadata -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" + } + } + AfterAll { + Pop-Location -StackName BuildModuleTest } - } - AfterEach { - Pop-Location -StackName BuildModuleTest } - Context "When I Build-Module -Version 1.2.3 -Prerelease pre-release" { - It "Should set the prerelese to 'pre-release'" { - Mock Update-Metadata -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.Prerelease" - } -MockWith { - $Value | Should -Be "pre-release" + Context "Setting the version with no pre-release" { + BeforeAll { + # $SemVer = "1.0.0-beta03+sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11" + $SemVer = @{ + Version = "1.0.0" + 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:/Output/MyModule" -Force + + Mock InitializeBuild { + # These are actually all the values that we need + [PSCustomObject]@{ + OutputDirectory = "TestDrive:/Output" + Name = "MyModule" + Version = [Version]"1.0.0" + Target = "CleanBuild" + ModuleBase = "TestDrive:/MyModule/" + CopyPaths = @() + Encoding = "UTF8" + PublicFilter = "Public/*.ps1" + } + } + Mock Convert-Path { $Path } + $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/Output/MyModule" + + Mock Get-ChildItem { + [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" } try { - Build-Module -Version "1.2.3" -Prerelease "pre-release" + Build-Module @SemVer } catch { + Pop-Location -StackName BuildModuleTest throw } + } + + It "Should build to an output folder with the simple version." { + Assert-MockCalled Remove-Item -Scope Context + Assert-MockCalled New-Item -Scope Context + } + It "Should update the module version to the simple version." { Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.Prerelease" -and $Value -eq "pre-release" - } + $PropertyName -eq "ModuleVersion" -and $Value -eq $ExpectedVersion + } -Scope Context + } + It "Should not change the module pre-release value" { + Assert-MockCalled Update-Metadata -Times 0 -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.Prerelease" + } -Scope Context + } + AfterAll { + Pop-Location -StackName BuildModuleTest } } + Context "Bug #70 Cannot build 1.2.3-pre-release" { + BeforeEach { + Push-Location TestDrive:/ -StackName BuildModuleTest + New-Item -ItemType Directory -Path TestDrive:/MyModule/ -Force + New-Item -ItemType Directory -Path "TestDrive:/$ExpectedVersion/" -Force - Context "When I Build-Module -SemVer 1.2.3-pre-release" { + Mock ImportModuleManifest { + [PSCustomObject]@{ + Name = "MyModule" + ModuleBase = "TestDrive:/MyModule/" + } + } - It "Should set the prerelese to 'pre-release'" { - Mock Update-Metadata -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.Prerelease" - } -MockWith { - $Value | Should -Be "pre-release" + $global:Mock_OutputPath = Convert-FolderSeparator "TestDrive:/MyModule/$ExpectedVersion" + + Mock Get-ChildItem { + [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" } + } + AfterEach { + Pop-Location -StackName BuildModuleTest + } - try { - Build-Module -SemVer "1.2.3-pre-release" - } catch { - throw + Context "When I Build-Module -Version 1.2.3 -Prerelease pre-release" { + It "Should set the prerelese to 'pre-release'" { + Mock Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.Prerelease" + } -MockWith { + $Value | Should -Be "pre-release" + } + + Mock GetBuildInfo { + # These are actually all the values that we need + [PSCustomObject]@{ + OutputDirectory = "TestDrive:/$Version" + Name = "MyModule" + Version = [Version]"1.2.3" + PreRelease = "pre-release" + Target = "CleanBuild" + SourcePath = "TestDrive:/MyModule/" + CopyPaths = @() + Encoding = "UTF8" + PublicFilter = "Public/*.ps1" + } + } + + + try { + Build-Module -Version "1.2.3" -Prerelease "pre-release" + } catch { + throw + } + + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.Prerelease" -and $Value -eq "pre-release" + } -Scope It } + } - Assert-MockCalled Update-Metadata -ParameterFilter { - $PropertyName -eq "PrivateData.PSData.Prerelease" -and $Value -eq "pre-release" + + Context "When I Build-Module -SemVer 1.2.3-pre-release" { + + It "Should set the prerelese to 'pre-release'" { + Mock Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.Prerelease" + } -MockWith { + $Value | Should -Be "pre-release" + } + + Mock GetBuildInfo { + # These are actually all the values that we need + [PSCustomObject]@{ + OutputDirectory = "TestDrive:/$Version" + Name = "MyModule" + Version = [Version]"1.2.3" + PreRelease = "pre-release" + Target = "CleanBuild" + SourcePath = "TestDrive:/MyModule/" + CopyPaths = @() + Encoding = "UTF8" + PublicFilter = "Public/*.ps1" + } + } + + try { + Build-Module -SemVer "1.2.3-pre-release" + } catch { + throw + } + + Assert-MockCalled Update-Metadata -ParameterFilter { + $PropertyName -eq "PrivateData.PSData.Prerelease" -and $Value -eq "pre-release" + } } } } } + } diff --git a/build.requires.psd1 b/build.requires.psd1 index 6001b64..a5d3175 100644 --- a/build.requires.psd1 +++ b/build.requires.psd1 @@ -2,7 +2,7 @@ @{ Configuration = ":[1.5.0, 2.0)" Metadata = ":[1.5.1, 2.0)" - Pester = ":[4.10.1, 5.0)" + Pester = ":[5.0, 6.0)" ModuleBuilder = ":[3.0.0, 4.0)" PSScriptAnalyzer = ":[1.21.0, 2.0)" InvokeBuild = ":[5.10.4, 6.0)" From ddb4e1046162c56e50daa5c1657e323e325c085e Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Thu, 6 Feb 2025 23:46:01 -0500 Subject: [PATCH 08/18] Fix paths --- Tests/Integration/Parameters.Tests.ps1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Tests/Integration/Parameters.Tests.ps1 b/Tests/Integration/Parameters.Tests.ps1 index 6206696..46edb30 100644 --- a/Tests/Integration/Parameters.Tests.ps1 +++ b/Tests/Integration/Parameters.Tests.ps1 @@ -1,14 +1,16 @@ #requires -Module ModuleBuilder -. $PSScriptRoot\..\Convert-FolderSeparator.ps1 Describe "Parameters.Set in build manifest" -Tag Integration { BeforeAll { - New-Item $PSScriptRoot\Result3\Parameters\ReadMe.md -ItemType File -Force - $Output = Build-Module $PSScriptRoot\Parameters\build.psd1 + . $PSScriptRoot/../Convert-FolderSeparator.ps1 + New-Item $PSScriptRoot/Result3/Parameters/ReadMe.md -ItemType File -Force + + $Output = Build-Module $PSScriptRoot/Parameters/build.psd1 if ($Output) { $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1") $Metadata = Import-Metadata $Output.Path } + } It "Passthru works" { @@ -16,7 +18,7 @@ Describe "Parameters.Set in build manifest" -Tag Integration { } It "The Target is Build" { - "$PSScriptRoot\Result3\Parameters\ReadMe.md" | Should -Exist + "$PSScriptRoot/Result3/Parameters/ReadMe.md" | Should -Exist } It "The version is set" { From 3d59679de481f5843dd853607e332c1e6ea5751a Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Thu, 6 Feb 2025 23:56:20 -0500 Subject: [PATCH 09/18] Let Pester handle after all --- Tests/Public/Build-Module.Tests.ps1 | 68 ++++++++--------------------- 1 file changed, 17 insertions(+), 51 deletions(-) diff --git a/Tests/Public/Build-Module.Tests.ps1 b/Tests/Public/Build-Module.Tests.ps1 index b5d2e51..c3164c5 100644 --- a/Tests/Public/Build-Module.Tests.ps1 +++ b/Tests/Public/Build-Module.Tests.ps1 @@ -303,12 +303,10 @@ Describe "Build-Module" { [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" } - try { - Build-Module -SemVer $SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + Build-Module -SemVer $SemVer + } + AfterAll { + Pop-Location -StackName BuildModuleTest } It "Should build to an output folder with the simple version." { @@ -336,12 +334,7 @@ Describe "Build-Module" { # If there's no release notes, but it was left uncommented Mock Get-Metadata { "" } - try { - Build-Module -SemVer $SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + Build-Module -SemVer $SemVer Assert-MockCalled Update-Metadata -ParameterFilter { $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq "MyModule v$SemVer" @@ -354,12 +347,7 @@ Describe "Build-Module" { Multi-line Release Notes With a prefix carriage return" } - try { - Build-Module -SemVer $SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + Build-Module -SemVer $SemVer Assert-MockCalled Update-Metadata -ParameterFilter { $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq " @@ -368,9 +356,6 @@ Describe "Build-Module" { With a prefix carriage return" } } - AfterAll { - Pop-Location -StackName BuildModuleTest - } } Context "Setting the version and pre-release" { @@ -414,12 +399,11 @@ Describe "Build-Module" { [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" } - try { - Build-Module @SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + Build-Module @SemVer + } + + AfterAll { + Pop-Location -StackName BuildModuleTest } It "Should build to an output folder with the simple version." { @@ -448,12 +432,7 @@ Describe "Build-Module" { # If there's no release notes, but it was left uncommented Mock Get-Metadata { "" } - try { - Build-Module @SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + Build-Module @SemVer Assert-MockCalled Update-Metadata -ParameterFilter { $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and @@ -467,12 +446,7 @@ Describe "Build-Module" { Multi-line Release Notes With a prefix carriage return" } - try { - Build-Module @SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + Build-Module @SemVer Assert-MockCalled Update-Metadata -ParameterFilter { $PropertyName -eq "PrivateData.PSData.ReleaseNotes" -and $Value -eq " @@ -481,9 +455,6 @@ Describe "Build-Module" { With a prefix carriage return" } } - AfterAll { - Pop-Location -StackName BuildModuleTest - } } Context "Setting the version with no pre-release" { @@ -518,12 +489,10 @@ Describe "Build-Module" { [IO.FileInfo]"$TestDrive/MyModule/Public/Get-MyInfo.ps1" } - try { - Build-Module @SemVer - } catch { - Pop-Location -StackName BuildModuleTest - throw - } + Build-Module @SemVer + } + AfterAll { + Pop-Location -StackName BuildModuleTest } It "Should build to an output folder with the simple version." { @@ -541,9 +510,6 @@ Describe "Build-Module" { $PropertyName -eq "PrivateData.PSData.Prerelease" } -Scope Context } - AfterAll { - Pop-Location -StackName BuildModuleTest - } } Context "Bug #70 Cannot build 1.2.3-pre-release" { From 827443eedc7917e04cebc2c483c9bec660f3d639 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 7 Feb 2025 00:01:33 -0500 Subject: [PATCH 10/18] Fixing scope for the BuildInfo --- Tests/Public/Build-Module.Tests.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/Public/Build-Module.Tests.ps1 b/Tests/Public/Build-Module.Tests.ps1 index c3164c5..4c55bd0 100644 --- a/Tests/Public/Build-Module.Tests.ps1 +++ b/Tests/Public/Build-Module.Tests.ps1 @@ -281,7 +281,8 @@ Describe "Build-Module" { [PSCustomObject]@{ OutputDirectory = "TestDrive:/Output" SourcePath = "TestDrive:/MyModule/" - SemVer = $SemVer ?? "1.0.0-beta03+sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11" + Version = [Version]"1.0.0" + Prerelease = "beta03" Target = "CleanBuild" CopyPaths = @() Encoding = "UTF8" From 4e06f10dc8509466d02ffb5035951da7d216e876 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 7 Feb 2025 00:11:20 -0500 Subject: [PATCH 11/18] Fixing semver test --- Tests/Public/Build-Module.Tests.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Public/Build-Module.Tests.ps1 b/Tests/Public/Build-Module.Tests.ps1 index 4c55bd0..4dacdcb 100644 --- a/Tests/Public/Build-Module.Tests.ps1 +++ b/Tests/Public/Build-Module.Tests.ps1 @@ -281,6 +281,7 @@ Describe "Build-Module" { [PSCustomObject]@{ OutputDirectory = "TestDrive:/Output" SourcePath = "TestDrive:/MyModule/" + SemVer = "1.0.0-beta03+sha.22c35ffff166f34addc49a3b80e622b543199cc5.Date.2018-10-11" Version = [Version]"1.0.0" Prerelease = "beta03" Target = "CleanBuild" From 0bd293bad947e1e2d9ed7e2a0e6d0a239dae49b2 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 7 Feb 2025 00:29:00 -0500 Subject: [PATCH 12/18] Fix the last set of tests broken by Pester 5 scope --- Tests/Integration/Parameters.Tests.ps1 | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Tests/Integration/Parameters.Tests.ps1 b/Tests/Integration/Parameters.Tests.ps1 index 46edb30..82726f0 100644 --- a/Tests/Integration/Parameters.Tests.ps1 +++ b/Tests/Integration/Parameters.Tests.ps1 @@ -4,28 +4,25 @@ Describe "Parameters.Set in build manifest" -Tag Integration { BeforeAll { . $PSScriptRoot/../Convert-FolderSeparator.ps1 New-Item $PSScriptRoot/Result3/Parameters/ReadMe.md -ItemType File -Force - - $Output = Build-Module $PSScriptRoot/Parameters/build.psd1 - if ($Output) { - $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1") - $Metadata = Import-Metadata $Output.Path - } - } - It "Passthru works" { + It "Passthru is read from the build manifest" { + $Output = Build-Module "$PSScriptRoot/Parameters/build.psd1" $Output | Should -Not -BeNullOrEmpty + $Output.Path | Convert-FolderSeparator | Should -Be (Convert-FolderSeparator "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psd1") } It "The Target is Build" { - "$PSScriptRoot/Result3/Parameters/ReadMe.md" | Should -Exist + "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psm1" | Should -Exist } It "The version is set" { + $Metadata = Import-Metadata "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psd1" $Metadata.ModuleVersion | Should -Be "3.0.0" } It "The PreRelease is set" { + $Metadata = Import-Metadata "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psd1" $Metadata.PrivateData.PSData.Prerelease | Should -Be 'alpha001' } } From f6af40e96465230f61f8e6c7ec2dddc0632aa2b6 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 7 Feb 2025 00:45:55 -0500 Subject: [PATCH 13/18] Add verbose to this test that won't pass --- Tests/Integration/Parameters.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Integration/Parameters.Tests.ps1 b/Tests/Integration/Parameters.Tests.ps1 index 82726f0..d19de2b 100644 --- a/Tests/Integration/Parameters.Tests.ps1 +++ b/Tests/Integration/Parameters.Tests.ps1 @@ -7,13 +7,13 @@ Describe "Parameters.Set in build manifest" -Tag Integration { } It "Passthru is read from the build manifest" { - $Output = Build-Module "$PSScriptRoot/Parameters/build.psd1" + $Output = Build-Module (Convert-FolderSeparator "$PSScriptRoot/Parameters/build.psd1") -Verbose $Output | Should -Not -BeNullOrEmpty $Output.Path | Convert-FolderSeparator | Should -Be (Convert-FolderSeparator "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psd1") } It "The Target is Build" { - "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psm1" | Should -Exist + Convert-FolderSeparator "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psm1" | Should -Exist } It "The version is set" { From 4741dec6a034fdc9e128388316b508a1a30b659a Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 7 Feb 2025 01:12:26 -0500 Subject: [PATCH 14/18] More tweaks to that failing test --- Tests/Integration/Parameters.Tests.ps1 | 12 +++++++++--- Tests/Integration/Result3/Parameters/ReadMe.md | 0 2 files changed, 9 insertions(+), 3 deletions(-) delete mode 100644 Tests/Integration/Result3/Parameters/ReadMe.md diff --git a/Tests/Integration/Parameters.Tests.ps1 b/Tests/Integration/Parameters.Tests.ps1 index d19de2b..4473731 100644 --- a/Tests/Integration/Parameters.Tests.ps1 +++ b/Tests/Integration/Parameters.Tests.ps1 @@ -1,9 +1,14 @@ #requires -Module ModuleBuilder -Describe "Parameters.Set in build manifest" -Tag Integration { +Describe "Parameters" -Tag Integration { BeforeAll { . $PSScriptRoot/../Convert-FolderSeparator.ps1 - New-Item $PSScriptRoot/Result3/Parameters/ReadMe.md -ItemType File -Force + # Make sure the Result3 folder is really clean ;) + if (Test-Path $PSScriptRoot/Result3) { + Remove-Item $PSScriptRoot/Result3 -Recurse -Force + } + # Throw in an extra file that would get cleaned up normally ... + New-Item $PSScriptRoot/Result3/Parameters/3.0.0/DeleteMe.md -ItemType File -Force } It "Passthru is read from the build manifest" { @@ -12,7 +17,8 @@ Describe "Parameters.Set in build manifest" -Tag Integration { $Output.Path | Convert-FolderSeparator | Should -Be (Convert-FolderSeparator "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psd1") } - It "The Target is Build" { + It "The target is 'Build' (not CleanBuild) so pre-created extra files get left behind" { + Convert-FolderSeparator "$PSScriptRoot/Result3/Parameters/3.0.0/DeleteMe.md" | Should -Exist Convert-FolderSeparator "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psm1" | Should -Exist } diff --git a/Tests/Integration/Result3/Parameters/ReadMe.md b/Tests/Integration/Result3/Parameters/ReadMe.md deleted file mode 100644 index e69de29..0000000 From 40bac9b7e163411c160a910b0d0ca61770cd8186 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 7 Feb 2025 01:13:46 -0500 Subject: [PATCH 15/18] Bump earthfile to 9.0 (PowerShell 7.5) --- Earthfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Earthfile b/Earthfile index 2a0eae7..bea1238 100644 --- a/Earthfile +++ b/Earthfile @@ -1,6 +1,6 @@ VERSION 0.7 IMPORT github.com/poshcode/tasks -FROM mcr.microsoft.com/dotnet/sdk:7.0 +FROM mcr.microsoft.com/dotnet/sdk:9.0 WORKDIR /work ARG --global EARTHLY_GIT_ORIGIN_URL From 89e61fcaacf95db9fbd5d5ebf0788795dca14a52 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 7 Feb 2025 01:21:11 -0500 Subject: [PATCH 16/18] Bump the version in Integration/Parameters.psd1 --- Tests/Integration/Parameters/Parameters.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Integration/Parameters/Parameters.psd1 b/Tests/Integration/Parameters/Parameters.psd1 index fa936e4..b9f4d2b 100644 --- a/Tests/Integration/Parameters/Parameters.psd1 +++ b/Tests/Integration/Parameters/Parameters.psd1 @@ -1,6 +1,6 @@ @{ # The module version should be SemVer.org compatible - ModuleVersion = "1.0.0" + ModuleVersion = "3.0.0" # PrivateData is where all third-party metadata goes PrivateData = @{ From 975a7ab42573a8580fad7d6553fb2c625ba21457 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 7 Feb 2025 01:23:30 -0500 Subject: [PATCH 17/18] Remove the upload that doesn't exist anyway --- .github/workflows/build.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e39e38e..aba5ae4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,16 +42,13 @@ jobs: name: TestResults path: Modules/ModuleBuilder-TestResults - - uses: actions/upload-artifact@v4 - with: - name: Packages - path: Modules/ModuleBuilder-Packages - + # These ones are just for the test matrix - name: Upload Tests uses: actions/upload-artifact@v4 with: name: PesterTests path: ${{github.workspace}}/Tests + - name: Upload build.requires.psd1 uses: actions/upload-artifact@v4 with: From 9d06dd8fe35b81366dc5e7286740b1da3ddbc3e9 Mon Sep 17 00:00:00 2001 From: Joel Bennett Date: Fri, 7 Feb 2025 19:12:49 -0500 Subject: [PATCH 18/18] Try to fix path problems so we test the right module --- .github/workflows/build.yml | 15 +++++++++++++-- Tests/Integration/Parameters.Tests.ps1 | 10 +++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aba5ae4..3eb5114 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,7 +66,7 @@ jobs: uses: actions/download-artifact@v4 with: name: ModuleBuilder - path: Modules/ModuleBuilder + path: Modules/ModuleBuilder # /home/runner/work/ModuleBuilder/ModuleBuilder/Modules/ModuleBuilder - name: Download Pester Tests uses: actions/download-artifact@v4 with: @@ -78,6 +78,17 @@ jobs: name: build.requires.psd1 - name: ⚡ Install PowerShell Modules uses: JustinGrote/ModuleFast-action@v0.0.1 + - name: Put Build output in PATH + shell: pwsh + run: | # PowerShell + Convert-Path Modules -OutVariable BuiltModules + Add-Content -Path $env:GITHUB_PATH -Value $BuiltModules -Encoding utf8 + # Uninstall the "installed" copy of ModuleBuilder + Get-Module -Name ModuleBuilder -List | Where ModuleBase -notmatch ([regex]::escape($pwd)) | Split-Path | Remove-Item -Recurse -Force + - name: Put Build output in PATH + shell: pwsh + run: | # PowerShell + $Env:PATH -split ([IO.Path]::PathSeparator) | Out-Host - name: Invoke Pester Tests id: pester uses: zyborg/pester-tests-report@v1 @@ -90,7 +101,7 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} - name: dump test results shell: pwsh - run: | + run: | # PowerShell Write-Host 'Total Tests Executed...: ${{ steps.pester.outputs.total_count }}' Write-Host 'Total Tests PASSED.....: ${{ steps.pester.outputs.passed_count }}' Write-Host 'Total Tests FAILED.....: ${{ steps.pester.outputs.failed_count }}' diff --git a/Tests/Integration/Parameters.Tests.ps1 b/Tests/Integration/Parameters.Tests.ps1 index 4473731..2cec9c9 100644 --- a/Tests/Integration/Parameters.Tests.ps1 +++ b/Tests/Integration/Parameters.Tests.ps1 @@ -9,10 +9,18 @@ Describe "Parameters" -Tag Integration { } # Throw in an extra file that would get cleaned up normally ... New-Item $PSScriptRoot/Result3/Parameters/3.0.0/DeleteMe.md -ItemType File -Force + + Write-Host "Module Under Test:" + Get-Command Build-Module + | Get-Module -Name { $_.Source } + | Get-Item + | Out-Host } It "Passthru is read from the build manifest" { - $Output = Build-Module (Convert-FolderSeparator "$PSScriptRoot/Parameters/build.psd1") -Verbose + Build-Module (Convert-FolderSeparator "$PSScriptRoot/Parameters/build.psd1") -Verbose -OutVariable Output + | Out-Host + $Output | Should -Not -BeNullOrEmpty $Output.Path | Convert-FolderSeparator | Should -Be (Convert-FolderSeparator "$PSScriptRoot/Result3/Parameters/3.0.0/Parameters.psd1") }