diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e1994b..78fa432 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- [**#105**](https://github.com/psake/PowerShellBuild/issues/105) + **Breaking:** help generation moved from `platyPS` 0.14.x to + [`Microsoft.PowerShell.PlatyPS`](https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS) + 1.x. PlatyPS is also no longer a `RequiredModules` entry, so + `Install-Module PowerShellBuild` no longer installs it — the two PlatyPS + modules cannot be loaded into one process, so forcing the new one into every + session would break any consumer still holding the old one. Install it + yourself if you build help. `$PSBPreference.Docs.AlphabeticParamsOrder` is + removed, because PlatyPS 1.x always sorts parameters alphabetically and + offers no way back. Generated markdown carries the 1.x schema, though its + on-disk layout is unchanged. `Build-PSBuildUpdatableHelp` warns and returns + until the cabinet pipeline migrates in + [#152](https://github.com/psake/PowerShellBuild/issues/152); it could never + succeed in 0.8.x either, see + [#169](https://github.com/psake/PowerShellBuild/issues/169). See the + [v0.8 → v1.0 migration guide](docs/migration-v0.8-to-v1.0.md). + - [**#144**](https://github.com/psake/PowerShellBuild/issues/144) **Breaking:** `Test-PSBuildScriptAnalysis` now counts PSScriptAnalyzer `ParseError` records alongside `Error`. A file that does not parse at all diff --git a/PowerShellBuild/IB.tasks.ps1 b/PowerShellBuild/IB.tasks.ps1 index fe54942..fe50828 100644 --- a/PowerShellBuild/IB.tasks.ps1 +++ b/PowerShellBuild/IB.tasks.ps1 @@ -109,8 +109,8 @@ Task Pester -If (. $pesterPreReqs) Build, { $genMarkdownPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($task.name)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($task.name)] task." $result = $false } $result @@ -124,7 +124,6 @@ Task GenerateMarkdown -if (. $genMarkdownPreReqs) StageFiles, { DocsPath = $PSBPreference.Docs.RootDir Locale = $PSBPreference.Help.DefaultLocale Overwrite = $PSBPreference.Docs.Overwrite - AlphabeticParamsOrder = $PSBPreference.Docs.AlphabeticParamsOrder ExcludeDontShow = $PSBPreference.Docs.ExcludeDontShow UseFullTypeName = $PSBPreference.Docs.UseFullTypeName } @@ -133,8 +132,8 @@ Task GenerateMarkdown -if (. $genMarkdownPreReqs) StageFiles, { $genHelpFilesPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($task.name)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($task.name)] task." $result = $false } $result @@ -147,8 +146,8 @@ Task GenerateMAML -if (. $genHelpFilesPreReqs) GenerateMarkdown, { $genUpdatableHelpPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($task.name)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($task.name)] task." $result = $false } $result diff --git a/PowerShellBuild/PowerShellBuild.psd1 b/PowerShellBuild/PowerShellBuild.psd1 index 16538fc..e87cd1b 100644 --- a/PowerShellBuild/PowerShellBuild.psd1 +++ b/PowerShellBuild/PowerShellBuild.psd1 @@ -11,7 +11,6 @@ RequiredModules = @( @{ModuleName = 'BuildHelpers'; ModuleVersion = '2.0.16' } @{ModuleName = 'Pester'; ModuleVersion = '5.6.1' } - @{ModuleName = 'platyPS'; ModuleVersion = '0.14.1' } @{ModuleName = 'psake'; ModuleVersion = '4.9.0' } ) FunctionsToExport = @( diff --git a/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 b/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 index 20d42a6..79e754b 100644 --- a/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 +++ b/PowerShellBuild/Public/Build-PSBuildMAMLHelp.ps1 @@ -27,13 +27,49 @@ function Build-PSBuildMAMLHelp { # Generate the module's primary MAML help file foreach ($locale in $helpLocales) { - $externalHelpParams = @{ - Path = [IO.Path]::Combine($Path, $locale) - OutputPath = [IO.Path]::Combine($DestinationPath, $locale) - Force = $true - ErrorAction = 'SilentlyContinue' - Verbose = $VerbosePreference + $localePath = [IO.Path]::Combine($Path, $locale) + + # Only command documents can be exported. A module landing page imports without + # complaint but fails on export, and that failure aborts the whole batch and writes + # nothing, so it has to be filtered out rather than caught. + $commandMarkdownPath = @( + Measure-PlatyPSMarkdown -Path ([IO.Path]::Combine($localePath, '*.md')) | + Where-Object { $_.Filetype -match 'CommandHelp' } | + Select-Object -ExpandProperty 'FilePath' + ) + if ($commandMarkdownPath.Count -eq 0) { + continue + } + + # Export-MamlCommandHelp writes to //, + # a level deeper than PowerShell looks and with the file name taken from the + # document's front matter. Export to a staging directory and move the results so the + # published layout stays //-help.xml, which is + # where every consumer's existing .ExternalHelp directive already points. + $stagingPath = [IO.Path]::Combine( + [IO.Path]::GetTempPath(), + [IO.Path]::GetRandomFileName() + ) + try { + $mamlFile = @( + Import-MarkdownCommandHelp -Path $commandMarkdownPath | + Export-MamlCommandHelp -OutputFolder $stagingPath -Force -Verbose:($VerbosePreference -eq 'Continue') + ) + + $localeDestinationPath = [IO.Path]::Combine($DestinationPath, $locale) + if (-not (Test-Path -LiteralPath $localeDestinationPath)) { + New-Item -Path $localeDestinationPath -ItemType Directory -Force > $null + } + + foreach ($file in $mamlFile) { + # The file name is whatever the document's "external help file" front matter + # says, which Build-PSBuildMarkdown pins to the 0.14.x casing. Renaming here + # instead would leave the markdown and the MAML disagreeing about the name. + $destinationFilePath = Join-Path -Path $localeDestinationPath -ChildPath $file.Name + Move-Item -LiteralPath $file.FullName -Destination $destinationFilePath -Force + } + } finally { + Remove-Item -LiteralPath $stagingPath -Recurse -Force -ErrorAction SilentlyContinue } - New-ExternalHelp @externalHelpParams > $null } } diff --git a/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 b/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 index 9010543..0f44807 100644 --- a/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 +++ b/PowerShellBuild/Public/Build-PSBuildMarkdown.ps1 @@ -4,6 +4,10 @@ function Build-PSBuildMarkdown { Creates PlatyPS markdown documents based on comment-based help of module. .DESCRIPTION Creates PlatyPS markdown documents based on comment-based help of module. + + Existing command markdown is refreshed in place with Update-MarkdownCommandHelp so + hand-written prose survives, and markdown for commands that have no document yet is + generated with New-MarkdownCommandHelp. .PARAMETER ModulePath The path to the module .PARAMETER ModuleName @@ -14,8 +18,6 @@ function Build-PSBuildMarkdown { The locale to save the markdown docs. .PARAMETER Overwrite Overwrite existing markdown files and use comment based help as the source of truth. - .PARAMETER AlphabeticParamsOrder - Order parameters alphabetically by name in PARAMETERS section. There are 5 exceptions: -Confirm, -WhatIf, -IncludeTotalCount, -Skip, and -First parameters will be the last. .PARAMETER ExcludeDontShow Exclude the parameters marked with `DontShow` in the parameter attribute from the help content. .PARAMETER UseFullTypeName @@ -42,9 +44,6 @@ function Build-PSBuildMarkdown { [parameter(Mandatory)] [bool]$Overwrite, - [parameter(Mandatory)] - [bool]$AlphabeticParamsOrder, - [parameter(Mandatory)] [bool]$ExcludeDontShow, @@ -60,41 +59,83 @@ function Build-PSBuildMarkdown { return } - if (-not (Test-Path -LiteralPath $DocsPath)) { - New-Item -Path $DocsPath -ItemType Directory > $null + $localePath = [IO.Path]::Combine($DocsPath, $Locale) + if (-not (Test-Path -LiteralPath $localePath)) { + New-Item -Path $localePath -ItemType Directory -Force > $null } - if (Get-ChildItem -LiteralPath $DocsPath -Filter *.md -Recurse) { - $updateMDParams = @{ - AlphabeticParamsOrder = $AlphabeticParamsOrder - ExcludeDontShow = $ExcludeDontShow - UseFullTypeName = $UseFullTypeName - Verbose = $VerbosePreference - } - Get-ChildItem -LiteralPath $DocsPath -Directory | ForEach-Object { - Update-MarkdownHelp -Path $_.FullName @updateMDParams > $null + # Refresh first. Update-MarkdownCommandHelp merges the module's current surface into + # existing documents and preserves hand-written prose, where regenerating would + # discard it. -NoBackup keeps it from littering the docs tree with .md.bak files. + # Module landing pages are a different document type and are left alone. + $existingMarkdown = @( + Get-ChildItem -LiteralPath $localePath -Filter '*.md' -File -ErrorAction SilentlyContinue + ) + if ($existingMarkdown.Count -gt 0) { + $existingCommandMarkdown = @( + $existingMarkdown.Where({ + (Measure-PlatyPSMarkdown -LiteralPath $_.FullName).Filetype -match 'CommandHelp' + }) + ) + if ($existingCommandMarkdown.Count -gt 0) { + Update-MarkdownCommandHelp -LiteralPath $existingCommandMarkdown.FullName -NoBackup > $null } } - # ErrorAction set to SilentlyContinue so this command will not overwrite an existing MD file. - $newMDParams = @{ - Module = $ModuleName - Locale = $Locale - OutputFolder = [IO.Path]::Combine($DocsPath, $Locale) - AlphabeticParamsOrder = $AlphabeticParamsOrder - ExcludeDontShow = $ExcludeDontShow - UseFullTypeName = $UseFullTypeName - ErrorAction = 'SilentlyContinue' - Verbose = $VerbosePreference - } - if ($Overwrite) { - $newMDParams.Add('Force', $true) - $newMDParams.Remove('ErrorAction') + # New-MarkdownCommandHelp always writes to /, and without + # -Force it skips existing files with a warning rather than an error. Generating into + # an empty staging directory and moving the results keeps the documented + # / layout and keeps Overwrite meaning what it did before. + $stagingPath = [IO.Path]::Combine( + [IO.Path]::GetTempPath(), + [IO.Path]::GetRandomFileName() + ) + try { + $newMarkdownParams = @{ + ModuleInfo = $moduleInfo + OutputFolder = $stagingPath + Locale = $Locale + # PlatyPS 1.x defaults this front matter key to "-Help.xml", where + # 0.14.x wrote "-help.xml". The key is what Export-MamlCommandHelp + # names the MAML file after, so pinning it here keeps the markdown, the MAML + # file name, and any existing .ExternalHelp directive in agreement -- and + # keeps help resolving on case-sensitive file systems. Renaming after export + # would fix the file name while leaving the front matter disagreeing with it. + Metadata = @{ 'external help file' = "$ModuleName-help.xml" } + # Compared explicitly rather than passing $VerbosePreference through. The + # preference is an ActionPreference, and converting it to a switch uses the + # underlying number, so Stop and Inquire turn verbose output on even though + # neither asked for it. + Verbose = ($VerbosePreference -eq 'Continue') + } + if ($ExcludeDontShow) { + $newMarkdownParams.ExcludeDontShow = $true + } + # The sense of this option inverted in PlatyPS 1.x: full type names are now the + # default and abbreviation is the switch, so the old setting maps to its absence. + if (-not $UseFullTypeName) { + $newMarkdownParams.AbbreviateParameterTypeName = $true + } + New-MarkdownCommandHelp @newMarkdownParams > $null + + $generatedPath = [IO.Path]::Combine($stagingPath, $ModuleName) + $generatedMarkdown = @( + Get-ChildItem -LiteralPath $generatedPath -Filter '*.md' -File -ErrorAction SilentlyContinue + ) + foreach ($markdownFile in $generatedMarkdown) { + $destinationPath = Join-Path -Path $localePath -ChildPath $markdownFile.Name + if ((Test-Path -LiteralPath $destinationPath) -and -not $Overwrite) { + # Already refreshed above; regenerating would discard hand-written prose. + continue + } + Move-Item -LiteralPath $markdownFile.FullName -Destination $destinationPath -Force + } + } finally { + Remove-Item -LiteralPath $stagingPath -Recurse -Force -ErrorAction SilentlyContinue } - New-MarkdownHelp @newMDParams > $null } catch { Write-Error ($LocalizedData.FailedToGenerateMarkdownHelp -f $_) } finally { - Remove-Module $moduleName + Remove-Module $ModuleName } } diff --git a/PowerShellBuild/Public/Build-PSBuildUpdatableHelp.ps1 b/PowerShellBuild/Public/Build-PSBuildUpdatableHelp.ps1 index de784eb..986a22e 100644 --- a/PowerShellBuild/Public/Build-PSBuildUpdatableHelp.ps1 +++ b/PowerShellBuild/Public/Build-PSBuildUpdatableHelp.ps1 @@ -4,6 +4,11 @@ function Build-PSBuildUpdatableHelp { Create updatable help .cab file based on PlatyPS markdown help. .DESCRIPTION Create updatable help .cab file based on PlatyPS markdown help. + + Not implemented against PlatyPS 1.x yet. The cabinet pipeline is migrated in + psake/PowerShellBuild#152 along with the three defects in #169 that prevented this + function from ever succeeding. Until then it reports that updatable help was skipped + and returns without writing anything. .PARAMETER DocsPath Path to PlatyPS markdown help files. .PARAMETER OutputPath @@ -14,8 +19,11 @@ function Build-PSBuildUpdatableHelp { .EXAMPLE PS> Build-PSBuildUpdatableHelp -DocsPath ./docs -OutputPath ./Output/UpdatableHelp - Create help .cab file based on PlatyPS markdown help. + Reports that updatable help is not available and returns. #> + # The parameters are unused only because the body is stubbed. They stay so the public + # signature does not change twice -- once here and again when #152 restores the body. + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')] [CmdletBinding()] param( [parameter(Mandatory)] @@ -27,44 +35,11 @@ function Build-PSBuildUpdatableHelp { [string]$Module = $ModuleName ) - if ($null -ne $IsWindows -and -not $IsWindows) { - Write-Warning $LocalizedData.MakeCabNotAvailable - return - } - - $helpLocales = (Get-ChildItem -Path $DocsPath -Directory).Name - - # Create updatable help output directory - if (-not (Test-Path -LiteralPath $OutputPath)) { - $newItemSplat = @{ - ItemType = 'Directory' - Verbose = $VerbosePreference - Path = $OutputPath - } - New-Item @newItemSplat > $null - } else { - Write-Verbose ($LocalizedData.DirectoryAlreadyExists -f $OutputPath) - $removeItemSplat = @{ - Recurse = $true - Force = $true - Verbose = $VerbosePreference - } - Get-ChildItem $OutputPath | Remove-Item @removeItemSplat - } - - # Generate updatable help files. Note: this will currently update the - # version number in the module's MD file in the metadata. - foreach ($locale in $helpLocales) { - $cabParams = @{ - CabFilesFolder = [IO.Path]::Combine($moduleOutDir, $locale) - LandingPagePath = [IO.Path]::Combine( - $DocsPath, - $locale, - "$Module.md" - ) - OutputFolder = $OutputPath - Verbose = $VerbosePreference - } - New-ExternalHelpCab @cabParams > $null - } + # Deliberately references no PlatyPS command. Naming New-ExternalHelpCab here is enough to + # make PowerShell autoload platyPS 0.14.2 on any session that resolves it, and once that + # module is loaded, Microsoft.PowerShell.PlatyPS can no longer be imported in the same + # process -- both ship their own YamlDotNet with different assembly identities. Leaving the + # old call in place would poison every session that still has 0.14.2 installed, which is + # every consumer part-way through the upgrade. + Write-Warning $LocalizedData.UpdatableHelpNotMigrated } diff --git a/PowerShellBuild/build.properties.ps1 b/PowerShellBuild/build.properties.ps1 index 541cda9..2e8d24c 100644 --- a/PowerShellBuild/build.properties.ps1 +++ b/PowerShellBuild/build.properties.ps1 @@ -126,16 +126,13 @@ $moduleVersion = (Import-PowerShellDataFile -Path $env:BHPSModuleManifest).Modul # Whether to overwrite existing markdown files and use comment based help as the source of truth Overwrite = $false - # Whether to order parameters alphabetically by name in PARAMETERS section. - # Value passed to New-MarkdownHelp and Update-MarkdownHelp. - AlphabeticParamsOrder = $false - # Exclude the parameters marked with `DontShow` in the parameter attribute from the help content. - # Value passed to New-MarkdownHelp and Update-MarkdownHelp. + # Value passed to New-MarkdownCommandHelp. ExcludeDontShow = $false # Indicates that the target document will use a full type name instead of a short name for parameters. - # Value passed to New-MarkdownHelp and Update-MarkdownHelp. + # PlatyPS 1.x writes full type names by default, so $false is passed through as + # New-MarkdownCommandHelp's -AbbreviateParameterTypeName switch. UseFullTypeName = $false } Publish = @{ diff --git a/PowerShellBuild/en-US/Messages.psd1 b/PowerShellBuild/en-US/Messages.psd1 index 9149e18..fae187d 100644 --- a/PowerShellBuild/en-US/Messages.psd1 +++ b/PowerShellBuild/en-US/Messages.psd1 @@ -3,6 +3,7 @@ NoCommandsExported=No commands have been exported. Skipping markdown generation. FailedToGenerateMarkdownHelp=Failed to generate markdown help. : {0} AddingFileToPsm1=Adding [{0}] to PSM1 MakeCabNotAvailable=MakeCab.exe is not available. Cannot create help cab. +UpdatableHelpNotMigrated=Updatable help was skipped. The cabinet pipeline has not been migrated to Microsoft.PowerShell.PlatyPS 1.x yet; see psake/PowerShellBuild#152. DirectoryAlreadyExists=Directory already exists [{0}]. PathLongerThan3Chars=Path [{0}] must be longer than 3 characters. BuildSystemDetails=Build System Details: diff --git a/PowerShellBuild/psakeFile.ps1 b/PowerShellBuild/psakeFile.ps1 index cff79f9..2208e18 100644 --- a/PowerShellBuild/psakeFile.ps1 +++ b/PowerShellBuild/psakeFile.ps1 @@ -174,8 +174,8 @@ Task BuildHelp -Depends $PSBBuildHelpDependency {} -Description 'Builds help doc $genMarkdownPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." $result = $false } $result @@ -187,7 +187,6 @@ Task GenerateMarkdown -Depends $PSBGenerateMarkdownDependency -PreCondition $gen DocsPath = $PSBPreference.Docs.RootDir Locale = $PSBPreference.Help.DefaultLocale Overwrite = $PSBPreference.Docs.Overwrite - AlphabeticParamsOrder = $PSBPreference.Docs.AlphabeticParamsOrder ExcludeDontShow = $PSBPreference.Docs.ExcludeDontShow UseFullTypeName = $PSBPreference.Docs.UseFullTypeName Verbose = $VerbosePreference -eq 'Continue' @@ -197,8 +196,8 @@ Task GenerateMarkdown -Depends $PSBGenerateMarkdownDependency -PreCondition $gen $genHelpFilesPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." $result = $false } $result @@ -209,8 +208,8 @@ Task GenerateMAML -Depends $PSBGenerateMAMLDependency -PreCondition $genHelpFile $genUpdatableHelpPreReqs = { $result = $true - if (-not (Get-Module platyPS -ListAvailable)) { - Write-Warning "platyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." + if (-not (Get-Module Microsoft.PowerShell.PlatyPS -ListAvailable)) { + Write-Warning "Microsoft.PowerShell.PlatyPS module is not installed. Skipping [$($psake.context.currentTaskName)] task." $result = $false } $result diff --git a/docs/migration-v0.8-to-v1.0.md b/docs/migration-v0.8-to-v1.0.md index 6268436..ee05ac1 100644 --- a/docs/migration-v0.8-to-v1.0.md +++ b/docs/migration-v0.8-to-v1.0.md @@ -28,9 +28,16 @@ One line per break; follow the link for details and migration steps. - [Unparsable files now fail the script analysis gate](#unparsable-files-now-fail-the-script-analysis-gate) — `ParseError` findings are counted with `Error`, so a file that does not parse fails every threshold except `None`. +- [Help generation now uses Microsoft.PowerShell.PlatyPS 1.x, and installs it yourself](#help-generation-now-uses-microsoftpowershellplatyps-1x-and-installs-it-yourself) + — the PlatyPS dependency changed module, and is no longer installed for you. +- [`$PSBPreference.Docs.AlphabeticParamsOrder` is removed](#psbpreferencedocsalphabeticparamsorder-is-removed) + — PlatyPS 1.x always sorts alphabetically, so the setting could no longer do anything. +- [Generated markdown uses the PlatyPS 1.x schema](#generated-markdown-uses-the-platyps-1x-schema) + — expect a large diff in `docs/` on the first 1.0.0 build. +- [Updatable help is temporarily unavailable](#updatable-help-is-temporarily-unavailable) + — the cabinet pipeline is migrated before 1.0.0 ships. -> More entries will follow as the Phase 2 migrations to -> Microsoft.PowerShell.PlatyPS 1.x and psake 5.x land. +> More entries will follow as the remaining Phase 2 work lands. ## AI-assisted migration @@ -200,6 +207,125 @@ This is additive — existing values behave as before. Tracked in issue [#144](https://github.com/psake/PowerShellBuild/issues/144). +### Help generation now uses Microsoft.PowerShell.PlatyPS 1.x, and installs it yourself + +`Build-PSBuildMarkdown` and `Build-PSBuildMAMLHelp` are built on +[`Microsoft.PowerShell.PlatyPS`](https://www.powershellgallery.com/packages/Microsoft.PowerShell.PlatyPS) +1.x instead of `platyPS` 0.14.x. The `GenerateMarkdown` and `GenerateMAML` +tasks now check for the new module and skip with a warning if it is +missing, exactly as they did for the old one. + +PlatyPS is **no longer listed in `RequiredModules`**, so +`Install-Module PowerShellBuild` no longer installs it for you. This is +deliberate rather than an oversight. The two PlatyPS modules each ship +their own `YamlDotNet.dll` with different assembly identities, and .NET +refuses to load both into one process — whichever imports second fails +with `Assembly with same name is already loaded`. A `RequiredModules` +entry forces that load into **every** session that imports +PowerShellBuild, including builds that never generate documentation, so +any consumer still holding `platyPS` 0.14.x — which is every consumer +part-way through this upgrade — would be unable to import PowerShellBuild +at all. Making the dependency optional matches how the docs tasks have +always behaved: they probe for the module and skip when it is absent. + +**Before (0.8.x):** + +```powershell +# platyPS arrived with PowerShellBuild via RequiredModules +Install-Module -Name PowerShellBuild +``` + +**After (1.0.0):** + +```powershell +Install-Module -Name PowerShellBuild +# Only if you build help; add it to your own requirements/bootstrap +Install-Module -Name Microsoft.PowerShell.PlatyPS -MinimumVersion 1.0.3 +``` + +**Detection:** the build prints +`Microsoft.PowerShell.PlatyPS module is not installed. Skipping [GenerateMarkdown] task.` +and produces no markdown or MAML. + +You can uninstall `platyPS` 0.14.x once nothing else on the machine needs +it. Leaving it installed is safe — it is only a problem if something +loads it into the same session that loads PlatyPS 1.x. + +Tracked in PRs [#150](https://github.com/psake/PowerShellBuild/issues/150) +and [#151](https://github.com/psake/PowerShellBuild/issues/151); chain +context in [#105](https://github.com/psake/PowerShellBuild/issues/105). + +### `$PSBPreference.Docs.AlphabeticParamsOrder` is removed + +PlatyPS 1.x always orders parameters alphabetically and offers no option +to restore declaration order, so the setting could no longer do anything. +Rather than keep a setting that silently lies, it is gone, along with the +`AlphabeticParamsOrder` parameter on `Build-PSBuildMarkdown`. + +**Before (0.8.x):** + +```powershell +$PSBPreference.Docs.AlphabeticParamsOrder = $true +``` + +**After (1.0.0):** + +```powershell +# Remove the line. Alphabetical ordering is now the only behavior. +``` + +**Detection:** setting the property no longer fails (it is a plain +hashtable), so this will not error — grep your build file for +`AlphabeticParamsOrder` and delete the assignment. Calling +`Build-PSBuildMarkdown` with `-AlphabeticParamsOrder` **does** fail, with +`A parameter cannot be found that matches parameter name 'AlphabeticParamsOrder'`. + +`ExcludeDontShow` and `UseFullTypeName` are unchanged and keep their +existing behavior. + +### Generated markdown uses the PlatyPS 1.x schema + +Markdown written into `$PSBPreference.Docs.RootDir` now carries +`PlatyPS schema version: 2024-05-01` and a `document type:` key where +0.14.x wrote `schema: 2.0.0`. Command documents also gain an `## ALIASES` +section and per-parameter-set `### __AllParameterSets` headings inside +`SYNTAX`. + +The on-disk layout is unchanged: documents stay at +`//.md`, and MAML still lands at +`//-help.xml`. PlatyPS 1.x would +otherwise nest both a level deeper under a `` directory; +PowerShellBuild flattens that back out so existing docs trees, static +site configuration, and `.ExternalHelp` directives keep working. + +**Detection:** your first 1.0.0 build produces a large diff in `docs/`. + +If you **commit** your `docs/` tree, review that diff for lost prose +before committing it. Existing documents are refreshed in place with +`Update-MarkdownCommandHelp`, which preserves hand-written content, so +this should be schema churn rather than content loss — but verify. +Consumer guidance for converting a committed tree is +[#154](https://github.com/psake/PowerShellBuild/issues/154). + +### Updatable help is temporarily unavailable + +`Build-PSBuildUpdatableHelp` and the `GenerateUpdatableHelp` task write a +warning and return without producing a cabinet. The 1.x cabinet pipeline +is migrated in [#152](https://github.com/psake/PowerShellBuild/issues/152) +before 1.0.0 ships. + +This costs nothing in practice: the function could never succeed in +0.8.x either. It required a module landing page that +`Build-PSBuildMarkdown` never generated, and it passed an undefined +variable as the cabinet source folder — three separate defects, recorded +in [#169](https://github.com/psake/PowerShellBuild/issues/169). The task +is opt-in and is not part of the default build, so most consumers never +reached it. + +**Detection:** `Updatable help was skipped. The cabinet pipeline has not +been migrated to Microsoft.PowerShell.PlatyPS 1.x yet` in the build +output, where 0.8.x raised a parameter-binding error. + ## Adding an entry (for PR contributors) Every breaking-change PR that lands in v1.0.0 must add an entry here for diff --git a/instructions/repository-specific.instructions.md b/instructions/repository-specific.instructions.md index c10d30f..ad048f7 100644 --- a/instructions/repository-specific.instructions.md +++ b/instructions/repository-specific.instructions.md @@ -232,7 +232,7 @@ versions — and installed via **PSDepend** when `./build.ps1 -Bootstrap` runs: | psake | Task runner for this repo's own build | | PSScriptAnalyzer | Static analysis of the built module | | InvokeBuild | Alternate task runner (consumer-facing `IB.tasks.ps1`) | -| platyPS | Help and documentation generation | +| Microsoft.PowerShell.PlatyPS | Help and documentation generation (optional; not a required module) | ## Testing diff --git a/requirements.psd1 b/requirements.psd1 index 3f920f5..bc837ae 100755 --- a/requirements.psd1 +++ b/requirements.psd1 @@ -12,5 +12,8 @@ psake = '5.0.4' PSScriptAnalyzer = '1.25.0' InvokeBuild = '5.14.23' - platyPS = '0.14.2' + PlatyPS = @{ + Name = 'Microsoft.PowerShell.PlatyPS' + Version = '1.0.3' + } } diff --git a/tests/Build-PSBuildHelp.tests.ps1 b/tests/Build-PSBuildHelp.tests.ps1 index e10236c..1d38a2b 100644 --- a/tests/Build-PSBuildHelp.tests.ps1 +++ b/tests/Build-PSBuildHelp.tests.ps1 @@ -21,8 +21,8 @@ BeforeDiscovery { # The psake PreConditions on the docs tasks gate on exactly this, so the tests behave the - # same way the shipped tasks do: absent platyPS means skipped, not failed. - $script:platyPSAvailable = [bool](Get-Module -Name 'platyPS' -ListAvailable) + # same way the shipped tasks do: an absent module means skipped, not failed. + $script:platyPSAvailable = [bool](Get-Module -Name 'Microsoft.PowerShell.PlatyPS' -ListAvailable) # Build-PSBuildUpdatableHelp returns early on non-Windows, and Windows PowerShell 5.1 has # no $IsWindows at all, so it takes the Windows path there. Resolved at discovery because @@ -85,12 +85,23 @@ Describe 'Help building functions' -Skip:(-not $script:platyPSAvailable) { Should -Not -Exist } - It 'produces markdown carrying the 0.14.x schema marker' { - # The 0.14.x front matter carries "external help file" and "schema: 2.0.0". The 1.x - # schema drops the latter, so this assertion is the tripwire that says the - # migration in #150 actually changed the output format. + It 'produces markdown carrying the 1.x schema marker' { + # 0.14.x front matter carried "schema: 2.0.0". 1.x replaces it with a dated schema + # version and a document type, so this pins the migration rather than just passing + # either way. $markdownPath = Join-Path -Path $script:markdownScenario.LocalePath -ChildPath 'Get-Widget.md' - Get-Content -Path $markdownPath -Raw | Should -Match 'schema:\s*2\.0\.0' + $markdown = Get-Content -Path $markdownPath -Raw + $markdown | Should -Match 'PlatyPS schema version:' + $markdown | Should -Match 'document type:\s*cmdlet' + $markdown | Should -Not -Match 'schema:\s*2\.0\.0' + } + + It 'keeps the markdown directly under the locale directory' { + # New-MarkdownCommandHelp writes to /. The function + # flattens that back out, so a nested module directory here means the flattening + # regressed and every downstream path assumption breaks with it. + Join-Path -Path $script:markdownScenario.LocalePath -ChildPath $script:markdownScenario.ModuleName | + Should -Not -Exist } } @@ -136,23 +147,6 @@ Describe 'Help building functions' -Skip:(-not $script:platyPSAvailable) { BeforeAll { $script:cabScenario = New-PSBuildDocsScenario -Path $TestDrive -Name 'cab' - $cabMarkdownJobParameter = @{ - ModulePath = $script:builtModulePath - CommandName = 'Build-PSBuildMarkdown' - Parameter = New-PSBuildMarkdownParameter -Scenario $script:cabScenario - } - $null = Invoke-PSBuildCommandInJob @cabMarkdownJobParameter - - $cabMamlJobParameter = @{ - ModulePath = $script:builtModulePath - CommandName = 'Build-PSBuildMAMLHelp' - Parameter = @{ - Path = $script:cabScenario.DocsPath - DestinationPath = $script:cabScenario.OutputPath - } - } - $null = Invoke-PSBuildCommandInJob @cabMamlJobParameter - $cabJobParameter = @{ ModulePath = $script:builtModulePath CommandName = 'Build-PSBuildUpdatableHelp' @@ -165,42 +159,18 @@ Describe 'Help building functions' -Skip:(-not $script:platyPSAvailable) { $script:cabResult = Invoke-PSBuildCommandInJob @cabJobParameter } - It 'declines to run on platforms without makecab' -Skip:$script:onWindows { + # Pins the documented intermediate state, not the destination. The cabinet pipeline + # migrates in #152 together with the three defects in #169 that stopped this function + # ever succeeding. Until then it must fail quietly rather than throw, and above all it + # must not name a platyPS 0.14.2 command: resolving one autoloads that module, and a + # session holding it can no longer import Microsoft.PowerShell.PlatyPS at all. + It 'returns without throwing' { $script:cabResult.Threw | Should -BeFalse - $script:cabScenario.UpdatableHelpPath | Should -Not -Exist - } - - It 'creates the output directory' -Skip:(-not $script:onWindows) { - # This much works today: the directory is created before the cab step throws. - $script:cabScenario.UpdatableHelpPath | Should -Exist + $script:cabResult.ErrorMessage | Should -BeNullOrEmpty } - It 'fails parameter binding on the cab step' -Skip:(-not $script:onWindows) { - # Pins the CURRENT broken behavior so the baseline is honest about what happens, - # and so fixing psake/PowerShellBuild#169 forces this test to be revisited rather - # than leaving a silent pass. Delete this test when #169 is fixed; the two below - # replace it. - # - # Either of two independent defects can surface first, depending on the order - # PowerShell binds the splatted parameters: LandingPagePath points at a module page - # that is never generated, and CabFilesFolder is built from the undefined - # $moduleOutDir, which collapses to the bare locale name. Asserting on one of them - # specifically makes this test flaky, so it accepts either. - $script:cabResult.Threw | Should -BeTrue - $script:cabResult.ErrorMessage | Should -Match 'LandingPagePath|CabFilesFolder' - } - - It 'produces a cabinet file' -Skip { - # Skipped pending psake/PowerShellBuild#169. This is the acceptance criterion for - # that fix and for the #152 migration, written now so it is not written twice. - Get-ChildItem -Path $script:cabScenario.UpdatableHelpPath -Filter '*.cab' | - Should -Not -BeNullOrEmpty - } - - It 'produces the help info manifest' -Skip { - # Skipped pending psake/PowerShellBuild#169. See above. - Get-ChildItem -Path $script:cabScenario.UpdatableHelpPath -Filter '*HelpInfo.xml' | - Should -Not -BeNullOrEmpty + It 'writes nothing' { + $script:cabScenario.UpdatableHelpPath | Should -Not -Exist } } } diff --git a/tests/fixtures/FixtureHelpers.psm1 b/tests/fixtures/FixtureHelpers.psm1 index 744a2ee..5e7bc7b 100644 --- a/tests/fixtures/FixtureHelpers.psm1 +++ b/tests/fixtures/FixtureHelpers.psm1 @@ -115,17 +115,14 @@ function New-PSBuildMarkdownParameter { .SYNOPSIS Build the Build-PSBuildMarkdown parameter set for a docs scenario. .DESCRIPTION - Build-PSBuildMarkdown takes four mandatory [bool] parameters that most tests do not care - about but cannot omit. This supplies them at their build.properties.ps1 defaults so a + Build-PSBuildMarkdown takes three mandatory [bool] parameters that most tests do not + care about but cannot omit. This supplies them at their build.properties.ps1 defaults so a test only has to name the ones it is actually exercising. .PARAMETER Scenario Scenario object from New-PSBuildDocsScenario. .PARAMETER Overwrite Whether comment-based help overwrites existing markdown. Defaults to $false, matching $PSBPreference.Docs.Overwrite. - .PARAMETER AlphabeticParamsOrder - Whether parameters are ordered alphabetically. Defaults to $false, matching - $PSBPreference.Docs.AlphabeticParamsOrder. .PARAMETER ExcludeDontShow Whether parameters marked DontShow are excluded. Defaults to $false, matching $PSBPreference.Docs.ExcludeDontShow. @@ -153,9 +150,6 @@ function New-PSBuildMarkdownParameter { [bool] $Overwrite = $false, - [bool] - $AlphabeticParamsOrder = $false, - [bool] $ExcludeDontShow = $false, @@ -169,7 +163,6 @@ function New-PSBuildMarkdownParameter { DocsPath = $Scenario.DocsPath Locale = $Scenario.Locale Overwrite = $Overwrite - AlphabeticParamsOrder = $AlphabeticParamsOrder ExcludeDontShow = $ExcludeDontShow UseFullTypeName = $UseFullTypeName }