From def401a825443769dea52689eab5793bbb4d7d38 Mon Sep 17 00:00:00 2001 From: IEvangelist <7679720+IEvangelist@users.noreply.github.com> Date: Tue, 27 Oct 2026 13:00:28 +0000 Subject: [PATCH 1/3] Fix Integration Data Updater apiReference filter Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/tools-tests.yml | 4 + .../generate-package-json.ps1 | 5 +- .../generate-package-json.Tests.ps1 | 74 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/PackageJsonGenerator.Tests/generate-package-json.Tests.ps1 diff --git a/.github/workflows/tools-tests.yml b/.github/workflows/tools-tests.yml index 142f552ee..58b9b0cf3 100644 --- a/.github/workflows/tools-tests.yml +++ b/.github/workflows/tools-tests.yml @@ -44,6 +44,10 @@ jobs: dotnet build tests/PackageJsonGenerator.Tests/PackageJsonGenerator.Tests.csproj --configuration Release --no-restore dotnet build tests/AtsJsonGenerator.Tests/AtsJsonGenerator.Tests.csproj --configuration Release --no-restore + - name: Test PackageJsonGenerator script + shell: pwsh + run: ./tests/PackageJsonGenerator.Tests/generate-package-json.Tests.ps1 + - name: Run PackageJsonGenerator tests run: > dotnet test tests/PackageJsonGenerator.Tests/PackageJsonGenerator.Tests.csproj diff --git a/src/tools/PackageJsonGenerator/generate-package-json.ps1 b/src/tools/PackageJsonGenerator/generate-package-json.ps1 index 91a3e67f5..12fdcb908 100644 --- a/src/tools/PackageJsonGenerator/generate-package-json.ps1 +++ b/src/tools/PackageJsonGenerator/generate-package-json.ps1 @@ -109,7 +109,10 @@ $integrationsFile = [System.IO.Path]::Combine($RepoRoot, "src", "frontend", "src $integrations = if (Test-Path $integrationsFile) { # Entries marked `"apiReference": false` (third-party packages) are not documented here. @(Get-Content $integrationsFile -Raw | ConvertFrom-Json | - Where-Object { $_.apiReference -ne $false }) + Where-Object { + $_.PSObject.Properties.Name -notcontains "apiReference" -or + $_.apiReference -ne $false + }) } else { @() diff --git a/tests/PackageJsonGenerator.Tests/generate-package-json.Tests.ps1 b/tests/PackageJsonGenerator.Tests/generate-package-json.Tests.ps1 new file mode 100644 index 000000000..98705e3d1 --- /dev/null +++ b/tests/PackageJsonGenerator.Tests/generate-package-json.Tests.ps1 @@ -0,0 +1,74 @@ +#!/usr/bin/env pwsh + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot ".." "..")).Path +$scriptPath = Join-Path $repoRoot "src/tools/PackageJsonGenerator/generate-package-json.ps1" +$catalogPath = Join-Path $repoRoot "src/frontend/src/data/aspire-integrations.json" + +$tokens = $null +$parseErrors = $null +$ast = [System.Management.Automation.Language.Parser]::ParseFile( + $scriptPath, + [ref]$tokens, + [ref]$parseErrors) + +if ($parseErrors.Count -gt 0) { + throw "generate-package-json.ps1 has parse errors: $($parseErrors.Message -join '; ')" +} + +$filterAst = $ast.Find({ + param($node) + + $node -is [System.Management.Automation.Language.CommandAst] -and + $node.GetCommandName() -eq "Where-Object" -and + $node.Extent.Text -match "apiReference" +}, $true) + +if ($null -eq $filterAst) { + throw "Could not find the apiReference catalog filter." +} + +$predicateAst = $filterAst.CommandElements | + Where-Object { $_ -is [System.Management.Automation.Language.ScriptBlockExpressionAst] } | + Select-Object -First 1 + +if ($null -eq $predicateAst) { + throw "Could not find the apiReference filter predicate." +} + +$predicateText = $predicateAst.ScriptBlock.Extent.Text +$predicate = [scriptblock]::Create($predicateText.Substring(1, $predicateText.Length - 2)) + +$fixture = @' +[ + { "title": "Property.Omitted" }, + { "title": "Explicit.False", "apiReference": false }, + { "title": "Explicit.True", "apiReference": true } +] +'@ | ConvertFrom-Json + +$fixtureResult = @($fixture | Where-Object $predicate) +$expectedFixtureTitles = @("Property.Omitted", "Explicit.True") +$actualFixtureTitles = @($fixtureResult.title) +if (Compare-Object $expectedFixtureTitles $actualFixtureTitles) { + throw "Unexpected fixture result: $($actualFixtureTitles -join ', ')" +} + +$catalog = @(Get-Content $catalogPath -Raw | ConvertFrom-Json) +$catalogResult = @($catalog | Where-Object $predicate) +$excluded = @($catalog | Where-Object { + $_.PSObject.Properties.Name -contains "apiReference" -and + $_.apiReference -eq $false +}) + +if ($catalogResult.Count -ne $catalog.Count - $excluded.Count) { + throw "Catalog filter retained $($catalogResult.Count) of $($catalog.Count) entries; expected $($catalog.Count - $excluded.Count)." +} + +if ($catalogResult.title -contains "Particular.Aspire.Hosting.ServicePlatform") { + throw "Catalog filter retained Particular.Aspire.Hosting.ServicePlatform." +} + +Write-Host "apiReference filter passed fixture and catalog checks ($($catalogResult.Count) included, $($excluded.Count) excluded)." From bdeaf3ff276d492cf5d5a705ba79f41e0afcd7d2 Mon Sep 17 00:00:00 2001 From: David Pine <7679720+IEvangelist@users.noreply.github.com> Date: Wed, 4 Nov 2026 05:43:46 -0600 Subject: [PATCH 2/3] Open a tracking issue when the Integration Data Updater fails Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/update-integration-data.yml | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.github/workflows/update-integration-data.yml b/.github/workflows/update-integration-data.yml index 2074dbe96..e59bc9443 100644 --- a/.github/workflows/update-integration-data.yml +++ b/.github/workflows/update-integration-data.yml @@ -33,6 +33,7 @@ jobs: timeout-minutes: 45 permissions: contents: read + issues: write steps: - name: Create GitHub App token id: app-token @@ -177,6 +178,33 @@ jobs: echo "Created $new_pr" fi + - name: Report failure + if: ${{ failure() && github.event_name == 'schedule' }} + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + shell: bash + run: | + set -euo pipefail + + # One tracking issue for consecutive failures: comment on it while it is + # open, so a broken updater is noticed without a daily issue flood. + title="Integration Data Updater is failing" + existing=$(gh issue list \ + --state open \ + --search "\"$title\" in:title" \ + --json number,title \ + --jq "map(select(.title == \"$title\")) | .[0].number // empty") + + if [ -n "$existing" ]; then + gh issue comment "$existing" --body "Scheduled run failed again: $RUN_URL" + else + gh issue create \ + --title "$title" \ + --body "The scheduled [Integration Data Updater]($RUN_URL) run failed. This issue is updated on each consecutive failure; close it once the workflow is green." + fi + - name: Summary if: ${{ always() }} shell: bash From ceda7e3c133d3ca04687216a214f230731367eef Mon Sep 17 00:00:00 2001 From: David Pine <7679720+IEvangelist@users.noreply.github.com> Date: Wed, 4 Nov 2026 05:45:46 -0600 Subject: [PATCH 3/3] Read optional catalog fields safely under StrictMode Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../PackageJsonGenerator/generate-package-json.ps1 | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/tools/PackageJsonGenerator/generate-package-json.ps1 b/src/tools/PackageJsonGenerator/generate-package-json.ps1 index 12fdcb908..a6d43352b 100644 --- a/src/tools/PackageJsonGenerator/generate-package-json.ps1 +++ b/src/tools/PackageJsonGenerator/generate-package-json.ps1 @@ -107,7 +107,9 @@ function Remove-StalePackageJsonFiles { $integrationsFile = [System.IO.Path]::Combine($RepoRoot, "src", "frontend", "src", "data", "aspire-integrations.json") $integrations = if (Test-Path $integrationsFile) { - # Entries marked `"apiReference": false` (third-party packages) are not documented here. + # Catalog fields are optional and StrictMode throws on missing properties, so + # read them through PSObject.Properties. Entries marked `"apiReference": false` + # (third-party packages) are not documented here. @(Get-Content $integrationsFile -Raw | ConvertFrom-Json | Where-Object { $_.PSObject.Properties.Name -notcontains "apiReference" -or @@ -119,9 +121,12 @@ else { } $catalogVersions = @{} foreach ($integration in $integrations) { - if (-not [string]::IsNullOrWhiteSpace($integration.title) -and - -not [string]::IsNullOrWhiteSpace($integration.version)) { - $catalogVersions[$integration.title] = $integration.version + $title = $integration.PSObject.Properties['title'] + $version = $integration.PSObject.Properties['version'] + if ($title -and $version -and + -not [string]::IsNullOrWhiteSpace($title.Value) -and + -not [string]::IsNullOrWhiteSpace($version.Value)) { + $catalogVersions[$title.Value] = $version.Value } }