From 0668cb7d2e423a3a475ce3f1306bdb5c2cdd5cd8 Mon Sep 17 00:00:00 2001 From: Trent Blackburn Date: Wed, 26 Aug 2026 15:16:01 -0400 Subject: [PATCH] docs: Document the docs/ schema conversion for consumers Add a migration entry covering how a consumer converts a committed docs/ tree from the platyPS 0.14.x schema to the Microsoft.PowerShell.PlatyPS 1.x schema, plus a Quick Start bullet linking to it. The headline finding is that most consumers need no conversion step at all: the GenerateMarkdown task already runs Update-MarkdownCommandHelp over every existing command document, so an ordinary 1.0.0 build rewrites a 0.14.x tree in place. The entry reframes the work as reading the diff rather than running a one-shot, and documents the manual path for the cases where a build cannot do it. Every claim was verified against Microsoft.PowerShell.PlatyPS 1.0.3 using a throwaway module whose 0.14.x markdown was generated by platyPS 0.14.2 in a separate process, then hand-edited so content loss would be visible. Closes #154 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01MuBy4d575f3TQf4c2FmVdA --- docs/migration-v0.8-to-v1.0.md | 217 ++++++++++++++++++++++++++++++++- 1 file changed, 215 insertions(+), 2 deletions(-) diff --git a/docs/migration-v0.8-to-v1.0.md b/docs/migration-v0.8-to-v1.0.md index 6457270..d9612b3 100644 --- a/docs/migration-v0.8-to-v1.0.md +++ b/docs/migration-v0.8-to-v1.0.md @@ -38,6 +38,9 @@ One line per break; follow the link for details and migration steps. — it could never succeed in 0.8.x; using it now needs a `HelpInfoUri` in your manifest. - [Your `docs/` tree gains a module landing page](#your-docs-tree-gains-a-module-landing-page) — a new `.md` appears alongside the per-command documents. +- [A committed `docs/` tree converts itself on the first build](#a-committed-docs-tree-converts-itself-on-the-first-build) + — the schema conversion is automatic; review the diff for the prose it + drops, and convert orphaned documents by hand. > More entries will follow as the remaining Phase 2 work lands. @@ -306,8 +309,8 @@ 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). +Consumer guidance for converting a committed tree is in +[A committed `docs/` tree converts itself on the first build](#a-committed-docs-tree-converts-itself-on-the-first-build). ### Updatable help works, and now requires a `HelpInfoUri` @@ -378,6 +381,216 @@ so `Build-PSBuildMAMLHelp` filters it out. **Detection:** a new `.md` file appears in your docs tree on the first 1.0.0 build. If you commit `docs/`, commit it too. +### A committed `docs/` tree converts itself on the first build + +If you commit your `docs/` tree, you do **not** need a manual conversion +step in the ordinary case. The `GenerateMarkdown` task runs +`Update-MarkdownCommandHelp` over every existing command document on every +build, and that cmdlet rewrites a 0.14.x document into the 1.x schema in +place. A tree that went into the first 1.0.0 build as `V1Schema` comes out +of it as `V2Schema`, in the same files, with no staging directory and no +leftovers: + +```console +=== docs tree BEFORE the build (genuine 0.14.x) === + Get-ScratchWidget.md CommandHelp, V1Schema + New-ScratchWidget.md CommandHelp, V1Schema + Remove-ScratchWidget.md CommandHelp, V1Schema + ScratchModule.md ModuleFile, V1Schema + +=== docs tree AFTER the build === + Get-ScratchWidget.md CommandHelp, V2Schema + New-ScratchWidget.md CommandHelp, V2Schema + Remove-ScratchWidget.md CommandHelp, V2Schema + ScratchModule.md ModuleFile, V2Schema +``` + +`Measure-PlatyPSMarkdown` is how you check which schema a tree is on: + +```powershell +Measure-PlatyPSMarkdown -Path ./docs/en-US/*.md | + Select-Object FileType, FilePath +``` + +So the work is not running a conversion. It is **reading the diff the build +produces before you commit it**, and handling the few documents the build +cannot convert. + +#### What the conversion keeps and what it drops + +Verified by round-tripping a 0.14.x tree whose markdown had been edited by +hand beyond what comment-based help contained: + +| Hand-written content | Result | +| ------------------------------------------------------- | ----------------------- | +| Extra prose paragraph in `## DESCRIPTION` | Survives | +| A whole `### EXAMPLE` block added only to the markdown | Survives | +| An edited parameter description | Survives, but see below | +| Bodies under `## INPUTS` and `## OUTPUTS` | Survives | +| Extra paragraph in `## NOTES` | Survives | +| A heading that is not part of the schema (`## CAVEATS`) | **Silently dropped** | + +The last row is the one to grep for. PlatyPS parses a command document into +a fixed set of sections; anything outside them has nowhere to go and is +discarded with no warning and no error. If your documents carry custom +sections, move that content into `## NOTES` — or into the module landing +page — before your first 1.0.0 build. + +**Edited parameter descriptions are appended to, not replaced.** Where the +description in the markdown differs from the one in the module's +comment-based help, `Update-MarkdownCommandHelp` adds the comment-based help +text underneath the markdown text rather than reconciling them — and it does +so again on every subsequent build. After one build: + +```text +### -IncludeHidden + +Include widgets that are marked as hidden. HANDWRITTEN-PARAMETER text. +Include widgets that are marked as hidden. +``` + +After two: + +```text +Include widgets that are marked as hidden. HANDWRITTEN-PARAMETER text. +Include widgets that are marked as hidden. +Include widgets that are marked as hidden. +``` + +Parameter descriptions unchanged from comment-based help are not affected. +The fix is to keep comment-based help as the single source of truth for +parameter descriptions and delete the divergent markdown text; prose in +`DESCRIPTION`, `EXAMPLES`, and `NOTES` does not behave this way. + +#### What the front matter becomes + +```yaml +# Before (0.14.x) +external help file: ScratchModule-help.xml +Module Name: ScratchModule +online version: https://example.com/scratch-widget +schema: 2.0.0 +``` + +```yaml +# After (1.0.0) +document type: cmdlet +external help file: ScratchModule-help.xml +HelpUri: https://example.com/scratch-widget +Module Name: ScratchModule +ms.date: 08/26/2026 +PlatyPS schema version: 2024-05-01 +``` + +`schema:` becomes `PlatyPS schema version:`, `online version:` becomes +`HelpUri:`, `document type:` and `ms.date:` are new, and the keys are +re-sorted. `external help file:` is carried across **byte for byte**, which +is what you want: the value names the MAML file, PowerShellBuild pins it to +the 0.14.x lowercase `-help.xml` spelling, and an existing +`.ExternalHelp` directive keeps resolving — including on case-sensitive file +systems. + +#### The documents the build cannot convert + +`Update-MarkdownCommandHelp` looks each document's command up in the current +session. A document for a command your module no longer exports has nothing +to look up, so the cmdlet writes a non-terminating error whose message is +just the command name, and leaves the file on the 0.14.x schema: + +```text +Update-MarkdownCommandHelp: Get-ScratchWidget +``` + +The error identifier is +`FailedToImportMarkdown,Microsoft.PowerShell.PlatyPS.UpdateMarkdownHelpCommand` +and the category reason is `CommandNotFoundException`. **Detection:** after +the build, `Measure-PlatyPSMarkdown` still reports `V1Schema` for those +files. Delete them if the command is gone, or rename them to match the +command that replaced it. + +#### Converting by hand, without a build + +You need the one-shot below only when you want the conversion as its own +reviewable commit, separate from a build. Import your module first — the +same session lookup applies: + +```powershell +Import-Module ./Output/MyModule/1.0.0/MyModule.psd1 -Force + +$commandDocument = Measure-PlatyPSMarkdown -Path ./docs/en-US/*.md | + Where-Object FileType -match 'CommandHelp' +Update-MarkdownCommandHelp -Path $commandDocument.FilePath -NoBackup +``` + +That converts the command documents only. If your 0.14.x tree has a module +landing page, it stays on the old schema — `Update-MarkdownModuleFile` +cannot refresh one on its own, because it requires the imported +`-CommandHelp` objects the page indexes. Leave it: your next build replaces +the landing page wholesale and stamps the 1.x front matter on it. + +Three details in that snippet are load-bearing: + +- **Filter to `CommandHelp`.** Your tree contains a module landing page + (`.md`), and it is a different document type. Fed to + `Update-MarkdownCommandHelp` it is at least rejected loudly — + `'…\MyModule.md' is not a CommandHelp file.` — and left alone while the + command documents still convert. The other two entry points are not so + safe. `Import-MarkdownCommandHelp` accepts the landing page without + complaint, hands back a `CommandHelp` object titled after the module, and + `Export-MarkdownCommandHelp` then writes it back out as an empty cmdlet + document whose front matter has the landing page's + `{{ Update Download Link }}` placeholders embedded as malformed YAML. Feed + the same object to `Export-MamlCommandHelp` and it aborts the whole export + and writes **nothing**, not even for the command documents that were fine + ([PowerShell/platyPS#862](https://github.com/PowerShell/platyPS/issues/862)). +- **Pass `-NoBackup`.** Without it the cmdlet writes a `.md.bak` + beside every document, and a second run fails on all of them with + `IOException: Cannot create a file when that file already exists.` + ([PowerShell/platyPS#863](https://github.com/PowerShell/platyPS/issues/863)). + With `-NoBackup` the command is repeatable. Your version control is the + backup. +- **Update in place; do not export.** The export pipeline that looks like + the natural one-shot does not do what it appears to: + + ```powershell + # Does NOT convert ./docs/en-US in place + Measure-PlatyPSMarkdown -Path ./docs/en-US/*.md | + Where-Object FileType -match 'CommandHelp' | + Import-MarkdownCommandHelp -Path { $_.FilePath } | + Export-MarkdownCommandHelp -OutputFolder ./docs/en-US -Force + ``` + + `Export-MarkdownCommandHelp` always appends the module name to + `-OutputFolder`, so that writes `./docs/en-US/MyModule/*.md` and leaves + every original file untouched on the 0.14.x schema. If you use the export + pipeline anyway, send it to a staging folder and move + `//*.md` back over your tree. Dropping `-Force` does not + help either: the export then skips each existing file with only a warning + — `'Get-ScratchWidget' exists, skipping. Use -Force to overwrite.` — + writes nothing, and returns success. + +#### Recommended sequence + +1. Commit or stash everything, so the conversion diff stands alone. +2. Grep your documents for headings outside the PlatyPS schema and relocate + that content. +3. Run your normal 1.0.0 build. +4. Run `Measure-PlatyPSMarkdown` and confirm every command document reports + `V2Schema`. Anything still on `V1Schema` is an orphaned document. +5. Read the diff for prose, not just for schema churn — in particular + doubled parameter descriptions and missing custom sections. +6. Commit the converted tree together with the new `.md` landing + page. + +Verified against Microsoft.PowerShell.PlatyPS 1.0.3 on PowerShell 7 with a +throwaway module whose 0.14.x markdown was generated by platyPS 0.14.2. +Note that platyPS 0.14.2 and Microsoft.PowerShell.PlatyPS cannot be loaded +into the same session — they ship conflicting `YamlDotNet` assemblies — so +if you compare old and new output yourself, use two separate PowerShell +processes. + +Related: [#154](https://github.com/psake/PowerShellBuild/issues/154). + ## Adding an entry (for PR contributors) Every breaking-change PR that lands in v1.0.0 must add an entry here for