mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 12:42:38 +00:00
c4280e823c
P5.x-A: Constants.SignalRMessages catalog (13 names) + SignalRGroupHelper.HubName;
all backend send sites and web subscriptions typed against the shared-manifest
union (SignalRContext.on/off) — unknown names are tsc errors. Dead eventStream
session-payload handling removed from diagnosis page.
P5.x-B: RowKeyCodec as the single inverted-tick encoder (persisted widths pinned,
UserActivity D20 legacy); DeletionRowDump.Table on tombstone rows with
DeletionTombstoneTables.Resolve replacing the duplicated Contains('_') heuristic
(legacy fallback retained for pre-field manifests).
P7.1: PATCH config/{tenantId}/fields flipped to TenantAdminOrGA (phase 2);
Settings sections save via per-section diff PATCH from sectionFieldMap.ts —
the ~39-field stale round-trip vector is gone; legacy webhook clearing now only
on the notifications save; agent-settings reset no longer discards contact edits.
P7.2/7.3: useGlobalAdminScope is a projection over useAggregatedAdminScope
(resolveConcreteScopeView, test-pinned); scopedApi builders own the tenant/global
endpoint-pair routing for all 11 former hand-rolled call sites; scopedFetch adds
the shared JSON fetch layer.
P7.4: navVisibility extraction + roles x nav-config matrix and nav<->route-guard
consistency test with a ratchet for the two known pre-existing mismatches
(Operator and GlobalReader vs /settings — user decision pending).
P7.5: web build stamp public/version.json (prebuild, GITHUB_SHA), SWA no-store
route, deploy-web verify poll + versions/web.json manifest, Portal Build card.
P7.6: OkAsyncBaselineGuardTests freezes the 44 anonymous-response sites
(shrink-only ratchet).
Verified: dotnet build 0W/0E, Functions.Tests 4123, DecisionCore 519, V2.Core
2206, SummaryDialog 44; tsc 0, ESLint 0, vitest 762/762; mutation proofs for all
new drift nets. Docs: docs/drift-guards.md + versioning.md web row.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
141 lines
6.8 KiB
YAML
141 lines
6.8 KiB
YAML
name: Deploy Web (Static Web App)
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
paths:
|
|
- 'src/Web/autopilot-monitor-web/**'
|
|
- '.github/workflows/deploy-web.yml'
|
|
workflow_dispatch:
|
|
pull_request:
|
|
types: [opened, synchronize, reopened, closed]
|
|
branches:
|
|
- main
|
|
paths:
|
|
- 'src/Web/autopilot-monitor-web/**'
|
|
- '.github/workflows/deploy-web.yml'
|
|
|
|
env:
|
|
PORTAL_VERSION_URL: https://portal.autopilotmonitor.com/version.json
|
|
VERSIONS_CONTAINER: https://autopilotmonitoreu.blob.core.windows.net/versions
|
|
|
|
jobs:
|
|
build_and_deploy_job:
|
|
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.action != 'closed')
|
|
runs-on: ubuntu-latest
|
|
name: Build and Deploy Job
|
|
# Dependabot PRs run without repo secrets, so the deploy token is absent.
|
|
# Surface it as an env var so the deploy step can gate on it — secrets
|
|
# cannot be referenced directly in an `if:` expression.
|
|
env:
|
|
DEPLOY_TOKEN: ${{ secrets.AZURE_SWA_DEPLOY_TOKEN }}
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
lfs: false
|
|
fetch-depth: 0 # Full history needed for git-based sitemap lastmod dates
|
|
- name: Build And Deploy
|
|
id: builddeploy
|
|
# Skip (green) instead of failing when the token is missing (Dependabot
|
|
# PRs); real deploys on main and internal PRs still have it.
|
|
if: env.DEPLOY_TOKEN != ''
|
|
uses: Azure/static-web-apps-deploy@v1
|
|
env:
|
|
NEXT_PUBLIC_ENTRA_CLIENT_ID: ${{ vars.NEXT_PUBLIC_ENTRA_CLIENT_ID }}
|
|
# Dual app-reg window: previous app registration (unset = single-app behaviour)
|
|
# and the default app for browsers without a stored selection (legacy|primary).
|
|
NEXT_PUBLIC_ENTRA_LEGACY_CLIENT_ID: ${{ vars.NEXT_PUBLIC_ENTRA_LEGACY_CLIENT_ID }}
|
|
NEXT_PUBLIC_ENTRA_DEFAULT_APP: ${{ vars.NEXT_PUBLIC_ENTRA_DEFAULT_APP }}
|
|
NEXT_PUBLIC_ENTRA_REDIRECT_URI: ${{ vars.NEXT_PUBLIC_ENTRA_REDIRECT_URI }}
|
|
NEXT_PUBLIC_ENTRA_POST_LOGOUT_REDIRECT_URI: ${{ vars.NEXT_PUBLIC_ENTRA_POST_LOGOUT_REDIRECT_URI }}
|
|
NEXT_PUBLIC_API_BASE_URL: ${{ vars.NEXT_PUBLIC_API_BASE_URL }}
|
|
NEXT_PUBLIC_PLATFORM_STATS_MANIFEST_URL: ${{ vars.NEXT_PUBLIC_PLATFORM_STATS_MANIFEST_URL }}
|
|
NEXT_PUBLIC_APPINSIGHTS_CONNECTION_STRING: ${{ secrets.NEXT_PUBLIC_APPINSIGHTS_CONNECTION_STRING }}
|
|
# Build stamp for public/version.json (scripts/generate-version.js in prebuild);
|
|
# the verify step below polls the deployed file for exactly this commit.
|
|
GITHUB_SHA: ${{ github.sha }}
|
|
with:
|
|
azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_DEPLOY_TOKEN }}
|
|
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
|
|
action: "upload"
|
|
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
|
|
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
|
|
app_location: "src/Web/autopilot-monitor-web" # App source code path
|
|
api_location: "" # Api source code path - optional
|
|
# Static export (next.config output:'export'): Oryx runs `npm run build`
|
|
# and uploads the exported out/ directory as plain static files — no
|
|
# managed SSR runtime is provisioned anymore. (No is_static_export
|
|
# input on this action version; Oryx detects the export from
|
|
# next.config + output_location.)
|
|
output_location: "out" # Built app content directory - optional
|
|
###### End of Repository/Build Configurations ######
|
|
|
|
# The SWA action reporting success proves the upload, not that the production host
|
|
# serves the new build — verify against the live /version.json (Cache-Control:
|
|
# no-store via staticwebapp.config.json) before publishing the version manifest.
|
|
# PR builds deploy to per-PR preview environments, so only main deploys are verified.
|
|
- name: Verify deployed portal build is live
|
|
if: env.DEPLOY_TOKEN != '' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
|
shell: pwsh
|
|
run: |
|
|
$expectedCommit = '${{ github.sha }}'.Substring(0, 7)
|
|
$deadline = [DateTime]::UtcNow.AddMinutes(5)
|
|
$attempt = 0
|
|
|
|
while ([DateTime]::UtcNow -lt $deadline) {
|
|
$attempt++
|
|
try {
|
|
$v = Invoke-RestMethod -Uri '${{ env.PORTAL_VERSION_URL }}' -Method Get -TimeoutSec 30 -Headers @{ 'Cache-Control' = 'no-cache' }
|
|
if ($v.commit -eq $expectedCommit) {
|
|
Write-Host "Live after $attempt attempt(s): web @ $($v.commit), built $($v.buildUtc)"
|
|
exit 0
|
|
}
|
|
Write-Host "Attempt ${attempt}: serving $($v.commit) -- waiting for $expectedCommit"
|
|
} catch {
|
|
Write-Host "Attempt ${attempt}: /version.json not answering yet -- $($_.Exception.Message)"
|
|
}
|
|
Start-Sleep -Seconds 15
|
|
}
|
|
|
|
throw "Portal did not serve commit $expectedCommit within 5 minutes -- deployment not verified, version manifest NOT published"
|
|
|
|
# Cross-component deploy record, written last and only on a verified deploy —
|
|
# same contract as versions/backend.json and versions/mcp.json.
|
|
- name: Publish version manifest
|
|
if: env.DEPLOY_TOKEN != '' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
|
shell: pwsh
|
|
run: |
|
|
$manifest = [ordered]@{
|
|
component = 'web'
|
|
commit = '${{ github.sha }}'.Substring(0, 7)
|
|
deployedUtc = [DateTime]::UtcNow.ToString('o')
|
|
runId = '${{ github.run_id }}'
|
|
} | ConvertTo-Json
|
|
|
|
$sas = '${{ secrets.AZURE_BLOB_VERSIONS_SAS_TOKEN }}'.TrimStart('?')
|
|
$url = "${{ env.VERSIONS_CONTAINER }}/web.json?$sas"
|
|
# no-cache: rotating pointer, must never be served stale by any fronting cache.
|
|
Invoke-RestMethod -Uri $url -Method Put -Headers @{ 'x-ms-blob-type' = 'BlockBlob'; 'x-ms-blob-cache-control' = 'no-cache' } -Body $manifest -ContentType 'application/json' | Out-Null
|
|
Write-Host "Published versions/web.json"
|
|
Write-Host $manifest
|
|
|
|
close_pull_request_job:
|
|
if: github.event_name == 'pull_request' && github.event.action == 'closed'
|
|
runs-on: ubuntu-latest
|
|
name: Close Pull Request Job
|
|
env:
|
|
DEPLOY_TOKEN: ${{ secrets.AZURE_SWA_DEPLOY_TOKEN }}
|
|
steps:
|
|
- name: Close Pull Request
|
|
id: closepullrequest
|
|
if: env.DEPLOY_TOKEN != ''
|
|
uses: Azure/static-web-apps-deploy@v1
|
|
with:
|
|
azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_DEPLOY_TOKEN }}
|
|
action: "close"
|
|
|
|
|
|
|
|
|