-
-
Notifications
You must be signed in to change notification settings - Fork 13
Fix standalone doctor SEO audit for BOM noindex pages #228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
PrzemyslawKlys
wants to merge
29
commits into
main
Choose a base branch
from
codex/testimox-doctor-seo-fix
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+5,617
−324
Open
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
7a7e150
Harden API docs layout and source-link preflight
PrzemyslawKlys 8652823
Improve PowerShell API docs fallback examples
PrzemyslawKlys 84cc125
Warn with sampled API source links
PrzemyslawKlys 30914a7
Warn on generated-only PowerShell examples
PrzemyslawKlys 66ebcce
Prefer command-specific PowerShell examples
PrzemyslawKlys 92ec980
Gate generated-only PowerShell examples
PrzemyslawKlys 1c1bb72
Track PowerShell example provenance in API coverage
PrzemyslawKlys 12a08a2
Add API docs thresholds for PowerShell example origins
PrzemyslawKlys bc3af3c
Add example media support to API docs
PrzemyslawKlys 9ae587d
Add PowerShell example validation for API docs
PrzemyslawKlys 0fc2cd4
Add git freshness metadata to API docs
PrzemyslawKlys 7d9d311
Add PowerShell example execution reporting
PrzemyslawKlys ee229ae
Add PowerShell example execution artifacts
PrzemyslawKlys 5be87de
Show API example provenance in docs
PrzemyslawKlys f552994
Attach PowerShell transcripts to docs examples
PrzemyslawKlys efa5a6d
Stage PowerShell playback assets for docs
PrzemyslawKlys 55cb8f1
Add PowerShell playback media coverage gates
PrzemyslawKlys 56faf9d
Warn on unhealthy PowerShell playback assets
PrzemyslawKlys 61e907b
Add playback asset health coverage thresholds
PrzemyslawKlys ff428c8
Show API example media capture recency
PrzemyslawKlys 7c6bf1a
Emit PowerShell example media manifest
PrzemyslawKlys 2e7b211
Fix doctor SEO audit for BOM noindex pages
PrzemyslawKlys 604363a
Simplify scaffolded website workflow lock resolution
PrzemyslawKlys 68f079e
Add reusable website workflows
PrzemyslawKlys a9f52fd
Harden reusable website workflows
PrzemyslawKlys 16d9c95
Deduplicate reusable website workflow logic
PrzemyslawKlys 1814482
Add CLI engine lock resolve mode
PrzemyslawKlys 16db966
Revert "Add CLI engine lock resolve mode"
PrzemyslawKlys 5ac8f5e
Harden website workflow maintenance wrappers
PrzemyslawKlys File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| name: PowerForge Website CI | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| website_root: | ||
| required: true | ||
| type: string | ||
| pipeline_config: | ||
| required: true | ||
| type: string | ||
| runner_labels_json: | ||
| required: false | ||
| type: string | ||
| default: '["ubuntu-latest"]' | ||
| timeout_minutes: | ||
| required: false | ||
| type: number | ||
| default: 20 | ||
| dotnet_version: | ||
| required: false | ||
| type: string | ||
| default: "10.0.x" | ||
| report_artifact_name: | ||
| required: false | ||
| type: string | ||
| default: "powerforge-website-reports" | ||
| powerforge_lock_path: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_repository: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_ref: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_repository_override: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_ref_override: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| secrets: | ||
| INDEXNOW_KEY: | ||
| required: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: powerforge-website-ci-${{ github.repository }}-${{ github.ref }}-${{ inputs.website_root }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| website-ci: | ||
| uses: ./.github/workflows/powerforge-website-run.yml | ||
| with: | ||
| website_root: ${{ inputs.website_root }} | ||
| pipeline_config: ${{ inputs.pipeline_config }} | ||
| runner_labels_json: ${{ inputs.runner_labels_json }} | ||
| timeout_minutes: ${{ inputs.timeout_minutes }} | ||
| dotnet_version: ${{ inputs.dotnet_version }} | ||
| report_artifact_name: ${{ inputs.report_artifact_name }} | ||
| powerforge_lock_path: ${{ inputs.powerforge_lock_path }} | ||
| powerforge_repository: ${{ inputs.powerforge_repository }} | ||
| powerforge_ref: ${{ inputs.powerforge_ref }} | ||
| powerforge_repository_override: ${{ inputs.powerforge_repository_override }} | ||
| powerforge_ref_override: ${{ inputs.powerforge_ref_override }} | ||
| pipeline_mode: ci | ||
| use_playwright_cache: true | ||
| secrets: | ||
| indexnow_key: ${{ secrets.INDEXNOW_KEY }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| name: PowerForge Website Maintenance | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| website_root: | ||
| required: true | ||
| type: string | ||
| pipeline_config: | ||
| required: true | ||
| type: string | ||
| runner_labels_json: | ||
| required: false | ||
| type: string | ||
| default: '["ubuntu-latest"]' | ||
| timeout_minutes: | ||
| required: false | ||
| type: number | ||
| default: 20 | ||
| dotnet_version: | ||
| required: false | ||
| type: string | ||
| default: "10.0.x" | ||
| report_artifact_name: | ||
| required: false | ||
| type: string | ||
| default: "powerforge-website-maintenance-reports" | ||
| powerforge_lock_path: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_repository: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_ref: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_repository_override: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_ref_override: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
|
|
||
| permissions: | ||
| contents: read | ||
| # Required for maintenance tasks such as GitHub artifact pruning. | ||
| actions: write | ||
|
|
||
| concurrency: | ||
| group: powerforge-website-maintenance-${{ github.repository }}-${{ github.ref }}-${{ inputs.website_root }} | ||
| # Let scheduled/manual maintenance finish once started. | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| website-maintenance: | ||
| uses: ./.github/workflows/powerforge-website-run.yml | ||
| with: | ||
| website_root: ${{ inputs.website_root }} | ||
| pipeline_config: ${{ inputs.pipeline_config }} | ||
| runner_labels_json: ${{ inputs.runner_labels_json }} | ||
| timeout_minutes: ${{ inputs.timeout_minutes }} | ||
| dotnet_version: ${{ inputs.dotnet_version }} | ||
| report_artifact_name: ${{ inputs.report_artifact_name }} | ||
| powerforge_lock_path: ${{ inputs.powerforge_lock_path }} | ||
| powerforge_repository: ${{ inputs.powerforge_repository }} | ||
| powerforge_ref: ${{ inputs.powerforge_ref }} | ||
| powerforge_repository_override: ${{ inputs.powerforge_repository_override }} | ||
| powerforge_ref_override: ${{ inputs.powerforge_ref_override }} | ||
| # Maintenance stays on strict CI mode; the selected pipeline config decides which tasks run. | ||
| pipeline_mode: ci | ||
| use_playwright_cache: true | ||
| maintenance_mode_note: true | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| name: PowerForge Website Run | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| website_root: | ||
| required: true | ||
| type: string | ||
| pipeline_config: | ||
| required: true | ||
| type: string | ||
| runner_labels_json: | ||
| required: false | ||
| type: string | ||
| default: '["ubuntu-latest"]' | ||
| timeout_minutes: | ||
| required: false | ||
| type: number | ||
| default: 20 | ||
| dotnet_version: | ||
| required: false | ||
| type: string | ||
| default: "10.0.x" | ||
| report_artifact_name: | ||
| required: false | ||
| type: string | ||
| default: "powerforge-website-reports" | ||
| powerforge_lock_path: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_repository: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_ref: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_repository_override: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| powerforge_ref_override: | ||
| required: false | ||
| type: string | ||
| default: "" | ||
| pipeline_mode: | ||
| required: false | ||
| type: string | ||
| default: "ci" | ||
| use_playwright_cache: | ||
| required: false | ||
| type: boolean | ||
| default: true | ||
| maintenance_mode_note: | ||
| required: false | ||
| type: boolean | ||
| default: false | ||
| secrets: | ||
| indexnow_key: | ||
| required: false | ||
|
|
||
| jobs: | ||
| website-run: | ||
| runs-on: ${{ fromJson(inputs.runner_labels_json) }} | ||
| timeout-minutes: ${{ inputs.timeout_minutes }} | ||
| env: | ||
| PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.cache/ms-playwright | ||
| steps: | ||
| - name: Checkout website | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| token: ${{ github.token }} | ||
|
|
||
| - name: Setup .NET | ||
| uses: actions/setup-dotnet@v4 | ||
| with: | ||
| dotnet-version: ${{ inputs.dotnet_version }} | ||
|
|
||
| - name: Resolve PowerForge engine source | ||
| id: powerforge | ||
| shell: pwsh | ||
| run: | | ||
| $websiteRoot = [string]'${{ inputs.website_root }}' | ||
| $lockPath = [string]'${{ inputs.powerforge_lock_path }}' | ||
| if ([string]::IsNullOrWhiteSpace($lockPath)) { | ||
| $lockPath = Join-Path $websiteRoot '.powerforge/engine-lock.json' | ||
| } | ||
|
|
||
| $resolvedRepository = [string]'${{ inputs.powerforge_repository }}' | ||
| $resolvedRef = [string]'${{ inputs.powerforge_ref }}' | ||
|
|
||
| if (([string]::IsNullOrWhiteSpace($resolvedRepository) -or [string]::IsNullOrWhiteSpace($resolvedRef)) -and (Test-Path -LiteralPath $lockPath)) { | ||
| $lock = Get-Content -LiteralPath $lockPath -Raw | ConvertFrom-Json | ||
| if ($null -eq $lock) { | ||
| throw "Invalid engine lock JSON: $lockPath" | ||
| } | ||
|
|
||
| if ([string]::IsNullOrWhiteSpace($resolvedRepository)) { | ||
| $resolvedRepository = [string]$lock.repository | ||
| } | ||
|
|
||
| if ([string]::IsNullOrWhiteSpace($resolvedRef)) { | ||
| $resolvedRef = [string]$lock.ref | ||
| } | ||
| } | ||
|
|
||
| if ([string]::IsNullOrWhiteSpace($resolvedRepository) -or [string]::IsNullOrWhiteSpace($resolvedRef)) { | ||
| throw "Provide either powerforge_repository + powerforge_ref or a valid engine lock file at '$lockPath'." | ||
| } | ||
|
|
||
| $repoOverride = [string]'${{ inputs.powerforge_repository_override }}' | ||
| $refOverride = [string]'${{ inputs.powerforge_ref_override }}' | ||
|
|
||
| $finalRepository = if ([string]::IsNullOrWhiteSpace($repoOverride)) { $resolvedRepository } else { $repoOverride } | ||
| $finalRef = if ([string]::IsNullOrWhiteSpace($refOverride)) { $resolvedRef } else { $refOverride } | ||
|
|
||
| if ($finalRepository -ne $resolvedRepository -or $finalRef -ne $resolvedRef) { | ||
| Write-Warning "Using PowerForge override instead of resolved source (${resolvedRepository}@${resolvedRef})." | ||
| } | ||
|
|
||
| if ($finalRef -notmatch '^(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})$') { | ||
| throw "PowerForge ref must be an immutable commit SHA (40/64 hex): '$finalRef'." | ||
| } | ||
|
|
||
| "repository=$finalRepository" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append | ||
| "ref=$finalRef" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append | ||
|
|
||
| - name: Checkout PowerForge engine | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: ${{ steps.powerforge.outputs.repository }} | ||
| ref: ${{ steps.powerforge.outputs.ref }} | ||
| path: ./.powerforge-engine | ||
| token: ${{ github.token }} | ||
|
|
||
| - name: Cache NuGet packages | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.nuget/packages | ||
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets', '**/packages.lock.json') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-nuget- | ||
|
|
||
| - name: Initialize Playwright cache directory | ||
| if: ${{ inputs.use_playwright_cache }} | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| mkdir -p "${PLAYWRIGHT_BROWSERS_PATH}" | ||
|
|
||
| - name: Run website pipeline | ||
| shell: pwsh | ||
| env: | ||
| GITHUB_TOKEN: ${{ github.token }} | ||
| INDEXNOW_KEY: ${{ secrets.indexnow_key }} | ||
| run: | | ||
| $pipelineConfig = [string]'${{ inputs.pipeline_config }}' | ||
| $pipelineMode = [string]'${{ inputs.pipeline_mode }}' | ||
|
|
||
| if ('${{ inputs.maintenance_mode_note }}' -eq 'true') { | ||
| Write-Host 'Maintenance uses the same strict CI mode; the selected pipeline config controls which tasks run.' | ||
| } | ||
|
|
||
| dotnet run --project ./.powerforge-engine/PowerForge.Web.Cli -- pipeline --config "./$pipelineConfig" --mode $pipelineMode | ||
|
|
||
| - name: Upload website reports | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: ${{ inputs.report_artifact_name }} | ||
| path: | | ||
| ./${{ inputs.website_root }}/_reports/** | ||
| ./${{ inputs.website_root }}/_site/_reports/** | ||
| if-no-files-found: ignore | ||
|
|
||
| - name: Cleanup Playwright cache | ||
| if: ${{ always() && inputs.use_playwright_cache }} | ||
| shell: bash | ||
| run: | | ||
| if [ -n "${PLAYWRIGHT_BROWSERS_PATH:-}" ] && [ -d "${PLAYWRIGHT_BROWSERS_PATH}" ]; then | ||
| rm -rf "${PLAYWRIGHT_BROWSERS_PATH}" | ||
| fi |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The maintenance wrapper calls
powerforge-website-run.ymlwithout passingindexnow_key, and this workflow also does not declare anINDEXNOW_KEYinput secret. Becausepowerforge-website-run.ymlreadssecrets.indexnow_keyintoINDEXNOW_KEY, maintenance runs cannot receive the key even when callers provide it, so maintenance pipelines that include IndexNow submission will run with an empty key and fail/skip publishing unexpectedly.Useful? React with 👍 / 👎.