← Files Power BI DesktopARCHIVED FILE
scripts/Test-PowerBIDocumentationCoverage.ps1
3.72 KB · Oct 2, 2026 · 00:32 UTC
param(
[switch]$Json
)
$ErrorActionPreference = 'Stop'
$scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$pluginRoot = Split-Path -Parent $scriptRoot
$repoRoot = Split-Path -Parent (Split-Path -Parent $pluginRoot)
function Resolve-ExistingFiles {
param([string[]]$Paths)
foreach ($path in $Paths) {
if (Test-Path -LiteralPath $path) {
Get-Item -LiteralPath $path
}
}
}
function Add-Finding {
param(
[System.Collections.Generic.List[object]]$Findings,
[string]$Id,
[string]$Severity,
[string]$Message,
[string]$Evidence
)
$Findings.Add([pscustomobject]@{
id = $Id
severity = $Severity
message = $Message
evidence = $Evidence
}) | Out-Null
}
$findings = [System.Collections.Generic.List[object]]::new()
$documentationFiles = @()
$documentationFiles += Resolve-ExistingFiles @(
(Join-Path $repoRoot 'README.md'),
(Join-Path $pluginRoot '.codex-plugin/plugin.json')
)
$documentationFiles += Get-ChildItem -LiteralPath (Join-Path $repoRoot 'docs') -Recurse -File -Filter '*.md' -ErrorAction SilentlyContinue
$documentationFiles += Get-ChildItem -LiteralPath (Join-Path $pluginRoot 'skills') -Recurse -File -Filter 'SKILL.md' -ErrorAction SilentlyContinue
$documentationText = ($documentationFiles | ForEach-Object {
Get-Content -LiteralPath $_.FullName -Raw
}) -join [Environment]::NewLine
$scriptFiles = Get-ChildItem -LiteralPath $scriptRoot -File -Filter '*.ps1' | Sort-Object Name
foreach ($script in $scriptFiles) {
if ($documentationText -notmatch [regex]::Escape($script.Name)) {
Add-Finding -Findings $findings -Id 'script.documentation.missing' -Severity 'Error' -Message 'Script is not mentioned in README, docs, SKILL, or plugin metadata.' -Evidence $script.Name
}
}
$forbiddenClaims = @('12-USP', 'semanticTestRunner.v1')
foreach ($claim in $forbiddenClaims) {
if ($documentationText -match [regex]::Escape($claim)) {
Add-Finding -Findings $findings -Id 'claim.forbidden' -Severity 'Error' -Message 'Forbidden stale claim found in documentation or plugin metadata.' -Evidence $claim
}
}
if ($documentationText -notmatch [regex]::Escape('New-PowerBILiveExecutiveNarrative.ps1')) {
Add-Finding -Findings $findings -Id 'live.executive.narrative.missing' -Severity 'Error' -Message 'Live executive narrative script must be explicitly documented.' -Evidence 'New-PowerBILiveExecutiveNarrative.ps1'
}
$pluginJsonPath = Join-Path $pluginRoot '.codex-plugin/plugin.json'
try {
Get-Content -LiteralPath $pluginJsonPath -Raw | ConvertFrom-Json | Out-Null
}
catch {
Add-Finding -Findings $findings -Id 'plugin.json.invalid' -Severity 'Error' -Message 'plugin.json must parse as JSON.' -Evidence $_.Exception.Message
}
$errors = @($findings | Where-Object { $_.severity -eq 'Error' })
$result = [pscustomobject]@{
schema = 'codex.powerbi.documentationCoverage.v1'
checkedScriptCount = @($scriptFiles).Count
checkedDocumentationFileCount = @($documentationFiles).Count
status = if ($errors.Count -gt 0) { 'Failed' } else { 'Passed' }
errorCount = $errors.Count
findings = @($findings)
}
if ($Json) {
$result | ConvertTo-Json -Depth 6
}
else {
'Power BI documentation coverage: {0}' -f $result.status
'Scripts checked: {0}' -f $result.checkedScriptCount
'Documentation files checked: {0}' -f $result.checkedDocumentationFileCount
foreach ($finding in $findings) {
'[{0}] {1}: {2} ({3})' -f $finding.severity, $finding.id, $finding.message, $finding.evidence
}
}
if ($errors.Count -gt 0) {
throw 'Power BI documentation coverage failed.'
}
SHA-256: 6c505fe6971d2335bcffdf0d21f06300b964632f3f360e7859db96874e3bbdbf