diff --git a/.github/workflows/github.yml b/.github/workflows/github.yml deleted file mode 100644 index 43bb7df4e..000000000 --- a/.github/workflows/github.yml +++ /dev/null @@ -1,277 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: PSKoans CI - -# Controls when the action will run. -on: - # Triggers the workflow on push or pull request events but only for the main branch - push: - branches: - - main - tags: - - '*' - pull_request: - branches: - - main - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -env: - NupkgArtifactName: 'PSKoans.nupkg' - ModuleArtifactName: 'PSKoans' - PesterInfoFileName: 'PesterVersion.txt' - PesterInfoFilePath: '$GITHUB_WORKSPACE/PesterVersion.txt' - -jobs: - - create_changelog: - name: 'Upload Changelog' - - # Don't run this step for pull requests - if: ${{ github.head_ref == '' }} - runs-on: ubuntu-latest - - env: - FilePath: '$GITHUB_WORKSPACE/Changelog.md' - - steps: - - uses: actions/checkout@v2 - - - name: Generate Changelog - shell: pwsh - run: ./Build/New-Changelog.ps1 -Path "${{ env.FilePath }}" -ApiKey "${{ secrets.GITHUB_TOKEN }}" - - - name: Upload Changelog - uses: actions/upload-artifact@v2.2.3 - with: - name: Changelog.md - path: $FilePath - - build: - name: 'Build Module' - runs-on: ubuntu-latest - - env: - FileSystemDeploymentPath: '$GITHUB_WORKSPACE/Deploy/FileSystem' - BuiltModulePath: '$GITHUB_WORKSPACE/Deploy/PSKoans' - # This needs to be set by the script which creates the nupkg - NupkgPath: '' - - steps: - - uses: actions/checkout@v2 - - - name: Install Dependencies - shell: pwsh - run: | - $Params = @{ - Scope = 'CurrentUser' - Force = $true - } - - Write-Host "Installing Modules" - $Params.Name = @( 'PSDeploy', 'BuildHelpers', 'PlatyPS' ) - $Params | Out-String | Write-Host - Install-Module @Params - - $Params.Name = 'Pester' - $Params.SkipPublisherCheck = $true - $Params.MinimumVersion = $Params.MinimumVersion = (Get-Module -ListAvailable ./PSKoans).RequiredModules.Where{$_.Name -eq 'Pester'}.Version - $Params | Out-String | Write-Host - Install-Module @Params - - $Params.MinimumVersion | Set-Content -Path "${{ env.PesterInfoFilePath }}" - - $Params.Remove('SkipPublisherCheck') - $Params.Remove('MinimumVersion') - - $Params.Name = 'EZOut' - $Params.AllowClobber = $true - $Params | Out-String | Write-Host - Install-Module @Params - - - name: Setup Environment - shell: pwsh - run: ./Build/Initialize-Environment.ps1 - - - name: Build Module - shell: pwsh - run: ./Build/Build-Module.ps1 - - - name: Upload Module Artifact - uses: actions/upload-artifact@v2.2.3 - with: - name: $ModuleArtifactName - path: $BuiltModulePath - - - name: Upload Pester Version Artifact - uses: actions/upload-artifact@v2.2.3 - with: - name: $PesterInfoFileName - path: $PesterInfoFilePath - - - name: Generate Nupkg - shell: pwsh - run: | - ./Build/Register-FileSystemRepository.ps1 -Path '${{ env.FileSystemDeploymentPath }}' -Name 'FileSystem' - ./Deploy/Publish.ps1 -Key 'filesystem' -Path '${{ env.FileSystemDeploymentPath }}' -OutputDirectory '${{ env.FileSystemDeploymentPath }}' - - - name: Upload Nupkg Artifact - uses: actions/upload-artifact@v2.2.3 - with: - name: $NupkgArtifactName - path: $NupkgPath - - test: - name: "Test Module" - needs: build - - strategy: - matrix: - os: - - windows-latest - - macOS-latest - - ubuntu-latest - - runs-on: ${{ matrix.os }} - - env: - PackageDownloadPath: '$GITHUB_WORKSPACE/Module' - PSRepositoryName: 'FileSystem' - # The following variables MUST be set in Invoke-ModuleTests.ps1 - TestFile: '' - CodeCoverageFile: '' - ModuleFolders: '' - - steps: - - uses: actions/checkout@v2 - - - name: Install Dependencies - shell: pwsh - run: | - $Params = @{ - Scope = 'CurrentUser' - Force = $true - } - - Write-Host "Installing Modules" - $Params.Name = @( 'PSDeploy', 'BuildHelpers', 'PlatyPS' ) - $Params | Out-String | Write-Host - Install-Module @Params - - $Params.Name = 'Pester' - $Params.SkipPublisherCheck = $true - $Params.MinimumVersion = $Params.MinimumVersion = (Get-Module -ListAvailable ./PSKoans).RequiredModules.Where{$_.Name -eq 'Pester'}.Version - $Params | Out-String | Write-Host - Install-Module @Params - - $Params.Remove('SkipPublisherCheck') - $Params.Remove('MinimumVersion') - - $Params.Name = 'EZOut' - $Params.AllowClobber = $true - $Params | Out-String | Write-Host - Install-Module @Params - - - name: Setup Environment - shell: pwsh - run: ./Build/Initialize-Environment.ps1 - - - name: Register FileSystem Repository - shell: pwsh - run: ./Build/Register-FileSystemRepository.ps1 -Path '${{ env.PackageDownloadPath }}' -Name '${{ env.PSRepositoryName }}' - - - name: Download Module Nupkg - uses: actions/download-artifact@v2.0.9 - with: - name: $NupkgArtifactName - path: $PackageDownloadPath - - - name: Download Pester Version Information - uses: actions/download-artifact@v2.0.9 - with: - name: $PesterInfoFileName - path: $PesterInfoFilePath - - - name: Install Module from Nupkg - shell: pwsh - run: | - $pesterParams = @{ - Name = 'Pester' - MinimumVersion = Get-Content -Path "${{ env.PesterInfoFilePath }}" - ProviderName = 'NuGet' - Path = '${{ env.PackageDownloadPath }}' - Force = $true - Source = 'PSGallery' - } - Register-PackageSource -Name PSGallery -ProviderName NuGet -Location https://www.powershellgallery.com/api/v2 -Force - Save-Package @pesterParams | Select-Object -Property Name, Version, Status, Source - Install-Module PSKoans -Repository ${{ env.PSRepositoryName }} -Force -Scope CurrentUser - - - name: Run Pester Tests - shell: pwsh - run: ./Build/Invoke-ModuleTests.ps1 - - - name: Publish Test Results - if: ${{ always() }} - uses: MirageNet/nunit-reporter@v1.0.5 - with: - access-token: ${{ secrets.GITHUB_TOKEN }} - path: '$GITHUB_WORKSPACE\$TestResults' - - - name: Generate Code Coverage - uses: danielpalme/ReportGenerator-GitHub-Action@4.8.8 - with: - reports: '$GITHUB_WORKSPACE\$CodeCoverageFile' - targetdir: '$GITHUB_WORKSPACE\coveragereports' - sourcedirs: $SourceFolders - title: PSKoans Code Coverage - - - name: Publish Code Coverage artifacts - uses: actions/upload-artifact@v2.2.3 - with: - name: 'Code Coverage Reports' - path: '$GITHUB_WORKSPACE\coveragereports' - - publish: - needs: test - if: ${{ success() && startsWith( 'refs/tags/', env.GITHUB_REF ) }} - - runs-on: ubuntu-latest - - env: - BuiltModulePath: '$GITHUB_WORKSPACE/Deploy/PSKoans' - GalleryDeploymentPath: '$GITHUB_WORKSPACE/Deploy/PSGallery' - # This variable must be set by the script - TagName: '' - - steps: - - uses: actions/checkout@v2 - - - name: Download Module Artifact - uses: actions/download-artifact@v2.0.9 - with: - name: $ModuleArtifactName - path: $BuiltModulePath - - - name: Deploy Module to PSGallery - shell: pwsh - run: ./Deploy/Publish.ps1 -ApiKey '${{ secrets.PSGALLERYAPIKEY }}' -Path '${{ env.GalleryDeploymentPath }}' - - - name: Set Release Tag Name - shell: pwsh - run: | - $tagName = ("${{ env.GITHUB_REF }}" -replace '^refs/tags/').Trim() - "TagName=$tagname" | Add-Content -Path '${{ env.GITHUB_ENV }}' - - - name: Download Artifacts - uses: actions/download-artifact@v2.0.9 - with: - path: '$GITHUB_WORKSPACE/artifacts' - - - name: Update Release with Artifacts & Changelog - uses: Roang-zero1/github-create-release-action@v2.1.0 - with: - created_tag: $TagName - changelog_file: '$GITHUB_WORKSPACE/artifacts/Changelog.md' - release_title: 'PSKoans Release $TagName' diff --git a/.gitignore b/.gitignore index 749a82be7..679f9dc55 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,5 @@ PSKoans.psproj PSKoans/*/PSKoans-help.xml Output/** -Tests/out/** +tests/out/** testResults.xml diff --git a/Build/Build-Module.ps1 b/Build/Build-Module.ps1 deleted file mode 100644 index 1ee5a3b8d..000000000 --- a/Build/Build-Module.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -# Grab nuget bits, set build variables, start build. -Get-PackageProvider -Name NuGet -ForceBootstrap > $null - -# Create format.ps1xml file -& "$PSScriptRoot/../PSKoans.ezformat.ps1" - -Import-Module "$env:PROJECTROOT/PSKoans" - -Set-BuildEnvironment - -$Lines = '-' * 70 - -Write-Host $Lines -Write-Host "STATUS: Generating External Help and Building Module" -Write-Host $Lines - -# Load the module, read the exported functions, update the psd1 FunctionsToExport -Set-ModuleFunction - -# Bump the module version if we didn't already -try { - [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 - - $GalleryVersion = Get-NextNugetPackageVersion -Name $env:BHProjectName -ErrorAction Stop - $GithubVersion = Get-Metadata -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -ErrorAction Stop - - if ($GalleryVersion -ge $GithubVersion) { - Update-Metadata -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -Value $GalleryVersion -ErrorAction Stop - } -} -catch { - Write-Host "Failed to update version for '$env:BHProjectName': $_." - Write-Host "Continuing with existing version." -} - -# Build external help files from Platyps MD files -New-ExternalHelp -Path "$env:PROJECTROOT/docs/" -OutputPath "$env:PROJECTROOT/PSKoans/en" - -Copy-Item -Path "$env:PROJECTROOT/PSKoans" -Destination $env:BUILTMODULEPATH -Recurse -PassThru | - Where-Object { -not $_.PSIsContainer } diff --git a/Build/Initialize-Environment.ps1 b/Build/Initialize-Environment.ps1 deleted file mode 100644 index 9576a58d6..000000000 --- a/Build/Initialize-Environment.ps1 +++ /dev/null @@ -1,14 +0,0 @@ -Get-PackageProvider -Name NuGet -ForceBootstrap > $null - -Set-BuildEnvironment - -$ProjectRoot = Resolve-Path -Path "$PSScriptRoot/.." -Write-Host "##vso[task.setvariable variable=ProjectRoot]$ProjectRoot" - -$Lines = '-' * 70 - -Write-Host $Lines -Write-Host "Repository Branch: $env:BUILD_SOURCEBRANCHNAME ($env:BUILD_SOURCEBRANCH)" -Write-Host "Build System Details:" -Get-Item 'Env:BH*' | Out-String | Write-Host -Write-Host $Lines diff --git a/Build/Invoke-ModuleTests.ps1 b/Build/Invoke-ModuleTests.ps1 deleted file mode 100644 index 70fe1c365..000000000 --- a/Build/Invoke-ModuleTests.ps1 +++ /dev/null @@ -1,51 +0,0 @@ -$Lines = '-' * 70 - -Import-Module 'PSKoans' - -$PesterVersion = (Get-Module -Name Pester).Version -$PSVersion = $PSVersionTable.PSVersion - -Write-Host $Lines -Write-Host "TEST: PowerShell Version: $PSVersion" -Write-Host "TEST: Pester Version: $PesterVersion" -Write-Host $Lines - -try { - # Try/Finally required since -CI will exit with exit code on failure. - Invoke-Pester -Path "$env:PROJECTROOT" -CI -Output Normal -} -finally { - $Timestamp = Get-Date -Format "yyyyMMdd-hhmmss" - $TestFile = "PS${PSVersion}_${TimeStamp}_PSKoans.TestResults.xml" - $CodeCoverageFile = "PS${PSVersion}_${TimeStamp}_PSKoans.CodeCoverage.xml" - - $ModuleFolders = @( - Get-Item -Path "$env:PROJECTROOT/PSKoans" - Get-ChildItem -Path "$env:PROJECTROOT/PSKoans" -Directory -Recurse | - Where-Object FullName -NotMatch '[\\/]Tests[\\/]|[\\/]PSKoans[\\/]Koans[\\/]' - ).FullName -join ';' - - $AzurePipelines = $env:BUILD_SOURCESDIRECTORY -and $env:BUILD_BUILDNUMBER - $GithubActions = [bool]$env:GITHUB_WORKSPACE - - if ($AzurePipelines) { - # Tell Azure what the test results & code coverage file names will be - Write-Host "##vso[task.setvariable variable=TestResults]$TestFile" - Write-Host "##vso[task.setvariable variable=CodeCoverageFile]$CodeCoverageFile" - Write-Host "##vso[task.setvariable variable=SourceFolders]$ModuleFolders" - - # Move files generated from Invoke-Pester to expected location - Move-Item -Path './testResults.xml' -Destination "$env:BUILD_ARTIFACTSTAGINGDIRECTORY/$TestFile" - Move-Item -Path './coverage.xml' -Destination "$env:BUILD_ARTIFACTSTAGINGDIRECTORY/$CodeCoverageFile" - } - elseif ($GithubActions) { - @( - "TestResults=$TestFile" - "CodeCoverageFile=$CodeCoverageFile" - "SourceFolders=$ModuleFolders" - ) | Add-Content -Path $env:GITHUB_ENV - - Move-Item -Path './testResults.xml' -Destination "$env:GITHUB_WORKSPACE/$TestFile" - Move-Item -Path './coverage.xml' -Destination "$env:GITHUB_WORKSPACE/$CodeCoverageFile" - } -} diff --git a/Build/New-Changelog.ps1 b/Build/New-Changelog.ps1 deleted file mode 100644 index 86f821ad4..000000000 --- a/Build/New-Changelog.ps1 +++ /dev/null @@ -1,122 +0,0 @@ -<# - .SYNOPSIS - Creates a Markdown changelog file with table formatting. - - .DESCRIPTION - Uses `git log` to compare the current commit to the last tagged commit, - and parses the output into CSV data. This is then processed and email - addresses of commit authors are used to retrieve their Github - usernames, if available. - - The final result is stored in a Markdown plaintext file at the - designated path. - - .PARAMETER Path - The file location to save the markdown text to. The file will be - overwritten if it already contains data. - - .PARAMETER CommitID - The commit tag or hash that is used to identify the commit to - compare with. By default, the last value given by `git tag` - will be used. - - .PARAMETER ApiKey - The Github API key to use when looking up commit authors' - Github user names. - - .EXAMPLE - New-Changelog.ps1 -Path File.md -ApiKey $GHApiKey - - Retrieves the commits since the last tagged commit and creates a - Markdown-formatted plaintext file called File.md in the current - location. - - .NOTES - The Github API limitation of 60 requests per minute is -barely- - usable without authentication. Authenticated requests have a - substantially higher limit on requests per minute. -#> -[CmdletBinding()] -param( - [Parameter(Mandatory, Position = 0)] - [ValidateScript( { Test-Path $_ -IsValid })] - [string] - $Path, - - [Parameter(Position = 1)] - [ValidatePattern('[a-f0-9]{6,40}|v?(\d+\.)+\d+(-\w+\d+)?')] - [string] - $CommitID = (git tag | Select-Object -Last 1), - - [Parameter()] - [Alias('OauthToken')] - [string] - $ApiKey -) - -begin { - if ($ApiKey) { - $RequestParams = @{ - SessionVariable = 'AuthSession' - Uri = 'https://api.github.com/' - Headers = @{ Authorization = "token $ApiKey" } - } - Invoke-RestMethod @RequestParams | Out-String | Write-Verbose - } -} -process { - $RequestParams = if ($AuthSession) { @{ WebSession = $AuthSession } } else { @{ } } - $Args = @( - '--no-pager' - 'log' - '--first-parent' - "$CommitID..HEAD" - '--format="%H~%aN~%aE~%s"' - '--' - '.' - '":(exclude)*.md"' - ) - $Commits = & git @args | ConvertFrom-Csv -Delimiter '~' -Header Hash, Name, Email, Subject - - $NameTable = @{ } - foreach ($Item in ($Commits | Sort-Object -Property Email -Unique)) { - $RequestParams['Uri'] = "https://api.github.com/search/users?q=$($Item.Email)+in:email" - - do { - $result = $null - $attempt = 0 - try { - $result = Invoke-RestMethod @RequestParams -ErrorAction Stop - } - catch { - # If this errors, we have probably hit Github's per-minute API restriction, - # so wait at least 30 seconds before retry. - Start-Sleep -Seconds 30 - $attempt++ - } - } while ($attempt -lt 3 -and -not $result) - - $NameTable[$Item.Email] = if ($result.total_count) { $result.items[0].login } else { $Item.Name } - } - - $CsvString = $Commits | - Select-Object -Property @( - @{ Name = 'Hash'; Expression = { $_.Hash.Substring(0, 7) } } - @{ Name = 'Name'; Expression = { $NameTable[$_.Email] } } - 'Subject' - ) | - ConvertTo-Csv -Delimiter '|' - - $TableRows = $CsvString -replace '"', ' ' -replace '^|$', '|' - - $MarkdownTable = @( - # Header Row Only - $TableRows | Select-Object -First 1 - # Adding Markdown table column alignments - "| :--: | :--- | :--- |" - # Data Rows - $TableRows | Select-Object -Skip 1 - ) - - $MarkdownTable | Set-Content -Path $Path -} diff --git a/Build/Register-FileSystemRepository.ps1 b/Build/Register-FileSystemRepository.ps1 deleted file mode 100644 index 2a79a77f0..000000000 --- a/Build/Register-FileSystemRepository.ps1 +++ /dev/null @@ -1,25 +0,0 @@ -[CmdletBinding()] -param( - [Parameter(Mandatory)] - [string] - $Path, - - [Parameter(Mandatory)] - [string] - $Name -) - -$RepositoryFolder = if (-not (Test-Path $Path)) { - New-Item -ItemType Directory -Path $Path -Force -} -else { - Get-Item -Path $Path -} - -$Params = @{ - Name = $Name - SourceLocation = $RepositoryFolder.FullName - ScriptSourceLocation = $RepositoryFolder.FullName - InstallationPolicy = 'Trusted' -} -Register-PSRepository @Params diff --git a/Deploy/FileSystem/PSKoans.psdeploy.ps1 b/Deploy/FileSystem/PSKoans.psdeploy.ps1 deleted file mode 100644 index e8a6734a8..000000000 --- a/Deploy/FileSystem/PSKoans.psdeploy.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -Deploy Module { - By PSGalleryModule { - FromSource "$PSScriptRoot/../PSKoans" - To FileSystem - WithOptions @{ - ApiKey = 'FileSystem' - } - } -} diff --git a/Deploy/PSGallery/PSKoans.psdeploy.ps1 b/Deploy/PSGallery/PSKoans.psdeploy.ps1 deleted file mode 100644 index 8aae78b5d..000000000 --- a/Deploy/PSGallery/PSKoans.psdeploy.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -Deploy Module { - By PSGalleryModule { - FromSource "$PSScriptRoot/../PSKoans" - To PSGallery - WithOptions @{ - ApiKey = $ENV:NugetApiKey - } - } -} diff --git a/Deploy/Publish.ps1 b/Deploy/Publish.ps1 deleted file mode 100644 index 62c5a9443..000000000 --- a/Deploy/Publish.ps1 +++ /dev/null @@ -1,65 +0,0 @@ -[CmdletBinding()] -param( - [string] - $Key, - - [string] - $Path, - - [string] - $OutputDirectory -) - -$env:NugetApiKey = $Key - -if ($OutputDirectory) { - Import-Module "$PSScriptRoot/PSKoans" - $Module = Get-Module -Name PSKoans - $Dependencies = @( - $Module.RequiredModules.Name - $Module.NestedModules.Name - ).Where{ $_ } - - foreach ($Module in $Dependencies) { - Publish-Module -Name $Module -Repository FileSystem -NugetApiKey "Test-Publish" - } -} - -$HelpFile = Get-ChildItem -Path "$PSScriptRoot/PSKoans" -File -Recurse -Filter '*-help.xml' - -if ($HelpFile.Directory -notmatch 'en|\w{1,2}(-\w{1,2})?') { - $PSCmdlet.WriteError( - [System.Management.Automation.ErrorRecord]::new( - [IO.FileNotFoundException]::new("Help files are missing!"), - 'Build.HelpXmlMissing', - 'ObjectNotFound', - $null - ) - ) - - exit 404 -} - -$DeploymentParams = @{ - Path = $Path - Recurse = $false - Force = $true - Verbose = $true -} - -Invoke-PSDeploy @DeploymentParams - -Get-ChildItem -Path $DeploymentParams['Path'] | Out-String | Write-Host - -$Nupkg = Get-ChildItem -Path $DeploymentParams['Path'] -Filter 'PSKoans*.nupkg' | ForEach-Object FullName - -$AzurePipelines = $env:BUILD_SOURCESDIRECTORY -and $env:BUILD_BUILDNUMBER -$GithubActions = [bool]$env:GITHUB_WORKSPACE - -if ($AzurePipelines) { - Write-Host "##vso[task.setvariable variable=NupkgPath]$Nupkg" -} - -if ($GithubActions) { - "NupkgPath=$Nupkg" | Add-Content -Path $env:GITHUB_ENV -} diff --git a/README.md b/README.md index 108700517..ad7dd2b7d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # PowerShell Koans -| | Build Status | -| ------------------------------------ | ----------------------------------------------------------------------------------------------- | -| [![PSKoans Logo][logo-64]][logo-svg] | [![Build Status][build-badge]][build-link]
[![Coverage Status][coverage-badge]][build-link] | +[![PSKoans Logo][logo-64]][logo-svg] ## About the Author @@ -57,7 +55,7 @@ Install-Module PSKoans -Scope CurrentUser ### Or Download the Repo -1. `git clone` the repository into your desired directory, or download the module zip file from the build artifacts available on [this page](https://dev.azure.com/SallowCode/PSKoans/_build/latest?definitionId=1). +1. `git clone` the repository into your desired directory. 2. From a normal powershell session run `Get-ChildItem -Recurse | Unblock-File` in that directory to remove the "downloaded from internet" flag that blocks them from running. 3. Check `Get-ExecutionPolicy`: if it says 'Restricted' or 'Undefined', you need to also run `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` in order to allow the scripts to run. 4. Add the repository folder to `$env:PSModulePath` so that PowerShell can see it. @@ -170,10 +168,7 @@ If you would like to support the project, you can: - [Donate with Ko-fi][ko-fi] [blog]: https://vexx32.github.io -[build-badge]: https://dev.azure.com/SallowCode/PSKoans/_apis/build/status/PSKoans%20CI?branchName=main -[build-link]: https://dev.azure.com/SallowCode/PSKoans/_build/latest?definitionId=1&branchName=main [contributing]: CONTRIBUTING.md -[coverage-badge]: https://img.shields.io/azure-devops/coverage/SallowCode/PSKoans/1 [define-koan]: https://en.wikipedia.org/wiki/K%C5%8Dan [fsharp-koans]: https://github.com/ChrisMarinos/FSharpKoans [github-sponsor]: https://github.com/sponsors/vexx32 diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 39d9e9f65..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,269 +0,0 @@ -# YAML spec: -# https://aka.ms/yaml - -trigger: - branches: - include: - - main - tags: - include: - - '*' - -pr: -- main - -variables: - NupkgArtifactName: 'PSKoans.nupkg' - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - Trigger: '$(SourceBranchName)' - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - Trigger: 'PR #$(System.PullRequest.PullRequestNumber)' - -name: '$(BuildID)-$(Date:yyyy-MM-dd)$(Rev:.r) $(TeamProject) (${{ variables.Trigger }})' - -stages: -- stage: UploadChangelog - displayName: 'Upload Changelog' - dependsOn: [] - condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/main') - - jobs: - - job: GenerateChangelog - displayName: "Generate Changelog" - - pool: - vmImage: ubuntu-latest - - variables: - FilePath: '$(System.DefaultWorkingDirectory)/Changelog.md' - - steps: - - task: PowerShell@2 - displayName: 'Create Changelog' - inputs: - targetType: 'filepath' - filePath: ./Build/New-Changelog.ps1 - arguments: -Path '$(FilePath)' -ApiKey $(GithubApiKey) -Verbose - - - task: PublishPipelineArtifact@1 - displayName: 'Publish Changelog' - inputs: - path: '$(FilePath)' - artifact: Changelog - -- stage: Build - displayName: 'Build PSKoans' - dependsOn: [] - - variables: - FileSystemDeploymentPath: '$(System.DefaultWorkingDirectory)/Deploy/FileSystem' - BuiltModulePath: '$(System.DefaultWorkingDirectory)/Deploy/PSKoans' - - jobs: - - job: BuildNupkg - displayName: 'Module Nupkg' - - pool: - vmImage: ubuntu-latest - - steps: - - template: templates/environment-setup.yml - - - task: PowerShell@2 - displayName: 'Stage PSKoans Module' - - inputs: - targetType: 'filePath' - filePath: ./Build/Build-Module.ps1 - - errorActionPreference: 'stop' - failOnStdErr: true - pwsh: true - - - task: PublishPipelineArtifact@1 - displayName: 'Publish Built Module Artifact' - inputs: - path: '$(BuiltModulePath)' - artifact: PSKoans - - - template: ./templates/register-local-repo.yml - parameters: - repositoryPath: '$(FileSystemDeploymentPath)' - - - task: PowerShell@2 - displayName: 'Create Module Nupkg' - inputs: - targetType: 'filePath' - filePath: ./Deploy/Publish.ps1 - arguments: -Key 'filesystem' -Path '$(FileSystemDeploymentPath)' -OutputDirectory '$(FileSystemDeploymentPath)' - - errorActionPreference: 'stop' - failOnStderr: true - pwsh: true - - - task: PublishPipelineArtifact@1 - displayName: 'Publish Nupkg Artifact' - inputs: - path: '$(NupkgPath)' - artifact: '$(NupkgArtifactName)' - -- stage: LinuxTests - displayName: 'Linux' - dependsOn: - - Build - - variables: - PackageDownloadPath: '$(System.DefaultWorkingDirectory)/Module' - PSRepositoryName: 'FileSystem' - - jobs: - - job: Linux - displayName: 'Pester Tests' - - pool: - vmImage: ubuntu-latest - - steps: - - template: templates/environment-setup.yml - - - template: ./templates/install-built-module.yml - parameters: - repositoryPath: '$(PackageDownloadPath)' - repositoryName: '$(PSRepositoryName)' - artifactName: '$(NupkgArtifactName)' - - - template: templates/test-steps.yml - -- stage: WindowsTests - displayName: 'Windows' - dependsOn: - - Build - - variables: - PackageDownloadPath: '$(System.DefaultWorkingDirectory)/Module' - PSRepositoryName: 'FileSystem' - - jobs: - - job: Windows - displayName: 'Pester Tests' - - pool: - vmImage: windows-latest - - steps: - - template: templates/environment-setup.yml - - - template: ./templates/install-built-module.yml - parameters: - repositoryPath: '$(PackageDownloadPath)' - repositoryName: '$(PSRepositoryName)' - artifactName: '$(NupkgArtifactName)' - - - template: templates/test-steps.yml - -- stage: MacOSTests - displayName: 'MacOS' - dependsOn: - - Build - - variables: - PackageDownloadPath: '$(System.DefaultWorkingDirectory)/Module' - PSRepositoryName: 'FileSystem' - - jobs: - - job: MacOS - displayName: 'Pester Tests' - - pool: - vmImage: macOS-latest - - steps: - - template: templates/environment-setup.yml - - - template: ./templates/install-built-module.yml - parameters: - repositoryPath: '$(PackageDownloadPath)' - repositoryName: '$(PSRepositoryName)' - artifactName: '$(NupkgArtifactName)' - - - template: templates/test-steps.yml - -- stage: PublishModule - displayName: 'Publish Module' - dependsOn: - - LinuxTests - - WindowsTests - - MacOSTests - condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/')) - variables: - TagName: '' - - jobs: - - deployment: PublishToGallery - displayName: 'PowerShell Gallery' - environment: - name: 'pskoans-releases' - - pool: - vmImage: ubuntu-latest - - variables: - BuiltModulePath: '$(System.DefaultWorkingDirectory)/Deploy/PSKoans' - GalleryDeploymentPath: '$(System.DefaultWorkingDirectory)/Deploy/PSGallery' - strategy: - runOnce: - deploy: - steps: - - checkout: self - - template: templates/environment-setup.yml - - task: DownloadPipelineArtifact@2 - displayName: 'Download Built Module Artifact' - inputs: - artifact: PSKoans - path: $(BuiltModulePath) - - - task: PowerShell@2 - displayName: 'Publish Module to PSGallery' - - inputs: - targetType: 'filePath' - arguments: -Key $(PSApiKey) -Path '$(GalleryDeploymentPath)' - filePath: ./Deploy/Publish.ps1 - - errorActionPreference: 'stop' - failOnStderr: true - pwsh: true - - - job: PublishAssets - displayName: 'Publish Assets to Github' - - pool: - vmImage: ubuntu-latest - - steps: - - task: PowerShell@2 - displayName: 'Set Release Tag Name' - - inputs: - targetType: 'inline' - script: | - $tagName = ("$(Build.SourceBranch)" -replace '^refs/tags/').Trim() - - Write-Host "##vso[task.setvariable variable=TagName]$tagname" - - errorActionPreference: 'stop' - failOnStderr: true - pwsh: true - - - task: DownloadPipelineArtifact@2 - inputs: - targetPath: '$(Build.ArtifactStagingDirectory)/' - - - task: GitHubRelease@0 - inputs: - gitHubConnection: github.com_vexx32 - repositoryName: '$(Build.Repository.Name)' - action: 'edit' # Options: create, edit, delete - tag: '$(TagName)' # Required when action == Edit || Action == Delete || TagSource == Manual - assets: '$(Build.ArtifactStagingDirectory)/**/*.nupkg' # Optional - assetUploadMode: 'replace' # Optional. Options: delete, replace diff --git a/psakeFile.ps1 b/psakeFile.ps1 index 4d5fee156..c33fa5aed 100644 --- a/psakeFile.ps1 +++ b/psakeFile.ps1 @@ -7,7 +7,7 @@ Properties { # Test configuration -- the module must be imported from the staged output before # Pester runs since the test suite expects `PSKoans` to already be loaded/resolvable - $PSBPreference.Test.RootDir = Join-Path $PSScriptRoot 'Tests' + $PSBPreference.Test.RootDir = Join-Path $PSScriptRoot 'tests' $PSBPreference.Test.ImportModule = $true $PSBPreference.Test.OutputFile = 'out/testResults.xml' $PSBPreference.Test.OutputFormat = 'JUnitXml' diff --git a/templates/environment-setup.yml b/templates/environment-setup.yml deleted file mode 100644 index 634a3f602..000000000 --- a/templates/environment-setup.yml +++ /dev/null @@ -1,44 +0,0 @@ -steps: -- task: PowerShell@2 - displayName: 'Install Dependencies' - - inputs: - targetType: 'inline' - script: | - $Params = @{ - Scope = 'CurrentUser' - Force = $true - } - - Write-Host "Installing Modules" - $Params.Name = @( 'PSDeploy', 'BuildHelpers', 'PlatyPS' ) - $Params | Out-String | Write-Host - Install-Module @Params - - $Params.Name = 'Pester' - $Params.SkipPublisherCheck = $true - $Params.MinimumVersion = '5.0.2' - $Params | Out-String | Write-Host - Install-Module @Params - $Params.Remove('SkipPublisherCheck') - $Params.Remove('MinimumVersion') - - $Params.Name = 'EZOut' - $Params.AllowClobber = $true - $Params | Out-String | Write-Host - Install-Module @Params - - errorActionPreference: 'stop' - failOnStderr: true - pwsh: true - -- task: PowerShell@2 - displayName: 'Initialize Environment' - - inputs: - targetType: 'filePath' - filePath: ./Build/Initialize-Environment.ps1 - - errorActionPreference: 'stop' - failOnStdErr: true - pwsh: true diff --git a/templates/install-built-module.yml b/templates/install-built-module.yml deleted file mode 100644 index 268f4c651..000000000 --- a/templates/install-built-module.yml +++ /dev/null @@ -1,44 +0,0 @@ -parameters: -- name: repositoryPath - type: string - default: '$(System.DefaultWorkingDirectory)' -- name: repositoryName - type: string - default: 'FileSystem' -- name: artifactName - type: string - default: 'PSKoans.nupkg' - -steps: -- template: ./register-local-repo.yml - parameters: - repositoryPath: ${{ parameters.repositoryPath }} - repositoryName: ${{ parameters.repositoryName }} - -- task: DownloadPipelineArtifact@2 - displayName: 'Download Built Module Artifact' - inputs: - artifact: ${{ parameters.artifactName }} - path: ${{ parameters.repositoryPath }} - -- task: PowerShell@2 - displayName: 'Install PSKoans from Nupkg' - inputs: - targetType: 'inline' - script: | - $pesterParams = @{ - Name = 'Pester' - MinimumVersion = '5.0.2' - ProviderName = 'NuGet' - Path = '${{ parameters.repositoryPath }}' - Force = $true - Source = 'PSGallery' - } - - Register-PackageSource -Name PSGallery -ProviderName NuGet -Location https://www.powershellgallery.com/api/v2 -Force - Save-Package @pesterParams | Select-Object -Property Name, Version, Status, Source - Install-Module PSKoans -Repository ${{ parameters.repositoryName }} -Force -Scope CurrentUser - - errorActionPreference: 'stop' - failOnStderr: true - pwsh: true diff --git a/templates/register-local-repo.yml b/templates/register-local-repo.yml deleted file mode 100644 index 4887e49ee..000000000 --- a/templates/register-local-repo.yml +++ /dev/null @@ -1,19 +0,0 @@ -parameters: -- name: repositoryPath - type: string - default: '$(System.DefaultWorkingDirectory)' -- name: repositoryName - type: string - default: 'FileSystem' - -steps: -- task: PowerShell@2 - displayName: 'Register FileSystem Repository' - inputs: - targetType: 'filePath' - filePath: ./Build/Register-FileSystemRepository.ps1 - arguments: -Path '${{ parameters.repositoryPath }}' -Name '${{ parameters.repositoryName }}' - - errorActionPreference: 'stop' - failOnStderr: true - pwsh: true diff --git a/templates/test-steps.yml b/templates/test-steps.yml deleted file mode 100644 index 0af79d3a7..000000000 --- a/templates/test-steps.yml +++ /dev/null @@ -1,31 +0,0 @@ -steps: -- task: PowerShell@2 - displayName: 'Run Pester Tests' - - inputs: - targetType: 'filePath' - filePath: ./Build/Invoke-ModuleTests.ps1 - - errorActionPreference: 'stop' - failOnStderr: true - pwsh: true - -- task: PublishTestResults@2 - displayName: 'Publish Test Results' - condition: succeededOrFailed() - - inputs: - testResultsFormat: NUnit - testResultsFiles: '$(TestResults)' - searchFolder: '$(Build.ArtifactStagingDirectory)' - mergeTestResults: true - -- task: PublishCodeCoverageResults@1 - displayName: 'Publish Code Coverage' - condition: succeededOrFailed() - - inputs: - codeCoverageTool: JaCoCo - summaryFileLocation: '$(Build.ArtifactStagingDirectory)/$(CodeCoverageFile)' - #reportDirectory: '$(Build.ArtifactStagingDirectory)' - pathToSources: '$(SourceFolders)' diff --git a/Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 b/tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 similarity index 100% rename from Tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 rename to tests/Functions/Private/Assert-UnblockedFile.Tests.ps1 diff --git a/Tests/Functions/Private/ControlTests/Invoke-Koan.Control_Tests.ps1 b/tests/Functions/Private/ControlTests/Invoke-Koan.Control_Tests.ps1 similarity index 100% rename from Tests/Functions/Private/ControlTests/Invoke-Koan.Control_Tests.ps1 rename to tests/Functions/Private/ControlTests/Invoke-Koan.Control_Tests.ps1 diff --git a/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 b/tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 similarity index 97% rename from Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 rename to tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 index 94fd3f29c..8c9da83e8 100644 --- a/Tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 +++ b/tests/Functions/Private/ConvertFrom-WildcardPattern.Tests.ps1 @@ -1,48 +1,48 @@ -#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } - -BeforeDiscovery { - if ($null -eq $env:BHProjectName) { - # Run the build in a child process -- build.ps1 calls `exit` on completion, which - # would otherwise terminate the host process running this test file. - & pwsh -NoProfile -File '.\build.ps1' -Task Build - if ($LASTEXITCODE -ne 0) { - throw 'Failed to build PSKoans before running tests.' - } - Set-BuildEnvironment -Force - } - $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest - $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' - $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName - $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion - $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" - $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath - - # Remove all versions of the module from the session. Pester can't handle multiple versions. - Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore - Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop -} - -Describe 'ConvertFrom-WildcardPattern' { - - It 'adds start and end of string anchors to an explicit value' { - InModuleScope 'PSKoans' { ConvertFrom-WildcardPattern 'AboutArrays' } | Should -Be '^AboutArrays$' - } - - It 'joins multiple expressions with |' { - InModuleScope 'PSKoans' { ConvertFrom-WildcardPattern 'AboutArrays', 'AboutComparison' } | - Should -Be '^AboutArrays$|^AboutComparison$' - } - - It 'replaces wildcard characters with regex equivalent' -TestCases @( - @{ Pattern = 'About*son'; Expected = '^About.*son$' } - @{ Pattern = 'AboutArrays*'; Expected = '^AboutArrays' } - @{ Pattern = '*Arrays'; Expected = 'Arrays$' } - @{ Pattern = '*Array*'; Expected = 'Array' } - ) { - InModuleScope 'PSKoans' -Parameters @{ Pattern = $Pattern } { - param($Pattern) - - ConvertFrom-WildcardPattern $Pattern - } | Should -Be $Expected - } -} +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} + +Describe 'ConvertFrom-WildcardPattern' { + + It 'adds start and end of string anchors to an explicit value' { + InModuleScope 'PSKoans' { ConvertFrom-WildcardPattern 'AboutArrays' } | Should -Be '^AboutArrays$' + } + + It 'joins multiple expressions with |' { + InModuleScope 'PSKoans' { ConvertFrom-WildcardPattern 'AboutArrays', 'AboutComparison' } | + Should -Be '^AboutArrays$|^AboutComparison$' + } + + It 'replaces wildcard characters with regex equivalent' -TestCases @( + @{ Pattern = 'About*son'; Expected = '^About.*son$' } + @{ Pattern = 'AboutArrays*'; Expected = '^AboutArrays' } + @{ Pattern = '*Arrays'; Expected = 'Arrays$' } + @{ Pattern = '*Array*'; Expected = 'Array' } + ) { + InModuleScope 'PSKoans' -Parameters @{ Pattern = $Pattern } { + param($Pattern) + + ConvertFrom-WildcardPattern $Pattern + } | Should -Be $Expected + } +} diff --git a/Tests/Functions/Private/Get-KoanAst.Tests.ps1 b/tests/Functions/Private/Get-KoanAst.Tests.ps1 similarity index 100% rename from Tests/Functions/Private/Get-KoanAst.Tests.ps1 rename to tests/Functions/Private/Get-KoanAst.Tests.ps1 diff --git a/Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 b/tests/Functions/Private/Get-KoanAttribute.Tests.ps1 similarity index 100% rename from Tests/Functions/Private/Get-KoanAttribute.Tests.ps1 rename to tests/Functions/Private/Get-KoanAttribute.Tests.ps1 diff --git a/Tests/Functions/Private/Get-KoanIt.Tests.ps1 b/tests/Functions/Private/Get-KoanIt.Tests.ps1 similarity index 100% rename from Tests/Functions/Private/Get-KoanIt.Tests.ps1 rename to tests/Functions/Private/Get-KoanIt.Tests.ps1 diff --git a/Tests/Functions/Private/Invoke-Koan.Tests.ps1 b/tests/Functions/Private/Invoke-Koan.Tests.ps1 similarity index 100% rename from Tests/Functions/Private/Invoke-Koan.Tests.ps1 rename to tests/Functions/Private/Invoke-Koan.Tests.ps1 diff --git a/Tests/Functions/Private/Measure-Koan.Tests.ps1 b/tests/Functions/Private/Measure-Koan.Tests.ps1 similarity index 97% rename from Tests/Functions/Private/Measure-Koan.Tests.ps1 rename to tests/Functions/Private/Measure-Koan.Tests.ps1 index 393e8b18e..a6cabb209 100644 --- a/Tests/Functions/Private/Measure-Koan.Tests.ps1 +++ b/tests/Functions/Private/Measure-Koan.Tests.ps1 @@ -1,112 +1,112 @@ -#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } - -BeforeDiscovery { - if ($null -eq $env:BHProjectName) { - # Run the build in a child process -- build.ps1 calls `exit` on completion, which - # would otherwise terminate the host process running this test file. - & pwsh -NoProfile -File '.\build.ps1' -Task Build - if ($LASTEXITCODE -ne 0) { - throw 'Failed to build PSKoans before running tests.' - } - Set-BuildEnvironment -Force - } - $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest - $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' - $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName - $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion - $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" - $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath - - # Remove all versions of the module from the session. Pester can't handle multiple versions. - Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore - Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop -} - -Describe 'Measure-Koan' -Skip { - - BeforeAll { - Set-Content -Path 'TestDrive:\TestCases.Koans.ps1' -Value @' - Describe 'Test cases param' { - It 'first ' -TestCases @( - @{ TestCase = 1 } - @{ TestCase = 2 } - @{ TestCase = 3 } - ) { - param($TestCase) - - $TestCase | Should -BeOfType int - } - } -'@ - - Set-Content -Path 'TestDrive:\JustIt.Koans.ps1' -Value @' - Describe 'Just it' { - It 'first' { - $true | Should -BeTrue - } - - It 'second' { - $true | Should -BeTrue - } - } -'@ - - Set-Content -Path TestDrive:\Mixed.Koans.ps1 -Value @' - Describe 'Mixed' { - It 'first' { - $true | Should -BeTrue - } - - It 'second ' -TestCases @( - @{ TestCase = 1 } - @{ TestCase = 2 } - ) { - param($TestCase) - - $TestCase | Should -BeOfType int - } - } -'@ - - Set-Content -Path TestDrive:\MutlipleTestCases.Koans.ps1 -Value @' - Describe 'Test cases param' { - It 'first ' -TestCases @( - @{ TestCase = 1 } - @{ TestCase = 2 } - @{ TestCase = 3 } - ) { - param($TestCase) - - $TestCase | Should -BeOfType int - } - - It 'second ' -TestCases @( - @{ TestCase = 1 } - @{ TestCase = 2 } - @{ TestCase = 3 } - ) { - param($TestCase) - - $TestCase | Should -BeOfType int - } - } -'@ - } - - It 'correctly counts the number of tests in , including -TestCases' -TestCases @( - @{ Path = 'TestDrive:\TestCases.Koans.ps1'; ExpectedValue = 3 } - @{ Path = 'TestDrive:\JustIt.Koans.ps1'; ExpectedValue = 2 } - @{ Path = 'TestDrive:\Mixed.Koans.ps1'; ExpectedValue = 3 } - @{ Path = 'TestDrive:\MutlipleTestCases.Koans.ps1'; ExpectedValue = 6 } - ) { - $koanInfo = [PSCustomObject]@{ - Path = $Path - PSTypeName = 'PSKoans.KoanInfo' - } - - InModuleScope 'PSKoans' -Parameters @{ Koan = $koanInfo } { - param($Koan) - Measure-Koan $Koan - } | Should -Be $ExpectedValue - } -} +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} + +Describe 'Measure-Koan' -Skip { + + BeforeAll { + Set-Content -Path 'TestDrive:\TestCases.Koans.ps1' -Value @' + Describe 'Test cases param' { + It 'first ' -TestCases @( + @{ TestCase = 1 } + @{ TestCase = 2 } + @{ TestCase = 3 } + ) { + param($TestCase) + + $TestCase | Should -BeOfType int + } + } +'@ + + Set-Content -Path 'TestDrive:\JustIt.Koans.ps1' -Value @' + Describe 'Just it' { + It 'first' { + $true | Should -BeTrue + } + + It 'second' { + $true | Should -BeTrue + } + } +'@ + + Set-Content -Path TestDrive:\Mixed.Koans.ps1 -Value @' + Describe 'Mixed' { + It 'first' { + $true | Should -BeTrue + } + + It 'second ' -TestCases @( + @{ TestCase = 1 } + @{ TestCase = 2 } + ) { + param($TestCase) + + $TestCase | Should -BeOfType int + } + } +'@ + + Set-Content -Path TestDrive:\MutlipleTestCases.Koans.ps1 -Value @' + Describe 'Test cases param' { + It 'first ' -TestCases @( + @{ TestCase = 1 } + @{ TestCase = 2 } + @{ TestCase = 3 } + ) { + param($TestCase) + + $TestCase | Should -BeOfType int + } + + It 'second ' -TestCases @( + @{ TestCase = 1 } + @{ TestCase = 2 } + @{ TestCase = 3 } + ) { + param($TestCase) + + $TestCase | Should -BeOfType int + } + } +'@ + } + + It 'correctly counts the number of tests in , including -TestCases' -TestCases @( + @{ Path = 'TestDrive:\TestCases.Koans.ps1'; ExpectedValue = 3 } + @{ Path = 'TestDrive:\JustIt.Koans.ps1'; ExpectedValue = 2 } + @{ Path = 'TestDrive:\Mixed.Koans.ps1'; ExpectedValue = 3 } + @{ Path = 'TestDrive:\MutlipleTestCases.Koans.ps1'; ExpectedValue = 6 } + ) { + $koanInfo = [PSCustomObject]@{ + Path = $Path + PSTypeName = 'PSKoans.KoanInfo' + } + + InModuleScope 'PSKoans' -Parameters @{ Koan = $koanInfo } { + param($Koan) + Measure-Koan $Koan + } | Should -Be $ExpectedValue + } +} diff --git a/Tests/Functions/Private/New-KoanRunspace.Tests.ps1 b/tests/Functions/Private/New-KoanRunspace.Tests.ps1 similarity index 100% rename from Tests/Functions/Private/New-KoanRunspace.Tests.ps1 rename to tests/Functions/Private/New-KoanRunspace.Tests.ps1 diff --git a/Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 b/tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 similarity index 100% rename from Tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 rename to tests/Functions/Private/New-PSKoanErrorRecord.Tests.ps1 diff --git a/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 b/tests/Functions/Private/Update-PSKoanFile.Tests.ps1 similarity index 97% rename from Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 rename to tests/Functions/Private/Update-PSKoanFile.Tests.ps1 index 09c5659b8..6688efc08 100644 --- a/Tests/Functions/Private/Update-PSKoanFile.Tests.ps1 +++ b/tests/Functions/Private/Update-PSKoanFile.Tests.ps1 @@ -1,104 +1,104 @@ -#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } - -BeforeDiscovery { - if ($null -eq $env:BHProjectName) { - # Run the build in a child process -- build.ps1 calls `exit` on completion, which - # would otherwise terminate the host process running this test file. - & pwsh -NoProfile -File '.\build.ps1' -Task Build - if ($LASTEXITCODE -ne 0) { - throw 'Failed to build PSKoans before running tests.' - } - Set-BuildEnvironment -Force - } - $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest - $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' - $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName - $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion - $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" - $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath - - # Remove all versions of the module from the session. Pester can't handle multiple versions. - Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore - Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop -} - -Describe 'Update-PSKoanFile' { - - BeforeAll { - $koanLocation = Join-Path -Path $TestDrive -ChildPath 'Koans' - $koanRelativePath = 'Group/AboutSomething.ps1' - $moduleKoanPath = Join-Path -Path $TestDrive -ChildPath 'Module/Group/AboutSomething.ps1' - - Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } - Mock 'Get-PSKoan' -ModuleName 'PSKoans' { - [PSCustomObject]@{ - Topic = 'AboutSomething' - Path = $moduleKoanPath - RelativePath = $koanRelativePath - } - } - - New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'Koans/Group') -ItemType Directory - New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'Module/Group') -ItemType Directory - - Set-Content -Path $moduleKoanPath -Value @' - Describe 'AboutSomething' { - It 'koan 1' { - __ | Should -Be 1 - } - - It 'koan 2' { - __ | Should -Be 2 - } - - Context 'first' { - It 'koan 3' { - __ | Should -Be 3 - } - } - - Context 'second' { - It 'koan 4' { - __ | Should -Be 4 - } - } - } -'@ - - $userFilePath = Join-Path -Path $koanLocation -ChildPath $koanRelativePath - } - - BeforeEach { - Set-Content -Path $userFilePath -Value @' - Describe 'AboutSomething' { - It 'koan 1' { - 1 | Should -Be 1 - } - - It 'koan 2' { - __ | Should -Be 2 - } - - Context 'second' { - It 'koan 4' { - 4 | Should -Be 4 - } - } - } -'@ - } - - It 'should replay completed koans' { - InModuleScope 'PSKoans' { Update-PSKoanFile -Topic AboutSomething -Confirm:$false } - - $userFilePath | Should -FileContentMatch '1 | Should -Be 1' - $userFilePath | Should -FileContentMatch '__ | Should -Be 2' - $userFilePath | Should -FileContentMatch '4 | Should -Be 4' - } - - It 'should should allow new koans to be inserted' { - InModuleScope 'PSKoans' { Update-PSKoanFile -Topic AboutSomething -Confirm:$false } - - $userFilePath | Should -FileContentMatch 'koan 3' - } -} +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} + +Describe 'Update-PSKoanFile' { + + BeforeAll { + $koanLocation = Join-Path -Path $TestDrive -ChildPath 'Koans' + $koanRelativePath = 'Group/AboutSomething.ps1' + $moduleKoanPath = Join-Path -Path $TestDrive -ChildPath 'Module/Group/AboutSomething.ps1' + + Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } + Mock 'Get-PSKoan' -ModuleName 'PSKoans' { + [PSCustomObject]@{ + Topic = 'AboutSomething' + Path = $moduleKoanPath + RelativePath = $koanRelativePath + } + } + + New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'Koans/Group') -ItemType Directory + New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'Module/Group') -ItemType Directory + + Set-Content -Path $moduleKoanPath -Value @' + Describe 'AboutSomething' { + It 'koan 1' { + __ | Should -Be 1 + } + + It 'koan 2' { + __ | Should -Be 2 + } + + Context 'first' { + It 'koan 3' { + __ | Should -Be 3 + } + } + + Context 'second' { + It 'koan 4' { + __ | Should -Be 4 + } + } + } +'@ + + $userFilePath = Join-Path -Path $koanLocation -ChildPath $koanRelativePath + } + + BeforeEach { + Set-Content -Path $userFilePath -Value @' + Describe 'AboutSomething' { + It 'koan 1' { + 1 | Should -Be 1 + } + + It 'koan 2' { + __ | Should -Be 2 + } + + Context 'second' { + It 'koan 4' { + 4 | Should -Be 4 + } + } + } +'@ + } + + It 'should replay completed koans' { + InModuleScope 'PSKoans' { Update-PSKoanFile -Topic AboutSomething -Confirm:$false } + + $userFilePath | Should -FileContentMatch '1 | Should -Be 1' + $userFilePath | Should -FileContentMatch '__ | Should -Be 2' + $userFilePath | Should -FileContentMatch '4 | Should -Be 4' + } + + It 'should should allow new koans to be inserted' { + InModuleScope 'PSKoans' { Update-PSKoanFile -Topic AboutSomething -Confirm:$false } + + $userFilePath | Should -FileContentMatch 'koan 3' + } +} diff --git a/Tests/Functions/Public/Get-Blank.Tests.ps1 b/tests/Functions/Public/Get-Blank.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Get-Blank.Tests.ps1 rename to tests/Functions/Public/Get-Blank.Tests.ps1 diff --git a/Tests/Functions/Public/Get-Karma.Tests.ps1 b/tests/Functions/Public/Get-Karma.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Get-Karma.Tests.ps1 rename to tests/Functions/Public/Get-Karma.Tests.ps1 diff --git a/Tests/Functions/Public/Get-PSKoan.Tests.ps1 b/tests/Functions/Public/Get-PSKoan.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Get-PSKoan.Tests.ps1 rename to tests/Functions/Public/Get-PSKoan.Tests.ps1 diff --git a/Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 b/tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 rename to tests/Functions/Public/Get-PSKoanLocation.Tests.ps1 diff --git a/Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 b/tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 rename to tests/Functions/Public/Get-PSKoanSetting.Tests.ps1 diff --git a/Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 b/tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 rename to tests/Functions/Public/Move-PSKoanLibrary.Tests.ps1 diff --git a/Tests/Functions/Public/Register-Advice.Tests.ps1 b/tests/Functions/Public/Register-Advice.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Register-Advice.Tests.ps1 rename to tests/Functions/Public/Register-Advice.Tests.ps1 diff --git a/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 b/tests/Functions/Public/Reset-PSKoan.Tests.ps1 similarity index 97% rename from Tests/Functions/Public/Reset-PSKoan.Tests.ps1 rename to tests/Functions/Public/Reset-PSKoan.Tests.ps1 index 7dc9e7d99..3b80cecd6 100644 --- a/Tests/Functions/Public/Reset-PSKoan.Tests.ps1 +++ b/tests/Functions/Public/Reset-PSKoan.Tests.ps1 @@ -1,245 +1,245 @@ -#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } - -BeforeDiscovery { - if ($null -eq $env:BHProjectName) { - # Run the build in a child process -- build.ps1 calls `exit` on completion, which - # would otherwise terminate the host process running this test file. - & pwsh -NoProfile -File '.\build.ps1' -Task Build - if ($LASTEXITCODE -ne 0) { - throw 'Failed to build PSKoans before running tests.' - } - Set-BuildEnvironment -Force - } - $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest - $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' - $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName - $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion - $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" - $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath - - # Remove all versions of the module from the session. Pester can't handle multiple versions. - Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore - Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop -} - -Describe Reset-PSKoan { - - BeforeAll { - $defaultParams = @{ - Confirm = $false - } - - $koanLocation = Join-Path -Path $TestDrive -ChildPath 'PSKoans' - $moduleKoanPath = Join-Path -Path $TestDrive -ChildPath 'Module\Group\AboutSomething.Koans.ps1' - - Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } - - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' -MockWith { - [PSCustomObject]@{ - Topic = 'AboutSomething' - Path = $moduleKoanPath - RelativePath = 'Group\AboutSomething.Koans.ps1' - } - } - - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' -MockWith { - [PSCustomObject]@{ - Topic = 'AboutSomething' - Path = $userFilePath - RelativePath = 'Group\AboutSomething.Koans.ps1' - } - } - - New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'Module\Group') -ItemType Directory - New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'PSKoans\Group') -ItemType Directory - - $userFilePath = Join-Path -Path $koanLocation -ChildPath 'Group\AboutSomething.Koans.ps1' - - Set-Content -Path $moduleKoanPath, $userFilePath -Value @' - using module PSKoans - [Koan(Position = 1)] - param ( ) - - Describe 'AboutSomething' { - It 'existing content' { - __ | Should -Be 1 - } - - It 'reset content' { - __ | Should -Be 2 - } - - Context 'first' { - It 'nested reset content' { - __ | Should -Be 3 - } - } - - Context 'second' { - It 'nested reset content' { - __ | Should -Be 4 - } - } - } -'@ - } - - Context 'User file exists, It block exists' { - - BeforeAll { - Mock 'Set-Content' -ModuleName 'PSKoans' - Mock 'Copy-Item' -ModuleName 'PSKoans' - } - - It 'updates an existing user file when -Name is supplied' { - Reset-PSKoan -Name 'existing content' @defaultParams - - Should -Invoke 'Set-Content' -Times 1 -ModuleName 'PSKoans' - Should -Invoke 'Copy-Item' -Times 0 -ModuleName 'PSKoans' - } - - It 'updates an existing user file when -Context is supplied' { - Reset-PSKoan -Context 'first' @defaultParams - - Should -Invoke 'Set-Content' -Times 1 -Exactly -ModuleName 'PSKoans' - Should -Invoke 'Copy-Item' -Times 0 -ModuleName 'PSKoans' - } - - It 'updates an existing user file when -Name and -Context are supplied' { - Reset-PSKoan -Name 'nested reset content' -Context 'first' @defaultParams - - Should -Invoke 'Set-Content' -Times 1 -Exactly -ModuleName 'PSKoans' - Should -Invoke 'Copy-Item' -Times 0 -ModuleName 'PSKoans' - } - - It 'copies a koan file from the module when -Name and -Context are not supplied' { - Reset-PSKoan @defaultParams - - Should -Invoke 'Set-Content' -Times 0 -ModuleName 'PSKoans' - Should -Invoke 'Copy-Item' -Times 1 -Exactly -ModuleName 'PSKoans' - } - } - - Context 'User file exists, It block does not exist' { - - It 'writes a non-terminating error when the user file does not include the specified Koan' { - $realGetKoanIt = InModuleScope 'PSKoans' { Get-Item -Path 'Function:\Get-KoanIt' } - Mock 'Get-KoanIt' -ModuleName 'PSKoans' -MockWith { & $realGetKoanIt @args } - Mock 'Get-KoanIt' -ParameterFilter { $Path -match 'PSKoans' } -ModuleName 'PSKoans' - - { Reset-PSKoan -Topic AboutSomething -Name 'existing content' -ErrorAction Stop @defaultParams } | - Should -Throw -ErrorId 'PSKoans.UserItNotFound,Reset-PSKoan' - } - } - - Context 'User file does not exist' { - - BeforeAll { - New-Item "$TestDrive/DoesNotExist.Koans.ps1" -ItemType File > $null - - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -Verifiable -ModuleName 'PSKoans' - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -Verifiable -ModuleName 'PSKoans' -MockWith { - [PSCustomObject]@{ - Topic = $Topic - Module = '_powershell' - Position = 101 - Path = "$TestDrive/DoesNotExist.Koans.ps1" - RelativePath = 'DoesNotExist.Koans.ps1' - PSTypeName = 'PSKoans.KoanInfo' - } - } - - Mock 'Update-PSKoan' -ModuleName 'PSKoans' - } - - It 'calls Update-PSKoan when the topic does not exist in the user location' { - Reset-PSKoan -Topic DoesNotExist -ErrorAction Stop @defaultParams - - Should -InvokeVerifiable - Should -Invoke Update-PSKoan -Times 1 -Exactly -ModuleName 'PSKoans' - } - } - - Context 'Module file does not exist' { - - BeforeAll { - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' - } - - It 'throws a terminating error when no topics are found in the module' { - { Reset-PSKoan -Topic DoesNotExist @defaultParams } | - Should -Throw -ErrorId 'PSKoans.ModuleTopicNotFound,Reset-PSKoan' - - Should -Invoke 'Get-PSKoan' -Times 1 -Exactly -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' - } - } - - Context 'Practical tests' { - - BeforeEach { - Set-Content -Path $userFilePath -Value @' - using module PSKoans - [Koan(Position = 1)] - param ( ) - - Describe 'AboutSomething' { - It 'existing content' { - 1 | Should -Be 1 - } - - It 'reset content' { - 1 | Should -Be 2 - } - - Context 'first' { - It 'nested reset content' { - 3 | Should -Be 3 - } - } - - Context 'second' { - It 'nested reset content' { - 4 | Should -Be 4 - } - } - } -'@ - } - - It 'should reset all koans in a file when Name is not specified' { - $userFilePath | Should -FileContentMatch '__ | Should -Be 1' - $userFilePath | Should -FileContentMatch '__ | Should -Be 2' - $userFilePath | Should -FileContentMatch '__ | Should -Be 3' - $userFilePath | Should -FileContentMatch '__ | Should -Be 4' - } - - It 'should reset the state of a single koan without affecting others when Name is specified' { - Reset-PSKoan -Topic AboutSomething -Name 'reset content' @defaultParams - - $userFilePath | Should -FileContentMatch '1 | Should -Be 1' - $userFilePath | Should -FileContentMatch '__ | Should -Be 2' - } - - It 'supports context based searching' { - Reset-PSKoan -Topic AboutSomething -Name "nested reset content" -Context 'first' @defaultParams - - $userFilePath | Should -FileContentMatch '__ | Should -Be 3' - $userFilePath | Should -FileContentMatch '4 | Should -Be 4' - } - - It 'allows koans of a given name to be reset across all contexts' { - Reset-PSKoan -Topic AboutSomething -Name "nested reset content" @defaultParams - - $userFilePath | Should -FileContentMatch '__ | Should -Be 3' - $userFilePath | Should -FileContentMatch '__ | Should -Be 4' - } - - It 'supports wildcard patterns when matching name' { - Reset-PSKoan -Topic AboutSomething -Name "*content" @defaultParams - - $userFilePath | Should -FileContentMatch '__ | Should -Be 1' - $userFilePath | Should -FileContentMatch '__ | Should -Be 2' - } - } -} +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} + +Describe Reset-PSKoan { + + BeforeAll { + $defaultParams = @{ + Confirm = $false + } + + $koanLocation = Join-Path -Path $TestDrive -ChildPath 'PSKoans' + $moduleKoanPath = Join-Path -Path $TestDrive -ChildPath 'Module\Group\AboutSomething.Koans.ps1' + + Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } + + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' -MockWith { + [PSCustomObject]@{ + Topic = 'AboutSomething' + Path = $moduleKoanPath + RelativePath = 'Group\AboutSomething.Koans.ps1' + } + } + + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' -MockWith { + [PSCustomObject]@{ + Topic = 'AboutSomething' + Path = $userFilePath + RelativePath = 'Group\AboutSomething.Koans.ps1' + } + } + + New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'Module\Group') -ItemType Directory + New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'PSKoans\Group') -ItemType Directory + + $userFilePath = Join-Path -Path $koanLocation -ChildPath 'Group\AboutSomething.Koans.ps1' + + Set-Content -Path $moduleKoanPath, $userFilePath -Value @' + using module PSKoans + [Koan(Position = 1)] + param ( ) + + Describe 'AboutSomething' { + It 'existing content' { + __ | Should -Be 1 + } + + It 'reset content' { + __ | Should -Be 2 + } + + Context 'first' { + It 'nested reset content' { + __ | Should -Be 3 + } + } + + Context 'second' { + It 'nested reset content' { + __ | Should -Be 4 + } + } + } +'@ + } + + Context 'User file exists, It block exists' { + + BeforeAll { + Mock 'Set-Content' -ModuleName 'PSKoans' + Mock 'Copy-Item' -ModuleName 'PSKoans' + } + + It 'updates an existing user file when -Name is supplied' { + Reset-PSKoan -Name 'existing content' @defaultParams + + Should -Invoke 'Set-Content' -Times 1 -ModuleName 'PSKoans' + Should -Invoke 'Copy-Item' -Times 0 -ModuleName 'PSKoans' + } + + It 'updates an existing user file when -Context is supplied' { + Reset-PSKoan -Context 'first' @defaultParams + + Should -Invoke 'Set-Content' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Copy-Item' -Times 0 -ModuleName 'PSKoans' + } + + It 'updates an existing user file when -Name and -Context are supplied' { + Reset-PSKoan -Name 'nested reset content' -Context 'first' @defaultParams + + Should -Invoke 'Set-Content' -Times 1 -Exactly -ModuleName 'PSKoans' + Should -Invoke 'Copy-Item' -Times 0 -ModuleName 'PSKoans' + } + + It 'copies a koan file from the module when -Name and -Context are not supplied' { + Reset-PSKoan @defaultParams + + Should -Invoke 'Set-Content' -Times 0 -ModuleName 'PSKoans' + Should -Invoke 'Copy-Item' -Times 1 -Exactly -ModuleName 'PSKoans' + } + } + + Context 'User file exists, It block does not exist' { + + It 'writes a non-terminating error when the user file does not include the specified Koan' { + $realGetKoanIt = InModuleScope 'PSKoans' { Get-Item -Path 'Function:\Get-KoanIt' } + Mock 'Get-KoanIt' -ModuleName 'PSKoans' -MockWith { & $realGetKoanIt @args } + Mock 'Get-KoanIt' -ParameterFilter { $Path -match 'PSKoans' } -ModuleName 'PSKoans' + + { Reset-PSKoan -Topic AboutSomething -Name 'existing content' -ErrorAction Stop @defaultParams } | + Should -Throw -ErrorId 'PSKoans.UserItNotFound,Reset-PSKoan' + } + } + + Context 'User file does not exist' { + + BeforeAll { + New-Item "$TestDrive/DoesNotExist.Koans.ps1" -ItemType File > $null + + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -Verifiable -ModuleName 'PSKoans' + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -Verifiable -ModuleName 'PSKoans' -MockWith { + [PSCustomObject]@{ + Topic = $Topic + Module = '_powershell' + Position = 101 + Path = "$TestDrive/DoesNotExist.Koans.ps1" + RelativePath = 'DoesNotExist.Koans.ps1' + PSTypeName = 'PSKoans.KoanInfo' + } + } + + Mock 'Update-PSKoan' -ModuleName 'PSKoans' + } + + It 'calls Update-PSKoan when the topic does not exist in the user location' { + Reset-PSKoan -Topic DoesNotExist -ErrorAction Stop @defaultParams + + Should -InvokeVerifiable + Should -Invoke Update-PSKoan -Times 1 -Exactly -ModuleName 'PSKoans' + } + } + + Context 'Module file does not exist' { + + BeforeAll { + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' + } + + It 'throws a terminating error when no topics are found in the module' { + { Reset-PSKoan -Topic DoesNotExist @defaultParams } | + Should -Throw -ErrorId 'PSKoans.ModuleTopicNotFound,Reset-PSKoan' + + Should -Invoke 'Get-PSKoan' -Times 1 -Exactly -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' + } + } + + Context 'Practical tests' { + + BeforeEach { + Set-Content -Path $userFilePath -Value @' + using module PSKoans + [Koan(Position = 1)] + param ( ) + + Describe 'AboutSomething' { + It 'existing content' { + 1 | Should -Be 1 + } + + It 'reset content' { + 1 | Should -Be 2 + } + + Context 'first' { + It 'nested reset content' { + 3 | Should -Be 3 + } + } + + Context 'second' { + It 'nested reset content' { + 4 | Should -Be 4 + } + } + } +'@ + } + + It 'should reset all koans in a file when Name is not specified' { + $userFilePath | Should -FileContentMatch '__ | Should -Be 1' + $userFilePath | Should -FileContentMatch '__ | Should -Be 2' + $userFilePath | Should -FileContentMatch '__ | Should -Be 3' + $userFilePath | Should -FileContentMatch '__ | Should -Be 4' + } + + It 'should reset the state of a single koan without affecting others when Name is specified' { + Reset-PSKoan -Topic AboutSomething -Name 'reset content' @defaultParams + + $userFilePath | Should -FileContentMatch '1 | Should -Be 1' + $userFilePath | Should -FileContentMatch '__ | Should -Be 2' + } + + It 'supports context based searching' { + Reset-PSKoan -Topic AboutSomething -Name "nested reset content" -Context 'first' @defaultParams + + $userFilePath | Should -FileContentMatch '__ | Should -Be 3' + $userFilePath | Should -FileContentMatch '4 | Should -Be 4' + } + + It 'allows koans of a given name to be reset across all contexts' { + Reset-PSKoan -Topic AboutSomething -Name "nested reset content" @defaultParams + + $userFilePath | Should -FileContentMatch '__ | Should -Be 3' + $userFilePath | Should -FileContentMatch '__ | Should -Be 4' + } + + It 'supports wildcard patterns when matching name' { + Reset-PSKoan -Topic AboutSomething -Name "*content" @defaultParams + + $userFilePath | Should -FileContentMatch '__ | Should -Be 1' + $userFilePath | Should -FileContentMatch '__ | Should -Be 2' + } + } +} diff --git a/Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 b/tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 rename to tests/Functions/Public/Set-PSKoanLocation.Tests.ps1 diff --git a/Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 b/tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 rename to tests/Functions/Public/Set-PSKoanSetting.Tests.ps1 diff --git a/Tests/Functions/Public/Show-Advice.Tests.ps1 b/tests/Functions/Public/Show-Advice.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Show-Advice.Tests.ps1 rename to tests/Functions/Public/Show-Advice.Tests.ps1 diff --git a/Tests/Functions/Public/Show-Karma.Tests.ps1 b/tests/Functions/Public/Show-Karma.Tests.ps1 similarity index 100% rename from Tests/Functions/Public/Show-Karma.Tests.ps1 rename to tests/Functions/Public/Show-Karma.Tests.ps1 diff --git a/Tests/Functions/Public/Update-PSKoan.Tests.ps1 b/tests/Functions/Public/Update-PSKoan.Tests.ps1 similarity index 97% rename from Tests/Functions/Public/Update-PSKoan.Tests.ps1 rename to tests/Functions/Public/Update-PSKoan.Tests.ps1 index 921dd396d..0d6819b74 100644 --- a/Tests/Functions/Public/Update-PSKoan.Tests.ps1 +++ b/tests/Functions/Public/Update-PSKoan.Tests.ps1 @@ -1,130 +1,130 @@ -#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } - -BeforeDiscovery { - if ($null -eq $env:BHProjectName) { - # Run the build in a child process -- build.ps1 calls `exit` on completion, which - # would otherwise terminate the host process running this test file. - & pwsh -NoProfile -File '.\build.ps1' -Task Build - if ($LASTEXITCODE -ne 0) { - throw 'Failed to build PSKoans before running tests.' - } - Set-BuildEnvironment -Force - } - $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest - $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' - $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName - $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion - $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" - $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath - - # Remove all versions of the module from the session. Pester can't handle multiple versions. - Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore - Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop -} - -Describe 'Update-PSKoan' { - - Context 'Mocked Commands' { - - BeforeAll { - Mock 'Remove-Item' -ModuleName 'PSKoans' - Mock 'Copy-Item' -ModuleName 'PSKoans' - Mock 'New-Item' -ModuleName 'PSKoans' - Mock 'Move-Item' -ModuleName 'PSKoans' - Mock 'Update-PSKoanFile' -ModuleName 'PSKoans' - - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' -MockWith { - [PSCustomObject]@{ - Topic = 'Missing' - Path = 'Module\Group\AboutSomethingMissing.Koans.ps1' - } - [PSCustomObject]@{ - Topic = 'IncorrectPath' - Path = 'Module\Group\AboutSomethingIncorrectPath.Koans.ps1' - } - [PSCustomObject]@{ - Topic = 'Existing' - Path = 'Module\Group\AboutSomethingExisting.Koans.ps1' - } - } - - Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' -MockWith { - [PSCustomObject]@{ - Topic = 'IncorrectPath' - Path = 'Module\RetiredGroup\AboutSomethingIncorrectPath.Koans.ps1' - } - [PSCustomObject]@{ - Topic = 'RetiredTopic' - Path = 'Module\RetiredGroup\AboutSomethingRetiredTopic.Koans.ps1' - } - [PSCustomObject]@{ - Topic = 'Existing' - Path = 'Module\Group\AboutSomethingExisting.Koans.ps1' - } - } - } - - It 'should not produce output' { - Update-PSKoan -Confirm:$false | Should -BeNullOrEmpty - } - - It 'should copy missing topic files' { - Should -Invoke 'Copy-Item' -Times 1 -Scope Context -ModuleName 'PSKoans' - } - - It 'should move incorrectly placed topics' { - Should -Invoke 'Remove-Item' -Times 1 -Scope Context -ModuleName 'PSKoans' - } - - It 'should remove discarded topics' { - Should -Invoke 'Remove-Item' -Times 1 -Scope Context -ModuleName 'PSKoans' - } - - It 'should update topics which exist in module and koan path' { - Should -Invoke 'Update-PSKoanFile' -ModuleName 'PSKoans' -Times 2 -Scope Context - } - } - - Context 'Practical Tests with TestDrive' { - - BeforeAll { - $koanLocation = Join-Path -Path $TestDrive -ChildPath 'PSKoans' - Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } - - New-Item -Path $koanLocation -ItemType Directory - Update-PSKoan -Confirm:$false - - $file = Get-ChildItem -Path $koanLocation -Filter *.koans.ps1 -File -Recurse | - Select-Object -First 1 - } - - It 'should copy missing topic files' { - $file | Remove-Item - $file.FullName | Should -Not -Exist - - Update-PSKoan -Confirm:$false - - $file.FullName | Should -Exist - } - - It 'should move incorrectly placed topics' { - $directory = New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'PSKoans\Wrong') -ItemType Directory - $file | Move-Item -Destination $directory.FullName - $file.FullName | Should -Not -Exist - - Update-PSKoan -Confirm:$false - - $file.FullName | Should -Exist - } - - It 'should remove discarded topics' { - $oldTopicPath = Join-Path $TestDrive 'PSKoans\Foundations\OldTopic.koans.ps1' - $file | Copy-Item -Destination $oldTopicPath - $oldTopicPath | Should -Exist - - Update-PSKoan -Confirm:$false - - $oldTopicPath | Should -Not -Exist - } - } -} +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } + +BeforeDiscovery { + if ($null -eq $env:BHProjectName) { + # Run the build in a child process -- build.ps1 calls `exit` on completion, which + # would otherwise terminate the host process running this test file. + & pwsh -NoProfile -File '.\build.ps1' -Task Build + if ($LASTEXITCODE -ne 0) { + throw 'Failed to build PSKoans before running tests.' + } + Set-BuildEnvironment -Force + } + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + $env:PSModulePath = $outputModDir + [IO.Path]::PathSeparator + $env:PSModulePath + + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} + +Describe 'Update-PSKoan' { + + Context 'Mocked Commands' { + + BeforeAll { + Mock 'Remove-Item' -ModuleName 'PSKoans' + Mock 'Copy-Item' -ModuleName 'PSKoans' + Mock 'New-Item' -ModuleName 'PSKoans' + Mock 'Move-Item' -ModuleName 'PSKoans' + Mock 'Update-PSKoanFile' -ModuleName 'PSKoans' + + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'Module' } -ModuleName 'PSKoans' -MockWith { + [PSCustomObject]@{ + Topic = 'Missing' + Path = 'Module\Group\AboutSomethingMissing.Koans.ps1' + } + [PSCustomObject]@{ + Topic = 'IncorrectPath' + Path = 'Module\Group\AboutSomethingIncorrectPath.Koans.ps1' + } + [PSCustomObject]@{ + Topic = 'Existing' + Path = 'Module\Group\AboutSomethingExisting.Koans.ps1' + } + } + + Mock 'Get-PSKoan' -ParameterFilter { $Scope -eq 'User' } -ModuleName 'PSKoans' -MockWith { + [PSCustomObject]@{ + Topic = 'IncorrectPath' + Path = 'Module\RetiredGroup\AboutSomethingIncorrectPath.Koans.ps1' + } + [PSCustomObject]@{ + Topic = 'RetiredTopic' + Path = 'Module\RetiredGroup\AboutSomethingRetiredTopic.Koans.ps1' + } + [PSCustomObject]@{ + Topic = 'Existing' + Path = 'Module\Group\AboutSomethingExisting.Koans.ps1' + } + } + } + + It 'should not produce output' { + Update-PSKoan -Confirm:$false | Should -BeNullOrEmpty + } + + It 'should copy missing topic files' { + Should -Invoke 'Copy-Item' -Times 1 -Scope Context -ModuleName 'PSKoans' + } + + It 'should move incorrectly placed topics' { + Should -Invoke 'Remove-Item' -Times 1 -Scope Context -ModuleName 'PSKoans' + } + + It 'should remove discarded topics' { + Should -Invoke 'Remove-Item' -Times 1 -Scope Context -ModuleName 'PSKoans' + } + + It 'should update topics which exist in module and koan path' { + Should -Invoke 'Update-PSKoanFile' -ModuleName 'PSKoans' -Times 2 -Scope Context + } + } + + Context 'Practical Tests with TestDrive' { + + BeforeAll { + $koanLocation = Join-Path -Path $TestDrive -ChildPath 'PSKoans' + Mock 'Get-PSKoanLocation' -ModuleName 'PSKoans' { $koanLocation } + + New-Item -Path $koanLocation -ItemType Directory + Update-PSKoan -Confirm:$false + + $file = Get-ChildItem -Path $koanLocation -Filter *.koans.ps1 -File -Recurse | + Select-Object -First 1 + } + + It 'should copy missing topic files' { + $file | Remove-Item + $file.FullName | Should -Not -Exist + + Update-PSKoan -Confirm:$false + + $file.FullName | Should -Exist + } + + It 'should move incorrectly placed topics' { + $directory = New-Item -Path (Join-Path -Path $TestDrive -ChildPath 'PSKoans\Wrong') -ItemType Directory + $file | Move-Item -Destination $directory.FullName + $file.FullName | Should -Not -Exist + + Update-PSKoan -Confirm:$false + + $file.FullName | Should -Exist + } + + It 'should remove discarded topics' { + $oldTopicPath = Join-Path $TestDrive 'PSKoans\Foundations\OldTopic.koans.ps1' + $file | Copy-Item -Destination $oldTopicPath + $oldTopicPath | Should -Exist + + Update-PSKoan -Confirm:$false + + $oldTopicPath | Should -Not -Exist + } + } +} diff --git a/Tests/KoanValidation.Tests.ps1 b/tests/KoanValidation.Tests.ps1 similarity index 100% rename from Tests/KoanValidation.Tests.ps1 rename to tests/KoanValidation.Tests.ps1 diff --git a/Tests/ModuleHelp.Tests.ps1 b/tests/ModuleHelp.Tests.ps1 similarity index 100% rename from Tests/ModuleHelp.Tests.ps1 rename to tests/ModuleHelp.Tests.ps1 diff --git a/Tests/ModuleValidation.Tests.ps1 b/tests/ModuleValidation.Tests.ps1 similarity index 100% rename from Tests/ModuleValidation.Tests.ps1 rename to tests/ModuleValidation.Tests.ps1