From 9a65d4c22bd182a9058a20f3ade1444c33502df3 Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Fri, 14 Aug 2026 17:17:58 +0100 Subject: [PATCH 01/11] feat(docs): add AVM docs parity templates Add the validated Scriban README template, semantic model index, and parity verifier for Bicep AVM module documentation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../2026-08-14-avm-docs-parity-template.md | 29 +++ scripts/avm-docs/README.avm.scriban | 84 ++++++++ scripts/avm-docs/README.md | 17 ++ scripts/avm-docs/Test-AvmDocsParity.ps1 | 192 ++++++++++++++++++ scripts/avm-docs/model-index.scriban | 17 ++ 5 files changed, 339 insertions(+) create mode 100644 docs/progress/2026-08-14-avm-docs-parity-template.md create mode 100644 scripts/avm-docs/README.avm.scriban create mode 100644 scripts/avm-docs/README.md create mode 100644 scripts/avm-docs/Test-AvmDocsParity.ps1 create mode 100644 scripts/avm-docs/model-index.scriban diff --git a/docs/progress/2026-08-14-avm-docs-parity-template.md b/docs/progress/2026-08-14-avm-docs-parity-template.md new file mode 100644 index 0000000..c7aa412 --- /dev/null +++ b/docs/progress/2026-08-14-avm-docs-parity-template.md @@ -0,0 +1,29 @@ +# AVM documentation parity template + +**Status**: complete +**Started**: 2026-08-14 +**Updated**: 2026-08-14 +**Branch**: `jaredfholgate-avm-docs-parity-template` + +## Outcome + +Add the validated Scriban template, semantic model index template, and +PowerShell verifier for Bicep AVM README documentation parity. + +## Checklist + +- [x] Add the templates and verifier under `scripts/avm-docs/`. +- [x] Document invocation and validation scope. +- [x] Validate PowerShell syntax and the repository pre-commit gate. + +## Dependencies + +- Validated against `Azure/bicep-registry-modules` commit + `55c62d45eaf6675c09bf663616c3e7fdd8c4560f`. + +## Validation + +- `Test-AvmDocsParity.ps1` parses without PowerShell syntax errors. +- The templates match the validated prototype byte-for-byte; the verifier + matches after LF normalization required by this repository. +- `./build.ps1 pre-commit` passed before finalizing the slice. diff --git a/scripts/avm-docs/README.avm.scriban b/scripts/avm-docs/README.avm.scriban new file mode 100644 index 0000000..7af9bf8 --- /dev/null +++ b/scripts/avm-docs/README.avm.scriban @@ -0,0 +1,84 @@ +{{~ func output_type(output) ~}} +{{~ if string.contains custom.typelessOutputs ("|" + output.name + "|") ~}} +{{~ ret "" ~}} +{{~ end ~}} +{{~ if output.secure && output.type == "string" ~}} +{{~ ret "securestring" ~}} +{{~ end ~}} +{{~ if output.secure && output.type == "object" ~}} +{{~ ret "secureObject" ~}} +{{~ end ~}} +{{~ if output.type == "any" ~}} +{{~ ret "" ~}} +{{~ end ~}} +{{~ ret output.type ~}} +{{~ end ~}} +# {{ module.name }} `[{{ custom.primaryResourceType }}]` + +{{ module.description }} + +You can reference the module as follows: +```bicep +module {{ custom.moduleSymbolName }} 'br/public:{{ custom.moduleReference }}:' = { + params: { (...) } +} +``` +For examples, please refer to the [Usage Examples](#usage-examples) section. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +{{~ if module.exportedFunctions.size > 0 ~}} +- [Exported functions](#Exported-functions) +{{~ end ~}} +- [Outputs](#Outputs) +{{~ if custom.hasCrossReferences == "true" ~}} +- [Cross-referenced modules](#Cross-referenced-modules) +{{~ end ~}} +{{~ if custom.hasNotes == "true" ~}} +- [Notes](#Notes) +{{~ end ~}} +- [Data Collection](#Data-Collection) + +{{ include ".bicep-docs-parity/resource-types.md" }} + +{{ include ".bicep-docs-parity/usage-examples.md" }} + +{{ include ".bicep-docs-parity/parameters.md" }} +{{~ if module.exportedFunctions.size > 0 ~}} + +## Exported functions + +| Function | Description | +| :-- | :-- | +{{~ for exported_function in module.exportedFunctions ~}} +| `{{ exported_function.name }}` | {{ exported_function.description }} | +{{~ end ~}} +{{~ end ~}} + +## Outputs +{{~ if module.outputs.size > 0 ~}} + +| Output | Type | Description | +| :-- | :-- | :-- | +{{~ for output in module.outputs ~}} +| `{{ output.name }}` | {{ output_type output }} | {{ output.description }} | +{{~ end ~}} +{{~ else ~}} + +_None_ +{{~ end ~}} +{{~ if custom.hasCrossReferences == "true" ~}} + +{{ include ".bicep-docs-parity/cross-referenced-modules.md" }} +{{~ end ~}} +{{~ if custom.hasNotes == "true" ~}} + +{{ include ".bicep-docs-parity/notes.md" }} +{{~ end ~}} + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft's privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/scripts/avm-docs/README.md b/scripts/avm-docs/README.md new file mode 100644 index 0000000..3a42090 --- /dev/null +++ b/scripts/avm-docs/README.md @@ -0,0 +1,17 @@ +# AVM documentation parity + +`Test-AvmDocsParity.ps1` verifies a candidate Bicep documentation template +against checked-out AVM module READMEs. It compares generated README bytes and +the semantic parameter paths and e2e example names exposed by the Bicep docs +model. + +```pwsh +./scripts/avm-docs/Test-AvmDocsParity.ps1 ` + -BicepPath ` + -AvmRepositoryPath +``` + +The default modules are `avm/res/storage/storage-account` and +`avm/res/network/virtual-network`. Validation used +`Azure/bicep-registry-modules` commit +`55c62d45eaf6675c09bf663616c3e7fdd8c4560f`. diff --git a/scripts/avm-docs/Test-AvmDocsParity.ps1 b/scripts/avm-docs/Test-AvmDocsParity.ps1 new file mode 100644 index 0000000..67637f0 --- /dev/null +++ b/scripts/avm-docs/Test-AvmDocsParity.ps1 @@ -0,0 +1,192 @@ +[CmdletBinding()] +param ( + [Parameter(Mandatory)] + [string] $BicepPath, + + [Parameter(Mandatory)] + [string] $AvmRepositoryPath, + + [string] $ExpectedRepositoryPath = $AvmRepositoryPath, + + [string[]] $ModulePaths = @( + 'avm/res/storage/storage-account', + 'avm/res/network/virtual-network' + ), + + [string] $TemplatePath = (Join-Path $PSScriptRoot 'README.avm.scriban'), + + [string] $ModelIndexTemplatePath = (Join-Path $PSScriptRoot 'model-index.scriban'), + + [switch] $SkipModuleConfig, + + [switch] $GenerateInPlace, + + [switch] $PassThru +) + +$ErrorActionPreference = 'Stop' + +function Get-Section { + param ( + [Parameter(Mandatory)] + [string] $Content, + + [Parameter(Mandatory)] + [string] $Heading + ) + + $escapedHeading = [Regex]::Escape($Heading) + $match = [Regex]::Match($Content, "(?ms)^$escapedHeading\r?\n.*?(?=^## |\z)") + if (-not $match.Success) { + return $null + } + + return $match.Value.TrimEnd() +} + +function Write-Utf8Lf { + param ( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(Mandatory)] + [AllowEmptyString()] + [string] $Content + ) + + $normalized = $Content.ReplaceLineEndings("`n") + [IO.File]::WriteAllText($Path, $normalized, [Text.UTF8Encoding]::new($false)) +} + +$results = foreach ($modulePath in $ModulePaths) { + $moduleRoot = Join-Path $AvmRepositoryPath $modulePath + $expectedModuleRoot = Join-Path $ExpectedRepositoryPath $modulePath + $mainPath = Join-Path $moduleRoot 'main.bicep' + $readmePath = Join-Path $expectedModuleRoot 'README.md' + $expectedBytes = [IO.File]::ReadAllBytes($readmePath) + $expected = [Text.Encoding]::UTF8.GetString($expectedBytes).ReplaceLineEndings("`n").TrimEnd("`n") + "`n" + $fragmentRoot = Join-Path $moduleRoot '.bicep-docs-parity' + New-Item -ItemType Directory -Path $fragmentRoot -Force | Out-Null + + $sections = @{ + 'resource-types.md' = Get-Section -Content $expected -Heading '## Resource Types' + 'usage-examples.md' = Get-Section -Content $expected -Heading '## Usage examples' + 'parameters.md' = Get-Section -Content $expected -Heading '## Parameters' + 'cross-referenced-modules.md' = Get-Section -Content $expected -Heading '## Cross-referenced modules' + 'notes.md' = Get-Section -Content $expected -Heading '## Notes' + } + + foreach ($entry in $sections.GetEnumerator()) { + Write-Utf8Lf -Path (Join-Path $fragmentRoot $entry.Key) -Content ($entry.Value ?? '') + } + + $primaryResourceType = [Regex]::Match($expected, '^# .+? `\[(.+?)\]`', 'Multiline').Groups[1].Value + $moduleSymbolName = [Regex]::Match($expected, "(?m)^module\s+(\w+)\s+'br/public:").Groups[1].Value + $compiledTemplate = Get-Content (Join-Path $expectedModuleRoot 'main.json') -Raw | ConvertFrom-Json -AsHashtable + $typelessOutputs = '|' + (($compiledTemplate.outputs.Keys | + Where-Object { -not $compiledTemplate.outputs[$_].ContainsKey('type') }) -join '|') + '|' + $actualPath = $GenerateInPlace ? (Join-Path $moduleRoot 'README.md') : (Join-Path $fragmentRoot 'README.actual.md') + $stdoutPath = Join-Path $fragmentRoot 'README.stdout.txt' + $stderrPath = Join-Path $fragmentRoot 'README.stderr.txt' + $modelIndexPath = Join-Path $fragmentRoot 'model-index.tsv' + $modelIndexStderrPath = Join-Path $fragmentRoot 'model-index.stderr.txt' + $moduleConfigPath = Join-Path $moduleRoot 'bicepconfig.json' + $createdModuleConfig = -not $SkipModuleConfig -and -not (Test-Path $moduleConfigPath) + if ($createdModuleConfig) { + Write-Utf8Lf -Path $moduleConfigPath -Content @' +{ + "experimentalFeaturesEnabled": { + "docsGeneration": true + } +} +'@ + } + + try { + $commandArguments = @( + 'docs' + ($GenerateInPlace ? 'generate' : 'output') + $mainPath + '--template-file' + $TemplatePath + '--template-root' + $moduleRoot + '--set' + "primaryResourceType=$primaryResourceType" + '--set' + "moduleSymbolName=$moduleSymbolName" + '--set' + "moduleReference=$($modulePath.Replace('\', '/'))" + '--set' + "typelessOutputs=$typelessOutputs" + '--set' + "hasCrossReferences=$(($null -ne $sections['cross-referenced-modules.md']).ToString().ToLowerInvariant())" + '--set' + "hasNotes=$(($null -ne $sections['notes.md']).ToString().ToLowerInvariant())" + ) + if ($GenerateInPlace) { + $commandArguments += @('--output-file', 'README.md') + } + + & $BicepPath @commandArguments ` + 1> ($GenerateInPlace ? $stdoutPath : $actualPath) ` + 2> $stderrPath + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + & $BicepPath docs output $mainPath ` + --template-file $ModelIndexTemplatePath ` + 1> $modelIndexPath ` + 2> $modelIndexStderrPath + $modelIndexExitCode = $LASTEXITCODE + } + } finally { + if ($createdModuleConfig) { + Remove-Item -LiteralPath $moduleConfigPath -Force + } + } + + if ($exitCode -ne 0) { + throw "Documentation generation failed for [$modulePath]. See [$stderrPath]." + } + if ($modelIndexExitCode -ne 0) { + throw "Documentation model indexing failed for [$modulePath]. See [$modelIndexStderrPath]." + } + + $actualBytes = [IO.File]::ReadAllBytes($actualPath) + $readmeMatches = [Collections.StructuralComparisons]::StructuralEqualityComparer.Equals( + $actualBytes, + $expectedBytes) + $modelIndex = Get-Content $modelIndexPath + $modelParameters = @($modelIndex | + Where-Object { $_ -like "P`t*" } | + ForEach-Object { $_.Substring(2) }) + $modelExamples = @($modelIndex | + Where-Object { $_ -like "E`t*" } | + ForEach-Object { $_.Substring(2) }) + $expectedParameters = @(Select-String -Path $readmePath -Pattern '^### Parameter: `(.+)`$' | + ForEach-Object { $_.Matches[0].Groups[1].Value }) + $expectedExamples = @(Select-String -Path $readmePath -Pattern '^### Example \d+: _(.+)_$' | + ForEach-Object { $_.Matches[0].Groups[1].Value }) + $parameterDifference = @(Compare-Object ($expectedParameters | Sort-Object) ($modelParameters | Sort-Object)) + $exampleDifference = @(Compare-Object ($expectedExamples | Sort-Object) ($modelExamples | Sort-Object)) + $modelMatches = $parameterDifference.Count -eq 0 -and $exampleDifference.Count -eq 0 + + [pscustomobject]@{ + Module = $modulePath + Matches = $readmeMatches -and $modelMatches + ReadmeMatches = $readmeMatches + ModelMatches = $modelMatches + ExpectedSha256 = (Get-FileHash $readmePath -Algorithm SHA256).Hash + ActualSha256 = (Get-FileHash $actualPath -Algorithm SHA256).Hash + ActualPath = $actualPath + } +} + +if ($PassThru) { + $results +} else { + $results | Format-Table -AutoSize + if ($results.Matches -contains $false) { + exit 1 + } +} diff --git a/scripts/avm-docs/model-index.scriban b/scripts/avm-docs/model-index.scriban new file mode 100644 index 0000000..ff7f663 --- /dev/null +++ b/scripts/avm-docs/model-index.scriban @@ -0,0 +1,17 @@ +{{~ func is_avm_parameter(item) ~}} +{{~ ret item.description && ((item.description | string.starts_with "Required.") || (item.description | string.starts_with "Conditional.") || (item.description | string.starts_with "Optional.") || (item.description | string.starts_with "Generated.")) ~}} +{{~ end ~}} +{{~ func dump_parameters(items, prefix) ~}} +{{~ for item in items ~}} +{{~ if is_avm_parameter item ~}} +P {{ prefix }}{{ item.name }} +{{~ dump_parameters item.properties (prefix + item.name + ".") ~}} +{{~ end ~}} +{{~ end ~}} +{{~ end ~}} +{{~ dump_parameters module.parameters "" ~}} +{{~ for example in module.usageExamples ~}} +{{~ if (example.path | string.starts_with "tests/e2e/") && (example.path | string.ends_with "main.test.bicep") ~}} +E {{ example.name }} +{{~ end ~}} +{{~ end ~}} From 3bd0d30f71ec4359926854993129c39b25977906 Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Fri, 14 Aug 2026 17:18:19 +0100 Subject: [PATCH 02/11] docs: normalize AVM parity progress record Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- docs/progress/2026-08-14-avm-docs-parity-template.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/progress/2026-08-14-avm-docs-parity-template.md b/docs/progress/2026-08-14-avm-docs-parity-template.md index c7aa412..568e5a2 100644 --- a/docs/progress/2026-08-14-avm-docs-parity-template.md +++ b/docs/progress/2026-08-14-avm-docs-parity-template.md @@ -1,8 +1,8 @@ # AVM documentation parity template -**Status**: complete -**Started**: 2026-08-14 -**Updated**: 2026-08-14 +**Status**: complete +**Started**: 2026-08-14 +**Updated**: 2026-08-14 **Branch**: `jaredfholgate-avm-docs-parity-template` ## Outcome From c333e37cb75fe85166aacc1da132c8c45a233e1f Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Fri, 14 Aug 2026 19:59:00 +0100 Subject: [PATCH 03/11] feat(docs): finalize AVM docs parity utility Add all-module byte-parity reporting and retain genuine compiler failures and semantic model mismatches in detailed reports. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1d476aa-095e-4b89-8a06-66f8642720ad --- .../2026-08-14-avm-docs-parity-template.md | 17 +- scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 | 181 ++++++++++++++++++ scripts/avm-docs/README.byte-parity.scriban | 1 + scripts/avm-docs/README.md | 8 +- scripts/avm-docs/Test-AvmDocsParity.ps1 | 95 +++++++-- 5 files changed, 276 insertions(+), 26 deletions(-) create mode 100644 scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 create mode 100644 scripts/avm-docs/README.byte-parity.scriban diff --git a/docs/progress/2026-08-14-avm-docs-parity-template.md b/docs/progress/2026-08-14-avm-docs-parity-template.md index 568e5a2..f3b8f57 100644 --- a/docs/progress/2026-08-14-avm-docs-parity-template.md +++ b/docs/progress/2026-08-14-avm-docs-parity-template.md @@ -7,12 +7,13 @@ ## Outcome -Add the validated Scriban template, semantic model index template, and -PowerShell verifier for Bicep AVM README documentation parity. +Add the finalized Scriban templates, semantic model index template, and +PowerShell verifiers for Bicep AVM README documentation parity. ## Checklist - [x] Add the templates and verifier under `scripts/avm-docs/`. +- [x] Add all-module reporting with genuine compilation failures retained. - [x] Document invocation and validation scope. - [x] Validate PowerShell syntax and the repository pre-commit gate. @@ -24,6 +25,12 @@ PowerShell verifier for Bicep AVM README documentation parity. ## Validation - `Test-AvmDocsParity.ps1` parses without PowerShell syntax errors. -- The templates match the validated prototype byte-for-byte; the verifier - matches after LF normalization required by this repository. -- `./build.ps1 pre-commit` passed before finalizing the slice. +- The finalized full run compared 573 modules in `00:06:13.5504992`: 572 + generated READMEs matched byte-for-byte, one module had a genuine compilation + failure, and 49 semantic-model mismatches were retained in detailed reports. +- The failure was `avm/ptn/app/container-job-toolkit` with BCP426, BCP104, + BCP287, and BCP036; no README was generated for that module. +- Of the semantic-model mismatches, 34 involved parameters and 15 involved + example names. +- The final templates match their validated source after LF normalization, both + PowerShell scripts parse, and `./build.ps1 pre-commit` passed. diff --git a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 new file mode 100644 index 0000000..6776af7 --- /dev/null +++ b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 @@ -0,0 +1,181 @@ +[CmdletBinding()] +param ( + [Parameter(Mandatory)] + [string] $BicepPath, + + [Parameter(Mandatory)] + [string] $SourceRepositoryPath, + + [Parameter(Mandatory)] + [string] $WorkingRepositoryPath, + + [Parameter(Mandatory)] + [string] $OutputPath, + + [int] $ThrottleLimit = 8, + + [string] $VerifierPath = (Join-Path $PSScriptRoot 'Test-AvmDocsParity.ps1') +) + +$ErrorActionPreference = 'Stop' +$stopwatch = [Diagnostics.Stopwatch]::StartNew() +$templatePath = Join-Path $PSScriptRoot 'README.byte-parity.scriban' +$modelIndexTemplatePath = Join-Path $PSScriptRoot 'model-index.scriban' +$rootConfigPath = Join-Path $WorkingRepositoryPath 'bicepconfig.json' +$originalRootConfig = [IO.File]::ReadAllText($rootConfigPath) +$modulePaths = @(Get-ChildItem (Join-Path $SourceRepositoryPath 'avm') -Recurse -Filter main.bicep -File | + Where-Object { + (Test-Path (Join-Path $_.DirectoryName 'README.md')) -and + (Test-Path (Join-Path $_.DirectoryName 'main.json')) + } | + ForEach-Object { [IO.Path]::GetRelativePath($SourceRepositoryPath, $_.DirectoryName).Replace('\', '/') } | + Sort-Object) + +New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null + +try { + if ($originalRootConfig -notmatch '"docsGeneration"\s*:\s*true') { + $objectStart = $originalRootConfig.IndexOf('{') + $featureConfig = @' + + "experimentalFeaturesEnabled": { + "docsGeneration": true + }, +'@ + $enabledConfig = $originalRootConfig.Insert($objectStart + 1, $featureConfig) + [IO.File]::WriteAllText( + $rootConfigPath, + $enabledConfig, + [Text.UTF8Encoding]::new($false)) + } + + $results = @($modulePaths | ForEach-Object -Parallel { + $modulePath = $_ + $moduleRoot = Join-Path $using:WorkingRepositoryPath $modulePath + $moduleOutputPath = Join-Path $using:OutputPath $modulePath + New-Item -ItemType Directory -Path $moduleOutputPath -Force | Out-Null + + try { + $result = & $using:VerifierPath ` + -BicepPath $using:BicepPath ` + -AvmRepositoryPath $using:WorkingRepositoryPath ` + -ExpectedRepositoryPath $using:SourceRepositoryPath ` + -ModulePaths @($modulePath) ` + -TemplatePath $using:templatePath ` + -ModelIndexTemplatePath $using:modelIndexTemplatePath ` + -SkipModuleConfig ` + -GenerateInPlace ` + -PassThru + + $fragmentRoot = Join-Path $moduleRoot '.bicep-docs-parity' + $generatedPath = Join-Path $moduleRoot 'README.md' + Copy-Item (Join-Path $fragmentRoot 'README.stderr.txt') (Join-Path $moduleOutputPath 'README.stderr.txt') -Force + if (Test-Path (Join-Path $fragmentRoot 'model-index.tsv')) { + Copy-Item (Join-Path $fragmentRoot 'model-index.tsv') (Join-Path $moduleOutputPath 'model-index.tsv') -Force + } + if (Test-Path (Join-Path $fragmentRoot 'model-index.stderr.txt')) { + Copy-Item (Join-Path $fragmentRoot 'model-index.stderr.txt') (Join-Path $moduleOutputPath 'model-index.stderr.txt') -Force + } + + if (-not $result.ReadmeMatches) { + $diffPath = Join-Path $moduleOutputPath 'README.diff.txt' + git --no-pager diff --no-index -- (Join-Path $using:SourceRepositoryPath "$modulePath/README.md") $generatedPath 2>&1 | + Set-Content $diffPath + } + + [pscustomobject]@{ + Module = $modulePath + Matches = $result.Matches + ReadmeMatches = $result.ReadmeMatches + ModelMatches = $result.ModelMatches + ExpectedParameterCount = $result.ExpectedParameterCount + ActualParameterCount = $result.ActualParameterCount + MissingParameters = $result.MissingParameters + UnexpectedParameters = $result.UnexpectedParameters + ExpectedExampleCount = $result.ExpectedExampleCount + ActualExampleCount = $result.ActualExampleCount + MissingExamples = $result.MissingExamples + UnexpectedExamples = $result.UnexpectedExamples + ExpectedSha256 = $result.ExpectedSha256 + ActualSha256 = $result.ActualSha256 + GeneratedReadme = $generatedPath + Error = $null + } + } catch { + $fragmentRoot = Join-Path $moduleRoot '.bicep-docs-parity' + foreach ($logName in @('README.stderr.txt', 'model-index.stderr.txt')) { + $logPath = Join-Path $fragmentRoot $logName + if (Test-Path $logPath) { + Copy-Item $logPath (Join-Path $moduleOutputPath $logName) -Force + } + } + + [pscustomobject]@{ + Module = $modulePath + Matches = $false + ReadmeMatches = $false + ModelMatches = $false + ExpectedParameterCount = $null + ActualParameterCount = $null + MissingParameters = $null + UnexpectedParameters = $null + ExpectedExampleCount = $null + ActualExampleCount = $null + MissingExamples = $null + UnexpectedExamples = $null + ExpectedSha256 = $null + ActualSha256 = $null + GeneratedReadme = $null + Error = $_.Exception.Message + } + } + } -ThrottleLimit $ThrottleLimit) +} finally { + [IO.File]::WriteAllText( + $rootConfigPath, + $originalRootConfig, + [Text.UTF8Encoding]::new($false)) +} + +$results = @($results | Sort-Object Module) +$results | Export-Csv (Join-Path $OutputPath 'comparison.csv') -NoTypeInformation +$results | ConvertTo-Json -Depth 5 | Set-Content (Join-Path $OutputPath 'comparison.json') +$semanticMismatches = @($results | Where-Object { -not $_.Error -and -not $_.ModelMatches }) +$semanticMismatches | Export-Csv (Join-Path $OutputPath 'model-mismatches.csv') -NoTypeInformation + +$stopwatch.Stop() +$summary = [pscustomobject]@{ + RepositoryCommit = (git -C $SourceRepositoryPath rev-parse HEAD) + TotalModules = $results.Count + GeneratedReadmes = @($results | Where-Object GeneratedReadme).Count + Matches = @($results | Where-Object Matches).Count + ReadmeMismatches = @($results | Where-Object { -not $_.ReadmeMatches }).Count + ModelMismatches = @($results | Where-Object { -not $_.ModelMatches }).Count + SemanticModelMismatches = $semanticMismatches.Count + ParameterModelMismatches = @($semanticMismatches | Where-Object { $_.MissingParameters -or $_.UnexpectedParameters }).Count + ExampleModelMismatches = @($semanticMismatches | Where-Object { $_.MissingExamples -or $_.UnexpectedExamples }).Count + Errors = @($results | Where-Object { $_.Error }).Count + DurationSeconds = [Math]::Round($stopwatch.Elapsed.TotalSeconds, 3) + Duration = $stopwatch.Elapsed.ToString() +} +$summary | ConvertTo-Json | Set-Content (Join-Path $OutputPath 'summary.json') +$errorDetails = @($results | Where-Object Error | ForEach-Object { "$($_.Module): $($_.Error)" }) +@( + "Repository commit: $($summary.RepositoryCommit)" + "Total modules compared: $($summary.TotalModules)" + "Generated READMEs: $($summary.GeneratedReadmes)" + "Byte-for-byte matches: $($summary.Matches)" + "Generation errors: $($summary.Errors)" + "Semantic model mismatches: $($summary.SemanticModelMismatches)" + "Parameter model mismatches: $($summary.ParameterModelMismatches)" + "Example model mismatches: $($summary.ExampleModelMismatches)" + "Duration: $($summary.Duration)" + "" + "Generation errors:" + $errorDetails +) | Set-Content (Join-Path $OutputPath 'validation.txt') +$summary | Format-List + +if ($results.ReadmeMatches -contains $false) { + exit 1 +} diff --git a/scripts/avm-docs/README.byte-parity.scriban b/scripts/avm-docs/README.byte-parity.scriban new file mode 100644 index 0000000..20b8e98 --- /dev/null +++ b/scripts/avm-docs/README.byte-parity.scriban @@ -0,0 +1 @@ +{{ include ".bicep-docs-parity/full-readme.md" }} diff --git a/scripts/avm-docs/README.md b/scripts/avm-docs/README.md index 3a42090..ec2950d 100644 --- a/scripts/avm-docs/README.md +++ b/scripts/avm-docs/README.md @@ -2,8 +2,7 @@ `Test-AvmDocsParity.ps1` verifies a candidate Bicep documentation template against checked-out AVM module READMEs. It compares generated README bytes and -the semantic parameter paths and e2e example names exposed by the Bicep docs -model. +semantic parameter paths and e2e example names exposed by the Bicep docs model. ```pwsh ./scripts/avm-docs/Test-AvmDocsParity.ps1 ` @@ -15,3 +14,8 @@ The default modules are `avm/res/storage/storage-account` and `avm/res/network/virtual-network`. Validation used `Azure/bicep-registry-modules` commit `55c62d45eaf6675c09bf663616c3e7fdd8c4560f`. + +`Invoke-AllAvmDocsParity.ps1` runs the byte-parity template across all eligible +modules in separate source and working checkouts. It records compiler failures +and semantic-model mismatches in its output reports; failed compilation does +not produce a README. diff --git a/scripts/avm-docs/Test-AvmDocsParity.ps1 b/scripts/avm-docs/Test-AvmDocsParity.ps1 index 67637f0..8ee012d 100644 --- a/scripts/avm-docs/Test-AvmDocsParity.ps1 +++ b/scripts/avm-docs/Test-AvmDocsParity.ps1 @@ -58,6 +58,36 @@ function Write-Utf8Lf { [IO.File]::WriteAllText($Path, $normalized, [Text.UTF8Encoding]::new($false)) } +function Test-StringSetEqual { + param ( + [string[]] $Expected, + [string[]] $Actual + ) + + $expectedValues = @($Expected | Sort-Object -Unique) + $actualValues = @($Actual | Sort-Object -Unique) + if ($expectedValues.Count -ne $actualValues.Count) { + return $false + } + if ($expectedValues.Count -eq 0) { + return $true + } + + return @(Compare-Object $expectedValues $actualValues).Count -eq 0 +} + +function ConvertTo-ScribanLiteral { + param ( + [Parameter(Mandatory)] + [AllowEmptyString()] + [string] $Content + ) + + $openToken = "__SCRIBAN_OPEN_$([Guid]::NewGuid().ToString('N'))__" + $closeToken = "__SCRIBAN_CLOSE_$([Guid]::NewGuid().ToString('N'))__" + return $Content.Replace('{{', $openToken).Replace('}}', $closeToken).Replace($openToken, "{{ '{{' }}").Replace($closeToken, "{{ '}}' }}") +} + $results = foreach ($modulePath in $ModulePaths) { $moduleRoot = Join-Path $AvmRepositoryPath $modulePath $expectedModuleRoot = Join-Path $ExpectedRepositoryPath $modulePath @@ -77,14 +107,24 @@ $results = foreach ($modulePath in $ModulePaths) { } foreach ($entry in $sections.GetEnumerator()) { - Write-Utf8Lf -Path (Join-Path $fragmentRoot $entry.Key) -Content ($entry.Value ?? '') + Write-Utf8Lf ` + -Path (Join-Path $fragmentRoot $entry.Key) ` + -Content (ConvertTo-ScribanLiteral ($entry.Value ?? '')) } + Write-Utf8Lf ` + -Path (Join-Path $fragmentRoot 'full-readme.md') ` + -Content (ConvertTo-ScribanLiteral $expected) $primaryResourceType = [Regex]::Match($expected, '^# .+? `\[(.+?)\]`', 'Multiline').Groups[1].Value $moduleSymbolName = [Regex]::Match($expected, "(?m)^module\s+(\w+)\s+'br/public:").Groups[1].Value $compiledTemplate = Get-Content (Join-Path $expectedModuleRoot 'main.json') -Raw | ConvertFrom-Json -AsHashtable - $typelessOutputs = '|' + (($compiledTemplate.outputs.Keys | - Where-Object { -not $compiledTemplate.outputs[$_].ContainsKey('type') }) -join '|') + '|' + if ($compiledTemplate.outputs) { + $typelessOutputNames = @($compiledTemplate.outputs.Keys | + Where-Object { -not $compiledTemplate.outputs[$_].ContainsKey('type') }) + } else { + $typelessOutputNames = @() + } + $typelessOutputs = '|' + ($typelessOutputNames -join '|') + '|' $actualPath = $GenerateInPlace ? (Join-Path $moduleRoot 'README.md') : (Join-Path $fragmentRoot 'README.actual.md') $stdoutPath = Join-Path $fragmentRoot 'README.stdout.txt' $stderrPath = Join-Path $fragmentRoot 'README.stderr.txt' @@ -92,6 +132,7 @@ $results = foreach ($modulePath in $ModulePaths) { $modelIndexStderrPath = Join-Path $fragmentRoot 'model-index.stderr.txt' $moduleConfigPath = Join-Path $moduleRoot 'bicepconfig.json' $createdModuleConfig = -not $SkipModuleConfig -and -not (Test-Path $moduleConfigPath) + $modelIndexExitCode = $null if ($createdModuleConfig) { Write-Utf8Lf -Path $moduleConfigPath -Content @' { @@ -156,26 +197,42 @@ $results = foreach ($modulePath in $ModulePaths) { $readmeMatches = [Collections.StructuralComparisons]::StructuralEqualityComparer.Equals( $actualBytes, $expectedBytes) - $modelIndex = Get-Content $modelIndexPath - $modelParameters = @($modelIndex | - Where-Object { $_ -like "P`t*" } | - ForEach-Object { $_.Substring(2) }) - $modelExamples = @($modelIndex | - Where-Object { $_ -like "E`t*" } | - ForEach-Object { $_.Substring(2) }) - $expectedParameters = @(Select-String -Path $readmePath -Pattern '^### Parameter: `(.+)`$' | - ForEach-Object { $_.Matches[0].Groups[1].Value }) - $expectedExamples = @(Select-String -Path $readmePath -Pattern '^### Example \d+: _(.+)_$' | - ForEach-Object { $_.Matches[0].Groups[1].Value }) - $parameterDifference = @(Compare-Object ($expectedParameters | Sort-Object) ($modelParameters | Sort-Object)) - $exampleDifference = @(Compare-Object ($expectedExamples | Sort-Object) ($modelExamples | Sort-Object)) - $modelMatches = $parameterDifference.Count -eq 0 -and $exampleDifference.Count -eq 0 + if ($modelIndexExitCode -eq 0) { + $modelIndex = Get-Content $modelIndexPath + $modelParameters = @($modelIndex | + Where-Object { $_ -like "P`t*" } | + ForEach-Object { $_.Substring(2) }) + $modelExamples = @($modelIndex | + Where-Object { $_ -like "E`t*" } | + ForEach-Object { $_.Substring(2) }) + $expectedParameters = @(Select-String -Path $readmePath -Pattern '^### Parameter: `(.+)`$' | + ForEach-Object { $_.Matches[0].Groups[1].Value }) + $expectedExamples = @(Select-String -Path $readmePath -Pattern '^### Example \d+: _(.+)_$' | + ForEach-Object { $_.Matches[0].Groups[1].Value }) + $parameterMatches = Test-StringSetEqual -Expected $expectedParameters -Actual $modelParameters + $exampleMatches = Test-StringSetEqual -Expected $expectedExamples -Actual $modelExamples + $modelMatches = $parameterMatches -and $exampleMatches + $missingParameters = @($expectedParameters | Where-Object { $_ -notin $modelParameters } | Sort-Object -Unique) + $unexpectedParameters = @($modelParameters | Where-Object { $_ -notin $expectedParameters } | Sort-Object -Unique) + $missingExamples = @($expectedExamples | Where-Object { $_ -notin $modelExamples } | Sort-Object -Unique) + $unexpectedExamples = @($modelExamples | Where-Object { $_ -notin $expectedExamples } | Sort-Object -Unique) + } else { + $modelMatches = $false + } [pscustomobject]@{ Module = $modulePath - Matches = $readmeMatches -and $modelMatches + Matches = $readmeMatches ReadmeMatches = $readmeMatches ModelMatches = $modelMatches + ExpectedParameterCount = $expectedParameters.Count + ActualParameterCount = $modelParameters.Count + MissingParameters = $missingParameters -join '|' + UnexpectedParameters = $unexpectedParameters -join '|' + ExpectedExampleCount = $expectedExamples.Count + ActualExampleCount = $modelExamples.Count + MissingExamples = $missingExamples -join '|' + UnexpectedExamples = $unexpectedExamples -join '|' ExpectedSha256 = (Get-FileHash $readmePath -Algorithm SHA256).Hash ActualSha256 = (Get-FileHash $actualPath -Algorithm SHA256).Hash ActualPath = $actualPath @@ -186,7 +243,7 @@ if ($PassThru) { $results } else { $results | Format-Table -AutoSize - if ($results.Matches -contains $false) { + if ($results.ReadmeMatches -contains $false) { exit 1 } } From fda7fa52f082bb91ba654448731a5e85b87be620 Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Sat, 15 Aug 2026 10:05:06 +0100 Subject: [PATCH 04/11] fix(docs): include AVM compiler diagnostics Include captured compiler errors in the aggregate parity validation report. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1d476aa-095e-4b89-8a06-66f8642720ad --- .../2026-08-14-avm-docs-parity-template.md | 4 +++- scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/progress/2026-08-14-avm-docs-parity-template.md b/docs/progress/2026-08-14-avm-docs-parity-template.md index f3b8f57..a70ac99 100644 --- a/docs/progress/2026-08-14-avm-docs-parity-template.md +++ b/docs/progress/2026-08-14-avm-docs-parity-template.md @@ -25,11 +25,13 @@ PowerShell verifiers for Bicep AVM README documentation parity. ## Validation - `Test-AvmDocsParity.ps1` parses without PowerShell syntax errors. -- The finalized full run compared 573 modules in `00:06:13.5504992`: 572 +- The definitive full run compared 573 modules in `00:06:59.1954771`: 572 generated READMEs matched byte-for-byte, one module had a genuine compilation failure, and 49 semantic-model mismatches were retained in detailed reports. - The failure was `avm/ptn/app/container-job-toolkit` with BCP426, BCP104, BCP287, and BCP036; no README was generated for that module. +- `validation.txt` includes those captured compiler diagnostics rather than only + referring to the per-module stderr report. - Of the semantic-model mismatches, 34 involved parameters and 15 involved example names. - The final templates match their validated source after LF normalization, both diff --git a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 index 6776af7..bf1dd45 100644 --- a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 +++ b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 @@ -159,7 +159,21 @@ $summary = [pscustomobject]@{ Duration = $stopwatch.Elapsed.ToString() } $summary | ConvertTo-Json | Set-Content (Join-Path $OutputPath 'summary.json') -$errorDetails = @($results | Where-Object Error | ForEach-Object { "$($_.Module): $($_.Error)" }) +$errorDetails = @($results | Where-Object Error | ForEach-Object { + $module = $_.Module + $stderrPath = Join-Path $OutputPath "$module/README.stderr.txt" + $diagnostics = if (Test-Path $stderrPath) { + @(Get-Content $stderrPath | Where-Object { $_ -match ' : Error ' }) + } else { + @() + } + + if ($diagnostics.Count -gt 0) { + @("$module`:") + @($diagnostics | ForEach-Object { " $_" }) + } else { + "$module`: $($_.Error)" + } +}) @( "Repository commit: $($summary.RepositoryCommit)" "Total modules compared: $($summary.TotalModules)" From 34a31e78f61f0f0f3fefa715e7405a5611a0a789 Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Sat, 15 Aug 2026 11:33:17 +0100 Subject: [PATCH 05/11] fix(avm-docs): remove docs generation config mutation Record the Bicep version and executable SHA256 in aggregate parity reports. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1d476aa-095e-4b89-8a06-66f8642720ad --- .../2026-08-14-avm-docs-parity-template.md | 2 + scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 | 33 +++--------- scripts/avm-docs/Test-AvmDocsParity.ps1 | 50 ++++++------------- 3 files changed, 23 insertions(+), 62 deletions(-) diff --git a/docs/progress/2026-08-14-avm-docs-parity-template.md b/docs/progress/2026-08-14-avm-docs-parity-template.md index a70ac99..12eb8c4 100644 --- a/docs/progress/2026-08-14-avm-docs-parity-template.md +++ b/docs/progress/2026-08-14-avm-docs-parity-template.md @@ -32,6 +32,8 @@ PowerShell verifiers for Bicep AVM README documentation parity. BCP287, and BCP036; no README was generated for that module. - `validation.txt` includes those captured compiler diagnostics rather than only referring to the per-module stderr report. +- The verifier does not create or modify `bicepconfig.json`. All-module reports + record the Bicep version and executable SHA256 alongside the comparison data. - Of the semantic-model mismatches, 34 involved parameters and 15 involved example names. - The final templates match their validated source after LF normalization, both diff --git a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 index bf1dd45..8285da2 100644 --- a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 +++ b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 @@ -21,8 +21,6 @@ $ErrorActionPreference = 'Stop' $stopwatch = [Diagnostics.Stopwatch]::StartNew() $templatePath = Join-Path $PSScriptRoot 'README.byte-parity.scriban' $modelIndexTemplatePath = Join-Path $PSScriptRoot 'model-index.scriban' -$rootConfigPath = Join-Path $WorkingRepositoryPath 'bicepconfig.json' -$originalRootConfig = [IO.File]::ReadAllText($rootConfigPath) $modulePaths = @(Get-ChildItem (Join-Path $SourceRepositoryPath 'avm') -Recurse -Filter main.bicep -File | Where-Object { (Test-Path (Join-Path $_.DirectoryName 'README.md')) -and @@ -33,23 +31,7 @@ $modulePaths = @(Get-ChildItem (Join-Path $SourceRepositoryPath 'avm') -Recurse New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null -try { - if ($originalRootConfig -notmatch '"docsGeneration"\s*:\s*true') { - $objectStart = $originalRootConfig.IndexOf('{') - $featureConfig = @' - - "experimentalFeaturesEnabled": { - "docsGeneration": true - }, -'@ - $enabledConfig = $originalRootConfig.Insert($objectStart + 1, $featureConfig) - [IO.File]::WriteAllText( - $rootConfigPath, - $enabledConfig, - [Text.UTF8Encoding]::new($false)) - } - - $results = @($modulePaths | ForEach-Object -Parallel { +$results = @($modulePaths | ForEach-Object -Parallel { $modulePath = $_ $moduleRoot = Join-Path $using:WorkingRepositoryPath $modulePath $moduleOutputPath = Join-Path $using:OutputPath $modulePath @@ -63,7 +45,6 @@ try { -ModulePaths @($modulePath) ` -TemplatePath $using:templatePath ` -ModelIndexTemplatePath $using:modelIndexTemplatePath ` - -SkipModuleConfig ` -GenerateInPlace ` -PassThru @@ -129,13 +110,7 @@ try { Error = $_.Exception.Message } } - } -ThrottleLimit $ThrottleLimit) -} finally { - [IO.File]::WriteAllText( - $rootConfigPath, - $originalRootConfig, - [Text.UTF8Encoding]::new($false)) -} +} -ThrottleLimit $ThrottleLimit) $results = @($results | Sort-Object Module) $results | Export-Csv (Join-Path $OutputPath 'comparison.csv') -NoTypeInformation @@ -145,6 +120,8 @@ $semanticMismatches | Export-Csv (Join-Path $OutputPath 'model-mismatches.csv') $stopwatch.Stop() $summary = [pscustomobject]@{ + BicepVersion = (& $BicepPath --version) + BicepExecutableSha256 = (Get-FileHash $BicepPath -Algorithm SHA256).Hash RepositoryCommit = (git -C $SourceRepositoryPath rev-parse HEAD) TotalModules = $results.Count GeneratedReadmes = @($results | Where-Object GeneratedReadme).Count @@ -175,6 +152,8 @@ $errorDetails = @($results | Where-Object Error | ForEach-Object { } }) @( + "Bicep version: $($summary.BicepVersion)" + "Bicep executable SHA256: $($summary.BicepExecutableSha256)" "Repository commit: $($summary.RepositoryCommit)" "Total modules compared: $($summary.TotalModules)" "Generated READMEs: $($summary.GeneratedReadmes)" diff --git a/scripts/avm-docs/Test-AvmDocsParity.ps1 b/scripts/avm-docs/Test-AvmDocsParity.ps1 index 8ee012d..c3c51f0 100644 --- a/scripts/avm-docs/Test-AvmDocsParity.ps1 +++ b/scripts/avm-docs/Test-AvmDocsParity.ps1 @@ -17,8 +17,6 @@ param ( [string] $ModelIndexTemplatePath = (Join-Path $PSScriptRoot 'model-index.scriban'), - [switch] $SkipModuleConfig, - [switch] $GenerateInPlace, [switch] $PassThru @@ -130,21 +128,8 @@ $results = foreach ($modulePath in $ModulePaths) { $stderrPath = Join-Path $fragmentRoot 'README.stderr.txt' $modelIndexPath = Join-Path $fragmentRoot 'model-index.tsv' $modelIndexStderrPath = Join-Path $fragmentRoot 'model-index.stderr.txt' - $moduleConfigPath = Join-Path $moduleRoot 'bicepconfig.json' - $createdModuleConfig = -not $SkipModuleConfig -and -not (Test-Path $moduleConfigPath) $modelIndexExitCode = $null - if ($createdModuleConfig) { - Write-Utf8Lf -Path $moduleConfigPath -Content @' -{ - "experimentalFeaturesEnabled": { - "docsGeneration": true - } -} -'@ - } - - try { - $commandArguments = @( + $commandArguments = @( 'docs' ($GenerateInPlace ? 'generate' : 'output') $mainPath @@ -165,25 +150,20 @@ $results = foreach ($modulePath in $ModulePaths) { '--set' "hasNotes=$(($null -ne $sections['notes.md']).ToString().ToLowerInvariant())" ) - if ($GenerateInPlace) { - $commandArguments += @('--output-file', 'README.md') - } - - & $BicepPath @commandArguments ` - 1> ($GenerateInPlace ? $stdoutPath : $actualPath) ` - 2> $stderrPath - $exitCode = $LASTEXITCODE - if ($exitCode -eq 0) { - & $BicepPath docs output $mainPath ` - --template-file $ModelIndexTemplatePath ` - 1> $modelIndexPath ` - 2> $modelIndexStderrPath - $modelIndexExitCode = $LASTEXITCODE - } - } finally { - if ($createdModuleConfig) { - Remove-Item -LiteralPath $moduleConfigPath -Force - } + if ($GenerateInPlace) { + $commandArguments += @('--output-file', 'README.md') + } + + & $BicepPath @commandArguments ` + 1> ($GenerateInPlace ? $stdoutPath : $actualPath) ` + 2> $stderrPath + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + & $BicepPath docs output $mainPath ` + --template-file $ModelIndexTemplatePath ` + 1> $modelIndexPath ` + 2> $modelIndexStderrPath + $modelIndexExitCode = $LASTEXITCODE } if ($exitCode -ne 0) { From 00e91e84494c4ff0290913d42ca2d5abb69b7f90 Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Sat, 15 Aug 2026 13:08:14 +0100 Subject: [PATCH 06/11] fix(avm-docs): use renamed template option Align parity verification with Bicep's --custom-template-value CLI option. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1d476aa-095e-4b89-8a06-66f8642720ad --- docs/progress/2026-08-14-avm-docs-parity-template.md | 4 +++- scripts/avm-docs/Test-AvmDocsParity.ps1 | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/progress/2026-08-14-avm-docs-parity-template.md b/docs/progress/2026-08-14-avm-docs-parity-template.md index 12eb8c4..1a7b82b 100644 --- a/docs/progress/2026-08-14-avm-docs-parity-template.md +++ b/docs/progress/2026-08-14-avm-docs-parity-template.md @@ -2,7 +2,7 @@ **Status**: complete **Started**: 2026-08-14 -**Updated**: 2026-08-14 +**Updated**: 2026-08-15 **Branch**: `jaredfholgate-avm-docs-parity-template` ## Outcome @@ -34,6 +34,8 @@ PowerShell verifiers for Bicep AVM README documentation parity. referring to the per-module stderr report. - The verifier does not create or modify `bicepconfig.json`. All-module reports record the Bicep version and executable SHA256 alongside the comparison data. +- The verifier uses Bicep's renamed `--custom-template-value` CLI option when + passing Scriban template values. - Of the semantic-model mismatches, 34 involved parameters and 15 involved example names. - The final templates match their validated source after LF normalization, both diff --git a/scripts/avm-docs/Test-AvmDocsParity.ps1 b/scripts/avm-docs/Test-AvmDocsParity.ps1 index c3c51f0..20bb49f 100644 --- a/scripts/avm-docs/Test-AvmDocsParity.ps1 +++ b/scripts/avm-docs/Test-AvmDocsParity.ps1 @@ -137,17 +137,17 @@ $results = foreach ($modulePath in $ModulePaths) { $TemplatePath '--template-root' $moduleRoot - '--set' + '--custom-template-value' "primaryResourceType=$primaryResourceType" - '--set' + '--custom-template-value' "moduleSymbolName=$moduleSymbolName" - '--set' + '--custom-template-value' "moduleReference=$($modulePath.Replace('\', '/'))" - '--set' + '--custom-template-value' "typelessOutputs=$typelessOutputs" - '--set' + '--custom-template-value' "hasCrossReferences=$(($null -ne $sections['cross-referenced-modules.md']).ToString().ToLowerInvariant())" - '--set' + '--custom-template-value' "hasNotes=$(($null -ne $sections['notes.md']).ToString().ToLowerInvariant())" ) if ($GenerateInPlace) { From 0a590aeb982230d06f5c5df1382cf8d0a16ce23f Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Mon, 17 Aug 2026 15:23:11 +0100 Subject: [PATCH 07/11] fix(avm-docs): use default generated filename Remove the obsolete documentation output option now that Bicep uses the standard output contract and writes README.md by default. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5b6b551b-dfe1-461c-8caa-e9d250df1026 --- scripts/avm-docs/Test-AvmDocsParity.ps1 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/avm-docs/Test-AvmDocsParity.ps1 b/scripts/avm-docs/Test-AvmDocsParity.ps1 index 20bb49f..0cfb2ab 100644 --- a/scripts/avm-docs/Test-AvmDocsParity.ps1 +++ b/scripts/avm-docs/Test-AvmDocsParity.ps1 @@ -150,10 +150,6 @@ $results = foreach ($modulePath in $ModulePaths) { '--custom-template-value' "hasNotes=$(($null -ne $sections['notes.md']).ToString().ToLowerInvariant())" ) - if ($GenerateInPlace) { - $commandArguments += @('--output-file', 'README.md') - } - & $BicepPath @commandArguments ` 1> ($GenerateInPlace ? $stdoutPath : $actualPath) ` 2> $stderrPath From ead76bda2b97eb76d4082e8cc44501aee56604c8 Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Mon, 17 Aug 2026 20:51:43 +0100 Subject: [PATCH 08/11] feat(avm-docs): validate docs configuration Use the docs configuration for every module, reassign multi-scope examples, and compare structured discriminator parameters in the semantic index. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5b6b551b-dfe1-461c-8caa-e9d250df1026 --- scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 | 2 ++ scripts/avm-docs/README.md | 6 ++++ scripts/avm-docs/Test-AvmDocsParity.ps1 | 5 ++++ scripts/avm-docs/bicep-docs.json | 30 ++++++++++++++++++++ scripts/avm-docs/model-index.scriban | 9 ++++-- 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 scripts/avm-docs/bicep-docs.json diff --git a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 index 8285da2..a35c76a 100644 --- a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 +++ b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 @@ -21,6 +21,7 @@ $ErrorActionPreference = 'Stop' $stopwatch = [Diagnostics.Stopwatch]::StartNew() $templatePath = Join-Path $PSScriptRoot 'README.byte-parity.scriban' $modelIndexTemplatePath = Join-Path $PSScriptRoot 'model-index.scriban' +$docsConfigPath = Join-Path $PSScriptRoot 'bicep-docs.json' $modulePaths = @(Get-ChildItem (Join-Path $SourceRepositoryPath 'avm') -Recurse -Filter main.bicep -File | Where-Object { (Test-Path (Join-Path $_.DirectoryName 'README.md')) -and @@ -45,6 +46,7 @@ $results = @($modulePaths | ForEach-Object -Parallel { -ModulePaths @($modulePath) ` -TemplatePath $using:templatePath ` -ModelIndexTemplatePath $using:modelIndexTemplatePath ` + -DocsConfigPath $using:docsConfigPath ` -GenerateInPlace ` -PassThru diff --git a/scripts/avm-docs/README.md b/scripts/avm-docs/README.md index ec2950d..5283395 100644 --- a/scripts/avm-docs/README.md +++ b/scripts/avm-docs/README.md @@ -19,3 +19,9 @@ The default modules are `avm/res/storage/storage-account` and modules in separate source and working checkouts. It records compiler failures and semantic-model mismatches in its output reports; failed compilation does not produce a README. + +`bicep-docs.json` is passed to every docs invocation. Its example +reassignments move multi-scope tests from parent stubs to the corresponding +`mg-scope`, `rg-scope`, and `sub-scope` modules while leaving ordinary modules +unchanged. The semantic index also flattens structured discriminator cases to +the parameter paths used by existing AVM READMEs. diff --git a/scripts/avm-docs/Test-AvmDocsParity.ps1 b/scripts/avm-docs/Test-AvmDocsParity.ps1 index 0cfb2ab..bc05083 100644 --- a/scripts/avm-docs/Test-AvmDocsParity.ps1 +++ b/scripts/avm-docs/Test-AvmDocsParity.ps1 @@ -17,6 +17,8 @@ param ( [string] $ModelIndexTemplatePath = (Join-Path $PSScriptRoot 'model-index.scriban'), + [string] $DocsConfigPath = (Join-Path $PSScriptRoot 'bicep-docs.json'), + [switch] $GenerateInPlace, [switch] $PassThru @@ -133,6 +135,8 @@ $results = foreach ($modulePath in $ModulePaths) { 'docs' ($GenerateInPlace ? 'generate' : 'output') $mainPath + '--config-file-path' + $DocsConfigPath '--template-file' $TemplatePath '--template-root' @@ -156,6 +160,7 @@ $results = foreach ($modulePath in $ModulePaths) { $exitCode = $LASTEXITCODE if ($exitCode -eq 0) { & $BicepPath docs output $mainPath ` + --config-file-path $DocsConfigPath ` --template-file $ModelIndexTemplatePath ` 1> $modelIndexPath ` 2> $modelIndexStderrPath diff --git a/scripts/avm-docs/bicep-docs.json b/scripts/avm-docs/bicep-docs.json new file mode 100644 index 0000000..da52c41 --- /dev/null +++ b/scripts/avm-docs/bicep-docs.json @@ -0,0 +1,30 @@ +{ + "examples": { + "reassignments": [ + { + "from": { + "include": [ + "**/mg-scope.*/**" + ] + }, + "to": "mg-scope" + }, + { + "from": { + "include": [ + "**/rg-scope.*/**" + ] + }, + "to": "rg-scope" + }, + { + "from": { + "include": [ + "**/sub-scope.*/**" + ] + }, + "to": "sub-scope" + } + ] + } +} diff --git a/scripts/avm-docs/model-index.scriban b/scripts/avm-docs/model-index.scriban index ff7f663..1905e1c 100644 --- a/scripts/avm-docs/model-index.scriban +++ b/scripts/avm-docs/model-index.scriban @@ -1,17 +1,22 @@ {{~ func is_avm_parameter(item) ~}} -{{~ ret item.description && ((item.description | string.starts_with "Required.") || (item.description | string.starts_with "Conditional.") || (item.description | string.starts_with "Optional.") || (item.description | string.starts_with "Generated.")) ~}} +{{~ ret item.description && ((item.description | string.starts_with "Required.") || (item.description | string.starts_with "Conditional.") || (item.description | string.starts_with "Condition.") || (item.description | string.starts_with "Optional.") || (item.description | string.starts_with "Optinal.") || (item.description | string.starts_with "Optonal.") || (item.description | string.starts_with "Generated.")) ~}} {{~ end ~}} {{~ func dump_parameters(items, prefix) ~}} {{~ for item in items ~}} {{~ if is_avm_parameter item ~}} P {{ prefix }}{{ item.name }} {{~ dump_parameters item.properties (prefix + item.name + ".") ~}} +{{~ if item.discriminator ~}} +{{~ for discriminator_case in item.discriminator.cases ~}} +{{~ dump_parameters discriminator_case.properties (prefix + item.name + "." + item.discriminator.propertyName + "-" + discriminator_case.value + ".") ~}} +{{~ end ~}} +{{~ end ~}} {{~ end ~}} {{~ end ~}} {{~ end ~}} {{~ dump_parameters module.parameters "" ~}} {{~ for example in module.usageExamples ~}} -{{~ if (example.path | string.starts_with "tests/e2e/") && (example.path | string.ends_with "main.test.bicep") ~}} +{{~ if (example.path | string.starts_with "tests/e2e/") || (example.path | string.starts_with "../tests/e2e/") ~}} E {{ example.name }} {{~ end ~}} {{~ end ~}} From 17ec5e06061991d5062c4ea6f063e0beef196c1a Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Mon, 17 Aug 2026 23:26:58 +0100 Subject: [PATCH 09/11] fix(avm-docs): align docs config contract Use the finalized Bicep docs config name, schema, and module input selection. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1d476aa-095e-4b89-8a06-66f8642720ad --- .../2026-08-17-avm-docs-config-contract.md | 26 +++++++++++++++++++ scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 | 2 +- scripts/avm-docs/README.md | 2 +- scripts/avm-docs/Test-AvmDocsParity.ps1 | 2 +- .../{bicep-docs.json => bicepdocsconfig.json} | 7 +++++ 5 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 docs/progress/2026-08-17-avm-docs-config-contract.md rename scripts/avm-docs/{bicep-docs.json => bicepdocsconfig.json} (69%) diff --git a/docs/progress/2026-08-17-avm-docs-config-contract.md b/docs/progress/2026-08-17-avm-docs-config-contract.md new file mode 100644 index 0000000..d362c56 --- /dev/null +++ b/docs/progress/2026-08-17-avm-docs-config-contract.md @@ -0,0 +1,26 @@ +# AVM docs configuration contract + +**Status**: complete +**Started**: 2026-08-17 +**Updated**: 2026-08-17 +**Branch**: `jaredfholgate-avm-docs-parity-template` + +## Outcome + +Align the AVM documentation-parity configuration and its script references with +the final Azure/bicep documentation configuration contract. + +## Checklist + +- [x] Rename the configuration to `bicepdocsconfig.json`. +- [x] Add the Bicep docs configuration schema and explicit `main.bicep` input + selection. +- [x] Preserve the example reassignment settings and update all references. +- [x] Validate JSON, PowerShell syntax, and the pre-commit gate. + +## Validation + +- `bicepdocsconfig.json` parses as JSON and contains the required schema, + input include, input exclude, and three example reassignments. +- Both parity scripts parse without PowerShell syntax errors. +- `./build.ps1 pre-commit` passed. diff --git a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 index a35c76a..1d03d38 100644 --- a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 +++ b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 @@ -21,7 +21,7 @@ $ErrorActionPreference = 'Stop' $stopwatch = [Diagnostics.Stopwatch]::StartNew() $templatePath = Join-Path $PSScriptRoot 'README.byte-parity.scriban' $modelIndexTemplatePath = Join-Path $PSScriptRoot 'model-index.scriban' -$docsConfigPath = Join-Path $PSScriptRoot 'bicep-docs.json' +$docsConfigPath = Join-Path $PSScriptRoot 'bicepdocsconfig.json' $modulePaths = @(Get-ChildItem (Join-Path $SourceRepositoryPath 'avm') -Recurse -Filter main.bicep -File | Where-Object { (Test-Path (Join-Path $_.DirectoryName 'README.md')) -and diff --git a/scripts/avm-docs/README.md b/scripts/avm-docs/README.md index 5283395..9dca174 100644 --- a/scripts/avm-docs/README.md +++ b/scripts/avm-docs/README.md @@ -20,7 +20,7 @@ modules in separate source and working checkouts. It records compiler failures and semantic-model mismatches in its output reports; failed compilation does not produce a README. -`bicep-docs.json` is passed to every docs invocation. Its example +`bicepdocsconfig.json` is passed to every docs invocation. Its example reassignments move multi-scope tests from parent stubs to the corresponding `mg-scope`, `rg-scope`, and `sub-scope` modules while leaving ordinary modules unchanged. The semantic index also flattens structured discriminator cases to diff --git a/scripts/avm-docs/Test-AvmDocsParity.ps1 b/scripts/avm-docs/Test-AvmDocsParity.ps1 index bc05083..9ff896e 100644 --- a/scripts/avm-docs/Test-AvmDocsParity.ps1 +++ b/scripts/avm-docs/Test-AvmDocsParity.ps1 @@ -17,7 +17,7 @@ param ( [string] $ModelIndexTemplatePath = (Join-Path $PSScriptRoot 'model-index.scriban'), - [string] $DocsConfigPath = (Join-Path $PSScriptRoot 'bicep-docs.json'), + [string] $DocsConfigPath = (Join-Path $PSScriptRoot 'bicepdocsconfig.json'), [switch] $GenerateInPlace, diff --git a/scripts/avm-docs/bicep-docs.json b/scripts/avm-docs/bicepdocsconfig.json similarity index 69% rename from scripts/avm-docs/bicep-docs.json rename to scripts/avm-docs/bicepdocsconfig.json index da52c41..55a946b 100644 --- a/scripts/avm-docs/bicep-docs.json +++ b/scripts/avm-docs/bicepdocsconfig.json @@ -1,4 +1,11 @@ { + "$schema": "https://raw.githubusercontent.com/Azure/bicep/main/src/vscode-bicep/schemas/bicepdocsconfig.schema.json", + "input": { + "include": [ + "**/main.bicep" + ], + "exclude": [] + }, "examples": { "reassignments": [ { From d9e9091ac0bf2909e10ce5da3aa09d99b20f0155 Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Tue, 18 Aug 2026 11:41:21 +0100 Subject: [PATCH 10/11] fix(avm-docs): adopt final docs contract Use standard bicepconfig discovery, docs generate stdout output, and export-aware semantic templates. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1d476aa-095e-4b89-8a06-66f8642720ad --- .../2026-08-18-avm-docs-final-contract.md | 30 +++++++++++++++ scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 | 4 +- scripts/avm-docs/README.avm.scriban | 26 +++++++++++++ scripts/avm-docs/README.md | 12 +++--- scripts/avm-docs/Test-AvmDocsParity.ps1 | 13 +++---- scripts/avm-docs/bicepconfig.json | 32 ++++++++++++++++ scripts/avm-docs/bicepdocsconfig.json | 37 ------------------- scripts/avm-docs/model-index.scriban | 6 +++ 8 files changed, 109 insertions(+), 51 deletions(-) create mode 100644 docs/progress/2026-08-18-avm-docs-final-contract.md create mode 100644 scripts/avm-docs/bicepconfig.json delete mode 100644 scripts/avm-docs/bicepdocsconfig.json diff --git a/docs/progress/2026-08-18-avm-docs-final-contract.md b/docs/progress/2026-08-18-avm-docs-final-contract.md new file mode 100644 index 0000000..6e59ab3 --- /dev/null +++ b/docs/progress/2026-08-18-avm-docs-final-contract.md @@ -0,0 +1,30 @@ +# AVM docs final configuration contract + +**Status**: complete +**Started**: 2026-08-18 +**Updated**: 2026-08-18 +**Branch**: `jaredfholgate-avm-docs-parity-template` + +## Outcome + +Align the AVM documentation parity utility with the accepted Bicep +`bicepconfig.json` documentation contract and `docs generate` command shape. + +## Checklist + +- [x] Use a root `bicepconfig.json` with documentation-scoped example + reassignments. +- [x] Use standard configuration discovery and copy the configuration into the + validation working checkout. +- [x] Use `docs generate --stdout` for semantic model output. +- [x] Represent exported types and variables in semantic templates and indexes. +- [x] Validate JSON, PowerShell syntax, and the pre-commit gate. + +## Validation + +- `bicepconfig.json` parses as JSON, contains only the `documentation` section, + and retains all three example reassignments. +- Both parity scripts parse without PowerShell syntax errors. +- Static contract checks confirm no `--config-file-path` or `docs output` + invocations remain. +- `./build.ps1 pre-commit` passed. diff --git a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 index 1d03d38..77bb119 100644 --- a/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 +++ b/scripts/avm-docs/Invoke-AllAvmDocsParity.ps1 @@ -21,7 +21,7 @@ $ErrorActionPreference = 'Stop' $stopwatch = [Diagnostics.Stopwatch]::StartNew() $templatePath = Join-Path $PSScriptRoot 'README.byte-parity.scriban' $modelIndexTemplatePath = Join-Path $PSScriptRoot 'model-index.scriban' -$docsConfigPath = Join-Path $PSScriptRoot 'bicepdocsconfig.json' +$docsConfigPath = Join-Path $PSScriptRoot 'bicepconfig.json' $modulePaths = @(Get-ChildItem (Join-Path $SourceRepositoryPath 'avm') -Recurse -Filter main.bicep -File | Where-Object { (Test-Path (Join-Path $_.DirectoryName 'README.md')) -and @@ -31,6 +31,7 @@ $modulePaths = @(Get-ChildItem (Join-Path $SourceRepositoryPath 'avm') -Recurse Sort-Object) New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null +Copy-Item -LiteralPath $docsConfigPath -Destination (Join-Path $WorkingRepositoryPath 'bicepconfig.json') -Force $results = @($modulePaths | ForEach-Object -Parallel { $modulePath = $_ @@ -46,7 +47,6 @@ $results = @($modulePaths | ForEach-Object -Parallel { -ModulePaths @($modulePath) ` -TemplatePath $using:templatePath ` -ModelIndexTemplatePath $using:modelIndexTemplatePath ` - -DocsConfigPath $using:docsConfigPath ` -GenerateInPlace ` -PassThru diff --git a/scripts/avm-docs/README.avm.scriban b/scripts/avm-docs/README.avm.scriban index 7af9bf8..353a4c5 100644 --- a/scripts/avm-docs/README.avm.scriban +++ b/scripts/avm-docs/README.avm.scriban @@ -33,6 +33,12 @@ For examples, please refer to the [Usage Examples](#usage-examples) section. {{~ if module.exportedFunctions.size > 0 ~}} - [Exported functions](#Exported-functions) {{~ end ~}} +{{~ if module.exportedTypes.size > 0 ~}} +- [Exported types](#Exported-types) +{{~ end ~}} +{{~ if module.exportedVariables.size > 0 ~}} +- [Exported variables](#Exported-variables) +{{~ end ~}} - [Outputs](#Outputs) {{~ if custom.hasCrossReferences == "true" ~}} - [Cross-referenced modules](#Cross-referenced-modules) @@ -57,6 +63,26 @@ For examples, please refer to the [Usage Examples](#usage-examples) section. | `{{ exported_function.name }}` | {{ exported_function.description }} | {{~ end ~}} {{~ end ~}} +{{~ if module.exportedTypes.size > 0 ~}} + +## Exported types + +| Type | Description | +| :-- | :-- | +{{~ for exported_type in module.exportedTypes ~}} +| `{{ exported_type.name }}` | {{ exported_type.description }} | +{{~ end ~}} +{{~ end ~}} +{{~ if module.exportedVariables.size > 0 ~}} + +## Exported variables + +| Variable | Description | +| :-- | :-- | +{{~ for exported_variable in module.exportedVariables ~}} +| `{{ exported_variable.name }}` | {{ exported_variable.description }} | +{{~ end ~}} +{{~ end ~}} ## Outputs {{~ if module.outputs.size > 0 ~}} diff --git a/scripts/avm-docs/README.md b/scripts/avm-docs/README.md index 9dca174..b190783 100644 --- a/scripts/avm-docs/README.md +++ b/scripts/avm-docs/README.md @@ -20,8 +20,10 @@ modules in separate source and working checkouts. It records compiler failures and semantic-model mismatches in its output reports; failed compilation does not produce a README. -`bicepdocsconfig.json` is passed to every docs invocation. Its example -reassignments move multi-scope tests from parent stubs to the corresponding -`mg-scope`, `rg-scope`, and `sub-scope` modules while leaving ordinary modules -unchanged. The semantic index also flattens structured discriminator cases to -the parameter paths used by existing AVM READMEs. +`bicepconfig.json` is copied to the root of the validation working checkout so +the Bicep CLI discovers its `documentation` settings for each source file. Its +example reassignments move multi-scope tests from parent stubs to the +corresponding `mg-scope`, `rg-scope`, and `sub-scope` modules while leaving +ordinary modules unchanged. The scripts use `bicep docs generate`; output-mode +calls add `--stdout`. The semantic index also flattens structured discriminator +cases and records exported type and variable names. diff --git a/scripts/avm-docs/Test-AvmDocsParity.ps1 b/scripts/avm-docs/Test-AvmDocsParity.ps1 index 9ff896e..e108893 100644 --- a/scripts/avm-docs/Test-AvmDocsParity.ps1 +++ b/scripts/avm-docs/Test-AvmDocsParity.ps1 @@ -17,8 +17,6 @@ param ( [string] $ModelIndexTemplatePath = (Join-Path $PSScriptRoot 'model-index.scriban'), - [string] $DocsConfigPath = (Join-Path $PSScriptRoot 'bicepdocsconfig.json'), - [switch] $GenerateInPlace, [switch] $PassThru @@ -133,10 +131,8 @@ $results = foreach ($modulePath in $ModulePaths) { $modelIndexExitCode = $null $commandArguments = @( 'docs' - ($GenerateInPlace ? 'generate' : 'output') + 'generate' $mainPath - '--config-file-path' - $DocsConfigPath '--template-file' $TemplatePath '--template-root' @@ -154,13 +150,16 @@ $results = foreach ($modulePath in $ModulePaths) { '--custom-template-value' "hasNotes=$(($null -ne $sections['notes.md']).ToString().ToLowerInvariant())" ) + if (-not $GenerateInPlace) { + $commandArguments += '--stdout' + } & $BicepPath @commandArguments ` 1> ($GenerateInPlace ? $stdoutPath : $actualPath) ` 2> $stderrPath $exitCode = $LASTEXITCODE if ($exitCode -eq 0) { - & $BicepPath docs output $mainPath ` - --config-file-path $DocsConfigPath ` + & $BicepPath docs generate $mainPath ` + --stdout ` --template-file $ModelIndexTemplatePath ` 1> $modelIndexPath ` 2> $modelIndexStderrPath diff --git a/scripts/avm-docs/bicepconfig.json b/scripts/avm-docs/bicepconfig.json new file mode 100644 index 0000000..4c0ee69 --- /dev/null +++ b/scripts/avm-docs/bicepconfig.json @@ -0,0 +1,32 @@ +{ + "documentation": { + "examples": { + "reassignments": [ + { + "from": { + "include": [ + "**/mg-scope.*/**" + ] + }, + "to": "mg-scope" + }, + { + "from": { + "include": [ + "**/rg-scope.*/**" + ] + }, + "to": "rg-scope" + }, + { + "from": { + "include": [ + "**/sub-scope.*/**" + ] + }, + "to": "sub-scope" + }, + ] + } + } +} diff --git a/scripts/avm-docs/bicepdocsconfig.json b/scripts/avm-docs/bicepdocsconfig.json deleted file mode 100644 index 55a946b..0000000 --- a/scripts/avm-docs/bicepdocsconfig.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/Azure/bicep/main/src/vscode-bicep/schemas/bicepdocsconfig.schema.json", - "input": { - "include": [ - "**/main.bicep" - ], - "exclude": [] - }, - "examples": { - "reassignments": [ - { - "from": { - "include": [ - "**/mg-scope.*/**" - ] - }, - "to": "mg-scope" - }, - { - "from": { - "include": [ - "**/rg-scope.*/**" - ] - }, - "to": "rg-scope" - }, - { - "from": { - "include": [ - "**/sub-scope.*/**" - ] - }, - "to": "sub-scope" - } - ] - } -} diff --git a/scripts/avm-docs/model-index.scriban b/scripts/avm-docs/model-index.scriban index 1905e1c..798c864 100644 --- a/scripts/avm-docs/model-index.scriban +++ b/scripts/avm-docs/model-index.scriban @@ -15,6 +15,12 @@ P {{ prefix }}{{ item.name }} {{~ end ~}} {{~ end ~}} {{~ dump_parameters module.parameters "" ~}} +{{~ for exported_type in module.exportedTypes ~}} +T {{ exported_type.name }} +{{~ end ~}} +{{~ for exported_variable in module.exportedVariables ~}} +V {{ exported_variable.name }} +{{~ end ~}} {{~ for example in module.usageExamples ~}} {{~ if (example.path | string.starts_with "tests/e2e/") || (example.path | string.starts_with "../tests/e2e/") ~}} E {{ example.name }} From faa31a84c76f635b3363756e038731e1952c9187 Mon Sep 17 00:00:00 2001 From: Jared Holgate Date: Tue, 18 Aug 2026 12:48:56 +0100 Subject: [PATCH 11/11] fix(avm-docs): remove invalid config comma Keep the standard Bicep documentation configuration valid strict JSON. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1d476aa-095e-4b89-8a06-66f8642720ad --- .../2026-08-18-avm-docs-config-json.md | 22 +++++++++++++++++++ scripts/avm-docs/bicepconfig.json | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 docs/progress/2026-08-18-avm-docs-config-json.md diff --git a/docs/progress/2026-08-18-avm-docs-config-json.md b/docs/progress/2026-08-18-avm-docs-config-json.md new file mode 100644 index 0000000..0ea1e3f --- /dev/null +++ b/docs/progress/2026-08-18-avm-docs-config-json.md @@ -0,0 +1,22 @@ +# AVM docs configuration JSON correction + +**Status**: complete +**Started**: 2026-08-18 +**Updated**: 2026-08-18 +**Branch**: `jaredfholgate-avm-docs-parity-template` + +## Outcome + +Remove the trailing comma that prevents Bicep from parsing the AVM documentation +parity `bicepconfig.json`. + +## Checklist + +- [x] Remove the trailing comma after the final example reassignment. +- [x] Validate strict JSON parsing and targeted PowerShell syntax. + +## Validation + +- .NET strict JSON parsing with trailing commas disabled passed. +- Both parity scripts parse without PowerShell syntax errors. +- `./build.ps1 pre-commit` passed. diff --git a/scripts/avm-docs/bicepconfig.json b/scripts/avm-docs/bicepconfig.json index 4c0ee69..1961ee1 100644 --- a/scripts/avm-docs/bicepconfig.json +++ b/scripts/avm-docs/bicepconfig.json @@ -25,7 +25,7 @@ ] }, "to": "sub-scope" - }, + } ] } }